@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
238 lines • 34.3 kB
JavaScript
"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==