UNPKG

@aws-cdk/core

Version:

AWS Cloud Development Kit Core Library

99 lines 13.7 kB
"use strict"; 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==