token-injectable-docker-builder
Version:
The TokenInjectableDockerBuilder is a flexible AWS CDK construct that enables the usage of AWS CDK tokens in the building, pushing, and deployment of Docker images to Amazon Elastic Container Registry (ECR). It leverages AWS CodeBuild and Lambda custom re
339 lines • 58.8 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.TokenInjectableDockerBuilder = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const crypto = require("crypto");
const aws_cdk_lib_1 = require("aws-cdk-lib");
const aws_codebuild_1 = require("aws-cdk-lib/aws-codebuild");
const aws_ecr_1 = require("aws-cdk-lib/aws-ecr");
const aws_ecs_1 = require("aws-cdk-lib/aws-ecs");
const aws_iam_1 = require("aws-cdk-lib/aws-iam");
const aws_kms_1 = require("aws-cdk-lib/aws-kms");
const aws_lambda_1 = require("aws-cdk-lib/aws-lambda");
const aws_s3_assets_1 = require("aws-cdk-lib/aws-s3-assets");
const constructs_1 = require("constructs");
const build_spec_1 = require("./build-spec");
const constants_1 = require("./constants");
const ecr_1 = require("./ecr");
const provider_1 = require("./provider");
/**
* A CDK construct to build and push Docker images to an ECR repository using
* CodeBuild and Lambda custom resources, **then** retrieve the final image tag
* so that ECS/Lambda references use the exact built image.
*/
class TokenInjectableDockerBuilder extends constructs_1.Construct {
constructor(scope, id, props) {
super(scope, id);
const { path: sourcePath, buildArgs, dockerLoginSecretArn, vpc, securityGroups, subnetSelection, installCommands, preBuildCommands, kmsEncryption = false, exclude, file: dockerFile, cacheDisabled = false, buildLogGroup, platform = 'linux/amd64', provider, ecrPullThroughCachePrefixes, retainBuildLogs = false, replicaRegions = [], } = props;
const stack = aws_cdk_lib_1.Stack.of(this);
this.primaryRegion = stack.region;
this.accountId = stack.account;
this.replicaRegions = [...replicaRegions];
const encryptionKey = kmsEncryption
? new aws_kms_1.Key(this, 'EcrEncryptionKey', { enableKeyRotation: true })
: undefined;
this.ecrRepository = (0, ecr_1.createBuilderEcrRepository)(this, 'ECRRepository', {
kmsEncryption,
encryptionKey,
});
const dockerFileName = dockerFile ?? 'Dockerfile';
const effectiveExclude = (0, build_spec_1.resolveExcludes)(sourcePath, dockerFileName, exclude);
const sourceAsset = new aws_s3_assets_1.Asset(this, 'SourceAsset', {
path: sourcePath,
exclude: effectiveExclude,
});
// Deterministic image tag: a hash of every input that materially affects
// the built image. Stable across synths → no spurious rebuilds, and
// cross-region SSM exports don't churn between deploys (which used to
// wedge the CDK CrossRegionExportReader/Writer when a deploy was retried
// after a rollback).
const imageTag = crypto.createHash('sha256').update(JSON.stringify({
assetHash: sourceAsset.assetHash,
dockerFile: dockerFileName,
buildArgs: buildArgs ?? {},
platform,
installCommands: installCommands ?? [],
preBuildCommands: preBuildCommands ?? [],
cacheDisabled,
dockerLoginSecretArn: dockerLoginSecretArn ?? null,
ecrPullThroughCachePrefixes: ecrPullThroughCachePrefixes ?? [],
})).digest('hex');
const buildSpecObj = (0, build_spec_1.buildBuildSpec)({
imageTag,
dockerFile,
buildArgs,
dockerLoginSecretArn,
installCommands,
preBuildCommands,
cacheDisabled,
platform,
});
const codeBuildImage = platform === 'linux/arm64'
? aws_codebuild_1.LinuxArmBuildImage.AMAZON_LINUX_2_STANDARD_3_0
: aws_codebuild_1.LinuxBuildImage.STANDARD_7_0;
const codeBuildProject = new aws_codebuild_1.Project(this, 'CodeBuildProject', {
source: aws_codebuild_1.Source.s3({
bucket: sourceAsset.bucket,
path: sourceAsset.s3ObjectKey,
}),
environment: {
buildImage: codeBuildImage,
privileged: true,
},
environmentVariables: {
ECR_REPO_URI: { value: this.ecrRepository.repositoryUri },
},
buildSpec: aws_codebuild_1.BuildSpec.fromObject(buildSpecObj),
...(buildLogGroup && {
logging: { cloudWatch: { logGroup: buildLogGroup } },
}),
vpc,
securityGroups,
subnetSelection,
});
this.grantBuildLogsAccess(codeBuildProject, retainBuildLogs);
this.grantEcrAccess(codeBuildProject);
this.grantPullThroughCacheAccess(codeBuildProject, ecrPullThroughCachePrefixes);
if (dockerLoginSecretArn) {
codeBuildProject.addToRolePolicy(new aws_iam_1.PolicyStatement({
actions: ['secretsmanager:GetSecretValue'],
resources: [dockerLoginSecretArn],
}));
}
if (encryptionKey) {
encryptionKey.grantEncryptDecrypt(codeBuildProject.role);
}
const effectiveProvider = provider ?? provider_1.TokenInjectableDockerBuilderProvider.getOrCreate(this);
effectiveProvider.registerProject(codeBuildProject, this.ecrRepository, encryptionKey);
if (replicaRegions.length > 0) {
this.validateReplicaRegions(replicaRegions);
effectiveProvider.registerReplication(this.ecrRepository.repositoryName, replicaRegions);
}
// The CR's construct ID has a "V2" suffix so that a v1-deployed stack
// upgrading to v2 sees a NEW resource (Replace), not an in-place update
// of the old `BuildTriggerResource`. CloudFormation forbids modifying a
// custom resource's `ServiceToken` in-place ("Modifying service token is
// not allowed."), and the serviceToken changes from v1's per-instance
// provider to v2's singleton provider. Replace dodges the constraint:
// the old CR is deleted, and a new one is created with the singleton's
// serviceToken — at the cost of one fresh build per builder on upgrade.
const buildTriggerResource = new aws_cdk_lib_1.CustomResource(this, 'BuildTriggerResourceV2', {
serviceToken: effectiveProvider.serviceToken,
properties: {
ProjectName: codeBuildProject.projectName,
ImageTag: imageTag,
Trigger: sourceAsset.assetHash,
RetainBuildLogs: retainBuildLogs ? 'true' : 'false',
RepositoryName: this.ecrRepository.repositoryName,
ReplicaRegions: JSON.stringify(replicaRegions),
},
});
buildTriggerResource.node.addDependency(codeBuildProject);
// SAFETY: reference by tag, not digest. The lifecycle policy above never
// deletes tagged images, so the digest behind this tag is guaranteed to
// remain in ECR for the life of the repository.
const imageTagRef = buildTriggerResource.getAttString('ImageTag');
this.imageTag = imageTagRef;
// Plain synth-time form, used by cross-region helpers to bypass CDK's
// CrossRegionExportWriter (see imageTagPlain docs).
this.imageTagPlain = imageTag;
this.repositoryName = this.ecrRepository.repositoryName;
this.containerImage = aws_ecs_1.ContainerImage.fromEcrRepository(this.ecrRepository, imageTagRef);
this.dockerImageCode = aws_lambda_1.DockerImageCode.fromEcr(this.ecrRepository, {
tagOrDigest: imageTagRef,
});
}
/**
* Format the ECR repository URI for a given region. The region must
* be either the primary region or one of `replicaRegions`.
*/
repositoryUriFor(region) {
this.assertRegionIsKnown(region);
return `${this.accountId}.dkr.ecr.${region}.amazonaws.com/${this.repositoryName}`;
}
/**
* Import the replicated repository as an ECS-compatible
* `ContainerImage` in a consumer scope (typically a stack in `region`).
*
* The consumer's stack must have `crossRegionReferences: true` when
* `region` differs from the builder's region.
*
* Cross-stack consumers (same region or different region) receive
* `imageTagPlain` (a synth-time string) rather than `imageTag` (a CFN
* token). Using the token would cause CDK to auto-create either a
* `CrossRegionExportWriter` (cross-region) or a cross-stack
* `Fn::Export` / `Fn::ImportValue` (same-region). Both wedge any deploy
* that changes the imageTag value, because CFN refuses to "update an
* export in use" or runs the writer's "Some exports have changed" check.
* Same-stack callers keep the token form so the Lambda still has a CFN
* dependency on the build trigger CR.
*/
containerImageFor(scope, region) {
this.assertRegionIsKnown(region);
const tag = this.tagForScope(scope);
return aws_ecs_1.ContainerImage.fromEcrRepository(this.importRepoFor(scope, region), tag);
}
/**
* Import the replicated repository as a Lambda-compatible
* `DockerImageCode` in a consumer scope (typically a stack in `region`).
*
* The consumer's stack must have `crossRegionReferences: true` when
* `region` differs from the builder's region.
*
* Cross-stack consumers (same region or different region) receive
* `imageTagPlain` (a synth-time string) rather than `imageTag` (a CFN
* token). See `containerImageFor` for the rationale.
*/
dockerImageCodeFor(scope, region) {
this.assertRegionIsKnown(region);
const tag = this.tagForScope(scope);
return aws_lambda_1.DockerImageCode.fromEcr(this.importRepoFor(scope, region), { tagOrDigest: tag });
}
/**
* Pick which tag form to hand to a cross-stack consumer:
* - same stack as the builder → CFN-token form (`imageTag`), preserves
* the CFN dependency from the consumer onto the build trigger CR.
* - different stack → synth-time plain string (`imageTagPlain`),
* so CDK doesn't auto-generate a cross-stack export/import or a
* `CrossRegionExportWriter`. Both would wedge on tag changes.
*
* For cross-stack same-region consumers in the same CDK app we also wire
* an explicit `Stack.addDependency`, since dropping the CFN export removes
* the implicit deploy ordering. Cross-region consumers in the same app
* are ordered by their CDK Stage / pipeline; cross-app consumers (e.g.
* separate pipelines) own their own orchestration.
*/
tagForScope(scope) {
const consumerStack = aws_cdk_lib_1.Stack.of(scope);
const producerStack = aws_cdk_lib_1.Stack.of(this);
if (consumerStack === producerStack) {
return this.imageTag;
}
if (consumerStack.account === producerStack.account &&
consumerStack.region === producerStack.region &&
consumerStack.node.root === producerStack.node.root) {
consumerStack.addDependency(producerStack);
}
return this.imageTagPlain;
}
importRepoFor(scope, region) {
this.assertRegionIsKnown(region);
if (region === this.primaryRegion)
return this.ecrRepository;
// Include the builder's own node.addr in the import id so two different
// builders importing the same region into the same scope each get their
// own Repository child (otherwise the second call would collide with the
// first and return the wrong builder's repo).
const importId = `ImportedRepo${region}${this.node.addr}`;
const existing = scope.node.tryFindChild(importId);
if (existing)
return existing;
return aws_ecr_1.Repository.fromRepositoryAttributes(scope, importId, {
repositoryName: this.repositoryName,
repositoryArn: aws_cdk_lib_1.Stack.of(scope).formatArn({
service: 'ecr',
resource: 'repository',
resourceName: this.repositoryName,
region,
account: this.accountId,
}),
});
}
assertRegionIsKnown(region) {
if (region === this.primaryRegion)
return;
if (this.replicaRegions.includes(region))
return;
throw new Error(`Region "${region}" is not the primary region (${this.primaryRegion}) ` +
`or one of the configured replicaRegions (${this.replicaRegions.join(', ') || '<none>'}). ` +
'Add the region to the builder\'s replicaRegions prop to make it available.');
}
validateReplicaRegions(replicaRegions) {
const stack = aws_cdk_lib_1.Stack.of(this);
const primaryPartition = stack.partition;
for (const region of replicaRegions) {
if (region === this.primaryRegion) {
throw new Error(`replicaRegions cannot include the primary region "${this.primaryRegion}". ` +
'Remove it from the list.');
}
// Partition cannot be cleanly inferred from region alone at synth time
// (it's a CDK pseudo-parameter and may be a token). We do the best-effort
// check: if both partition values are concrete and they differ, fail.
// Cross-partition replication is unsupported by ECR.
if (!aws_cdk_lib_1.Token.isUnresolved(primaryPartition)) {
const expectedPartition = inferPartition(region);
if (expectedPartition && expectedPartition !== primaryPartition) {
throw new Error('Cross-partition ECR replication is not supported. ' +
`Primary partition is "${primaryPartition}" but replica region ` +
`"${region}" appears to be in partition "${expectedPartition}".`);
}
}
}
}
grantEcrAccess(project) {
this.ecrRepository.grantPullPush(project);
project.addToRolePolicy(new aws_iam_1.PolicyStatement({
actions: [
'ecr:GetAuthorizationToken',
'ecr:GetDownloadUrlForLayer',
'ecr:BatchCheckLayerAvailability',
'ecr:BatchGetImage',
// DescribeImages: pre_build probes for the :cache tag's existence
// and only attaches --cache-from when it exists; without this
// permission the probe AccessDenies and the build crashes.
'ecr:DescribeImages',
],
resources: ['*'],
}));
}
grantPullThroughCacheAccess(project, prefixes) {
if (!prefixes || prefixes.length === 0)
return;
const stack = aws_cdk_lib_1.Stack.of(this);
project.addToRolePolicy(new aws_iam_1.PolicyStatement({
actions: [
'ecr:BatchGetImage',
'ecr:GetDownloadUrlForLayer',
'ecr:BatchCheckLayerAvailability',
'ecr:BatchImportUpstreamImage',
'ecr:CreateRepository',
],
resources: prefixes.map((prefix) => `arn:aws:ecr:${stack.region}:${stack.account}:repository/${prefix}/*`),
}));
}
grantBuildLogsAccess(project, retainBuildLogs) {
if (!retainBuildLogs)
return;
const stack = aws_cdk_lib_1.Stack.of(this);
project.addToRolePolicy(new aws_iam_1.PolicyStatement({
actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
resources: [
`arn:aws:logs:${stack.region}:${stack.account}:log-group:${constants_1.BUILD_LOG_GROUP_PREFIX}${project.projectName}`,
`arn:aws:logs:${stack.region}:${stack.account}:log-group:${constants_1.BUILD_LOG_GROUP_PREFIX}${project.projectName}:*`,
],
}));
}
}
exports.TokenInjectableDockerBuilder = TokenInjectableDockerBuilder;
_a = JSII_RTTI_SYMBOL_1;
TokenInjectableDockerBuilder[_a] = { fqn: "token-injectable-docker-builder.TokenInjectableDockerBuilder", version: "2.0.4" };
/**
* Best-effort partition inference from an AWS region name. Returns
* undefined if the region doesn't look like a known partition prefix —
* callers should treat that as "skip the partition check".
*/
function inferPartition(region) {
if (region.startsWith('cn-'))
return 'aws-cn';
if (region.startsWith('us-gov-'))
return 'aws-us-gov';
if (region.startsWith('us-iso-'))
return 'aws-iso';
if (region.startsWith('us-isob-'))
return 'aws-iso-b';
if (/^[a-z]{2}-[a-z]+-\d+$/.test(region))
return 'aws';
return undefined;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9idWlsZGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7O0FBQUEsaUNBQWlDO0FBRWpDLDZDQUEyRDtBQUMzRCw2REFNbUM7QUFFbkMsaURBQWlEO0FBQ2pELGlEQUFxRDtBQUNyRCxpREFBc0Q7QUFDdEQsaURBQTBDO0FBQzFDLHVEQUF5RDtBQUV6RCw2REFBa0Q7QUFDbEQsMkNBQXVDO0FBRXZDLDZDQUErRDtBQUMvRCwyQ0FBcUQ7QUFDckQsK0JBQW1EO0FBQ25ELHlDQUFrRTtBQTBLbEU7Ozs7R0FJRztBQUNILE1BQWEsNEJBQTZCLFNBQVEsc0JBQVM7SUEwQ3pELFlBQVksS0FBZ0IsRUFBRSxFQUFVLEVBQUUsS0FBd0M7UUFDaEYsS0FBSyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVqQixNQUFNLEVBQ0osSUFBSSxFQUFFLFVBQVUsRUFDaEIsU0FBUyxFQUNULG9CQUFvQixFQUNwQixHQUFHLEVBQ0gsY0FBYyxFQUNkLGVBQWUsRUFDZixlQUFlLEVBQ2YsZ0JBQWdCLEVBQ2hCLGFBQWEsR0FBRyxLQUFLLEVBQ3JCLE9BQU8sRUFDUCxJQUFJLEVBQUUsVUFBVSxFQUNoQixhQUFhLEdBQUcsS0FBSyxFQUNyQixhQUFhLEVBQ2IsUUFBUSxHQUFHLGFBQWEsRUFDeEIsUUFBUSxFQUNSLDJCQUEyQixFQUMzQixlQUFlLEdBQUcsS0FBSyxFQUN2QixjQUFjLEdBQUcsRUFBRSxHQUNwQixHQUFHLEtBQUssQ0FBQztRQUVWLE1BQU0sS0FBSyxHQUFHLG1CQUFLLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzdCLElBQUksQ0FBQyxhQUFhLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQztRQUNsQyxJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUM7UUFDL0IsSUFBSSxDQUFDLGNBQWMsR0FBRyxDQUFDLEdBQUcsY0FBYyxD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QUFJLEtBQUssQ0FBQyxPQUFPLGNBQWMsa0NBQXNCLEdBQUcsT0FBTyxDQUFDLFdBQVcsRUFBRTtnQkFDekcsZ0JBQWdCLEtBQUssQ0FBQyxNQUFNLElBQUksS0FBSyxDQUFDLE9BQU8sY0FBYyxrQ0FBc0IsR0FBRyxPQUFPLENBQUMsV0FBVyxJQUFJO2FBQzVHO1NBQ0YsQ0FBQyxDQUNILENBQUM7SUFDSixDQUFDOztBQXhZSCxvRUF5WUM7OztBQUVEOzs7O0dBSUc7QUFDSCxTQUFTLGNBQWMsQ0FBQyxNQUFjO0lBQ3BDLElBQUksTUFBTSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUM7UUFBRSxPQUFPLFFBQVEsQ0FBQztJQUM5QyxJQUFJLE1BQU0sQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDO1FBQUUsT0FBTyxZQUFZLENBQUM7SUFDdEQsSUFBSSxNQUFNLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQztRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ25ELElBQUksTUFBTSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUM7UUFBRSxPQUFPLFdBQVcsQ0FBQztJQUN0RCxJQUFJLHVCQUF1QixDQUFDLElBQUksQ0FBQyxNQUFNLENBQUM7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUN2RCxPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY3J5cHRvIGZyb20gJ2NyeXB0byc7XG5cbmltcG9ydCB7IEN1c3RvbVJlc291cmNlLCBTdGFjaywgVG9rZW4gfSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQge1xuICBQcm9qZWN0LFxuICBTb3VyY2UsXG4gIExpbnV4QnVpbGRJbWFnZSxcbiAgTGludXhBcm1CdWlsZEltYWdlLFxuICBCdWlsZFNwZWMsXG59IGZyb20gJ2F3cy1jZGstbGliL2F3cy1jb2RlYnVpbGQnO1xuaW1wb3J0IHsgSVZwYywgSVNlY3VyaXR5R3JvdXAsIFN1Ym5ldFNlbGVjdGlvbiB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1lYzInO1xuaW1wb3J0IHsgUmVwb3NpdG9yeSB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1lY3InO1xuaW1wb3J0IHsgQ29udGFpbmVySW1hZ2UgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtZWNzJztcbmltcG9ydCB7IFBvbGljeVN0YXRlbWVudCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1pYW0nO1xuaW1wb3J0IHsgS2V5IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLWttcyc7XG5pbXBvcnQgeyBEb2NrZXJJbWFnZUNvZGUgfSBmcm9tICdhd3MtY2RrLWxpYi9hd3MtbGFtYmRhJztcbmltcG9ydCB7IElMb2dHcm91cCB9IGZyb20gJ2F3cy1jZGstbGliL2F3cy1sb2dzJztcbmltcG9ydCB7IEFzc2V0IH0gZnJvbSAnYXdzLWNkay1saWIvYXdzLXMzLWFzc2V0cyc7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcblxuaW1wb3J0IHsgYnVpbGRCdWlsZFNwZWMsIHJlc29sdmVFeGNsdWRlcyB9IGZyb20gJy4vYnVpbGQtc3BlYyc7XG5pbXBvcnQgeyBCVUlMRF9MT0dfR1JPVVBfUFJFRklYIH0gZnJvbSAnLi9jb25zdGFudHMnO1xuaW1wb3J0IHsgY3JlYXRlQnVpbGRlckVjclJlcG9zaXRvcnkgfSBmcm9tICcuL2Vjcic7XG5pbXBvcnQgeyBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvdmlkZXIgfSBmcm9tICcuL3Byb3ZpZGVyJztcblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciB0aGUgYFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJgIGNvbnN0cnVjdC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvcHMge1xuICAvKipcbiAgICogVGhlIHBhdGggdG8gdGhlIGRpcmVjdG9yeSBjb250YWluaW5nIHRoZSBEb2NrZXJmaWxlIG9yIHNvdXJjZSBjb2RlLlxuICAgKi9cbiAgcmVhZG9ubHkgcGF0aDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBCdWlsZCBhcmd1bWVudHMgdG8gcGFzcyB0byB0aGUgRG9ja2VyIGJ1aWxkIHByb2Nlc3MuXG4gICAqIFRoZXNlIGFyZSB0cmFuc2Zvcm1lZCBpbnRvIGAtLWJ1aWxkLWFyZyBLRVk9VkFMVUVgIGZsYWdzLlxuICAgKiBAZXhhbXBsZVxuICAgKiB7XG4gICAqICAgVE9LRU46ICdteS1zZWNyZXQtdG9rZW4nLFxuICAgKiAgIEVOVjogJ3Byb2R1Y3Rpb24nXG4gICAqIH1cbiAgICovXG4gIHJlYWRvbmx5IGJ1aWxkQXJncz86IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH07XG5cbiAgLyoqXG4gICAqIFRoZSBBUk4gb2YgdGhlIEFXUyBTZWNyZXRzIE1hbmFnZXIgc2VjcmV0IGNvbnRhaW5pbmcgRG9ja2VyIGxvZ2luIGNyZWRlbnRpYWxzLlxuICAgKiBUaGUgc2VjcmV0IG11c3Qgc3RvcmUgYSBKU09OIG9iamVjdDogYHtcInVzZXJuYW1lXCI6XCIuLi5cIixcInBhc3N3b3JkXCI6XCIuLi5cIn1gLlxuICAgKiBNdXN0IGJlIGluIHRoZSBzYW1lIHJlZ2lvbiBhcyB0aGUgc3RhY2suXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gRG9ja2VyIEh1YiBsb2dpbi5cbiAgICovXG4gIHJlYWRvbmx5IGRvY2tlckxvZ2luU2VjcmV0QXJuPzogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgVlBDIGluIHdoaWNoIHRoZSBDb2RlQnVpbGQgcHJvamVjdCB3aWxsIGJlIGRlcGxveWVkLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIENvZGVCdWlsZCB1c2VzIHB1YmxpYyBpbnRlcm5ldC5cbiAgICovXG4gIHJlYWRvbmx5IHZwYz86IElWcGM7XG5cbiAgLyoqXG4gICAqIFNlY3VyaXR5IGdyb3VwcyBhdHRhY2hlZCB0byB0aGUgQ29kZUJ1aWxkIHByb2plY3QuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gc2VjdXJpdHkgZ3JvdXBzIGF0dGFjaGVkLlxuICAgKi9cbiAgcmVhZG9ubHkgc2VjdXJpdHlHcm91cHM/OiBJU2VjdXJpdHlHcm91cFtdO1xuXG4gIC8qKlxuICAgKiBTdWJuZXQgc2VsZWN0aW9uIHdpdGhpbiB0aGUgVlBDLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIEFsbCBzdWJuZXRzIGluIHRoZSBWUEMuXG4gICAqL1xuICByZWFkb25seSBzdWJuZXRTZWxlY3Rpb24/OiBTdWJuZXRTZWxlY3Rpb247XG5cbiAgLyoqXG4gICAqIEN1c3RvbSBjb21tYW5kcyB0byBydW4gZHVyaW5nIHRoZSBpbnN0YWxsIHBoYXNlIG9mIENvZGVCdWlsZC5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBObyBhZGRpdGlvbmFsIGluc3RhbGwgY29tbWFuZHMuXG4gICAqL1xuICByZWFkb25seSBpbnN0YWxsQ29tbWFuZHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQ3VzdG9tIGNvbW1hbmRzIHRvIHJ1biBkdXJpbmcgdGhlIHByZV9idWlsZCBwaGFzZSBvZiBDb2RlQnVpbGQuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gTm8gYWRkaXRpb25hbCBwcmUtYnVpbGQgY29tbWFuZHMuXG4gICAqL1xuICByZWFkb25seSBwcmVCdWlsZENvbW1hbmRzPzogc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gZW5hYmxlIEtNUyBlbmNyeXB0aW9uIGZvciB0aGUgRUNSIHJlcG9zaXRvcnkuXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBrbXNFbmNyeXB0aW9uPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogRmlsZSBwYXRocyBpbiB0aGUgRG9ja2VyIGRpcmVjdG9yeSB0byBleGNsdWRlIGZyb20gdGhlIGJ1aWxkIGFzc2V0LlxuICAgKiBGYWxscyBiYWNrIHRvIGAuZG9ja2VyaWdub3JlYCBpZiBwcmVzZW50LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGZpbGUgcGF0aCBleGNsdXNpb25zLlxuICAgKi9cbiAgcmVhZG9ubHkgZXhjbHVkZT86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBOYW1lIG9mIHRoZSBEb2NrZXJmaWxlIChwYXNzZWQgYXMgYC1mYCkuXG4gICAqXG4gICAqIEBleGFtcGxlICdEb2NrZXJmaWxlLnByb2R1Y3Rpb24nXG4gICAqIEBkZWZhdWx0ICdEb2NrZXJmaWxlJ1xuICAgKi9cbiAgcmVhZG9ubHkgZmlsZT86IHN0cmluZztcblxuICAvKipcbiAgICogV2hlbiBgdHJ1ZWAsIGRpc2FibGVzIERvY2tlciBsYXllciBjYWNoaW5nLlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgY2FjaGVEaXNhYmxlZD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIENsb3VkV2F0Y2ggbG9nIGdyb3VwIGZvciBDb2RlQnVpbGQgYnVpbGQgbG9ncy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBDb2RlQnVpbGQgZGVmYXVsdCBsb2dnaW5nLlxuICAgKi9cbiAgcmVhZG9ubHkgYnVpbGRMb2dHcm91cD86IElMb2dHcm91cDtcblxuICAvKipcbiAgICogVGFyZ2V0IHBsYXRmb3JtIGZvciB0aGUgRG9ja2VyIGltYWdlLlxuICAgKlxuICAgKiBAZGVmYXVsdCAnbGludXgvYW1kNjQnXG4gICAqL1xuICByZWFkb25seSBwbGF0Zm9ybT86ICdsaW51eC9hbWQ2NCcgfCAnbGludXgvYXJtNjQnO1xuXG4gIC8qKlxuICAgKiBTaGFyZWQgcHJvdmlkZXIgZm9yIHRoZSBjdXN0b20gcmVzb3VyY2UgTGFtYmRhcy5cbiAgICpcbiAgICogUGFzcyBgVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlclByb3ZpZGVyLmdldE9yQ3JlYXRlKHRoaXMsIHsgcXVlcnlJbnRlcnZhbCB9KWBcbiAgICogaWYgeW91IG5lZWQgYSBub24tZGVmYXVsdCBxdWVyeSBpbnRlcnZhbC4gT3RoZXJ3aXNlLCB0aGUgY29uc3RydWN0IHdpbGxcbiAgICogY2FsbCBgZ2V0T3JDcmVhdGUodGhpcylgIGl0c2VsZiBhbmQgcmV1c2UgdGhlIHBlci1zdGFjayBzaW5nbGV0b24uXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gUGVyLXN0YWNrIHNpbmdsZXRvbiBwcm92aWRlciwgY3JlYXRlZCBvbiBmaXJzdCB1c2UuXG4gICAqL1xuICByZWFkb25seSBwcm92aWRlcj86IFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJQcm92aWRlcjtcblxuICAvKipcbiAgICogRUNSIHB1bGwtdGhyb3VnaCBjYWNoZSByZXBvc2l0b3J5IHByZWZpeGVzIHRvIGdyYW50IHB1bGwgYWNjZXNzIHRvLlxuICAgKlxuICAgKiBAZXhhbXBsZSBbJ2RvY2tlci1odWInLCAnZ2hjciddXG4gICAqIEBkZWZhdWx0IC0gTm8gcHVsbC10aHJvdWdoIGNhY2hlIGFjY2Vzcy5cbiAgICovXG4gIHJlYWRvbmx5IGVjclB1bGxUaHJvdWdoQ2FjaGVQcmVmaXhlcz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBXaGVuIGB0cnVlYCwgY3JlYXRlcyBhIENsb3VkV2F0Y2ggbG9nIGdyb3VwIG91dHNpZGUgb2YgQ2xvdWRGb3JtYXRpb25cbiAgICogKGAvZG9ja2VyLWJ1aWxkZXIvPHByb2plY3ROYW1lPmApIGFuZCBkaXJlY3RzIENvZGVCdWlsZCBvdXRwdXQgdGhlcmUuXG4gICAqIFN1cnZpdmVzIHN0YWNrIHJvbGxiYWNrcyBmb3IgZGVidWdnaW5nLiA3LWRheSByZXRlbnRpb24uXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSByZXRhaW5CdWlsZExvZ3M/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBZGRpdGlvbmFsIEFXUyByZWdpb25zIHRvIHJlcGxpY2F0ZSB0aGUgYnVpbHQgaW1hZ2UgdG8gdmlhIEVDUidzXG4gICAqIG5hdGl2ZSByZWdpc3RyeSByZXBsaWNhdGlvbi4gVGhlIGltYWdlIGlzIHB1c2hlZCB0byB0aGUgcHJpbWFyeVxuICAgKiByZWdpb24ncyBFQ1IgYXMgdXN1YWw7IEVDUiBhc3luY2hyb25vdXNseSByZXBsaWNhdGVzIHRoZSBzYW1lXG4gICAqIGByZXBvc2l0b3J5TmFtZWAgKyBgaW1hZ2VUYWdgIHRvIGVhY2ggcmVnaW9uIGxpc3RlZCBoZXJlLlxuICAgKlxuICAgKiBDb25zdW1lcnMgaW4gYW5vdGhlciByZWdpb24gKGEgTGFtYmRhIGluIGB1cy13ZXN0LTJgIHJlZmVyZW5jaW5nIGFuXG4gICAqIGltYWdlIGJ1aWx0IGluIGB1cy1lYXN0LTFgKSBjYW4gdXNlIGBkb2NrZXJJbWFnZUNvZGVGb3IocmVnaW9uKWAgb3JcbiAgICogYGNvbnRhaW5lckltYWdlRm9yKHJlZ2lvbilgIHRvIGltcG9ydCB0aGUgcmVwbGljYXRlZCBpbWFnZS5cbiAgICpcbiAgICogVGhlIGN1c3RvbSByZXNvdXJjZSB3YWl0cyBmb3IgcmVwbGljYXRpb24gdG8gY29tcGxldGUgYmVmb3JlXG4gICAqIHNpZ25hbGxpbmcgZGVwbG95LWNvbXBsZXRlLCBzbyBkb3duc3RyZWFtIHN0YWNrcyBjYW4gc2FmZWx5IGRlcGxveVxuICAgKiBpbW1lZGlhdGVseSBhZnRlci5cbiAgICpcbiAgICogKipDYXZlYXRzOioqXG4gICAqIC0gQ3Jvc3MtcmVnaW9uIHJlcGxpY2F0aW9uIGlzIG5vdCBzdXBwb3J0ZWQgYmV0d2VlbiBBV1MgcGFydGl0aW9ucy5cbiAgICogLSBSZXBsaWNhcyBkbyAqKm5vdCoqIGluaGVyaXQgdGhlIHByaW1hcnkncyBlbmNyeXB0aW9uIChkZWZhdWx0cyB0b1xuICAgKiAgIEFFUy0yNTYpLCBsaWZlY3ljbGUgcG9saWNpZXMsIG9yIHJlcG9zaXRvcnkgcG9saWNpZXMuXG4gICAqIC0gUmVwbGljYXRlZCByZXBvc2l0b3JpZXMgcGVyc2lzdCBvbiBzdGFjayBkZWxldGlvbiDigJQgQVdTIGRvZXMgbm90XG4gICAqICAgYXV0by1kZWxldGUgdGhlbS4gQ2xlYW4gdXAgbWFudWFsbHkgdmlhIHRoZSBFQ1IgY29uc29sZSAvIENMSSBpZlxuICAgKiAgIG5lZWRlZC5cbiAgICogLSBCb3RoIHRoZSBidWlsZGVyIHN0YWNrIGFuZCBhbnkgY29uc3VtZXIgc3RhY2sgaW4gYW5vdGhlciByZWdpb25cbiAgICogICBtdXN0IHNldCBgY3Jvc3NSZWdpb25SZWZlcmVuY2VzOiB0cnVlYCBmb3IgdGhlIGltYWdlIHRhZyB0byBmbG93LlxuICAgKiAtIFN0YWNrcyBtdXN0IGhhdmUgYSBjb25jcmV0ZSByZWdpb24gKGBlbnY6IHsgYWNjb3VudCwgcmVnaW9uIH1gKSxcbiAgICogICBub3QgdGhlIGVudi1hZ25vc3RpYyBkZWZhdWx0LlxuICAgKlxuICAgKiBAZXhhbXBsZSBbJ3VzLXdlc3QtMicsICdldS13ZXN0LTEnXVxuICAgKiBAZGVmYXVsdCBbXSAtIG5vIHJlcGxpY2F0aW9uXG4gICAqL1xuICByZWFkb25seSByZXBsaWNhUmVnaW9ucz86IHN0cmluZ1tdO1xufVxuXG4vKipcbiAqIEEgQ0RLIGNvbnN0cnVjdCB0byBidWlsZCBhbmQgcHVzaCBEb2NrZXIgaW1hZ2VzIHRvIGFuIEVDUiByZXBvc2l0b3J5IHVzaW5nXG4gKiBDb2RlQnVpbGQgYW5kIExhbWJkYSBjdXN0b20gcmVzb3VyY2VzLCAqKnRoZW4qKiByZXRyaWV2ZSB0aGUgZmluYWwgaW1hZ2UgdGFnXG4gKiBzbyB0aGF0IEVDUy9MYW1iZGEgcmVmZXJlbmNlcyB1c2UgdGhlIGV4YWN0IGJ1aWx0IGltYWdlLlxuICovXG5leHBvcnQgY2xhc3MgVG9rZW5JbmplY3RhYmxlRG9ja2VyQnVpbGRlciBleHRlbmRzIENvbnN0cnVjdCB7XG4gIC8qKiBUaGUgRUNSIHJlcG9zaXRvcnkgdGhhdCBzdG9yZXMgdGhlIHJlc3VsdGluZyBEb2NrZXIgaW1hZ2UuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgZWNyUmVwb3NpdG9yeTogUmVwb3NpdG9yeTtcblxuICAvKiogRUNTLWNvbXBhdGlibGUgY29udGFpbmVyIGltYWdlIHJlZmVyZW5jZSAocHJpbWFyeSByZWdpb24pLiAqL1xuICBwdWJsaWMgcmVhZG9ubHkgY29udGFpbmVySW1hZ2U6IENvbnRhaW5lckltYWdlO1xuXG4gIC8qKiBMYW1iZGEtY29tcGF0aWJsZSBEb2NrZXJJbWFnZUNvZGUgcmVmZXJlbmNlIChwcmltYXJ5IHJlZ2lvbikuICovXG4gIHB1YmxpYyByZWFkb25seSBkb2NrZXJJbWFnZUNvZGU6IERvY2tlckltYWdlQ29kZTtcblxuICAvKiogVGhlIEVDUiByZXBvc2l0b3J5IG5hbWUg4oCUIHByZXNlcnZlZCBhY3Jvc3MgcmVwbGljYSByZWdpb25zLiAqL1xuICBwdWJsaWMgcmVhZG9ubHkgcmVwb3NpdG9yeU5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIHJlc29sdmVkIGltYWdlIHRhZyAoQ0ZOIHRva2VuOyBhdmFpbGFibGUgYXQgZGVwbG95IHRpbWUpLlxuICAgKlxuICAgKiBTYWZlIHRvIHVzZSBhbnl3aGVyZSB0aGUgY29uc3VtZXIgaXMgaW4gdGhlICoqc2FtZSByZWdpb24qKiBhcyB0aGVcbiAgICogYnVpbGRlciAoc2FtZSBzdGFjayBvciBkaWZmZXJlbnQgc3RhY2spLiBGb3IgY3Jvc3MtcmVnaW9uIGNvbnN1bWVyc1xuICAgKiB1c2UgYGltYWdlVGFnUGxhaW5gIOKAlCBgaW1hZ2VUYWdgIHdvdWxkIHRyaWdnZXIgQ0RLJ3NcbiAgICogYENyb3NzUmVnaW9uRXhwb3J0V3JpdGVyYCBhbmQgd2VkZ2Ugb24gYW55IHRhZyBjaGFuZ2UuXG4gICAqL1xuICBwdWJsaWMgcmVhZG9ubHkgaW1hZ2VUYWc6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGRldGVybWluaXN0aWMgaW1hZ2UgdGFnIGFzIGEgcGxhaW4gc3ludGgtdGltZSBzdHJpbmcgKG5vIENGTiB0b2tlbikuXG4gICAqXG4gICAqIFNhbWUgdmFsdWUgYXMgYGltYWdlVGFnYCBidXQgcmVzb2x2ZWQgaW1tZWRpYXRlbHkg4oCUIHVzZWZ1bCBmb3IgY3Jvc3MtcmVnaW9uXG4gICAqIGNvbnN1bWVycywgd2hlcmUgdGhlIENGTi10b2tlbiBmb3JtIHdvdWxkIHRyaWdnZXIgQ0RLIHRvIGF1dG8tY3JlYXRlIGFcbiAgICogYENyb3NzUmVnaW9uRXhwb3J0V3JpdGVyYC4gVGhhdCB3cml0ZXIgaGFzIGFuIG92ZXItc3RyaWN0IHNhZmV0eSBjaGVja1xuICAgKiB0aGF0IGZhaWxzIGFueSB1cGRhdGUgd2hlcmUgdGhlIHRhZyB2YWx1ZSBjaGFuZ2VzIChpLmUuIGV2ZXJ5IHJlYWwgY29kZVxuICAgKiBjaGFuZ2UpLCB3ZWRnaW5nIHRoZSBzdGFjayBpbiBgVVBEQVRFX1JPTExCQUNLX0ZBSUxFRGAuXG4gICAqXG4gICAqIGBjb250YWluZXJJbWFnZUZvcmAgYW5kIGBkb2NrZXJJbWFnZUNvZGVGb3JgIHVzZSB0aGlzIHN0cmluZyBhdXRvbWF0aWNhbGx5XG4gICAqIHdoZW4gdGhlIGNvbnN1bWVyIHJlZ2lvbiBkaWZmZXJzIGZyb20gdGhlIHByaW1hcnkgcmVnaW9uLCBzbyBjYWxsZXJzXG4gICAqIG5vcm1hbGx5IGRvbid0IHJlZmVyZW5jZSB0aGlzIHByb3BlcnR5IGRpcmVjdGx5LlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGltYWdlVGFnUGxhaW46IHN0cmluZztcblxuICBwcml2YXRlIHJlYWRvbmx5IHByaW1hcnlSZWdpb246IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSBhY2NvdW50SWQ6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSByZXBsaWNhUmVnaW9uczogc3RyaW5nW107XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IFRva2VuSW5qZWN0YWJsZURvY2tlckJ1aWxkZXJQcm9wcykge1xuICAgIHN1cGVyKHNjb3BlLCBpZCk7XG5cbiAgICBjb25zdCB7XG4gICAgICBwYXRoOiBzb3VyY2VQYXRoLFxuICAgICAgYnVpbGRBcmdzLFxuICAgICAgZG9ja2VyTG9naW5TZWNyZXRBcm4sXG4gICAgICB2cGMsXG4gICAgICBzZWN1cml0eUdyb3VwcyxcbiAgICAgIHN1Ym5ldFNlbGVjdGlvbixcbiAgICAgIGluc3RhbGxDb21tYW5kcyxcbiAgICAgIHByZUJ1aWxkQ29tbWFuZHMsXG4gICAgICBrbXNFbmNyeXB0aW9uID0gZmFsc2UsXG4gICAgICBleGNsdWRlLFxuICAgICAgZmlsZTogZG9ja2VyRmlsZSxcbiAgICAgIGNhY2hlRGlzYWJsZWQgPSBmYWxzZSxcbiAgICAgIGJ1aWxkTG9nR3JvdXAsXG4gICAgICBwbGF0Zm9ybSA9ICdsaW51eC9hbWQ2NCcsXG4gICAgICBwcm92aWRlcixcbiAgICAgIGVjclB1bGxUaHJvdWdoQ2FjaGVQcmVmaXhlcyxcbiAgICAgIHJldGFpbkJ1aWxkTG9ncyA9IGZhbHNlLFxuICAgICAgcmVwbGljYVJlZ2lvbnMgPSBbXSxcbiAgICB9ID0gcHJvcHM7XG5cbiAgICBjb25zdCBzdGFjayA9IFN0YWNrLm9mKHRoaXMpO1xuICAgIHRoaXMucHJpbWFyeVJlZ2lvbiA9IHN0YWNrLnJlZ2lvbjtcbiAgICB0aGlzLmFjY291bnRJZCA9IHN0YWNrLmFjY291bnQ7XG4gICAgdGhpcy5yZXBsaWNhUmVnaW9ucyA9IFsuLi5yZXBsaWNhUmVnaW9uc107XG5cbiAgICBjb25zdCBlbmNyeXB0aW9uS2V5ID0ga21zRW5jcnlwdGlvblxuICAgICAgPyBuZXcgS2V5KHRoaXMsICdFY3JFbmNyeXB0aW9uS2V5JywgeyBlbmFibGVLZXlSb3RhdGlvbjogdHJ1ZSB9KVxuICAgICAgOiB1bmRlZmluZWQ7XG5cbiAgICB0aGlzLmVjclJlcG9zaXRvcnkgPSBjcmVhdGVCdWlsZGVyRWNyUmVwb3NpdG9yeSh0aGlzLCAnRUNSUmVwb3NpdG9yeScsIHtcbiAgICAgIGttc0VuY3J5cHRpb24sXG4gICAgICBlbmNyeXB0aW9uS2V5LFxuICAgIH0pO1xuXG4gICAgY29uc3QgZG9ja2VyRmlsZU5hbWUgPSBkb2NrZXJGaWxlID8/ICdEb2NrZXJmaWxlJztcbiAgICBjb25zdCBlZmZlY3RpdmVFeGNsdWRlID0gcmVzb2x2ZUV4Y2x1ZGVzKHNvdXJjZVBhdGgsIGRvY2tlckZpbGVOYW1lLCBleGNsdWRlKTtcblxuICAgIGNvbnN0IHNvdXJjZUFzc2V0ID0gbmV3IEFzc2V0KHRoaXMsICdTb3VyY2VBc3NldCcsIHtcbiAgICAgIHBhdGg6IHNvdXJjZVBhdGgsXG4gICAgICBleGNsdWRlOiBlZmZlY3RpdmVFeGNsdWRlLFxuICAgIH0pO1xuXG4gICAgLy8gRGV0ZXJtaW5pc3RpYyBpbWFnZSB0YWc6IGEgaGFzaCBvZiBldmVyeSBpbnB1dCB0aGF0IG1hdGVyaWFsbHkgYWZmZWN0c1xuICAgIC8vIHRoZSBidWlsdCBpbWFnZS4gU3RhYmxlIGFjcm9zcyBzeW50aHMg4oaSIG5vIHNwdXJpb3VzIHJlYnVpbGRzLCBhbmRcbiAgICAvLyBjcm9zcy1yZWdpb24gU1NNIGV4cG9ydHMgZG9uJ3QgY2h1cm4gYmV0d2VlbiBkZXBsb3lzICh3aGljaCB1c2VkIHRvXG4gICAgLy8gd2VkZ2UgdGhlIENESyBDcm9zc1JlZ2lvbkV4cG9ydFJlYWRlci9Xcml0ZXIgd2hlbiBhIGRlcGxveSB3YXMgcmV0cmllZFxuICAgIC8vIGFmdGVyIGEgcm9sbGJhY2spLlxuICAgIGNvbnN0IGltYWdlVGFnID0gY3J5cHRvLmNyZWF0ZUhhc2goJ3NoYTI1NicpLnVwZGF0ZShKU09OLnN0cmluZ2lmeSh7XG4gICAgICBhc3NldEhhc2g6IHNvdXJjZUFzc2V0LmFzc2V0SGFzaCxcbiAgICAgIGRvY2tlckZpbGU6IGRvY2tlckZpbGVOYW1lLFxuICAgICAgYnVpbGRBcmdzOiBidWlsZEFyZ3MgPz8ge30sXG4gICAgICBwbGF0Zm9ybSxcbiAgICAgIGluc3RhbGxDb21tYW5kczogaW5zdGFsbENvbW1hbmRzID8/IFtdLFxuICAgICAgcHJlQnVpbGRDb21tYW5kczogcHJlQnVpbGRDb21tYW5kcyA/PyBbXSxcbiAgICAgIGNhY2hlRGlzYWJsZWQsXG4gICAgICBkb2NrZXJMb2dpblNlY3JldEFybjogZG9ja2VyTG9naW5TZWNyZXRBcm4gPz8gbnVsbCxcbiAgICAgIGVjclB1bGxUaHJvdWdoQ2FjaGVQcmVmaXhlczogZWNyUHVsbFRocm91Z2hDYWNoZVByZWZpeGVzID8/IFtdLFxuICAgIH0pKS5kaWdlc3QoJ2hleCcpO1xuXG4gICAgY29uc3QgYnVpbGRTcGVjT2JqID0gYnVpbGRCdWlsZFNwZWMoe1xuICAgICAgaW1hZ2VUYWcsXG4gICAgICBkb2NrZXJGaWxlLFxuICAgICAgYnVpbGRBcmdzLFxuICAgICAgZG9ja2VyTG9naW5TZWNyZXRBcm4sXG4gICAgICBpbnN0YWxsQ29tbWFuZHMsXG4gICAgICBwcmVCdWlsZENvbW1hbmRzLFxuICAgICAgY2FjaGVEaXNhYmxlZCxcbiAgICAgIHBsYXRmb3JtLFxuICAgIH0pO1xuXG4gICAgY29uc3QgY29kZUJ1aWxkSW1hZ2UgPSBwbGF0Zm9ybSA9PT0gJ2xpbnV4L2FybTY0J1xuICAgICAgPyBMaW51eEFybUJ1aWxkSW1hZ2UuQU1BWk9OX0xJTlVYXzJfU1RBTkRBUkRfM18wXG4gICAgICA6IExpbnV4QnVpbGRJbWFnZS5TVEFOREFSRF83XzA7XG5cbiAgICBjb25zdCBjb2RlQnVpbGRQcm9qZWN0ID0gbmV3IFByb2plY3QodGhpcywgJ0NvZGVCdWlsZFByb2plY3QnLCB7XG4gICAgICBzb3VyY2U6IFNvdXJjZS5zMyh7XG4gICAgICAgIGJ1Y2tldDogc291cmNlQXNzZXQuYnVja2V0LFxuICAgICAgICBwYXRoOiBzb3VyY2VBc3NldC5zM09iamVjdEtleSxcbiAgICAgIH0pLFxuICAgICAgZW52aXJvbm1lbnQ6IHtcbiAgICAgICAgYnVpbGRJbWFnZTogY29kZUJ1aWxkSW1hZ2UsXG4gICAgICAgIHByaXZpbGVnZWQ6IHRydWUsXG4gICAgICB9LFxuICAgICAgZW52aXJvbm1lbnRWYXJpYWJsZXM6IHtcbiAgICAgICAgRUNSX1JFUE9fVVJJOiB7IHZhbHVlOiB0aGlzLmVjclJlcG9zaXRvcnkucmVwb3NpdG9yeVVyaSB9LFxuICAgICAgfSxcbiAgICAgIGJ1aWxkU3BlYzogQnVpbGRTcGVjLmZyb21PYmplY3QoYnVpbGRTcGVjT2JqKSxcbiAgICAgIC4uLihidWlsZExvZ0dyb3VwICYmIHtcbiAgICAgICAgbG9nZ2luZzogeyBjbG91ZFdhdGNoOiB7IGxvZ0dyb3VwOiBidWlsZExvZ0dyb3VwIH0gfSxcbiAgICAgIH0pLFxuICAgICAgdnBjLFxuICAgICAgc2VjdXJpdHlHcm91cHMsXG4gICAgICBzdWJuZXRTZWxlY3Rpb24sXG4gICAgfSk7XG5cbiAgICB0aGlzLmdyYW50QnVpbGRMb2dzQWNjZXNzKGNvZGVCdWlsZFByb2plY3QsIHJldGFpbkJ1aWxkTG9ncyk7XG4gICAgdGhpcy5ncmFudEVjckFjY2Vzcyhjb2RlQnVpbGRQcm9qZWN0KTtcbiAgICB0aGlzLmdyYW50UHVsbFRocm91Z2hDYWNoZUFjY2Vzcyhjb2RlQnVpbGRQcm9qZWN0LCBlY3JQdWxsVGhyb3VnaENhY2hlUHJlZml4ZXMpO1xuXG4gICAgaWYgKGRvY2tlckxvZ2luU2VjcmV0QXJuKSB7XG4gICAgICBjb2RlQnVpbGRQcm9qZWN0LmFkZFRvUm9sZVBvbGljeShcbiAgICAgICAgbmV3IFBvbGljeVN0YXRlbWVudCh7XG4gICAgICAgICAgYWN0aW9uczogWydzZWNyZXRzbWFuYWdlcjpHZXRTZWNyZXRWYWx1ZSddLFxuICAgICAgICAgIHJlc291cmNlczogW2RvY2tlckxvZ2luU2VjcmV0QXJuXSxcbiAgICAgICAgfSksXG4gICAgICApO1xuICAgIH1cblxuICAgIGlmIChlbmNyeXB0aW9uS2V5KSB7XG4gICAgICBlbmNyeXB0aW9uS2V5LmdyYW50RW5jcnlwdERlY3J5cHQoY29kZUJ1aWxkUHJvamVjdC5yb2xlISk7XG4gICAgfVxuXG4gICAgY29uc3QgZWZmZWN0aXZlUHJvdmlkZXIgPSBwcm92aWRlciA/PyBUb2tlbkluamVjdGFibGVEb2NrZXJCdWlsZGVyUHJvdmlkZXIuZ2V0T3JDcmVhdGUodGhpcyk7XG4gICAgZWZmZWN0aXZlUHJvdmlkZXIucmVnaXN0ZXJQcm9qZWN0KGNvZGVCdWlsZFByb2plY3QsIHRoaXMuZWNyUmVwb3NpdG9yeSwgZW5jcnlwdGlvbktleSk7XG5cbiAgICBpZiAocmVwbGljYVJlZ2lvbnMubGVuZ3RoID4gMCkge1xuICAgICAgdGhpcy52YWxpZGF0ZVJlcGxpY2FSZWdpb25zKHJlcGxpY2FSZWdpb25zKTtcbiAgICAgIGVmZmVjdGl2ZVByb3ZpZGVyLnJlZ2lzdGVyUmVwbGljYXRpb24odGhpcy5lY3JSZXBvc2l0b3J5LnJlcG9zaXRvcnlOYW1lLCByZXBsaWNhUmVnaW9ucyk7XG4gICAgfVxuXG4gICAgLy8gVGhlIENSJ3MgY29uc3RydWN0IElEIGhhcyBhIFwiVjJcIiBzdWZmaXggc28gdGhhdCBhIHYxLWRlcGxveWVkIHN0YWNrXG4gICAgLy8gdXBncmFkaW5nIHRvIHYyIHNlZXMgYSBORVcgcmVzb3VyY2UgKFJlcGxhY2UpLCBub3QgYW4gaW4tcGxhY2UgdXBkYXRlXG4gICAgLy8gb2YgdGhlIG9sZCBgQnVpbGRUcmlnZ2VyUmVzb3VyY2VgLiBDbG91ZEZvcm1hdGlvbiBmb3JiaWRzIG1vZGlmeWluZyBhXG4gICAgLy8gY3VzdG9tIHJlc291cmNlJ3MgYFNlcnZpY2VUb2tlbmAgaW4tcGxhY2UgKFwiTW9kaWZ5aW5nIHNlcnZpY2UgdG9rZW4gaXNcbiAgICAvLyBub3QgYWxsb3dlZC5cIiksIGFuZCB0aGUgc2VydmljZVRva2VuIGNoYW5nZXMgZnJvbSB2MSdzIHBlci1pbnN0YW5jZVxuICAgIC8vIHByb3ZpZGVyIHRvIHYyJ3Mgc2luZ2xldG9uIHByb3ZpZGVyLiBSZXBsYWNlIGRvZGdlcyB0aGUgY29uc3RyYWludDpcbiAgICAvLyB0aGUgb2xkIENSIGlzIGRlbGV0ZWQsIGFuZCBhIG5ldyBvbmUgaXMgY3JlYXRlZCB3aXRoIHRoZSBzaW5nbGV0b24nc1xuICAgIC8vIHNlcnZpY2VUb2tlbiDigJQgYXQgdGhlIGNvc3Qgb2Ygb25lIGZyZXNoIGJ1aWxkIHBlciBidWlsZGVyIG9uIHVwZ3JhZGUuXG4gICAgY29uc3QgYnVpbGRUcmlnZ2VyUmVzb3VyY2UgPSBuZXcgQ3VzdG9tUmVzb3VyY2UodGhpcywgJ0J1aWxkVHJpZ2dlclJlc291cmNlVjInLCB7XG4gICAgICBzZXJ2aWNlVG9rZW46IGVmZmVjdGl2ZVByb3ZpZGVyLnNlcnZpY2VUb2tlbixcbiAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgUHJvamVjdE5hbWU6IGNvZGVCdWlsZFByb2plY3QucHJvamVjdE5hbWUsXG4gICAgICAgIEltYWdlVGFnOiBpbWFnZVRhZyxcbiAgICAgICAgVHJpZ2dlcjogc291cmNlQXNzZXQuYXNzZXRIYXNoLFxuICAgICAgICBSZXRhaW5CdWlsZExvZ3M6IHJldGFpbkJ1aWxkTG9ncyA/ICd0cnVlJyA6ICdmYWxzZScsXG4gICAgICAgIFJlcG9zaXRvcnlOYW1lOiB0aGlzLmVjclJlcG9zaXRvcnkucmVwb3NpdG9yeU5hbWUsXG4gICAgICAgIFJlcGxpY2FSZWdpb25zOiBKU09OLnN0cmluZ2lmeShyZXBsaWNhUmVnaW9ucyksXG4gICAgICB9LFxuICAgIH0pO1xuICAgIGJ1aWxkVHJpZ2dlclJlc291cmNlLm5vZGUuYWRkRGVwZW5kZW5jeShjb2RlQnVpbGRQcm9qZWN0KTtcblxuICAgIC8vIFNBRkVUWTogcmVmZXJlbmNlIGJ5IHRhZywgbm90IGRpZ2VzdC4gVGhlIGxpZmVjeWNsZSBwb2xpY3kgYWJvdmUgbmV2ZXJcbiAgICAvLyBkZWxldGVzIHRhZ2dlZCBpbWFnZXMsIHNvIHRoZSBkaWdlc3QgYmVoaW5kIHRoaXMgdGFnIGlzIGd1YXJhbnRlZWQgdG9cbiAgICAvLyByZW1haW4gaW4gRUNSIGZvciB0aGUgbGlmZSBvZiB0aGUgcmVwb3NpdG9yeS5cbiAgICBjb25zdCBpbWFnZVRhZ1JlZiA9IGJ1aWxkVHJpZ2dlclJlc291cmNlLmdldEF0dFN0cmluZygnSW1hZ2VUYWcnKTtcbiAgICB0aGlzLmltYWdlVGFnID0gaW1hZ2VUYWdSZWY7XG4gICAgLy8gUGxhaW4gc3ludGgtdGltZSBmb3JtLCB1c2VkIGJ5IGNyb3NzLXJlZ2lvbiBoZWxwZXJzIHRvIGJ5cGFzcyBDREsnc1xuICAgIC8vIENyb3NzUmVnaW9uRXhwb3J0V3JpdGVyIChzZWUgaW1hZ2VUYWdQbGFpbiBkb2NzKS5cbiAgICB0aGlzLmltYWdlVGFnUGxhaW4gPSBpbWFnZVRhZztcbiAgICB0aGlzLnJlcG9zaXRvcnlOYW1lID0gdGhpcy5lY3JSZXBvc2l0b3J5LnJlcG9zaXRvcnlOYW1lO1xuICAgIHRoaXMuY29udGFpbmVySW1hZ2UgPSBDb250YWluZXJJbWFnZS5mcm9tRWNyUmVwb3NpdG9yeSh0aGlzLmVjclJlcG9zaXRvcnksIGltYWdlVGFnUmVmKTtcbiAgICB0aGlzLmRvY2tlckltYWdlQ29kZSA9IERvY2tlckltYWdlQ29kZS5mcm9tRWNyKHRoaXMuZWNyUmVwb3NpdG9yeSwge1xuICAgICAgdGFnT3JEaWdlc3Q6IGltYWdlVGFnUmVmLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEZvcm1hdCB0aGUgRUNSIHJlcG9zaXRvcnkgVVJJIGZvciBhIGdpdmVuIHJlZ2lvbi4gVGhlIHJlZ2lvbiBtdXN0XG4gICAqIGJlIGVpdGhlciB0aGUgcHJpbWFyeSByZWdpb24gb3Igb25lIG9mIGByZXBsaWNhUmVnaW9uc2AuXG4gICAqL1xuICBwdWJsaWMgcmVwb3NpdG9yeVVyaUZvcihyZWdpb246IHN0cmluZyk6IHN0cmluZyB7XG4gICAgdGhpcy5hc3NlcnRSZWdpb25Jc0tub3duKHJlZ2lvbik7XG4gICAgcmV0dXJuIGAke3RoaXMuYWNjb3VudElkfS5ka3IuZWNyLiR7cmVnaW9ufS5hbWF6b25hd3MuY29tLyR7dGhpcy5yZXBvc2l0b3J5TmFtZX1gO1xuICB9XG5cbiAgLyoqXG4gICAqIEltcG9ydCB0aGUgcmVwbGljYXRlZCByZXBvc2l0b3J5IGFzIGFuIEVDUy1jb21wYXRpYmxlXG4gICAqIGBDb250YWluZXJJbWFnZWAgaW4gYSBjb25zdW1lciBzY29wZSAodHlwaWNhbGx5IGEgc3RhY2sgaW4gYHJlZ2lvbmApLlxuICAgKlxuICAgKiBUaGUgY29uc3VtZXIncyBzdGFjayBtdXN0IGhhdmUgYGNyb3NzUmVnaW9uUmVmZXJlbmNlczogdHJ1ZWAgd2hlblxuICAgKiBgcmVnaW9uYCBkaWZmZXJzIGZyb20gdGhlIGJ1aWxkZXIncyByZWdpb24uXG4gICAqXG4gICAqIENyb3NzLXN0YWNrIGNvbnN1bWVycyAoc2FtZSByZWdpb24gb3IgZGlmZmVyZW50IHJlZ2lvbikgcmVjZWl2ZVxuICAgKiBgaW1hZ2VUYWdQbGFpbmAgKGEgc3ludGgtdGltZSBzdHJpbmcpIHJhdGhlciB0aGFuIGBpbWFnZVRhZ2AgKGEgQ0ZOXG4gICAqIHRva2VuKS4gVXNpbmcgdGhlIHRva2VuIHdvdWxkIGNhdXNlIENESyB0byBhdXRvLWNyZWF0ZSBlaXRoZXIgYVxuICAgKiBgQ3Jvc3NSZWdpb25FeHBvcnRXcml0ZXJgIChjcm9zcy1yZWdpb24pIG9yIGEgY3Jvc3Mtc3RhY2tcbiAgICogYEZuOjpFeHBvcnRgIC8gYEZuOjpJbXBvcnRWYWx1ZWAgKHNhbWUtcmVnaW9uKS4gQm90aCB3ZWRnZSBhbnkgZGVwbG95XG4gICAqIHRoYXQgY2hhbmdlcyB0aGUgaW1hZ2VUYWcgdmFsdWUsIGJlY2F1c2UgQ0ZOIHJlZnVzZXMgdG8gXCJ1cGRhdGUgYW5cbiAgICogZXhwb3J0IGluIHVzZVwiIG9yIHJ1bnMgdGhlIHdyaXRlcidzIFwiU29tZSBleHBvcnRzIGhhdmUgY2hhbmdlZFwiIGNoZWNrLlxuICAgKiBTYW1lLXN0YWNrIGNhbGxlcnMga2VlcCB0aGUgdG9rZW4gZm9ybSBzbyB0aGUgTGFtYmRhIHN0aWxsIGhhcyBhIENGTlxuICAgKiBkZXBlbmRlbmN5IG9uIHRoZSBidWlsZCB0cmlnZ2VyIENSLlxuICAgKi9cbiAgcHVibGljIGNvbnRhaW5lckltYWdlRm9yKHNjb3BlOiBDb25zdHJ1Y3QsIHJlZ2lvbjogc3RyaW5nKTogQ29udGFpbmVySW1hZ2Uge1xuICAgIHRoaXMuYXNzZXJ0UmVnaW9uSXNLbm93bihyZWdpb24pO1xuICAgIGNvbnN0IHRhZyA9IHRoaXMudGFnRm9yU2NvcGUoc2NvcGUpO1xuICAgIHJldHVybiBDb250YWluZXJJbWFnZS5mcm9tRWNyUmVwb3NpdG9yeSh0aGlzLmltcG9ydFJlcG9Gb3Ioc2NvcGUsIHJlZ2lvbiksIHRhZyk7XG4gIH1cblxuICAvKipcbiAgICogSW1wb3J0IHRoZSByZXBsaWNhdGVkIHJlcG9zaXRvcnkgYXMgYSBMYW1iZGEtY29tcGF0aWJsZVxuICAgKiBgRG9ja2VySW1hZ2VDb2RlYCBpbiBhIGNvbnN1bWVyIHNjb3BlICh0eXBpY2FsbHkgYSBzdGFjayBpbiBgcmVnaW9uYCkuXG4gICAqXG4gICAqIFRoZSBjb25zdW1lcidzIHN0YWNrIG11c3QgaGF2ZSBgY3Jvc3NSZWdpb25SZWZlcmVuY2VzOiB0cnVlYCB3aGVuXG4gICAqIGByZWdpb25gIGRpZmZlcnMgZnJvbSB0aGUgYnVpbGRlcidzIHJlZ2lvbi5cbiAgICpcbiAgICogQ3Jvc3Mtc3RhY2sgY29uc3VtZXJzIChzYW1lIHJlZ2lvbiBvciBkaWZmZXJlbnQgcmVnaW9uKSByZWNlaXZlXG4gICAqIGBpbWFnZVRhZ1BsYWluYCAoYSBzeW50aC10aW1lIHN0cmluZykgcmF0aGVyIHRoYW4gYGltYWdlVGFnYCAoYSBDRk5cbiAgICogdG9rZW4pLiBTZWUgYGNvbnRhaW5lckltYWdlRm9yYCBmb3IgdGhlIHJhdGlvbmFsZS5cbiAgICovXG4gIHB1YmxpYyBkb2NrZXJJbWFnZUNvZGVGb3Ioc2NvcGU6IENvbnN0cnVjdCwgcmVnaW9uOiBzdHJpbmcpOiBEb2NrZXJJbWFnZUNvZGUge1xuICAgIHRoaXMuYXNzZXJ0UmVnaW9uSXNLbm93bihyZWdpb24pO1xuICAgIGNvbnN0IHRhZyA9IHRoaXMudGFnRm9yU2NvcGUoc2Nv