@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
174 lines • 24.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.NestedStack = void 0;
const crypto = require("crypto");
const constructs_1 = require("constructs");
const assets_1 = require("./assets");
const cfn_fn_1 = require("./cfn-fn");
const cfn_pseudo_1 = require("./cfn-pseudo");
const cloudformation_generated_1 = require("./cloudformation.generated");
const lazy_1 = require("./lazy");
const stack_1 = require("./stack");
const stack_synthesizers_1 = require("./stack-synthesizers");
const token_1 = require("./token");
// v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch.
// eslint-disable-next-line
const construct_compat_1 = require("./construct-compat");
const NESTED_STACK_SYMBOL = Symbol.for('@aws-cdk/core.NestedStack');
/**
* (experimental) A CloudFormation nested stack.
*
* When you apply template changes to update a top-level stack, CloudFormation
* updates the top-level stack and initiates an update to its nested stacks.
* CloudFormation updates the resources of modified nested stacks, but does not
* update the resources of unmodified nested stacks.
*
* Furthermore, this stack will not be treated as an independent deployment
* artifact (won't be listed in "cdk list" or deployable through "cdk deploy"),
* but rather only synthesized as a template and uploaded as an asset to S3.
*
* Cross references of resource attributes between the parent stack and the
* nested stack will automatically be translated to stack parameters and
* outputs.
*
* @experimental
*/
class NestedStack extends stack_1.Stack {
/**
* @experimental
*/
constructor(scope, id, props = {}) {
const parentStack = findParentStack(scope);
super(scope, id, {
env: { account: parentStack.account, region: parentStack.region },
synthesizer: new stack_synthesizers_1.NestedStackSynthesizer(parentStack.synthesizer),
});
this._parentStack = parentStack;
// @deprecate: remove this in v2.0 (redundent)
const parentScope = new construct_compat_1.Construct(scope, id + '.NestedStack');
Object.defineProperty(this, NESTED_STACK_SYMBOL, { value: true });
// this is the file name of the synthesized template file within the cloud assembly
this.templateFile = `${this.node.uniqueId}.nested.template.json`;
this.parameters = props.parameters || {};
this.resource = new cloudformation_generated_1.CfnStack(parentScope, `${id}.NestedStackResource`, {
templateUrl: lazy_1.Lazy.stringValue({ produce: () => this._templateUrl || '<unresolved>' }),
parameters: lazy_1.Lazy.anyValue({ produce: () => Object.keys(this.parameters).length > 0 ? this.parameters : undefined }),
notificationArns: props.notificationArns,
timeoutInMinutes: props.timeout ? props.timeout.toMinutes() : undefined,
});
this.nestedStackResource = this.resource;
// context-aware stack name: if resolved from within this stack, return AWS::StackName
// if resolved from the outer stack, use the { Ref } of the AWS::CloudFormation::Stack resource
// which resolves the ARN of the stack. We need to extract the stack name, which is the second
// component after splitting by "/"
this._contextualStackName = this.contextualAttribute(cfn_pseudo_1.Aws.STACK_NAME, cfn_fn_1.Fn.select(1, cfn_fn_1.Fn.split('/', this.resource.ref)));
this._contextualStackId = this.contextualAttribute(cfn_pseudo_1.Aws.STACK_ID, this.resource.ref);
}
/**
* (experimental) Checks if `x` is an object of type `NestedStack`.
*
* @experimental
*/
static isNestedStack(x) {
return x != null && typeof (x) === 'object' && NESTED_STACK_SYMBOL in x;
}
/**
* (experimental) An attribute that represents the name of the nested stack.
*
* This is a context aware attribute:
* - If this is referenced from the parent stack, it will return a token that parses the name from the stack ID.
* - If this is referenced from the context of the nested stack, it will return `{ "Ref": "AWS::StackName" }`
*
* @experimental
* @attribute true
* @example
*
* mystack-mynestedstack-sggfrhxhum7w
*/
get stackName() {
return this._contextualStackName;
}
/**
* (experimental) An attribute that represents the ID of the stack.
*
* This is a context aware attribute:
* - If this is referenced from the parent stack, it will return `{ "Ref": "LogicalIdOfNestedStackResource" }`.
* - If this is referenced from the context of the nested stack, it will return `{ "Ref": "AWS::StackId" }`
*
* @experimental
* @attribute true
* @example
*
* "arn:aws:cloudformation:us-east-2:123456789012:stack/mystack-mynestedstack-sggfrhxhum7w/f449b250-b969-11e0-a185-5081d0136786"
*/
get stackId() {
return this._contextualStackId;
}
/**
* (experimental) Assign a value to one of the nested stack parameters.
*
* @param name The parameter name (ID).
* @param value The value to assign.
* @experimental
*/
setParameter(name, value) {
this.parameters[name] = value;
}
/**
* Defines an asset at the parent stack which represents the template of this
* nested stack.
*
* This private API is used by `App.prepare()` within a loop that rectifies
* references every time an asset is added. This is because (at the moment)
* assets are addressed using CloudFormation parameters.
*
* @returns `true` if a new asset was added or `false` if an asset was
* previously added. When this returns `true`, App will do another reference
* rectification cycle.
*
* @internal
*/
_prepareTemplateAsset() {
if (this._templateUrl) {
return false;
}
const cfn = JSON.stringify(this._toCloudFormation());
const templateHash = crypto.createHash('sha256').update(cfn).digest('hex');
const templateLocation = this._parentStack.addFileAsset({
packaging: assets_1.FileAssetPackaging.FILE,
sourceHash: templateHash,
fileName: this.templateFile,
});
// if bucketName/objectKey are cfn parameters from a stack other than the parent stack, they will
// be resolved as cross-stack references like any other (see "multi" tests).
this._templateUrl = `https://s3.${this._parentStack.region}.${this._parentStack.urlSuffix}/${templateLocation.bucketName}/${templateLocation.objectKey}`;
return true;
}
contextualAttribute(innerValue, outerValue) {
return token_1.Token.asString({
resolve: (context) => {
if (stack_1.Stack.of(context.scope) === this) {
return innerValue;
}
else {
return outerValue;
}
},
});
}
}
exports.NestedStack = NestedStack;
/**
* Validates the scope for a nested stack. Nested stacks must be defined within the scope of another `Stack`.
*/
function findParentStack(scope) {
if (!scope) {
throw new Error('Nested stacks cannot be defined as a root construct');
}
const parentStack = constructs_1.Node.of(scope).scopes.reverse().find(p => stack_1.Stack.isStack(p));
if (!parentStack) {
throw new Error('Nested stacks must be defined within scope of another non-nested stack');
}
return parentStack;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmVzdGVkLXN0YWNrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibmVzdGVkLXN0YWNrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLGlDQUFpQztBQUNqQywyQ0FBNkM7QUFDN0MscUNBQThDO0FBQzlDLHFDQUE4QjtBQUM5Qiw2Q0FBbUM7QUFFbkMseUVBQXNEO0FBRXRELGlDQUE4QjtBQUU5QixtQ0FBZ0M7QUFDaEMsNkRBQThEO0FBQzlELG1DQUFnQztBQUVoQyxnSEFBZ0g7QUFDaEgsMkJBQTJCO0FBQzNCLHlEQUFnRTtBQUVoRSxNQUFNLG1CQUFtQixHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLENBQUMsQ0FBQzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQStEcEUsTUFBYSxXQUFZLFNBQVEsYUFBSzs7OztJQW1CcEMsWUFBWSxLQUFnQixFQUFFLEVBQVUsRUFBRSxRQUEwQixFQUFHO1FBQ3JFLE1BQU0sV0FBVyxHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUUzQyxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTtZQUNmLEdBQUcsRUFBRSxFQUFFLE9BQU8sRUFBRSxXQUFXLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxXQUFXLENBQUMsTUFBTSxFQUFFO1lBQ2pFLFdBQVcsRUFBRSxJQUFJLDJDQUFzQixDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUM7U0FDakUsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLFlBQVksR0FBRyxXQUFXLENBQUM7UUFFaEMsOENBQThDO1FBQzlDLE1BQU0sV0FBVyxHQUFHLElBQUksNEJBQWEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxHQUFHLGNBQWMsQ0FBQyxDQUFDO1FBRWxFLE1BQU0sQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFLG1CQUFtQixFQUFFLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7UUFFbEUsbUZBQW1GO1FBQ25GLElBQUksQ0FBQyxZQUFZLEdB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Y3J5cHRvJztcbmltcG9ydCB7IENvbnN0cnVjdCwgTm9kZSB9IGZyb20gJ2NvbnN0cnVjdHMnO1xuaW1wb3J0IHsgRmlsZUFzc2V0UGFja2FnaW5nIH0gZnJvbSAnLi9hc3NldHMnO1xuaW1wb3J0IHsgRm4gfSBmcm9tICcuL2Nmbi1mbic7XG5pbXBvcnQgeyBBd3MgfSBmcm9tICcuL2Nmbi1wc2V1ZG8nO1xuaW1wb3J0IHsgQ2ZuUmVzb3VyY2UgfSBmcm9tICcuL2Nmbi1yZXNvdXJjZSc7XG5pbXBvcnQgeyBDZm5TdGFjayB9IGZyb20gJy4vY2xvdWRmb3JtYXRpb24uZ2VuZXJhdGVkJztcbmltcG9ydCB7IER1cmF0aW9uIH0gZnJvbSAnLi9kdXJhdGlvbic7XG5pbXBvcnQgeyBMYXp5IH0gZnJvbSAnLi9sYXp5JztcbmltcG9ydCB7IElSZXNvbHZlQ29udGV4dCB9IGZyb20gJy4vcmVzb2x2YWJsZSc7XG5pbXBvcnQgeyBTdGFjayB9IGZyb20gJy4vc3RhY2snO1xuaW1wb3J0IHsgTmVzdGVkU3RhY2tTeW50aGVzaXplciB9IGZyb20gJy4vc3RhY2stc3ludGhlc2l6ZXJzJztcbmltcG9ydCB7IFRva2VuIH0gZnJvbSAnLi90b2tlbic7XG5cbi8vIHYyIC0ga2VlcCB0aGlzIGltcG9ydCBhcyBhIHNlcGFyYXRlIHNlY3Rpb24gdG8gcmVkdWNlIG1lcmdlIGNvbmZsaWN0IHdoZW4gZm9yd2FyZCBtZXJnaW5nIHdpdGggdGhlIHYyIGJyYW5jaC5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuaW1wb3J0IHsgQ29uc3RydWN0IGFzIENvcmVDb25zdHJ1Y3QgfSBmcm9tICcuL2NvbnN0cnVjdC1jb21wYXQnO1xuXG5jb25zdCBORVNURURfU1RBQ0tfU1lNQk9MID0gU3ltYm9sLmZvcignQGF3cy1jZGsvY29yZS5OZXN0ZWRTdGFjaycpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbmV4cG9ydCBpbnRlcmZhY2UgTmVzdGVkU3RhY2tQcm9wcyB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICByZWFkb25seSBwYXJhbWV0ZXJzPzogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICByZWFkb25seSB0aW1lb3V0PzogRHVyYXRpb247XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcmVhZG9ubHkgbm90aWZpY2F0aW9uQXJucz86IHN0cmluZ1tdO1xufVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbmV4cG9ydCBjbGFzcyBOZXN0ZWRTdGFjayBleHRlbmRzIFN0YWNrIHtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBzdGF0aWMgaXNOZXN0ZWRTdGFjayh4OiBhbnkpOiB4IGlzIE5lc3RlZFN0YWNrIHtcbiAgICByZXR1cm4geCAhPSBudWxsICYmIHR5cGVvZih4KSA9PT0gJ29iamVjdCcgJiYgTkVTVEVEX1NUQUNLX1NZTUJPTCBpbiB4O1xuICB9XG5cbiAgcHVibGljIHJlYWRvbmx5IHRlbXBsYXRlRmlsZTogc3RyaW5nO1xuICBwdWJsaWMgcmVhZG9ubHkgbmVzdGVkU3RhY2tSZXNvdXJjZT86IENmblJlc291cmNlO1xuXG4gIHByaXZhdGUgcmVhZG9ubHkgcGFyYW1ldGVyczogeyBbbmFtZTogc3RyaW5nXTogc3RyaW5nIH07XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVzb3VyY2U6IENmblN0YWNrO1xuICBwcml2YXRlIHJlYWRvbmx5IF9jb250ZXh0dWFsU3RhY2tJZDogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IF9jb250ZXh0dWFsU3RhY2tOYW1lOiBzdHJpbmc7XG4gIHByaXZhdGUgX3RlbXBsYXRlVXJsPzogc3RyaW5nO1xuICBwcml2YXRlIF9wYXJlbnRTdGFjazogU3RhY2s7XG5cbiAgY29uc3RydWN0b3Ioc2NvcGU6IENvbnN0cnVjdCwgaWQ6IHN0cmluZywgcHJvcHM6IE5lc3RlZFN0YWNrUHJvcHMgPSB7IH0pIHtcbiAgICBjb25zdCBwYXJlbnRTdGFjayA9IGZpbmRQYXJlbnRTdGFjayhzY29wZSk7XG5cbiAgICBzdXBlcihzY29wZSwgaWQsIHtcbiAgICAgIGVudjogeyBhY2NvdW50OiBwYXJlbnRTdGFjay5hY2NvdW50LCByZWdpb246IHBhcmVudFN0YWNrLnJlZ2lvbiB9LFxuICAgICAgc3ludGhlc2l6ZXI6IG5ldyBOZXN0ZWRTdGFja1N5bnRoZXNpemVyKHBhcmVudFN0YWNrLnN5bnRoZXNpemVyKSxcbiAgICB9KTtcblxuICAgIHRoaXMuX3BhcmVudFN0YWNrID0gcGFyZW50U3RhY2s7XG5cbiAgICAvLyBAZGVwcmVjYXRlOiByZW1vdmUgdGhpcyBpbiB2Mi4wIChyZWR1bmRlbnQpXG4gICAgY29uc3QgcGFyZW50U2NvcGUgPSBuZXcgQ29yZUNvbnN0cnVjdChzY29wZSwgaWQgKyAnLk5lc3RlZFN0YWNrJyk7XG5cbiAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcywgTkVTVEVEX1NUQUNLX1NZTUJPTCwgeyB2YWx1ZTogdHJ1ZSB9KTtcblxuICAgIC8vIHRoaXMgaXMgdGhlIGZpbGUgbmFtZSBvZiB0aGUgc3ludGhlc2l6ZWQgdGVtcGxhdGUgZmlsZSB3aXRoaW4gdGhlIGNsb3VkIGFzc2VtYmx5XG4gICAgdGhpcy50ZW1wbGF0ZUZpbGUgPSBgJHt0aGlzLm5vZGUudW5pcXVlSWR9Lm5lc3RlZC50ZW1wbGF0ZS5qc29uYDtcblxuICAgIHRoaXMucGFyYW1ldGVycyA9IHByb3BzLnBhcmFtZXRlcnMgfHwge307XG5cbiAgICB0aGlzLnJlc291cmNlID0gbmV3IENmblN0YWNrKHBhcmVudFNjb3BlLCBgJHtpZH0uTmVzdGVkU3RhY2tSZXNvdXJjZWAsIHtcbiAgICAgIHRlbXBsYXRlVXJsOiBMYXp5LnN0cmluZ1ZhbHVlKHsgcHJvZHVjZTogKCkgPT4gdGhpcy5fdGVtcGxhdGVVcmwgfHwgJzx1bnJlc29sdmVkPicgfSksXG4gICAgICBwYXJhbWV0ZXJzOiBMYXp5LmFueVZhbHVlKHsgcHJvZHVjZTogKCkgPT4gT2JqZWN0LmtleXModGhpcy5wYXJhbWV0ZXJzKS5sZW5ndGggPiAwID8gdGhpcy5wYXJhbWV0ZXJzIDogdW5kZWZpbmVkIH0pLFxuICAgICAgbm90aWZpY2F0aW9uQXJuczogcHJvcHMubm90aWZpY2F0aW9uQXJucyxcbiAgICAgIHRpbWVvdXRJbk1pbnV0ZXM6IHByb3BzLnRpbWVvdXQgPyBwcm9wcy50aW1lb3V0LnRvTWludXRlcygpIDogdW5kZWZpbmVkLFxuICAgIH0pO1xuXG4gICAgdGhpcy5uZXN0ZWRTdGFja1Jlc291cmNlID0gdGhpcy5yZXNvdXJjZTtcblxuICAgIC8vIGNvbnRleHQtYXdhcmUgc3RhY2sgbmFtZTogaWYgcmVzb2x2ZWQgZnJvbSB3aXRoaW4gdGhpcyBzdGFjaywgcmV0dXJuIEFXUzo6U3RhY2tOYW1lXG4gICAgLy8gaWYgcmVzb2x2ZWQgZnJvbSB0aGUgb3V0ZXIgc3RhY2ssIHVzZSB0aGUgeyBSZWYgfSBvZiB0aGUgQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2sgcmVzb3VyY2VcbiAgICAvLyB3aGljaCByZXNvbHZlcyB0aGUgQVJOIG9mIHRoZSBzdGFjay4gV2UgbmVlZCB0byBleHRyYWN0IHRoZSBzdGFjayBuYW1lLCB3aGljaCBpcyB0aGUgc2Vjb25kXG4gICAgLy8gY29tcG9uZW50IGFmdGVyIHNwbGl0dGluZyBieSBcIi9cIlxuICAgIHRoaXMuX2NvbnRleHR1YWxTdGFja05hbWUgPSB0aGlzLmNvbnRleHR1YWxBdHRyaWJ1dGUoQXdzLlNUQUNLX05BTUUsIEZuLnNlbGVjdCgxLCBGbi5zcGxpdCgnLycsIHRoaXMucmVzb3VyY2UucmVmKSkpO1xuICAgIHRoaXMuX2NvbnRleHR1YWxTdGFja0lkID0gdGhpcy5jb250ZXh0dWFsQXR0cmlidXRlKEF3cy5TVEFDS19JRCwgdGhpcy5yZXNvdXJjZS5yZWYpO1xuICB9XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICBwdWJsaWMgZ2V0IHN0YWNrTmFtZSgpIHtcbiAgICByZXR1cm4gdGhpcy5fY29udGV4dHVhbFN0YWNrTmFtZTtcbiAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gIHB1YmxpYyBnZXQgc3RhY2tJZCgpIHtcbiAgICByZXR1cm4gdGhpcy5fY29udGV4dHVhbFN0YWNrSWQ7XG4gIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgcHVibGljIHNldFBhcmFtZXRlcihuYW1lOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcpIHtcbiAgICB0aGlzLnBhcmFtZXRlcnNbbmFtZV0gPSB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWZpbmVzIGFuIGFzc2V0IGF0IHRoZSBwYXJlbnQgc3RhY2sgd2hpY2ggcmVwcmVzZW50cyB0aGUgdGVtcGxhdGUgb2YgdGhpc1xuICAgKiBuZXN0ZWQgc3RhY2suXG4gICAqXG4gICAqIFRoaXMgcHJpdmF0ZSBBUEkgaXMgdXNlZCBieSBgQXBwLnByZXBhcmUoKWAgd2l0aGluIGEgbG9vcCB0aGF0IHJlY3RpZmllc1xuICAgKiByZWZlcmVuY2VzIGV2ZXJ5IHRpbWUgYW4gYXNzZXQgaXMgYWRkZWQuIFRoaXMgaXMgYmVjYXVzZSAoYXQgdGhlIG1vbWVudClcbiAgICogYXNzZXRzIGFyZSBhZGRyZXNzZWQgdXNpbmcgQ2xvdWRGb3JtYXRpb24gcGFyYW1ldGVycy5cbiAgICpcbiAgICogQHJldHVybnMgYHRydWVgIGlmIGEgbmV3IGFzc2V0IHdhcyBhZGRlZCBvciBgZmFsc2VgIGlmIGFuIGFzc2V0IHdhc1xuICAgKiBwcmV2aW91c2x5IGFkZGVkLiBXaGVuIHRoaXMgcmV0dXJucyBgdHJ1ZWAsIEFwcCB3aWxsIGRvIGFub3RoZXIgcmVmZXJlbmNlXG4gICAqIHJlY3RpZmljYXRpb24gY3ljbGUuXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgcHVibGljIF9wcmVwYXJlVGVtcGxhdGVBc3NldCgpIHtcbiAgICBpZiAodGhpcy5fdGVtcGxhdGVVcmwpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCBjZm4gPSBKU09OLnN0cmluZ2lmeSh0aGlzLl90b0Nsb3VkRm9ybWF0aW9uKCkpO1xuICAgIGNvbnN0IHRlbXBsYXRlSGFzaCA9IGNyeXB0by5jcmVhdGVIYXNoKCdzaGEyNTYnKS51cGRhdGUoY2ZuKS5kaWdlc3QoJ2hleCcpO1xuXG4gICAgY29uc3QgdGVtcGxhdGVMb2NhdGlvbiA9IHRoaXMuX3BhcmVudFN0YWNrLmFkZEZpbGVBc3NldCh7XG4gICAgICBwYWNrYWdpbmc6IEZpbGVBc3NldFBhY2thZ2luZy5GSUxFLFxuICAgICAgc291cmNlSGFzaDogdGVtcGxhdGVIYXNoLFxuICAgICAgZmlsZU5hbWU6IHRoaXMudGVtcGxhdGVGaWxlLFxuICAgIH0pO1xuXG4gICAgLy8gaWYgYnVja2V0TmFtZS9vYmplY3RLZXkgYXJlIGNmbiBwYXJhbWV0ZXJzIGZyb20gYSBzdGFjayBvdGhlciB0aGFuIHRoZSBwYXJlbnQgc3RhY2ssIHRoZXkgd2lsbFxuICAgIC8vIGJlIHJlc29sdmVkIGFzIGNyb3NzLXN0YWNrIHJlZmVyZW5jZXMgbGlrZSBhbnkgb3RoZXIgKHNlZSBcIm11bHRpXCIgdGVzdHMpLlxuICAgIHRoaXMuX3RlbXBsYXRlVXJsID0gYGh0dHBzOi8vczMuJHt0aGlzLl9wYXJlbnRTdGFjay5yZWdpb259LiR7dGhpcy5fcGFyZW50U3RhY2sudXJsU3VmZml4fS8ke3RlbXBsYXRlTG9jYXRpb24uYnVja2V0TmFtZX0vJHt0ZW1wbGF0ZUxvY2F0aW9uLm9iamVjdEtleX1gO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgcHJpdmF0ZSBjb250ZXh0dWFsQXR0cmlidXRlKGlubmVyVmFsdWU6IHN0cmluZywgb3V0ZXJWYWx1ZTogc3RyaW5nKSB7XG4gICAgcmV0dXJuIFRva2VuLmFzU3RyaW5nKHtcbiAgICAgIHJlc29sdmU6IChjb250ZXh0OiBJUmVzb2x2ZUNvbnRleHQpID0+IHtcbiAgICAgICAgaWYgKFN0YWNrLm9mKGNvbnRleHQuc2NvcGUpID09PSB0aGlzKSB7XG4gICAgICAgICAgcmV0dXJuIGlubmVyVmFsdWU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIG91dGVyVmFsdWU7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cbn1cblxuLyoqXG4gKiBWYWxpZGF0ZXMgdGhlIHNjb3BlIGZvciBhIG5lc3RlZCBzdGFjay4gTmVzdGVkIHN0YWNrcyBtdXN0IGJlIGRlZmluZWQgd2l0aGluIHRoZSBzY29wZSBvZiBhbm90aGVyIGBTdGFja2AuXG4gKi9cbmZ1bmN0aW9uIGZpbmRQYXJlbnRTdGFjayhzY29wZTogQ29uc3RydWN0KTogU3RhY2sge1xuICBpZiAoIXNjb3BlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdOZXN0ZWQgc3RhY2tzIGNhbm5vdCBiZSBkZWZpbmVkIGFzIGEgcm9vdCBjb25zdHJ1Y3QnKTtcbiAgfVxuXG4gIGNvbnN0IHBhcmVudFN0YWNrID0gTm9kZS5vZihzY29wZSkuc2NvcGVzLnJldmVyc2UoKS5maW5kKHAgPT4gU3RhY2suaXNTdGFjayhwKSk7XG4gIGlmICghcGFyZW50U3RhY2spIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ05lc3RlZCBzdGFja3MgbXVzdCBiZSBkZWZpbmVkIHdpdGhpbiBzY29wZSBvZiBhbm90aGVyIG5vbi1uZXN0ZWQgc3RhY2snKTtcbiAgfVxuXG4gIHJldHVybiBwYXJlbnRTdGFjayBhcyBTdGFjaztcbn1cbiJdfQ==