UNPKG

30.7 kBJavaScriptView Raw
1"use strict";
2var _a;
3Object.defineProperty(exports, "__esModule", { value: true });
4exports.NestedStack = void 0;
5const jsiiDeprecationWarnings = require("../.warnings.jsii.js");
6const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
7const crypto = require("crypto");
8const cxapi = require("@aws-cdk/cx-api");
9const constructs_1 = require("constructs");
10const assets_1 = require("./assets");
11const cfn_fn_1 = require("./cfn-fn");
12const cfn_pseudo_1 = require("./cfn-pseudo");
13const cloudformation_generated_1 = require("./cloudformation.generated");
14const lazy_1 = require("./lazy");
15const names_1 = require("./names");
16const removal_policy_1 = require("./removal-policy");
17const stack_1 = require("./stack");
18const stack_synthesizers_1 = require("./stack-synthesizers");
19const token_1 = require("./token");
20// v2 - keep this import as a separate section to reduce merge conflict when forward merging with the v2 branch.
21// eslint-disable-next-line
22const construct_compat_1 = require("./construct-compat");
23const NESTED_STACK_SYMBOL = Symbol.for('@aws-cdk/core.NestedStack');
24/**
25 * A CloudFormation nested stack.
26 *
27 * When you apply template changes to update a top-level stack, CloudFormation
28 * updates the top-level stack and initiates an update to its nested stacks.
29 * CloudFormation updates the resources of modified nested stacks, but does not
30 * update the resources of unmodified nested stacks.
31 *
32 * Furthermore, this stack will not be treated as an independent deployment
33 * artifact (won't be listed in "cdk list" or deployable through "cdk deploy"),
34 * but rather only synthesized as a template and uploaded as an asset to S3.
35 *
36 * Cross references of resource attributes between the parent stack and the
37 * nested stack will automatically be translated to stack parameters and
38 * outputs.
39 *
40 */
41class NestedStack extends stack_1.Stack {
42 constructor(scope, id, props = {}) {
43 try {
44 jsiiDeprecationWarnings._aws_cdk_core_NestedStackProps(props);
45 }
46 catch (error) {
47 if (process.env.JSII_DEBUG !== "1" && error.name === "DeprecationError") {
48 Error.captureStackTrace(error, NestedStack);
49 }
50 throw error;
51 }
52 const parentStack = findParentStack(scope);
53 super(scope, id, {
54 env: { account: parentStack.account, region: parentStack.region },
55 synthesizer: new stack_synthesizers_1.NestedStackSynthesizer(parentStack.synthesizer),
56 });
57 this._parentStack = parentStack;
58 // @deprecate: remove this in v2.0 (redundent)
59 const parentScope = new construct_compat_1.Construct(scope, id + '.NestedStack');
60 Object.defineProperty(this, NESTED_STACK_SYMBOL, { value: true });
61 // this is the file name of the synthesized template file within the cloud assembly
62 this.templateFile = `${names_1.Names.uniqueId(this)}.nested.template.json`;
63 this.parameters = props.parameters || {};
64 this.resource = new cloudformation_generated_1.CfnStack(parentScope, `${id}.NestedStackResource`, {
65 // This value cannot be cached since it changes during the synthesis phase
66 templateUrl: lazy_1.Lazy.uncachedString({ produce: () => this._templateUrl || '<unresolved>' }),
67 parameters: lazy_1.Lazy.any({ produce: () => Object.keys(this.parameters).length > 0 ? this.parameters : undefined }),
68 notificationArns: props.notificationArns,
69 timeoutInMinutes: props.timeout ? props.timeout.toMinutes() : undefined,
70 });
71 this.resource.applyRemovalPolicy(props.removalPolicy ?? removal_policy_1.RemovalPolicy.DESTROY);
72 this.nestedStackResource = this.resource;
73 this.node.defaultChild = this.resource;
74 // context-aware stack name: if resolved from within this stack, return AWS::StackName
75 // if resolved from the outer stack, use the { Ref } of the AWS::CloudFormation::Stack resource
76 // which resolves the ARN of the stack. We need to extract the stack name, which is the second
77 // component after splitting by "/"
78 this._contextualStackName = this.contextualAttribute(cfn_pseudo_1.Aws.STACK_NAME, cfn_fn_1.Fn.select(1, cfn_fn_1.Fn.split('/', this.resource.ref)));
79 this._contextualStackId = this.contextualAttribute(cfn_pseudo_1.Aws.STACK_ID, this.resource.ref);
80 }
81 /**
82 * Checks if `x` is an object of type `NestedStack`.
83 */
84 static isNestedStack(x) {
85 return x != null && typeof (x) === 'object' && NESTED_STACK_SYMBOL in x;
86 }
87 /**
88 * An attribute that represents the name of the nested stack.
89 *
90 * This is a context aware attribute:
91 * - If this is referenced from the parent stack, it will return a token that parses the name from the stack ID.
92 * - If this is referenced from the context of the nested stack, it will return `{ "Ref": "AWS::StackName" }`
93 *
94 * Example value: `mystack-mynestedstack-sggfrhxhum7w`
95 * @attribute
96 */
97 get stackName() {
98 return this._contextualStackName;
99 }
100 /**
101 * An attribute that represents the ID of the stack.
102 *
103 * This is a context aware attribute:
104 * - If this is referenced from the parent stack, it will return `{ "Ref": "LogicalIdOfNestedStackResource" }`.
105 * - If this is referenced from the context of the nested stack, it will return `{ "Ref": "AWS::StackId" }`
106 *
107 * Example value: `arn:aws:cloudformation:us-east-2:123456789012:stack/mystack-mynestedstack-sggfrhxhum7w/f449b250-b969-11e0-a185-5081d0136786`
108 * @attribute
109 */
110 get stackId() {
111 return this._contextualStackId;
112 }
113 /**
114 * Assign a value to one of the nested stack parameters.
115 * @param name The parameter name (ID)
116 * @param value The value to assign
117 */
118 setParameter(name, value) {
119 this.parameters[name] = value;
120 }
121 /**
122 * Defines an asset at the parent stack which represents the template of this
123 * nested stack.
124 *
125 * This private API is used by `App.prepare()` within a loop that rectifies
126 * references every time an asset is added. This is because (at the moment)
127 * assets are addressed using CloudFormation parameters.
128 *
129 * @returns `true` if a new asset was added or `false` if an asset was
130 * previously added. When this returns `true`, App will do another reference
131 * rectification cycle.
132 *
133 * @internal
134 */
135 _prepareTemplateAsset() {
136 if (this._templateUrl) {
137 return false;
138 }
139 // When adding tags to nested stack, the tags need to be added to all the resources in
140 // in nested stack, which is handled by the `tags` property, But to tag the
141 // tags have to be added in the parent stack CfnStack resource. The CfnStack resource created
142 // by this class dont share the same TagManager as that of the one exposed by the `tag` property of the
143 // class, all the tags need to be copied to the CfnStack resource before synthesizing the resource.
144 // See https://github.com/aws/aws-cdk/pull/19128
145 Object.entries(this.tags.tagValues()).forEach(([key, value]) => {
146 this.resource.tags.setTag(key, value);
147 });
148 const cfn = JSON.stringify(this._toCloudFormation());
149 const templateHash = crypto.createHash('sha256').update(cfn).digest('hex');
150 const templateLocation = this._parentStack.synthesizer.addFileAsset({
151 packaging: assets_1.FileAssetPackaging.FILE,
152 sourceHash: templateHash,
153 fileName: this.templateFile,
154 });
155 this.addResourceMetadata(this.resource, 'TemplateURL');
156 // if bucketName/objectKey are cfn parameters from a stack other than the parent stack, they will
157 // be resolved as cross-stack references like any other (see "multi" tests).
158 this._templateUrl = `https://s3.${this._parentStack.region}.${this._parentStack.urlSuffix}/${templateLocation.bucketName}/${templateLocation.objectKey}`;
159 return true;
160 }
161 contextualAttribute(innerValue, outerValue) {
162 return token_1.Token.asString({
163 resolve: (context) => {
164 if (stack_1.Stack.of(context.scope) === this) {
165 return innerValue;
166 }
167 else {
168 return outerValue;
169 }
170 },
171 });
172 }
173 addResourceMetadata(resource, resourceProperty) {
174 if (!this.node.tryGetContext(cxapi.ASSET_RESOURCE_METADATA_ENABLED_CONTEXT)) {
175 return; // not enabled
176 }
177 // tell tools such as SAM CLI that the "TemplateURL" property of this resource
178 // points to the nested stack template for local emulation
179 resource.cfnOptions.metadata = resource.cfnOptions.metadata || {};
180 resource.cfnOptions.metadata[cxapi.ASSET_RESOURCE_METADATA_PATH_KEY] = this.templateFile;
181 resource.cfnOptions.metadata[cxapi.ASSET_RESOURCE_METADATA_PROPERTY_KEY] = resourceProperty;
182 }
183}
184exports.NestedStack = NestedStack;
185_a = JSII_RTTI_SYMBOL_1;
186NestedStack[_a] = { fqn: "@aws-cdk/core.NestedStack", version: "1.204.0" };
187/**
188 * Validates the scope for a nested stack. Nested stacks must be defined within the scope of another `Stack`.
189 */
190function findParentStack(scope) {
191 if (!scope) {
192 throw new Error('Nested stacks cannot be defined as a root construct');
193 }
194 const parentStack = constructs_1.Node.of(scope).scopes.reverse().find(p => stack_1.Stack.isStack(p));
195 if (!parentStack) {
196 throw new Error('Nested stacks must be defined within scope of another non-nested stack');
197 }
198 return parentStack;
199}
200//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmVzdGVkLXN0YWNrLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsibmVzdGVkLXN0YWNrLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7OztBQUFBLGlDQUFpQztBQUNqQyx5Q0FBeUM7QUFDekMsMkNBQTZDO0FBQzdDLHFDQUE4QztBQUM5QyxxQ0FBOEI7QUFDOUIsNkNBQW1DO0FBRW5DLHlFQUFzRDtBQUV0RCxpQ0FBOEI7QUFDOUIsbUNBQWdDO0FBQ2hDLHFEQUFpRDtBQUVqRCxtQ0FBZ0M7QUFDaEMsNkRBQThEO0FBQzlELG1DQUFnQztBQUVoQyxnSEFBZ0g7QUFDaEgsMkJBQTJCO0FBQzNCLHlEQUFnRTtBQUVoRSxNQUFNLG1CQUFtQixHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLENBQUMsQ0FBQztBQXVEcEU7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCxNQUFhLFdBQVksU0FBUSxhQUFLO0lBbUJwQyxZQUFZLEtBQWdCLEVBQUUsRUFBVSxFQUFFLFFBQTBCLEVBQUc7Ozs7OzsrQ0FuQjVELFdBQVc7Ozs7UUFvQnBCLE1BQU0sV0FBVyxHQUFHLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUUzQyxLQUFLLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRTtZQUNmLEdBQUcsRUFBRSxFQUFFLE9BQU8sRUFBRSxXQUFXLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxXQUFXLENBQUMsTUFBTSxFQUFFO1lBQ2pFLFdBQVcsRUFBRSxJQUFJLDJDQUFzQixDQUFDLFdBQVcsQ0FBQyxXQUFXLENBQUM7U0FDakUsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLFlBQVksR0FBRyxXQUFXLENBQUM7UUFFaEMsOENBQThDO1FBQzlDLE1BQU0sV0FBVyxHQUFHLElBQUksNEJBQWEsQ0FBQyxLQUFLLEVBQUUsRUFBRSxHQUFHLGNBQWMsQ0FBQyxDQUFDO1FBRWxFLE1BQU0sQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFLG1CQUFtQixFQUFFLEVB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QU8sV0FBb0IsQ0FBQztBQUM5QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY3J5cHRvIGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgKiBhcyBjeGFwaSBmcm9tICdAYXdzLWNkay9jeC1hcGknO1xuaW1wb3J0IHsgQ29uc3RydWN0LCBOb2RlIH0gZnJvbSAnY29uc3RydWN0cyc7XG5pbXBvcnQgeyBGaWxlQXNzZXRQYWNrYWdpbmcgfSBmcm9tICcuL2Fzc2V0cyc7XG5pbXBvcnQgeyBGbiB9IGZyb20gJy4vY2ZuLWZuJztcbmltcG9ydCB7IEF3cyB9IGZyb20gJy4vY2ZuLXBzZXVkbyc7XG5pbXBvcnQgeyBDZm5SZXNvdXJjZSB9IGZyb20gJy4vY2ZuLXJlc291cmNlJztcbmltcG9ydCB7IENmblN0YWNrIH0gZnJvbSAnLi9jbG91ZGZvcm1hdGlvbi5nZW5lcmF0ZWQnO1xuaW1wb3J0IHsgRHVyYXRpb24gfSBmcm9tICcuL2R1cmF0aW9uJztcbmltcG9ydCB7IExhenkgfSBmcm9tICcuL2xhenknO1xuaW1wb3J0IHsgTmFtZXMgfSBmcm9tICcuL25hbWVzJztcbmltcG9ydCB7IFJlbW92YWxQb2xpY3kgfSBmcm9tICcuL3JlbW92YWwtcG9saWN5JztcbmltcG9ydCB7IElSZXNvbHZlQ29udGV4dCB9IGZyb20gJy4vcmVzb2x2YWJsZSc7XG5pbXBvcnQgeyBTdGFjayB9IGZyb20gJy4vc3RhY2snO1xuaW1wb3J0IHsgTmVzdGVkU3RhY2tTeW50aGVzaXplciB9IGZyb20gJy4vc3RhY2stc3ludGhlc2l6ZXJzJztcbmltcG9ydCB7IFRva2VuIH0gZnJvbSAnLi90b2tlbic7XG5cbi8vIHYyIC0ga2VlcCB0aGlzIGltcG9ydCBhcyBhIHNlcGFyYXRlIHNlY3Rpb24gdG8gcmVkdWNlIG1lcmdlIGNvbmZsaWN0IHdoZW4gZm9yd2FyZCBtZXJnaW5nIHdpdGggdGhlIHYyIGJyYW5jaC5cbi8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZVxuaW1wb3J0IHsgQ29uc3RydWN0IGFzIENvcmVDb25zdHJ1Y3QgfSBmcm9tICcuL2NvbnN0cnVjdC1jb21wYXQnO1xuXG5jb25zdCBORVNURURfU1RBQ0tfU1lNQk9MID0gU3ltYm9sLmZvcignQGF3cy1jZGsvY29yZS5OZXN0ZWRTdGFjaycpO1xuXG4vKipcbiAqIEluaXRpYWxpemF0aW9uIHByb3BzIGZvciB0aGUgYE5lc3RlZFN0YWNrYCBjb25zdHJ1Y3QuXG4gKlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE5lc3RlZFN0YWNrUHJvcHMge1xuICAvKipcbiAgICogVGhlIHNldCB2YWx1ZSBwYWlycyB0aGF0IHJlcHJlc2VudCB0aGUgcGFyYW1ldGVycyBwYXNzZWQgdG8gQ2xvdWRGb3JtYXRpb25cbiAgICogd2hlbiB0aGlzIG5lc3RlZCBzdGFjayBpcyBjcmVhdGVkLiBFYWNoIHBhcmFtZXRlciBoYXMgYSBuYW1lIGNvcnJlc3BvbmRpbmdcbiAgICogdG8gYSBwYXJhbWV0ZXIgZGVmaW5lZCBpbiB0aGUgZW1iZWRkZWQgdGVtcGxhdGUgYW5kIGEgdmFsdWUgcmVwcmVzZW50aW5nXG4gICAqIHRoZSB2YWx1ZSB0aGF0IHlvdSB3YW50IHRvIHNldCBmb3IgdGhlIHBhcmFtZXRlci5cbiAgICpcbiAgICogVGhlIG5lc3RlZCBzdGFjayBjb25zdHJ1Y3Qgd2lsbCBhdXRvbWF0aWNhbGx5IHN5bnRoZXNpemUgcGFyYW1ldGVycyBpbiBvcmRlclxuICAgKiB0byBiaW5kIHJlZmVyZW5jZXMgZnJvbSB0aGUgcGFyZW50IHN0YWNrKHMpIGludG8gdGhlIG5lc3RlZCBzdGFjay5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyB1c2VyLWRlZmluZWQgcGFyYW1ldGVycyBhcmUgcGFzc2VkIHRvIHRoZSBuZXN0ZWQgc3RhY2tcbiAgICovXG4gIHJlYWRvbmx5IHBhcmFtZXRlcnM/OiB7IFtrZXk6IHN0cmluZ106IHN0cmluZyB9O1xuXG4gIC8qKlxuICAgKiBUaGUgbGVuZ3RoIG9mIHRpbWUgdGhhdCBDbG91ZEZvcm1hdGlvbiB3YWl0cyBmb3IgdGhlIG5lc3RlZCBzdGFjayB0byByZWFjaFxuICAgKiB0aGUgQ1JFQVRFX0NPTVBMRVRFIHN0YXRlLlxuICAgKlxuICAgKiBXaGVuIENsb3VkRm9ybWF0aW9uIGRldGVjdHMgdGhhdCB0aGUgbmVzdGVkIHN0YWNrIGhhcyByZWFjaGVkIHRoZVxuICAgKiBDUkVBVEVfQ09NUExFVEUgc3RhdGUsIGl0IG1hcmtzIHRoZSBuZXN0ZWQgc3RhY2sgcmVzb3VyY2UgYXNcbiAgICogQ1JFQVRFX0NPTVBMRVRFIGluIHRoZSBwYXJlbnQgc3RhY2sgYW5kIHJlc3VtZXMgY3JlYXRpbmcgdGhlIHBhcmVudCBzdGFjay5cbiAgICogSWYgdGhlIHRpbWVvdXQgcGVyaW9kIGV4cGlyZXMgYmVmb3JlIHRoZSBuZXN0ZWQgc3RhY2sgcmVhY2hlc1xuICAgKiBDUkVBVEVfQ09NUExFVEUsIENsb3VkRm9ybWF0aW9uIG1hcmtzIHRoZSBuZXN0ZWQgc3RhY2sgYXMgZmFpbGVkIGFuZCByb2xsc1xuICAgKiBiYWNrIGJvdGggdGhlIG5lc3RlZCBzdGFjayBhbmQgcGFyZW50IHN0YWNrLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIG5vIHRpbWVvdXRcbiAgICovXG4gIHJlYWRvbmx5IHRpbWVvdXQ/OiBEdXJhdGlvbjtcblxuICAvKipcbiAgICogVGhlIFNpbXBsZSBOb3RpZmljYXRpb24gU2VydmljZSAoU05TKSB0b3BpY3MgdG8gcHVibGlzaCBzdGFjayByZWxhdGVkXG4gICAqIGV2ZW50cy5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBub3RpZmljYXRpb25zIGFyZSBub3Qgc2VudCBmb3IgdGhpcyBzdGFjay5cbiAgICovXG4gIHJlYWRvbmx5IG5vdGlmaWNhdGlvbkFybnM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogUG9saWN5IHRvIGFwcGx5IHdoZW4gdGhlIG5lc3RlZCBzdGFjayBpcyByZW1vdmVkXG4gICAqXG4gICAqIFRoZSBkZWZhdWx0IGlzIGBEZXN0cm95YCwgYmVjYXVzZSBhbGwgUmVtb3ZhbCBQb2xpY2llcyBvZiByZXNvdXJjZXMgaW5zaWRlIHRoZVxuICAgKiBOZXN0ZWQgU3RhY2sgc2hvdWxkIGFscmVhZHkgaGF2ZSBiZWVuIHNldCBjb3JyZWN0bHkuIFlvdSBub3JtYWxseSBzaG91bGRcbiAgICogbm90IG5lZWQgdG8gc2V0IHRoaXMgdmFsdWUuXG4gICAqXG4gICAqIEBkZWZhdWx0IFJlbW92YWxQb2xpY3kuREVTVFJPWVxuICAgKi9cbiAgcmVhZG9ubHkgcmVtb3ZhbFBvbGljeT86IFJlbW92YWxQb2xpY3k7XG59XG5cbi8qKlxuICogQSBDbG91ZEZvcm1hdGlvbiBuZXN0ZWQgc3RhY2suXG4gKlxuICogV2hlbiB5b3UgYXBwbHkgdGVtcGxhdGUgY2hhbmdlcyB0byB1cGRhdGUgYSB0b3AtbGV2ZWwgc3RhY2ssIENsb3VkRm9ybWF0aW9uXG4gKiB1cGRhdGVzIHRoZSB0b3AtbGV2ZWwgc3RhY2sgYW5kIGluaXRpYXRlcyBhbiB1cGRhdGUgdG8gaXRzIG5lc3RlZCBzdGFja3MuXG4gKiBDbG91ZEZvcm1hdGlvbiB1cGRhdGVzIHRoZSByZXNvdXJjZXMgb2YgbW9kaWZpZWQgbmVzdGVkIHN0YWNrcywgYnV0IGRvZXMgbm90XG4gKiB1cGRhdGUgdGhlIHJlc291cmNlcyBvZiB1bm1vZGlmaWVkIG5lc3RlZCBzdGFja3MuXG4gKlxuICogRnVydGhlcm1vcmUsIHRoaXMgc3RhY2sgd2lsbCBub3QgYmUgdHJlYXRlZCBhcyBhbiBpbmRlcGVuZGVudCBkZXBsb3ltZW50XG4gKiBhcnRpZmFjdCAod29uJ3QgYmUgbGlzdGVkIGluIFwiY2RrIGxpc3RcIiBvciBkZXBsb3lhYmxlIHRocm91Z2ggXCJjZGsgZGVwbG95XCIpLFxuICogYnV0IHJhdGhlciBvbmx5IHN5bnRoZXNpemVkIGFzIGEgdGVtcGxhdGUgYW5kIHVwbG9hZGVkIGFzIGFuIGFzc2V0IHRvIFMzLlxuICpcbiAqIENyb3NzIHJlZmVyZW5jZXMgb2YgcmVzb3VyY2UgYXR0cmlidXRlcyBiZXR3ZWVuIHRoZSBwYXJlbnQgc3RhY2sgYW5kIHRoZVxuICogbmVzdGVkIHN0YWNrIHdpbGwgYXV0b21hdGljYWxseSBiZSB0cmFuc2xhdGVkIHRvIHN0YWNrIHBhcmFtZXRlcnMgYW5kXG4gKiBvdXRwdXRzLlxuICpcbiAqL1xuZXhwb3J0IGNsYXNzIE5lc3RlZFN0YWNrIGV4dGVuZHMgU3RhY2sge1xuXG4gIC8qKlxuICAgKiBDaGVja3MgaWYgYHhgIGlzIGFuIG9iamVjdCBvZiB0eXBlIGBOZXN0ZWRTdGFja2AuXG4gICAqL1xuICBwdWJsaWMgc3RhdGljIGlzTmVzdGVkU3RhY2soeDogYW55KTogeCBpcyBOZXN0ZWRTdGFjayB7XG4gICAgcmV0dXJuIHggIT0gbnVsbCAmJiB0eXBlb2YoeCkgPT09ICdvYmplY3QnICYmIE5FU1RFRF9TVEFDS19TWU1CT0wgaW4geDtcbiAgfVxuXG4gIHB1YmxpYyByZWFkb25seSB0ZW1wbGF0ZUZpbGU6IHN0cmluZztcbiAgcHVibGljIHJlYWRvbmx5IG5lc3RlZFN0YWNrUmVzb3VyY2U/OiBDZm5SZXNvdXJjZTtcblxuICBwcml2YXRlIHJlYWRvbmx5IHBhcmFtZXRlcnM6IHsgW25hbWU6IHN0cmluZ106IHN0cmluZyB9O1xuICBwcml2YXRlIHJlYWRvbmx5IHJlc291cmNlOiBDZm5TdGFjaztcbiAgcHJpdmF0ZSByZWFkb25seSBfY29udGV4dHVhbFN0YWNrSWQ6IHN0cmluZztcbiAgcHJpdmF0ZSByZWFkb25seSBfY29udGV4dHVhbFN0YWNrTmFtZTogc3RyaW5nO1xuICBwcml2YXRlIF90ZW1wbGF0ZVVybD86IHN0cmluZztcbiAgcHJpdmF0ZSBfcGFyZW50U3RhY2s6IFN0YWNrO1xuXG4gIGNvbnN0cnVjdG9yKHNjb3BlOiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBOZXN0ZWRTdGFja1Byb3BzID0geyB9KSB7XG4gICAgY29uc3QgcGFyZW50U3RhY2sgPSBmaW5kUGFyZW50U3RhY2soc2NvcGUpO1xuXG4gICAgc3VwZXIoc2NvcGUsIGlkLCB7XG4gICAgICBlbnY6IHsgYWNjb3VudDogcGFyZW50U3RhY2suYWNjb3VudCwgcmVnaW9uOiBwYXJlbnRTdGFjay5yZWdpb24gfSxcbiAgICAgIHN5bnRoZXNpemVyOiBuZXcgTmVzdGVkU3RhY2tTeW50aGVzaXplcihwYXJlbnRTdGFjay5zeW50aGVzaXplciksXG4gICAgfSk7XG5cbiAgICB0aGlzLl9wYXJlbnRTdGFjayA9IHBhcmVudFN0YWNrO1xuXG4gICAgLy8gQGRlcHJlY2F0ZTogcmVtb3ZlIHRoaXMgaW4gdjIuMCAocmVkdW5kZW50KVxuICAgIGNvbnN0IHBhcmVudFNjb3BlID0gbmV3IENvcmVDb25zdHJ1Y3Qoc2NvcGUsIGlkICsgJy5OZXN0ZWRTdGFjaycpO1xuXG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KHRoaXMsIE5FU1RFRF9TVEFDS19TWU1CT0wsIHsgdmFsdWU6IHRydWUgfSk7XG5cbiAgICAvLyB0aGlzIGlzIHRoZSBmaWxlIG5hbWUgb2YgdGhlIHN5bnRoZXNpemVkIHRlbXBsYXRlIGZpbGUgd2l0aGluIHRoZSBjbG91ZCBhc3NlbWJseVxuICAgIHRoaXMudGVtcGxhdGVGaWxlID0gYCR7TmFtZXMudW5pcXVlSWQodGhpcyl9Lm5lc3RlZC50ZW1wbGF0ZS5qc29uYDtcblxuICAgIHRoaXMucGFyYW1ldGVycyA9IHByb3BzLnBhcmFtZXRlcnMgfHwge307XG5cbiAgICB0aGlzLnJlc291cmNlID0gbmV3IENmblN0YWNrKHBhcmVudFNjb3BlLCBgJHtpZH0uTmVzdGVkU3RhY2tSZXNvdXJjZWAsIHtcbiAgICAgIC8vIFRoaXMgdmFsdWUgY2Fubm90IGJlIGNhY2hlZCBzaW5jZSBpdCBjaGFuZ2VzIGR1cmluZyB0aGUgc3ludGhlc2lzIHBoYXNlXG4gICAgICB0ZW1wbGF0ZVVybDogTGF6eS51bmNhY2hlZFN0cmluZyh7IHByb2R1Y2U6ICgpID0+IHRoaXMuX3RlbXBsYXRlVXJsIHx8ICc8dW5yZXNvbHZlZD4nIH0pLFxuICAgICAgcGFyYW1ldGVyczogTGF6eS5hbnkoeyBwcm9kdWNlOiAoKSA9PiBPYmplY3Qua2V5cyh0aGlzLnBhcmFtZXRlcnMpLmxlbmd0aCA+IDAgPyB0aGlzLnBhcmFtZXRlcnMgOiB1bmRlZmluZWQgfSksXG4gICAgICBub3RpZmljYXRpb25Bcm5zOiBwcm9wcy5ub3RpZmljYXRpb25Bcm5zLFxuICAgICAgdGltZW91dEluTWludXRlczogcHJvcHMudGltZW91dCA/IHByb3BzLnRpbWVvdXQudG9NaW51dGVzKCkgOiB1bmRlZmluZWQsXG4gICAgfSk7XG4gICAgdGhpcy5yZXNvdXJjZS5hcHBseVJlbW92YWxQb2xpY3kocHJvcHMucmVtb3ZhbFBvbGljeSA/PyBSZW1vdmFsUG9saWN5LkRFU1RST1kpO1xuXG4gICAgdGhpcy5uZXN0ZWRTdGFja1Jlc291cmNlID0gdGhpcy5yZXNvdXJjZTtcbiAgICB0aGlzLm5vZGUuZGVmYXVsdENoaWxkID0gdGhpcy5yZXNvdXJjZTtcblxuICAgIC8vIGNvbnRleHQtYXdhcmUgc3RhY2sgbmFtZTogaWYgcmVzb2x2ZWQgZnJvbSB3aXRoaW4gdGhpcyBzdGFjaywgcmV0dXJuIEFXUzo6U3RhY2tOYW1lXG4gICAgLy8gaWYgcmVzb2x2ZWQgZnJvbSB0aGUgb3V0ZXIgc3RhY2ssIHVzZSB0aGUgeyBSZWYgfSBvZiB0aGUgQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2sgcmVzb3VyY2VcbiAgICAvLyB3aGljaCByZXNvbHZlcyB0aGUgQVJOIG9mIHRoZSBzdGFjay4gV2UgbmVlZCB0byBleHRyYWN0IHRoZSBzdGFjayBuYW1lLCB3aGljaCBpcyB0aGUgc2Vjb25kXG4gICAgLy8gY29tcG9uZW50IGFmdGVyIHNwbGl0dGluZyBieSBcIi9cIlxuICAgIHRoaXMuX2NvbnRleHR1YWxTdGFja05hbWUgPSB0aGlzLmNvbnRleHR1YWxBdHRyaWJ1dGUoQXdzLlNUQUNLX05BTUUsIEZuLnNlbGVjdCgxLCBGbi5zcGxpdCgnLycsIHRoaXMucmVzb3VyY2UucmVmKSkpO1xuICAgIHRoaXMuX2NvbnRleHR1YWxTdGFja0lkID0gdGhpcy5jb250ZXh0dWFsQXR0cmlidXRlKEF3cy5TVEFDS19JRCwgdGhpcy5yZXNvdXJjZS5yZWYpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFuIGF0dHJpYnV0ZSB0aGF0IHJlcHJlc2VudHMgdGhlIG5hbWUgb2YgdGhlIG5lc3RlZCBzdGFjay5cbiAgICpcbiAgICogVGhpcyBpcyBhIGNvbnRleHQgYXdhcmUgYXR0cmlidXRlOlxuICAgKiAtIElmIHRoaXMgaXMgcmVmZXJlbmNlZCBmcm9tIHRoZSBwYXJlbnQgc3RhY2ssIGl0IHdpbGwgcmV0dXJuIGEgdG9rZW4gdGhhdCBwYXJzZXMgdGhlIG5hbWUgZnJvbSB0aGUgc3RhY2sgSUQuXG4gICAqIC0gSWYgdGhpcyBpcyByZWZlcmVuY2VkIGZyb20gdGhlIGNvbnRleHQgb2YgdGhlIG5lc3RlZCBzdGFjaywgaXQgd2lsbCByZXR1cm4gYHsgXCJSZWZcIjogXCJBV1M6OlN0YWNrTmFtZVwiIH1gXG4gICAqXG4gICAqIEV4YW1wbGUgdmFsdWU6IGBteXN0YWNrLW15bmVzdGVkc3RhY2stc2dnZnJoeGh1bTd3YFxuICAgKiBAYXR0cmlidXRlXG4gICAqL1xuICBwdWJsaWMgZ2V0IHN0YWNrTmFtZSgpIHtcbiAgICByZXR1cm4gdGhpcy5fY29udGV4dHVhbFN0YWNrTmFtZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBbiBhdHRyaWJ1dGUgdGhhdCByZXByZXNlbnRzIHRoZSBJRCBvZiB0aGUgc3RhY2suXG4gICAqXG4gICAqIFRoaXMgaXMgYSBjb250ZXh0IGF3YXJlIGF0dHJpYnV0ZTpcbiAgICogLSBJZiB0aGlzIGlzIHJlZmVyZW5jZWQgZnJvbSB0aGUgcGFyZW50IHN0YWNrLCBpdCB3aWxsIHJldHVybiBgeyBcIlJlZlwiOiBcIkxvZ2ljYWxJZE9mTmVzdGVkU3RhY2tSZXNvdXJjZVwiIH1gLlxuICAgKiAtIElmIHRoaXMgaXMgcmVmZXJlbmNlZCBmcm9tIHRoZSBjb250ZXh0IG9mIHRoZSBuZXN0ZWQgc3RhY2ssIGl0IHdpbGwgcmV0dXJuIGB7IFwiUmVmXCI6IFwiQVdTOjpTdGFja0lkXCIgfWBcbiAgICpcbiAgICogRXhhbXBsZSB2YWx1ZTogYGFybjphd3M6Y2xvdWRmb3JtYXRpb246dXMtZWFzdC0yOjEyMzQ1Njc4OTAxMjpzdGFjay9teXN0YWNrLW15bmVzdGVkc3RhY2stc2dnZnJoeGh1bTd3L2Y0NDliMjUwLWI5NjktMTFlMC1hMTg1LTUwODFkMDEzNjc4NmBcbiAgICogQGF0dHJpYnV0ZVxuICAgKi9cbiAgcHVibGljIGdldCBzdGFja0lkKCkge1xuICAgIHJldHVybiB0aGlzLl9jb250ZXh0dWFsU3RhY2tJZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBBc3NpZ24gYSB2YWx1ZSB0byBvbmUgb2YgdGhlIG5lc3RlZCBzdGFjayBwYXJhbWV0ZXJzLlxuICAgKiBAcGFyYW0gbmFtZSBUaGUgcGFyYW1ldGVyIG5hbWUgKElEKVxuICAgKiBAcGFyYW0gdmFsdWUgVGhlIHZhbHVlIHRvIGFzc2lnblxuICAgKi9cbiAgcHVibGljIHNldFBhcmFtZXRlcihuYW1lOiBzdHJpbmcsIHZhbHVlOiBzdHJpbmcpIHtcbiAgICB0aGlzLnBhcmFtZXRlcnNbbmFtZV0gPSB2YWx1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBEZWZpbmVzIGFuIGFzc2V0IGF0IHRoZSBwYXJlbnQgc3RhY2sgd2hpY2ggcmVwcmVzZW50cyB0aGUgdGVtcGxhdGUgb2YgdGhpc1xuICAgKiBuZXN0ZWQgc3RhY2suXG4gICAqXG4gICAqIFRoaXMgcHJpdmF0ZSBBUEkgaXMgdXNlZCBieSBgQXBwLnByZXBhcmUoKWAgd2l0aGluIGEgbG9vcCB0aGF0IHJlY3RpZmllc1xuICAgKiByZWZlcmVuY2VzIGV2ZXJ5IHRpbWUgYW4gYXNzZXQgaXMgYWRkZWQuIFRoaXMgaXMgYmVjYXVzZSAoYXQgdGhlIG1vbWVudClcbiAgICogYXNzZXRzIGFyZSBhZGRyZXNzZWQgdXNpbmcgQ2xvdWRGb3JtYXRpb24gcGFyYW1ldGVycy5cbiAgICpcbiAgICogQHJldHVybnMgYHRydWVgIGlmIGEgbmV3IGFzc2V0IHdhcyBhZGRlZCBvciBgZmFsc2VgIGlmIGFuIGFzc2V0IHdhc1xuICAgKiBwcmV2aW91c2x5IGFkZGVkLiBXaGVuIHRoaXMgcmV0dXJucyBgdHJ1ZWAsIEFwcCB3aWxsIGRvIGFub3RoZXIgcmVmZXJlbmNlXG4gICAqIHJlY3RpZmljYXRpb24gY3ljbGUuXG4gICAqXG4gICAqIEBpbnRlcm5hbFxuICAgKi9cbiAgcHVibGljIF9wcmVwYXJlVGVtcGxhdGVBc3NldCgpIHtcbiAgICBpZiAodGhpcy5fdGVtcGxhdGVVcmwpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBXaGVuIGFkZGluZyB0YWdzIHRvIG5lc3RlZCBzdGFjaywgdGhlIHRhZ3MgbmVlZCB0byBiZSBhZGRlZCB0byBhbGwgdGhlIHJlc291cmNlcyBpblxuICAgIC8vIGluIG5lc3RlZCBzdGFjaywgd2hpY2ggaXMgaGFuZGxlZCBieSB0aGUgYHRhZ3NgIHByb3BlcnR5LCBCdXQgdG8gdGFnIHRoZVxuICAgIC8vICB0YWdzIGhhdmUgdG8gYmUgYWRkZWQgaW4gdGhlIHBhcmVudCBzdGFjayBDZm5TdGFjayByZXNvdXJjZS4gVGhlIENmblN0YWNrIHJlc291cmNlIGNyZWF0ZWRcbiAgICAvLyBieSB0aGlzIGNsYXNzIGRvbnQgc2hhcmUgdGhlIHNhbWUgVGFnTWFuYWdlciBhcyB0aGF0IG9mIHRoZSBvbmUgZXhwb3NlZCBieSB0aGUgYHRhZ2AgcHJvcGVydHkgb2YgdGhlXG4gICAgLy8gIGNsYXNzLCBhbGwgdGhlIHRhZ3MgbmVlZCB0byBiZSBjb3BpZWQgdG8gdGhlIENmblN0YWNrIHJlc291cmNlIGJlZm9yZSBzeW50aGVzaXppbmcgdGhlIHJlc291cmNlLlxuICAgIC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vYXdzL2F3cy1jZGsvcHVsbC8xOTEyOFxuICAgIE9iamVjdC5lbnRyaWVzKHRoaXMudGFncy50YWdWYWx1ZXMoKSkuZm9yRWFjaCgoW2tleSwgdmFsdWVdKSA9PiB7XG4gICAgICB0aGlzLnJlc291cmNlLnRhZ3Muc2V0VGFnKGtleSwgdmFsdWUpO1xuICAgIH0pO1xuXG4gICAgY29uc3QgY2ZuID0gSlNPTi5zdHJpbmdpZnkodGhpcy5fdG9DbG91ZEZvcm1hdGlvbigpKTtcbiAgICBjb25zdCB0ZW1wbGF0ZUhhc2ggPSBjcnlwdG8uY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKGNmbikuZGlnZXN0KCdoZXgnKTtcblxuICAgIGNvbnN0IHRlbXBsYXRlTG9jYXRpb24gPSB0aGlzLl9wYXJlbnRTdGFjay5zeW50aGVzaXplci5hZGRGaWxlQXNzZXQoe1xuICAgICAgcGFja2FnaW5nOiBGaWxlQXNzZXRQYWNrYWdpbmcuRklMRSxcbiAgICAgIHNvdXJjZUhhc2g6IHRlbXBsYXRlSGFzaCxcbiAgICAgIGZpbGVOYW1lOiB0aGlzLnRlbXBsYXRlRmlsZSxcbiAgICB9KTtcblxuICAgIHRoaXMuYWRkUmVzb3VyY2VNZXRhZGF0YSh0aGlzLnJlc291cmNlLCAnVGVtcGxhdGVVUkwnKTtcblxuICAgIC8vIGlmIGJ1Y2tldE5hbWUvb2JqZWN0S2V5IGFyZSBjZm4gcGFyYW1ldGVycyBmcm9tIGEgc3RhY2sgb3RoZXIgdGhhbiB0aGUgcGFyZW50IHN0YWNrLCB0aGV5IHdpbGxcbiAgICAvLyBiZSByZXNvbHZlZCBhcyBjcm9zcy1zdGFjayByZWZlcmVuY2VzIGxpa2UgYW55IG90aGVyIChzZWUgXCJtdWx0aVwiIHRlc3RzKS5cbiAgICB0aGlzLl90ZW1wbGF0ZVVybCA9IGBodHRwczovL3MzLiR7dGhpcy5fcGFyZW50U3RhY2sucmVnaW9ufS4ke3RoaXMuX3BhcmVudFN0YWNrLnVybFN1ZmZpeH0vJHt0ZW1wbGF0ZUxvY2F0aW9uLmJ1Y2tldE5hbWV9LyR7dGVtcGxhdGVMb2NhdGlvbi5vYmplY3RLZXl9YDtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIHByaXZhdGUgY29udGV4dHVhbEF0dHJpYnV0ZShpbm5lclZhbHVlOiBzdHJpbmcsIG91dGVyVmFsdWU6IHN0cmluZykge1xuICAgIHJldHVybiBUb2tlbi5hc1N0cmluZyh7XG4gICAgICByZXNvbHZlOiAoY29udGV4dDogSVJlc29sdmVDb250ZXh0KSA9PiB7XG4gICAgICAgIGlmIChTdGFjay5vZihjb250ZXh0LnNjb3BlKSA9PT0gdGhpcykge1xuICAgICAgICAgIHJldHVybiBpbm5lclZhbHVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBvdXRlclZhbHVlO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSBhZGRSZXNvdXJjZU1ldGFkYXRhKHJlc291cmNlOiBDZm5SZXNvdXJjZSwgcmVzb3VyY2VQcm9wZXJ0eTogc3RyaW5nKSB7XG4gICAgaWYgKCF0aGlzLm5vZGUudHJ5R2V0Q29udGV4dChjeGFwaS5BU1NFVF9SRVNPVVJDRV9NRVRBREFUQV9FTkFCTEVEX0NPTlRFWFQpKSB7XG4gICAgICByZXR1cm47IC8vIG5vdCBlbmFibGVkXG4gICAgfVxuXG4gICAgLy8gdGVsbCB0b29scyBzdWNoIGFzIFNBTSBDTEkgdGhhdCB0aGUgXCJUZW1wbGF0ZVVSTFwiIHByb3BlcnR5IG9mIHRoaXMgcmVzb3VyY2VcbiAgICAvLyBwb2ludHMgdG8gdGhlIG5lc3RlZCBzdGFjayB0ZW1wbGF0ZSBmb3IgbG9jYWwgZW11bGF0aW9uXG4gICAgcmVzb3VyY2UuY2ZuT3B0aW9ucy5tZXRhZGF0YSA9IHJlc291cmNlLmNmbk9wdGlvbnMubWV0YWRhdGEgfHwgeyB9O1xuICAgIHJlc291cmNlLmNmbk9wdGlvbnMubWV0YWRhdGFbY3hhcGkuQVNTRVRfUkVTT1VSQ0VfTUVUQURBVEFfUEFUSF9LRVldID0gdGhpcy50ZW1wbGF0ZUZpbGU7XG4gICAgcmVzb3VyY2UuY2ZuT3B0aW9ucy5tZXRhZGF0YVtjeGFwaS5BU1NFVF9SRVNPVVJDRV9NRVRBREFUQV9QUk9QRVJUWV9LRVldID0gcmVzb3VyY2VQcm9wZXJ0eTtcbiAgfVxufVxuXG4vKipcbiAqIFZhbGlkYXRlcyB0aGUgc2NvcGUgZm9yIGEgbmVzdGVkIHN0YWNrLiBOZXN0ZWQgc3RhY2tzIG11c3QgYmUgZGVmaW5lZCB3aXRoaW4gdGhlIHNjb3BlIG9mIGFub3RoZXIgYFN0YWNrYC5cbiAqL1xuZnVuY3Rpb24gZmluZFBhcmVudFN0YWNrKHNjb3BlOiBDb25zdHJ1Y3QpOiBTdGFjayB7XG4gIGlmICghc2NvcGUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ05lc3RlZCBzdGFja3MgY2Fubm90IGJlIGRlZmluZWQgYXMgYSByb290IGNvbnN0cnVjdCcpO1xuICB9XG5cbiAgY29uc3QgcGFyZW50U3RhY2sgPSBOb2RlLm9mKHNjb3BlKS5zY29wZXMucmV2ZXJzZSgpLmZpbmQocCA9PiBTdGFjay5pc1N0YWNrKHApKTtcbiAgaWYgKCFwYXJlbnRTdGFjaykge1xuICAgIHRocm93IG5ldyBFcnJvcignTmVzdGVkIHN0YWNrcyBtdXN0IGJlIGRlZmluZWQgd2l0aGluIHNjb3BlIG9mIGFub3RoZXIgbm9uLW5lc3RlZCBzdGFjaycpO1xuICB9XG5cbiAgcmV0dXJuIHBhcmVudFN0YWNrIGFzIFN0YWNrO1xufVxuIl19
\No newline at end of file