aws-cdk
Version:
CDK Toolkit, the command line tool for CDK apps
342 lines • 45.8 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.WorkGraph = void 0;
const parallel_1 = require("./parallel");
const work_graph_types_1 = require("./work-graph-types");
const logging_1 = require("../logging");
const error_1 = require("../toolkit/error");
class WorkGraph {
constructor(nodes = {}) {
this.readyPool = [];
this.lazyDependencies = new Map();
this.nodes = { ...nodes };
}
addNodes(...nodes) {
for (const node of nodes) {
if (this.nodes[node.id]) {
throw new error_1.ToolkitError(`Duplicate use of node id: ${node.id}`);
}
const ld = this.lazyDependencies.get(node.id);
if (ld) {
for (const x of ld) {
node.dependencies.add(x);
}
this.lazyDependencies.delete(node.id);
}
this.nodes[node.id] = node;
}
}
removeNode(nodeId) {
const id = typeof nodeId === 'string' ? nodeId : nodeId.id;
const removedNode = this.nodes[id];
this.lazyDependencies.delete(id);
delete this.nodes[id];
if (removedNode) {
for (const node of Object.values(this.nodes)) {
node.dependencies.delete(removedNode.id);
}
}
}
/**
* Return all nodes of a given type
*/
nodesOfType(type) {
return Object.values(this.nodes).filter(n => n.type === type);
}
/**
* Return all nodes that depend on a given node
*/
dependees(nodeId) {
const id = typeof nodeId === 'string' ? nodeId : nodeId.id;
return Object.values(this.nodes).filter(n => n.dependencies.has(id));
}
/**
* Add a dependency, that may come before or after the nodes involved
*/
addDependency(fromId, toId) {
const node = this.nodes[fromId];
if (node) {
node.dependencies.add(toId);
return;
}
let lazyDeps = this.lazyDependencies.get(fromId);
if (!lazyDeps) {
lazyDeps = [];
this.lazyDependencies.set(fromId, lazyDeps);
}
lazyDeps.push(toId);
}
tryGetNode(id) {
return this.nodes[id];
}
node(id) {
const ret = this.nodes[id];
if (!ret) {
throw new error_1.ToolkitError(`No node with id ${id} among ${Object.keys(this.nodes)}`);
}
return ret;
}
absorb(graph) {
this.addNodes(...Object.values(graph.nodes));
}
hasFailed() {
return Object.values(this.nodes).some((n) => n.deploymentState === work_graph_types_1.DeploymentState.FAILED);
}
doParallel(concurrency, actions) {
return this.forAllArtifacts(concurrency, async (x) => {
switch (x.type) {
case 'stack':
await actions.deployStack(x);
break;
case 'asset-build':
await actions.buildAsset(x);
break;
case 'asset-publish':
await actions.publishAsset(x);
break;
}
});
}
/**
* Return the set of unblocked nodes
*/
ready() {
this.updateReadyPool();
return this.readyPool;
}
forAllArtifacts(n, fn) {
const graph = this;
// If 'n' is a number, we limit all concurrency equally (effectively we will be using totalMax)
// If 'n' is a record, we limit each job independently (effectively we will be using max)
const max = typeof n === 'number' ?
{
'asset-build': n,
'asset-publish': n,
'stack': n,
} : n;
const totalMax = typeof n === 'number' ? n : sum(Object.values(n));
return new Promise((ok, fail) => {
let active = {
'asset-build': 0,
'asset-publish': 0,
'stack': 0,
};
function totalActive() {
return sum(Object.values(active));
}
start();
function start() {
graph.updateReadyPool();
for (let i = 0; i < graph.readyPool.length;) {
const node = graph.readyPool[i];
if (active[node.type] < max[node.type] && totalActive() < totalMax) {
graph.readyPool.splice(i, 1);
startOne(node);
}
else {
i += 1;
}
}
if (totalActive() === 0) {
if (graph.done()) {
ok();
}
// wait for other active deploys to finish before failing
if (graph.hasFailed()) {
fail(graph.error);
}
}
}
function startOne(x) {
x.deploymentState = work_graph_types_1.DeploymentState.DEPLOYING;
active[x.type]++;
void fn(x)
.finally(() => {
active[x.type]--;
})
.then(() => {
graph.deployed(x);
start();
}).catch((err) => {
// By recording the failure immediately as the queued task exits, we prevent the next
// queued task from starting.
graph.failed(x, err);
start();
});
}
});
}
done() {
return Object.values(this.nodes).every((n) => work_graph_types_1.DeploymentState.COMPLETED === n.deploymentState);
}
deployed(node) {
node.deploymentState = work_graph_types_1.DeploymentState.COMPLETED;
}
failed(node, error) {
this.error = error;
node.deploymentState = work_graph_types_1.DeploymentState.FAILED;
this.skipRest();
this.readyPool.splice(0);
}
toString() {
return [
'digraph D {',
...Object.entries(this.nodes).flatMap(([id, node]) => renderNode(id, node)),
'}',
].join('\n');
function renderNode(id, node) {
const ret = [];
if (node.deploymentState === work_graph_types_1.DeploymentState.COMPLETED) {
ret.push(` ${gv(id, { style: 'filled', fillcolor: 'yellow', comment: node.note })};`);
}
else {
ret.push(` ${gv(id, { comment: node.note })};`);
}
for (const dep of node.dependencies) {
ret.push(` ${gv(id)} -> ${gv(dep)};`);
}
return ret;
}
}
/**
* Ensure all dependencies actually exist. This protects against scenarios such as the following:
* StackA depends on StackB, but StackB is not selected to deploy. The dependency is redundant
* and will be dropped.
* This assumes the manifest comes uncorrupted so we will not fail if a dependency is not found.
*/
removeUnavailableDependencies() {
for (const node of Object.values(this.nodes)) {
const removeDeps = Array.from(node.dependencies).filter((dep) => this.nodes[dep] === undefined);
removeDeps.forEach((d) => {
node.dependencies.delete(d);
});
}
}
/**
* Remove all asset publishing steps for assets that are already published, and then build
* that aren't used anymore.
*
* Do this in parallel, because there may be a lot of assets in an application (seen in practice: >100 assets)
*/
async removeUnnecessaryAssets(isUnnecessary) {
(0, logging_1.debug)('Checking for previously published assets');
const publishes = this.nodesOfType('asset-publish');
const classifiedNodes = await (0, parallel_1.parallelPromises)(8, publishes.map((assetNode) => async () => [assetNode, await isUnnecessary(assetNode)]));
const alreadyPublished = classifiedNodes.filter(([_, unnecessary]) => unnecessary).map(([assetNode, _]) => assetNode);
for (const assetNode of alreadyPublished) {
this.removeNode(assetNode);
}
(0, logging_1.debug)(`${publishes.length} total assets, ${publishes.length - alreadyPublished.length} still need to be published`);
// Now also remove any asset build steps that don't have any dependencies on them anymore
const unusedBuilds = this.nodesOfType('asset-build').filter(build => this.dependees(build).length === 0);
for (const unusedBuild of unusedBuilds) {
this.removeNode(unusedBuild);
}
}
updateReadyPool() {
const activeCount = Object.values(this.nodes).filter((x) => x.deploymentState === work_graph_types_1.DeploymentState.DEPLOYING).length;
const pendingCount = Object.values(this.nodes).filter((x) => x.deploymentState === work_graph_types_1.DeploymentState.PENDING).length;
const newlyReady = Object.values(this.nodes).filter((x) => x.deploymentState === work_graph_types_1.DeploymentState.PENDING &&
Array.from(x.dependencies).every((id) => this.node(id).deploymentState === work_graph_types_1.DeploymentState.COMPLETED));
// Add newly available nodes to the ready pool
for (const node of newlyReady) {
node.deploymentState = work_graph_types_1.DeploymentState.QUEUED;
this.readyPool.push(node);
}
// Remove nodes from the ready pool that have already started deploying
retainOnly(this.readyPool, (node) => node.deploymentState === work_graph_types_1.DeploymentState.QUEUED);
// Sort by reverse priority
this.readyPool.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
if (this.readyPool.length === 0 && activeCount === 0 && pendingCount > 0) {
const cycle = this.findCycle() ?? ['No cycle found!'];
(0, logging_1.trace)(`Cycle ${cycle.join(' -> ')} in graph ${this}`);
throw new error_1.ToolkitError(`Unable to make progress anymore, dependency cycle between remaining artifacts: ${cycle.join(' -> ')} (run with -vv for full graph)`);
}
}
skipRest() {
for (const node of Object.values(this.nodes)) {
if ([work_graph_types_1.DeploymentState.QUEUED, work_graph_types_1.DeploymentState.PENDING].includes(node.deploymentState)) {
node.deploymentState = work_graph_types_1.DeploymentState.SKIPPED;
}
}
}
/**
* Find cycles in a graph
*
* Not the fastest, but effective and should be rare
*/
findCycle() {
const seen = new Set();
const self = this;
for (const nodeId of Object.keys(this.nodes)) {
const cycle = recurse(nodeId, [nodeId]);
if (cycle) {
return cycle;
}
}
return undefined;
function recurse(nodeId, path) {
if (seen.has(nodeId)) {
return undefined;
}
try {
for (const dep of self.nodes[nodeId].dependencies ?? []) {
const index = path.indexOf(dep);
if (index > -1) {
return [...path.slice(index), dep];
}
const cycle = recurse(dep, [...path, dep]);
if (cycle) {
return cycle;
}
}
return undefined;
}
finally {
seen.add(nodeId);
}
}
}
/**
* Whether the `end` node is reachable from the `start` node, following the dependency arrows
*/
reachable(start, end) {
const seen = new Set();
const self = this;
return recurse(start);
function recurse(current) {
if (seen.has(current)) {
return false;
}
seen.add(current);
if (current === end) {
return true;
}
for (const dep of self.nodes[current].dependencies) {
if (recurse(dep)) {
return true;
}
}
return false;
}
}
}
exports.WorkGraph = WorkGraph;
function sum(xs) {
let ret = 0;
for (const x of xs) {
ret += x;
}
return ret;
}
function retainOnly(xs, pred) {
xs.splice(0, xs.length, ...xs.filter(pred));
}
function gv(id, attrs) {
const attrString = Object.entries(attrs ?? {}).flatMap(([k, v]) => v !== undefined ? [`${k}="${v}"`] : []).join(',');
return attrString ? `"${simplifyId(id)}" [${attrString}]` : `"${simplifyId(id)}"`;
}
function simplifyId(id) {
return id.replace(/([0-9a-f]{6})[0-9a-f]{6,}/g, '$1');
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid29yay1ncmFwaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIndvcmstZ3JhcGgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEseUNBQThDO0FBQzlDLHlEQUE0RztBQUM1Ryx3Q0FBMEM7QUFDMUMsNENBQWdEO0FBSWhELE1BQWEsU0FBUztJQU1wQixZQUFtQixRQUFrQyxFQUFFO1FBSnRDLGNBQVMsR0FBb0IsRUFBRSxDQUFDO1FBQ2hDLHFCQUFnQixHQUFHLElBQUksR0FBRyxFQUFvQixDQUFDO1FBSTlELElBQUksQ0FBQyxLQUFLLEdBQUcsRUFBRSxHQUFHLEtBQUssRUFBRSxDQUFDO0lBQzVCLENBQUM7SUFFTSxRQUFRLENBQUMsR0FBRyxLQUFpQjtRQUNsQyxLQUFLLE1BQU0sSUFBSSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3pCLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztnQkFDeEIsTUFBTSxJQUFJLG9CQUFZLENBQUMsNkJBQTZCLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ2pFLENBQUM7WUFFRCxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUM5QyxJQUFJLEVBQUUsRUFBRSxDQUFDO2dCQUNQLEtBQUssTUFBTSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7b0JBQ25CLElBQUksQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUMzQixDQUFDO2dCQUNELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1lBQ3hDLENBQUM7WUFFRCxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxJQUFJLENBQUM7UUFDN0IsQ0FBQztJQUNILENBQUM7SUFFTSxVQUFV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VSxDQUFDLEVBQUUsQ0FBQyxNQUFNLFVBQVUsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLFVBQVUsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO0FBQ3BGLENBQUM7QUFFRCxTQUFTLFVBQVUsQ0FBQyxFQUFVO0lBQzVCLE9BQU8sRUFBRSxDQUFDLE9BQU8sQ0FBQyw0QkFBNEIsRUFBRSxJQUFJLENBQUMsQ0FBQztBQUN4RCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcGFyYWxsZWxQcm9taXNlcyB9IGZyb20gJy4vcGFyYWxsZWwnO1xuaW1wb3J0IHsgV29ya05vZGUsIERlcGxveW1lbnRTdGF0ZSwgU3RhY2tOb2RlLCBBc3NldEJ1aWxkTm9kZSwgQXNzZXRQdWJsaXNoTm9kZSB9IGZyb20gJy4vd29yay1ncmFwaC10eXBlcyc7XG5pbXBvcnQgeyBkZWJ1ZywgdHJhY2UgfSBmcm9tICcuLi9sb2dnaW5nJztcbmltcG9ydCB7IFRvb2xraXRFcnJvciB9IGZyb20gJy4uL3Rvb2xraXQvZXJyb3InO1xuXG5leHBvcnQgdHlwZSBDb25jdXJyZW5jeSA9IG51bWJlciB8IFJlY29yZDxXb3JrTm9kZVsndHlwZSddLCBudW1iZXI+O1xuXG5leHBvcnQgY2xhc3MgV29ya0dyYXBoIHtcbiAgcHVibGljIHJlYWRvbmx5IG5vZGVzOiBSZWNvcmQ8c3RyaW5nLCBXb3JrTm9kZT47XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVhZHlQb29sOiBBcnJheTxXb3JrTm9kZT4gPSBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBsYXp5RGVwZW5kZW5jaWVzID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZ1tdPigpO1xuICBwdWJsaWMgZXJyb3I/OiBFcnJvcjtcblxuICBwdWJsaWMgY29uc3RydWN0b3Iobm9kZXM6IFJlY29yZDxzdHJpbmcsIFdvcmtOb2RlPiA9IHt9KSB7XG4gICAgdGhpcy5ub2RlcyA9IHsgLi4ubm9kZXMgfTtcbiAgfVxuXG4gIHB1YmxpYyBhZGROb2RlcyguLi5ub2RlczogV29ya05vZGVbXSkge1xuICAgIGZvciAoY29uc3Qgbm9kZSBvZiBub2Rlcykge1xuICAgICAgaWYgKHRoaXMubm9kZXNbbm9kZS5pZF0pIHtcbiAgICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcihgRHVwbGljYXRlIHVzZSBvZiBub2RlIGlkOiAke25vZGUuaWR9YCk7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGxkID0gdGhpcy5sYXp5RGVwZW5kZW5jaWVzLmdldChub2RlLmlkKTtcbiAgICAgIGlmIChsZCkge1xuICAgICAgICBmb3IgKGNvbnN0IHggb2YgbGQpIHtcbiAgICAgICAgICBub2RlLmRlcGVuZGVuY2llcy5hZGQoeCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5sYXp5RGVwZW5kZW5jaWVzLmRlbGV0ZShub2RlLmlkKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5ub2Rlc1tub2RlLmlkXSA9IG5vZGU7XG4gICAgfVxuICB9XG5cbiAgcHVibGljIHJlbW92ZU5vZGUobm9kZUlkOiBzdHJpbmcgfCBXb3JrTm9kZSkge1xuICAgIGNvbnN0IGlkID0gdHlwZW9mIG5vZGVJZCA9PT0gJ3N0cmluZycgPyBub2RlSWQgOiBub2RlSWQuaWQ7XG4gICAgY29uc3QgcmVtb3ZlZE5vZGUgPSB0aGlzLm5vZGVzW2lkXTtcblxuICAgIHRoaXMubGF6eURlcGVuZGVuY2llcy5kZWxldGUoaWQpO1xuICAgIGRlbGV0ZSB0aGlzLm5vZGVzW2lkXTtcblxuICAgIGlmIChyZW1vdmVkTm9kZSkge1xuICAgICAgZm9yIChjb25zdCBub2RlIG9mIE9iamVjdC52YWx1ZXModGhpcy5ub2RlcykpIHtcbiAgICAgICAgbm9kZS5kZXBlbmRlbmNpZXMuZGVsZXRlKHJlbW92ZWROb2RlLmlkKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGFsbCBub2RlcyBvZiBhIGdpdmVuIHR5cGVcbiAgICovXG4gIHB1YmxpYyBub2Rlc09mVHlwZTxUIGV4dGVuZHMgV29ya05vZGVbJ3R5cGUnXT4odHlwZTogVCk6IEV4dHJhY3Q8V29ya05vZGUsIHsgdHlwZTogVCB9PltdIHtcbiAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyh0aGlzLm5vZGVzKS5maWx0ZXIobiA9PiBuLnR5cGUgPT09IHR5cGUpIGFzIGFueTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYWxsIG5vZGVzIHRoYXQgZGVwZW5kIG9uIGEgZ2l2ZW4gbm9kZVxuICAgKi9cbiAgcHVibGljIGRlcGVuZGVlcyhub2RlSWQ6IHN0cmluZyB8IFdvcmtOb2RlKSB7XG4gICAgY29uc3QgaWQgPSB0eXBlb2Ygbm9kZUlkID09PSAnc3RyaW5nJyA/IG5vZGVJZCA6IG5vZGVJZC5pZDtcbiAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyh0aGlzLm5vZGVzKS5maWx0ZXIobiA9PiBuLmRlcGVuZGVuY2llcy5oYXMoaWQpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBkZXBlbmRlbmN5LCB0aGF0IG1heSBjb21lIGJlZm9yZSBvciBhZnRlciB0aGUgbm9kZXMgaW52b2x2ZWRcbiAgICovXG4gIHB1YmxpYyBhZGREZXBlbmRlbmN5KGZyb21JZDogc3RyaW5nLCB0b0lkOiBzdHJpbmcpIHtcbiAgICBjb25zdCBub2RlID0gdGhpcy5ub2Rlc1tmcm9tSWRdO1xuICAgIGlmIChub2RlKSB7XG4gICAgICBub2RlLmRlcGVuZGVuY2llcy5hZGQodG9JZCk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGxldCBsYXp5RGVwcyA9IHRoaXMubGF6eURlcGVuZGVuY2llcy5nZXQoZnJvbUlkKTtcbiAgICBpZiAoIWxhenlEZXBzKSB7XG4gICAgICBsYXp5RGVwcyA9IFtdO1xuICAgICAgdGhpcy5sYXp5RGVwZW5kZW5jaWVzLnNldChmcm9tSWQsIGxhenlEZXBzKTtcbiAgICB9XG4gICAgbGF6eURlcHMucHVzaCh0b0lkKTtcbiAgfVxuXG4gIHB1YmxpYyB0cnlHZXROb2RlKGlkOiBzdHJpbmcpOiBXb3JrTm9kZSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMubm9kZXNbaWRdO1xuICB9XG5cbiAgcHVibGljIG5vZGUoaWQ6IHN0cmluZykge1xuICAgIGNvbnN0IHJldCA9IHRoaXMubm9kZXNbaWRdO1xuICAgIGlmICghcmV0KSB7XG4gICAgICB0aHJvdyBuZXcgVG9vbGtpdEVycm9yKGBObyBub2RlIHdpdGggaWQgJHtpZH0gYW1vbmcgJHtPYmplY3Qua2V5cyh0aGlzLm5vZGVzKX1gKTtcbiAgICB9XG4gICAgcmV0dXJuIHJldDtcbiAgfVxuXG4gIHB1YmxpYyBhYnNvcmIoZ3JhcGg6IFdvcmtHcmFwaCkge1xuICAgIHRoaXMuYWRkTm9kZXMoLi4uT2JqZWN0LnZhbHVlcyhncmFwaC5ub2RlcykpO1xuICB9XG5cbiAgcHJpdmF0ZSBoYXNGYWlsZWQoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIE9iamVjdC52YWx1ZXModGhpcy5ub2Rlcykuc29tZSgobikgPT4gbi5kZXBsb3ltZW50U3RhdGUgPT09IERlcGxveW1lbnRTdGF0ZS5GQUlMRUQpO1xuICB9XG5cbiAgcHVibGljIGRvUGFyYWxsZWwoY29uY3VycmVuY3k6IENvbmN1cnJlbmN5LCBhY3Rpb25zOiBXb3JrR3JhcGhBY3Rpb25zKSB7XG4gICAgcmV0dXJuIHRoaXMuZm9yQWxsQXJ0aWZhY3RzKGNvbmN1cnJlbmN5LCBhc3luYyAoeDogV29ya05vZGUpID0+IHtcbiAgICAgIHN3aXRjaCAoeC50eXBlKSB7XG4gICAgICAgIGNhc2UgJ3N0YWNrJzpcbiAgICAgICAgICBhd2FpdCBhY3Rpb25zLmRlcGxveVN0YWNrKHgpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdhc3NldC1idWlsZCc6XG4gICAgICAgICAgYXdhaXQgYWN0aW9ucy5idWlsZEFzc2V0KHgpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdhc3NldC1wdWJsaXNoJzpcbiAgICAgICAgICBhd2FpdCBhY3Rpb25zLnB1Ymxpc2hBc3NldCh4KTtcbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIHNldCBvZiB1bmJsb2NrZWQgbm9kZXNcbiAgICovXG4gIHB1YmxpYyByZWFkeSgpOiBSZWFkb25seUFycmF5PFdvcmtOb2RlPiB7XG4gICAgdGhpcy51cGRhdGVSZWFkeVBvb2woKTtcbiAgICByZXR1cm4gdGhpcy5yZWFkeVBvb2w7XG4gIH1cblxuICBwcml2YXRlIGZvckFsbEFydGlmYWN0cyhuOiBDb25jdXJyZW5jeSwgZm46ICh4OiBXb3JrTm9kZSkgPT4gUHJvbWlzZTx2b2lkPik6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IGdyYXBoID0gdGhpcztcblxuICAgIC8vIElmICduJyBpcyBhIG51bWJlciwgd2UgbGltaXQgYWxsIGNvbmN1cnJlbmN5IGVxdWFsbHkgKGVmZmVjdGl2ZWx5IHdlIHdpbGwgYmUgdXNpbmcgdG90YWxNYXgpXG4gICAgLy8gSWYgJ24nIGlzIGEgcmVjb3JkLCB3ZSBsaW1pdCBlYWNoIGpvYiBpbmRlcGVuZGVudGx5IChlZmZlY3RpdmVseSB3ZSB3aWxsIGJlIHVzaW5nIG1heClcbiAgICBjb25zdCBtYXg6IFJlY29yZDxXb3JrTm9kZVsndHlwZSddLCBudW1iZXI+ID0gdHlwZW9mIG4gPT09ICdudW1iZXInID9cbiAgICAgIHtcbiAgICAgICAgJ2Fzc2V0LWJ1aWxkJzogbixcbiAgICAgICAgJ2Fzc2V0LXB1Ymxpc2gnOiBuLFxuICAgICAgICAnc3RhY2snOiBuLFxuICAgICAgfSA6IG47XG4gICAgY29uc3QgdG90YWxNYXggPSB0eXBlb2YgbiA9PT0gJ251bWJlcicgPyBuIDogc3VtKE9iamVjdC52YWx1ZXMobikpO1xuXG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChvaywgZmFpbCkgPT4ge1xuICAgICAgbGV0IGFjdGl2ZTogUmVjb3JkPFdvcmtOb2RlWyd0eXBlJ10sIG51bWJlcj4gPSB7XG4gICAgICAgICdhc3NldC1idWlsZCc6IDAsXG4gICAgICAgICdhc3NldC1wdWJsaXNoJzogMCxcbiAgICAgICAgJ3N0YWNrJzogMCxcbiAgICAgIH07XG4gICAgICBmdW5jdGlvbiB0b3RhbEFjdGl2ZSgpIHtcbiAgICAgICAgcmV0dXJuIHN1bShPYmplY3QudmFsdWVzKGFjdGl2ZSkpO1xuICAgICAgfVxuXG4gICAgICBzdGFydCgpO1xuXG4gICAgICBmdW5jdGlvbiBzdGFydCgpIHtcbiAgICAgICAgZ3JhcGgudXBkYXRlUmVhZHlQb29sKCk7XG5cbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBncmFwaC5yZWFkeVBvb2wubGVuZ3RoOyApIHtcbiAgICAgICAgICBjb25zdCBub2RlID0gZ3JhcGgucmVhZHlQb29sW2ldO1xuXG4gICAgICAgICAgaWYgKGFjdGl2ZVtub2RlLnR5cGVdIDwgbWF4W25vZGUudHlwZV0gJiYgdG90YWxBY3RpdmUoKSA8IHRvdGFsTWF4KSB7XG4gICAgICAgICAgICBncmFwaC5yZWFkeVBvb2wuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgc3RhcnRPbmUobm9kZSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGkgKz0gMTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodG90YWxBY3RpdmUoKSA9PT0gMCkge1xuICAgICAgICAgIGlmIChncmFwaC5kb25lKCkpIHtcbiAgICAgICAgICAgIG9rKCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIC8vIHdhaXQgZm9yIG90aGVyIGFjdGl2ZSBkZXBsb3lzIHRvIGZpbmlzaCBiZWZvcmUgZmFpbGluZ1xuICAgICAgICAgIGlmIChncmFwaC5oYXNGYWlsZWQoKSkge1xuICAgICAgICAgICAgZmFpbChncmFwaC5lcnJvcik7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGZ1bmN0aW9uIHN0YXJ0T25lKHg6IFdvcmtOb2RlKSB7XG4gICAgICAgIHguZGVwbG95bWVudFN0YXRlID0gRGVwbG95bWVudFN0YXRlLkRFUExPWUlORztcbiAgICAgICAgYWN0aXZlW3gudHlwZV0rKztcbiAgICAgICAgdm9pZCBmbih4KVxuICAgICAgICAgIC5maW5hbGx5KCgpID0+IHtcbiAgICAgICAgICAgIGFjdGl2ZVt4LnR5cGVdLS07XG4gICAgICAgICAgfSlcbiAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICBncmFwaC5kZXBsb3llZCh4KTtcbiAgICAgICAgICAgIHN0YXJ0KCk7XG4gICAgICAgICAgfSkuY2F0Y2goKGVycikgPT4ge1xuICAgICAgICAgICAgLy8gQnkgcmVjb3JkaW5nIHRoZSBmYWlsdXJlIGltbWVkaWF0ZWx5IGFzIHRoZSBxdWV1ZWQgdGFzayBleGl0cywgd2UgcHJldmVudCB0aGUgbmV4dFxuICAgICAgICAgICAgLy8gcXVldWVkIHRhc2sgZnJvbSBzdGFydGluZy5cbiAgICAgICAgICAgIGdyYXBoLmZhaWxlZCh4LCBlcnIpO1xuICAgICAgICAgICAgc3RhcnQoKTtcbiAgICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgZG9uZSgpOiBib29sZWFuIHtcbiAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyh0aGlzLm5vZGVzKS5ldmVyeSgobikgPT4gRGVwbG95bWVudFN0YXRlLkNPTVBMRVRFRCA9PT0gbi5kZXBsb3ltZW50U3RhdGUpO1xuICB9XG5cbiAgcHJpdmF0ZSBkZXBsb3llZChub2RlOiBXb3JrTm9kZSkge1xuICAgIG5vZGUuZGVwbG95bWVudFN0YXRlID0gRGVwbG95bWVudFN0YXRlLkNPTVBMRVRFRDtcbiAgfVxuXG4gIHByaXZhdGUgZmFpbGVkKG5vZGU6IFdvcmtOb2RlLCBlcnJvcj86IEVycm9yKSB7XG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xuICAgIG5vZGUuZGVwbG95bWVudFN0YXRlID0gRGVwbG95bWVudFN0YXRlLkZBSUxFRDtcbiAgICB0aGlzLnNraXBSZXN0KCk7XG4gICAgdGhpcy5yZWFkeVBvb2wuc3BsaWNlKDApO1xuICB9XG5cbiAgcHVibGljIHRvU3RyaW5nKCkge1xuICAgIHJldHVybiBbXG4gICAgICAnZGlncmFwaCBEIHsnLFxuICAgICAgLi4uT2JqZWN0LmVudHJpZXModGhpcy5ub2RlcykuZmxhdE1hcCgoW2lkLCBub2RlXSkgPT4gcmVuZGVyTm9kZShpZCwgbm9kZSkpLFxuICAgICAgJ30nLFxuICAgIF0uam9pbignXFxuJyk7XG5cbiAgICBmdW5jdGlvbiByZW5kZXJOb2RlKGlkOiBzdHJpbmcsIG5vZGU6IFdvcmtOb2RlKTogc3RyaW5nW10ge1xuICAgICAgY29uc3QgcmV0ID0gW107XG4gICAgICBpZiAobm9kZS5kZXBsb3ltZW50U3RhdGUgPT09IERlcGxveW1lbnRTdGF0ZS5DT01QTEVURUQpIHtcbiAgICAgICAgcmV0LnB1c2goYCAgJHtndihpZCwgeyBzdHlsZTogJ2ZpbGxlZCcsIGZpbGxjb2xvcjogJ3llbGxvdycsIGNvbW1lbnQ6IG5vZGUubm90ZSB9KX07YCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXQucHVzaChgICAke2d2KGlkLCB7IGNvbW1lbnQ6IG5vZGUubm90ZSB9KX07YCk7XG4gICAgICB9XG4gICAgICBmb3IgKGNvbnN0IGRlcCBvZiBub2RlLmRlcGVuZGVuY2llcykge1xuICAgICAgICByZXQucHVzaChgICAke2d2KGlkKX0gLT4gJHtndihkZXApfTtgKTtcbiAgICAgIH1cbiAgICAgIHJldHVybiByZXQ7XG4gICAgfVxuXG4gIH1cblxuICAvKipcbiAgICogRW5zdXJlIGFsbCBkZXBlbmRlbmNpZXMgYWN0dWFsbHkgZXhpc3QuIFRoaXMgcHJvdGVjdHMgYWdhaW5zdCBzY2VuYXJpb3Mgc3VjaCBhcyB0aGUgZm9sbG93aW5nOlxuICAgKiBTdGFja0EgZGVwZW5kcyBvbiBTdGFja0IsIGJ1dCBTdGFja0IgaXMgbm90IHNlbGVjdGVkIHRvIGRlcGxveS4gVGhlIGRlcGVuZGVuY3kgaXMgcmVkdW5kYW50XG4gICAqIGFuZCB3aWxsIGJlIGRyb3BwZWQuXG4gICAqIFRoaXMgYXNzdW1lcyB0aGUgbWFuaWZlc3QgY29tZXMgdW5jb3JydXB0ZWQgc28gd2Ugd2lsbCBub3QgZmFpbCBpZiBhIGRlcGVuZGVuY3kgaXMgbm90IGZvdW5kLlxuICAgKi9cbiAgcHVibGljIHJlbW92ZVVuYXZhaWxhYmxlRGVwZW5kZW5jaWVzKCkge1xuICAgIGZvciAoY29uc3Qgbm9kZSBvZiBPYmplY3QudmFsdWVzKHRoaXMubm9kZXMpKSB7XG4gICAgICBjb25zdCByZW1vdmVEZXBzID0gQXJyYXkuZnJvbShub2RlLmRlcGVuZGVuY2llcykuZmlsdGVyKChkZXApID0+IHRoaXMubm9kZXNbZGVwXSA9PT0gdW5kZWZpbmVkKTtcblxuICAgICAgcmVtb3ZlRGVwcy5mb3JFYWNoKChkKSA9PiB7XG4gICAgICAgIG5vZGUuZGVwZW5kZW5jaWVzLmRlbGV0ZShkKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgYWxsIGFzc2V0IHB1Ymxpc2hpbmcgc3RlcHMgZm9yIGFzc2V0cyB0aGF0IGFyZSBhbHJlYWR5IHB1Ymxpc2hlZCwgYW5kIHRoZW4gYnVpbGRcbiAgICogdGhhdCBhcmVuJ3QgdXNlZCBhbnltb3JlLlxuICAgKlxuICAgKiBEbyB0aGlzIGluIHBhcmFsbGVsLCBiZWNhdXNlIHRoZXJlIG1heSBiZSBhIGxvdCBvZiBhc3NldHMgaW4gYW4gYXBwbGljYXRpb24gKHNlZW4gaW4gcHJhY3RpY2U6ID4xMDAgYXNzZXRzKVxuICAgKi9cbiAgcHVibGljIGFzeW5jIHJlbW92ZVVubmVjZXNzYXJ5QXNzZXRzKGlzVW5uZWNlc3Nhcnk6ICh4OiBBc3NldFB1Ymxpc2hOb2RlKSA9PiBQcm9taXNlPGJvb2xlYW4+KSB7XG4gICAgZGVidWcoJ0NoZWNraW5nIGZvciBwcmV2aW91c2x5IHB1Ymxpc2hlZCBhc3NldHMnKTtcblxuICAgIGNvbnN0IHB1Ymxpc2hlcyA9IHRoaXMubm9kZXNPZlR5cGUoJ2Fzc2V0LXB1Ymxpc2gnKTtcblxuICAgIGNvbnN0IGNsYXNzaWZpZWROb2RlcyA9IGF3YWl0IHBhcmFsbGVsUHJvbWlzZXMoXG4gICAgICA4LFxuICAgICAgcHVibGlzaGVzLm1hcCgoYXNzZXROb2RlKSA9PiBhc3luYygpID0+IFthc3NldE5vZGUsIGF3YWl0IGlzVW5uZWNlc3NhcnkoYXNzZXROb2RlKV0gYXMgY29uc3QpKTtcblxuICAgIGNvbnN0IGFscmVhZHlQdWJsaXNoZWQgPSBjbGFzc2lmaWVkTm9kZXMuZmlsdGVyKChbXywgdW5uZWNlc3NhcnldKSA9PiB1bm5lY2Vzc2FyeSkubWFwKChbYXNzZXROb2RlLCBfXSkgPT4gYXNzZXROb2RlKTtcbiAgICBmb3IgKGNvbnN0IGFzc2V0Tm9kZSBvZiBhbHJlYWR5UHVibGlzaGVkKSB7XG4gICAgICB0aGlzLnJlbW92ZU5vZGUoYXNzZXROb2RlKTtcbiAgICB9XG5cbiAgICBkZWJ1ZyhgJHtwdWJsaXNoZXMubGVuZ3RofSB0b3RhbCBhc3NldHMsICR7cHVibGlzaGVzLmxlbmd0aCAtIGFscmVhZHlQdWJsaXNoZWQubGVuZ3RofSBzdGlsbCBuZWVkIHRvIGJlIHB1Ymxpc2hlZGApO1xuXG4gICAgLy8gTm93IGFsc28gcmVtb3ZlIGFueSBhc3NldCBidWlsZCBzdGVwcyB0aGF0IGRvbid0IGhhdmUgYW55IGRlcGVuZGVuY2llcyBvbiB0aGVtIGFueW1vcmVcbiAgICBjb25zdCB1bnVzZWRCdWlsZHMgPSB0aGlzLm5vZGVzT2ZUeXBlKCdhc3NldC1idWlsZCcpLmZpbHRlcihidWlsZCA9PiB0aGlzLmRlcGVuZGVlcyhidWlsZCkubGVuZ3RoID09PSAwKTtcbiAgICBmb3IgKGNvbnN0IHVudXNlZEJ1aWxkIG9mIHVudXNlZEJ1aWxkcykge1xuICAgICAgdGhpcy5yZW1vdmVOb2RlKHVudXNlZEJ1aWxkKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZVJlYWR5UG9vbCgpIHtcbiAgICBjb25zdCBhY3RpdmVDb3VudCA9IE9iamVjdC52YWx1ZXModGhpcy5ub2RlcykuZmlsdGVyKCh4KSA9PiB4LmRlcGxveW1lbnRTdGF0ZSA9PT0gRGVwbG95bWVudFN0YXRlLkRFUExPWUlORykubGVuZ3RoO1xuICAgIGNvbnN0IHBlbmRpbmdDb3VudCA9IE9iamVjdC52YWx1ZXModGhpcy5ub2RlcykuZmlsdGVyKCh4KSA9PiB4LmRlcGxveW1lbnRTdGF0ZSA9PT0gRGVwbG95bWVudFN0YXRlLlBFTkRJTkcpLmxlbmd0aDtcblxuICAgIGNvbnN0IG5ld2x5UmVhZHkgPSBPYmplY3QudmFsdWVzKHRoaXMubm9kZXMpLmZpbHRlcigoeCkgPT5cbiAgICAgIHguZGVwbG95bWVudFN0YXRlID09PSBEZXBsb3ltZW50U3RhdGUuUEVORElORyAmJlxuICAgICAgQXJyYXkuZnJvbSh4LmRlcGVuZGVuY2llcykuZXZlcnkoKGlkKSA9PiB0aGlzLm5vZGUoaWQpLmRlcGxveW1lbnRTdGF0ZSA9PT0gRGVwbG95bWVudFN0YXRlLkNPTVBMRVRFRCkpO1xuXG4gICAgLy8gQWRkIG5ld2x5IGF2YWlsYWJsZSBub2RlcyB0byB0aGUgcmVhZHkgcG9vbFxuICAgIGZvciAoY29uc3Qgbm9kZSBvZiBuZXdseVJlYWR5KSB7XG4gICAgICBub2RlLmRlcGxveW1lbnRTdGF0ZSA9IERlcGxveW1lbnRTdGF0ZS5RVUVVRUQ7XG4gICAgICB0aGlzLnJlYWR5UG9vbC5wdXNoKG5vZGUpO1xuICAgIH1cblxuICAgIC8vIFJlbW92ZSBub2RlcyBmcm9tIHRoZSByZWFkeSBwb29sIHRoYXQgaGF2ZSBhbHJlYWR5IHN0YXJ0ZWQgZGVwbG95aW5nXG4gICAgcmV0YWluT25seSh0aGlzLnJlYWR5UG9vbCwgKG5vZGUpID0+IG5vZGUuZGVwbG95bWVudFN0YXRlID09PSBEZXBsb3ltZW50U3RhdGUuUVVFVUVEKTtcblxuICAgIC8vIFNvcnQgYnkgcmV2ZXJzZSBwcmlvcml0eVxuICAgIHRoaXMucmVhZHlQb29sLnNvcnQoKGEsIGIpID0+IChiLnByaW9yaXR5ID8/IDApIC0gKGEucHJpb3JpdHkgPz8gMCkpO1xuXG4gICAgaWYgKHRoaXMucmVhZHlQb29sLmxlbmd0aCA9PT0gMCAmJiBhY3RpdmVDb3VudCA9PT0gMCAmJiBwZW5kaW5nQ291bnQgPiAwKSB7XG4gICAgICBjb25zdCBjeWNsZSA9IHRoaXMuZmluZEN5Y2xlKCkgPz8gWydObyBjeWNsZSBmb3VuZCEnXTtcbiAgICAgIHRyYWNlKGBDeWNsZSAke2N5Y2xlLmpvaW4oJyAtPiAnKX0gaW4gZ3JhcGggJHt0aGlzfWApO1xuICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcihgVW5hYmxlIHRvIG1ha2UgcHJvZ3Jlc3MgYW55bW9yZSwgZGVwZW5kZW5jeSBjeWNsZSBiZXR3ZWVuIHJlbWFpbmluZyBhcnRpZmFjdHM6ICR7Y3ljbGUuam9pbignIC0+ICcpfSAocnVuIHdpdGggLXZ2IGZvciBmdWxsIGdyYXBoKWApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgc2tpcFJlc3QoKSB7XG4gICAgZm9yIChjb25zdCBub2RlIG9mIE9iamVjdC52YWx1ZXModGhpcy5ub2RlcykpIHtcbiAgICAgIGlmIChbRGVwbG95bWVudFN0YXRlLlFVRVVFRCwgRGVwbG95bWVudFN0YXRlLlBFTkRJTkddLmluY2x1ZGVzKG5vZGUuZGVwbG95bWVudFN0YXRlKSkge1xuICAgICAgICBub2RlLmRlcGxveW1lbnRTdGF0ZSA9IERlcGxveW1lbnRTdGF0ZS5TS0lQUEVEO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5kIGN5Y2xlcyBpbiBhIGdyYXBoXG4gICAqXG4gICAqIE5vdCB0aGUgZmFzdGVzdCwgYnV0IGVmZmVjdGl2ZSBhbmQgc2hvdWxkIGJlIHJhcmVcbiAgICovXG4gIHB1YmxpYyBmaW5kQ3ljbGUoKTogc3RyaW5nW10gfCB1bmRlZmluZWQge1xuICAgIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICBmb3IgKGNvbnN0IG5vZGVJZCBvZiBPYmplY3Qua2V5cyh0aGlzLm5vZGVzKSkge1xuICAgICAgY29uc3QgY3ljbGUgPSByZWN1cnNlKG5vZGVJZCwgW25vZGVJZF0pO1xuICAgICAgaWYgKGN5Y2xlKSB7IHJldHVybiBjeWNsZTsgfVxuICAgIH1cbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuXG4gICAgZnVuY3Rpb24gcmVjdXJzZShub2RlSWQ6IHN0cmluZywgcGF0aDogc3RyaW5nW10pOiBzdHJpbmdbXSB8IHVuZGVmaW5lZCB7XG4gICAgICBpZiAoc2Vlbi5oYXMobm9kZUlkKSkge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgfVxuICAgICAgdHJ5IHtcbiAgICAgICAgZm9yIChjb25zdCBkZXAgb2Ygc2VsZi5ub2Rlc1tub2RlSWRdLmRlcGVuZGVuY2llcyA/PyBbXSkge1xuICAgICAgICAgIGNvbnN0IGluZGV4ID0gcGF0aC5pbmRleE9mKGRlcCk7XG4gICAgICAgICAgaWYgKGluZGV4ID4gLTEpIHtcbiAgICAgICAgICAgIHJldHVybiBbLi4ucGF0aC5zbGljZShpbmRleCksIGRlcF07XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgY29uc3QgY3ljbGUgPSByZWN1cnNlKGRlcCwgWy4uLnBhdGgsIGRlcF0pO1xuICAgICAgICAgIGlmIChjeWNsZSkgeyByZXR1cm4gY3ljbGU7IH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBzZWVuLmFkZChub2RlSWQpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBgZW5kYCBub2RlIGlzIHJlYWNoYWJsZSBmcm9tIHRoZSBgc3RhcnRgIG5vZGUsIGZvbGxvd2luZyB0aGUgZGVwZW5kZW5jeSBhcnJvd3NcbiAgICovXG4gIHB1YmxpYyByZWFjaGFibGUoc3RhcnQ6IHN0cmluZywgZW5kOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICBjb25zdCBzZWVuID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgcmV0dXJuIHJlY3Vyc2Uoc3RhcnQpO1xuXG4gICAgZnVuY3Rpb24gcmVjdXJzZShjdXJyZW50OiBzdHJpbmcpIHtcbiAgICAgIGlmIChzZWVuLmhhcyhjdXJyZW50KSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBzZWVuLmFkZChjdXJyZW50KTtcblxuICAgICAgaWYgKGN1cnJlbnQgPT09IGVuZCkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIGZvciAoY29uc3QgZGVwIG9mIHNlbGYubm9kZXNbY3VycmVudF0uZGVwZW5kZW5jaWVzKSB7XG4gICAgICAgIGlmIChyZWN1cnNlKGRlcCkpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFdvcmtHcmFwaEFjdGlvbnMge1xuICBkZXBsb3lTdGFjazogKHN0YWNrTm9kZTogU3RhY2tOb2RlKSA9PiBQcm9taXNlPHZvaWQ+O1xuICBidWlsZEFzc2V0OiAoYXNzZXROb2RlOiBBc3NldEJ1aWxkTm9kZSkgPT4gUHJvbWlzZTx2b2lkPjtcbiAgcHVibGlzaEFzc2V0OiAoYXNzZXROb2RlOiBBc3NldFB1Ymxpc2hOb2RlKSA9PiBQcm9taXNlPHZvaWQ+O1xufVxuXG5mdW5jdGlvbiBzdW0oeHM6IG51bWJlcltdKSB7XG4gIGxldCByZXQgPSAwO1xuICBmb3IgKGNvbnN0IHggb2YgeHMpIHtcbiAgICByZXQgKz0geDtcbiAgfVxuICByZXR1cm4gcmV0O1xufVxuXG5mdW5jdGlvbiByZXRhaW5Pbmx5PEE+KHhzOiBBW10sIHByZWQ6ICh4OiBBKSA9PiBib29sZWFuKSB7XG4gIHhzLnNwbGljZSgwLCB4cy5sZW5ndGgsIC4uLnhzLmZpbHRlcihwcmVkKSk7XG59XG5cbmZ1bmN0aW9uIGd2KGlkOiBzdHJpbmcsIGF0dHJzPzogUmVjb3JkPHN0cmluZywgc3RyaW5nIHwgdW5kZWZpbmVkPikge1xuICBjb25zdCBhdHRyU3RyaW5nID0gT2JqZWN0LmVudHJpZXMoYXR0cnMgPz8ge30pLmZsYXRNYXAoKFtrLCB2XSkgPT4gdiAhPT0gdW5kZWZpbmVkID8gW2Ake2t9PVwiJHt2fVwiYF0gOiBbXSkuam9pbignLCcpO1xuXG4gIHJldHVybiBhdHRyU3RyaW5nID8gYFwiJHtzaW1wbGlmeUlkKGlkKX1cIiBbJHthdHRyU3RyaW5nfV1gIDogYFwiJHtzaW1wbGlmeUlkKGlkKX1cImA7XG59XG5cbmZ1bmN0aW9uIHNpbXBsaWZ5SWQoaWQ6IHN0cmluZykge1xuICByZXR1cm4gaWQucmVwbGFjZSgvKFswLTlhLWZdezZ9KVswLTlhLWZdezYsfS9nLCAnJDEnKTtcbn1cbiJdfQ==