UNPKG

aws-cdk

Version:

AWS CDK CLI, the command line tool for CDK apps

440 lines 68.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EvaluateCloudFormationTemplate = exports.CfnEvaluationException = exports.LazyLookupExport = exports.LookupExportError = exports.LazyListStackResources = void 0; const api_1 = require("../../../../@aws-cdk/tmp-toolkit-helpers/src/api"); const resource_metadata_1 = require("../../../../@aws-cdk/tmp-toolkit-helpers/src/api/resource-metadata"); class LazyListStackResources { constructor(sdk, stackName) { this.sdk = sdk; this.stackName = stackName; } async listStackResources() { if (this.stackResources === undefined) { this.stackResources = this.sdk.cloudFormation().listStackResources({ StackName: this.stackName, }); } return this.stackResources; } } exports.LazyListStackResources = LazyListStackResources; class LookupExportError extends Error { } exports.LookupExportError = LookupExportError; class LazyLookupExport { constructor(sdk) { this.sdk = sdk; this.cachedExports = {}; } async lookupExport(name) { if (this.cachedExports[name]) { return this.cachedExports[name]; } for await (const cfnExport of this.listExports()) { if (!cfnExport.Name) { continue; // ignore any result that omits a name } this.cachedExports[cfnExport.Name] = cfnExport; if (cfnExport.Name === name) { return cfnExport; } } return undefined; // export not found } // TODO: Paginate async *listExports() { let nextToken = undefined; while (true) { const response = await this.sdk.cloudFormation().listExports({ NextToken: nextToken }); for (const cfnExport of response.Exports ?? []) { yield cfnExport; } if (!response.NextToken) { return; } nextToken = response.NextToken; } } } exports.LazyLookupExport = LazyLookupExport; class CfnEvaluationException extends Error { } exports.CfnEvaluationException = CfnEvaluationException; class EvaluateCloudFormationTemplate { constructor(props) { this.stackArtifact = props.stackArtifact; this.stackName = props.stackName ?? props.stackArtifact.stackName; this.template = props.template ?? props.stackArtifact.template; this.context = { 'AWS::AccountId': props.account, 'AWS::Region': props.region, 'AWS::Partition': props.partition, ...props.parameters, }; this.account = props.account; this.region = props.region; this.partition = props.partition; this.sdk = props.sdk; // We need names of nested stack so we can evaluate cross stack references this.nestedStacks = props.nestedStacks ?? {}; // The current resources of the Stack. // We need them to figure out the physical name of a resource in case it wasn't specified by the user. // We fetch it lazily, to save a service call, in case all hotswapped resources have their physical names set. this.stackResources = new LazyListStackResources(this.sdk, this.stackName); // CloudFormation Exports lookup to be able to resolve Fn::ImportValue intrinsics in template this.lookupExport = new LazyLookupExport(this.sdk); } // clones current EvaluateCloudFormationTemplate object, but updates the stack name async createNestedEvaluateCloudFormationTemplate(stackName, nestedTemplate, nestedStackParameters) { const evaluatedParams = await this.evaluateCfnExpression(nestedStackParameters); return new EvaluateCloudFormationTemplate({ stackArtifact: this.stackArtifact, stackName, template: nestedTemplate, parameters: evaluatedParams, account: this.account, region: this.region, partition: this.partition, sdk: this.sdk, nestedStacks: this.nestedStacks, }); } async establishResourcePhysicalName(logicalId, physicalNameInCfnTemplate) { if (physicalNameInCfnTemplate != null) { try { return await this.evaluateCfnExpression(physicalNameInCfnTemplate); } catch (e) { // If we can't evaluate the resource's name CloudFormation expression, // just look it up in the currently deployed Stack if (!(e instanceof CfnEvaluationException)) { throw e; } } } return this.findPhysicalNameFor(logicalId); } async findPhysicalNameFor(logicalId) { const stackResources = await this.stackResources.listStackResources(); return stackResources.find((sr) => sr.LogicalResourceId === logicalId)?.PhysicalResourceId; } async findLogicalIdForPhysicalName(physicalName) { const stackResources = await this.stackResources.listStackResources(); return stackResources.find((sr) => sr.PhysicalResourceId === physicalName)?.LogicalResourceId; } findReferencesTo(logicalId) { const ret = new Array(); for (const [resourceLogicalId, resourceDef] of Object.entries(this.template?.Resources ?? {})) { if (logicalId !== resourceLogicalId && this.references(logicalId, resourceDef)) { ret.push({ ...resourceDef, LogicalId: resourceLogicalId, }); } } return ret; } async evaluateCfnExpression(cfnExpression) { const self = this; /** * Evaluates CloudFormation intrinsic functions * * Note that supported intrinsic functions are documented in README.md -- please update * list of supported functions when adding new evaluations * * See: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html */ class CfnIntrinsics { evaluateIntrinsic(intrinsic) { const intrinsicFunc = this[intrinsic.name]; if (!intrinsicFunc) { throw new CfnEvaluationException(`CloudFormation function ${intrinsic.name} is not supported`); } const argsAsArray = Array.isArray(intrinsic.args) ? intrinsic.args : [intrinsic.args]; return intrinsicFunc.apply(this, argsAsArray); } async 'Fn::Join'(separator, args) { const evaluatedArgs = await self.evaluateCfnExpression(args); return evaluatedArgs.join(separator); } async 'Fn::Split'(separator, args) { const evaluatedArgs = await self.evaluateCfnExpression(args); return evaluatedArgs.split(separator); } async 'Fn::Select'(index, args) { const evaluatedArgs = await self.evaluateCfnExpression(args); return evaluatedArgs[index]; } async Ref(logicalId) { const refTarget = await self.findRefTarget(logicalId); if (refTarget) { return refTarget; } else { throw new CfnEvaluationException(`Parameter or resource '${logicalId}' could not be found for evaluation`); } } async 'Fn::GetAtt'(logicalId, attributeName) { // ToDo handle the 'logicalId.attributeName' form of Fn::GetAtt const attrValue = await self.findGetAttTarget(logicalId, attributeName); if (attrValue) { return attrValue; } else { throw new CfnEvaluationException(`Attribute '${attributeName}' of resource '${logicalId}' could not be found for evaluation`); } } async 'Fn::Sub'(template, explicitPlaceholders) { const placeholders = explicitPlaceholders ? await self.evaluateCfnExpression(explicitPlaceholders) : {}; return asyncGlobalReplace(template, /\${([^}]*)}/g, (key) => { if (key in placeholders) { return placeholders[key]; } else { const splitKey = key.split('.'); return splitKey.length === 1 ? this.Ref(key) : this['Fn::GetAtt'](splitKey[0], splitKey.slice(1).join('.')); } }); } async 'Fn::ImportValue'(name) { const exported = await self.lookupExport.lookupExport(name); if (!exported) { throw new CfnEvaluationException(`Export '${name}' could not be found for evaluation`); } if (!exported.Value) { throw new CfnEvaluationException(`Export '${name}' exists without a value`); } return exported.Value; } } if (cfnExpression == null) { return cfnExpression; } if (Array.isArray(cfnExpression)) { // Small arrays in practice // eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism return Promise.all(cfnExpression.map((expr) => this.evaluateCfnExpression(expr))); } if (typeof cfnExpression === 'object') { const intrinsic = this.parseIntrinsic(cfnExpression); if (intrinsic) { return new CfnIntrinsics().evaluateIntrinsic(intrinsic); } else { const ret = {}; for (const [key, val] of Object.entries(cfnExpression)) { ret[key] = await this.evaluateCfnExpression(val); } return ret; } } return cfnExpression; } getResourceProperty(logicalId, propertyName) { return this.template.Resources?.[logicalId]?.Properties?.[propertyName]; } metadataFor(logicalId) { return (0, resource_metadata_1.resourceMetadata)(this.stackArtifact, logicalId); } references(logicalId, templateElement) { if (typeof templateElement === 'string') { return logicalId === templateElement; } if (templateElement == null) { return false; } if (Array.isArray(templateElement)) { return templateElement.some((el) => this.references(logicalId, el)); } if (typeof templateElement === 'object') { return Object.values(templateElement).some((el) => this.references(logicalId, el)); } return false; } parseIntrinsic(x) { const keys = Object.keys(x); if (keys.length === 1 && (keys[0].startsWith('Fn::') || keys[0] === 'Ref')) { return { name: keys[0], args: x[keys[0]], }; } return undefined; } async findRefTarget(logicalId) { // first, check to see if the Ref is a Parameter who's value we have if (logicalId === 'AWS::URLSuffix') { if (!this.cachedUrlSuffix) { this.cachedUrlSuffix = await this.sdk.getUrlSuffix(this.region); } return this.cachedUrlSuffix; } // Try finding the ref in the passed in parameters const parameterTarget = this.context[logicalId]; if (parameterTarget) { return parameterTarget; } // If not in the passed in parameters, see if there is a default value in the template parameter that was not passed in const defaultParameterValue = this.template.Parameters?.[logicalId]?.Default; if (defaultParameterValue) { return defaultParameterValue; } // if it's not a Parameter, we need to search in the current Stack resources return this.findGetAttTarget(logicalId); } async findGetAttTarget(logicalId, attribute) { // Handle case where the attribute is referencing a stack output (used in nested stacks to share parameters) // See https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/quickref-cloudformation.html#w2ab1c17c23c19b5 if (logicalId === 'Outputs' && attribute) { return this.evaluateCfnExpression(this.template.Outputs[attribute]?.Value); } const stackResources = await this.stackResources.listStackResources(); const foundResource = stackResources.find((sr) => sr.LogicalResourceId === logicalId); if (!foundResource) { return undefined; } if (foundResource.ResourceType == 'AWS::CloudFormation::Stack' && attribute?.startsWith('Outputs.')) { const dependantStack = this.findNestedStack(logicalId, this.nestedStacks); if (!dependantStack || !dependantStack.physicalName) { // this is a newly created nested stack and cannot be hotswapped return undefined; } const evaluateCfnTemplate = await this.createNestedEvaluateCloudFormationTemplate(dependantStack.physicalName, dependantStack.generatedTemplate, dependantStack.generatedTemplate.Parameters); // Split Outputs.<refName> into 'Outputs' and '<refName>' and recursively call evaluate return evaluateCfnTemplate.evaluateCfnExpression({ 'Fn::GetAtt': attribute.split(/\.(.*)/s), }); } // now, we need to format the appropriate identifier depending on the resource type, // and the requested attribute name return this.formatResourceAttribute(foundResource, attribute); } findNestedStack(logicalId, nestedStacks) { for (const nestedStackLogicalId of Object.keys(nestedStacks)) { if (nestedStackLogicalId === logicalId) { return nestedStacks[nestedStackLogicalId]; } const checkInNestedChildStacks = this.findNestedStack(logicalId, nestedStacks[nestedStackLogicalId].nestedStackTemplates); if (checkInNestedChildStacks) return checkInNestedChildStacks; } return undefined; } formatResourceAttribute(resource, attribute) { const physicalId = resource.PhysicalResourceId; // no attribute means Ref expression, for which we use the physical ID directly if (!attribute) { return physicalId; } const resourceTypeFormats = RESOURCE_TYPE_ATTRIBUTES_FORMATS[resource.ResourceType]; if (!resourceTypeFormats) { throw new CfnEvaluationException(`We don't support attributes of the '${resource.ResourceType}' resource. This is a CDK limitation. ` + 'Please report it at https://github.com/aws/aws-cdk/issues/new/choose'); } const attributeFmtFunc = resourceTypeFormats[attribute]; if (!attributeFmtFunc) { throw new CfnEvaluationException(`We don't support the '${attribute}' attribute of the '${resource.ResourceType}' resource. This is a CDK limitation. ` + 'Please report it at https://github.com/aws/aws-cdk/issues/new/choose'); } const service = this.getServiceOfResource(resource); const resourceTypeArnPart = this.getResourceTypeArnPartOfResource(resource); return attributeFmtFunc({ partition: this.partition, service, region: this.region, account: this.account, resourceType: resourceTypeArnPart, resourceName: physicalId, }); } getServiceOfResource(resource) { return resource.ResourceType.split('::')[1].toLowerCase(); } getResourceTypeArnPartOfResource(resource) { const resourceType = resource.ResourceType; const specialCaseResourceType = RESOURCE_TYPE_SPECIAL_NAMES[resourceType]?.resourceType; return specialCaseResourceType ? specialCaseResourceType : // this is the default case resourceType.split('::')[2].toLowerCase(); } } exports.EvaluateCloudFormationTemplate = EvaluateCloudFormationTemplate; /** * Usually, we deduce the names of the service and the resource type used to format the ARN from the CloudFormation resource type. * For a CFN type like AWS::Service::ResourceType, the second segment becomes the service name, and the third the resource type * (after converting both of them to lowercase). * However, some resource types break this simple convention, and we need to special-case them. * This map is for storing those cases. */ const RESOURCE_TYPE_SPECIAL_NAMES = { 'AWS::Events::EventBus': { resourceType: 'event-bus', }, }; const RESOURCE_TYPE_ATTRIBUTES_FORMATS = { 'AWS::IAM::Role': { Arn: iamArnFmt }, 'AWS::IAM::User': { Arn: iamArnFmt }, 'AWS::IAM::Group': { Arn: iamArnFmt }, 'AWS::S3::Bucket': { Arn: s3ArnFmt }, 'AWS::Lambda::Function': { Arn: stdColonResourceArnFmt }, 'AWS::Events::EventBus': { Arn: stdSlashResourceArnFmt, // the name attribute of the EventBus is the same as the Ref Name: (parts) => parts.resourceName, }, 'AWS::DynamoDB::Table': { Arn: stdSlashResourceArnFmt }, 'AWS::AppSync::GraphQLApi': { ApiId: appsyncGraphQlApiApiIdFmt }, 'AWS::AppSync::FunctionConfiguration': { FunctionId: appsyncGraphQlFunctionIDFmt, }, 'AWS::AppSync::DataSource': { Name: appsyncGraphQlDataSourceNameFmt }, 'AWS::KMS::Key': { Arn: stdSlashResourceArnFmt }, }; function iamArnFmt(parts) { // we skip region for IAM resources return `arn:${parts.partition}:${parts.service}::${parts.account}:${parts.resourceType}/${parts.resourceName}`; } function s3ArnFmt(parts) { // we skip account, region and resourceType for S3 resources return `arn:${parts.partition}:${parts.service}:::${parts.resourceName}`; } function stdColonResourceArnFmt(parts) { // this is a standard format for ARNs like: arn:aws:service:region:account:resourceType:resourceName return `arn:${parts.partition}:${parts.service}:${parts.region}:${parts.account}:${parts.resourceType}:${parts.resourceName}`; } function stdSlashResourceArnFmt(parts) { // this is a standard format for ARNs like: arn:aws:service:region:account:resourceType/resourceName return `arn:${parts.partition}:${parts.service}:${parts.region}:${parts.account}:${parts.resourceType}/${parts.resourceName}`; } function appsyncGraphQlApiApiIdFmt(parts) { // arn:aws:appsync:us-east-1:111111111111:apis/<apiId> return parts.resourceName.split('/')[1]; } function appsyncGraphQlFunctionIDFmt(parts) { // arn:aws:appsync:us-east-1:111111111111:apis/<apiId>/functions/<functionId> return parts.resourceName.split('/')[3]; } function appsyncGraphQlDataSourceNameFmt(parts) { // arn:aws:appsync:us-east-1:111111111111:apis/<apiId>/datasources/<name> return parts.resourceName.split('/')[3]; } async function asyncGlobalReplace(str, regex, cb) { if (!regex.global) { throw new api_1.ToolkitError('Regex must be created with /g flag'); } const ret = new Array(); let start = 0; while (true) { const match = regex.exec(str); if (!match) { break; } ret.push(str.substring(start, match.index)); ret.push(await cb(match[1])); start = regex.lastIndex; } ret.push(str.slice(start)); return ret.join(''); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXZhbHVhdGUtY2xvdWRmb3JtYXRpb24tdGVtcGxhdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJldmFsdWF0ZS1jbG91ZGZvcm1hdGlvbi10ZW1wbGF0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFLQSwwRUFBZ0Y7QUFDaEYsMEdBQXNHO0FBT3RHLE1BQWEsc0JBQXNCO0lBR2pDLFlBQ21CLEdBQVEsRUFDUixTQUFpQjtRQURqQixRQUFHLEdBQUgsR0FBRyxDQUFLO1FBQ1IsY0FBUyxHQUFULFNBQVMsQ0FBUTtJQUVwQyxDQUFDO0lBRU0sS0FBSyxDQUFDLGtCQUFrQjtRQUM3QixJQUFJLElBQUksQ0FBQyxjQUFjLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDdEMsSUFBSSxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDLGtCQUFrQixDQUFDO2dCQUNqRSxTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7YUFDMUIsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUNELE9BQU8sSUFBSSxDQUFDLGNBQWMsQ0FBQztJQUM3QixDQUFDO0NBQ0Y7QUFqQkQsd0RBaUJDO0FBTUQsTUFBYSxpQkFBa0IsU0FBUSxLQUFLO0NBQzNDO0FBREQsOENBQ0M7QUFFRCxNQUFhLGdCQUFnQjtJQUczQixZQUE2QixHQUFRO1FBQVIsUUFBRyxHQUFILEdBQUcsQ0FBSztRQUY3QixrQkFBYSxHQUErQixFQUFFLENBQUM7SUFHdkQsQ0FBQztJQUVELEtBQUssQ0FBQyxZQUFZLENBQUMsSUFBWTtRQUM3QixJQUFJLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUM3QixPQUFPLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDbEMsQ0FBQztRQUVELElBQUksS0FBSyxFQUFFLE1BQU0sU0FBUyxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO1lBQ2pELElBQUksQ0FB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Q0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUMxQyxDQUFDO0FBT0QsS0FBSyxVQUFVLGtCQUFrQixDQUFDLEdBQVcsRUFBRSxLQUFhLEVBQUUsRUFBa0M7SUFDOUYsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUNsQixNQUFNLElBQUksa0JBQVksQ0FBQyxvQ0FBb0MsQ0FBQyxDQUFDO0lBQy9ELENBQUM7SUFFRCxNQUFNLEdBQUcsR0FBRyxJQUFJLEtBQUssRUFBVSxDQUFDO0lBQ2hDLElBQUksS0FBSyxHQUFHLENBQUMsQ0FBQztJQUNkLE9BQU8sSUFBSSxFQUFFLENBQUM7UUFDWixNQUFNLEtBQUssR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzlCLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQztZQUNYLE1BQU07UUFDUixDQUFDO1FBRUQsR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQztRQUM1QyxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFFN0IsS0FBSyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUM7SUFDMUIsQ0FBQztJQUNELEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDO0lBRTNCLE9BQU8sR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUN0QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBDbG91ZEZvcm1hdGlvblN0YWNrQXJ0aWZhY3QgfSBmcm9tICdAYXdzLWNkay9jeC1hcGknO1xuaW1wb3J0IHR5cGUgeyBFeHBvcnQsIExpc3RFeHBvcnRzQ29tbWFuZE91dHB1dCwgU3RhY2tSZXNvdXJjZVN1bW1hcnkgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtY2xvdWRmb3JtYXRpb24nO1xuaW1wb3J0IHR5cGUgeyBTREsgfSBmcm9tICcuLi9hd3MtYXV0aCc7XG5pbXBvcnQgdHlwZSB7IE5lc3RlZFN0YWNrVGVtcGxhdGVzIH0gZnJvbSAnLi9uZXN0ZWQtc3RhY2staGVscGVycyc7XG5pbXBvcnQgdHlwZSB7IFRlbXBsYXRlIH0gZnJvbSAnLi9zdGFjay1oZWxwZXJzJztcbmltcG9ydCB7IFRvb2xraXRFcnJvciB9IGZyb20gJy4uLy4uLy4uLy4uL0Bhd3MtY2RrL3RtcC10b29sa2l0LWhlbHBlcnMvc3JjL2FwaSc7XG5pbXBvcnQgeyByZXNvdXJjZU1ldGFkYXRhIH0gZnJvbSAnLi4vLi4vLi4vLi4vQGF3cy1jZGsvdG1wLXRvb2xraXQtaGVscGVycy9zcmMvYXBpL3Jlc291cmNlLW1ldGFkYXRhJztcbmltcG9ydCB0eXBlIHsgUmVzb3VyY2VNZXRhZGF0YSB9IGZyb20gJy4uLy4uLy4uLy4uL0Bhd3MtY2RrL3RtcC10b29sa2l0LWhlbHBlcnMvc3JjL2FwaS9yZXNvdXJjZS1tZXRhZGF0YSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgTGlzdFN0YWNrUmVzb3VyY2VzIHtcbiAgbGlzdFN0YWNrUmVzb3VyY2VzKCk6IFByb21pc2U8U3RhY2tSZXNvdXJjZVN1bW1hcnlbXT47XG59XG5cbmV4cG9ydCBjbGFzcyBMYXp5TGlzdFN0YWNrUmVzb3VyY2VzIGltcGxlbWVudHMgTGlzdFN0YWNrUmVzb3VyY2VzIHtcbiAgcHJpdmF0ZSBzdGFja1Jlc291cmNlczogUHJvbWlzZTxTdGFja1Jlc291cmNlU3VtbWFyeVtdPiB8IHVuZGVmaW5lZDtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHNkazogU0RLLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgc3RhY2tOYW1lOiBzdHJpbmcsXG4gICkge1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGxpc3RTdGFja1Jlc291cmNlcygpOiBQcm9taXNlPFN0YWNrUmVzb3VyY2VTdW1tYXJ5W10+IHtcbiAgICBpZiAodGhpcy5zdGFja1Jlc291cmNlcyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICB0aGlzLnN0YWNrUmVzb3VyY2VzID0gdGhpcy5zZGsuY2xvdWRGb3JtYXRpb24oKS5saXN0U3RhY2tSZXNvdXJjZXMoe1xuICAgICAgICBTdGFja05hbWU6IHRoaXMuc3RhY2tOYW1lLFxuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnN0YWNrUmVzb3VyY2VzO1xuICB9XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTG9va3VwRXhwb3J0IHtcbiAgbG9va3VwRXhwb3J0KG5hbWU6IHN0cmluZyk6IFByb21pc2U8RXhwb3J0IHwgdW5kZWZpbmVkPjtcbn1cblxuZXhwb3J0IGNsYXNzIExvb2t1cEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xufVxuXG5leHBvcnQgY2xhc3MgTGF6eUxvb2t1cEV4cG9ydCBpbXBsZW1lbnRzIExvb2t1cEV4cG9ydCB7XG4gIHByaXZhdGUgY2FjaGVkRXhwb3J0czogeyBbbmFtZTogc3RyaW5nXTogRXhwb3J0IH0gPSB7fTtcblxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIHJlYWRvbmx5IHNkazogU0RLKSB7XG4gIH1cblxuICBhc3luYyBsb29rdXBFeHBvcnQobmFtZTogc3RyaW5nKTogUHJvbWlzZTxFeHBvcnQgfCB1bmRlZmluZWQ+IHtcbiAgICBpZiAodGhpcy5jYWNoZWRFeHBvcnRzW25hbWVdKSB7XG4gICAgICByZXR1cm4gdGhpcy5jYWNoZWRFeHBvcnRzW25hbWVdO1xuICAgIH1cblxuICAgIGZvciBhd2FpdCAoY29uc3QgY2ZuRXhwb3J0IG9mIHRoaXMubGlzdEV4cG9ydHMoKSkge1xuICAgICAgaWYgKCFjZm5FeHBvcnQuTmFtZSkge1xuICAgICAgICBjb250aW51ZTsgLy8gaWdub3JlIGFueSByZXN1bHQgdGhhdCBvbWl0cyBhIG5hbWVcbiAgICAgIH1cbiAgICAgIHRoaXMuY2FjaGVkRXhwb3J0c1tjZm5FeHBvcnQuTmFtZV0gPSBjZm5FeHBvcnQ7XG5cbiAgICAgIGlmIChjZm5FeHBvcnQuTmFtZSA9PT0gbmFtZSkge1xuICAgICAgICByZXR1cm4gY2ZuRXhwb3J0O1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB1bmRlZmluZWQ7IC8vIGV4cG9ydCBub3QgZm91bmRcbiAgfVxuXG4gIC8vIFRPRE86IFBhZ2luYXRlXG4gIHByaXZhdGUgYXN5bmMgKmxpc3RFeHBvcnRzKCkge1xuICAgIGxldCBuZXh0VG9rZW46IHN0cmluZyB8IHVuZGVmaW5lZCA9IHVuZGVmaW5lZDtcbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgY29uc3QgcmVzcG9uc2U6IExpc3RFeHBvcnRzQ29tbWFuZE91dHB1dCA9IGF3YWl0IHRoaXMuc2RrLmNsb3VkRm9ybWF0aW9uKCkubGlzdEV4cG9ydHMoeyBOZXh0VG9rZW46IG5leHRUb2tlbiB9KTtcbiAgICAgIGZvciAoY29uc3QgY2ZuRXhwb3J0IG9mIHJlc3BvbnNlLkV4cG9ydHMgPz8gW10pIHtcbiAgICAgICAgeWllbGQgY2ZuRXhwb3J0O1xuICAgICAgfVxuXG4gICAgICBpZiAoIXJlc3BvbnNlLk5leHRUb2tlbikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBuZXh0VG9rZW4gPSByZXNwb25zZS5OZXh0VG9rZW47XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBjbGFzcyBDZm5FdmFsdWF0aW9uRXhjZXB0aW9uIGV4dGVuZHMgRXJyb3Ige1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlc291cmNlRGVmaW5pdGlvbiB7XG4gIHJlYWRvbmx5IExvZ2ljYWxJZDogc3RyaW5nO1xuICByZWFkb25seSBUeXBlOiBzdHJpbmc7XG4gIHJlYWRvbmx5IFByb3BlcnRpZXM6IHsgW3A6IHN0cmluZ106IGFueSB9O1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEV2YWx1YXRlQ2xvdWRGb3JtYXRpb25UZW1wbGF0ZVByb3BzIHtcbiAgcmVhZG9ubHkgc3RhY2tBcnRpZmFjdDogQ2xvdWRGb3JtYXRpb25TdGFja0FydGlmYWN0O1xuICByZWFkb25seSBzdGFja05hbWU/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHRlbXBsYXRlPzogVGVtcGxhdGU7XG4gIHJlYWRvbmx5IHBhcmFtZXRlcnM6IHsgW3BhcmFtZXRlck5hbWU6IHN0cmluZ106IHN0cmluZyB9O1xuICByZWFkb25seSBhY2NvdW50OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJlZ2lvbjogc3RyaW5nO1xuICByZWFkb25seSBwYXJ0aXRpb246IHN0cmluZztcbiAgcmVhZG9ubHkgc2RrOiBTREs7XG4gIHJlYWRvbmx5IG5lc3RlZFN0YWNrcz86IHtcbiAgICBbbmVzdGVkU3RhY2tMb2dpY2FsSWQ6IHN0cmluZ106IE5lc3RlZFN0YWNrVGVtcGxhdGVzO1xuICB9O1xufVxuXG5leHBvcnQgY2xhc3MgRXZhbHVhdGVDbG91ZEZvcm1hdGlvblRlbXBsYXRlIHtcbiAgcHVibGljIHJlYWRvbmx5IHN0YWNrQXJ0aWZhY3Q6IENsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdDtcbiAgcHJpdmF0ZSByZWFkb25seSBzdGFja05hbWU6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSB0ZW1wbGF0ZTogVGVtcGxhdGU7XG4gIHByaXZhdGUgcmVhZG9ubHkgY29udGV4dDogeyBbazogc3RyaW5nXTogYW55IH07XG4gIHByaXZhdGUgcmVhZG9ubHkgYWNjb3VudDogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lvbjogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IHBhcnRpdGlvbjogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IHNkazogU0RLO1xuICBwcml2YXRlIHJlYWRvbmx5IG5lc3RlZFN0YWNrczoge1xuICAgIFtuZXN0ZWRTdGFja0xvZ2ljYWxJZDogc3RyaW5nXTogTmVzdGVkU3RhY2tUZW1wbGF0ZXM7XG4gIH07XG4gIHByaXZhdGUgcmVhZG9ubHkgc3RhY2tSZXNvdXJjZXM6IExpc3RTdGFja1Jlc291cmNlcztcbiAgcHJpdmF0ZSByZWFkb25seSBsb29rdXBFeHBvcnQ6IExvb2t1cEV4cG9ydDtcblxuICBwcml2YXRlIGNhY2hlZFVybFN1ZmZpeDogc3RyaW5nIHwgdW5kZWZpbmVkO1xuXG4gIGNvbnN0cnVjdG9yKHByb3BzOiBFdmFsdWF0ZUNsb3VkRm9ybWF0aW9uVGVtcGxhdGVQcm9wcykge1xuICAgIHRoaXMuc3RhY2tBcnRpZmFjdCA9IHByb3BzLnN0YWNrQXJ0aWZhY3Q7XG4gICAgdGhpcy5zdGFja05hbWUgPSBwcm9wcy5zdGFja05hbWUgPz8gcHJvcHMuc3RhY2tBcnRpZmFjdC5zdGFja05hbWU7XG4gICAgdGhpcy50ZW1wbGF0ZSA9IHByb3BzLnRlbXBsYXRlID8/IHByb3BzLnN0YWNrQXJ0aWZhY3QudGVtcGxhdGU7XG4gICAgdGhpcy5jb250ZXh0ID0ge1xuICAgICAgJ0FXUzo6QWNjb3VudElkJzogcHJvcHMuYWNjb3VudCxcbiAgICAgICdBV1M6OlJlZ2lvbic6IHByb3BzLnJlZ2lvbixcbiAgICAgICdBV1M6OlBhcnRpdGlvbic6IHByb3BzLnBhcnRpdGlvbixcbiAgICAgIC4uLnByb3BzLnBhcmFtZXRlcnMsXG4gICAgfTtcbiAgICB0aGlzLmFjY291bnQgPSBwcm9wcy5hY2NvdW50O1xuICAgIHRoaXMucmVnaW9uID0gcHJvcHMucmVnaW9uO1xuICAgIHRoaXMucGFydGl0aW9uID0gcHJvcHMucGFydGl0aW9uO1xuICAgIHRoaXMuc2RrID0gcHJvcHMuc2RrO1xuXG4gICAgLy8gV2UgbmVlZCBuYW1lcyBvZiBuZXN0ZWQgc3RhY2sgc28gd2UgY2FuIGV2YWx1YXRlIGNyb3NzIHN0YWNrIHJlZmVyZW5jZXNcbiAgICB0aGlzLm5lc3RlZFN0YWNrcyA9IHByb3BzLm5lc3RlZFN0YWNrcyA/PyB7fTtcblxuICAgIC8vIFRoZSBjdXJyZW50IHJlc291cmNlcyBvZiB0aGUgU3RhY2suXG4gICAgLy8gV2UgbmVlZCB0aGVtIHRvIGZpZ3VyZSBvdXQgdGhlIHBoeXNpY2FsIG5hbWUgb2YgYSByZXNvdXJjZSBpbiBjYXNlIGl0IHdhc24ndCBzcGVjaWZpZWQgYnkgdGhlIHVzZXIuXG4gICAgLy8gV2UgZmV0Y2ggaXQgbGF6aWx5LCB0byBzYXZlIGEgc2VydmljZSBjYWxsLCBpbiBjYXNlIGFsbCBob3Rzd2FwcGVkIHJlc291cmNlcyBoYXZlIHRoZWlyIHBoeXNpY2FsIG5hbWVzIHNldC5cbiAgICB0aGlzLnN0YWNrUmVzb3VyY2VzID0gbmV3IExhenlMaXN0U3RhY2tSZXNvdXJjZXModGhpcy5zZGssIHRoaXMuc3RhY2tOYW1lKTtcblxuICAgIC8vIENsb3VkRm9ybWF0aW9uIEV4cG9ydHMgbG9va3VwIHRvIGJlIGFibGUgdG8gcmVzb2x2ZSBGbjo6SW1wb3J0VmFsdWUgaW50cmluc2ljcyBpbiB0ZW1wbGF0ZVxuICAgIHRoaXMubG9va3VwRXhwb3J0ID0gbmV3IExhenlMb29rdXBFeHBvcnQodGhpcy5zZGspO1xuICB9XG5cbiAgLy8gY2xvbmVzIGN1cnJlbnQgRXZhbHVhdGVDbG91ZEZvcm1hdGlvblRlbXBsYXRlIG9iamVjdCwgYnV0IHVwZGF0ZXMgdGhlIHN0YWNrIG5hbWVcbiAgcHVibGljIGFzeW5jIGNyZWF0ZU5lc3RlZEV2YWx1YXRlQ2xvdWRGb3JtYXRpb25UZW1wbGF0ZShcbiAgICBzdGFja05hbWU6IHN0cmluZyxcbiAgICBuZXN0ZWRUZW1wbGF0ZTogVGVtcGxhdGUsXG4gICAgbmVzdGVkU3RhY2tQYXJhbWV0ZXJzOiB7IFtwYXJhbWV0ZXJOYW1lOiBzdHJpbmddOiBhbnkgfSxcbiAgKSB7XG4gICAgY29uc3QgZXZhbHVhdGVkUGFyYW1zID0gYXdhaXQgdGhpcy5ldmFsdWF0ZUNmbkV4cHJlc3Npb24obmVzdGVkU3RhY2tQYXJhbWV0ZXJzKTtcbiAgICByZXR1cm4gbmV3IEV2YWx1YXRlQ2xvdWRGb3JtYXRpb25UZW1wbGF0ZSh7XG4gICAgICBzdGFja0FydGlmYWN0OiB0aGlzLnN0YWNrQXJ0aWZhY3QsXG4gICAgICBzdGFja05hbWUsXG4gICAgICB0ZW1wbGF0ZTogbmVzdGVkVGVtcGxhdGUsXG4gICAgICBwYXJhbWV0ZXJzOiBldmFsdWF0ZWRQYXJhbXMsXG4gICAgICBhY2NvdW50OiB0aGlzLmFjY291bnQsXG4gICAgICByZWdpb246IHRoaXMucmVnaW9uLFxuICAgICAgcGFydGl0aW9uOiB0aGlzLnBhcnRpdGlvbixcbiAgICAgIHNkazogdGhpcy5zZGssXG4gICAgICBuZXN0ZWRTdGFja3M6IHRoaXMubmVzdGVkU3RhY2tzLFxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGFzeW5jIGVzdGFibGlzaFJlc291cmNlUGh5c2ljYWxOYW1lKFxuICAgIGxvZ2ljYWxJZDogc3RyaW5nLFxuICAgIHBoeXNpY2FsTmFtZUluQ2ZuVGVtcGxhdGU6IGFueSxcbiAgKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgICBpZiAocGh5c2ljYWxOYW1lSW5DZm5UZW1wbGF0ZSAhPSBudWxsKSB7XG4gICAgICB0cnkge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5ldmFsdWF0ZUNmbkV4cHJlc3Npb24ocGh5c2ljYWxOYW1lSW5DZm5UZW1wbGF0ZSk7XG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIC8vIElmIHdlIGNhbid0IGV2YWx1YXRlIHRoZSByZXNvdXJjZSdzIG5hbWUgQ2xvdWRGb3JtYXRpb24gZXhwcmVzc2lvbixcbiAgICAgICAgLy8ganVzdCBsb29rIGl0IHVwIGluIHRoZSBjdXJyZW50bHkgZGVwbG95ZWQgU3RhY2tcbiAgICAgICAgaWYgKCEoZSBpbnN0YW5jZW9mIENmbkV2YWx1YXRpb25FeGNlcHRpb24pKSB7XG4gICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy5maW5kUGh5c2ljYWxOYW1lRm9yKGxvZ2ljYWxJZCk7XG4gIH1cblxuICBwdWJsaWMgYXN5bmMgZmluZFBoeXNpY2FsTmFtZUZvcihsb2dpY2FsSWQ6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nIHwgdW5kZWZpbmVkPiB7XG4gICAgY29uc3Qgc3RhY2tSZXNvdXJjZXMgPSBhd2FpdCB0aGlzLnN0YWNrUmVzb3VyY2VzLmxpc3RTdGFja1Jlc291cmNlcygpO1xuICAgIHJldHVybiBzdGFja1Jlc291cmNlcy5maW5kKChzcikgPT4gc3IuTG9naWNhbFJlc291cmNlSWQgPT09IGxvZ2ljYWxJZCk/LlBoeXNpY2FsUmVzb3VyY2VJZDtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBmaW5kTG9naWNhbElkRm9yUGh5c2ljYWxOYW1lKHBoeXNpY2FsTmFtZTogc3RyaW5nKTogUHJvbWlzZTxzdHJpbmcgfCB1bmRlZmluZWQ+IHtcbiAgICBjb25zdCBzdGFja1Jlc291cmNlcyA9IGF3YWl0IHRoaXMuc3RhY2tSZXNvdXJjZXMubGlzdFN0YWNrUmVzb3VyY2VzKCk7XG4gICAgcmV0dXJuIHN0YWNrUmVzb3VyY2VzLmZpbmQoKHNyKSA9PiBzci5QaHlzaWNhbFJlc291cmNlSWQgPT09IHBoeXNpY2FsTmFtZSk/LkxvZ2ljYWxSZXNvdXJjZUlkO1xuICB9XG5cbiAgcHVibGljIGZpbmRSZWZlcmVuY2VzVG8obG9naWNhbElkOiBzdHJpbmcpOiBBcnJheTxSZXNvdXJjZURlZmluaXRpb24+IHtcbiAgICBjb25zdCByZXQgPSBuZXcgQXJyYXk8UmVzb3VyY2VEZWZpbml0aW9uPigpO1xuICAgIGZvciAoY29uc3QgW3Jlc291cmNlTG9naWNhbElkLCByZXNvdXJjZURlZl0gb2YgT2JqZWN0LmVudHJpZXModGhpcy50ZW1wbGF0ZT8uUmVzb3VyY2VzID8/IHt9KSkge1xuICAgICAgaWYgKGxvZ2ljYWxJZCAhPT0gcmVzb3VyY2VMb2dpY2FsSWQgJiYgdGhpcy5yZWZlcmVuY2VzKGxvZ2ljYWxJZCwgcmVzb3VyY2VEZWYpKSB7XG4gICAgICAgIHJldC5wdXNoKHtcbiAgICAgICAgICAuLi4ocmVzb3VyY2VEZWYgYXMgYW55KSxcbiAgICAgICAgICBMb2dpY2FsSWQ6IHJlc291cmNlTG9naWNhbElkLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfVxuXG4gIHB1YmxpYyBhc3luYyBldmFsdWF0ZUNmbkV4cHJlc3Npb24oY2ZuRXhwcmVzc2lvbjogYW55KTogUHJvbWlzZTxhbnk+IHtcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAvKipcbiAgICAgKiBFdmFsdWF0ZXMgQ2xvdWRGb3JtYXRpb24gaW50cmluc2ljIGZ1bmN0aW9uc1xuICAgICAqXG4gICAgICogTm90ZSB0aGF0IHN1cHBvcnRlZCBpbnRyaW5zaWMgZnVuY3Rpb25zIGFyZSBkb2N1bWVudGVkIGluIFJFQURNRS5tZCAtLSBwbGVhc2UgdXBkYXRlXG4gICAgICogbGlzdCBvZiBzdXBwb3J0ZWQgZnVuY3Rpb25zIHdoZW4gYWRkaW5nIG5ldyBldmFsdWF0aW9uc1xuICAgICAqXG4gICAgICogU2VlOiBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQVdTQ2xvdWRGb3JtYXRpb24vbGF0ZXN0L1VzZXJHdWlkZS9pbnRyaW5zaWMtZnVuY3Rpb24tcmVmZXJlbmNlLmh0bWxcbiAgICAgKi9cbiAgICBjbGFzcyBDZm5JbnRyaW5zaWNzIHtcbiAgICAgIHB1YmxpYyBldmFsdWF0ZUludHJpbnNpYyhpbnRyaW5zaWM6IEludHJpbnNpYyk6IGFueSB7XG4gICAgICAgIGNvbnN0IGludHJpbnNpY0Z1bmMgPSAodGhpcyBhcyBhbnkpW2ludHJpbnNpYy5uYW1lXTtcbiAgICAgICAgaWYgKCFpbnRyaW5zaWNGdW5jKSB7XG4gICAgICAgICAgdGhyb3cgbmV3IENmbkV2YWx1YXRpb25FeGNlcHRpb24oYENsb3VkRm9ybWF0aW9uIGZ1bmN0aW9uICR7aW50cmluc2ljLm5hbWV9IGlzIG5vdCBzdXBwb3J0ZWRgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGFyZ3NBc0FycmF5ID0gQXJyYXkuaXNBcnJheShpbnRyaW5zaWMuYXJncykgPyBpbnRyaW5zaWMuYXJncyA6IFtpbnRyaW5zaWMuYXJnc107XG5cbiAgICAgICAgcmV0dXJuIGludHJpbnNpY0Z1bmMuYXBwbHkodGhpcywgYXJnc0FzQXJyYXkpO1xuICAgICAgfVxuXG4gICAgICBhc3luYyAnRm46OkpvaW4nKHNlcGFyYXRvcjogc3RyaW5nLCBhcmdzOiBhbnlbXSk6IFByb21pc2U8c3RyaW5nPiB7XG4gICAgICAgIGNvbnN0IGV2Y