@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
99 lines • 13.7 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.addDependency = void 0;
const stack_1 = require("./stack");
const stage_1 = require("./stage");
const util_1 = require("./util");
/**
* Adds a dependency between two resources or stacks, across stack and nested
* stack boundaries.
*
* The algorithm consists of:
* - Try to find the deepest common stack between the two elements
* - If there isn't a common stack, it means the elements belong to two
* disjoined stack-trees and therefore we apply the dependency at the
* assembly/app level between the two topl-level stacks.
* - If we did find a common stack, we apply the dependency as a CloudFormation
* "DependsOn" between the resources that "represent" our source and target
* either directly or through the AWS::CloudFormation::Stack resources that
* "lead" to them.
*
* @param source The source resource/stack (the depedent)
* @param target The target resource/stack (the dependency)
* @param reason Optional resource to associate with the dependency for
* diagnostics
*/
function addDependency(source, target, reason) {
if (source === target) {
return;
}
const sourceStack = stack_1.Stack.of(source);
const targetStack = stack_1.Stack.of(target);
const sourceStage = stage_1.Stage.of(sourceStack);
const targetStage = stage_1.Stage.of(targetStack);
if (sourceStage !== targetStage) {
// eslint-disable-next-line max-len
throw new Error(`You cannot add a dependency from '${source.node.path}' (in ${describeStage(sourceStage)}) to '${target.node.path}' (in ${describeStage(targetStage)}): dependency cannot cross stage boundaries`);
}
// find the deepest common stack between the two elements
const sourcePath = util_1.pathToTopLevelStack(sourceStack);
const targetPath = util_1.pathToTopLevelStack(targetStack);
const commonStack = util_1.findLastCommonElement(sourcePath, targetPath);
// if there is no common stack, then define a assembly-level dependency
// between the two top-level stacks
if (!commonStack) {
const topLevelSource = sourcePath[0]; // first path element is the top-level stack
const topLevelTarget = targetPath[0];
topLevelSource._addAssemblyDependency(topLevelTarget, reason);
return;
}
// assertion: at this point if source and target are stacks, both are nested stacks.
// since we have a common stack, it is impossible that both are top-level
// stacks, so let's examine the two cases where one of them is top-level and
// the other is nested.
// case 1 - source is top-level and target is nested: this implies that
// `target` is a direct or indirect nested stack of `source`, and an explicit
// dependency is not required because nested stacks will always be deployed
// before their parents.
if (commonStack === source) {
return;
}
// case 2 - source is nested and target is top-level: this implies that
// `source` is a direct or indirect nested stack of `target`, and this is not
// possible (nested stacks cannot depend on their parents).
if (commonStack === target) {
throw new Error(`Nested stack '${sourceStack.node.path}' cannot depend on a parent stack '${targetStack.node.path}': ${reason}`);
}
// we have a common stack from which we can reach both `source` and `target`
// now we need to find two resources which are defined directly in this stack
// and which can "lead us" to the source/target.
const sourceResource = resourceInCommonStackFor(source);
const targetResource = resourceInCommonStackFor(target);
sourceResource._addResourceDependency(targetResource);
function resourceInCommonStackFor(element) {
const resource = stack_1.Stack.isStack(element) ? element.nestedStackResource : element;
if (!resource) {
throw new Error('assertion failure'); // see "assertion" above
}
const resourceStack = stack_1.Stack.of(resource);
// we reached a resource defined in the common stack
if (commonStack === resourceStack) {
return resource;
}
return resourceInCommonStackFor(resourceStack);
}
}
exports.addDependency = addDependency;
/**
* Return a string representation of the given assembler, for use in error messages
*/
function describeStage(assembly) {
if (!assembly) {
return 'an unrooted construct tree';
}
if (!assembly.parentStage) {
return 'the App';
}
return `Stage '${assembly.node.path}'`;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImRlcHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQ0EsbUNBQWdDO0FBQ2hDLG1DQUFnQztBQUNoQyxpQ0FBa0Y7QUFJbEY7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtCRztBQUNILFNBQWdCLGFBQWEsQ0FBb0IsTUFBUyxFQUFFLE1BQVMsRUFBRSxNQUFlO0lBQ3BGLElBQUksTUFBTSxLQUFLLE1BQU0sRUFBRTtRQUNyQixPQUFPO0tBQ1I7SUFFRCxNQUFNLFdBQVcsR0FBRyxhQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3JDLE1BQU0sV0FBVyxHQUFHLGFBQUssQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUM7SUFFckMsTUFBTSxXQUFXLEdBQUcsYUFBSyxDQUFDLEVBQUUsQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUMxQyxNQUFNLFdBQVcsR0FBRyxhQUFLLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQzFDLElBQUksV0FBVyxLQUFLLFdBQVcsRUFBRTtRQUMvQixtQ0FBbUM7UUFDbkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxxQ0FBcUMsTUFBTSxDQUFDLElBQUksQ0FBQyxJQUFJLFNBQVMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxTQUFTLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxTQUFTLGFBQWEsQ0FBQyxXQUFXLENBQUMsNkNBQTZDLENBQUMsQ0FBQztLQUNwTjtJQUVELHlEQUF5RDtJQUN6RCxNQUFNLFVBQVUsR0FBRywwQkFBVSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQzNDLE1BQU0sVUFBVSxHQUFHLDBCQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDM0MsTUFBTSxXQUFXLEdBQUcsNEJBQXFCLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBRWxFLHVFQUF1RTtJQUN2RSxtQ0FBbUM7SUFDbkMsSUFBSSxDQUFDLFdBQVcsRUFBRTtRQUNoQixNQUFNLGNBQWMsR0FBRyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyw0Q0FBNEM7UUFDbEYsTUFBTSxjQUFjLEdBQUcsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ3JDLGNBQWMsQ0FBQyxzQkFBc0IsQ0FBQyxjQUFjLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDOUQsT0FBTztLQUNSO0lBRUQsb0ZBQW9GO0lBQ3BGLHlFQUF5RTtJQUN6RSw0RUFBNEU7SUFDNUUsdUJBQXVCO0lBRXZCLHVFQUF1RTtJQUN2RSw2RUFBNkU7SUFDN0UsMkVBQTJFO0lBQzNFLHdCQUF3QjtJQUN4QixJQUFJLFdBQVcsS0FBSyxNQUFNLEVBQUU7UUFDMUIsT0FBTztLQUNSO0lBRUQsdUVBQXVFO0lBQ3ZFLDZFQUE2RTtJQUM3RSwyREFBMkQ7SUFDM0QsSUFBSSxXQUFXLEtBQUssTUFBTSxFQUFFO1FBQzFCLE1BQU0sSUFBSSxLQUFLLENBQUMsaUJBQWlCLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxzQ0FBc0MsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLE1BQU0sTUFBTSxFQUFFLENBQUMsQ0FBQztLQUNsSTtJQUVELDRFQUE0RTtJQUM1RSw2RUFBNkU7SUFDN0UsZ0RBQWdEO0lBQ2hELE1BQU0sY0FBYyxHQUFHLHdCQUF3QixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3hELE1BQU0sY0FBYyxHQUFHLHdCQUF3QixDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3hELGNBQWMsQ0FBQyxzQkFBc0IsQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUV0RCxTQUFTLHdCQUF3QixDQUFDLE9BQTRCO1FBQzVELE1BQU0sUUFBUSxHQUFHLGFBQUssQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDO1FBQ2hGLElBQUksQ0FBQyxRQUFRLEVBQUU7WUFDYixNQUFNLElBQUksS0FBSyxDQUFDLG1CQUFtQixDQUFDLENBQUMsQ0FBQyx3QkFBd0I7U0FDL0Q7UUFFRCxNQUFNLGFBQWEsR0FBRyxhQUFLLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBRXpDLG9EQUFvRDtRQUNwRCxJQUFJLFdBQVcsS0FBSyxhQUFhLEVBQUU7WUFDakMsT0FBTyxRQUFRLENBQUM7U0FDakI7UUFFRCxPQUFPLHdCQUF3QixDQUFDLGFBQWEsQ0FBQyxDQUFDO0lBQ2pELENBQUM7QUFDSCxDQUFDO0FBdkVELHNDQXVFQztBQUVEOztHQUVHO0FBQ0gsU0FBUyxhQUFhLENBQUMsUUFBMkI7SUFDaEQsSUFBSSxDQUFDLFFBQVEsRUFBRTtRQUFFLE9BQU8sNEJBQTRCLENBQUM7S0FBRTtJQUN2RCxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRTtRQUFFLE9BQU8sU0FBUyxDQUFDO0tBQUU7SUFDaEQsT0FBTyxVQUFVLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxHQUFHLENBQUM7QUFDekMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENmblJlc291cmNlIH0gZnJvbSAnLi9jZm4tcmVzb3VyY2UnO1xuaW1wb3J0IHsgU3RhY2sgfSBmcm9tICcuL3N0YWNrJztcbmltcG9ydCB7IFN0YWdlIH0gZnJvbSAnLi9zdGFnZSc7XG5pbXBvcnQgeyBmaW5kTGFzdENvbW1vbkVsZW1lbnQsIHBhdGhUb1RvcExldmVsU3RhY2sgYXMgcGF0aFRvUm9vdCB9IGZyb20gJy4vdXRpbCc7XG5cbnR5cGUgRWxlbWVudCA9IENmblJlc291cmNlIHwgU3RhY2s7XG5cbi8qKlxuICogQWRkcyBhIGRlcGVuZGVuY3kgYmV0d2VlbiB0d28gcmVzb3VyY2VzIG9yIHN0YWNrcywgYWNyb3NzIHN0YWNrIGFuZCBuZXN0ZWRcbiAqIHN0YWNrIGJvdW5kYXJpZXMuXG4gKlxuICogVGhlIGFsZ29yaXRobSBjb25zaXN0cyBvZjpcbiAqIC0gVHJ5IHRvIGZpbmQgdGhlIGRlZXBlc3QgY29tbW9uIHN0YWNrIGJldHdlZW4gdGhlIHR3byBlbGVtZW50c1xuICogLSBJZiB0aGVyZSBpc24ndCBhIGNvbW1vbiBzdGFjaywgaXQgbWVhbnMgdGhlIGVsZW1lbnRzIGJlbG9uZyB0byB0d29cbiAqICAgZGlzam9pbmVkIHN0YWNrLXRyZWVzIGFuZCB0aGVyZWZvcmUgd2UgYXBwbHkgdGhlIGRlcGVuZGVuY3kgYXQgdGhlXG4gKiAgIGFzc2VtYmx5L2FwcCBsZXZlbCBiZXR3ZWVuIHRoZSB0d28gdG9wbC1sZXZlbCBzdGFja3MuXG4gKiAtIElmIHdlIGRpZCBmaW5kIGEgY29tbW9uIHN0YWNrLCB3ZSBhcHBseSB0aGUgZGVwZW5kZW5jeSBhcyBhIENsb3VkRm9ybWF0aW9uXG4gKiAgIFwiRGVwZW5kc09uXCIgYmV0d2VlbiB0aGUgcmVzb3VyY2VzIHRoYXQgXCJyZXByZXNlbnRcIiBvdXIgc291cmNlIGFuZCB0YXJnZXRcbiAqICAgZWl0aGVyIGRpcmVjdGx5IG9yIHRocm91Z2ggdGhlIEFXUzo6Q2xvdWRGb3JtYXRpb246OlN0YWNrIHJlc291cmNlcyB0aGF0XG4gKiAgIFwibGVhZFwiIHRvIHRoZW0uXG4gKlxuICogQHBhcmFtIHNvdXJjZSBUaGUgc291cmNlIHJlc291cmNlL3N0YWNrICh0aGUgZGVwZWRlbnQpXG4gKiBAcGFyYW0gdGFyZ2V0IFRoZSB0YXJnZXQgcmVzb3VyY2Uvc3RhY2sgKHRoZSBkZXBlbmRlbmN5KVxuICogQHBhcmFtIHJlYXNvbiBPcHRpb25hbCByZXNvdXJjZSB0byBhc3NvY2lhdGUgd2l0aCB0aGUgZGVwZW5kZW5jeSBmb3JcbiAqIGRpYWdub3N0aWNzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZGREZXBlbmRlbmN5PFQgZXh0ZW5kcyBFbGVtZW50Pihzb3VyY2U6IFQsIHRhcmdldDogVCwgcmVhc29uPzogc3RyaW5nKSB7XG4gIGlmIChzb3VyY2UgPT09IHRhcmdldCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHNvdXJjZVN0YWNrID0gU3RhY2sub2Yoc291cmNlKTtcbiAgY29uc3QgdGFyZ2V0U3RhY2sgPSBTdGFjay5vZih0YXJnZXQpO1xuXG4gIGNvbnN0IHNvdXJjZVN0YWdlID0gU3RhZ2Uub2Yoc291cmNlU3RhY2spO1xuICBjb25zdCB0YXJnZXRTdGFnZSA9IFN0YWdlLm9mKHRhcmdldFN0YWNrKTtcbiAgaWYgKHNvdXJjZVN0YWdlICE9PSB0YXJnZXRTdGFnZSkge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtbGVuXG4gICAgdGhyb3cgbmV3IEVycm9yKGBZb3UgY2Fubm90IGFkZCBhIGRlcGVuZGVuY3kgZnJvbSAnJHtzb3VyY2Uubm9kZS5wYXRofScgKGluICR7ZGVzY3JpYmVTdGFnZShzb3VyY2VTdGFnZSl9KSB0byAnJHt0YXJnZXQubm9kZS5wYXRofScgKGluICR7ZGVzY3JpYmVTdGFnZSh0YXJnZXRTdGFnZSl9KTogZGVwZW5kZW5jeSBjYW5ub3QgY3Jvc3Mgc3RhZ2UgYm91bmRhcmllc2ApO1xuICB9XG5cbiAgLy8gZmluZCB0aGUgZGVlcGVzdCBjb21tb24gc3RhY2sgYmV0d2VlbiB0aGUgdHdvIGVsZW1lbnRzXG4gIGNvbnN0IHNvdXJjZVBhdGggPSBwYXRoVG9Sb290KHNvdXJjZVN0YWNrKTtcbiAgY29uc3QgdGFyZ2V0UGF0aCA9IHBhdGhUb1Jvb3QodGFyZ2V0U3RhY2spO1xuICBjb25zdCBjb21tb25TdGFjayA9IGZpbmRMYXN0Q29tbW9uRWxlbWVudChzb3VyY2VQYXRoLCB0YXJnZXRQYXRoKTtcblxuICAvLyBpZiB0aGVyZSBpcyBubyBjb21tb24gc3RhY2ssIHRoZW4gZGVmaW5lIGEgYXNzZW1ibHktbGV2ZWwgZGVwZW5kZW5jeVxuICAvLyBiZXR3ZWVuIHRoZSB0d28gdG9wLWxldmVsIHN0YWNrc1xuICBpZiAoIWNvbW1vblN0YWNrKSB7XG4gICAgY29uc3QgdG9wTGV2ZWxTb3VyY2UgPSBzb3VyY2VQYXRoWzBdOyAvLyBmaXJzdCBwYXRoIGVsZW1lbnQgaXMgdGhlIHRvcC1sZXZlbCBzdGFja1xuICAgIGNvbnN0IHRvcExldmVsVGFyZ2V0ID0gdGFyZ2V0UGF0aFswXTtcbiAgICB0b3BMZXZlbFNvdXJjZS5fYWRkQXNzZW1ibHlEZXBlbmRlbmN5KHRvcExldmVsVGFyZ2V0LCByZWFzb24pO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIGFzc2VydGlvbjogYXQgdGhpcyBwb2ludCBpZiBzb3VyY2UgYW5kIHRhcmdldCBhcmUgc3RhY2tzLCBib3RoIGFyZSBuZXN0ZWQgc3RhY2tzLlxuICAvLyBzaW5jZSB3ZSBoYXZlIGEgY29tbW9uIHN0YWNrLCBpdCBpcyBpbXBvc3NpYmxlIHRoYXQgYm90aCBhcmUgdG9wLWxldmVsXG4gIC8vIHN0YWNrcywgc28gbGV0J3MgZXhhbWluZSB0aGUgdHdvIGNhc2VzIHdoZXJlIG9uZSBvZiB0aGVtIGlzIHRvcC1sZXZlbCBhbmRcbiAgLy8gdGhlIG90aGVyIGlzIG5lc3RlZC5cblxuICAvLyBjYXNlIDEgLSBzb3VyY2UgaXMgdG9wLWxldmVsIGFuZCB0YXJnZXQgaXMgbmVzdGVkOiB0aGlzIGltcGxpZXMgdGhhdFxuICAvLyBgdGFyZ2V0YCBpcyBhIGRpcmVjdCBvciBpbmRpcmVjdCBuZXN0ZWQgc3RhY2sgb2YgYHNvdXJjZWAsIGFuZCBhbiBleHBsaWNpdFxuICAvLyBkZXBlbmRlbmN5IGlzIG5vdCByZXF1aXJlZCBiZWNhdXNlIG5lc3RlZCBzdGFja3Mgd2lsbCBhbHdheXMgYmUgZGVwbG95ZWRcbiAgLy8gYmVmb3JlIHRoZWlyIHBhcmVudHMuXG4gIGlmIChjb21tb25TdGFjayA9PT0gc291cmNlKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gY2FzZSAyIC0gc291cmNlIGlzIG5lc3RlZCBhbmQgdGFyZ2V0IGlzIHRvcC1sZXZlbDogdGhpcyBpbXBsaWVzIHRoYXRcbiAgLy8gYHNvdXJjZWAgaXMgYSBkaXJlY3Qgb3IgaW5kaXJlY3QgbmVzdGVkIHN0YWNrIG9mIGB0YXJnZXRgLCBhbmQgdGhpcyBpcyBub3RcbiAgLy8gcG9zc2libGUgKG5lc3RlZCBzdGFja3MgY2Fubm90IGRlcGVuZCBvbiB0aGVpciBwYXJlbnRzKS5cbiAgaWYgKGNvbW1vblN0YWNrID09PSB0YXJnZXQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYE5lc3RlZCBzdGFjayAnJHtzb3VyY2VTdGFjay5ub2RlLnBhdGh9JyBjYW5ub3QgZGVwZW5kIG9uIGEgcGFyZW50IHN0YWNrICcke3RhcmdldFN0YWNrLm5vZGUucGF0aH0nOiAke3JlYXNvbn1gKTtcbiAgfVxuXG4gIC8vIHdlIGhhdmUgYSBjb21tb24gc3RhY2sgZnJvbSB3aGljaCB3ZSBjYW4gcmVhY2ggYm90aCBgc291cmNlYCBhbmQgYHRhcmdldGBcbiAgLy8gbm93IHdlIG5lZWQgdG8gZmluZCB0d28gcmVzb3VyY2VzIHdoaWNoIGFyZSBkZWZpbmVkIGRpcmVjdGx5IGluIHRoaXMgc3RhY2tcbiAgLy8gYW5kIHdoaWNoIGNhbiBcImxlYWQgdXNcIiB0byB0aGUgc291cmNlL3RhcmdldC5cbiAgY29uc3Qgc291cmNlUmVzb3VyY2UgPSByZXNvdXJjZUluQ29tbW9uU3RhY2tGb3Ioc291cmNlKTtcbiAgY29uc3QgdGFyZ2V0UmVzb3VyY2UgPSByZXNvdXJjZUluQ29tbW9uU3RhY2tGb3IodGFyZ2V0KTtcbiAgc291cmNlUmVzb3VyY2UuX2FkZFJlc291cmNlRGVwZW5kZW5jeSh0YXJnZXRSZXNvdXJjZSk7XG5cbiAgZnVuY3Rpb24gcmVzb3VyY2VJbkNvbW1vblN0YWNrRm9yKGVsZW1lbnQ6IENmblJlc291cmNlIHwgU3RhY2spOiBDZm5SZXNvdXJjZSB7XG4gICAgY29uc3QgcmVzb3VyY2UgPSBTdGFjay5pc1N0YWNrKGVsZW1lbnQpID8gZWxlbWVudC5uZXN0ZWRTdGFja1Jlc291cmNlIDogZWxlbWVudDtcbiAgICBpZiAoIXJlc291cmNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2Fzc2VydGlvbiBmYWlsdXJlJyk7IC8vIHNlZSBcImFzc2VydGlvblwiIGFib3ZlXG4gICAgfVxuXG4gICAgY29uc3QgcmVzb3VyY2VTdGFjayA9IFN0YWNrLm9mKHJlc291cmNlKTtcblxuICAgIC8vIHdlIHJlYWNoZWQgYSByZXNvdXJjZSBkZWZpbmVkIGluIHRoZSBjb21tb24gc3RhY2tcbiAgICBpZiAoY29tbW9uU3RhY2sgPT09IHJlc291cmNlU3RhY2spIHtcbiAgICAgIHJldHVybiByZXNvdXJjZTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzb3VyY2VJbkNvbW1vblN0YWNrRm9yKHJlc291cmNlU3RhY2spO1xuICB9XG59XG5cbi8qKlxuICogUmV0dXJuIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBnaXZlbiBhc3NlbWJsZXIsIGZvciB1c2UgaW4gZXJyb3IgbWVzc2FnZXNcbiAqL1xuZnVuY3Rpb24gZGVzY3JpYmVTdGFnZShhc3NlbWJseTogU3RhZ2UgfCB1bmRlZmluZWQpOiBzdHJpbmcge1xuICBpZiAoIWFzc2VtYmx5KSB7IHJldHVybiAnYW4gdW5yb290ZWQgY29uc3RydWN0IHRyZWUnOyB9XG4gIGlmICghYXNzZW1ibHkucGFyZW50U3RhZ2UpIHsgcmV0dXJuICd0aGUgQXBwJzsgfVxuICByZXR1cm4gYFN0YWdlICcke2Fzc2VtYmx5Lm5vZGUucGF0aH0nYDtcbn1cbiJdfQ==
;