UNPKG

@aws-cdk/core

Version:

AWS Cloud Development Kit Core Library

238 lines 34.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolveReferences = void 0; // ---------------------------------------------------- // CROSS REFERENCES // ---------------------------------------------------- const cxapi = require("@aws-cdk/cx-api"); 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 feature_flags_1 = require("../feature-flags"); 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 stackRelativeExports = feature_flags_1.FeatureFlags.of(stackExports).isEnabled(cxapi.STACK_RELATIVE_EXPORTS_CONTEXT); const stack = stack_1.Stack.of(stackExports); const components = [ ...stackExports.node.scopes .slice(stackRelativeExports ? stack.node.scopes.length : 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVmcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJlZnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsdURBQXVEO0FBQ3ZELG1CQUFtQjtBQUNuQix1REFBdUQ7QUFDdkQseUNBQXlDO0FBRXpDLGdEQUE0QztBQUM1Qyw4Q0FBMEM7QUFDMUMsb0RBQWdEO0FBQ2hELDBEQUE0RDtBQUM1RCxvREFBZ0Q7QUFHaEQsb0NBQWlDO0FBQ2pDLG9DQUFpQztBQUNqQyxtREFBK0M7QUFDL0MsMkNBQXdDO0FBQ3hDLHVDQUF1QztBQUN2Qyx5Q0FBMEM7QUFFMUM7OztHQUdHO0FBQ0gsU0FBZ0IsaUJBQWlCLENBQUMsS0FBaUI7SUFDakQsTUFBTSxLQUFLLEdBQUcsaUJBQWlCLENBQUMsS0FBSyxDQUFDLENBQUM7SUFFdkMsS0FBSyxNQUFNLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxJQUFJLEtBQUssRUFBRTtRQUNyQyxNQUFNLFFBQVEsR0FBRyxhQUFLLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBRWxDLG1EQUFtRDtRQUNuRCxJQUFJLENBQUMsS0FBSyxDQUFDLGdCQUFnQixDQUFDLFFBQVEsQ0FBQyxFQUFFO1lBQ3JDLE1BQU0sUUFBUSxHQUFHLFlBQVksQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLENBQUM7WUFDL0MsS0FBSyxDQUFDLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxRQUFRLENBQUMsQ0FBQztTQUMvQztLQUNGO0FBQ0gsQ0FBQztBQVpELDhDQVlDO0FBRUQ7O0dBRUc7QUFDSCxTQUFTLFlBQVksQ0FBQyxRQUFlLEVBQUUsU0FBdUI7SUFDNUQsTUFBTSxRQUFRLEdBQUcsYUFBSyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7SUFFNUMsaUZBQWlGO0lBQ2pGLElBQUksUUFBUSxLQUFLLFFBQVEsRUFBRTtRQUN6QixPQUFPLFNBQVMsQ0FBQztLQUNsQjtJQUVELDBDQUEwQztJQUMxQyxJ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SUFBSSxDQUFDLFFBQVEsR0FBRyxTQUFTLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDN0UsSUFBSSxNQUFNLEdBQUcsUUFBUSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFjLENBQUM7SUFDL0QsSUFBSSxDQUFDLE1BQU0sRUFBRTtRQUNYLE1BQU0sR0FBRyxJQUFJLHNCQUFTLENBQUMsUUFBUSxFQUFFLFFBQVEsRUFBRSxFQUFFLEtBQUssRUFBRSxhQUFLLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUMsQ0FBQztLQUNsRjtJQUVELElBQUksQ0FBQyxRQUFRLENBQUMsbUJBQW1CLEVBQUU7UUFDakMsTUFBTSxJQUFJLEtBQUssQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO0tBQ3JDO0lBRUQsT0FBTyxRQUFRLENBQUMsbUJBQW1CLENBQUMsTUFBTSxDQUFDLFdBQVcsTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFpQixDQUFDO0FBQzVGLENBQUM7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFTLFFBQVEsQ0FBQyxNQUFhLEVBQUUsTUFBYTtJQUM1QyxtQ0FBbUM7SUFDbkMsSUFBSSxNQUFNLENBQUMsaUJBQWlCLEtBQUssTUFBTSxFQUFFO1FBQ3ZDLE9BQU8sSUFBSSxDQUFDO0tBQ2I7SUFFRCx1RUFBdUU7SUFDdkUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsRUFBRTtRQUM3QixPQUFPLEtBQUssQ0FBQztLQUNkO0lBRUQseUNBQXlDO0lBQ3pDLE9BQU8sUUFBUSxDQUFDLE1BQU0sQ0FBQyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsQ0FBQztBQUNwRCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gQ1JPU1MgUkVGRVJFTkNFU1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuaW1wb3J0ICogYXMgY3hhcGkgZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcblxuaW1wb3J0IHsgQ2ZuRWxlbWVudCB9IGZyb20gJy4uL2Nmbi1lbGVtZW50JztcbmltcG9ydCB7IENmbk91dHB1dCB9IGZyb20gJy4uL2Nmbi1vdXRwdXQnO1xuaW1wb3J0IHsgQ2ZuUGFyYW1ldGVyIH0gZnJvbSAnLi4vY2ZuLXBhcmFtZXRlcic7XG5pbXBvcnQgeyBDb25zdHJ1Y3QsIElDb25zdHJ1Y3QgfSBmcm9tICcuLi9jb25zdHJ1Y3QtY29tcGF0JztcbmltcG9ydCB7IEZlYXR1cmVGbGFncyB9IGZyb20gJy4uL2ZlYXR1cmUtZmxhZ3MnO1xuaW1wb3J0IHsgUmVmZXJlbmNlIH0gZnJvbSAnLi4vcmVmZXJlbmNlJztcbmltcG9ydCB7IElSZXNvbHZhYmxlIH0gZnJvbSAnLi4vcmVzb2x2YWJsZSc7XG5pbXBvcnQgeyBTdGFjayB9IGZyb20gJy4uL3N0YWNrJztcbmltcG9ydCB7IFRva2VuIH0gZnJvbSAnLi4vdG9rZW4nO1xuaW1wb3J0IHsgQ2ZuUmVmZXJlbmNlIH0gZnJvbSAnLi9jZm4tcmVmZXJlbmNlJztcbmltcG9ydCB7IEludHJpbnNpYyB9IGZyb20gJy4vaW50cmluc2ljJztcbmltcG9ydCB7IGZpbmRUb2tlbnMgfSBmcm9tICcuL3Jlc29sdmUnO1xuaW1wb3J0IHsgbWFrZVVuaXF1ZUlkIH0gZnJvbSAnLi91bmlxdWVpZCc7XG5cbi8qKlxuICogVGhpcyBpcyBjYWxsZWQgZnJvbSB0aGUgQXBwIGxldmVsIHRvIHJlc29sdmUgYWxsIHJlZmVyZW5jZXMgZGVmaW5lZC4gRWFjaFxuICogcmVmZXJlbmNlIGlzIHJlc29sdmVkIGJhc2VkIG9uIGl0J3MgY29uc3VtcHRpb24gY29udGV4dC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVSZWZlcmVuY2VzKHNjb3BlOiBJQ29uc3RydWN0KTogdm9pZCB7XG4gIGNvbnN0IGVkZ2VzID0gZmluZEFsbFJlZmVyZW5jZXMoc2NvcGUpO1xuXG4gIGZvciAoY29uc3QgeyBzb3VyY2UsIHZhbHVlIH0gb2YgZWRnZXMpIHtcbiAgICBjb25zdCBjb25zdW1lciA9IFN0YWNrLm9mKHNvdXJjZSk7XG5cbiAgICAvLyByZXNvbHZlIHRoZSB2YWx1ZSBpbiB0aGUgY29udGV4dCBvZiB0aGUgY29uc3VtZXJcbiAgICBpZiAoIXZhbHVlLmhhc1ZhbHVlRm9yU3RhY2soY29uc3VtZXIpKSB7XG4gICAgICBjb25zdCByZXNvbHZlZCA9IHJlc29sdmVWYWx1ZShjb25zdW1lciwgdmFsdWUpO1xuICAgICAgdmFsdWUuYXNzaWduVmFsdWVGb3JTdGFjayhjb25zdW1lciwgcmVzb2x2ZWQpO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFJlc29sdmVzIHRoZSB2YWx1ZSBmb3IgYHJlZmVyZW5jZWAgaW4gdGhlIGNvbnRleHQgb2YgYGNvbnN1bWVyYC5cbiAqL1xuZnVuY3Rpb24gcmVzb2x2ZVZhbHVlKGNvbnN1bWVyOiBTdGFjaywgcmVmZXJlbmNlOiBDZm5SZWZlcmVuY2UpOiBJUmVzb2x2YWJsZSB7XG4gIGNvbnN0IHByb2R1Y2VyID0gU3RhY2sub2YocmVmZXJlbmNlLnRhcmdldCk7XG5cbiAgLy8gcHJvZHVjZSBhbmQgY29uc3VtZXIgc3RhY2tzIGFyZSB0aGUgc2FtZSwgd2UgY2FuIGp1c3QgcmV0dXJuIHRoZSB2YWx1ZSBpdHNlbGYuXG4gIGlmIChwcm9kdWNlciA9PT0gY29uc3VtZXIpIHtcbiAgICByZXR1cm4gcmVmZXJlbmNlO1xuICB9XG5cbiAgLy8gdW5zdXBwb3J0ZWQ6IHN0YWNrcyBmcm9tIGRpZmZlcmVudCBhcHBzXG4gIGlmIChwcm9kdWNlci5ub2RlLnJvb3QgIT09IGNvbnN1bWVyLm5vZGUucm9vdCkge1xuICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IHJlZmVyZW5jZSBhY3Jvc3MgYXBwcy4gQ29uc3VtaW5nIGFuZCBwcm9kdWNpbmcgc3RhY2tzIG11c3QgYmUgZGVmaW5lZCB3aXRoaW4gdGhlIHNhbWUgQ0RLIGFwcC4nKTtcbiAgfVxuXG4gIC8vIHVuc3VwcG9ydGVkOiBzdGFja3MgYXJlIG5vdCBpbiB0aGUgc2FtZSBlbnZpcm9ubWVudFxuICBpZiAocHJvZHVjZXIuZW52aXJvbm1lbnQgIT09IGNvbnN1bWVyLmVudmlyb25tZW50KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYFN0YWNrIFwiJHtjb25zdW1lci5ub2RlLnBhdGh9XCIgY2Fubm90IGNvbnN1bWUgYSBjcm9zcyByZWZlcmVuY2UgZnJvbSBzdGFjayBcIiR7cHJvZHVjZXIubm9kZS5wYXRofVwiLiBgICtcbiAgICAgICdDcm9zcyBzdGFjayByZWZlcmVuY2VzIGFyZSBvbmx5IHN1cHBvcnRlZCBmb3Igc3RhY2tzIGRlcGxveWVkIHRvIHRoZSBzYW1lIGVudmlyb25tZW50IG9yIGJldHdlZW4gbmVzdGVkIHN0YWNrcyBhbmQgdGhlaXIgcGFyZW50IHN0YWNrJyk7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIGNvbnN1bWVyIGlzIG5lc3RlZCBpbiB0aGUgcHJvZHVjZXIgKGRpcmVjdGx5IG9yIGluZGlyZWN0bHkpXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAvLyBpZiB0aGUgY29uc3VtZXIgaXMgbmVzdGVkIHdpdGhpbiB0aGUgcHJvZHVjZXIgKGRpcmVjdGx5IG9yIGluZGlyZWN0bHkpLFxuICAvLyB3aXJlIHRocm91Z2ggYSBDbG91ZEZvcm1hdGlvbiBwYXJhbWV0ZXIgYW5kIHRoZW4gcmVzb2x2ZSB0aGUgcmVmZXJlbmNlIHdpdGhcbiAgLy8gdGhlIHBhcmVudCBzdGFjayBhcyB0aGUgY29uc3VtZXIuXG4gIGlmIChjb25zdW1lci5uZXN0ZWRTdGFja1BhcmVudCAmJiBpc05lc3RlZChjb25zdW1lciwgcHJvZHVjZXIpKSB7XG4gICAgY29uc3QgcGFyYW1ldGVyVmFsdWUgPSByZXNvbHZlVmFsdWUoY29uc3VtZXIubmVzdGVkU3RhY2tQYXJlbnQsIHJlZmVyZW5jZSk7XG4gICAgcmV0dXJuIGNyZWF0ZU5lc3RlZFN0YWNrUGFyYW1ldGVyKGNvbnN1bWVyLCByZWZlcmVuY2UsIHBhcmFtZXRlclZhbHVlKTtcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gcHJvZHVjZXIgaXMgYSBuZXN0ZWQgc3RhY2tcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIGlmIHRoZSBwcm9kdWNlciBpcyBuZXN0ZWQsIGFsd2F5cyBwdWJsaXNoIHRoZSB2YWx1ZSB0aHJvdWdoIGFcbiAgLy8gY2xvdWRmb3JtYXRpb24gb3V0cHV0IGFuZCByZXNvbHZlIHJlY3Vyc2l2ZWx5IHdpdGggdGhlIEZuOjpHZXRBdHRcbiAgLy8gb2YgdGhlIG91dHB1dCBpbiB0aGUgcGFyZW50IHN0YWNrLlxuXG4gIC8vIG9uZSBtaWdodCBhc2ssIGlmIHRoZSBjb25zdW1lciBpcyBub3QgYSBwYXJlbnQgb2YgdGhlIHByb2R1Y2VyLFxuICAvLyB3aHkgbm90IGp1c3QgdXNlIGV4cG9ydC9pbXBvcnQ/IHRoZSByZWFzb24gaXMgdGhhdCB3ZSBjYW5ub3RcbiAgLy8gZ2VuZXJhdGUgYW4gXCJleHBvcnQgbmFtZVwiIGZyb20gYSBuZXN0ZWQgc3RhY2sgYmVjYXVzZSB0aGUgZXhwb3J0XG4gIC8vIG5hbWUgbXVzdCBjb250YWluIHRoZSBzdGFjayBuYW1lIHRvIGVuc3VyZSB1bmlxdWVuZXNzLCBhbmQgd2VcbiAgLy8gZG9uJ3Qga25vdyB0aGUgc3RhY2sgbmFtZSBvZiBhIG5lc3RlZCBzdGFjayBiZWZvcmUgd2UgZGVwbG95IGl0LlxuICAvLyB0aGVyZWZvcmUsIHdlIGNhbiBvbmx5IGV4cG9ydCBmcm9tIGEgdG9wLWxldmVsIHN0YWNrLlxuICBpZiAocHJvZHVjZXIubmVzdGVkKSB7XG4gICAgY29uc3Qgb3V0cHV0VmFsdWUgPSBjcmVhdGVOZXN0ZWRTdGFja091dHB1dChwcm9kdWNlciwgcmVmZXJlbmNlKTtcbiAgICByZXR1cm4gcmVzb2x2ZVZhbHVlKGNvbnN1bWVyLCBvdXRwdXRWYWx1ZSk7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIGV4cG9ydC9pbXBvcnRcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIGV4cG9ydCB0aGUgdmFsdWUgdGhyb3VnaCBhIGNsb3VkZm9ybWF0aW9uIFwiZXhwb3J0IG5hbWVcIiBhbmQgdXNlIGFuXG4gIC8vIEZuOjpJbXBvcnRWYWx1ZSBpbiB0aGUgY29uc3VtcHRpb24gc2l0ZS5cblxuICAvLyBhZGQgYSBkZXBlbmRlbmN5IGJldHdlZW4gdGhlIHByb2R1Y2VyIGFuZCB0aGUgY29uc3VtZXIuIGRlcGVuZGVuY3kgbG9naWNcbiAgLy8gd2lsbCB0YWtlIGNhcmUgb2YgYXBwbHlpbmcgdGhlIGRlcGVuZGVuY3kgYXQgdGhlIHJpZ2h0IGxldmVsIChlLmcuIHRoZVxuICAvLyB0b3AtbGV2ZWwgc3RhY2tzKS5cbiAgY29uc3VtZXIuYWRkRGVwZW5kZW5jeShwcm9kdWNlcixcbiAgICBgJHtjb25zdW1lci5ub2RlLnBhdGh9IC0+ICR7cmVmZXJlbmNlLnRhcmdldC5ub2RlLnBhdGh9LiR7cmVmZXJlbmNlLmRpc3BsYXlOYW1lfWApO1xuXG4gIHJldHVybiBjcmVhdGVJbXBvcnRWYWx1ZShyZWZlcmVuY2UpO1xufVxuXG4vKipcbiAqIEZpbmRzIGFsbCB0aGUgQ2xvdWRGb3JtYXRpb24gcmVmZXJlbmNlcyBpbiBhIGNvbnN0cnVjdCB0cmVlLlxuICovXG5mdW5jdGlvbiBmaW5kQWxsUmVmZXJlbmNlcyhyb290OiBJQ29uc3RydWN0KSB7XG4gIGNvbnN0IHJlc3VsdCA9IG5ldyBBcnJheTx7IHNvdXJjZTogQ2ZuRWxlbWVudCwgdmFsdWU6IENmblJlZmVyZW5jZSB9PigpO1xuICBmb3IgKGNvbnN0IGNvbnN1bWVyIG9mIHJvb3Qubm9kZS5maW5kQWxsKCkpIHtcblxuICAgIC8vIGluY2x1ZGUgb25seSBDZm5FbGVtZW50cyAoaS5lLiByZXNvdXJjZXMpXG4gICAgaWYgKCFDZm5FbGVtZW50LmlzQ2ZuRWxlbWVudChjb25zdW1lcikpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCB0b2tlbnMgPSBmaW5kVG9rZW5zKGNvbnN1bWVyLCAoKSA9PiBjb25zdW1lci5fdG9DbG91ZEZvcm1hdGlvbigpKTtcblxuICAgICAgLy8gaXRlcmF0ZSBvdmVyIGFsbCB0aGUgdG9rZW5zIChlLmcuIGludHJpbnNpYyBmdW5jdGlvbnMsIGxhemllcywgZXRjKSB0aGF0XG4gICAgICAvLyB3ZXJlIGZvdW5kIGluIHRoZSBjbG91ZGZvcm1hdGlvbiByZXByZXNlbnRhdGlvbiBvZiB0aGlzIHJlc291cmNlLlxuICAgICAgZm9yIChjb25zdCB0b2tlbiBvZiB0b2tlbnMpIHtcblxuICAgICAgICAvLyBpbmNsdWRlIG9ubHkgQ2ZuUmVmZXJlbmNlcyAoaS5lLiBcIlJlZlwiIGFuZCBcIkZuOjpHZXRBdHRcIilcbiAgICAgICAgaWYgKCFDZm5SZWZlcmVuY2UuaXNDZm5SZWZlcmVuY2UodG9rZW4pKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICByZXN1bHQucHVzaCh7XG4gICAgICAgICAgc291cmNlOiBjb25zdW1lcixcbiAgICAgICAgICB2YWx1ZTogdG9rZW4sXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIC8vIE5vdGU6IGl0IG1pZ2h0IGJlIHRoYXQgdGhlIHByb3BlcnRpZXMgb2YgdGhlIENGTiBvYmplY3QgYXJlbid0IHZhbGlkLlxuICAgICAgLy8gVGhpcyB3aWxsIHVzdWFsbHkgYmUgcHJldmVudGF0aXZlbHkgY2F1Z2h0IGluIGEgY29uc3RydWN0J3MgdmFsaWRhdGUoKVxuICAgICAgLy8gYW5kIHR1cm5lZCBpbnRvIGEgbmljZWx5IGRlc2NyaXB0aXZlIGVycm9yLCBidXQgd2UncmUgcnVubmluZyBwcmVwYXJlKClcbiAgICAgIC8vIGJlZm9yZSB2YWxpZGF0ZSgpLiBTd2FsbG93IGVycm9ycyB0aGF0IG9jY3VyIGJlY2F1c2UgdGhlIENGTiBsYXllclxuICAgICAgLy8gZG9lc24ndCB2YWxpZGF0ZSBjb21wbGV0ZWx5LlxuICAgICAgLy9cbiAgICAgIC8vIFRoaXMgZG9lcyBtYWtlIHRoZSBhc3N1bXB0aW9uIHRoYXQgdGhlIGVycm9yIHdpbGwgbm90IGJlIHJlY3RpZmllZCxcbiAgICAgIC8vIGJ1dCB0aGUgZXJyb3Igd2lsbCBiZSB0aHJvd24gbGF0ZXIgb24gYW55d2F5LiBJZiB0aGUgZXJyb3IgZG9lc24ndFxuICAgICAgLy8gZ2V0IHRocm93biBkb3duIHRoZSBsaW5lLCB3ZSBtYXkgbWlzcyByZWZlcmVuY2VzLlxuICAgICAgaWYgKGUudHlwZSA9PT0gJ0NmblN5bnRoZXNpc0Vycm9yJykge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIGV4cG9ydC9pbXBvcnRcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vKipcbiAqIEltcG9ydHMgYSB2YWx1ZSBmcm9tIGFub3RoZXIgc3RhY2sgYnkgY3JlYXRpbmcgYW4gXCJPdXRwdXRcIiB3aXRoIGFuIFwiRXhwb3J0TmFtZVwiXG4gKiBhbmQgcmV0dXJuaW5nIGFuIFwiRm46OkltcG9ydFZhbHVlXCIgdG9rZW4uXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUltcG9ydFZhbHVlKHJlZmVyZW5jZTogUmVmZXJlbmNlKTogSW50cmluc2ljIHtcbiAgY29uc3QgZXhwb3J0aW5nU3RhY2sgPSBTdGFjay5vZihyZWZlcmVuY2UudGFyZ2V0KTtcblxuICAvLyBFbnN1cmUgYSBzaW5nbGV0b24gXCJFeHBvcnRzXCIgc2NvcGluZyBDb25zdHJ1Y3RcbiAgLy8gVGhpcyBtb3N0bHkgZXhpc3RzIHRvIHRyaWdnZXIgTG9naWNhbElEIG11bmdpbmcsIHdoaWNoIHdvdWxkIGJlXG4gIC8vIGRpc2FibGVkIGlmIHdlIHBhcmVudGVkIGNvbnN0cnVjdHMgZGlyZWN0bHkgdW5kZXIgU3RhY2suXG4gIC8vIEFsc28gaXQgbmljZWx5IHByZXZlbnRzIGxpa2VseSBjb25zdHJ1Y3QgbmFtZSBjbGFzaGVzXG4gIGNvbnN0IGV4cG9ydHNTY29wZSA9IGdldENyZWF0ZUV4cG9ydHNTY29wZShleHBvcnRpbmdTdGFjayk7XG5cbiAgLy8gRW5zdXJlIGEgc2luZ2xldG9uIENmbk91dHB1dCBmb3IgdGhpcyB2YWx1ZVxuICBjb25zdCByZXNvbHZlZCA9IGV4cG9ydGluZ1N0YWNrLnJlc29sdmUocmVmZXJlbmNlKTtcbiAgY29uc3QgaWQgPSAnT3V0cHV0JyArIEpTT04uc3RyaW5naWZ5KHJlc29sdmVkKTtcbiAgY29uc3QgZXhwb3J0TmFtZSA9IGdlbmVyYXRlRXhwb3J0TmFtZShleHBvcnRzU2NvcGUsIGlkKTtcblxuICBpZiAoVG9rZW4uaXNVbnJlc29sdmVkKGV4cG9ydE5hbWUpKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKGB1bnJlc29sdmVkIHRva2VuIGluIGdlbmVyYXRlZCBleHBvcnQgbmFtZTogJHtKU09OLnN0cmluZ2lmeShleHBvcnRpbmdTdGFjay5yZXNvbHZlKGV4cG9ydE5hbWUpKX1gKTtcbiAgfVxuXG4gIGNvbnN0IG91dHB1dCA9IGV4cG9ydHNTY29wZS5ub2RlLnRyeUZpbmRDaGlsZChpZCkgYXMgQ2ZuT3V0cHV0O1xuICBpZiAoIW91dHB1dCkge1xuICAgIG5ldyBDZm5PdXRwdXQoZXhwb3J0c1Njb3BlLCBpZCwgeyB2YWx1ZTogVG9rZW4uYXNTdHJpbmcocmVmZXJlbmNlKSwgZXhwb3J0TmFtZSB9KTtcbiAgfVxuXG4gIC8vIFdlIHdhbnQgdG8gcmV0dXJuIGFuIGFjdHVhbCBGbkltcG9ydFZhbHVlIFRva2VuIGhlcmUsIGJ1dCBGbi5pbXBvcnRWYWx1ZSgpIHJldHVybnMgYSAnc3RyaW5nJyxcbiAgLy8gc28gY29uc3RydWN0IG9uZSBpbi1wbGFjZS5cbiAgcmV0dXJuIG5ldyBJbnRyaW5zaWMoeyAnRm46OkltcG9ydFZhbHVlJzogZXhwb3J0TmFtZSB9KTtcbn1cblxuZnVuY3Rpb24gZ2V0Q3JlYXRlRXhwb3J0c1Njb3BlKHN0YWNrOiBTdGFjaykge1xuICBjb25zdCBleHBvcnRzTmFtZSA9ICdFeHBvcnRzJztcbiAgbGV0IHN0YWNrRXhwb3J0cyA9IHN0YWNrLm5vZGUudHJ5RmluZENoaWxkKGV4cG9ydHNOYW1lKSBhcyBDb25zdHJ1Y3Q7XG4gIGlmIChzdGFja0V4cG9ydHMgPT09IHVuZGVmaW5lZCkge1xuICAgIHN0YWNrRXhwb3J0cyA9IG5ldyBDb25zdHJ1Y3Qoc3RhY2ssIGV4cG9ydHNOYW1lKTtcbiAgfVxuXG4gIHJldHVybiBzdGFja0V4cG9ydHM7XG59XG5cbmZ1bmN0aW9uIGdlbmVyYXRlRXhwb3J0TmFtZShzdGFja0V4cG9ydHM6IENvbnN0cnVjdCwgaWQ6IHN0cmluZykge1xuICBjb25zdCBzdGFja1JlbGF0aXZlRXhwb3J0cyA9IEZlYXR1cmVGbGFncy5vZihzdGFja0V4cG9ydHMpLmlzRW5hYmxlZChjeGFwaS5TVEFDS19SRUxBVElWRV9FWFBPUlRTX0NPTlRFWFQpO1xuICBjb25zdCBzdGFjayA9IFN0YWNrLm9mKHN0YWNrRXhwb3J0cyk7XG5cbiAgY29uc3QgY29tcG9uZW50cyA9IFtcbiAgICAuLi5zdGFja0V4cG9ydHMubm9kZS5zY29wZXNcbiAgICAgIC5zbGljZShzdGFja1JlbGF0aXZlRXhwb3J0cyA/IHN0YWNrLm5vZGUuc2NvcGVzLmxlbmd0aCA6IDIpXG4gICAgICAubWFwKGMgPT4gYy5ub2RlLmlkKSxcbiAgICBpZCxcbiAgXTtcbiAgY29uc3QgcHJlZml4ID0gc3RhY2suc3RhY2tOYW1lID8gc3RhY2suc3RhY2tOYW1lICsgJzonIDogJyc7XG4gIGNvbnN0IGV4cG9ydE5hbWUgPSBwcmVmaXggKyBtYWtlVW5pcXVlSWQoY29tcG9uZW50cyk7XG4gIHJldHVybiBleHBvcnROYW1lO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIG5lc3RlZCBzdGFja3Ncbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vKipcbiAqIEFkZHMgYSBDbG91ZEZvcm1hdGlvbiBwYXJhbWV0ZXIgdG8gYSBuZXN0ZWQgc3RhY2sgYW5kIGFzc2lnbnMgaXQgd2l0aCB0aGVcbiAqIHZhbHVlIG9mIHRoZSByZWZlcmVuY2UuXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZU5lc3RlZFN0YWNrUGFyYW1ldGVyKG5lc3RlZDogU3RhY2ssIHJlZmVyZW5jZTogQ2ZuUmVmZXJlbmNlLCB2YWx1ZTogSVJlc29sdmFibGUpIHtcbiAgLy8gd2UgY2FsbCBcInRoaXMucmVzb2x2ZVwiIHRvIGVuc3VyZSB0aGF0IHRva2VucyBkbyBub3QgY3JlZXAgaW4gKGZvciBleGFtcGxlLCBpZiB0aGUgcmVmZXJlbmNlIGRpc3BsYXkgbmFtZSBpbmNsdWRlcyB0b2tlbnMpXG4gIGNvbnN0IHBhcmFtSWQgPSBuZXN0ZWQucmVzb2x2ZShgcmVmZXJlbmNlLXRvLSR7cmVmZXJlbmNlLnRhcmdldC5ub2RlLnVuaXF1ZUlkfS4ke3JlZmVyZW5jZS5kaXNwbGF5TmFtZX1gKTtcbiAgbGV0IHBhcmFtID0gbmVzdGVkLm5vZGUudHJ5RmluZENoaWxkKHBhcmFtSWQpIGFzIENmblBhcmFtZXRlcjtcbiAgaWYgKCFwYXJhbSkge1xuICAgIHBhcmFtID0gbmV3IENmblBhcmFtZXRlcihuZXN0ZWQsIHBhcmFtSWQsIHsgdHlwZTogJ1N0cmluZycgfSk7XG5cbiAgICAvLyBVZ2x5IGxpdHRsZSBoYWNrIHVudGlsIHdlIG1vdmUgTmVzdGVkU3RhY2sgdG8gdGhpcyBtb2R1bGUuXG4gICAgaWYgKCEoJ3NldFBhcmFtZXRlcicgaW4gbmVzdGVkKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdhc3NlcnRpb24gZmFpbGVkOiBuZXN0ZWQgc3RhY2sgc2hvdWxkIGhhdmUgYSBcInNldFBhcmFtZXRlclwiIG1ldGhvZCcpO1xuICAgIH1cblxuICAgIChuZXN0ZWQgYXMgYW55KS5zZXRQYXJhbWV0ZXIocGFyYW0ubG9naWNhbElkLCBUb2tlbi5hc1N0cmluZyh2YWx1ZSkpO1xuICB9XG5cbiAgcmV0dXJuIHBhcmFtLnZhbHVlIGFzIENmblJlZmVyZW5jZTtcbn1cblxuLyoqXG4gKiBBZGRzIGEgQ2xvdWRGb3JtYXRpb24gb3V0cHV0IHRvIGEgbmVzdGVkIHN0YWNrIGFuZCByZXR1cm5zIGFuIFwiRm46OkdldEF0dFwiXG4gKiBpbnRyaW5zaWMgdGhhdCBjYW4gYmUgdXNlZCB0byByZWZlcmVuY2UgdGhpcyBvdXRwdXQgaW4gdGhlIHBhcmVudCBzdGFjay5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlTmVzdGVkU3RhY2tPdXRwdXQocHJvZHVjZXI6IFN0YWNrLCByZWZlcmVuY2U6IFJlZmVyZW5jZSk6IENmblJlZmVyZW5jZSB7XG4gIGNvbnN0IG91dHB1dElkID0gYCR7cmVmZXJlbmNlLnRhcmdldC5ub2RlLnVuaXF1ZUlkfSR7cmVmZXJlbmNlLmRpc3BsYXlOYW1lfWA7XG4gIGxldCBvdXRwdXQgPSBwcm9kdWNlci5ub2RlLnRyeUZpbmRDaGlsZChvdXRwdXRJZCkgYXMgQ2ZuT3V0cHV0O1xuICBpZiAoIW91dHB1dCkge1xuICAgIG91dHB1dCA9IG5ldyBDZm5PdXRwdXQocHJvZHVjZXIsIG91dHB1dElkLCB7IHZhbHVlOiBUb2tlbi5hc1N0cmluZyhyZWZlcmVuY2UpIH0pO1xuICB9XG5cbiAgaWYgKCFwcm9kdWNlci5uZXN0ZWRTdGFja1Jlc291cmNlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdhc3NlcnRpb24gZmFpbGVkJyk7XG4gIH1cblxuICByZXR1cm4gcHJvZHVjZXIubmVzdGVkU3RhY2tSZXNvdXJjZS5nZXRBdHQoYE91dHB1dHMuJHtvdXRwdXQubG9naWNhbElkfWApIGFzIENmblJlZmVyZW5jZTtcbn1cblxuLyoqXG4gKiBAcmV0dXJucyB0cnVlIGlmIHRoaXMgc3RhY2sgaXMgYSBkaXJlY3Qgb3IgaW5kaXJlY3QgcGFyZW50IG9mIHRoZSBuZXN0ZWRcbiAqIHN0YWNrIGBuZXN0ZWRgLlxuICpcbiAqIElmIGBjaGlsZGAgaXMgbm90IGEgbmVzdGVkIHN0YWNrLCBhbHdheXMgcmV0dXJucyBgZmFsc2VgIGJlY2F1c2UgaXQgY2FuJ3RcbiAqIGhhdmUgYSBwYXJlbnQsIGRhaC5cbiAqL1xuZnVuY3Rpb24gaXNOZXN0ZWQobmVzdGVkOiBTdGFjaywgcGFyZW50OiBTdGFjayk6IGJvb2xlYW4ge1xuICAvLyBpZiB0aGUgcGFyZW50IGlzIGEgZGlyZWN0IHBhcmVudFxuICBpZiAobmVzdGVkLm5lc3RlZFN0YWNrUGFyZW50ID09PSBwYXJlbnQpIHtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIC8vIHdlIHJlYWNoZWQgYSB0b3AtbGV2ZWwgKG5vbi1uZXN0ZWQpIHN0YWNrIHdpdGhvdXQgZmluZGluZyB0aGUgcGFyZW50XG4gIGlmICghbmVzdGVkLm5lc3RlZFN0YWNrUGFyZW50KSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gcmVjdXJzZSB3aXRoIHRoZSBjaGlsZCdzIGRpcmVjdCBwYXJlbnRcbiAgcmV0dXJuIGlzTmVzdGVkKG5lc3RlZC5uZXN0ZWRTdGFja1BhcmVudCwgcGFyZW50KTtcbn1cbiJdfQ==