UNPKG

20.2 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.stackTemplateFileAsset = exports.resolvedOr = exports.StringSpecializer = exports.assertBound = exports.contentHash = exports.addStackArtifactToAssembly = void 0;
4const crypto = require("crypto");
5const fs = require("fs");
6const path = require("path");
7const cxschema = require("@aws-cdk/cloud-assembly-schema");
8const cxapi = require("@aws-cdk/cx-api");
9const assets_1 = require("../assets");
10const construct_compat_1 = require("../construct-compat");
11const stack_1 = require("../stack");
12const token_1 = require("../token");
13/**
14 * Shared logic of writing stack artifact to the Cloud Assembly
15 *
16 * This logic is shared between StackSyntheses.
17 *
18 * It could have been a protected method on a base class, but it
19 * uses `Partial<cxapi.AwsCloudFormationStackProperties>` in the
20 * parameters (which is convenient so I can remain typesafe without
21 * copy/pasting), and jsii will choke on this type.
22 */
23function addStackArtifactToAssembly(session, stack, stackProps, additionalStackDependencies) {
24 // nested stack tags are applied at the AWS::CloudFormation::Stack resource
25 // level and are not needed in the cloud assembly.
26 if (stack.tags.hasTags()) {
27 stack.node.addMetadata(cxschema.ArtifactMetadataEntryType.STACK_TAGS, stack.tags.renderTags());
28 }
29 const deps = [
30 ...stack.dependencies.map(s => s.artifactId),
31 ...additionalStackDependencies,
32 ];
33 const meta = collectStackMetadata(stack);
34 // backwards compatibility since originally artifact ID was always equal to
35 // stack name the stackName attribute is optional and if it is not specified
36 // the CLI will use the artifact ID as the stack name. we *could have*
37 // always put the stack name here but wanted to minimize the risk around
38 // changes to the assembly manifest. so this means that as long as stack
39 // name and artifact ID are the same, the cloud assembly manifest will not
40 // change.
41 const stackNameProperty = stack.stackName === stack.artifactId
42 ? {}
43 : { stackName: stack.stackName };
44 const properties = {
45 templateFile: stack.templateFile,
46 terminationProtection: stack.terminationProtection,
47 tags: nonEmptyDict(stack.tags.tagValues()),
48 validateOnSynth: session.validateOnSynth,
49 ...stackProps,
50 ...stackNameProperty,
51 };
52 // add an artifact that represents this stack
53 session.assembly.addArtifact(stack.artifactId, {
54 type: cxschema.ArtifactType.AWS_CLOUDFORMATION_STACK,
55 environment: stack.environment,
56 properties,
57 dependencies: deps.length > 0 ? deps : undefined,
58 metadata: Object.keys(meta).length > 0 ? meta : undefined,
59 displayName: stack.node.path,
60 });
61}
62exports.addStackArtifactToAssembly = addStackArtifactToAssembly;
63/**
64 * Collect the metadata from a stack
65 */
66function collectStackMetadata(stack) {
67 const output = {};
68 visit(stack);
69 return output;
70 function visit(node) {
71 // break off if we reached a node that is not a child of this stack
72 const parent = findParentStack(node);
73 if (parent !== stack) {
74 return;
75 }
76 if (node.node.metadataEntry.length > 0) {
77 // Make the path absolute
78 output[construct_compat_1.ConstructNode.PATH_SEP + node.node.path] = node.node.metadataEntry.map(md => stack.resolve(md));
79 }
80 for (const child of node.node.children) {
81 visit(child);
82 }
83 }
84 function findParentStack(node) {
85 if (stack_1.Stack.isStack(node) && node.nestedStackParent === undefined) {
86 return node;
87 }
88 if (!node.node.scope) {
89 return undefined;
90 }
91 return findParentStack(node.node.scope);
92 }
93}
94/**
95 * Hash a string
96 */
97function contentHash(content) {
98 return crypto.createHash('sha256').update(content).digest('hex');
99}
100exports.contentHash = contentHash;
101/**
102 * Throw an error message about binding() if we don't have a value for x.
103 *
104 * This replaces the ! assertions we would need everywhere otherwise.
105 */
106function assertBound(x) {
107 if (x === null && x === undefined) {
108 throw new Error('You must call bindStack() first');
109 }
110}
111exports.assertBound = assertBound;
112function nonEmptyDict(xs) {
113 return Object.keys(xs).length > 0 ? xs : undefined;
114}
115/**
116 * A "replace-all" function that doesn't require us escaping a literal string to a regex
117 */
118function replaceAll(s, search, replace) {
119 return s.split(search).join(replace);
120}
121class StringSpecializer {
122 constructor(stack, qualifier) {
123 this.stack = stack;
124 this.qualifier = qualifier;
125 }
126 /**
127 * Function to replace placeholders in the input string as much as possible
128 *
129 * We replace:
130 * - ${Qualifier}: always
131 * - ${AWS::AccountId}, ${AWS::Region}: only if we have the actual values available
132 * - ${AWS::Partition}: never, since we never have the actual partition value.
133 */
134 specialize(s) {
135 s = replaceAll(s, '${Qualifier}', this.qualifier);
136 return cxapi.EnvironmentPlaceholders.replace(s, {
137 region: resolvedOr(this.stack.region, cxapi.EnvironmentPlaceholders.CURRENT_REGION),
138 accountId: resolvedOr(this.stack.account, cxapi.EnvironmentPlaceholders.CURRENT_ACCOUNT),
139 partition: cxapi.EnvironmentPlaceholders.CURRENT_PARTITION,
140 });
141 }
142 /**
143 * Specialize only the qualifier
144 */
145 qualifierOnly(s) {
146 return replaceAll(s, '${Qualifier}', this.qualifier);
147 }
148}
149exports.StringSpecializer = StringSpecializer;
150/**
151 * Return the given value if resolved or fall back to a default
152 */
153function resolvedOr(x, def) {
154 return token_1.Token.isUnresolved(x) ? def : x;
155}
156exports.resolvedOr = resolvedOr;
157function stackTemplateFileAsset(stack, session) {
158 const templatePath = path.join(session.assembly.outdir, stack.templateFile);
159 const template = fs.readFileSync(templatePath, { encoding: 'utf-8' });
160 const sourceHash = contentHash(template);
161 return {
162 fileName: stack.templateFile,
163 packaging: assets_1.FileAssetPackaging.FILE,
164 sourceHash,
165 };
166}
167exports.stackTemplateFileAsset = stackTemplateFileAsset;
168//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX3NoYXJlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIl9zaGFyZWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaUNBQWlDO0FBQ2pDLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IsMkRBQTJEO0FBQzNELHlDQUF5QztBQUN6QyxzQ0FBZ0U7QUFDaEUsMERBQW1GO0FBQ25GLG9DQUFpQztBQUNqQyxvQ0FBaUM7QUFFakM7Ozs7Ozs7OztHQVNHO0FBQ0gsU0FBZ0IsMEJBQTBCLENBQ3hDLE9BQTBCLEVBQzFCLEtBQVksRUFDWixVQUE4RCxFQUM5RCwyQkFBcUM7SUFFckMsMkVBQTJFO0lBQzNFLGtEQUFrRDtJQUNsRCxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEVBQUU7UUFDeEIsS0FBSyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLHlCQUF5QixDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7S0FDaEc7SUFFRCxNQUFNLElBQUksR0FBRztRQUNYLEdBQUcsS0FBSyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDO1FBQzVDLEdBQUcsMkJBQTJCO0tBQy9CLENBQUM7SUFDRixNQUFNLElBQUksR0FBRyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUV6QywyRUFBMkU7SUFDM0UsNEVBQTRFO0lBQzVFLHNFQUFzRTtJQUN0RSx3RUFBd0U7SUFDeEUsd0VBQXdFO0lBQ3hFLDBFQUEwRTtJQUMxRSxVQUFVO0lBQ1YsTUFBTSxpQkFBaUIsR0FBRyxLQUFLLENBQUMsU0FBUyxLQUFLLEtBQUssQ0FBQyxVQUFVO1FBQzVELENBQUMsQ0FBQyxFQUFHO1FBQ0wsQ0FBQyxDQUFDLEVBQUUsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUVuQyxNQUFNLFVBQVUs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LENBQUMsQ0FBQztLQUN0RDtDQUNGO0FBM0JELDhDQTJCQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsVUFBVSxDQUFJLENBQVMsRUFBRSxHQUFNO0lBQzdDLE9BQU8sYUFBSyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDekMsQ0FBQztBQUZELGdDQUVDO0FBRUQsU0FBZ0Isc0JBQXNCLENBQUMsS0FBWSxFQUFFLE9BQTBCO0lBQzdFLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQzVFLE1BQU0sUUFBUSxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsWUFBWSxFQUFFLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFFdEUsTUFBTSxVQUFVLEdBQUcsV0FBVyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBRXpDLE9BQU87UUFDTCxRQUFRLEVBQUUsS0FBSyxDQUFDLFlBQVk7UUFDNUIsU0FBUyxFQUFFLDJCQUFrQixDQUFDLElBQUk7UUFDbEMsVUFBVTtLQUNYLENBQUM7QUFDSixDQUFDO0FBWEQsd0RBV0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjcnlwdG8gZnJvbSAnY3J5cHRvJztcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBjeHNjaGVtYSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1zY2hlbWEnO1xuaW1wb3J0ICogYXMgY3hhcGkgZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcbmltcG9ydCB7IEZpbGVBc3NldFNvdXJjZSwgRmlsZUFzc2V0UGFja2FnaW5nIH0gZnJvbSAnLi4vYXNzZXRzJztcbmltcG9ydCB7IENvbnN0cnVjdE5vZGUsIElDb25zdHJ1Y3QsIElTeW50aGVzaXNTZXNzaW9uIH0gZnJvbSAnLi4vY29uc3RydWN0LWNvbXBhdCc7XG5pbXBvcnQgeyBTdGFjayB9IGZyb20gJy4uL3N0YWNrJztcbmltcG9ydCB7IFRva2VuIH0gZnJvbSAnLi4vdG9rZW4nO1xuXG4vKipcbiAqIFNoYXJlZCBsb2dpYyBvZiB3cml0aW5nIHN0YWNrIGFydGlmYWN0IHRvIHRoZSBDbG91ZCBBc3NlbWJseVxuICpcbiAqIFRoaXMgbG9naWMgaXMgc2hhcmVkIGJldHdlZW4gU3RhY2tTeW50aGVzZXMuXG4gKlxuICogSXQgY291bGQgaGF2ZSBiZWVuIGEgcHJvdGVjdGVkIG1ldGhvZCBvbiBhIGJhc2UgY2xhc3MsIGJ1dCBpdFxuICogdXNlcyBgUGFydGlhbDxjeGFwaS5Bd3NDbG91ZEZvcm1hdGlvblN0YWNrUHJvcGVydGllcz5gIGluIHRoZVxuICogcGFyYW1ldGVycyAod2hpY2ggaXMgY29udmVuaWVudCBzbyBJIGNhbiByZW1haW4gdHlwZXNhZmUgd2l0aG91dFxuICogY29weS9wYXN0aW5nKSwgYW5kIGpzaWkgd2lsbCBjaG9rZSBvbiB0aGlzIHR5cGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZGRTdGFja0FydGlmYWN0VG9Bc3NlbWJseShcbiAgc2Vzc2lvbjogSVN5bnRoZXNpc1Nlc3Npb24sXG4gIHN0YWNrOiBTdGFjayxcbiAgc3RhY2tQcm9wczogUGFydGlhbDxjeHNjaGVtYS5Bd3NDbG91ZEZvcm1hdGlvblN0YWNrUHJvcGVydGllcz4sXG4gIGFkZGl0aW9uYWxTdGFja0RlcGVuZGVuY2llczogc3RyaW5nW10pIHtcblxuICAvLyBuZXN0ZWQgc3RhY2sgdGFncyBhcmUgYXBwbGllZCBhdCB0aGUgQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2sgcmVzb3VyY2VcbiAgLy8gbGV2ZWwgYW5kIGFyZSBub3QgbmVlZGVkIGluIHRoZSBjbG91ZCBhc3NlbWJseS5cbiAgaWYgKHN0YWNrLnRhZ3MuaGFzVGFncygpKSB7XG4gICAgc3RhY2subm9kZS5hZGRNZXRhZGF0YShjeHNjaGVtYS5BcnRpZmFjdE1ldGFkYXRhRW50cnlUeXBlLlNUQUNLX1RBR1MsIHN0YWNrLnRhZ3MucmVuZGVyVGFncygpKTtcbiAgfVxuXG4gIGNvbnN0IGRlcHMgPSBbXG4gICAgLi4uc3RhY2suZGVwZW5kZW5jaWVzLm1hcChzID0+IHMuYXJ0aWZhY3RJZCksXG4gICAgLi4uYWRkaXRpb25hbFN0YWNrRGVwZW5kZW5jaWVzLFxuICBdO1xuICBjb25zdCBtZXRhID0gY29sbGVjdFN0YWNrTWV0YWRhdGEoc3RhY2spO1xuXG4gIC8vIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IHNpbmNlIG9yaWdpbmFsbHkgYXJ0aWZhY3QgSUQgd2FzIGFsd2F5cyBlcXVhbCB0b1xuICAvLyBzdGFjayBuYW1lIHRoZSBzdGFja05hbWUgYXR0cmlidXRlIGlzIG9wdGlvbmFsIGFuZCBpZiBpdCBpcyBub3Qgc3BlY2lmaWVkXG4gIC8vIHRoZSBDTEkgd2lsbCB1c2UgdGhlIGFydGlmYWN0IElEIGFzIHRoZSBzdGFjayBuYW1lLiB3ZSAqY291bGQgaGF2ZSpcbiAgLy8gYWx3YXlzIHB1dCB0aGUgc3RhY2sgbmFtZSBoZXJlIGJ1dCB3YW50ZWQgdG8gbWluaW1pemUgdGhlIHJpc2sgYXJvdW5kXG4gIC8vIGNoYW5nZXMgdG8gdGhlIGFzc2VtYmx5IG1hbmlmZXN0LiBzbyB0aGlzIG1lYW5zIHRoYXQgYXMgbG9uZyBhcyBzdGFja1xuICAvLyBuYW1lIGFuZCBhcnRpZmFjdCBJRCBhcmUgdGhlIHNhbWUsIHRoZSBjbG91ZCBhc3NlbWJseSBtYW5pZmVzdCB3aWxsIG5vdFxuICAvLyBjaGFuZ2UuXG4gIGNvbnN0IHN0YWNrTmFtZVByb3BlcnR5ID0gc3RhY2suc3RhY2tOYW1lID09PSBzdGFjay5hcnRpZmFjdElkXG4gICAgPyB7IH1cbiAgICA6IHsgc3RhY2tOYW1lOiBzdGFjay5zdGFja05hbWUgfTtcblxuICBjb25zdCBwcm9wZXJ0aWVzOiBjeHNjaGVtYS5Bd3NDbG91ZEZvcm1hdGlvblN0YWNrUHJvcGVydGllcyA9IHtcbiAgICB0ZW1wbGF0ZUZpbGU6IHN0YWNrLnRlbXBsYXRlRmlsZSxcbiAgICB0ZXJtaW5hdGlvblByb3RlY3Rpb246IHN0YWNrLnRlcm1pbmF0aW9uUHJvdGVjdGlvbixcbiAgICB0YWdzOiBub25FbXB0eURpY3Qoc3RhY2sudGFncy50YWdWYWx1ZXMoKSksXG4gICAgdmFsaWRhdGVPblN5bnRoOiBzZXNzaW9uLnZhbGlkYXRlT25TeW50aCxcbiAgICAuLi5zdGFja1Byb3BzLFxuICAgIC4uLnN0YWNrTmFtZVByb3BlcnR5LFxuICB9O1xuXG4gIC8vIGFkZCBhbiBhcnRpZmFjdCB0aGF0IHJlcHJlc2VudHMgdGhpcyBzdGFja1xuICBzZXNzaW9uLmFzc2VtYmx5LmFkZEFydGlmYWN0KHN0YWNrLmFydGlmYWN0SWQsIHtcbiAgICB0eXBlOiBjeHNjaGVtYS5BcnRpZmFjdFR5cGUuQVdTX0NMT1VERk9STUFUSU9OX1NUQUNLLFxuICAgIGVudmlyb25tZW50OiBzdGFjay5lbnZpcm9ubWVudCxcbiAgICBwcm9wZXJ0aWVzLFxuICAgIGRlcGVuZGVuY2llczogZGVwcy5sZW5ndGggPiAwID8gZGVwcyA6IHVuZGVmaW5lZCxcbiAgICBtZXRhZGF0YTogT2JqZWN0LmtleXMobWV0YSkubGVuZ3RoID4gMCA/IG1ldGEgOiB1bmRlZmluZWQsXG4gICAgZGlzcGxheU5hbWU6IHN0YWNrLm5vZGUucGF0aCxcbiAgfSk7XG59XG5cbi8qKlxuICogQ29sbGVjdCB0aGUgbWV0YWRhdGEgZnJvbSBhIHN0YWNrXG4gKi9cbmZ1bmN0aW9uIGNvbGxlY3RTdGFja01ldGFkYXRhKHN0YWNrOiBTdGFjaykge1xuICBjb25zdCBvdXRwdXQ6IHsgW2lkOiBzdHJpbmddOiBjeHNjaGVtYS5NZXRhZGF0YUVudHJ5W10gfSA9IHsgfTtcblxuICB2aXNpdChzdGFjayk7XG5cbiAgcmV0dXJuIG91dHB1dDtcblxuICBmdW5jdGlvbiB2aXNpdChub2RlOiBJQ29uc3RydWN0KSB7XG4gICAgLy8gYnJlYWsgb2ZmIGlmIHdlIHJlYWNoZWQgYSBub2RlIHRoYXQgaXMgbm90IGEgY2hpbGQgb2YgdGhpcyBzdGFja1xuICAgIGNvbnN0IHBhcmVudCA9IGZpbmRQYXJlbnRTdGFjayhub2RlKTtcbiAgICBpZiAocGFyZW50ICE9PSBzdGFjaykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChub2RlLm5vZGUubWV0YWRhdGFFbnRyeS5sZW5ndGggPiAwKSB7XG4gICAgICAvLyBNYWtlIHRoZSBwYXRoIGFic29sdXRlXG4gICAgICBvdXRwdXRbQ29uc3RydWN0Tm9kZS5QQVRIX1NFUCArIG5vZGUubm9kZS5wYXRoXSA9IG5vZGUubm9kZS5tZXRhZGF0YUVudHJ5Lm1hcChtZCA9PiBzdGFjay5yZXNvbHZlKG1kKSBhcyBjeHNjaGVtYS5NZXRhZGF0YUVudHJ5KTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIG5vZGUubm9kZS5jaGlsZHJlbikge1xuICAgICAgdmlzaXQoY2hpbGQpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGZpbmRQYXJlbnRTdGFjayhub2RlOiBJQ29uc3RydWN0KTogU3RhY2sgfCB1bmRlZmluZWQge1xuICAgIGlmIChTdGFjay5pc1N0YWNrKG5vZGUpICYmIG5vZGUubmVzdGVkU3RhY2tQYXJlbnQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIG5vZGU7XG4gICAgfVxuXG4gICAgaWYgKCFub2RlLm5vZGUuc2NvcGUpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZpbmRQYXJlbnRTdGFjayhub2RlLm5vZGUuc2NvcGUpO1xuICB9XG59XG5cbi8qKlxuICogSGFzaCBhIHN0cmluZ1xuICovXG5leHBvcnQgZnVuY3Rpb24gY29udGVudEhhc2goY29udGVudDogc3RyaW5nKSB7XG4gIHJldHVybiBjcnlwdG8uY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKGNvbnRlbnQpLmRpZ2VzdCgnaGV4Jyk7XG59XG5cbi8qKlxuICogVGhyb3cgYW4gZXJyb3IgbWVzc2FnZSBhYm91dCBiaW5kaW5nKCkgaWYgd2UgZG9uJ3QgaGF2ZSBhIHZhbHVlIGZvciB4LlxuICpcbiAqIFRoaXMgcmVwbGFjZXMgdGhlICEgYXNzZXJ0aW9ucyB3ZSB3b3VsZCBuZWVkIGV2ZXJ5d2hlcmUgb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0Qm91bmQ8QT4oeDogQSB8IHVuZGVmaW5lZCk6IGFzc2VydHMgeCBpcyBOb25OdWxsYWJsZTxBPiB7XG4gIGlmICh4ID09PSBudWxsICYmIHggPT09IHVuZGVmaW5lZCkge1xuICAgIHRocm93IG5ldyBFcnJvcignWW91IG11c3QgY2FsbCBiaW5kU3RhY2soKSBmaXJzdCcpO1xuICB9XG59XG5cbmZ1bmN0aW9uIG5vbkVtcHR5RGljdDxBPih4czogUmVjb3JkPHN0cmluZywgQT4pIHtcbiAgcmV0dXJuIE9iamVjdC5rZXlzKHhzKS5sZW5ndGggPiAwID8geHMgOiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogQSBcInJlcGxhY2UtYWxsXCIgZnVuY3Rpb24gdGhhdCBkb2Vzbid0IHJlcXVpcmUgdXMgZXNjYXBpbmcgYSBsaXRlcmFsIHN0cmluZyB0byBhIHJlZ2V4XG4gKi9cbmZ1bmN0aW9uIHJlcGxhY2VBbGwoczogc3RyaW5nLCBzZWFyY2g6IHN0cmluZywgcmVwbGFjZTogc3RyaW5nKSB7XG4gIHJldHVybiBzLnNwbGl0KHNlYXJjaCkuam9pbihyZXBsYWNlKTtcbn1cblxuZXhwb3J0IGNsYXNzIFN0cmluZ1NwZWNpYWxpemVyIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBzdGFjazogU3RhY2ssIHByaXZhdGUgcmVhZG9ubHkgcXVhbGlmaWVyOiBzdHJpbmcpIHtcbiAgfVxuXG4gIC8qKlxuICAgKiBGdW5jdGlvbiB0byByZXBsYWNlIHBsYWNlaG9sZGVycyBpbiB0aGUgaW5wdXQgc3RyaW5nIGFzIG11Y2ggYXMgcG9zc2libGVcbiAgICpcbiAgICogV2UgcmVwbGFjZTpcbiAgICogLSAke1F1YWxpZmllcn06IGFsd2F5c1xuICAgKiAtICR7QVdTOjpBY2NvdW50SWR9LCAke0FXUzo6UmVnaW9ufTogb25seSBpZiB3ZSBoYXZlIHRoZSBhY3R1YWwgdmFsdWVzIGF2YWlsYWJsZVxuICAgKiAtICR7QVdTOjpQYXJ0aXRpb259OiBuZXZlciwgc2luY2Ugd2UgbmV2ZXIgaGF2ZSB0aGUgYWN0dWFsIHBhcnRpdGlvbiB2YWx1ZS5cbiAgICovXG4gIHB1YmxpYyBzcGVjaWFsaXplKHM6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcyA9IHJlcGxhY2VBbGwocywgJyR7UXVhbGlmaWVyfScsIHRoaXMucXVhbGlmaWVyKTtcbiAgICByZXR1cm4gY3hhcGkuRW52aXJvbm1lbnRQbGFjZWhvbGRlcnMucmVwbGFjZShzLCB7XG4gICAgICByZWdpb246IHJlc29sdmVkT3IodGhpcy5zdGFjay5yZWdpb24sIGN4YXBpLkVudmlyb25tZW50UGxhY2Vob2xkZXJzLkNVUlJFTlRfUkVHSU9OKSxcbiAgICAgIGFjY291bnRJZDogcmVzb2x2ZWRPcih0aGlzLnN0YWNrLmFjY291bnQsIGN4YXBpLkVudmlyb25tZW50UGxhY2Vob2xkZXJzLkNVUlJFTlRfQUNDT1VOVCksXG4gICAgICBwYXJ0aXRpb246IGN4YXBpLkVudmlyb25tZW50UGxhY2Vob2xkZXJzLkNVUlJFTlRfUEFSVElUSU9OLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNwZWNpYWxpemUgb25seSB0aGUgcXVhbGlmaWVyXG4gICAqL1xuICBwdWJsaWMgcXVhbGlmaWVyT25seShzOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiByZXBsYWNlQWxsKHMsICcke1F1YWxpZmllcn0nLCB0aGlzLnF1YWxpZmllcik7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm4gdGhlIGdpdmVuIHZhbHVlIGlmIHJlc29sdmVkIG9yIGZhbGwgYmFjayB0byBhIGRlZmF1bHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVkT3I8QT4oeDogc3RyaW5nLCBkZWY6IEEpOiBzdHJpbmcgfCBBIHtcbiAgcmV0dXJuIFRva2VuLmlzVW5yZXNvbHZlZCh4KSA/IGRlZiA6IHg7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzdGFja1RlbXBsYXRlRmlsZUFzc2V0KHN0YWNrOiBTdGFjaywgc2Vzc2lvbjogSVN5bnRoZXNpc1Nlc3Npb24pOiBGaWxlQXNzZXRTb3VyY2Uge1xuICBjb25zdCB0ZW1wbGF0ZVBhdGggPSBwYXRoLmpvaW4oc2Vzc2lvbi5hc3NlbWJseS5vdXRkaXIsIHN0YWNrLnRlbXBsYXRlRmlsZSk7XG4gIGNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKHRlbXBsYXRlUGF0aCwgeyBlbmNvZGluZzogJ3V0Zi04JyB9KTtcblxuICBjb25zdCBzb3VyY2VIYXNoID0gY29udGVudEhhc2godGVtcGxhdGUpO1xuXG4gIHJldHVybiB7XG4gICAgZmlsZU5hbWU6IHN0YWNrLnRlbXBsYXRlRmlsZSxcbiAgICBwYWNrYWdpbmc6IEZpbGVBc3NldFBhY2thZ2luZy5GSUxFLFxuICAgIHNvdXJjZUhhc2gsXG4gIH07XG59XG4iXX0=
\No newline at end of file