1 | ;
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | exports.stackTemplateFileAsset = exports.resolvedOr = exports.StringSpecializer = exports.assertBound = exports.contentHash = exports.addStackArtifactToAssembly = void 0;
|
4 | const crypto = require("crypto");
|
5 | const fs = require("fs");
|
6 | const path = require("path");
|
7 | const cxschema = require("@aws-cdk/cloud-assembly-schema");
|
8 | const cxapi = require("@aws-cdk/cx-api");
|
9 | const assets_1 = require("../assets");
|
10 | const construct_compat_1 = require("../construct-compat");
|
11 | const stack_1 = require("../stack");
|
12 | const 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 | */
|
23 | function 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 | }
|
62 | exports.addStackArtifactToAssembly = addStackArtifactToAssembly;
|
63 | /**
|
64 | * Collect the metadata from a stack
|
65 | */
|
66 | function 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 | */
|
97 | function contentHash(content) {
|
98 | return crypto.createHash('sha256').update(content).digest('hex');
|
99 | }
|
100 | exports.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 | */
|
106 | function assertBound(x) {
|
107 | if (x === null && x === undefined) {
|
108 | throw new Error('You must call bindStack() first');
|
109 | }
|
110 | }
|
111 | exports.assertBound = assertBound;
|
112 | function 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 | */
|
118 | function replaceAll(s, search, replace) {
|
119 | return s.split(search).join(replace);
|
120 | }
|
121 | class 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 | }
|
149 | exports.StringSpecializer = StringSpecializer;
|
150 | /**
|
151 | * Return the given value if resolved or fall back to a default
|
152 | */
|
153 | function resolvedOr(x, def) {
|
154 | return token_1.Token.isUnresolved(x) ? def : x;
|
155 | }
|
156 | exports.resolvedOr = resolvedOr;
|
157 | function 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 | }
|
167 | exports.stackTemplateFileAsset = stackTemplateFileAsset;
|
168 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiX3NoYXJlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIl9zaGFyZWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaUNBQWlDO0FBQ2pDLHlCQUF5QjtBQUN6Qiw2QkFBNkI7QUFDN0IsMkRBQTJEO0FBQzNELHlDQUF5QztBQUN6QyxzQ0FBZ0U7QUFDaEUsMERBQW1GO0FBQ25GLG9DQUFpQztBQUNqQyxvQ0FBaUM7QUFFakM7Ozs7Ozs7OztHQVNHO0FBQ0gsU0FBZ0IsMEJBQTBCLENBQ3hDLE9BQTBCLEVBQzFCLEtBQVksRUFDWixVQUE4RCxFQUM5RCwyQkFBcUM7SUFFckMsMkVBQTJFO0lBQzNFLGtEQUFrRDtJQUNsRCxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxFQUFFLEVBQUU7UUFDeEIsS0FBSyxDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLHlCQUF5QixDQUFDLFVBQVUsRUFBRSxLQUFLLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDLENBQUM7S0FDaEc7SUFFRCxNQUFNLElBQUksR0FBRztRQUNYLEdBQUcsS0FBSyxDQUFDLFlBQVksQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDO1FBQzVDLEdBQUcsMkJBQTJCO0tBQy9CLENBQUM7SUFDRixNQUFNLElBQUksR0FBRyxvQkFBb0IsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUV6QywyRUFBMkU7SUFDM0UsNEVBQTRFO0lBQzVFLHNFQUFzRTtJQUN0RSx3RUFBd0U7SUFDeEUsd0VBQXdFO0lBQ3hFLDBFQUEwRTtJQUMxRSxVQUFVO0lBQ1YsTUFBTSxpQkFBaUIsR0FBRyxLQUFLLENBQUMsU0FBUyxLQUFLLEtBQUssQ0FBQyxVQUFVO1FBQzVELENBQUMsQ0FBQyxFQUFHO1FBQ0wsQ0FBQyxDQUFDLEVBQUUsU0FBUyxFQUFFLEtBQUssQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUVuQyxNQUFNLFVBQVUs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LENBQUMsQ0FBQztLQUN0RDtDQUNGO0FBM0JELDhDQTJCQztBQUVEOztHQUVHO0FBQ0gsU0FBZ0IsVUFBVSxDQUFJLENBQVMsRUFBRSxHQUFNO0lBQzdDLE9BQU8sYUFBSyxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDekMsQ0FBQztBQUZELGdDQUVDO0FBRUQsU0FBZ0Isc0JBQXNCLENBQUMsS0FBWSxFQUFFLE9BQTBCO0lBQzdFLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDO0lBQzVFLE1BQU0sUUFBUSxHQUFHLEVBQUUsQ0FBQyxZQUFZLENBQUMsWUFBWSxFQUFFLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7SUFFdEUsTUFBTSxVQUFVLEdBQUcsV0FBVyxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBRXpDLE9BQU87UUFDTCxRQUFRLEVBQUUsS0FBSyxDQUFDLFlBQVk7UUFDNUIsU0FBUyxFQUFFLDJCQUFrQixDQUFDLElBQUk7UUFDbEMsVUFBVTtLQUNYLENBQUM7QUFDSixDQUFDO0FBWEQsd0RBV0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBjcnlwdG8gZnJvbSAnY3J5cHRvJztcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBjeHNjaGVtYSBmcm9tICdAYXdzLWNkay9jbG91ZC1hc3NlbWJseS1zY2hlbWEnO1xuaW1wb3J0ICogYXMgY3hhcGkgZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcbmltcG9ydCB7IEZpbGVBc3NldFNvdXJjZSwgRmlsZUFzc2V0UGFja2FnaW5nIH0gZnJvbSAnLi4vYXNzZXRzJztcbmltcG9ydCB7IENvbnN0cnVjdE5vZGUsIElDb25zdHJ1Y3QsIElTeW50aGVzaXNTZXNzaW9uIH0gZnJvbSAnLi4vY29uc3RydWN0LWNvbXBhdCc7XG5pbXBvcnQgeyBTdGFjayB9IGZyb20gJy4uL3N0YWNrJztcbmltcG9ydCB7IFRva2VuIH0gZnJvbSAnLi4vdG9rZW4nO1xuXG4vKipcbiAqIFNoYXJlZCBsb2dpYyBvZiB3cml0aW5nIHN0YWNrIGFydGlmYWN0IHRvIHRoZSBDbG91ZCBBc3NlbWJseVxuICpcbiAqIFRoaXMgbG9naWMgaXMgc2hhcmVkIGJldHdlZW4gU3RhY2tTeW50aGVzZXMuXG4gKlxuICogSXQgY291bGQgaGF2ZSBiZWVuIGEgcHJvdGVjdGVkIG1ldGhvZCBvbiBhIGJhc2UgY2xhc3MsIGJ1dCBpdFxuICogdXNlcyBgUGFydGlhbDxjeGFwaS5Bd3NDbG91ZEZvcm1hdGlvblN0YWNrUHJvcGVydGllcz5gIGluIHRoZVxuICogcGFyYW1ldGVycyAod2hpY2ggaXMgY29udmVuaWVudCBzbyBJIGNhbiByZW1haW4gdHlwZXNhZmUgd2l0aG91dFxuICogY29weS9wYXN0aW5nKSwgYW5kIGpzaWkgd2lsbCBjaG9rZSBvbiB0aGlzIHR5cGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZGRTdGFja0FydGlmYWN0VG9Bc3NlbWJseShcbiAgc2Vzc2lvbjogSVN5bnRoZXNpc1Nlc3Npb24sXG4gIHN0YWNrOiBTdGFjayxcbiAgc3RhY2tQcm9wczogUGFydGlhbDxjeHNjaGVtYS5Bd3NDbG91ZEZvcm1hdGlvblN0YWNrUHJvcGVydGllcz4sXG4gIGFkZGl0aW9uYWxTdGFja0RlcGVuZGVuY2llczogc3RyaW5nW10pIHtcblxuICAvLyBuZXN0ZWQgc3RhY2sgdGFncyBhcmUgYXBwbGllZCBhdCB0aGUgQVdTOjpDbG91ZEZvcm1hdGlvbjo6U3RhY2sgcmVzb3VyY2VcbiAgLy8gbGV2ZWwgYW5kIGFyZSBub3QgbmVlZGVkIGluIHRoZSBjbG91ZCBhc3NlbWJseS5cbiAgaWYgKHN0YWNrLnRhZ3MuaGFzVGFncygpKSB7XG4gICAgc3RhY2subm9kZS5hZGRNZXRhZGF0YShjeHNjaGVtYS5BcnRpZmFjdE1ldGFkYXRhRW50cnlUeXBlLlNUQUNLX1RBR1MsIHN0YWNrLnRhZ3MucmVuZGVyVGFncygpKTtcbiAgfVxuXG4gIGNvbnN0IGRlcHMgPSBbXG4gICAgLi4uc3RhY2suZGVwZW5kZW5jaWVzLm1hcChzID0+IHMuYXJ0aWZhY3RJZCksXG4gICAgLi4uYWRkaXRpb25hbFN0YWNrRGVwZW5kZW5jaWVzLFxuICBdO1xuICBjb25zdCBtZXRhID0gY29sbGVjdFN0YWNrTWV0YWRhdGEoc3RhY2spO1xuXG4gIC8vIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IHNpbmNlIG9yaWdpbmFsbHkgYXJ0aWZhY3QgSUQgd2FzIGFsd2F5cyBlcXVhbCB0b1xuICAvLyBzdGFjayBuYW1lIHRoZSBzdGFja05hbWUgYXR0cmlidXRlIGlzIG9wdGlvbmFsIGFuZCBpZiBpdCBpcyBub3Qgc3BlY2lmaWVkXG4gIC8vIHRoZSBDTEkgd2lsbCB1c2UgdGhlIGFydGlmYWN0IElEIGFzIHRoZSBzdGFjayBuYW1lLiB3ZSAqY291bGQgaGF2ZSpcbiAgLy8gYWx3YXlzIHB1dCB0aGUgc3RhY2sgbmFtZSBoZXJlIGJ1dCB3YW50ZWQgdG8gbWluaW1pemUgdGhlIHJpc2sgYXJvdW5kXG4gIC8vIGNoYW5nZXMgdG8gdGhlIGFzc2VtYmx5IG1hbmlmZXN0LiBzbyB0aGlzIG1lYW5zIHRoYXQgYXMgbG9uZyBhcyBzdGFja1xuICAvLyBuYW1lIGFuZCBhcnRpZmFjdCBJRCBhcmUgdGhlIHNhbWUsIHRoZSBjbG91ZCBhc3NlbWJseSBtYW5pZmVzdCB3aWxsIG5vdFxuICAvLyBjaGFuZ2UuXG4gIGNvbnN0IHN0YWNrTmFtZVByb3BlcnR5ID0gc3RhY2suc3RhY2tOYW1lID09PSBzdGFjay5hcnRpZmFjdElkXG4gICAgPyB7IH1cbiAgICA6IHsgc3RhY2tOYW1lOiBzdGFjay5zdGFja05hbWUgfTtcblxuICBjb25zdCBwcm9wZXJ0aWVzOiBjeHNjaGVtYS5Bd3NDbG91ZEZvcm1hdGlvblN0YWNrUHJvcGVydGllcyA9IHtcbiAgICB0ZW1wbGF0ZUZpbGU6IHN0YWNrLnRlbXBsYXRlRmlsZSxcbiAgICB0ZXJtaW5hdGlvblByb3RlY3Rpb246IHN0YWNrLnRlcm1pbmF0aW9uUHJvdGVjdGlvbixcbiAgICB0YWdzOiBub25FbXB0eURpY3Qoc3RhY2sudGFncy50YWdWYWx1ZXMoKSksXG4gICAgdmFsaWRhdGVPblN5bnRoOiBzZXNzaW9uLnZhbGlkYXRlT25TeW50aCxcbiAgICAuLi5zdGFja1Byb3BzLFxuICAgIC4uLnN0YWNrTmFtZVByb3BlcnR5LFxuICB9O1xuXG4gIC8vIGFkZCBhbiBhcnRpZmFjdCB0aGF0IHJlcHJlc2VudHMgdGhpcyBzdGFja1xuICBzZXNzaW9uLmFzc2VtYmx5LmFkZEFydGlmYWN0KHN0YWNrLmFydGlmYWN0SWQsIHtcbiAgICB0eXBlOiBjeHNjaGVtYS5BcnRpZmFjdFR5cGUuQVdTX0NMT1VERk9STUFUSU9OX1NUQUNLLFxuICAgIGVudmlyb25tZW50OiBzdGFjay5lbnZpcm9ubWVudCxcbiAgICBwcm9wZXJ0aWVzLFxuICAgIGRlcGVuZGVuY2llczogZGVwcy5sZW5ndGggPiAwID8gZGVwcyA6IHVuZGVmaW5lZCxcbiAgICBtZXRhZGF0YTogT2JqZWN0LmtleXMobWV0YSkubGVuZ3RoID4gMCA/IG1ldGEgOiB1bmRlZmluZWQsXG4gICAgZGlzcGxheU5hbWU6IHN0YWNrLm5vZGUucGF0aCxcbiAgfSk7XG59XG5cbi8qKlxuICogQ29sbGVjdCB0aGUgbWV0YWRhdGEgZnJvbSBhIHN0YWNrXG4gKi9cbmZ1bmN0aW9uIGNvbGxlY3RTdGFja01ldGFkYXRhKHN0YWNrOiBTdGFjaykge1xuICBjb25zdCBvdXRwdXQ6IHsgW2lkOiBzdHJpbmddOiBjeHNjaGVtYS5NZXRhZGF0YUVudHJ5W10gfSA9IHsgfTtcblxuICB2aXNpdChzdGFjayk7XG5cbiAgcmV0dXJuIG91dHB1dDtcblxuICBmdW5jdGlvbiB2aXNpdChub2RlOiBJQ29uc3RydWN0KSB7XG4gICAgLy8gYnJlYWsgb2ZmIGlmIHdlIHJlYWNoZWQgYSBub2RlIHRoYXQgaXMgbm90IGEgY2hpbGQgb2YgdGhpcyBzdGFja1xuICAgIGNvbnN0IHBhcmVudCA9IGZpbmRQYXJlbnRTdGFjayhub2RlKTtcbiAgICBpZiAocGFyZW50ICE9PSBzdGFjaykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChub2RlLm5vZGUubWV0YWRhdGFFbnRyeS5sZW5ndGggPiAwKSB7XG4gICAgICAvLyBNYWtlIHRoZSBwYXRoIGFic29sdXRlXG4gICAgICBvdXRwdXRbQ29uc3RydWN0Tm9kZS5QQVRIX1NFUCArIG5vZGUubm9kZS5wYXRoXSA9IG5vZGUubm9kZS5tZXRhZGF0YUVudHJ5Lm1hcChtZCA9PiBzdGFjay5yZXNvbHZlKG1kKSBhcyBjeHNjaGVtYS5NZXRhZGF0YUVudHJ5KTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGNoaWxkIG9mIG5vZGUubm9kZS5jaGlsZHJlbikge1xuICAgICAgdmlzaXQoY2hpbGQpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGZpbmRQYXJlbnRTdGFjayhub2RlOiBJQ29uc3RydWN0KTogU3RhY2sgfCB1bmRlZmluZWQge1xuICAgIGlmIChTdGFjay5pc1N0YWNrKG5vZGUpICYmIG5vZGUubmVzdGVkU3RhY2tQYXJlbnQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgcmV0dXJuIG5vZGU7XG4gICAgfVxuXG4gICAgaWYgKCFub2RlLm5vZGUuc2NvcGUpIHtcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcmV0dXJuIGZpbmRQYXJlbnRTdGFjayhub2RlLm5vZGUuc2NvcGUpO1xuICB9XG59XG5cbi8qKlxuICogSGFzaCBhIHN0cmluZ1xuICovXG5leHBvcnQgZnVuY3Rpb24gY29udGVudEhhc2goY29udGVudDogc3RyaW5nKSB7XG4gIHJldHVybiBjcnlwdG8uY3JlYXRlSGFzaCgnc2hhMjU2JykudXBkYXRlKGNvbnRlbnQpLmRpZ2VzdCgnaGV4Jyk7XG59XG5cbi8qKlxuICogVGhyb3cgYW4gZXJyb3IgbWVzc2FnZSBhYm91dCBiaW5kaW5nKCkgaWYgd2UgZG9uJ3QgaGF2ZSBhIHZhbHVlIGZvciB4LlxuICpcbiAqIFRoaXMgcmVwbGFjZXMgdGhlICEgYXNzZXJ0aW9ucyB3ZSB3b3VsZCBuZWVkIGV2ZXJ5d2hlcmUgb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0Qm91bmQ8QT4oeDogQSB8IHVuZGVmaW5lZCk6IGFzc2VydHMgeCBpcyBOb25OdWxsYWJsZTxBPiB7XG4gIGlmICh4ID09PSBudWxsICYmIHggPT09IHVuZGVmaW5lZCkge1xuICAgIHRocm93IG5ldyBFcnJvcignWW91IG11c3QgY2FsbCBiaW5kU3RhY2soKSBmaXJzdCcpO1xuICB9XG59XG5cbmZ1bmN0aW9uIG5vbkVtcHR5RGljdDxBPih4czogUmVjb3JkPHN0cmluZywgQT4pIHtcbiAgcmV0dXJuIE9iamVjdC5rZXlzKHhzKS5sZW5ndGggPiAwID8geHMgOiB1bmRlZmluZWQ7XG59XG5cbi8qKlxuICogQSBcInJlcGxhY2UtYWxsXCIgZnVuY3Rpb24gdGhhdCBkb2Vzbid0IHJlcXVpcmUgdXMgZXNjYXBpbmcgYSBsaXRlcmFsIHN0cmluZyB0byBhIHJlZ2V4XG4gKi9cbmZ1bmN0aW9uIHJlcGxhY2VBbGwoczogc3RyaW5nLCBzZWFyY2g6IHN0cmluZywgcmVwbGFjZTogc3RyaW5nKSB7XG4gIHJldHVybiBzLnNwbGl0KHNlYXJjaCkuam9pbihyZXBsYWNlKTtcbn1cblxuZXhwb3J0IGNsYXNzIFN0cmluZ1NwZWNpYWxpemVyIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSByZWFkb25seSBzdGFjazogU3RhY2ssIHByaXZhdGUgcmVhZG9ubHkgcXVhbGlmaWVyOiBzdHJpbmcpIHtcbiAgfVxuXG4gIC8qKlxuICAgKiBGdW5jdGlvbiB0byByZXBsYWNlIHBsYWNlaG9sZGVycyBpbiB0aGUgaW5wdXQgc3RyaW5nIGFzIG11Y2ggYXMgcG9zc2libGVcbiAgICpcbiAgICogV2UgcmVwbGFjZTpcbiAgICogLSAke1F1YWxpZmllcn06IGFsd2F5c1xuICAgKiAtICR7QVdTOjpBY2NvdW50SWR9LCAke0FXUzo6UmVnaW9ufTogb25seSBpZiB3ZSBoYXZlIHRoZSBhY3R1YWwgdmFsdWVzIGF2YWlsYWJsZVxuICAgKiAtICR7QVdTOjpQYXJ0aXRpb259OiBuZXZlciwgc2luY2Ugd2UgbmV2ZXIgaGF2ZSB0aGUgYWN0dWFsIHBhcnRpdGlvbiB2YWx1ZS5cbiAgICovXG4gIHB1YmxpYyBzcGVjaWFsaXplKHM6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgcyA9IHJlcGxhY2VBbGwocywgJyR7UXVhbGlmaWVyfScsIHRoaXMucXVhbGlmaWVyKTtcbiAgICByZXR1cm4gY3hhcGkuRW52aXJvbm1lbnRQbGFjZWhvbGRlcnMucmVwbGFjZShzLCB7XG4gICAgICByZWdpb246IHJlc29sdmVkT3IodGhpcy5zdGFjay5yZWdpb24sIGN4YXBpLkVudmlyb25tZW50UGxhY2Vob2xkZXJzLkNVUlJFTlRfUkVHSU9OKSxcbiAgICAgIGFjY291bnRJZDogcmVzb2x2ZWRPcih0aGlzLnN0YWNrLmFjY291bnQsIGN4YXBpLkVudmlyb25tZW50UGxhY2Vob2xkZXJzLkNVUlJFTlRfQUNDT1VOVCksXG4gICAgICBwYXJ0aXRpb246IGN4YXBpLkVudmlyb25tZW50UGxhY2Vob2xkZXJzLkNVUlJFTlRfUEFSVElUSU9OLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFNwZWNpYWxpemUgb25seSB0aGUgcXVhbGlmaWVyXG4gICAqL1xuICBwdWJsaWMgcXVhbGlmaWVyT25seShzOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiByZXBsYWNlQWxsKHMsICcke1F1YWxpZmllcn0nLCB0aGlzLnF1YWxpZmllcik7XG4gIH1cbn1cblxuLyoqXG4gKiBSZXR1cm4gdGhlIGdpdmVuIHZhbHVlIGlmIHJlc29sdmVkIG9yIGZhbGwgYmFjayB0byBhIGRlZmF1bHRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVkT3I8QT4oeDogc3RyaW5nLCBkZWY6IEEpOiBzdHJpbmcgfCBBIHtcbiAgcmV0dXJuIFRva2VuLmlzVW5yZXNvbHZlZCh4KSA/IGRlZiA6IHg7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzdGFja1RlbXBsYXRlRmlsZUFzc2V0KHN0YWNrOiBTdGFjaywgc2Vzc2lvbjogSVN5bnRoZXNpc1Nlc3Npb24pOiBGaWxlQXNzZXRTb3VyY2Uge1xuICBjb25zdCB0ZW1wbGF0ZVBhdGggPSBwYXRoLmpvaW4oc2Vzc2lvbi5hc3NlbWJseS5vdXRkaXIsIHN0YWNrLnRlbXBsYXRlRmlsZSk7XG4gIGNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKHRlbXBsYXRlUGF0aCwgeyBlbmNvZGluZzogJ3V0Zi04JyB9KTtcblxuICBjb25zdCBzb3VyY2VIYXNoID0gY29udGVudEhhc2godGVtcGxhdGUpO1xuXG4gIHJldHVybiB7XG4gICAgZmlsZU5hbWU6IHN0YWNrLnRlbXBsYXRlRmlsZSxcbiAgICBwYWNrYWdpbmc6IEZpbGVBc3NldFBhY2thZ2luZy5GSUxFLFxuICAgIHNvdXJjZUhhc2gsXG4gIH07XG59XG4iXX0= |
\ | No newline at end of file |