UNPKG

@aws-cdk/core

Version:

AWS Cloud Development Kit Core Library

229 lines 33.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // ---------------------------------------------------- // CROSS REFERENCES // ---------------------------------------------------- const cfn_element_1 = require("../cfn-element"); const cfn_output_1 = require("../cfn-output"); const cfn_parameter_1 = require("../cfn-parameter"); const construct_compat_1 = require("../construct-compat"); const stack_1 = require("../stack"); const token_1 = require("../token"); const cfn_reference_1 = require("./cfn-reference"); const intrinsic_1 = require("./intrinsic"); const resolve_1 = require("./resolve"); const uniqueid_1 = require("./uniqueid"); /** * This is called from the App level to resolve all references defined. Each * reference is resolved based on it's consumption context. */ function resolveReferences(scope) { const edges = findAllReferences(scope); for (const { source, value } of edges) { const consumer = stack_1.Stack.of(source); // resolve the value in the context of the consumer if (!value.hasValueForStack(consumer)) { const resolved = resolveValue(consumer, value); value.assignValueForStack(consumer, resolved); } } } exports.resolveReferences = resolveReferences; /** * Resolves the value for `reference` in the context of `consumer`. */ function resolveValue(consumer, reference) { const producer = stack_1.Stack.of(reference.target); // produce and consumer stacks are the same, we can just return the value itself. if (producer === consumer) { return reference; } // unsupported: stacks from different apps if (producer.node.root !== consumer.node.root) { throw new Error('Cannot reference across apps. Consuming and producing stacks must be defined within the same CDK app.'); } // unsupported: stacks are not in the same environment if (producer.environment !== consumer.environment) { throw new Error(`Stack "${consumer.node.path}" cannot consume a cross reference from stack "${producer.node.path}". ` + 'Cross stack references are only supported for stacks deployed to the same environment or between nested stacks and their parent stack'); } // ---------------------------------------------------------------------- // consumer is nested in the producer (directly or indirectly) // ---------------------------------------------------------------------- // if the consumer is nested within the producer (directly or indirectly), // wire through a CloudFormation parameter and then resolve the reference with // the parent stack as the consumer. if (consumer.nestedStackParent && isNested(consumer, producer)) { const parameterValue = resolveValue(consumer.nestedStackParent, reference); return createNestedStackParameter(consumer, reference, parameterValue); } // ---------------------------------------------------------------------- // producer is a nested stack // ---------------------------------------------------------------------- // if the producer is nested, always publish the value through a // cloudformation output and resolve recursively with the Fn::GetAtt // of the output in the parent stack. // one might ask, if the consumer is not a parent of the producer, // why not just use export/import? the reason is that we cannot // generate an "export name" from a nested stack because the export // name must contain the stack name to ensure uniqueness, and we // don't know the stack name of a nested stack before we deploy it. // therefore, we can only export from a top-level stack. if (producer.nested) { const outputValue = createNestedStackOutput(producer, reference); return resolveValue(consumer, outputValue); } // ---------------------------------------------------------------------- // export/import // ---------------------------------------------------------------------- // export the value through a cloudformation "export name" and use an // Fn::ImportValue in the consumption site. // add a dependency between the producer and the consumer. dependency logic // will take care of applying the dependency at the right level (e.g. the // top-level stacks). consumer.addDependency(producer, `${consumer.node.path} -> ${reference.target.node.path}.${reference.displayName}`); return createImportValue(reference); } /** * Finds all the CloudFormation references in a construct tree. */ function findAllReferences(root) { const result = new Array(); for (const consumer of root.node.findAll()) { // include only CfnElements (i.e. resources) if (!cfn_element_1.CfnElement.isCfnElement(consumer)) { continue; } try { const tokens = resolve_1.findTokens(consumer, () => consumer._toCloudFormation()); // iterate over all the tokens (e.g. intrinsic functions, lazies, etc) that // were found in the cloudformation representation of this resource. for (const token of tokens) { // include only CfnReferences (i.e. "Ref" and "Fn::GetAtt") if (!cfn_reference_1.CfnReference.isCfnReference(token)) { continue; } result.push({ source: consumer, value: token, }); } } catch (e) { // Note: it might be that the properties of the CFN object aren't valid. // This will usually be preventatively caught in a construct's validate() // and turned into a nicely descriptive error, but we're running prepare() // before validate(). Swallow errors that occur because the CFN layer // doesn't validate completely. // // This does make the assumption that the error will not be rectified, // but the error will be thrown later on anyway. If the error doesn't // get thrown down the line, we may miss references. if (e.type === 'CfnSynthesisError') { continue; } throw e; } } return result; } // ------------------------------------------------------------------------------------------------ // export/import // ------------------------------------------------------------------------------------------------ /** * Imports a value from another stack by creating an "Output" with an "ExportName" * and returning an "Fn::ImportValue" token. */ function createImportValue(reference) { const exportingStack = stack_1.Stack.of(reference.target); // Ensure a singleton "Exports" scoping Construct // This mostly exists to trigger LogicalID munging, which would be // disabled if we parented constructs directly under Stack. // Also it nicely prevents likely construct name clashes const exportsScope = getCreateExportsScope(exportingStack); // Ensure a singleton CfnOutput for this value const resolved = exportingStack.resolve(reference); const id = 'Output' + JSON.stringify(resolved); const exportName = generateExportName(exportsScope, id); if (token_1.Token.isUnresolved(exportName)) { throw new Error(`unresolved token in generated export name: ${JSON.stringify(exportingStack.resolve(exportName))}`); } const output = exportsScope.node.tryFindChild(id); if (!output) { new cfn_output_1.CfnOutput(exportsScope, id, { value: token_1.Token.asString(reference), exportName }); } // We want to return an actual FnImportValue Token here, but Fn.importValue() returns a 'string', // so construct one in-place. return new intrinsic_1.Intrinsic({ 'Fn::ImportValue': exportName }); } function getCreateExportsScope(stack) { const exportsName = 'Exports'; let stackExports = stack.node.tryFindChild(exportsName); if (stackExports === undefined) { stackExports = new construct_compat_1.Construct(stack, exportsName); } return stackExports; } function generateExportName(stackExports, id) { const stack = stack_1.Stack.of(stackExports); const components = [...stackExports.node.scopes.slice(2).map(c => c.node.id), id]; const prefix = stack.stackName ? stack.stackName + ':' : ''; const exportName = prefix + uniqueid_1.makeUniqueId(components); return exportName; } // ------------------------------------------------------------------------------------------------ // nested stacks // ------------------------------------------------------------------------------------------------ /** * Adds a CloudFormation parameter to a nested stack and assigns it with the * value of the reference. */ function createNestedStackParameter(nested, reference, value) { // we call "this.resolve" to ensure that tokens do not creep in (for example, if the reference display name includes tokens) const paramId = nested.resolve(`reference-to-${reference.target.node.uniqueId}.${reference.displayName}`); let param = nested.node.tryFindChild(paramId); if (!param) { param = new cfn_parameter_1.CfnParameter(nested, paramId, { type: 'String' }); // Ugly little hack until we move NestedStack to this module. if (!('setParameter' in nested)) { throw new Error('assertion failed: nested stack should have a "setParameter" method'); } nested.setParameter(param.logicalId, token_1.Token.asString(value)); } return param.value; } /** * Adds a CloudFormation output to a nested stack and returns an "Fn::GetAtt" * intrinsic that can be used to reference this output in the parent stack. */ function createNestedStackOutput(producer, reference) { const outputId = `${reference.target.node.uniqueId}${reference.displayName}`; let output = producer.node.tryFindChild(outputId); if (!output) { output = new cfn_output_1.CfnOutput(producer, outputId, { value: token_1.Token.asString(reference) }); } if (!producer.nestedStackResource) { throw new Error('assertion failed'); } return producer.nestedStackResource.getAtt(`Outputs.${output.logicalId}`); } /** * @returns true if this stack is a direct or indirect parent of the nested * stack `nested`. * * If `child` is not a nested stack, always returns `false` because it can't * have a parent, dah. */ function isNested(nested, parent) { // if the parent is a direct parent if (nested.nestedStackParent === parent) { return true; } // we reached a top-level (non-nested) stack without finding the parent if (!nested.nestedStackParent) { return false; } // recurse with the child's direct parent return isNested(nested.nestedStackParent, parent); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVmcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJlZnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFBQSx1REFBdUQ7QUFDdkQsbUJBQW1CO0FBQ25CLHVEQUF1RDtBQUN2RCxnREFBNEM7QUFDNUMsOENBQTBDO0FBQzFDLG9EQUFnRDtBQUNoRCwwREFBZ0Q7QUFHaEQsb0NBQWlDO0FBQ2pDLG9DQUFpQztBQUNqQyxtREFBK0M7QUFDL0MsMkNBQXdDO0FBQ3hDLHVDQUF1QztBQUN2Qyx5Q0FBMEM7QUFFMUM7OztHQUdHO0FBQ0gsU0FBZ0IsaUJBQWlCLENBQUMsS0FBZ0I7SUFDaEQsTUFBTSxLQUFLLEdBQUcsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUM7SUFFdkMsS0FBSyxNQUFNLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxJQUFJLEtBQUssRUFBRTtRQUNyQyxNQUFNLFFBQVEsR0FBRyxhQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRWxDLG1EQUFtRDtRQUNuRCxJQUFJLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQ3JDLE1BQU0sUUFBUSxHQUFHLFlBQVksQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDL0MsS0FBSyxDQUFDLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQztTQUMvQztLQUNGO0FBQ0gsQ0FBQztBQVpELDhDQVlDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxRQUFlLEVBQUUsU0FBdUI7SUFDNUQsTUFBTSxRQUFRLEdBQUcsYUFBSyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7SUFFNUMsaUZBQWlGO0lBQ2pGLElBQUksUUFBUSxLQUFLLFFBQVEsRUFBRTtRQUN6QixPQUFPLFNBQVMsQ0FBQztLQUNsQjtJQUVELDBDQUEwQztJQUMxQyxJQUFJLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFB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QUFFLGFBQUssQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0tBQ2xGO0lBRUQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxtQkFBbUIsRUFBRTtRQUNqQyxNQUFNLElBQUksS0FBSyxDQUFDLGtCQUFrQixDQUFDLENBQUM7S0FDckM7SUFFRCxPQUFPLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUMsV0FBVyxNQUFNLENBQUMsU0FBUyxFQUFFLENBQWlCLENBQUM7QUFDNUYsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILFNBQVMsUUFBUSxDQUFDLE1BQWEsRUFBRSxNQUFhO0lBQzVDLG1DQUFtQztJQUNuQyxJQUFJLE1BQU0sQ0FBQyxpQkFBaUIsS0FBSyxNQUFNLEVBQUU7UUFDdkMsT0FBTyxJQUFJLENBQUM7S0FDYjtJQUVELHVFQUF1RTtJQUN2RSxJQUFJLENBQUMsTUFBTSxDQUFDLGlCQUFpQixFQUFFO1FBQzdCLE9BQU8sS0FBSyxDQUFDO0tBQ2Q7SUFFRCx5Q0FBeUM7SUFDekMsT0FBTyxRQUFRLENBQUMsTUFBTSxDQUFDLGlCQUFpQixFQUFFLE1BQU0sQ0FBQyxDQUFDO0FBQ3BELENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBDUk9TUyBSRUZFUkVOQ0VTXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5pbXBvcnQgeyBDZm5FbGVtZW50IH0gZnJvbSAnLi4vY2ZuLWVsZW1lbnQnO1xuaW1wb3J0IHsgQ2ZuT3V0cHV0IH0gZnJvbSAnLi4vY2ZuLW91dHB1dCc7XG5pbXBvcnQgeyBDZm5QYXJhbWV0ZXIgfSBmcm9tICcuLi9jZm4tcGFyYW1ldGVyJztcbmltcG9ydCB7IENvbnN0cnVjdCB9IGZyb20gJy4uL2NvbnN0cnVjdC1jb21wYXQnO1xuaW1wb3J0IHsgUmVmZXJlbmNlIH0gZnJvbSAnLi4vcmVmZXJlbmNlJztcbmltcG9ydCB7IElSZXNvbHZhYmxlIH0gZnJvbSAnLi4vcmVzb2x2YWJsZSc7XG5pbXBvcnQgeyBTdGFjayB9IGZyb20gJy4uL3N0YWNrJztcbmltcG9ydCB7IFRva2VuIH0gZnJvbSAnLi4vdG9rZW4nO1xuaW1wb3J0IHsgQ2ZuUmVmZXJlbmNlIH0gZnJvbSAnLi9jZm4tcmVmZXJlbmNlJztcbmltcG9ydCB7IEludHJpbnNpYyB9IGZyb20gJy4vaW50cmluc2ljJztcbmltcG9ydCB7IGZpbmRUb2tlbnMgfSBmcm9tICcuL3Jlc29sdmUnO1xuaW1wb3J0IHsgbWFrZVVuaXF1ZUlkIH0gZnJvbSAnLi91bmlxdWVpZCc7XG5cbi8qKlxuICogVGhpcyBpcyBjYWxsZWQgZnJvbSB0aGUgQXBwIGxldmVsIHRvIHJlc29sdmUgYWxsIHJlZmVyZW5jZXMgZGVmaW5lZC4gRWFjaFxuICogcmVmZXJlbmNlIGlzIHJlc29sdmVkIGJhc2VkIG9uIGl0J3MgY29uc3VtcHRpb24gY29udGV4dC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVSZWZlcmVuY2VzKHNjb3BlOiBDb25zdHJ1Y3QpOiB2b2lkIHtcbiAgY29uc3QgZWRnZXMgPSBmaW5kQWxsUmVmZXJlbmNlcyhzY29wZSk7XG5cbiAgZm9yIChjb25zdCB7IHNvdXJjZSwgdmFsdWUgfSBvZiBlZGdlcykge1xuICAgIGNvbnN0IGNvbnN1bWVyID0gU3RhY2sub2Yoc291cmNlKTtcblxuICAgIC8vIHJlc29sdmUgdGhlIHZhbHVlIGluIHRoZSBjb250ZXh0IG9mIHRoZSBjb25zdW1lclxuICAgIGlmICghdmFsdWUuaGFzVmFsdWVGb3JTdGFjayhjb25zdW1lcikpIHtcbiAgICAgIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZVZhbHVlKGNvbnN1bWVyLCB2YWx1ZSk7XG4gICAgICB2YWx1ZS5hc3NpZ25WYWx1ZUZvclN0YWNrKGNvbnN1bWVyLCByZXNvbHZlZCk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogUmVzb2x2ZXMgdGhlIHZhbHVlIGZvciBgcmVmZXJlbmNlYCBpbiB0aGUgY29udGV4dCBvZiBgY29uc3VtZXJgLlxuICovXG5mdW5jdGlvbiByZXNvbHZlVmFsdWUoY29uc3VtZXI6IFN0YWNrLCByZWZlcmVuY2U6IENmblJlZmVyZW5jZSk6IElSZXNvbHZhYmxlIHtcbiAgY29uc3QgcHJvZHVjZXIgPSBTdGFjay5vZihyZWZlcmVuY2UudGFyZ2V0KTtcblxuICAvLyBwcm9kdWNlIGFuZCBjb25zdW1lciBzdGFja3MgYXJlIHRoZSBzYW1lLCB3ZSBjYW4ganVzdCByZXR1cm4gdGhlIHZhbHVlIGl0c2VsZi5cbiAgaWYgKHByb2R1Y2VyID09PSBjb25zdW1lcikge1xuICAgIHJldHVybiByZWZlcmVuY2U7XG4gIH1cblxuICAvLyB1bnN1cHBvcnRlZDogc3RhY2tzIGZyb20gZGlmZmVyZW50IGFwcHNcbiAgaWYgKHByb2R1Y2VyLm5vZGUucm9vdCAhPT0gY29uc3VtZXIubm9kZS5yb290KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdDYW5ub3QgcmVmZXJlbmNlIGFjcm9zcyBhcHBzLiBDb25zdW1pbmcgYW5kIHByb2R1Y2luZyBzdGFja3MgbXVzdCBiZSBkZWZpbmVkIHdpdGhpbiB0aGUgc2FtZSBDREsgYXBwLicpO1xuICB9XG5cbiAgLy8gdW5zdXBwb3J0ZWQ6IHN0YWNrcyBhcmUgbm90IGluIHRoZSBzYW1lIGVudmlyb25tZW50XG4gIGlmIChwcm9kdWNlci5lbnZpcm9ubWVudCAhPT0gY29uc3VtZXIuZW52aXJvbm1lbnQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICBgU3RhY2sgXCIke2NvbnN1bWVyLm5vZGUucGF0aH1cIiBjYW5ub3QgY29uc3VtZSBhIGNyb3NzIHJlZmVyZW5jZSBmcm9tIHN0YWNrIFwiJHtwcm9kdWNlci5ub2RlLnBhdGh9XCIuIGAgK1xuICAgICAgJ0Nyb3NzIHN0YWNrIHJlZmVyZW5jZXMgYXJlIG9ubHkgc3VwcG9ydGVkIGZvciBzdGFja3MgZGVwbG95ZWQgdG8gdGhlIHNhbWUgZW52aXJvbm1lbnQgb3IgYmV0d2VlbiBuZXN0ZWQgc3RhY2tzIGFuZCB0aGVpciBwYXJlbnQgc3RhY2snKTtcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gY29uc3VtZXIgaXMgbmVzdGVkIGluIHRoZSBwcm9kdWNlciAoZGlyZWN0bHkgb3IgaW5kaXJlY3RseSlcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIGlmIHRoZSBjb25zdW1lciBpcyBuZXN0ZWQgd2l0aGluIHRoZSBwcm9kdWNlciAoZGlyZWN0bHkgb3IgaW5kaXJlY3RseSksXG4gIC8vIHdpcmUgdGhyb3VnaCBhIENsb3VkRm9ybWF0aW9uIHBhcmFtZXRlciBhbmQgdGhlbiByZXNvbHZlIHRoZSByZWZlcmVuY2Ugd2l0aFxuICAvLyB0aGUgcGFyZW50IHN0YWNrIGFzIHRoZSBjb25zdW1lci5cbiAgaWYgKGNvbnN1bWVyLm5lc3RlZFN0YWNrUGFyZW50ICYmIGlzTmVzdGVkKGNvbnN1bWVyLCBwcm9kdWNlcikpIHtcbiAgICBjb25zdCBwYXJhbWV0ZXJWYWx1ZSA9IHJlc29sdmVWYWx1ZShjb25zdW1lci5uZXN0ZWRTdGFja1BhcmVudCwgcmVmZXJlbmNlKTtcbiAgICByZXR1cm4gY3JlYXRlTmVzdGVkU3RhY2tQYXJhbWV0ZXIoY29uc3VtZXIsIHJlZmVyZW5jZSwgcGFyYW1ldGVyVmFsdWUpO1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvLyBwcm9kdWNlciBpcyBhIG5lc3RlZCBzdGFja1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gaWYgdGhlIHByb2R1Y2VyIGlzIG5lc3RlZCwgYWx3YXlzIHB1Ymxpc2ggdGhlIHZhbHVlIHRocm91Z2ggYVxuICAvLyBjbG91ZGZvcm1hdGlvbiBvdXRwdXQgYW5kIHJlc29sdmUgcmVjdXJzaXZlbHkgd2l0aCB0aGUgRm46OkdldEF0dFxuICAvLyBvZiB0aGUgb3V0cHV0IGluIHRoZSBwYXJlbnQgc3RhY2suXG5cbiAgLy8gb25lIG1pZ2h0IGFzaywgaWYgdGhlIGNvbnN1bWVyIGlzIG5vdCBhIHBhcmVudCBvZiB0aGUgcHJvZHVjZXIsXG4gIC8vIHdoeSBub3QganVzdCB1c2UgZXhwb3J0L2ltcG9ydD8gdGhlIHJlYXNvbiBpcyB0aGF0IHdlIGNhbm5vdFxuICAvLyBnZW5lcmF0ZSBhbiBcImV4cG9ydCBuYW1lXCIgZnJvbSBhIG5lc3RlZCBzdGFjayBiZWNhdXNlIHRoZSBleHBvcnRcbiAgLy8gbmFtZSBtdXN0IGNvbnRhaW4gdGhlIHN0YWNrIG5hbWUgdG8gZW5zdXJlIHVuaXF1ZW5lc3MsIGFuZCB3ZVxuICAvLyBkb24ndCBrbm93IHRoZSBzdGFjayBuYW1lIG9mIGEgbmVzdGVkIHN0YWNrIGJlZm9yZSB3ZSBkZXBsb3kgaXQuXG4gIC8vIHRoZXJlZm9yZSwgd2UgY2FuIG9ubHkgZXhwb3J0IGZyb20gYSB0b3AtbGV2ZWwgc3RhY2suXG4gIGlmIChwcm9kdWNlci5uZXN0ZWQpIHtcbiAgICBjb25zdCBvdXRwdXRWYWx1ZSA9IGNyZWF0ZU5lc3RlZFN0YWNrT3V0cHV0KHByb2R1Y2VyLCByZWZlcmVuY2UpO1xuICAgIHJldHVybiByZXNvbHZlVmFsdWUoY29uc3VtZXIsIG91dHB1dFZhbHVlKTtcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gZXhwb3J0L2ltcG9ydFxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gZXhwb3J0IHRoZSB2YWx1ZSB0aHJvdWdoIGEgY2xvdWRmb3JtYXRpb24gXCJleHBvcnQgbmFtZVwiIGFuZCB1c2UgYW5cbiAgLy8gRm46OkltcG9ydFZhbHVlIGluIHRoZSBjb25zdW1wdGlvbiBzaXRlLlxuXG4gIC8vIGFkZCBhIGRlcGVuZGVuY3kgYmV0d2VlbiB0aGUgcHJvZHVjZXIgYW5kIHRoZSBjb25zdW1lci4gZGVwZW5kZW5jeSBsb2dpY1xuICAvLyB3aWxsIHRha2UgY2FyZSBvZiBhcHBseWluZyB0aGUgZGVwZW5kZW5jeSBhdCB0aGUgcmlnaHQgbGV2ZWwgKGUuZy4gdGhlXG4gIC8vIHRvcC1sZXZlbCBzdGFja3MpLlxuICBjb25zdW1lci5hZGREZXBlbmRlbmN5KHByb2R1Y2VyLFxuICAgIGAke2NvbnN1bWVyLm5vZGUucGF0aH0gLT4gJHtyZWZlcmVuY2UudGFyZ2V0Lm5vZGUucGF0aH0uJHtyZWZlcmVuY2UuZGlzcGxheU5hbWV9YCk7XG5cbiAgcmV0dXJuIGNyZWF0ZUltcG9ydFZhbHVlKHJlZmVyZW5jZSk7XG59XG5cbi8qKlxuICogRmluZHMgYWxsIHRoZSBDbG91ZEZvcm1hdGlvbiByZWZlcmVuY2VzIGluIGEgY29uc3RydWN0IHRyZWUuXG4gKi9cbmZ1bmN0aW9uIGZpbmRBbGxSZWZlcmVuY2VzKHJvb3Q6IENvbnN0cnVjdCkge1xuICBjb25zdCByZXN1bHQgPSBuZXcgQXJyYXk8eyBzb3VyY2U6IENmbkVsZW1lbnQsIHZhbHVlOiBDZm5SZWZlcmVuY2UgfT4oKTtcbiAgZm9yIChjb25zdCBjb25zdW1lciBvZiByb290Lm5vZGUuZmluZEFsbCgpKSB7XG5cbiAgICAvLyBpbmNsdWRlIG9ubHkgQ2ZuRWxlbWVudHMgKGkuZS4gcmVzb3VyY2VzKVxuICAgIGlmICghQ2ZuRWxlbWVudC5pc0NmbkVsZW1lbnQoY29uc3VtZXIpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgdG9rZW5zID0gZmluZFRva2Vucyhjb25zdW1lciwgKCkgPT4gY29uc3VtZXIuX3RvQ2xvdWRGb3JtYXRpb24oKSk7XG5cbiAgICAgIC8vIGl0ZXJhdGUgb3ZlciBhbGwgdGhlIHRva2VucyAoZS5nLiBpbnRyaW5zaWMgZnVuY3Rpb25zLCBsYXppZXMsIGV0YykgdGhhdFxuICAgICAgLy8gd2VyZSBmb3VuZCBpbiB0aGUgY2xvdWRmb3JtYXRpb24gcmVwcmVzZW50YXRpb24gb2YgdGhpcyByZXNvdXJjZS5cbiAgICAgIGZvciAoY29uc3QgdG9rZW4gb2YgdG9rZW5zKSB7XG5cbiAgICAgICAgLy8gaW5jbHVkZSBvbmx5IENmblJlZmVyZW5jZXMgKGkuZS4gXCJSZWZcIiBhbmQgXCJGbjo6R2V0QXR0XCIpXG4gICAgICAgIGlmICghQ2ZuUmVmZXJlbmNlLmlzQ2ZuUmVmZXJlbmNlKHRva2VuKSkge1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmVzdWx0LnB1c2goe1xuICAgICAgICAgIHNvdXJjZTogY29uc3VtZXIsXG4gICAgICAgICAgdmFsdWU6IHRva2VuLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9ICBjYXRjaCAoZSkge1xuICAgICAgLy8gTm90ZTogaXQgbWlnaHQgYmUgdGhhdCB0aGUgcHJvcGVydGllcyBvZiB0aGUgQ0ZOIG9iamVjdCBhcmVuJ3QgdmFsaWQuXG4gICAgICAvLyBUaGlzIHdpbGwgdXN1YWxseSBiZSBwcmV2ZW50YXRpdmVseSBjYXVnaHQgaW4gYSBjb25zdHJ1Y3QncyB2YWxpZGF0ZSgpXG4gICAgICAvLyBhbmQgdHVybmVkIGludG8gYSBuaWNlbHkgZGVzY3JpcHRpdmUgZXJyb3IsIGJ1dCB3ZSdyZSBydW5uaW5nIHByZXBhcmUoKVxuICAgICAgLy8gYmVmb3JlIHZhbGlkYXRlKCkuIFN3YWxsb3cgZXJyb3JzIHRoYXQgb2NjdXIgYmVjYXVzZSB0aGUgQ0ZOIGxheWVyXG4gICAgICAvLyBkb2Vzbid0IHZhbGlkYXRlIGNvbXBsZXRlbHkuXG4gICAgICAvL1xuICAgICAgLy8gVGhpcyBkb2VzIG1ha2UgdGhlIGFzc3VtcHRpb24gdGhhdCB0aGUgZXJyb3Igd2lsbCBub3QgYmUgcmVjdGlmaWVkLFxuICAgICAgLy8gYnV0IHRoZSBlcnJvciB3aWxsIGJlIHRocm93biBsYXRlciBvbiBhbnl3YXkuIElmIHRoZSBlcnJvciBkb2Vzbid0XG4gICAgICAvLyBnZXQgdGhyb3duIGRvd24gdGhlIGxpbmUsIHdlIG1heSBtaXNzIHJlZmVyZW5jZXMuXG4gICAgICBpZiAoZS50eXBlID09PSAnQ2ZuU3ludGhlc2lzRXJyb3InKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gZXhwb3J0L2ltcG9ydFxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKlxuICogSW1wb3J0cyBhIHZhbHVlIGZyb20gYW5vdGhlciBzdGFjayBieSBjcmVhdGluZyBhbiBcIk91dHB1dFwiIHdpdGggYW4gXCJFeHBvcnROYW1lXCJcbiAqIGFuZCByZXR1cm5pbmcgYW4gXCJGbjo6SW1wb3J0VmFsdWVcIiB0b2tlbi5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlSW1wb3J0VmFsdWUocmVmZXJlbmNlOiBSZWZlcmVuY2UpOiBJbnRyaW5zaWMge1xuICBjb25zdCBleHBvcnRpbmdTdGFjayA9IFN0YWNrLm9mKHJlZmVyZW5jZS50YXJnZXQpO1xuXG4gIC8vIEVuc3VyZSBhIHNpbmdsZXRvbiBcIkV4cG9ydHNcIiBzY29waW5nIENvbnN0cnVjdFxuICAvLyBUaGlzIG1vc3RseSBleGlzdHMgdG8gdHJpZ2dlciBMb2dpY2FsSUQgbXVuZ2luZywgd2hpY2ggd291bGQgYmVcbiAgLy8gZGlzYWJsZWQgaWYgd2UgcGFyZW50ZWQgY29uc3RydWN0cyBkaXJlY3RseSB1bmRlciBTdGFjay5cbiAgLy8gQWxzbyBpdCBuaWNlbHkgcHJldmVudHMgbGlrZWx5IGNvbnN0cnVjdCBuYW1lIGNsYXNoZXNcbiAgY29uc3QgZXhwb3J0c1Njb3BlID0gZ2V0Q3JlYXRlRXhwb3J0c1Njb3BlKGV4cG9ydGluZ1N0YWNrKTtcblxuICAvLyBFbnN1cmUgYSBzaW5nbGV0b24gQ2ZuT3V0cHV0IGZvciB0aGlzIHZhbHVlXG4gIGNvbnN0IHJlc29sdmVkID0gZXhwb3J0aW5nU3RhY2sucmVzb2x2ZShyZWZlcmVuY2UpO1xuICBjb25zdCBpZCA9ICdPdXRwdXQnICsgSlNPTi5zdHJpbmdpZnkocmVzb2x2ZWQpO1xuICBjb25zdCBleHBvcnROYW1lID0gZ2VuZXJhdGVFeHBvcnROYW1lKGV4cG9ydHNTY29wZSwgaWQpO1xuXG4gIGlmIChUb2tlbi5pc1VucmVzb2x2ZWQoZXhwb3J0TmFtZSkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYHVucmVzb2x2ZWQgdG9rZW4gaW4gZ2VuZXJhdGVkIGV4cG9ydCBuYW1lOiAke0pTT04uc3RyaW5naWZ5KGV4cG9ydGluZ1N0YWNrLnJlc29sdmUoZXhwb3J0TmFtZSkpfWApO1xuICB9XG5cbiAgY29uc3Qgb3V0cHV0ID0gZXhwb3J0c1Njb3BlLm5vZGUudHJ5RmluZENoaWxkKGlkKSBhcyBDZm5PdXRwdXQ7XG4gIGlmICghb3V0cHV0KSB7XG4gICAgbmV3IENmbk91dHB1dChleHBvcnRzU2NvcGUsIGlkLCB7IHZhbHVlOiBUb2tlbi5hc1N0cmluZyhyZWZlcmVuY2UpLCBleHBvcnROYW1lIH0pO1xuICB9XG5cbiAgLy8gV2Ugd2FudCB0byByZXR1cm4gYW4gYWN0dWFsIEZuSW1wb3J0VmFsdWUgVG9rZW4gaGVyZSwgYnV0IEZuLmltcG9ydFZhbHVlKCkgcmV0dXJucyBhICdzdHJpbmcnLFxuICAvLyBzbyBjb25zdHJ1Y3Qgb25lIGluLXBsYWNlLlxuICByZXR1cm4gbmV3IEludHJpbnNpYyh7ICdGbjo6SW1wb3J0VmFsdWUnOiBleHBvcnROYW1lIH0pO1xufVxuXG5mdW5jdGlvbiBnZXRDcmVhdGVFeHBvcnRzU2NvcGUoc3RhY2s6IFN0YWNrKSB7XG4gIGNvbnN0IGV4cG9ydHNOYW1lID0gJ0V4cG9ydHMnO1xuICBsZXQgc3RhY2tFeHBvcnRzID0gc3RhY2subm9kZS50cnlGaW5kQ2hpbGQoZXhwb3J0c05hbWUpIGFzIENvbnN0cnVjdDtcbiAgaWYgKHN0YWNrRXhwb3J0cyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgc3RhY2tFeHBvcnRzID0gbmV3IENvbnN0cnVjdChzdGFjaywgZXhwb3J0c05hbWUpO1xuICB9XG5cbiAgcmV0dXJuIHN0YWNrRXhwb3J0cztcbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVFeHBvcnROYW1lKHN0YWNrRXhwb3J0czogQ29uc3RydWN0LCBpZDogc3RyaW5nKSB7XG4gIGNvbnN0IHN0YWNrID0gU3RhY2sub2Yoc3RhY2tFeHBvcnRzKTtcbiAgY29uc3QgY29tcG9uZW50cyA9IFsuLi5zdGFja0V4cG9ydHMubm9kZS5zY29wZXMuc2xpY2UoMikubWFwKGMgPT4gYy5ub2RlLmlkKSwgaWRdO1xuICBjb25zdCBwcmVmaXggPSBzdGFjay5zdGFja05hbWUgPyBzdGFjay5zdGFja05hbWUgKyAnOicgOiAnJztcbiAgY29uc3QgZXhwb3J0TmFtZSA9IHByZWZpeCArIG1ha2VVbmlxdWVJZChjb21wb25lbnRzKTtcbiAgcmV0dXJuIGV4cG9ydE5hbWU7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gbmVzdGVkIHN0YWNrc1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8qKlxuICogQWRkcyBhIENsb3VkRm9ybWF0aW9uIHBhcmFtZXRlciB0byBhIG5lc3RlZCBzdGFjayBhbmQgYXNzaWducyBpdCB3aXRoIHRoZVxuICogdmFsdWUgb2YgdGhlIHJlZmVyZW5jZS5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlTmVzdGVkU3RhY2tQYXJhbWV0ZXIobmVzdGVkOiBTdGFjaywgcmVmZXJlbmNlOiBDZm5SZWZlcmVuY2UsIHZhbHVlOiBJUmVzb2x2YWJsZSkge1xuICAvLyB3ZSBjYWxsIFwidGhpcy5yZXNvbHZlXCIgdG8gZW5zdXJlIHRoYXQgdG9rZW5zIGRvIG5vdCBjcmVlcCBpbiAoZm9yIGV4YW1wbGUsIGlmIHRoZSByZWZlcmVuY2UgZGlzcGxheSBuYW1lIGluY2x1ZGVzIHRva2VucylcbiAgY29uc3QgcGFyYW1JZCA9IG5lc3RlZC5yZXNvbHZlKGByZWZlcmVuY2UtdG8tJHtyZWZlcmVuY2UudGFyZ2V0Lm5vZGUudW5pcXVlSWR9LiR7cmVmZXJlbmNlLmRpc3BsYXlOYW1lfWApO1xuICBsZXQgcGFyYW0gPSBuZXN0ZWQubm9kZS50cnlGaW5kQ2hpbGQocGFyYW1JZCkgYXMgQ2ZuUGFyYW1ldGVyO1xuICBpZiAoIXBhcmFtKSB7XG4gICAgcGFyYW0gPSBuZXcgQ2ZuUGFyYW1ldGVyKG5lc3RlZCwgcGFyYW1JZCwgeyB0eXBlOiAnU3RyaW5nJyB9KTtcblxuICAgIC8vIFVnbHkgbGl0dGxlIGhhY2sgdW50aWwgd2UgbW92ZSBOZXN0ZWRTdGFjayB0byB0aGlzIG1vZHVsZS5cbiAgICBpZiAoISgnc2V0UGFyYW1ldGVyJyBpbiBuZXN0ZWQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2Fzc2VydGlvbiBmYWlsZWQ6IG5lc3RlZCBzdGFjayBzaG91bGQgaGF2ZSBhIFwic2V0UGFyYW1ldGVyXCIgbWV0aG9kJyk7XG4gICAgfVxuXG4gICAgKG5lc3RlZCBhcyBhbnkpLnNldFBhcmFtZXRlcihwYXJhbS5sb2dpY2FsSWQsIFRva2VuLmFzU3RyaW5nKHZhbHVlKSk7XG4gIH1cblxuICByZXR1cm4gcGFyYW0udmFsdWUgYXMgQ2ZuUmVmZXJlbmNlO1xufVxuXG4vKipcbiAqIEFkZHMgYSBDbG91ZEZvcm1hdGlvbiBvdXRwdXQgdG8gYSBuZXN0ZWQgc3RhY2sgYW5kIHJldHVybnMgYW4gXCJGbjo6R2V0QXR0XCJcbiAqIGludHJpbnNpYyB0aGF0IGNhbiBiZSB1c2VkIHRvIHJlZmVyZW5jZSB0aGlzIG91dHB1dCBpbiB0aGUgcGFyZW50IHN0YWNrLlxuICovXG5mdW5jdGlvbiBjcmVhdGVOZXN0ZWRTdGFja091dHB1dChwcm9kdWNlcjogU3RhY2ssIHJlZmVyZW5jZTogUmVmZXJlbmNlKTogQ2ZuUmVmZXJlbmNlIHtcbiAgY29uc3Qgb3V0cHV0SWQgPSBgJHtyZWZlcmVuY2UudGFyZ2V0Lm5vZGUudW5pcXVlSWR9JHtyZWZlcmVuY2UuZGlzcGxheU5hbWV9YDtcbiAgbGV0IG91dHB1dCA9IHByb2R1Y2VyLm5vZGUudHJ5RmluZENoaWxkKG91dHB1dElkKSBhcyBDZm5PdXRwdXQ7XG4gIGlmICghb3V0cHV0KSB7XG4gICAgb3V0cHV0ID0gbmV3IENmbk91dHB1dChwcm9kdWNlciwgb3V0cHV0SWQsIHsgdmFsdWU6IFRva2VuLmFzU3RyaW5nKHJlZmVyZW5jZSkgfSk7XG4gIH1cblxuICBpZiAoIXByb2R1Y2VyLm5lc3RlZFN0YWNrUmVzb3VyY2UpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ2Fzc2VydGlvbiBmYWlsZWQnKTtcbiAgfVxuXG4gIHJldHVybiBwcm9kdWNlci5uZXN0ZWRTdGFja1Jlc291cmNlLmdldEF0dChgT3V0cHV0cy4ke291dHB1dC5sb2dpY2FsSWR9YCkgYXMgQ2ZuUmVmZXJlbmNlO1xufVxuXG4vKipcbiAqIEByZXR1cm5zIHRydWUgaWYgdGhpcyBzdGFjayBpcyBhIGRpcmVjdCBvciBpbmRpcmVjdCBwYXJlbnQgb2YgdGhlIG5lc3RlZFxuICogc3RhY2sgYG5lc3RlZGAuXG4gKlxuICogSWYgYGNoaWxkYCBpcyBub3QgYSBuZXN0ZWQgc3RhY2ssIGFsd2F5cyByZXR1cm5zIGBmYWxzZWAgYmVjYXVzZSBpdCBjYW4ndFxuICogaGF2ZSBhIHBhcmVudCwgZGFoLlxuICovXG5mdW5jdGlvbiBpc05lc3RlZChuZXN0ZWQ6IFN0YWNrLCBwYXJlbnQ6IFN0YWNrKTogYm9vbGVhbiB7XG4gIC8vIGlmIHRoZSBwYXJlbnQgaXMgYSBkaXJlY3QgcGFyZW50XG4gIGlmIChuZXN0ZWQubmVzdGVkU3RhY2tQYXJlbnQgPT09IHBhcmVudCkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLy8gd2UgcmVhY2hlZCBhIHRvcC1sZXZlbCAobm9uLW5lc3RlZCkgc3RhY2sgd2l0aG91dCBmaW5kaW5nIHRoZSBwYXJlbnRcbiAgaWYgKCFuZXN0ZWQubmVzdGVkU3RhY2tQYXJlbnQpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyByZWN1cnNlIHdpdGggdGhlIGNoaWxkJ3MgZGlyZWN0IHBhcmVudFxuICByZXR1cm4gaXNOZXN0ZWQobmVzdGVkLm5lc3RlZFN0YWNrUGFyZW50LCBwYXJlbnQpO1xufVxuIl19