UNPKG

@aws-cdk/aws-ecs

Version:

The CDK Construct Library for AWS::ECS

599 lines 96.5 kB
"use strict"; var _a; Object.defineProperty(exports, "__esModule", { value: true }); exports.isExternalCompatible = exports.isFargateCompatible = exports.isEc2Compatible = exports.Compatibility = exports.Scope = exports.PidMode = exports.IpcMode = exports.NetworkMode = exports.TaskDefinition = void 0; const jsiiDeprecationWarnings = require("../../.warnings.jsii.js"); const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti"); const ec2 = require("@aws-cdk/aws-ec2"); const iam = require("@aws-cdk/aws-iam"); const core_1 = require("@aws-cdk/core"); const container_definition_1 = require("../container-definition"); const ecs_generated_1 = require("../ecs.generated"); const firelens_log_router_1 = require("../firelens-log-router"); const aws_log_driver_1 = require("../log-drivers/aws-log-driver"); const _imported_task_definition_1 = require("./_imported-task-definition"); class TaskDefinitionBase extends core_1.Resource { /** * Return true if the task definition can be run on an EC2 cluster */ get isEc2Compatible() { return isEc2Compatible(this.compatibility); } /** * Return true if the task definition can be run on a Fargate cluster */ get isFargateCompatible() { return isFargateCompatible(this.compatibility); } /** * Return true if the task definition can be run on a ECS anywhere cluster */ get isExternalCompatible() { return isExternalCompatible(this.compatibility); } } /** * The base class for all task definitions. */ class TaskDefinition extends TaskDefinitionBase { /** * Constructs a new instance of the TaskDefinition class. */ constructor(scope, id, props) { super(scope, id); /** * The container definitions. */ this.containers = new Array(); /** * All volumes */ this.volumes = []; /** * Placement constraints for task instances */ this.placementConstraints = new Array(); /** * Inference accelerators for task instances */ this._inferenceAccelerators = []; try { jsiiDeprecationWarnings._aws_cdk_aws_ecs_TaskDefinitionProps(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, TaskDefinition); } throw error; } this.family = props.family || core_1.Names.uniqueId(this); this.compatibility = props.compatibility; if (props.volumes) { props.volumes.forEach(v => this.addVolume(v)); } this.networkMode = props.networkMode ?? (this.isFargateCompatible ? NetworkMode.AWS_VPC : NetworkMode.BRIDGE); if (this.isFargateCompatible && this.networkMode !== NetworkMode.AWS_VPC) { throw new Error(`Fargate tasks can only have AwsVpc network mode, got: ${this.networkMode}`); } if (props.proxyConfiguration && this.networkMode !== NetworkMode.AWS_VPC) { throw new Error(`ProxyConfiguration can only be used with AwsVpc network mode, got: ${this.networkMode}`); } if (props.placementConstraints && props.placementConstraints.length > 0 && this.isFargateCompatible) { throw new Error('Cannot set placement constraints on tasks that run on Fargate'); } if (this.isFargateCompatible && (!props.cpu || !props.memoryMiB)) { throw new Error(`Fargate-compatible tasks require both CPU (${props.cpu}) and memory (${props.memoryMiB}) specifications`); } if (props.inferenceAccelerators && props.inferenceAccelerators.length > 0 && this.isFargateCompatible) { throw new Error('Cannot use inference accelerators on tasks that run on Fargate'); } if (this.isExternalCompatible && this.networkMode !== NetworkMode.BRIDGE) { throw new Error(`External tasks can only have Bridge network mode, got: ${this.networkMode}`); } if (!this.isFargateCompatible && props.runtimePlatform) { throw new Error('Cannot specify runtimePlatform in non-Fargate compatible tasks'); } this._executionRole = props.executionRole; this.taskRole = props.taskRole || new iam.Role(this, 'TaskRole', { assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), }); if (props.inferenceAccelerators) { props.inferenceAccelerators.forEach(ia => this.addInferenceAccelerator(ia)); } this.ephemeralStorageGiB = props.ephemeralStorageGiB; // validate the cpu and memory size for the Windows operation system family. if (props.runtimePlatform?.operatingSystemFamily?._operatingSystemFamily.includes('WINDOWS')) { // We know that props.cpu and props.memoryMiB are defined because an error would have been thrown previously if they were not. // But, typescript is not able to figure this out, so using the `!` operator here to let the type-checker know they are defined. this.checkFargateWindowsBasedTasksSize(props.cpu, props.memoryMiB, props.runtimePlatform); } this.runtimePlatform = props.runtimePlatform; const taskDef = new ecs_generated_1.CfnTaskDefinition(this, 'Resource', { containerDefinitions: core_1.Lazy.any({ produce: () => this.renderContainers() }, { omitEmptyArray: true }), volumes: core_1.Lazy.any({ produce: () => this.renderVolumes() }, { omitEmptyArray: true }), executionRoleArn: core_1.Lazy.string({ produce: () => this.executionRole && this.executionRole.roleArn }), family: this.family, taskRoleArn: this.taskRole.roleArn, requiresCompatibilities: [ ...(isEc2Compatible(props.compatibility) ? ['EC2'] : []), ...(isFargateCompatible(props.compatibility) ? ['FARGATE'] : []), ...(isExternalCompatible(props.compatibility) ? ['EXTERNAL'] : []), ], networkMode: this.renderNetworkMode(this.networkMode), placementConstraints: core_1.Lazy.any({ produce: () => !isFargateCompatible(this.compatibility) ? this.placementConstraints : undefined, }, { omitEmptyArray: true }), proxyConfiguration: props.proxyConfiguration ? props.proxyConfiguration.bind(this.stack, this) : undefined, cpu: props.cpu, memory: props.memoryMiB, ipcMode: props.ipcMode, pidMode: props.pidMode, inferenceAccelerators: core_1.Lazy.any({ produce: () => !isFargateCompatible(this.compatibility) ? this.renderInferenceAccelerators() : undefined, }, { omitEmptyArray: true }), ephemeralStorage: this.ephemeralStorageGiB ? { sizeInGiB: this.ephemeralStorageGiB, } : undefined, runtimePlatform: this.isFargateCompatible && this.runtimePlatform ? { cpuArchitecture: this.runtimePlatform?.cpuArchitecture?._cpuArchitecture, operatingSystemFamily: this.runtimePlatform?.operatingSystemFamily?._operatingSystemFamily, } : undefined, }); if (props.placementConstraints) { props.placementConstraints.forEach(pc => this.addPlacementConstraint(pc)); } this.taskDefinitionArn = taskDef.ref; } /** * Imports a task definition from the specified task definition ARN. * * The task will have a compatibility of EC2+Fargate. */ static fromTaskDefinitionArn(scope, id, taskDefinitionArn) { return new _imported_task_definition_1.ImportedTaskDefinition(scope, id, { taskDefinitionArn: taskDefinitionArn }); } /** * Create a task definition from a task definition reference */ static fromTaskDefinitionAttributes(scope, id, attrs) { try { jsiiDeprecationWarnings._aws_cdk_aws_ecs_TaskDefinitionAttributes(attrs); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.fromTaskDefinitionAttributes); } throw error; } return new _imported_task_definition_1.ImportedTaskDefinition(scope, id, { taskDefinitionArn: attrs.taskDefinitionArn, compatibility: attrs.compatibility, networkMode: attrs.networkMode, taskRole: attrs.taskRole, }); } get executionRole() { return this._executionRole; } /** * Public getter method to access list of inference accelerators attached to the instance. */ get inferenceAccelerators() { return this._inferenceAccelerators; } renderVolumes() { return this.volumes.map(renderVolume); function renderVolume(spec) { return { host: spec.host, name: spec.name, dockerVolumeConfiguration: spec.dockerVolumeConfiguration && { autoprovision: spec.dockerVolumeConfiguration.autoprovision, driver: spec.dockerVolumeConfiguration.driver, driverOpts: spec.dockerVolumeConfiguration.driverOpts, labels: spec.dockerVolumeConfiguration.labels, scope: spec.dockerVolumeConfiguration.scope, }, efsVolumeConfiguration: spec.efsVolumeConfiguration && { filesystemId: spec.efsVolumeConfiguration.fileSystemId, authorizationConfig: spec.efsVolumeConfiguration.authorizationConfig, rootDirectory: spec.efsVolumeConfiguration.rootDirectory, transitEncryption: spec.efsVolumeConfiguration.transitEncryption, transitEncryptionPort: spec.efsVolumeConfiguration.transitEncryptionPort, }, }; } } renderInferenceAccelerators() { return this._inferenceAccelerators.map(renderInferenceAccelerator); function renderInferenceAccelerator(inferenceAccelerator) { return { deviceName: inferenceAccelerator.deviceName, deviceType: inferenceAccelerator.deviceType, }; } } /** * Validate the existence of the input target and set default values. * * @internal */ _validateTarget(options) { const targetContainer = this.findContainer(options.containerName); if (targetContainer === undefined) { throw new Error(`No container named '${options.containerName}'. Did you call "addContainer()"?`); } const targetProtocol = options.protocol || container_definition_1.Protocol.TCP; const targetContainerPort = options.containerPort || targetContainer.containerPort; const portMapping = targetContainer.findPortMapping(targetContainerPort, targetProtocol); if (portMapping === undefined) { // eslint-disable-next-line max-len throw new Error(`Container '${targetContainer}' has no mapping for port ${options.containerPort} and protocol ${targetProtocol}. Did you call "container.addPortMappings()"?`); } return { containerName: options.containerName, portMapping, }; } /** * Returns the port range to be opened that match the provided container name and container port. * * @internal */ _portRangeFromPortMapping(portMapping) { if (portMapping.hostPort !== undefined && portMapping.hostPort !== 0) { return portMapping.protocol === container_definition_1.Protocol.UDP ? ec2.Port.udp(portMapping.hostPort) : ec2.Port.tcp(portMapping.hostPort); } if (this.networkMode === NetworkMode.BRIDGE || this.networkMode === NetworkMode.NAT) { return EPHEMERAL_PORT_RANGE; } return portMapping.protocol === container_definition_1.Protocol.UDP ? ec2.Port.udp(portMapping.containerPort) : ec2.Port.tcp(portMapping.containerPort); } /** * Adds a policy statement to the task IAM role. */ addToTaskRolePolicy(statement) { this.taskRole.addToPrincipalPolicy(statement); } /** * Adds a policy statement to the task execution IAM role. */ addToExecutionRolePolicy(statement) { this.obtainExecutionRole().addToPrincipalPolicy(statement); } /** * Adds a new container to the task definition. */ addContainer(id, props) { try { jsiiDeprecationWarnings._aws_cdk_aws_ecs_ContainerDefinitionOptions(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addContainer); } throw error; } return new container_definition_1.ContainerDefinition(this, id, { taskDefinition: this, ...props }); } /** * Adds a firelens log router to the task definition. */ addFirelensLogRouter(id, props) { try { jsiiDeprecationWarnings._aws_cdk_aws_ecs_FirelensLogRouterDefinitionOptions(props); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addFirelensLogRouter); } throw error; } // only one firelens log router is allowed in each task. if (this.containers.find(x => x instanceof firelens_log_router_1.FirelensLogRouter)) { throw new Error('Firelens log router is already added in this task.'); } return new firelens_log_router_1.FirelensLogRouter(this, id, { taskDefinition: this, ...props }); } /** * Links a container to this task definition. * @internal */ _linkContainer(container) { this.containers.push(container); if (this.defaultContainer === undefined && container.essential) { this.defaultContainer = container; } if (container.referencesSecretJsonField) { this._referencesSecretJsonField = true; } } /** * Adds a volume to the task definition. */ addVolume(volume) { try { jsiiDeprecationWarnings._aws_cdk_aws_ecs_Volume(volume); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addVolume); } throw error; } this.volumes.push(volume); } /** * Adds the specified placement constraint to the task definition. */ addPlacementConstraint(constraint) { try { jsiiDeprecationWarnings._aws_cdk_aws_ecs_PlacementConstraint(constraint); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addPlacementConstraint); } throw error; } if (isFargateCompatible(this.compatibility)) { throw new Error('Cannot set placement constraints on tasks that run on Fargate'); } this.placementConstraints.push(...constraint.toJson()); } /** * Adds the specified extension to the task definition. * * Extension can be used to apply a packaged modification to * a task definition. */ addExtension(extension) { try { jsiiDeprecationWarnings._aws_cdk_aws_ecs_ITaskDefinitionExtension(extension); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addExtension); } throw error; } extension.extend(this); } /** * Adds an inference accelerator to the task definition. */ addInferenceAccelerator(inferenceAccelerator) { try { jsiiDeprecationWarnings._aws_cdk_aws_ecs_InferenceAccelerator(inferenceAccelerator); } catch (error) { if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") { Error.captureStackTrace(error, this.addInferenceAccelerator); } throw error; } if (isFargateCompatible(this.compatibility)) { throw new Error('Cannot use inference accelerators on tasks that run on Fargate'); } this._inferenceAccelerators.push(inferenceAccelerator); } /** * Creates the task execution IAM role if it doesn't already exist. */ obtainExecutionRole() { if (!this._executionRole) { this._executionRole = new iam.Role(this, 'ExecutionRole', { assumedBy: new iam.ServicePrincipal('ecs-tasks.amazonaws.com'), // needed for cross-account access with TagParameterContainerImage roleName: core_1.PhysicalName.GENERATE_IF_NEEDED, }); } return this._executionRole; } /** * Whether this task definition has at least a container that references a * specific JSON field of a secret stored in Secrets Manager. */ get referencesSecretJsonField() { return this._referencesSecretJsonField; } /** * Validates the task definition. */ validate() { const ret = super.validate(); if (isEc2Compatible(this.compatibility)) { // EC2 mode validations // Container sizes for (const container of this.containers) { if (!container.memoryLimitSpecified) { ret.push(`ECS Container ${container.containerName} must have at least one of 'memoryLimitMiB' or 'memoryReservationMiB' specified`); } } } return ret; } /** * Returns the container that match the provided containerName. */ findContainer(containerName) { return this.containers.find(c => c.containerName === containerName); } renderNetworkMode(networkMode) { return (networkMode === NetworkMode.NAT) ? undefined : networkMode; } renderContainers() { // add firelens log router container if any application container is using firelens log driver, // also check if already created log router container for (const container of this.containers) { if (container.logDriverConfig && container.logDriverConfig.logDriver === 'awsfirelens' && !this.containers.find(x => x instanceof firelens_log_router_1.FirelensLogRouter)) { this.addFirelensLogRouter('log-router', { image: firelens_log_router_1.obtainDefaultFluentBitECRImage(this, container.logDriverConfig), firelensConfig: { type: firelens_log_router_1.FirelensLogRouterType.FLUENTBIT, }, logging: new aws_log_driver_1.AwsLogDriver({ streamPrefix: 'firelens' }), memoryReservationMiB: 50, }); break; } } return this.containers.map(x => x.renderContainerDefinition()); } checkFargateWindowsBasedTasksSize(cpu, memory, runtimePlatform) { if (Number(cpu) === 1024) { if (Number(memory) < 1024 || Number(memory) > 8192 || (Number(memory) % 1024 !== 0)) { throw new Error(`If provided cpu is ${cpu}, then memoryMiB must have a min of 1024 and a max of 8192, in 1024 increments. Provided memoryMiB was ${Number(memory)}.`); } } else if (Number(cpu) === 2048) { if (Number(memory) < 4096 || Number(memory) > 16384 || (Number(memory) % 1024 !== 0)) { throw new Error(`If provided cpu is ${cpu}, then memoryMiB must have a min of 4096 and max of 16384, in 1024 increments. Provided memoryMiB ${Number(memory)}.`); } } else if (Number(cpu) === 4096) { if (Number(memory) < 8192 || Number(memory) > 30720 || (Number(memory) % 1024 !== 0)) { throw new Error(`If provided cpu is ${cpu}, then memoryMiB must have a min of 8192 and a max of 30720, in 1024 increments.Provided memoryMiB was ${Number(memory)}.`); } } else { throw new Error(`If operatingSystemFamily is ${runtimePlatform.operatingSystemFamily._operatingSystemFamily}, then cpu must be in 1024 (1 vCPU), 2048 (2 vCPU), or 4096 (4 vCPU). Provided value was: ${cpu}`); } } ; } exports.TaskDefinition = TaskDefinition; _a = JSII_RTTI_SYMBOL_1; TaskDefinition[_a] = { fqn: "@aws-cdk/aws-ecs.TaskDefinition", version: "1.204.0" }; /** * The port range to open up for dynamic port mapping */ const EPHEMERAL_PORT_RANGE = ec2.Port.tcpRange(32768, 65535); /** * The networking mode to use for the containers in the task. */ var NetworkMode; (function (NetworkMode) { /** * The task's containers do not have external connectivity and port mappings can't be specified in the container definition. */ NetworkMode["NONE"] = "none"; /** * The task utilizes Docker's built-in virtual network which runs inside each container instance. */ NetworkMode["BRIDGE"] = "bridge"; /** * The task is allocated an elastic network interface. */ NetworkMode["AWS_VPC"] = "awsvpc"; /** * The task bypasses Docker's built-in virtual network and maps container ports directly to the EC2 instance's network interface directly. * * In this mode, you can't run multiple instantiations of the same task on a * single container instance when port mappings are used. */ NetworkMode["HOST"] = "host"; /** * The task utilizes NAT network mode required by Windows containers. * * This is the only supported network mode for Windows containers. For more information, see * [Task Definition Parameters](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definition_parameters.html#network_mode). */ NetworkMode["NAT"] = "nat"; })(NetworkMode = exports.NetworkMode || (exports.NetworkMode = {})); /** * The IPC resource namespace to use for the containers in the task. */ var IpcMode; (function (IpcMode) { /** * If none is specified, then IPC resources within the containers of a task are private and not * shared with other containers in a task or on the container instance */ IpcMode["NONE"] = "none"; /** * If host is specified, then all containers within the tasks that specified the host IPC mode on * the same container instance share the same IPC resources with the host Amazon EC2 instance. */ IpcMode["HOST"] = "host"; /** * If task is specified, all containers within the specified task share the same IPC resources. */ IpcMode["TASK"] = "task"; })(IpcMode = exports.IpcMode || (exports.IpcMode = {})); /** * The process namespace to use for the containers in the task. */ var PidMode; (function (PidMode) { /** * If host is specified, then all containers within the tasks that specified the host PID mode * on the same container instance share the same process namespace with the host Amazon EC2 instance. */ PidMode["HOST"] = "host"; /** * If task is specified, all containers within the specified task share the same process namespace. */ PidMode["TASK"] = "task"; })(PidMode = exports.PidMode || (exports.PidMode = {})); /** * The scope for the Docker volume that determines its lifecycle. * Docker volumes that are scoped to a task are automatically provisioned when the task starts and destroyed when the task stops. * Docker volumes that are scoped as shared persist after the task stops. */ var Scope; (function (Scope) { /** * Docker volumes that are scoped to a task are automatically provisioned when the task starts and destroyed when the task stops. */ Scope["TASK"] = "task"; /** * Docker volumes that are scoped as shared persist after the task stops. */ Scope["SHARED"] = "shared"; })(Scope = exports.Scope || (exports.Scope = {})); /** * The task launch type compatibility requirement. */ var Compatibility; (function (Compatibility) { /** * The task should specify the EC2 launch type. */ Compatibility[Compatibility["EC2"] = 0] = "EC2"; /** * The task should specify the Fargate launch type. */ Compatibility[Compatibility["FARGATE"] = 1] = "FARGATE"; /** * The task can specify either the EC2 or Fargate launch types. */ Compatibility[Compatibility["EC2_AND_FARGATE"] = 2] = "EC2_AND_FARGATE"; /** * The task should specify the External launch type. */ Compatibility[Compatibility["EXTERNAL"] = 3] = "EXTERNAL"; })(Compatibility = exports.Compatibility || (exports.Compatibility = {})); /** * Return true if the given task definition can be run on an EC2 cluster */ function isEc2Compatible(compatibility) { return [Compatibility.EC2, Compatibility.EC2_AND_FARGATE].includes(compatibility); } exports.isEc2Compatible = isEc2Compatible; /** * Return true if the given task definition can be run on a Fargate cluster */ function isFargateCompatible(compatibility) { return [Compatibility.FARGATE, Compatibility.EC2_AND_FARGATE].includes(compatibility); } exports.isFargateCompatible = isFargateCompatible; /** * Return true if the given task definition can be run on a ECS Anywhere cluster */ function isExternalCompatible(compatibility) { return [Compatibility.EXTERNAL].includes(compatibility); } exports.isExternalCompatible = isExternalCompatible; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGFzay1kZWZpbml0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsidGFzay1kZWZpbml0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLHdDQUF3QztBQUN4Qyx3Q0FBd0M7QUFDeEMsd0NBQStFO0FBRS9FLGtFQUFpSDtBQUNqSCxvREFBcUQ7QUFDckQsZ0VBQXNKO0FBQ3RKLGtFQUE2RDtBQUk3RCwyRUFBcUU7QUF1UHJFLE1BQWUsa0JBQW1CLFNBQVEsZUFBUTtJQVFoRDs7T0FFRztJQUNILElBQVcsZUFBZTtRQUN4QixPQUFPLGVBQWUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7S0FDNUM7SUFFRDs7T0FFRztJQUNILElBQVcsbUJBQW1CO1FBQzVCLE9BQU8sbUJBQW1CLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0tBQ2hEO0lBRUQ7O09BRUc7SUFDSCxJQUFXLG9CQUFvQjtRQUM3QixPQUFPLG9CQUFvQixDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztLQUNqRDtDQUNGO0FBRUQ7O0dBRUc7QUFDSCxNQUFhLGNBQWUsU0FBUSxrQkFBa0I7SUE0RnBEOztPQUVHO0lBQ0gsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxLQUEwQjtRQUNsRSxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBOUJuQjs7V0FFRztRQUNnQixlQUFVLEdBQUcsSUFBSSxLQUFLLEVBQXVCLENBQUM7UUFFakU7O1dBRUc7UUFDYyxZQUFPLEdBQWEsRUFBRSxDQUFDO1FBRXhDOztXQUVHO1FBQ2MseUJBQW9CLEdBQUcsSUFBSSxLQUFLLEVBQStELENBQUM7UUFFakg7O1dBRUc7UUFDYywyQkFBc0IsR0FBMkIsRUFBRSxDQUFDOzs7Ozs7K0NBcEYxRCxjQUFjOzs7O1FBa0d2QixJQUFJLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQyxNQUFNLElBQUksWUFBSyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENB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LCtDQUFHLENBQUE7SUFFSDs7T0FFRztJQUNILHVEQUFPLENBQUE7SUFFUDs7T0FFRztJQUNILHVFQUFlLENBQUE7SUFFZjs7T0FFRztJQUNILHlEQUFRLENBQUE7QUFDVixDQUFDLEVBcEJXLGFBQWEsR0FBYixxQkFBYSxLQUFiLHFCQUFhLFFBb0J4QjtBQW9CRDs7R0FFRztBQUNILFNBQWdCLGVBQWUsQ0FBQyxhQUE0QjtJQUMxRCxPQUFPLENBQUMsYUFBYSxDQUFDLEdBQUcsRUFBRSxhQUFhLENBQUMsZUFBZSxDQUFDLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0FBQ3BGLENBQUM7QUFGRCwwQ0FFQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsbUJBQW1CLENBQUMsYUFBNEI7SUFDOUQsT0FBTyxDQUFDLGFBQWEsQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDLGVBQWUsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxhQUFhLENBQUMsQ0FBQztBQUN4RixDQUFDO0FBRkQsa0RBRUM7QUFFRDs7R0FFRztBQUNILFNBQWdCLG9CQUFvQixDQUFDLGFBQTRCO0lBQy9ELE9BQU8sQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUMsUUFBUSxDQUFDLGFBQWEsQ0FBQyxDQUFDO0FBQzFELENBQUM7QUFGRCxvREFFQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCAqIGFzIGVjMiBmcm9tICdAYXdzLWNkay9hd3MtZWMyJztcbmltcG9ydCAqIGFzIGlhbSBmcm9tICdAYXdzLWNkay9hd3MtaWFtJztcbmltcG9ydCB7IElSZXNvdXJjZSwgTGF6eSwgTmFtZXMsIFBoeXNpY2FsTmFtZSwgUmVzb3VyY2UgfSBmcm9tICdAYXdzLWNkay9jb3JlJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgQ29udGFpbmVyRGVmaW5pdGlvbiwgQ29udGFpbmVyRGVmaW5pdGlvbk9wdGlvbnMsIFBvcnRNYXBwaW5nLCBQcm90b2NvbCB9IGZyb20gJy4uL2NvbnRhaW5lci1kZWZpbml0aW9uJztcbmltcG9ydCB7IENmblRhc2tEZWZpbml0aW9uIH0gZnJvbSAnLi4vZWNzLmdlbmVyYXRlZCc7XG5pbXBvcnQgeyBGaXJlbGVuc0xvZ1JvdXRlciwgRmlyZWxlbnNMb2dSb3V0ZXJEZWZpbml0aW9uT3B0aW9ucywgRmlyZWxlbnNMb2dSb3V0ZXJUeXBlLCBvYnRhaW5EZWZhdWx0Rmx1ZW50Qml0RUNSSW1hZ2UgfSBmcm9tICcuLi9maXJlbGVucy1sb2ctcm91dGVyJztcbmltcG9ydCB7IEF3c0xvZ0RyaXZlciB9IGZyb20gJy4uL2xvZy1kcml2ZXJzL2F3cy1sb2ctZHJpdmVyJztcbmltcG9ydCB7IFBsYWNlbWVudENvbnN0cmFpbnQgfSBmcm9tICcuLi9wbGFjZW1lbnQnO1xuaW1wb3J0IHsgUHJveHlDb25maWd1cmF0aW9uIH0gZnJvbSAnLi4vcHJveHktY29uZmlndXJhdGlvbi9wcm94eS1jb25maWd1cmF0aW9uJztcbmltcG9ydCB7IFJ1bnRpbWVQbGF0Zm9ybSB9IGZyb20gJy4uL3J1bnRpbWUtcGxhdGZvcm0nO1xuaW1wb3J0IHsgSW1wb3J0ZWRUYXNrRGVmaW5pdGlvbiB9IGZyb20gJy4vX2ltcG9ydGVkLXRhc2stZGVmaW5pdGlvbic7XG5cbi8qKlxuICogVGhlIGludGVyZmFjZSBmb3IgYWxsIHRhc2sgZGVmaW5pdGlvbnMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSVRhc2tEZWZpbml0aW9uIGV4dGVuZHMgSVJlc291cmNlIHtcbiAgLyoqXG4gICAqIEFSTiBvZiB0aGlzIHRhc2sgZGVmaW5pdGlvblxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICByZWFkb25seSB0YXNrRGVmaW5pdGlvbkFybjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBFeGVjdXRpb24gcm9sZSBmb3IgdGhpcyB0YXNrIGRlZmluaXRpb25cbiAgICovXG4gIHJlYWRvbmx5IGV4ZWN1dGlvblJvbGU/OiBpYW0uSVJvbGU7XG5cbiAgLyoqXG4gICAqIFdoYXQgbGF1bmNoIHR5cGVzIHRoaXMgdGFzayBkZWZpbml0aW9uIHNob3VsZCBiZSBjb21wYXRpYmxlIHdpdGguXG4gICAqL1xuICByZWFkb25seSBjb21wYXRpYmlsaXR5OiBDb21wYXRpYmlsaXR5O1xuXG4gIC8qKlxuICAgKiBSZXR1cm4gdHJ1ZSBpZiB0aGUgdGFzayBkZWZpbml0aW9uIGNhbiBiZSBydW4gb24gYW4gRUMyIGNsdXN0ZXJcbiAgICovXG4gIHJlYWRvbmx5IGlzRWMyQ29tcGF0aWJsZTogYm9vbGVhbjtcblxuICAvKipcbiAgICogUmV0dXJuIHRydWUgaWYgdGhlIHRhc2sgZGVmaW5pdGlvbiBjYW4gYmUgcnVuIG9uIGEgRmFyZ2F0ZSBjbHVzdGVyXG4gICAqL1xuICByZWFkb25seSBpc0ZhcmdhdGVDb21wYXRpYmxlOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBSZXR1cm4gdHJ1ZSBpZiB0aGUgdGFzayBkZWZpbml0aW9uIGNhbiBiZSBydW4gb24gYSBFQ1MgQW55d2hlcmUgY2x1c3RlclxuICAgKi9cbiAgcmVhZG9ubHkgaXNFeHRlcm5hbENvbXBhdGlibGU6IGJvb2xlYW47XG5cblxuICAvKipcbiAgICogVGhlIG5ldHdvcmtpbmcgbW9kZSB0byB1c2UgZm9yIHRoZSBjb250YWluZXJzIGluIHRoZSB0YXNrLlxuICAgKi9cbiAgcmVhZG9ubHkgbmV0d29ya01vZGU6IE5ldHdvcmtNb2RlO1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgSUFNIHJvbGUgdGhhdCBncmFudHMgY29udGFpbmVycyBpbiB0aGUgdGFzayBwZXJtaXNzaW9uIHRvIGNhbGwgQVdTIEFQSXMgb24geW91ciBiZWhhbGYuXG4gICAqL1xuICByZWFkb25seSB0YXNrUm9sZTogaWFtLklSb2xlO1xufVxuXG4vKipcbiAqIFRoZSBjb21tb24gcHJvcGVydGllcyBmb3IgYWxsIHRhc2sgZGVmaW5pdGlvbnMuIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWVcbiAqIFtUYXNrIERlZmluaXRpb24gUGFyYW1ldGVyc10oaHR0cHM6Ly9kb2NzLmF3cy5hbWF6b24uY29tL0FtYXpvbkVDUy9sYXRlc3QvZGV2ZWxvcGVyZ3VpZGUvdGFza19kZWZpbml0aW9uX3BhcmFtZXRlcnMuaHRtbCkuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ29tbW9uVGFza0RlZmluaXRpb25Qcm9wcyB7XG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiBhIGZhbWlseSB0aGF0IHRoaXMgdGFzayBkZWZpbml0aW9uIGlzIHJlZ2lzdGVyZWQgdG8uIEEgZmFtaWx5IGdyb3VwcyBtdWx0aXBsZSB2ZXJzaW9ucyBvZiBhIHRhc2sgZGVmaW5pdGlvbi5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBdXRvbWF0aWNhbGx5IGdlbmVyYXRlZCBuYW1lLlxuICAgKi9cbiAgcmVhZG9ubHkgZmFtaWx5Pzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgbmFtZSBvZiB0aGUgSUFNIHRhc2sgZXhlY3V0aW9uIHJvbGUgdGhhdCBncmFudHMgdGhlIEVDUyBhZ2VudCBwZXJtaXNzaW9uIHRvIGNhbGwgQVdTIEFQSXMgb24geW91ciBiZWhhbGYuXG4gICAqXG4gICAqIFRoZSByb2xlIHdpbGwgYmUgdXNlZCB0byByZXRyaWV2ZSBjb250YWluZXIgaW1hZ2VzIGZyb20gRUNSIGFuZCBjcmVhdGUgQ2xvdWRXYXRjaCBsb2cgZ3JvdXBzLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEFuIGV4ZWN1dGlvbiByb2xlIHdpbGwgYmUgYXV0b21hdGljYWxseSBjcmVhdGVkIGlmIHlvdSB1c2UgRUNSIGltYWdlcyBpbiB5b3VyIHRhc2sgZGVmaW5pdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IGV4ZWN1dGlvblJvbGU/OiBpYW0uSVJvbGU7XG5cbiAgLyoqXG4gICAqIFRoZSBuYW1lIG9mIHRoZSBJQU0gcm9sZSB0aGF0IGdyYW50cyBjb250YWluZXJzIGluIHRoZSB0YXNrIHBlcm1pc3Npb24gdG8gY2FsbCBBV1MgQVBJcyBvbiB5b3VyIGJlaGFsZi5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBBIHRhc2sgcm9sZSBpcyBhdXRvbWF0aWNhbGx5IGNyZWF0ZWQgZm9yIHlvdS5cbiAgICovXG4gIHJlYWRvbmx5IHRhc2tSb2xlPzogaWFtLklSb2xlO1xuXG4gIC8qKlxuICAgKiBUaGUgY29uZmlndXJhdGlvbiBkZXRhaWxzIGZvciB0aGUgQXBwIE1lc2ggcHJveHkuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gcHJveHkgY29uZmlndXJhdGlvbi5cbiAgICovXG4gIHJlYWRvbmx5IHByb3h5Q29uZmlndXJhdGlvbj86IFByb3h5Q29uZmlndXJhdGlvbjtcblxuICAvKipcbiAgICogVGhlIGxpc3Qgb2Ygdm9sdW1lIGRlZmluaXRpb25zIGZvciB0aGUgdGFzay4gRm9yIG1vcmUgaW5mb3JtYXRpb24sIHNlZVxuICAgKiBbVGFzayBEZWZpbml0aW9uIFBhcmFtZXRlciBWb2x1bWVzXShodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uRUNTL2xhdGVzdC9kZXZlbG9wZXJndWlkZS8vdGFza19kZWZpbml0aW9uX3BhcmFtZXRlcnMuaHRtbCN2b2x1bWVzKS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyB2b2x1bWVzIGFyZSBwYXNzZWQgdG8gdGhlIERvY2tlciBkYWVtb24gb24gYSBjb250YWluZXIgaW5zdGFuY2UuXG4gICAqL1xuICByZWFkb25seSB2b2x1bWVzPzogVm9sdW1lW107XG59XG5cbi8qKlxuICogVGhlIHByb3BlcnRpZXMgZm9yIHRhc2sgZGVmaW5pdGlvbnMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgVGFza0RlZmluaXRpb25Qcm9wcyBleHRlbmRzIENvbW1vblRhc2tEZWZpbml0aW9uUHJvcHMge1xuICAvKipcbiAgICogVGhlIG5ldHdvcmtpbmcgbW9kZSB0byB1c2UgZm9yIHRoZSBjb250YWluZXJzIGluIHRoZSB0YXNrLlxuICAgKlxuICAgKiBPbiBGYXJnYXRlLCB0aGUgb25seSBzdXBwb3J0ZWQgbmV0d29ya2luZyBtb2RlIGlzIEF3c1ZwYy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBOZXR3b3JrTW9kZS5CcmlkZ2UgZm9yIEVDMiAmIEV4dGVybmFsIHRhc2tzLCBBd3NWcGMgZm9yIEZhcmdhdGUgdGFza3MuXG4gICAqL1xuICByZWFkb25seSBuZXR3b3JrTW9kZT86IE5ldHdvcmtNb2RlO1xuXG4gIC8qKlxuICAgKiBUaGUgcGxhY2VtZW50IGNvbnN0cmFpbnRzIHRvIHVzZSBmb3IgdGFza3MgaW4gdGhlIHNlcnZpY2UuXG4gICAqXG4gICAqIFlvdSBjYW4gc3BlY2lmeSBhIG1heGltdW0gb2YgMTAgY29uc3RyYWludHMgcGVyIHRhc2sgKHRoaXMgbGltaXQgaW5jbHVkZXNcbiAgICogY29uc3RyYWludHMgaW4gdGhlIHRhc2sgZGVmaW5pdGlvbiBhbmQgdGhvc2Ugc3BlY2lmaWVkIGF0IHJ1biB0aW1lKS5cbiAgICpcbiAgICogTm90IHN1cHBvcnRlZCBpbiBGYXJnYXRlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIHBsYWNlbWVudCBjb25zdHJhaW50cy5cbiAgICovXG4gIHJlYWRvbmx5IHBsYWNlbWVudENvbnN0cmFpbnRzPzogUGxhY2VtZW50Q29uc3RyYWludFtdO1xuXG4gIC8qKlxuICAgKiBUaGUgdGFzayBsYXVuY2ggdHlwZSBjb21wYXRpYmxpdHkgcmVxdWlyZW1lbnQuXG4gICAqL1xuICByZWFkb25seSBjb21wYXRpYmlsaXR5OiBDb21wYXRpYmlsaXR5O1xuXG4gIC8qKlxuICAgKiBUaGUgbnVtYmVyIG9mIGNwdSB1bml0cyB1c2VkIGJ5IHRoZSB0YXNrLlxuICAgKlxuICAgKiBJZiB5b3UgYXJlIHVzaW5nIHRoZSBFQzIgbGF1bmNoIHR5cGUsIHRoaXMgZmllbGQgaXMgb3B0aW9uYWwgYW5kIGFueSB2YWx1ZSBjYW4gYmUgdXNlZC5cbiAgICogSWYgeW91IGFyZSB1c2luZyB0aGUgRmFyZ2F0ZSBsYXVuY2ggdHlwZSwgdGhpcyBmaWVsZCBpcyBy