@aws-cdk/core
Version:
AWS Cloud Development Kit Core Library
224 lines • 31.4 kB
JavaScript
// ----------------------------------------------------
// CROSS REFERENCES
// ----------------------------------------------------
Object.defineProperty(exports, "__esModule", { value: true });
exports.referenceNestedStackValueInParent = exports.resolveReferences = void 0;
const cfn_element_1 = require("../cfn-element");
const cfn_output_1 = require("../cfn-output");
const cfn_parameter_1 = require("../cfn-parameter");
const names_1 = require("../names");
const stack_1 = require("../stack");
const token_1 = require("../token");
const cfn_reference_1 = require("./cfn-reference");
const resolve_1 = require("./resolve");
/**
* 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);
const importExpr = exportingStack.exportValue(reference);
// I happen to know this returns a Fn.importValue() which implements Intrinsic.
return token_1.Tokenization.reverseCompleteString(importExpr);
}
// ------------------------------------------------------------------------------------------------
// nested stacks
// ------------------------------------------------------------------------------------------------
/**
* Adds a CloudFormation parameter to a nested stack and assigns it with the
* value of the reference.
*/
function createNestedStackParameter(nested, reference, value) {
const paramId = generateUniqueId(nested, reference, 'reference-to-');
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 = generateUniqueId(producer, reference);
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}`);
}
/**
* Translate a Reference into a nested stack into a value in the parent stack
*
* Will create Outputs along the chain of Nested Stacks, and return the final `{ Fn::GetAtt }`.
*/
function referenceNestedStackValueInParent(reference, targetStack) {
let currentStack = stack_1.Stack.of(reference.target);
if (currentStack !== targetStack && !isNested(currentStack, targetStack)) {
throw new Error(`Referenced resource must be in stack '${targetStack.node.path}', got '${reference.target.node.path}'`);
}
while (currentStack !== targetStack) {
reference = createNestedStackOutput(stack_1.Stack.of(reference.target), reference);
currentStack = stack_1.Stack.of(reference.target);
}
return reference;
}
exports.referenceNestedStackValueInParent = referenceNestedStackValueInParent;
/**
* @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);
}
/**
* Generates a unique id for a `Reference`
* @param stack A stack used to resolve tokens
* @param ref The reference
* @param prefix Optional prefix for the id
* @returns A unique id
*/
function generateUniqueId(stack, ref, prefix = '') {
// we call "resolve()" to ensure that tokens do not creep in (for example, if the reference display name includes tokens)
return stack.resolve(`${prefix}${names_1.Names.nodeUniqueId(ref.target.node)}${ref.displayName}`);
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVmcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInJlZnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBLHVEQUF1RDtBQUN2RCxtQkFBbUI7QUFDbkIsdURBQXVEOzs7QUFFdkQsZ0RBQTRDO0FBQzVDLDhDQUEwQztBQUMxQyxvREFBZ0Q7QUFFaEQsb0NBQWlDO0FBR2pDLG9DQUFpQztBQUNqQyxvQ0FBK0M7QUFDL0MsbURBQStDO0FBRS9DLHVDQUF1QztBQUV2Qzs7O0dBR0c7QUFDSCxTQUFnQixpQkFBaUIsQ0FBQyxLQUFpQjtJQUNqRCxNQUFNLEtBQUssR0FBRyxpQkFBaUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztJQUV2QyxLQUFLLE1BQU0sRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFLElBQUksS0FBSyxFQUFFO1FBQ3JDLE1BQU0sUUFBUSxHQUFHLGFBQUssQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFbEMsbURBQW1EO1FBQ25ELElBQUksQ0FBQyxLQUFLLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxDQUFDLEVBQUU7WUFDckMsTUFBTSxRQUFRLEdBQUcsWUFBWSxDQUFDLFFBQVEsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUMvQyxLQUFLLENBQUMsbUJBQW1CLENBQUMsUUFBUSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1NBQy9DO0tBQ0Y7QUFDSCxDQUFDO0FBWkQsOENBWUM7QUFFRDs7R0FFRztBQUNILFNBQVMsWUFBWSxDQUFDLFFBQWUsRUFBRSxTQUF1QjtJQUM1RCxNQUFNLFFBQVEsR0FBRyxhQUFLLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUU1QyxpRkFBaUY7SUFDakYsSUFBSSxRQUFRLEtBQUssUUFBUSxFQUFFO1FBQ3pCLE9BQU8sU0FBUyxDQUFDO0tBQ2xCO0lBRUQsMENBQTBDO0lBQzFDLElBQUksUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLEtBQUssUUFBUSxDQUFDLElBQUksQ0FB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QU8sWUFBWSxLQUFLLFdBQVcsRUFBRTtRQUNuQyxTQUFTLEdBQUcsdUJBQXVCLENBQUMsYUFBSyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFDM0UsWUFBWSxHQUFHLGFBQUssQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0tBQzNDO0lBRUQsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQVpELDhFQVlDO0FBRUQ7Ozs7OztHQU1HO0FBQ0gsU0FBUyxRQUFRLENBQUMsTUFBYSxFQUFFLE1BQWE7SUFDNUMsbUNBQW1DO0lBQ25DLElBQUksTUFBTSxDQUFDLGlCQUFpQixLQUFLLE1BQU0sRUFBRTtRQUN2QyxPQUFPLElBQUksQ0FBQztLQUNiO0lBRUQsdUVBQXVFO0lBQ3ZFLElBQUksQ0FBQyxNQUFNLENBQUMsaUJBQWlCLEVBQUU7UUFDN0IsT0FBTyxLQUFLLENBQUM7S0FDZDtJQUVELHlDQUF5QztJQUN6QyxPQUFPLFFBQVEsQ0FBQyxNQUFNLENBQUMsaUJBQWlCLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFDcEQsQ0FBQztBQUVEOzs7Ozs7R0FNRztBQUNILFNBQVMsZ0JBQWdCLENBQUMsS0FBWSxFQUFFLEdBQWMsRUFBRSxNQUFNLEdBQUcsRUFBRTtJQUNqRSx5SEFBeUg7SUFDekgsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLEdBQUcsTUFBTSxHQUFHLGFBQUssQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLENBQUMsV0FBVyxFQUFFLENBQUMsQ0FBQztBQUM1RixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gQ1JPU1MgUkVGRVJFTkNFU1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5pbXBvcnQgeyBDZm5FbGVtZW50IH0gZnJvbSAnLi4vY2ZuLWVsZW1lbnQnO1xuaW1wb3J0IHsgQ2ZuT3V0cHV0IH0gZnJvbSAnLi4vY2ZuLW91dHB1dCc7XG5pbXBvcnQgeyBDZm5QYXJhbWV0ZXIgfSBmcm9tICcuLi9jZm4tcGFyYW1ldGVyJztcbmltcG9ydCB7IElDb25zdHJ1Y3QgfSBmcm9tICcuLi9jb25zdHJ1Y3QtY29tcGF0JztcbmltcG9ydCB7IE5hbWVzIH0gZnJvbSAnLi4vbmFtZXMnO1xuaW1wb3J0IHsgUmVmZXJlbmNlIH0gZnJvbSAnLi4vcmVmZXJlbmNlJztcbmltcG9ydCB7IElSZXNvbHZhYmxlIH0gZnJvbSAnLi4vcmVzb2x2YWJsZSc7XG5pbXBvcnQgeyBTdGFjayB9IGZyb20gJy4uL3N0YWNrJztcbmltcG9ydCB7IFRva2VuLCBUb2tlbml6YXRpb24gfSBmcm9tICcuLi90b2tlbic7XG5pbXBvcnQgeyBDZm5SZWZlcmVuY2UgfSBmcm9tICcuL2Nmbi1yZWZlcmVuY2UnO1xuaW1wb3J0IHsgSW50cmluc2ljIH0gZnJvbSAnLi9pbnRyaW5zaWMnO1xuaW1wb3J0IHsgZmluZFRva2VucyB9IGZyb20gJy4vcmVzb2x2ZSc7XG5cbi8qKlxuICogVGhpcyBpcyBjYWxsZWQgZnJvbSB0aGUgQXBwIGxldmVsIHRvIHJlc29sdmUgYWxsIHJlZmVyZW5jZXMgZGVmaW5lZC4gRWFjaFxuICogcmVmZXJlbmNlIGlzIHJlc29sdmVkIGJhc2VkIG9uIGl0J3MgY29uc3VtcHRpb24gY29udGV4dC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVSZWZlcmVuY2VzKHNjb3BlOiBJQ29uc3RydWN0KTogdm9pZCB7XG4gIGNvbnN0IGVkZ2VzID0gZmluZEFsbFJlZmVyZW5jZXMoc2NvcGUpO1xuXG4gIGZvciAoY29uc3QgeyBzb3VyY2UsIHZhbHVlIH0gb2YgZWRnZXMpIHtcbiAgICBjb25zdCBjb25zdW1lciA9IFN0YWNrLm9mKHNvdXJjZSk7XG5cbiAgICAvLyByZXNvbHZlIHRoZSB2YWx1ZSBpbiB0aGUgY29udGV4dCBvZiB0aGUgY29uc3VtZXJcbiAgICBpZiAoIXZhbHVlLmhhc1ZhbHVlRm9yU3RhY2soY29uc3VtZXIpKSB7XG4gICAgICBjb25zdCByZXNvbHZlZCA9IHJlc29sdmVWYWx1ZShjb25zdW1lciwgdmFsdWUpO1xuICAgICAgdmFsdWUuYXNzaWduVmFsdWVGb3JTdGFjayhjb25zdW1lciwgcmVzb2x2ZWQpO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFJlc29sdmVzIHRoZSB2YWx1ZSBmb3IgYHJlZmVyZW5jZWAgaW4gdGhlIGNvbnRleHQgb2YgYGNvbnN1bWVyYC5cbiAqL1xuZnVuY3Rpb24gcmVzb2x2ZVZhbHVlKGNvbnN1bWVyOiBTdGFjaywgcmVmZXJlbmNlOiBDZm5SZWZlcmVuY2UpOiBJUmVzb2x2YWJsZSB7XG4gIGNvbnN0IHByb2R1Y2VyID0gU3RhY2sub2YocmVmZXJlbmNlLnRhcmdldCk7XG5cbiAgLy8gcHJvZHVjZSBhbmQgY29uc3VtZXIgc3RhY2tzIGFyZSB0aGUgc2FtZSwgd2UgY2FuIGp1c3QgcmV0dXJuIHRoZSB2YWx1ZSBpdHNlbGYuXG4gIGlmIChwcm9kdWNlciA9PT0gY29uc3VtZXIpIHtcbiAgICByZXR1cm4gcmVmZXJlbmNlO1xuICB9XG5cbiAgLy8gdW5zdXBwb3J0ZWQ6IHN0YWNrcyBmcm9tIGRpZmZlcmVudCBhcHBzXG4gIGlmIChwcm9kdWNlci5ub2RlLnJvb3QgIT09IGNvbnN1bWVyLm5vZGUucm9vdCkge1xuICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IHJlZmVyZW5jZSBhY3Jvc3MgYXBwcy4gQ29uc3VtaW5nIGFuZCBwcm9kdWNpbmcgc3RhY2tzIG11c3QgYmUgZGVmaW5lZCB3aXRoaW4gdGhlIHNhbWUgQ0RLIGFwcC4nKTtcbiAgfVxuXG4gIC8vIHVuc3VwcG9ydGVkOiBzdGFja3MgYXJlIG5vdCBpbiB0aGUgc2FtZSBlbnZpcm9ubWVudFxuICBpZiAocHJvZHVjZXIuZW52aXJvbm1lbnQgIT09IGNvbnN1bWVyLmVudmlyb25tZW50KSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgYFN0YWNrIFwiJHtjb25zdW1lci5ub2RlLnBhdGh9XCIgY2Fubm90IGNvbnN1bWUgYSBjcm9zcyByZWZlcmVuY2UgZnJvbSBzdGFjayBcIiR7cHJvZHVjZXIubm9kZS5wYXRofVwiLiBgICtcbiAgICAgICdDcm9zcyBzdGFjayByZWZlcmVuY2VzIGFyZSBvbmx5IHN1cHBvcnRlZCBmb3Igc3RhY2tzIGRlcGxveWVkIHRvIHRoZSBzYW1lIGVudmlyb25tZW50IG9yIGJldHdlZW4gbmVzdGVkIHN0YWNrcyBhbmQgdGhlaXIgcGFyZW50IHN0YWNrJyk7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIGNvbnN1bWVyIGlzIG5lc3RlZCBpbiB0aGUgcHJvZHVjZXIgKGRpcmVjdGx5IG9yIGluZGlyZWN0bHkpXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAvLyBpZiB0aGUgY29uc3VtZXIgaXMgbmVzdGVkIHdpdGhpbiB0aGUgcHJvZHVjZXIgKGRpcmVjdGx5IG9yIGluZGlyZWN0bHkpLFxuICAvLyB3aXJlIHRocm91Z2ggYSBDbG91ZEZvcm1hdGlvbiBwYXJhbWV0ZXIgYW5kIHRoZW4gcmVzb2x2ZSB0aGUgcmVmZXJlbmNlIHdpdGhcbiAgLy8gdGhlIHBhcmVudCBzdGFjayBhcyB0aGUgY29uc3VtZXIuXG4gIGlmIChjb25zdW1lci5uZXN0ZWRTdGFja1BhcmVudCAmJiBpc05lc3RlZChjb25zdW1lciwgcHJvZHVjZXIpKSB7XG4gICAgY29uc3QgcGFyYW1ldGVyVmFsdWUgPSByZXNvbHZlVmFsdWUoY29uc3VtZXIubmVzdGVkU3RhY2tQYXJlbnQsIHJlZmVyZW5jZSk7XG4gICAgcmV0dXJuIGNyZWF0ZU5lc3RlZFN0YWNrUGFyYW1ldGVyKGNvbnN1bWVyLCByZWZlcmVuY2UsIHBhcmFtZXRlclZhbHVlKTtcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gcHJvZHVjZXIgaXMgYSBuZXN0ZWQgc3RhY2tcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIGlmIHRoZSBwcm9kdWNlciBpcyBuZXN0ZWQsIGFsd2F5cyBwdWJsaXNoIHRoZSB2YWx1ZSB0aHJvdWdoIGFcbiAgLy8gY2xvdWRmb3JtYXRpb24gb3V0cHV0IGFuZCByZXNvbHZlIHJlY3Vyc2l2ZWx5IHdpdGggdGhlIEZuOjpHZXRBdHRcbiAgLy8gb2YgdGhlIG91dHB1dCBpbiB0aGUgcGFyZW50IHN0YWNrLlxuXG4gIC8vIG9uZSBtaWdodCBhc2ssIGlmIHRoZSBjb25zdW1lciBpcyBub3QgYSBwYXJlbnQgb2YgdGhlIHByb2R1Y2VyLFxuICAvLyB3aHkgbm90IGp1c3QgdXNlIGV4cG9ydC9pbXBvcnQ/IHRoZSByZWFzb24gaXMgdGhhdCB3ZSBjYW5ub3RcbiAgLy8gZ2VuZXJhdGUgYW4gXCJleHBvcnQgbmFtZVwiIGZyb20gYSBuZXN0ZWQgc3RhY2sgYmVjYXVzZSB0aGUgZXhwb3J0XG4gIC8vIG5hbWUgbXVzdCBjb250YWluIHRoZSBzdGFjayBuYW1lIHRvIGVuc3VyZSB1bmlxdWVuZXNzLCBhbmQgd2VcbiAgLy8gZG9uJ3Qga25vdyB0aGUgc3RhY2sgbmFtZSBvZiBhIG5lc3RlZCBzdGFjayBiZWZvcmUgd2UgZGVwbG95IGl0LlxuICAvLyB0aGVyZWZvcmUsIHdlIGNhbiBvbmx5IGV4cG9ydCBmcm9tIGEgdG9wLWxldmVsIHN0YWNrLlxuICBpZiAocHJvZHVjZXIubmVzdGVkKSB7XG4gICAgY29uc3Qgb3V0cHV0VmFsdWUgPSBjcmVhdGVOZXN0ZWRTdGFja091dHB1dChwcm9kdWNlciwgcmVmZXJlbmNlKTtcbiAgICByZXR1cm4gcmVzb2x2ZVZhbHVlKGNvbnN1bWVyLCBvdXRwdXRWYWx1ZSk7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIGV4cG9ydC9pbXBvcnRcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIGV4cG9ydCB0aGUgdmFsdWUgdGhyb3VnaCBhIGNsb3VkZm9ybWF0aW9uIFwiZXhwb3J0IG5hbWVcIiBhbmQgdXNlIGFuXG4gIC8vIEZuOjpJbXBvcnRWYWx1ZSBpbiB0aGUgY29uc3VtcHRpb24gc2l0ZS5cblxuICAvLyBhZGQgYSBkZXBlbmRlbmN5IGJldHdlZW4gdGhlIHByb2R1Y2VyIGFuZCB0aGUgY29uc3VtZXIuIGRlcGVuZGVuY3kgbG9naWNcbiAgLy8gd2lsbCB0YWtlIGNhcmUgb2YgYXBwbHlpbmcgdGhlIGRlcGVuZGVuY3kgYXQgdGhlIHJpZ2h0IGxldmVsIChlLmcuIHRoZVxuICAvLyB0b3AtbGV2ZWwgc3RhY2tzKS5cbiAgY29uc3VtZXIuYWRkRGVwZW5kZW5jeShwcm9kdWNlcixcbiAgICBgJHtjb25zdW1lci5ub2RlLnBhdGh9IC0+ICR7cmVmZXJlbmNlLnRhcmdldC5ub2RlLnBhdGh9LiR7cmVmZXJlbmNlLmRpc3BsYXlOYW1lfWApO1xuXG4gIHJldHVybiBjcmVhdGVJbXBvcnRWYWx1ZShyZWZlcmVuY2UpO1xufVxuXG4vKipcbiAqIEZpbmRzIGFsbCB0aGUgQ2xvdWRGb3JtYXRpb24gcmVmZXJlbmNlcyBpbiBhIGNvbnN0cnVjdCB0cmVlLlxuICovXG5mdW5jdGlvbiBmaW5kQWxsUmVmZXJlbmNlcyhyb290OiBJQ29uc3RydWN0KSB7XG4gIGNvbnN0IHJlc3VsdCA9IG5ldyBBcnJheTx7IHNvdXJjZTogQ2ZuRWxlbWVudCwgdmFsdWU6IENmblJlZmVyZW5jZSB9PigpO1xuICBmb3IgKGNvbnN0IGNvbnN1bWVyIG9mIHJvb3Qubm9kZS5maW5kQWxsKCkpIHtcblxuICAgIC8vIGluY2x1ZGUgb25seSBDZm5FbGVtZW50cyAoaS5lLiByZXNvdXJjZXMpXG4gICAgaWYgKCFDZm5FbGVtZW50LmlzQ2ZuRWxlbWVudChjb25zdW1lcikpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIHRyeSB7XG4gICAgICBjb25zdCB0b2tlbnMgPSBmaW5kVG9rZW5zKGNvbnN1bWVyLCAoKSA9PiBjb25zdW1lci5fdG9DbG91ZEZvcm1hdGlvbigpKTtcblxuICAgICAgLy8gaXRlcmF0ZSBvdmVyIGFsbCB0aGUgdG9rZW5zIChlLmcuIGludHJpbnNpYyBmdW5jdGlvbnMsIGxhemllcywgZXRjKSB0aGF0XG4gICAgICAvLyB3ZXJlIGZvdW5kIGluIHRoZSBjbG91ZGZvcm1hdGlvbiByZXByZXNlbnRhdGlvbiBvZiB0aGlzIHJlc291cmNlLlxuICAgICAgZm9yIChjb25zdCB0b2tlbiBvZiB0b2tlbnMpIHtcblxuICAgICAgICAvLyBpbmNsdWRlIG9ubHkgQ2ZuUmVmZXJlbmNlcyAoaS5lLiBcIlJlZlwiIGFuZCBcIkZuOjpHZXRBdHRcIilcbiAgICAgICAgaWYgKCFDZm5SZWZlcmVuY2UuaXNDZm5SZWZlcmVuY2UodG9rZW4pKSB7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICByZXN1bHQucHVzaCh7XG4gICAgICAgICAgc291cmNlOiBjb25zdW1lcixcbiAgICAgICAgICB2YWx1ZTogdG9rZW4sXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIC8vIE5vdGU6IGl0IG1pZ2h0IGJlIHRoYXQgdGhlIHByb3BlcnRpZXMgb2YgdGhlIENGTiBvYmplY3QgYXJlbid0IHZhbGlkLlxuICAgICAgLy8gVGhpcyB3aWxsIHVzdWFsbHkgYmUgcHJldmVudGF0aXZlbHkgY2F1Z2h0IGluIGEgY29uc3RydWN0J3MgdmFsaWRhdGUoKVxuICAgICAgLy8gYW5kIHR1cm5lZCBpbnRvIGEgbmljZWx5IGRlc2NyaXB0aXZlIGVycm9yLCBidXQgd2UncmUgcnVubmluZyBwcmVwYXJlKClcbiAgICAgIC8vIGJlZm9yZSB2YWxpZGF0ZSgpLiBTd2FsbG93IGVycm9ycyB0aGF0IG9jY3VyIGJlY2F1c2UgdGhlIENGTiBsYXllclxuICAgICAgLy8gZG9lc24ndCB2YWxpZGF0ZSBjb21wbGV0ZWx5LlxuICAgICAgLy9cbiAgICAgIC8vIFRoaXMgZG9lcyBtYWtlIHRoZSBhc3N1bXB0aW9uIHRoYXQgdGhlIGVycm9yIHdpbGwgbm90IGJlIHJlY3RpZmllZCxcbiAgICAgIC8vIGJ1dCB0aGUgZXJyb3Igd2lsbCBiZSB0aHJvd24gbGF0ZXIgb24gYW55d2F5LiBJZiB0aGUgZXJyb3IgZG9lc24ndFxuICAgICAgLy8gZ2V0IHRocm93biBkb3duIHRoZSBsaW5lLCB3ZSBtYXkgbWlzcyByZWZlcmVuY2VzLlxuICAgICAgaWYgKGUudHlwZSA9PT0gJ0NmblN5bnRoZXNpc0Vycm9yJykge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIGV4cG9ydC9pbXBvcnRcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vKipcbiAqIEltcG9ydHMgYSB2YWx1ZSBmcm9tIGFub3RoZXIgc3RhY2sgYnkgY3JlYXRpbmcgYW4gXCJPdXRwdXRcIiB3aXRoIGFuIFwiRXhwb3J0TmFtZVwiXG4gKiBhbmQgcmV0dXJuaW5nIGFuIFwiRm46OkltcG9ydFZhbHVlXCIgdG9rZW4uXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUltcG9ydFZhbHVlKHJlZmVyZW5jZTogUmVmZXJlbmNlKTogSW50cmluc2ljIHtcbiAgY29uc3QgZXhwb3J0aW5nU3RhY2sgPSBTdGFjay5vZihyZWZlcmVuY2UudGFyZ2V0KTtcblxuICBjb25zdCBpbXBvcnRFeHByID0gZXhwb3J0aW5nU3RhY2suZXhwb3J0VmFsdWUocmVmZXJlbmNlKTtcblxuICAvLyBJIGhhcHBlbiB0byBrbm93IHRoaXMgcmV0dXJucyBhIEZuLmltcG9ydFZhbHVlKCkgd2hpY2ggaW1wbGVtZW50cyBJbnRyaW5zaWMuXG4gIHJldHVybiBUb2tlbml6YXRpb24ucmV2ZXJzZUNvbXBsZXRlU3RyaW5nKGltcG9ydEV4cHIpIGFzIEludHJpbnNpYztcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBuZXN0ZWQgc3RhY2tzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLyoqXG4gKiBBZGRzIGEgQ2xvdWRGb3JtYXRpb24gcGFyYW1ldGVyIHRvIGEgbmVzdGVkIHN0YWNrIGFuZCBhc3NpZ25zIGl0IHdpdGggdGhlXG4gKiB2YWx1ZSBvZiB0aGUgcmVmZXJlbmNlLlxuICovXG5mdW5jdGlvbiBjcmVhdGVOZXN0ZWRTdGFja1BhcmFtZXRlcihuZXN0ZWQ6IFN0YWNrLCByZWZlcmVuY2U6IENmblJlZmVyZW5jZSwgdmFsdWU6IElSZXNvbHZhYmxlKSB7XG4gIGNvbnN0IHBhcmFtSWQgPSBnZW5lcmF0ZVVuaXF1ZUlkKG5lc3RlZCwgcmVmZXJlbmNlLCAncmVmZXJlbmNlLXRvLScpO1xuICBsZXQgcGFyYW0gPSBuZXN0ZWQubm9kZS50cnlGaW5kQ2hpbGQocGFyYW1JZCkgYXMgQ2ZuUGFyYW1ldGVyO1xuICBpZiAoIXBhcmFtKSB7XG4gICAgcGFyYW0gPSBuZXcgQ2ZuUGFyYW1ldGVyKG5lc3RlZCwgcGFyYW1JZCwgeyB0eXBlOiAnU3RyaW5nJyB9KTtcblxuICAgIC8vIFVnbHkgbGl0dGxlIGhhY2sgdW50aWwgd2UgbW92ZSBOZXN0ZWRTdGFjayB0byB0aGlzIG1vZHVsZS5cbiAgICBpZiAoISgnc2V0UGFyYW1ldGVyJyBpbiBuZXN0ZWQpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2Fzc2VydGlvbiBmYWlsZWQ6IG5lc3RlZCBzdGFjayBzaG91bGQgaGF2ZSBhIFwic2V0UGFyYW1ldGVyXCIgbWV0aG9kJyk7XG4gICAgfVxuXG4gICAgKG5lc3RlZCBhcyBhbnkpLnNldFBhcmFtZXRlcihwYXJhbS5sb2dpY2FsSWQsIFRva2VuLmFzU3RyaW5nKHZhbHVlKSk7XG4gIH1cblxuICByZXR1cm4gcGFyYW0udmFsdWUgYXMgQ2ZuUmVmZXJlbmNlO1xufVxuXG4vKipcbiAqIEFkZHMgYSBDbG91ZEZvcm1hdGlvbiBvdXRwdXQgdG8gYSBuZXN0ZWQgc3RhY2sgYW5kIHJldHVybnMgYW4gXCJGbjo6R2V0QXR0XCJcbiAqIGludHJpbnNpYyB0aGF0IGNhbiBiZSB1c2VkIHRvIHJlZmVyZW5jZSB0aGlzIG91dHB1dCBpbiB0aGUgcGFyZW50IHN0YWNrLlxuICovXG5mdW5jdGlvbiBjcmVhdGVOZXN0ZWRTdGFja091dHB1dChwcm9kdWNlcjogU3RhY2ssIHJlZmVyZW5jZTogUmVmZXJlbmNlKTogQ2ZuUmVmZXJlbmNlIHtcbiAgY29uc3Qgb3V0cHV0SWQgPSBnZW5lcmF0ZVVuaXF1ZUlkKHByb2R1Y2VyLCByZWZlcmVuY2UpO1xuICBsZXQgb3V0cHV0ID0gcHJvZHVjZXIubm9kZS50cnlGaW5kQ2hpbGQob3V0cHV0SWQpIGFzIENmbk91dHB1dDtcbiAgaWYgKCFvdXRwdXQpIHtcbiAgICBvdXRwdXQgPSBuZXcgQ2ZuT3V0cHV0KHByb2R1Y2VyLCBvdXRwdXRJZCwgeyB2YWx1ZTogVG9rZW4uYXNTdHJpbmcocmVmZXJlbmNlKSB9KTtcbiAgfVxuXG4gIGlmICghcHJvZHVjZXIubmVzdGVkU3RhY2tSZXNvdXJjZSkge1xuICAgIHRocm93IG5ldyBFcnJvcignYXNzZXJ0aW9uIGZhaWxlZCcpO1xuICB9XG5cbiAgcmV0dXJuIHByb2R1Y2VyLm5lc3RlZFN0YWNrUmVzb3VyY2UuZ2V0QXR0KGBPdXRwdXRzLiR7b3V0cHV0LmxvZ2ljYWxJZH1gKSBhcyBDZm5SZWZlcmVuY2U7XG59XG5cbi8qKlxuICogVHJhbnNsYXRlIGEgUmVmZXJlbmNlIGludG8gYSBuZXN0ZWQgc3RhY2sgaW50byBhIHZhbHVlIGluIHRoZSBwYXJlbnQgc3RhY2tcbiAqXG4gKiBXaWxsIGNyZWF0ZSBPdXRwdXRzIGFsb25nIHRoZSBjaGFpbiBvZiBOZXN0ZWQgU3RhY2tzLCBhbmQgcmV0dXJuIHRoZSBmaW5hbCBgeyBGbjo6R2V0QXR0IH1gLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVmZXJlbmNlTmVzdGVkU3RhY2tWYWx1ZUluUGFyZW50KHJlZmVyZW5jZTogUmVmZXJlbmNlLCB0YXJnZXRTdGFjazogU3RhY2spIHtcbiAgbGV0IGN1cnJlbnRTdGFjayA9IFN0YWNrLm9mKHJlZmVyZW5jZS50YXJnZXQpO1xuICBpZiAoY3VycmVudFN0YWNrICE9PSB0YXJnZXRTdGFjayAmJiAhaXNOZXN0ZWQoY3VycmVudFN0YWNrLCB0YXJnZXRTdGFjaykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFJlZmVyZW5jZWQgcmVzb3VyY2UgbXVzdCBiZSBpbiBzdGFjayAnJHt0YXJnZXRTdGFjay5ub2RlLnBhdGh9JywgZ290ICcke3JlZmVyZW5jZS50YXJnZXQubm9kZS5wYXRofSdgKTtcbiAgfVxuXG4gIHdoaWxlIChjdXJyZW50U3RhY2sgIT09IHRhcmdldFN0YWNrKSB7XG4gICAgcmVmZXJlbmNlID0gY3JlYXRlTmVzdGVkU3RhY2tPdXRwdXQoU3RhY2sub2YocmVmZXJlbmNlLnRhcmdldCksIHJlZmVyZW5jZSk7XG4gICAgY3VycmVudFN0YWNrID0gU3RhY2sub2YocmVmZXJlbmNlLnRhcmdldCk7XG4gIH1cblxuICByZXR1cm4gcmVmZXJlbmNlO1xufVxuXG4vKipcbiAqIEByZXR1cm5zIHRydWUgaWYgdGhpcyBzdGFjayBpcyBhIGRpcmVjdCBvciBpbmRpcmVjdCBwYXJlbnQgb2YgdGhlIG5lc3RlZFxuICogc3RhY2sgYG5lc3RlZGAuXG4gKlxuICogSWYgYGNoaWxkYCBpcyBub3QgYSBuZXN0ZWQgc3RhY2ssIGFsd2F5cyByZXR1cm5zIGBmYWxzZWAgYmVjYXVzZSBpdCBjYW4ndFxuICogaGF2ZSBhIHBhcmVudCwgZGFoLlxuICovXG5mdW5jdGlvbiBpc05lc3RlZChuZXN0ZWQ6IFN0YWNrLCBwYXJlbnQ6IFN0YWNrKTogYm9vbGVhbiB7XG4gIC8vIGlmIHRoZSBwYXJlbnQgaXMgYSBkaXJlY3QgcGFyZW50XG4gIGlmIChuZXN0ZWQubmVzdGVkU3RhY2tQYXJlbnQgPT09IHBhcmVudCkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLy8gd2UgcmVhY2hlZCBhIHRvcC1sZXZlbCAobm9uLW5lc3RlZCkgc3RhY2sgd2l0aG91dCBmaW5kaW5nIHRoZSBwYXJlbnRcbiAgaWYgKCFuZXN0ZWQubmVzdGVkU3RhY2tQYXJlbnQpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyByZWN1cnNlIHdpdGggdGhlIGNoaWxkJ3MgZGlyZWN0IHBhcmVudFxuICByZXR1cm4gaXNOZXN0ZWQobmVzdGVkLm5lc3RlZFN0YWNrUGFyZW50LCBwYXJlbnQpO1xufVxuXG4vKipcbiAqIEdlbmVyYXRlcyBhIHVuaXF1ZSBpZCBmb3IgYSBgUmVmZXJlbmNlYFxuICogQHBhcmFtIHN0YWNrIEEgc3RhY2sgdXNlZCB0byByZXNvbHZlIHRva2Vuc1xuICogQHBhcmFtIHJlZiBUaGUgcmVmZXJlbmNlXG4gKiBAcGFyYW0gcHJlZml4IE9wdGlvbmFsIHByZWZpeCBmb3IgdGhlIGlkXG4gKiBAcmV0dXJucyBBIHVuaXF1ZSBpZFxuICovXG5mdW5jdGlvbiBnZW5lcmF0ZVVuaXF1ZUlkKHN0YWNrOiBTdGFjaywgcmVmOiBSZWZlcmVuY2UsIHByZWZpeCA9ICcnKSB7XG4gIC8vIHdlIGNhbGwgXCJyZXNvbHZlKClcIiB0byBlbnN1cmUgdGhhdCB0b2tlbnMgZG8gbm90IGNyZWVwIGluIChmb3IgZXhhbXBsZSwgaWYgdGhlIHJlZmVyZW5jZSBkaXNwbGF5IG5hbWUgaW5jbHVkZXMgdG9rZW5zKVxuICByZXR1cm4gc3RhY2sucmVzb2x2ZShgJHtwcmVmaXh9JHtOYW1lcy5ub2RlVW5pcXVlSWQocmVmLnRhcmdldC5ub2RlKX0ke3JlZi5kaXNwbGF5TmFtZX1gKTtcbn0iXX0=
;