@aws/pdk
Version:
All documentation is located at: https://aws.github.io/aws-pdk
330 lines • 49.1 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.computeGraph = computeGraph;
/*! Copyright [Amazon.com](http://amazon.com/), Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0 */
const aws_cdk_lib_1 = require("aws-cdk-lib");
const merge = require("lodash.merge"); // eslint-disable-line @typescript-eslint/no-require-imports
const uniq = require("lodash.uniq"); // eslint-disable-line @typescript-eslint/no-require-imports
const uniqBy = require("lodash.uniqby"); // eslint-disable-line @typescript-eslint/no-require-imports
const constants_1 = require("./constants");
const debug_1 = require("./debug");
const Graph = require("./graph");
const types_1 = require("./types");
const utils_1 = require("./utils");
/** List of cdk stack children used by cdk that the graph ignores */
const IGNORED_STACK_CHILDREN = [
"CDKMetadata",
"BootstrapVersion",
"CheckBootstrapVersion",
];
/**
* Computes the graph store for a given Cdk construct, usually App.
* @internal
*/
function computeGraph(root) {
const store = new Graph.Store();
// List of nodes that should not be processed (extraneous nodes detected during compute)
// NB: example is stack template construct which cdk creates as sibling of nested stacks,
// we care about the stack and not the marshalled construct.
const nodesToIgnore = [];
// List of all unresolved referenced detected during compute, which are resolved after all nodes have been stored
const allUnresolvedReferences = [];
// List of all unresolved dependencies detected during compute, which are resolved after all nodes have been stored
const allUnresolvedDependencies = [];
const visit = (construct, parent) => {
// Do not graph the CdkGraph itself
if (construct.node.id === constants_1.GRAPH_ID) {
return;
}
// Do not graph the Tree construct (synthesizes tree.json)
if (Graph.AppNode.isAppNode(parent) && construct.node.id === "Tree") {
return;
}
// Do not graph stack CDKMetadata, BootstrapVersion, and similar constructs
if (Graph.StackNode.isStackNode(parent) &&
IGNORED_STACK_CHILDREN.includes(construct.node.id)) {
return;
}
const { uuid, attributes = {}, metadata = [], tags = {}, logicalId, cfnType, constructInfo, dependencies, unresolvedReferences, flags, } = (0, utils_1.inferNodeProps)(construct);
if (nodesToIgnore.includes(uuid)) {
return;
}
// Infer the stack this construct belongs to
let stack;
try {
if (construct.node.scope) {
const stackUUID = (0, utils_1.getConstructUUID)(aws_cdk_lib_1.Stack.of(construct));
stack = store.getStack(stackUUID);
}
}
catch {
// ignore - expected to throw if construct is not contained in a stack
}
const nodeProps = {
store,
stack,
parent,
uuid,
id: construct.node.id,
path: construct.node.path,
attributes,
metadata,
tags,
constructInfo,
logicalId,
cfnType,
flags,
};
let node;
switch (constructInfo?.fqn) {
case types_1.ConstructInfoFqnEnum.PDKAPP_MONO:
case types_1.ConstructInfoFqnEnum.PDKAPP:
case types_1.ConstructInfoFqnEnum.APP: {
node = new Graph.AppNode({
store,
parent,
attributes,
metadata,
tags,
constructInfo,
logicalId,
flags,
});
break;
}
case types_1.ConstructInfoFqnEnum.STAGE: {
node = new Graph.StageNode(nodeProps);
break;
}
case types_1.ConstructInfoFqnEnum.STACK: {
node = new Graph.StackNode(nodeProps);
break;
}
case types_1.ConstructInfoFqnEnum.NESTED_STACK: {
// NB: handle NestedStack<->CfnStack as single Node with NestedStack construct as source
// https://github.com/aws/aws-cdk/blob/119c92f65bf26c3fdf4bb818a4a4812022a3744a/packages/%40aws-cdk/core/lib/nested-stack.ts#L119
const parentStack = (0, utils_1.inferNodeProps)(construct.nestedStackParent);
const _nestedStack = construct.node.scope.node.findChild(construct.node.id + ".NestedStack");
const cfnStackWrapper = (0, utils_1.inferNodeProps)(_nestedStack);
const cfnStack = (0, utils_1.inferNodeProps)(_nestedStack.node.findChild(construct.node.id + ".NestedStackResource"));
// ignore parent scope cfn stack (template) constructs
nodesToIgnore.push(cfnStackWrapper.uuid, cfnStackWrapper.uuid);
node = new Graph.NestedStackNode({
...nodeProps,
logicalId: cfnStack.logicalId,
attributes: merge({}, attributes, cfnStackWrapper.attributes, cfnStack.attributes),
metadata: [
...metadata,
...(cfnStackWrapper.metadata || []),
...(cfnStack.metadata || []),
],
parentStack: store.getStack(parentStack.uuid),
});
// Only add uniq dependencies as wrapper and stack may duplicate
dependencies.push(...uniq([...cfnStackWrapper.dependencies, ...cfnStack.dependencies]));
// Only add uniq references as wrapper and stack may duplicate
unresolvedReferences.push(...uniqBy([
...cfnStackWrapper.unresolvedReferences.map((ref) => ({
...ref,
source: uuid,
})),
...cfnStack.unresolvedReferences.map((ref) => ({
...ref,
source: uuid,
})),
], (v) => `${v.referenceType}::${v.source}::${v.target}::${JSON.stringify(v.value || "")}`));
break;
}
case types_1.ConstructInfoFqnEnum.CFN_STACK: {
// CfnStack always proceeds NestedStack, based on above case we merge CfnStack into
// NestedStack (mirror developer expectations) and then ignore CfnStack.
throw new Error(`CfnStack should be ignored by NestedStack: ${uuid}`);
}
case types_1.ConstructInfoFqnEnum.CFN_OUTPUT: {
node = new Graph.OutputNode({
...nodeProps,
value: aws_cdk_lib_1.Stack.of(construct).resolve(construct.value),
description: aws_cdk_lib_1.Stack.of(construct).resolve(construct.description),
exportName: aws_cdk_lib_1.Stack.of(construct).resolve(construct.exportName),
});
// extract unresolved references from value
unresolvedReferences.push(...(0, utils_1.extractUnresolvedReferences)(node.uuid, node.value || {}));
break;
}
case types_1.ConstructInfoFqnEnum.CFN_PARAMETER: {
const cfnParameter = construct;
node = new Graph.ParameterNode({
...nodeProps,
value: aws_cdk_lib_1.Stack.of(construct).resolve(cfnParameter.value),
description: aws_cdk_lib_1.Stack.of(construct).resolve(cfnParameter.description),
parameterType: cfnParameter.type,
});
break;
}
default: {
if (flags?.includes(types_1.FlagEnum.IMPORT)) {
node = new Graph.CfnResourceNode({
...nodeProps,
cfnType: (0, utils_1.inferImportCfnType)(construct, constructInfo),
importArnToken: (0, utils_1.resolveImportedConstructArnToken)(construct),
});
}
else if (aws_cdk_lib_1.Resource.isResource(construct)) {
node = new Graph.ResourceNode({
...nodeProps,
cdkOwned: aws_cdk_lib_1.Resource.isOwnedResource(construct),
});
}
else if (cfnType) {
node = new Graph.CfnResourceNode(nodeProps);
}
else {
node = new Graph.Node({
nodeType: types_1.NodeTypeEnum.DEFAULT,
...nodeProps,
});
// Cdk Stack.Exports is proxy to actual Cfn exports and extraneous in the graph
if (construct.node.id === types_1.CdkConstructIds.EXPORTS &&
aws_cdk_lib_1.Stack.isStack(construct.node.scope)) {
node.addFlag(types_1.FlagEnum.EXTRANEOUS);
}
}
}
}
// Track unresolved dependencies, since nodes might not be created in the store yet
allUnresolvedDependencies.push(...dependencies.map((dep) => [uuid, dep]));
// Track all logicalId references in the nodes attributes
// this will get resolved after all nodes have been stored
allUnresolvedReferences.push(...unresolvedReferences);
// Visit all child to compute the tree
for (const child of construct.node.children) {
try {
visit(child, node);
}
catch (e) {
aws_cdk_lib_1.Annotations.of(root).addWarning(`Failed to render graph for node ${child.node.path}. Reason: ${e}`);
throw e;
}
}
};
visit(root, store.root);
// Resolve all references - now that the tree is stored
for (const unresolved of allUnresolvedReferences) {
try {
resolveReference(store, unresolved);
}
catch (e) {
debug_1.IS_DEBUG && console.warn(e, unresolved);
// TODO: consider saving unresolved references if become valuable.
}
}
// Resolve all dependencies - now that the tree is stored
for (const unresolved of allUnresolvedDependencies) {
resolveDependency(store, unresolved);
}
return store;
}
/**
* Resolve reference. During initial graph traversal not all nodes have been added at the time
* a reference has been detected, as such we need to resolve all references after the graph tree
* has been stored.
* @internal
*/
function resolveReference(store, unresolved) {
const source = store.getNode(unresolved.source);
if (source.stack == null) {
console.warn(String(source), source);
throw new Error(`Node ${source} is not within stack`);
}
let target;
switch (unresolved.referenceType) {
case types_1.ReferenceTypeEnum.REF: {
// ref logicalId is only unique in the stack
target = store.findNodeByLogicalId(source.stack, unresolved.target);
return new Graph.Reference({
store,
uuid: (0, utils_1.generateConsistentUUID)(unresolved, Graph.Reference.PREFIX),
referenceType: types_1.ReferenceTypeEnum.REF,
source,
target,
});
}
case types_1.ReferenceTypeEnum.IMPORT: {
// imports already contain the stack id (stack:logicalId)
target = store.findNodeByLogicalUniversalId(unresolved.target);
return new Graph.ImportReference({
store,
uuid: (0, utils_1.generateConsistentUUID)(unresolved, Graph.ImportReference.PREFIX),
source,
target,
});
}
case types_1.ReferenceTypeEnum.IMPORT_ARN: {
const resolvedImportArnNode = store.findNodeByImportArn(unresolved.target);
if (!resolvedImportArnNode) {
// ImportArn tokens are not direct matches, so we can safely ignore misses.
// We only care about resources directly imported into the CDK app.
return undefined;
}
return new Graph.ImportReference({
store,
uuid: (0, utils_1.generateConsistentUUID)(unresolved, Graph.ImportReference.PREFIX),
source,
target: resolvedImportArnNode,
});
}
case types_1.ReferenceTypeEnum.ATTRIBUTE: {
const attribute = unresolved.value;
if (attribute && attribute.startsWith("Outputs.")) {
// Stack output reference
const stacksToSearch = source.rootStack?.stage?.stacks || store.stacks;
const potentialRefStacks = Object.values(stacksToSearch).filter((_stack) => _stack.logicalId === unresolved.target);
if (potentialRefStacks.length === 1) {
const refStack = potentialRefStacks[0];
target = refStack.findOutput(attribute.replace("Outputs.", ""));
}
else {
console.warn("Failed to find logical id from attribute reference:", unresolved.target);
if (potentialRefStacks.length) {
console.warn("Found multiple matching stacks:", Object.values(potentialRefStacks).map((stack) => `${String(stack)}:${stack.logicalId || "ROOT"}`));
}
else {
console.warn("Available stacks:", Object.values(store.stacks).map((stack) => `${String(stack)}:${stack.logicalId || "ROOT"}`));
}
throw new Error(`Failed to find Fn::GetAtt stack for output reference "${unresolved.target}": ${potentialRefStacks.length}`);
}
}
else {
target = store.findNodeByLogicalId(source.stack, unresolved.target);
}
if (target) {
return new Graph.AttributeReference({
store,
uuid: (0, utils_1.generateConsistentUUID)(unresolved, Graph.AttributeReference.PREFIX),
source,
target,
value: attribute,
});
}
}
}
throw new Error(`Failed to resolve reference: ${JSON.stringify(unresolved)}`);
}
/**
* Resolve dependency. During initial graph traversal not all nodes have been added at the time
* a dependency has been detected, as such we need to resolve all dependencies after the graph tree
* has been stored.
* @internal
*/
function resolveDependency(store, unresolved) {
const source = store.getNode(unresolved[0]);
const target = store.getNode(unresolved[1]);
return new Graph.Dependency({
store,
uuid: (0, utils_1.generateConsistentUUID)(unresolved, Graph.Dependency.PREFIX),
source,
target,
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcHV0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImNvbXB1dGUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFtREEsb0NBZ1JDO0FBblVEO3NDQUNzQztBQUN0Qyw2Q0FRcUI7QUFFckIsc0NBQXVDLENBQUMsNERBQTREO0FBQ3BHLG9DQUFxQyxDQUFDLDREQUE0RDtBQUNsRyx3Q0FBeUMsQ0FBQyw0REFBNEQ7QUFDdEcsMkNBQXVDO0FBQ3ZDLG1DQUFtQztBQUNuQyxpQ0FBaUM7QUFFakMsbUNBUWlCO0FBQ2pCLG1DQU9pQjtBQUtqQixvRUFBb0U7QUFDcEUsTUFBTSxzQkFBc0IsR0FBRztJQUM3QixhQUFhO0lBQ2Isa0JBQWtCO0lBQ2xCLHVCQUF1QjtDQUN4QixDQUFDO0FBRUY7OztHQUdHO0FBQ0gsU0FBZ0IsWUFBWSxDQUFDLElBQWdCO0lBQzNDLE1BQU0sS0FBSyxHQUFHLElBQUksS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO0lBRWhDLHdGQUF3RjtJQUN4Rix5RkFBeUY7SUFDekYsNERBQTREO0lBQzVELE1BQU0sYUFBYSxHQUFXLEVBQUUsQ0FBQztJQUVqQyxpSEFBaUg7SUFDakgsTUFBTSx1QkFBdUIsR0FBNEMsRUFBRSxDQUFDO0lBQzVFLG1IQUFtSDtJQUNuSCxNQUFNLHlCQUF5QixHQUEyQixFQUFFLENBQUM7SUFFN0QsTUFBTSxLQUFLLEdBQUcsQ0FBQyxTQUFxQixFQUFFLE1BQWtCLEVBQVEsRUFBRTtRQUNoRSxtQ0FBbUM7UUFDbkMsSUFBSSxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxvQkFBUSxFQUFFLENBQUM7WUFDbkMsT0FBTztRQUNULENBQUM7UUFFRCwwREFBMEQ7UUFDMUQsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsSUFBSSxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsS0FBSyxNQUFNLEVBQUUsQ0FBQztZQUNwRSxPQUFPO1FBQ1QsQ0FBQztRQUVELDJF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Z0M7SUFFaEMsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUM1QyxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRTVDLE9BQU8sSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFDO1FBQzFCLEtBQUs7UUFDTCxJQUFJLEVBQUUsSUFBQSw4QkFBc0IsRUFBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUM7UUFDakUsTUFBTTtRQUNOLE1BQU07S0FDUCxDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyohIENvcHlyaWdodCBbQW1hem9uLmNvbV0oaHR0cDovL2FtYXpvbi5jb20vKSwgSW5jLiBvciBpdHMgYWZmaWxpYXRlcy4gQWxsIFJpZ2h0cyBSZXNlcnZlZC5cblNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wICovXG5pbXBvcnQge1xuICBBbm5vdGF0aW9ucyxcbiAgQ2ZuT3V0cHV0LFxuICBDZm5QYXJhbWV0ZXIsXG4gIENmblN0YWNrLFxuICBOZXN0ZWRTdGFjayxcbiAgUmVzb3VyY2UsXG4gIFN0YWNrLFxufSBmcm9tIFwiYXdzLWNkay1saWJcIjtcbmltcG9ydCB7IElDb25zdHJ1Y3QgfSBmcm9tIFwiY29uc3RydWN0c1wiO1xuaW1wb3J0IG1lcmdlID0gcmVxdWlyZShcImxvZGFzaC5tZXJnZVwiKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG5pbXBvcnQgdW5pcSA9IHJlcXVpcmUoXCJsb2Rhc2gudW5pcVwiKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG5pbXBvcnQgdW5pcUJ5ID0gcmVxdWlyZShcImxvZGFzaC51bmlxYnlcIik7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuaW1wb3J0IHsgR1JBUEhfSUQgfSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IElTX0RFQlVHIH0gZnJvbSBcIi4vZGVidWdcIjtcbmltcG9ydCAqIGFzIEdyYXBoIGZyb20gXCIuL2dyYXBoXCI7XG5pbXBvcnQgKiBhcyBTZXJpYWxpemVkR3JhcGggZnJvbSBcIi4vc2VyaWFsaXplZC1ncmFwaFwiO1xuaW1wb3J0IHtcbiAgQ2RrQ29uc3RydWN0SWRzLFxuICBDb25zdHJ1Y3RJbmZvRnFuRW51bSxcbiAgRmxhZ0VudW0sXG4gIExPR0lDQUxfVU5JVkVSU0FMX0lELFxuICBOb2RlVHlwZUVudW0sXG4gIFJlZmVyZW5jZVR5cGVFbnVtLFxuICBVVUlELFxufSBmcm9tIFwiLi90eXBlc1wiO1xuaW1wb3J0IHtcbiAgZXh0cmFjdFVucmVzb2x2ZWRSZWZlcmVuY2VzLFxuICBnZW5lcmF0ZUNvbnNpc3RlbnRVVUlELFxuICBnZXRDb25zdHJ1Y3RVVUlELFxuICByZXNvbHZlSW1wb3J0ZWRDb25zdHJ1Y3RBcm5Ub2tlbixcbiAgaW5mZXJJbXBvcnRDZm5UeXBlLFxuICBpbmZlck5vZGVQcm9wcyxcbn0gZnJvbSBcIi4vdXRpbHNcIjtcblxuLy8gW3NvdXJjZTogVVVJRCwgdGFyZ2V0OiBVVUlEXVxudHlwZSBVbnJlc29sdmVkRGVwZW5kZW5jeSA9IFtVVUlELCBVVUlEXTtcblxuLyoqIExpc3Qgb2YgY2RrIHN0YWNrIGNoaWxkcmVuIHVzZWQgYnkgY2RrIHRoYXQgdGhlIGdyYXBoIGlnbm9yZXMgKi9cbmNvbnN0IElHTk9SRURfU1RBQ0tfQ0hJTERSRU4gPSBbXG4gIFwiQ0RLTWV0YWRhdGFcIixcbiAgXCJCb290c3RyYXBWZXJzaW9uXCIsXG4gIFwiQ2hlY2tCb290c3RyYXBWZXJzaW9uXCIsXG5dO1xuXG4vKipcbiAqIENvbXB1dGVzIHRoZSBncmFwaCBzdG9yZSBmb3IgYSBnaXZlbiBDZGsgY29uc3RydWN0LCB1c3VhbGx5IEFwcC5cbiAqIEBpbnRlcm5hbFxuICovXG5leHBvcnQgZnVuY3Rpb24gY29tcHV0ZUdyYXBoKHJvb3Q6IElDb25zdHJ1Y3QpOiBHcmFwaC5TdG9yZSB7XG4gIGNvbnN0IHN0b3JlID0gbmV3IEdyYXBoLlN0b3JlKCk7XG5cbiAgLy8gTGlzdCBvZiBub2RlcyB0aGF0IHNob3VsZCBub3QgYmUgcHJvY2Vzc2VkIChleHRyYW5lb3VzIG5vZGVzIGRldGVjdGVkIGR1cmluZyBjb21wdXRlKVxuICAvLyBOQjogZXhhbXBsZSBpcyBzdGFjayB0ZW1wbGF0ZSBjb25zdHJ1Y3Qgd2hpY2ggY2RrIGNyZWF0ZXMgYXMgc2libGluZyBvZiBuZXN0ZWQgc3RhY2tzLFxuICAvLyB3ZSBjYXJlIGFib3V0IHRoZSBzdGFjayBhbmQgbm90IHRoZSBtYXJzaGFsbGVkIGNvbnN0cnVjdC5cbiAgY29uc3Qgbm9kZXNUb0lnbm9yZTogVVVJRFtdID0gW107XG5cbiAgLy8gTGlzdCBvZiBhbGwgdW5yZXNvbHZlZCByZWZlcmVuY2VkIGRldGVjdGVkIGR1cmluZyBjb21wdXRlLCB3aGljaCBhcmUgcmVzb2x2ZWQgYWZ0ZXIgYWxsIG5vZGVzIGhhdmUgYmVlbiBzdG9yZWRcbiAgY29uc3QgYWxsVW5yZXNvbHZlZFJlZmVyZW5jZXM6IFNlcmlhbGl6ZWRHcmFwaC5TR1VucmVzb2x2ZWRSZWZlcmVuY2VbXSA9IFtdO1xuICAvLyBMaXN0IG9mIGFsbCB1bnJlc29sdmVkIGRlcGVuZGVuY2llcyBkZXRlY3RlZCBkdXJpbmcgY29tcHV0ZSwgd2hpY2ggYXJlIHJlc29sdmVkIGFmdGVyIGFsbCBub2RlcyBoYXZlIGJlZW4gc3RvcmVkXG4gIGNvbnN0IGFsbFVucmVzb2x2ZWREZXBlbmRlbmNpZXM6IFVucmVzb2x2ZWREZXBlbmRlbmN5W10gPSBbXTtcblxuICBjb25zdCB2aXNpdCA9IChjb25zdHJ1Y3Q6IElDb25zdHJ1Y3QsIHBhcmVudDogR3JhcGguTm9kZSk6IHZvaWQgPT4ge1xuICAgIC8vIERvIG5vdCBncmFwaCB0aGUgQ2RrR3JhcGggaXRzZWxmXG4gICAgaWYgKGNvbnN0cnVjdC5ub2RlLmlkID09PSBHUkFQSF9JRCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIERvIG5vdCBncmFwaCB0aGUgVHJlZSBjb25zdHJ1Y3QgKHN5bnRoZXNpemVzIHRyZWUuanNvbilcbiAgICBpZiAoR3JhcGguQXBwTm9kZS5pc0FwcE5vZGUocGFyZW50KSAmJiBjb25zdHJ1Y3Qubm9kZS5pZCA9PT0gXCJUcmVlXCIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBEbyBub3QgZ3JhcGggc3RhY2sgQ0RLTWV0YWRhdGEsIEJvb3RzdHJhcFZlcnNpb24sIGFuZCBzaW1pbGFyIGNvbnN0cnVjdHNcbiAgICBpZiAoXG4gICAgICBHcmFwaC5TdGFja05vZGUuaXNTdGFja05vZGUocGFyZW50KSAmJlxuICAgICAgSUdOT1JFRF9TVEFDS19DSElMRFJFTi5pbmNsdWRlcyhjb25zdHJ1Y3Qubm9kZS5pZClcbiAgICApIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCB7XG4gICAgICB1dWlkLFxuICAgICAgYXR0cmlidXRlcyA9IHt9LFxuICAgICAgbWV0YWRhdGEgPSBbXSxcbiAgICAgIHRhZ3MgPSB7fSxcbiAgICAgIGxvZ2ljYWxJZCxcbiAgICAgIGNmblR5cGUsXG4gICAgICBjb25zdHJ1Y3RJbmZvLFxuICAgICAgZGVwZW5kZW5jaWVzLFxuICAgICAgdW5yZXNvbHZlZFJlZmVyZW5jZXMsXG4gICAgICBmbGFncyxcbiAgICB9ID0gaW5mZXJOb2RlUHJvcHMoY29uc3RydWN0KTtcblxuICAgIGlmIChub2Rlc1RvSWdub3JlLmluY2x1ZGVzKHV1aWQpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gSW5mZXIgdGhlIHN0YWNrIHRoaXMgY29uc3RydWN0IGJlbG9uZ3MgdG9cbiAgICBsZXQgc3RhY2s6IEdyYXBoLlN0YWNrTm9kZSB8IHVuZGVmaW5lZDtcbiAgICB0cnkge1xuICAgICAgaWYgKGNvbnN0cnVjdC5ub2RlLnNjb3BlKSB7XG4gICAgICAgIGNvbnN0IHN0YWNrVVVJRCA9IGdldENvbnN0cnVjdFVVSUQoU3RhY2sub2YoY29uc3RydWN0KSk7XG4gICAgICAgIHN0YWNrID0gc3RvcmUuZ2V0U3RhY2soc3RhY2tVVUlEKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIHtcbiAgICAgIC8vIGlnbm9yZSAtIGV4cGVjdGVkIHRvIHRocm93IGlmIGNvbnN0cnVjdCBpcyBub3QgY29udGFpbmVkIGluIGEgc3RhY2tcbiAgICB9XG5cbiAgICBjb25zdCBub2RlUHJvcHM6IEdyYXBoLklUeXBlZE5vZGVQcm9wcyA9IHtcbiAgICAgIHN0b3JlLFxuICAgICAgc3RhY2ssXG4gICAgICBwYXJlbnQsXG4gICAgICB1dWlkLFxuICAgICAgaWQ6IGNvbnN0cnVjdC5ub2RlLmlkLFxuICAgICAgcGF0aDogY29uc3RydWN0Lm5vZGUucGF0aCxcbiAgICAgIGF0dHJpYnV0ZXMsXG4gICAgICBtZXRhZGF0YSxcbiAgICAgIHRhZ3MsXG4gICAgICBjb25zdHJ1Y3RJbmZvLFxuICAgICAgbG9naWNhbElkLFxuICAgICAgY2ZuVHlwZSxcbiAgICAgIGZsYWdzLFxuICAgIH07XG4gICAgbGV0IG5vZGU6IEdyYXBoLk5vZGU7XG4gICAgc3dpdGNoIChjb25zdHJ1Y3RJbmZvPy5mcW4gYXMgQ29uc3RydWN0SW5mb0ZxbkVudW0pIHtcbiAgICAgIGNhc2UgQ29uc3RydWN0SW5mb0ZxbkVudW0uUERLQVBQX01PTk86XG4gICAgICBjYXNlIENvbnN0cnVjdEluZm9GcW5FbnVtLlBES0FQUDpcbiAgICAgIGNhc2UgQ29uc3RydWN0SW5mb0ZxbkVudW0uQVBQOiB7XG4gICAgICAgIG5vZGUgPSBuZXcgR3JhcGguQXBwTm9kZSh7XG4gICAgICAgICAgc3RvcmUsXG4gICAgICAgICAgcGFyZW50LFxuICAgICAgICAgIGF0dHJpYnV0ZXMsXG4gICAgICAgICAgbWV0YWRhdGEsXG4gICAgICAgICAgdGFncyxcbiAgICAgICAgICBjb25zdHJ1Y3RJbmZvLFxuICAgICAgICAgIGxvZ2ljYWxJZCxcbiAgICAgICAgICBmbGFncyxcbiAgICAgICAgfSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgY2FzZSBDb25zdHJ1Y3RJbmZvRnFuRW51bS5TVEFHRToge1xuICAgICAgICBub2RlID0gbmV3IEdyYXBoLlN0YWdlTm9kZShub2RlUHJvcHMpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGNhc2UgQ29uc3RydWN0SW5mb0ZxbkVudW0uU1RBQ0s6IHtcbiAgICAgICAgbm9kZSA9IG5ldyBHcmFwaC5TdGFja05vZGUobm9kZVByb3BzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlIENvbnN0cnVjdEluZm9GcW5FbnVtLk5FU1RFRF9TVEFDSzoge1xuICAgICAgICAvLyBOQjogaGFuZGxlIE5lc3RlZFN0YWNrPC0+Q2ZuU3RhY2sgYXMgc2luZ2xlIE5vZGUgd2l0aCBOZXN0ZWRTdGFjayBjb25zdHJ1Y3QgYXMgc291cmNlXG4gICAgICAgIC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9hd3MvYXdzLWNkay9ibG9iLzExOWM5MmY2NWJmMjZjM2ZkZjRiYjgxOGE0YTQ4MTIwMjJhMzc0NGEvcGFja2FnZXMvJTQwYXdzLWNkay9jb3JlL2xpYi9uZXN0ZWQtc3RhY2sudHMjTDExOVxuXG4gICAgICAgIGNvbnN0IHBhcmVudFN0YWNrID0gaW5mZXJOb2RlUHJvcHMoXG4gICAgICAgICAgKGNvbnN0cnVjdCBhcyBOZXN0ZWRTdGFjaykubmVzdGVkU3RhY2tQYXJlbnQhXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IF9uZXN0ZWRTdGFjayA9IGNvbnN0cnVjdC5ub2RlLnNjb3BlIS5ub2RlLmZpbmRDaGlsZChcbiAgICAgICAgICBjb25zdHJ1Y3Qubm9kZS5pZCArIFwiLk5lc3RlZFN0YWNrXCJcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgY2ZuU3RhY2tXcmFwcGVyID0gaW5mZXJOb2RlUHJvcHMoX25lc3RlZFN0YWNrKTtcbiAgICAgICAgY29uc3QgY2ZuU3RhY2sgPSBpbmZlck5vZGVQcm9wcyhcbiAgICAgICAgICBfbmVzdGVkU3RhY2subm9kZS5maW5kQ2hpbGQoXG4gICAgICAgICAgICBjb25zdHJ1Y3Qubm9kZS5pZCArIFwiLk5lc3RlZFN0YWNrUmVzb3VyY2VcIlxuICAgICAgICAgICkgYXMgQ2ZuU3RhY2tcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBpZ25vcmUgcGFyZW50IHNjb3BlIGNmbiBzdGFjayAodGVtcGxhdGUpIGNvbnN0cnVjdHNcbiAgICAgICAgbm9kZXNUb0lnbm9yZS5wdXNoKGNmblN0YWNrV3JhcHBlci51dWlkLCBjZm5TdGFja1dyYXBwZXIudXVpZCk7XG5cbiAgICAgICAgbm9kZSA9IG5ldyBHcmFwaC5OZXN0ZWRTdGFja05vZGUoe1xuICAgICAgICAgIC4uLm5vZGVQcm9wcyxcbiAgICAgICAgICBsb2dpY2FsSWQ6IGNmblN0YWNrLmxvZ2ljYWxJZCxcbiAgICAgICAgICBhdHRyaWJ1dGVzOiBtZXJnZShcbiAgICAgICAgICAgIHt9LFxuICAgICAgICAgICAgYXR0cmlidXRlcyxcbiAgICAgICAgICAgIGNmblN0YWNrV3JhcHBlci5hdHRyaWJ1dGVzLFxuICAgICAgICAgICAgY2ZuU3RhY2suYXR0cmlidXRlc1xuICAgICAgICAgICksXG4gICAgICAgICAgbWV0YWRhdGE6IFtcbiAgICAgICAgICAgIC4uLm1ldGFkYXRhLFxuICAgICAgICAgICAgLi4uKGNmblN0YWNrV3JhcHBlci5tZXRhZGF0YSB8fCBbXSksXG4gICAgICAgICAgICAuLi4oY2ZuU3RhY2subWV0YWRhdGEgfHwgW10pLFxuICAgICAgICAgIF0sXG4gICAgICAgICAgcGFyZW50U3RhY2s6IHN0b3JlLmdldFN0YWNrKHBhcmVudFN0YWNrLnV1aWQpLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBPbmx5IGFkZCB1bmlxIGRlcGVuZGVuY2llcyBhcyB3cmFwcGVyIGFuZCBzdGFjayBtYXkgZHVwbGljYXRlXG4gICAgICAgIGRlcGVuZGVuY2llcy5wdXNoKFxuICAgICAgICAgIC4uLnVuaXEoWy4uLmNmblN0YWNrV3JhcHBlci5kZXBlbmRlbmNpZXMsIC4uLmNmblN0YWNrLmRlcGVuZGVuY2llc10pXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gT25seSBhZGQgdW5pcSByZWZlcmVuY2VzIGFzIHdyYXBwZXIgYW5kIHN0YWNrIG1heSBkdXBsaWNhdGVcbiAgICAgICAgdW5yZXNvbHZlZFJlZmVyZW5jZXMucHVzaChcbiAgICAgICAgICAuLi51bmlxQnkoXG4gICAgICAgICAgICBbXG4gICAgICAgICAgICAgIC4uLmNmblN0YWNrV3JhcHBlci51bnJlc29sdmVkUmVmZXJlbmNlcy5tYXAoKHJlZikgPT4gKHtcbiAgICAgICAgICAgICAgICAuLi5yZWYsXG4gICAgICAgICAgICAgICAgc291cmNlOiB1dWlkLFxuICAgICAgICAgICAgICB9KSksXG4gICAgICAgICAgICAgIC4uLmNmblN0YWNrLnVucmVzb2x2ZWRSZWZlcmVuY2VzLm1hcCgocmVmKSA9PiAoe1xuICAgICAgICAgICAgICAgIC4uLnJlZixcbiAgICAgICAgICAgICAgICBzb3VyY2U6IHV1aWQsXG4gICAgICAgICAgICAgIH0pKSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAodikgPT5cbiAgICAgICAgICAgICAgYCR7di5yZWZlcmVuY2VUeXBlfTo6JHt2LnNvdXJjZX06OiR7di50YXJnZXR9Ojoke0pTT04uc3RyaW5naWZ5KFxuICAgICAgICAgICAgICAgIHYudmFsdWUgfHwgXCJcIlxuICAgICAgICAgICAgICApfWBcbiAgICAgICAgICApXG4gICAgICAgICk7XG5cbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlIENvbnN0cnVjdEluZm9GcW5FbnVtLkNGTl9TVEFDSzoge1xuICAgICAgICAvLyBDZm5TdGFjayBhbHdheXMgcHJvY2VlZHMgTmVzdGVkU3RhY2ssIGJhc2VkIG9uIGFib3ZlIGNhc2Ugd2UgbWVyZ2UgQ2ZuU3RhY2sgaW50b1xuICAgICAgICAvLyBOZXN0ZWRTdGFjayAobWlycm9yIGRldmVsb3BlciBleHBlY3RhdGlvbnMpIGFuZCB0aGVuIGlnbm9yZSBDZm5TdGFjay5cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDZm5TdGFjayBzaG91bGQgYmUgaWdub3JlZCBieSBOZXN0ZWRTdGFjazogJHt1dWlkfWApO1xuICAgICAgfVxuICAgICAgY2FzZSBDb25zdHJ1Y3RJbmZvRnFuRW51bS5DRk5fT1VUUFVUOiB7XG4gICAgICAgIG5vZGUgPSBuZXcgR3JhcGguT3V0cHV0Tm9kZSh7XG4gICAgICAgICAgLi4ubm9kZVByb3BzLFxuICAgICAgICAgIHZhbHVlOiBTdGFjay5vZihjb25zdHJ1Y3QpLnJlc29sdmUoKGNvbnN0cnVjdCBhcyBDZm5PdXRwdXQpLnZhbHVlKSxcbiAgICAgICAgICBkZXNjcmlwdGlvbjogU3RhY2sub2YoY29uc3RydWN0KS5yZXNvbHZlKFxuICAgICAgICAgICAgKGNvbnN0cnVjdCBhcyBDZm5PdXRwdXQpLmRlc2NyaXB0aW9uXG4gICAgICAgICAgKSxcbiAgICAgICAgICBleHBvcnROYW1lOiBTdGFjay5vZihjb25zdHJ1Y3QpLnJlc29sdmUoXG4gICAgICAgICAgICAoY29uc3RydWN0IGFzIENmbk91dHB1dCkuZXhwb3J0TmFtZVxuICAgICAgICAgICksXG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIGV4dHJhY3QgdW5yZXNvbHZlZCByZWZlcmVuY2VzIGZyb20gdmFsdWVcbiAgICAgICAgdW5yZXNvbHZlZFJlZmVyZW5jZXMucHVzaChcbiAgICAgICAgICAuLi5leHRyYWN0VW5yZXNvbHZlZFJlZmVyZW5jZXMoXG4gICAgICAgICAgICBub2RlLnV1aWQsXG4gICAgICAgICAgICAobm9kZSBhcyBHcmFwaC5PdXRwdXROb2RlKS52YWx1ZSB8fCB7fVxuICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGNhc2UgQ29uc3RydWN0SW5mb0ZxbkVudW0uQ0ZOX1BBUkFNRVRFUjoge1xuICAgICAgICBjb25zdCBjZm5QYXJhbWV0ZXIgPSBjb25zdHJ1Y3QgYXMgQ2ZuUGFyYW1ldGVyO1xuICAgICAgICBub2RlID0gbmV3IEdyYXBoLlBhcmFtZXRlck5vZGUoe1xuICAgICAgICAgIC4uLm5vZGVQcm9wcyxcbiAgICAgICAgICB2YWx1ZTogU3RhY2sub2YoY29uc3RydWN0KS5yZXNvbHZlKGNmblBhcmFtZXRlci52YWx1ZSksXG4gICAgICAgICAgZGVzY3JpcHRpb246IFN0YWNrLm9mKGNvbnN0cnVjdCkucmVzb2x2ZShjZm5QYXJhbWV0ZXIuZGVzY3JpcHRpb24pLFxuICAgICAgICAgIHBhcmFtZXRlclR5cGU6IGNmblBhcmFtZXRlci50eXBlLFxuICAgICAgICB9KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBkZWZhdWx0OiB7XG4gICAgICAgIGlmIChmbGFncz8uaW5jbHVkZXMoRmxhZ0VudW0uSU1QT1JUKSkge1xuICAgICAgICAgIG5vZGUgPSBuZXcgR3JhcGguQ2ZuUmVzb3VyY2VOb2RlKHtcbiAgICAgICAgICAgIC4uLm5vZGVQcm9wcyxcbiAgICAgICAgICAgIGNmblR5cGU6IGluZmVySW1wb3J0Q2ZuVHlwZShjb25zdHJ1Y3QsIGNvbnN0cnVjdEluZm8pLFxuICAgICAgICAgICAgaW1wb3J0QXJuVG9rZW46IHJlc29sdmVJbXBvcnRlZENvbnN0cnVjdEFyblRva2VuKGNvbnN0cnVjdCksXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoUmVzb3VyY2UuaXNSZXNvdXJjZShjb25zdHJ1Y3QpKSB7XG4gICAgICAgICAgbm9kZSA9IG5ldyBHcmFwaC5SZXNvdXJjZU5vZGUoe1xuICAgICAgICAgICAgLi4ubm9kZVByb3BzLFxuICAgICAgICAgICAgY2RrT3duZWQ6IFJlc291cmNlLmlzT3duZWRSZXNvdXJjZShjb25zdHJ1Y3QpLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2UgaWYgKGNmblR5cGUpIHtcbiAgICAgICAgICBub2RlID0gbmV3IEdyYXBoLkNmblJlc291cmNlTm9kZShub2RlUHJvcHMpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG5vZGUgPSBuZXcgR3JhcGguTm9kZSh7XG4gICAgICAgICAgICBub2RlVHlwZTogTm9kZVR5cGVFbnVtLkRFRkFVTFQsXG4gICAgICAgICAgICAuLi5ub2RlUHJvcHMsXG4gICAgICAgICAgfSk7XG5cbiAgICAgICAgICAvLyBDZGsgU3RhY2suRXhwb3J0cyBpcyBwcm94eSB0byBhY3R1YWwgQ2ZuIGV4cG9ydHMgYW5kIGV4dHJhbmVvdXMgaW4gdGhlIGdyYXBoXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgY29uc3RydWN0Lm5vZGUuaWQgPT09IENka0NvbnN0cnVjdElkcy5FWFBPUlRTICYmXG4gICAgICAgICAgICBTdGFjay5pc1N0YWNrKGNvbnN0cnVjdC5ub2RlLnNjb3BlKVxuICAgICAgICAgICkge1xuICAgICAgICAgICAgbm9kZS5hZGRGbGFnKEZsYWdFbnVtLkVYVFJBTkVPVVMpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFRyYWNrIHVucmVzb2x2ZWQgZGVwZW5kZW5jaWVzLCBzaW5jZSBub2RlcyBtaWdodCBub3QgYmUgY3JlYXRlZCBpbiB0aGUgc3RvcmUgeWV0XG4gICAgYWxsVW5yZXNvbHZlZERlcGVuZGVuY2llcy5wdXNoKFxuICAgICAgLi4uZGVwZW5kZW5jaWVzLm1hcCgoZGVwKSA9PiBbdXVpZCwgZGVwXSBhcyBbc3RyaW5nLCBzdHJpbmddKVxuICAgICk7XG5cbiAgICAvLyBUcmFjayBhbGwgbG9naWNhbElkIHJlZmVyZW5jZXMgaW4gdGhlIG5vZGVzIGF0dHJpYnV0ZXNcbiAgICAvLyB0aGlzIHdpbGwgZ2V0IHJlc29sdmVkIGFmdGVyIGFsbCBub2RlcyBoYXZlIGJlZW4gc3RvcmVkXG4gICAgYWxsVW5yZXNvbHZlZFJlZmVyZW5jZXMucHVzaCguLi51bnJlc29sdmVkUmVmZXJlbmNlcyk7XG5cbiAgICAvLyBWaXNpdCBhbGwgY2hpbGQgdG8gY29tcHV0ZSB0aGUgdHJlZVxuICAgIGZvciAoY29uc3QgY2hpbGQgb2YgY29uc3RydWN0Lm5vZGUuY2hpbGRyZW4pIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIHZpc2l0KGNoaWxkLCBub2RlKTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgQW5ub3RhdGlvbnMub2Yocm9vdCkuYWRkV2FybmluZyhcbiAgICAgICAgICBgRmFpbGVkIHRvIHJlbmRlciBncmFwaCBmb3Igbm9kZSAke2NoaWxkLm5vZGUucGF0aH0uIFJlYXNvbjogJHtlfWBcbiAgICAgICAgKTtcbiAgICAgICAgdGhyb3cgZTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgdmlzaXQocm9vdCwgc3RvcmUucm9vdCk7XG5cbiAgLy8gUmVzb2x2ZSBhbGwgcmVmZXJlbmNlcyAtIG5vdyB0aGF0IHRoZSB0cmVlIGlzIHN0b3JlZFxuICBmb3IgKGNvbnN0IHVucmVzb2x2ZWQgb2YgYWxsVW5yZXNvbHZlZFJlZmVyZW5jZXMpIHtcbiAgICB0cnkge1xuICAgICAgcmVzb2x2ZVJlZmVyZW5jZShzdG9yZSwgdW5yZXNvbHZlZCk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgSVNfREVCVUcgJiYgY29uc29sZS53YXJuKGUsIHVucmVzb2x2ZWQpO1xuICAgICAgLy8gVE9ETzogY29uc2lkZXIgc2F2aW5nIHVucmVzb2x2ZWQgcmVmZXJlbmNlcyBpZiBiZWNvbWUgdmFsdWFibGUuXG4gICAgfVxuICB9XG5cbiAgLy8gUmVzb2x2ZSBhbGwgZGVwZW5kZW5jaWVzIC0gbm93IHRoYXQgdGhlIHRyZWUgaXMgc3RvcmVkXG4gIGZvciAoY29uc3QgdW5yZXNvbHZlZCBvZiBhbGxVbnJlc29sdmVkRGVwZW5kZW5jaWVzKSB7XG4gICAgcmVzb2x2ZURlcGVuZGVuY3koc3RvcmUsIHVucmVzb2x2ZWQpO1xuICB9XG5cbiAgcmV0dXJuIHN0b3JlO1xufVxuXG4vKipcbiAqIFJlc29sdmUgcmVmZXJlbmNlLiBEdXJpbmcgaW5pdGlhbCBncmFwaCB0cmF2ZXJzYWwgbm90IGFsbCBub2RlcyBoYXZlIGJlZW4gYWRkZWQgYXQgdGhlIHRpbWVcbiAqIGEgcmVmZXJlbmNlIGhhcyBiZWVuIGRldGVjdGVkLCBhcyBzdWNoIHdlIG5lZWQgdG8gcmVzb2x2ZSBhbGwgcmVmZXJlbmNlcyBhZnRlciB0aGUgZ3JhcGggdHJlZVxuICogaGFzIGJlZW4gc3RvcmVkLlxuICogQGludGVybmFsXG4gKi9cbmZ1bmN0aW9uIHJlc29sdmVSZWZlcmVuY2UoXG4gIHN0b3JlOiBHcmFwaC5TdG9yZSxcbiAgdW5yZXNvbHZlZDogU2VyaWFsaXplZEdyYXBoLlNHVW5yZXNvbHZlZFJlZmVyZW5jZVxuKTogR3JhcGguUmVmZXJlbmNlIHwgdW5kZWZpbmVkIHtcbiAgY29uc3Qgc291cmNlID0gc3RvcmUuZ2V0Tm9kZSh1bnJlc29sdmVkLnNvdXJjZSk7XG4gIGlmIChzb3VyY2Uuc3RhY2sgPT0gbnVsbCkge1xuICAgIGNvbnNvbGUud2FybihTdHJpbmcoc291cmNlKSwgc291cmNlKTtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYE5vZGUgJHtzb3VyY2V9IGlzIG5vdCB3aXRoaW4gc3RhY2tgKTtcbiAgfVxuXG4gIGxldCB0YXJnZXQ6IEdyYXBoLk5vZGU7XG5cbiAgc3dpdGNoICh1bnJlc29sdmVkLnJlZmVyZW5jZVR5cGUpIHtcbiAgICBjYXNlIFJlZmVyZW5jZVR5cGVFbnVtLlJFRjoge1xuICAgICAgLy8gcmVmIGxvZ2ljYWxJZCBpcyBvbmx5IHVuaXF1ZSBpbiB0aGUgc3RhY2tcbiAgICAgIHRhcmdldCA9IHN0b3JlLmZpbmROb2RlQnlMb2dpY2FsSWQoc291cmNlLnN0YWNrLCB1bnJlc29sdmVkLnRhcmdldCk7XG4gICAgICByZXR1cm4gbmV3IEdyYXBoLlJlZmVyZW5jZSh7XG4gICAgICAgIHN0b3JlLFxuICAgICAgICB1dWlkOiBnZW5lcmF0ZUNvbnNpc3RlbnRVVUlEKHVucmVzb2x2ZWQsIEdyYXBoLlJlZmVyZW5jZS5QUkVGSVgpLFxuICAgICAgICByZWZlcmVuY2VUeXBlOiBSZWZlcmVuY2VUeXBlRW51bS5SRUYsXG4gICAgICAgIHNvdXJjZSxcbiAgICAgICAgdGFyZ2V0LFxuICAgICAgfSk7XG4gICAgfVxuICAgIGNhc2UgUmVmZXJlbmNlVHlwZUVudW0uSU1QT1JUOiB7XG4gICAgICAvLyBpbXBvcnRzIGFscmVhZHkgY29udGFpbiB0aGUgc3RhY2sgaWQgKHN0YWNrOmxvZ2ljYWxJZClcbiAgICAgIHRhcmdldCA9IHN0b3JlLmZpbmROb2RlQnlMb2dpY2FsVW5pdmVyc2FsSWQoXG4gICAgICAgIHVucmVzb2x2ZWQudGFyZ2V0IGFzIExPR0lDQUxfVU5JVkVSU0FMX0lEXG4gICAgICApO1xuICAgICAgcmV0dXJuIG5ldyBHcmFwaC5JbXBvcnRSZWZlcmVuY2Uoe1xuICAgICAgICBzdG9yZSxcbiAgICAgICAgdXVpZDogZ2VuZXJhdGVDb25zaXN0ZW50VVVJRCh1bnJlc29sdmVkLCBHcmFwaC5JbXBvcnRSZWZlcmVuY2UuUFJFRklYKSxcbiAgICAgICAgc291cmNlLFxuICAgICAgICB0YXJnZXQsXG4gICAgICB9KTtcbiAgICB9XG4gICAgY2FzZSBSZWZlcmVuY2VUeXBlRW51bS5JTVBPUlRfQVJOOiB7XG4gICAgICBjb25zdCByZXNvbHZlZEltcG9ydEFybk5vZGUgPSBzdG9yZS5maW5kTm9kZUJ5SW1wb3J0QXJuKFxuICAgICAgICB1bnJlc29sdmVkLnRhcmdldFxuICAgICAgKTtcbiAgICAgIGlmICghcmVzb2x2ZWRJbXBvcnRBcm5Ob2RlKSB7XG4gICAgICAgIC8vIEltcG9ydEFybiB0b2tlbnMgYXJlIG5vdCBkaXJlY3QgbWF0Y2hlcywgc28gd2UgY2FuIHNhZmVseSBpZ25vcmUgbWlzc2VzLlxuICAgICAgICAvLyBXZSBvbmx5IGNhcmUgYWJvdXQgcmVzb3VyY2VzIGRpcmVjdGx5IGltcG9ydGVkIGludG8gdGhlIENESyBhcHAuXG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBuZXcgR3JhcGguSW1wb3J0UmVmZXJlbmNlKHtcbiAgICAgICAgc3RvcmUsXG4gICAgICAgIHV1aWQ6IGdlbmVyYXRlQ29uc2lzdGVudFVVSUQodW5yZXNvbHZlZCwgR3JhcGguSW1wb3J0UmVmZXJlbmNlLlBSRUZJWCksXG4gICAgICAgIHNvdXJjZSxcbiAgICAgICAgdGFyZ2V0OiByZXNvbHZlZEltcG9ydEFybk5vZGUsXG4gICAgICB9KTtcbiAgICB9XG4gICAgY2FzZSBSZWZlcmVuY2VUeXBlRW51bS5BVFRSSUJVVEU6IHtcbiAgICAgIGNvbnN0IGF0dHJpYnV0ZSA9IHVucmVzb2x2ZWQudmFsdWUgYXMgc3RyaW5nO1xuICAgICAgaWYgKGF0dHJpYnV0ZSAmJiBhdHRyaWJ1dGUuc3RhcnRzV2l0aChcIk91dHB1dHMuXCIpKSB7XG4gICAgICAgIC8vIFN0YWNrIG91dHB1dCByZWZlcmVuY2VcbiAgICAgICAgY29uc3Qgc3RhY2tzVG9TZWFyY2ggPSBzb3VyY2Uucm9vdFN0YWNrPy5zdGFnZT8uc3RhY2tzIHx8IHN0b3JlLnN0YWNrcztcbiAgICAgICAgY29uc3QgcG90ZW50aWFsUmVmU3RhY2tzID0gT2JqZWN0LnZhbHVlcyhzdGFja3NUb1NlYXJjaCkuZmlsdGVyKFxuICAgICAgICAgIChfc3RhY2spID0+IF9zdGFjay5sb2dpY2FsSWQgPT09IHVucmVzb2x2ZWQudGFyZ2V0XG4gICAgICAgICk7XG4gICAgICAgIGlmIChwb3RlbnRpYWxSZWZTdGFja3MubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgY29uc3QgcmVmU3RhY2sgPSBwb3RlbnRpYWxSZWZTdGFja3NbMF07XG4gICAgICAgICAgdGFyZ2V0ID0gcmVmU3RhY2suZmluZE91dHB1dChhdHRyaWJ1dGUucmVwbGFjZShcIk91dHB1dHMuXCIsIFwiXCIpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICBcIkZhaWxlZCB0byBmaW5kIGxvZ2ljYWwgaWQgZnJvbSBhdHRyaWJ1dGUgcmVmZXJlbmNlOlwiLFxuICAgICAgICAgICAgdW5yZXNvbHZlZC50YXJnZXRcbiAgICAgICAgICApO1xuICAgICAgICAgIGlmIChwb3RlbnRpYWxSZWZTdGFja3MubGVuZ3RoKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgIFwiRm91bmQgbXVsdGlwbGUgbWF0Y2hpbmcgc3RhY2tzOlwiLFxuICAgICAgICAgICAgICBPYmplY3QudmFsdWVzKHBvdGVudGlhbFJlZlN0YWNrcykubWFwKFxuICAgICAgICAgICAgICAgIChzdGFjaykgPT4gYCR7U3RyaW5nKHN0YWNrKX06JHtzdGFjay5sb2dpY2FsSWQgfHwgXCJST09UXCJ9YFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgIFwiQXZhaWxhYmxlIHN0YWNrczpcIixcbiAgICAgICAgICAgICAgT2JqZWN0LnZhbHVlcyhzdG9yZS5zdGFja3MpLm1hcChcbiAgICAgICAgICAgICAgICAoc3RhY2spID0+IGAke1N0cmluZyhzdGFjayl9OiR7c3RhY2subG9naWNhbElkIHx8IFwiUk9PVFwifWBcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgYEZhaWxlZCB0byBmaW5kIEZuOjpHZXRBdHQgc3RhY2sgZm9yIG91dHB1dCByZWZlcmVuY2UgXCIke3VucmVzb2x2ZWQudGFyZ2V0fVwiOiAke3BvdGVudGlhbFJlZlN0YWNrcy5sZW5ndGh9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRhcmdldCA9IHN0b3JlLmZpbmROb2RlQnlMb2dpY2FsSWQoc291cmNlLnN0YWNrLCB1bnJlc29sdmVkLnRhcmdldCk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0YXJnZXQpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBHcmFwaC5BdHRyaWJ1dGVSZWZlcmVuY2Uoe1xuICAgICAgICAgIHN0b3JlLFxuICAgICAgICAgIHV1aWQ6IGdlbmVyYXRlQ29uc2lzdGVudFVVSUQoXG4gICAgICAgICAgICB1bnJlc29sdmVkLFxuICAgICAgICAgICAgR3JhcGguQXR0cmlidXRlUmVmZXJlbmNlLlBSRUZJWFxuICAgICAgICAgICksXG4gICAgICAgICAgc291cmNlLFxuICAgICAgICAgIHRhcmdldCxcbiAgICAgICAgICB2YWx1ZTogYXR0cmlidXRlLFxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICB0aHJvdyBuZXcgRXJyb3IoYEZhaWxlZCB0byByZXNvbHZlIHJlZmVyZW5jZTogJHtKU09OLnN0cmluZ2lmeSh1bnJlc29sdmVkKX1gKTtcbn1cblxuLyoqXG4gKiBSZXNvbHZlIGRlcGVuZGVuY3kuIER1cmluZyBpbml0aWFsIGdyYXBoIHRyYXZlcnNhbCBub3QgYWxsIG5vZGVzIGhhdmUgYmVlbiBhZGRlZCBhdCB0aGUgdGltZVxuICogYSBkZXBlbmRlbmN5IGhhcyBiZWVuIGRldGVjdGVkLCBhcyBzdWNoIHdlIG5lZWQgdG8gcmVzb2x2ZSBhbGwgZGVwZW5kZW5jaWVzIGFmdGVyIHRoZSBncmFwaCB0cmVlXG4gKiBoYXMgYmVlbiBzdG9yZWQuXG4gKiBAaW50ZXJuYWxcbiAqL1xuZnVuY3Rpb24gcmVzb2x2ZURlcGVuZGVuY3koXG4gIHN0b3JlOiBHcmFwaC5TdG9yZSxcbiAgdW5yZXNvbHZlZDogVW5yZXNvbHZlZERlcGVuZGVuY3lcbik6IEdyYXBoLkRlcGVuZGVuY3kge1xuICBjb25zdCBzb3VyY2UgPSBzdG9yZS5nZXROb2RlKHVucmVzb2x2ZWRbMF0pO1xuICBjb25zdCB0YXJnZXQgPSBzdG9yZS5nZXROb2RlKHVucmVzb2x2ZWRbMV0pO1xuXG4gIHJldHVybiBuZXcgR3JhcGguRGVwZW5kZW5jeSh7XG4gICAgc3RvcmUsXG4gICAgdXVpZDogZ2VuZXJhdGVDb25zaXN0ZW50VVVJRCh1bnJlc29sdmVkLCBHcmFwaC5EZXBlbmRlbmN5LlBSRUZJWCksXG4gICAgc291cmNlLFxuICAgIHRhcmdldCxcbiAgfSk7XG59XG4iXX0=