Skip to content

Instantly share code, notes, and snippets.

@monfera

monfera/.block

Last active Mar 5, 2018
Embed
What would you like to do?
A breath of relaxation
license: mit
border: no
scrolling: no
height: 550

Visualizes the layout relaxation iteration of the Sankey component by Mike Bostock.

Code: https://github.com/monfera/sankey-bench

The graph layout process was visualized to see the effects of various tweaks, as the current layouting doesn't eliminate all avoidable link crossings (e.g. Marine Algae wouldn't have to cross Other waste, which, on the other hand, represents a much higher volume).

This specific animation deviates from the alpha decay in the original for a smoother initial animation: alpha starts out at zero, rides up half a sine and goes back to zero.

d3-sankey Copyright Mike Bostock

Energy data: Department of Energy & Climate Change, Tom Counsell http://tamc.github.io/Sankey/ via Mike's example

Rendering code derived from work in process Copyright Plotly, will be MIT licensed in plotly.js

d3-sankey source repository: https://github.com/d3/d3-sankey

Local modifications:

  • Stable sorting (irrelevant with this dataset)
  • Inlining code here so it works with d3 v3.*
  • Replacing the relaxation loop with a requestAnimationFrame loop to allow pre-iteration rendering (via passed-on render callback)
  • Overriding alpha decay and iteration limit check with a half-sine curve

Uploaded with blockbuilder.org

<!DOCTYPE html>
<head>
<meta charset="utf-8">
<script src="https://d3js.org/d3.v3.min.js"></script>
<style>
body { margin:0;position:fixed;top:0;right:0;bottom:0;left:0; }
</style>
</head>
<body>
<script>
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
/**
* d3-sankey Copyright Mike Bostock
*
* Source repository: https://github.com/d3/d3-sankey
*
* Minor local modifications:
* - Stable sorting https://github.com/d3/d3-sankey/pull/19 (irrelevant here)
* - Inlining code here so it works with d3 v3.*
* - Replacing the relaxation loop with a rAF
* - Overriding alpha decay and iteration limit check with a half-sine curve
*/
// var d3 = require('d3');
var nest = d3.nest;
var interpolateNumber = d3.interpolateNumber;
var ascending = d3.ascending;
var min = d3.min;
var sum = d3.sum;
module.exports = function() {
var sankey = {},
nodeWidth = 24,
nodePadding = 8,
size = [1, 1],
nodes = [],
links = [];
sankey.nodeWidth = function(_) {
if (!arguments.length) return nodeWidth;
nodeWidth = +_;
return sankey;
};
sankey.nodePadding = function(_) {
if (!arguments.length) return nodePadding;
nodePadding = +_;
return sankey;
};
sankey.nodes = function(_) {
if (!arguments.length) return nodes;
nodes = _;
return sankey;
};
sankey.links = function(_) {
if (!arguments.length) return links;
links = _;
return sankey;
};
sankey.size = function(_) {
if (!arguments.length) return size;
size = _;
return sankey;
};
sankey.layout = function(iterations, callback) {
computeNodeLinks();
computeNodeValues();
computeNodeBreadths();
computeNodeDepths(iterations, callback);
};
sankey.relayout = function() {
computeLinkDepths();
return sankey;
};
sankey.link = function() {
var curvature = .5;
function link(d) {
var x0 = d.source.x + d.source.dx,
x1 = d.target.x,
xi = interpolateNumber(x0, x1),
x2 = xi(curvature),
x3 = xi(1 - curvature),
y0 = d.source.y + d.sy + d.dy / 2,
y1 = d.target.y + d.ty + d.dy / 2;
return "M" + x0 + "," + y0
+ "C" + x2 + "," + y0
+ " " + x3 + "," + y1
+ " " + x1 + "," + y1;
}
link.curvature = function(_) {
if (!arguments.length) return curvature;
curvature = +_;
return link;
};
return link;
};
// Populate the sourceLinks and targetLinks for each node.
// Also, if the source and target are not objects, assume they are indices.
function computeNodeLinks() {
nodes.forEach(function(node) {
node.sourceLinks = [];
node.targetLinks = [];
});
links.forEach(function(link, i) {
var source = link.source,
target = link.target;
if (typeof source === "number") source = link.source = nodes[link.source];
if (typeof target === "number") target = link.target = nodes[link.target];
link.originalIndex = i;
source.sourceLinks.push(link);
target.targetLinks.push(link);
});
}
// Compute the value (size) of each node by summing the associated links.
function computeNodeValues() {
nodes.forEach(function(node) {
node.value = Math.max(
sum(node.sourceLinks, value),
sum(node.targetLinks, value)
);
});
}
// Iteratively assign the breadth (x-position) for each node.
// Nodes are assigned the maximum breadth of incoming neighbors plus one;
// nodes with no incoming links are assigned breadth zero, while
// nodes with no outgoing links are assigned the maximum breadth.
function computeNodeBreadths() {
var remainingNodes = nodes,
nextNodes,
x = 0;
while (remainingNodes.length) {
nextNodes = [];
remainingNodes.forEach(function(node) {
node.x = x;
node.dx = nodeWidth;
node.sourceLinks.forEach(function(link) {
if (nextNodes.indexOf(link.target) < 0) {
nextNodes.push(link.target);
}
});
});
remainingNodes = nextNodes;
++x;
}
//
moveSinksRight(x);
scaleNodeBreadths((size[0] - nodeWidth) / (x - 1));
}
// function moveSourcesRight() {
// nodes.forEach(function(node) {
// if (!node.targetLinks.length) {
// node.x = min(node.sourceLinks, function(d) { return d.target.x; }) - 1;
// }
// });
// }
function moveSinksRight(x) {
nodes.forEach(function(node) {
if (!node.sourceLinks.length) {
node.x = x - 1;
}
});
}
function scaleNodeBreadths(kx) {
nodes.forEach(function(node) {
node.x *= kx;
});
}
function computeNodeDepths(iterations, callback) {
var nodesByBreadth = nest()
.key(function(d) { return d.x; })
.sortKeys(ascending)
.entries(nodes)
.map(function(d) { return d.values; });
//
initializeNodeDepth();
resolveCollisions();
window.requestAnimationFrame(function render(t) {
var alpha = Math.pow(Math.sin(t / 3000), 2);
relaxRightToLeft(alpha);
resolveCollisions();
relaxLeftToRight(alpha);
resolveCollisions();
computeLinkDepths();
callback(sankey);
if(t / 3000 < Math.PI) {
window.requestAnimationFrame(render);
}
});
function initializeNodeDepth() {
var ky = min(nodesByBreadth, function(nodes) {
return (size[1] - (nodes.length - 1) * nodePadding) / sum(nodes, value);
});
nodesByBreadth.forEach(function(nodes) {
nodes.forEach(function(node, i) {
node.y = i;
node.dy = node.value * ky;
});
});
links.forEach(function(link) {
link.dy = link.value * ky;
});
}
function relaxLeftToRight(alpha) {
nodesByBreadth.forEach(function(nodes) {
nodes.forEach(function(node) {
if (node.targetLinks.length) {
var y = sum(node.targetLinks, weightedSource) / sum(node.targetLinks, value);
node.y += (y - center(node)) * alpha;
}
});
});
function weightedSource(link) {
return center(link.source) * link.value;
}
}
function relaxRightToLeft(alpha) {
nodesByBreadth.slice().reverse().forEach(function(nodes) {
nodes.forEach(function(node) {
if (node.sourceLinks.length) {
var y = sum(node.sourceLinks, weightedTarget) / sum(node.sourceLinks, value);
node.y += (y - center(node)) * alpha;
}
});
});
function weightedTarget(link) {
return center(link.target) * link.value;
}
}
function resolveCollisions() {
nodesByBreadth.forEach(function(nodes) {
var node,
dy,
y0 = 0,
n = nodes.length,
i;
// Push any overlapping nodes down.
nodes.sort(ascendingDepth);
for (i = 0; i < n; ++i) {
node = nodes[i];
dy = y0 - node.y;
if (dy > 0) node.y += dy;
y0 = node.y + node.dy + nodePadding;
}
// If the bottommost node goes outside the bounds, push it back up.
dy = y0 - nodePadding - size[1];
if (dy > 0) {
y0 = node.y -= dy;
// Push any overlapping nodes back up.
for (i = n - 2; i >= 0; --i) {
node = nodes[i];
dy = node.y + node.dy + nodePadding - y0;
if (dy > 0) node.y -= dy;
y0 = node.y;
}
}
});
}
function ascendingDepth(a, b) {
return a.y - b.y;
}
}
function computeLinkDepths() {
nodes.forEach(function(node) {
node.sourceLinks.sort(ascendingTargetDepth);
node.targetLinks.sort(ascendingSourceDepth);
});
nodes.forEach(function(node) {
var sy = 0, ty = 0;
node.sourceLinks.forEach(function(link) {
link.sy = sy;
sy += link.dy;
});
node.targetLinks.forEach(function(link) {
link.ty = ty;
ty += link.dy;
});
});
function ascendingSourceDepth(a, b) {
return (a.source.y - b.source.y) || (a.originalIndex - b.originalIndex);
}
function ascendingTargetDepth(a, b) {
return (a.target.y - b.target.y) || (a.originalIndex - b.originalIndex);
}
}
function center(node) {
return node.y + node.dy / 2;
}
function value(link) {
return link.value;
}
return sankey;
}
},{}],2:[function(require,module,exports){
/**
* Direct source: https://bost.ocks.org/mike/sankey/ by Mike Bostock
* Ultimate source: Department of Energy & Climate Change, Tom Counsell
* http://tamc.github.io/Sankey/
*/
module.exports = {
"nodes":[
{"name":"Agricultural 'waste'"},
{"name":"Bio-conversion"},
{"name":"Liquid"},
{"name":"Losses"},
{"name":"Solid"},
{"name":"Gas"},
{"name":"Biofuel imports"},
{"name":"Biomass imports"},
{"name":"Coal imports"},
{"name":"Coal"},
{"name":"Coal reserves"},
{"name":"District heating"},
{"name":"Industry"},
{"name":"Heating and cooling - commercial"},
{"name":"Heating and cooling - homes"},
{"name":"Electricity grid"},
{"name":"Over generation / exports"},
{"name":"H2 conversion"},
{"name":"Road transport"},
{"name":"Agriculture"},
{"name":"Rail transport"},
{"name":"Lighting & appliances - commercial"},
{"name":"Lighting & appliances - homes"},
{"name":"Gas imports"},
{"name":"Ngas"},
{"name":"Gas reserves"},
{"name":"Thermal generation"},
{"name":"Geothermal"},
{"name":"H2"},
{"name":"Hydro"},
{"name":"International shipping"},
{"name":"Domestic aviation"},
{"name":"International aviation"},
{"name":"National navigation"},
{"name":"Marine algae"},
{"name":"Nuclear"},
{"name":"Oil imports"},
{"name":"Oil"},
{"name":"Oil reserves"},
{"name":"Other waste"},
{"name":"Pumped heat"},
{"name":"Solar PV"},
{"name":"Solar Thermal"},
{"name":"Solar"},
{"name":"Tidal"},
{"name":"UK land based bioenergy"},
{"name":"Wave"},
{"name":"Wind"}
],
"links":[
{"source":0,"target":1,"value":124.729},
{"source":1,"target":2,"value":0.597},
{"source":1,"target":3,"value":26.862},
{"source":1,"target":4,"value":280.322},
{"source":1,"target":5,"value":81.144},
{"source":6,"target":2,"value":35},
{"source":7,"target":4,"value":35},
{"source":8,"target":9,"value":11.606},
{"source":10,"target":9,"value":63.965},
{"source":9,"target":4,"value":75.571},
{"source":11,"target":12,"value":10.639},
{"source":11,"target":13,"value":22.505},
{"source":11,"target":14,"value":46.184},
{"source":15,"target":16,"value":104.453},
{"source":15,"target":14,"value":113.726},
{"source":15,"target":17,"value":27.14},
{"source":15,"target":12,"value":342.165},
{"source":15,"target":18,"value":37.797},
{"source":15,"target":19,"value":4.412},
{"source":15,"target":13,"value":40.858},
{"source":15,"target":3,"value":56.691},
{"source":15,"target":20,"value":7.863},
{"source":15,"target":21,"value":90.008},
{"source":15,"target":22,"value":93.494},
{"source":23,"target":24,"value":40.719},
{"source":25,"target":24,"value":82.233},
{"source":5,"target":13,"value":0.129},
{"source":5,"target":3,"value":1.401},
{"source":5,"target":26,"value":151.891},
{"source":5,"target":19,"value":2.096},
{"source":5,"target":12,"value":48.58},
{"source":27,"target":15,"value":7.013},
{"source":17,"target":28,"value":20.897},
{"source":17,"target":3,"value":6.242},
{"source":28,"target":18,"value":20.897},
{"source":29,"target":15,"value":6.995},
{"source":2,"target":12,"value":121.066},
{"source":2,"target":30,"value":128.69},
{"source":2,"target":18,"value":135.835},
{"source":2,"target":31,"value":14.458},
{"source":2,"target":32,"value":206.267},
{"source":2,"target":19,"value":3.64},
{"source":2,"target":33,"value":33.218},
{"source":2,"target":20,"value":4.413},
{"source":34,"target":1,"value":14.375},
{"source":24,"target":5,"value":122.952},
{"source":35,"target":26,"value":839.978},
{"source":36,"target":37,"value":504.287},
{"source":38,"target":37,"value":107.703},
{"source":37,"target":2,"value":611.99},
{"source":39,"target":4,"value":56.587},
{"source":39,"target":1,"value":77.81},
{"source":40,"target":14,"value":193.026},
{"source":40,"target":13,"value":70.672},
{"source":41,"target":15,"value":59.901},
{"source":42,"target":14,"value":19.263},
{"source":43,"target":42,"value":19.263},
{"source":43,"target":41,"value":59.901},
{"source":4,"target":19,"value":0.882},
{"source":4,"target":26,"value":400.12},
{"source":4,"target":12,"value":46.477},
{"source":26,"target":15,"value":525.531},
{"source":26,"target":3,"value":787.129},
{"source":26,"target":11,"value":79.329},
{"source":44,"target":15,"value":9.452},
{"source":45,"target":1,"value":182.01},
{"source":46,"target":15,"value":19.013},
{"source":47,"target":15,"value":289.366}
]
};
},{}],3:[function(require,module,exports){
/**
* Copyright 2012-2017, Plotly, Inc.
* All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
//var d3 = require('d3');
var d3sankey = require('./d3-sankey');
var data = require('./energy');
var width = 800;
var height = 500;
var margin = {
l: 20,
t: 20,
r: 200,
b: 20
};
var c = {
nodeTextOffset: 5,
nodeWidth: 15,
nodePadding: 14,
sankeyIterations: 700,
vertical: false,
nodeOpacity: 0.7,
nodeSalientOpacity: 1,
linkOpacity: 0.2,
linkSalientOpacity: 0.4
};
function keyFun(d) {return d.key;}
function repeat(d) {return [d];}
function noop() {}
function viewModel(sankey) {
return {
key: 0,
translateX: margin.l,
translateY: margin.t,
dragLength: c.vertical ? width : height,
nodes: sankey.nodes(),
links: sankey.links(),
sankey: sankey
};
}
function render(svg, callbacks) {
return function(sankey) {
var dragInProgress = false;
var hovered = false;
function attachPointerEvents(selection, eventSet) {
selection
.on('mouseover', function (d) {
if (!dragInProgress) {
eventSet.hover(this, d);
hovered = [this, d];
}
})
.on('mouseout', function (d) {
if (!dragInProgress) {
eventSet.unhover(this, d);
hovered = false;
}
})
.on('click', function (d) {
if (hovered) {
eventSet.unhover(this, d);
hovered = false;
}
if (!dragInProgress) {
eventSet.select(this, d);
}
});
}
function linkPath(d) {
return d.sankey.link()(d.link);
}
var colorer = d3.scale.category20();
var sankey = svg.selectAll('.sankey')
.data([viewModel(sankey)], keyFun);
sankey.enter()
.append('g')
.classed('sankey', true)
.attr('overflow', 'visible')
.style('box-sizing', 'content-box')
.style('position', 'absolute')
.style('left', 0)
.style('overflow', 'visible')
.style('shape-rendering', 'geometricPrecision')
.style('pointer-events', 'auto')
.style('box-sizing', 'content-box');
sankey
.attr('transform', function(d) {
return 'translate(' + d.translateX + ',' + d.translateY + ')';
});
var sankeyLinks = sankey.selectAll('.sankeyLinks')
.data(repeat, keyFun);
sankeyLinks.enter()
.append('g')
.classed('sankeyLinks', true)
.style('transform', c.vertical ? 'matrix(0,1,1,0,0,0)' : 'matrix(1,0,0,1,0,0)')
.style('fill', 'none')
.style('stroke', 'black')
.style('stroke-opacity', c.linkOpacity);
var sankeyLink = sankeyLinks.selectAll('.sankeyPath')
.data(function(d) {
return d.sankey.links().map(function(l) {
return {
link: l,
sankey: d.sankey
};
});
});
sankeyLink.enter()
.append('path')
.classed('sankeyPath', true)
.call(attachPointerEvents, callbacks.linkEvents);
sankeyLink
.attr('d', linkPath)
.style('stroke-width', function(d) {return Math.max(1, d.link.dy);});
var sankeyNodes = sankey.selectAll('.sankeyNodes')
.data(repeat, keyFun);
sankeyNodes.enter()
.append('g')
.style('shape-rendering', 'crispEdges')
.classed('sankeyNodes', true);
var sankeyNode = sankeyNodes.selectAll('.sankeyNode')
.data(function(d) {
return d.sankey.nodes().map(function(l) {
return {
node: l,
sankey: d.sankey,
model: d
};
});
}, function(d) {return d.node.name;});
sankeyNode.enter()
.append('g')
.classed('sankeyNode', true)
.call(d3.behavior.drag()
.origin(function(d) {return c.vertical ? {x: d.node.y} : d.node;})
.on('dragstart', function(d) {
d.node.dragStartLocation = c.vertical ? d3.event.x : d3.event.y;
this.parentNode.appendChild(this);
dragInProgress = true;
if(hovered) {
//callbacks.nodeEvents.unhover.apply(0, hovered);
hovered = false;
}
})
.on('drag', function(d) {
if(c.vertical) {
d.node.y = Math.max(0, Math.min(d.model.dragLength - d.node.dy, d3.event.x));
d3.select(this).style('transform', 'translate(' + d.node.y + 'px,' + d.node.x + 'px)');
} else {
d.node.y = Math.max(0, Math.min(d.model.dragLength - d.node.dy, d3.event.y));
d3.select(this).style('transform', 'translate(' + d.node.x + 'px,' + d.node.y + 'px)');
}
d.sankey.relayout();
sankeyLink.attr('d', linkPath);
}
)
.on('dragend', function() {
dragInProgress = false;
}));
sankeyNode
.style('transform', c.vertical ?
function(d) {return 'translate(' + (Math.floor(d.node.y) - 0.5) + 'px, ' + (Math.floor(d.node.x) + 0.5) + 'px)';} :
function(d) {return 'translate(' + (Math.floor(d.node.x) - 0.5) + 'px, ' + (Math.floor(d.node.y) + 0.5) + 'px)';});
var nodeRect = sankeyNode.selectAll('.nodeRect')
.data(repeat);
nodeRect.enter()
.append('rect')
.classed('nodeRect', true)
.style('shape-rendering', 'crispEdges')
.style('fill', function(d) {return colorer(d.sankey.nodes().indexOf(d.node));})
.style('stroke-width', 0.5)
.style('stroke', 'black')
.style('stroke-opacity', 1)
.style('fill-opacity', c.nodeOpacity)
.call(attachPointerEvents, callbacks.nodeEvents);
nodeRect // ceil, +/-0.5 and crispEdges is wizardry for consistent border width on all 4 sides
.attr(c.vertical ? 'height' : 'width', function(d) {return Math.ceil(d.node.dx + 0.5);})
.attr(c.vertical ? 'width' : 'height', function(d) {return Math.ceil(d.node.dy - 0.5);});
var nodeLabel = sankeyNode.selectAll('.nodeLabel')
.data(repeat);
nodeLabel.enter()
.append('text')
.classed('nodeLabel', true);
nodeLabel
.attr('x', function(d) {return c.vertical ? d.node.dy / 2 : d.node.dx + c.nodeTextOffset;})
.attr('y', function(d) {return c.vertical ? d.node.dx / 2 : d.node.dy / 2;})
.text(function(d) {return d.node.name;})
.attr('alignment-baseline', 'middle')
.attr('text-anchor', c.vertical ? 'middle' : 'start')
.style('font-family', 'sans-serif')
.style('font-size', '10px');
};
};
var svg = d3.select('body').append('svg')
.attr('width', width + margin.l + margin.r)
.attr('height', height + margin.t + margin.b);
var renderer = render(svg, {
linkEvents: {
hover: function(e, l) {
d3.selectAll('.nodeRect')
.filter(function(n) {return n.node.name === l.link.source.name || n.node.name === l.link.target.name;})
.style('fill-opacity', c.nodeSalientOpacity);
d3.select(e).style('stroke-opacity', c.linkSalientOpacity);
},
unhover: function(e, d) {
d3.selectAll('.nodeRect').style('fill-opacity', c.nodeOpacity);
d3.select(e).style('stroke-opacity', c.linkOpacity);
},
select: noop
},
nodeEvents: {
hover: function(e, n) {
d3.selectAll('.sankeyPath')
.filter(function(l) {return n.node.name === l.link.source.name || n.node.name === l.link.target.name;})
.style('stroke-opacity', c.linkSalientOpacity);
d3.select(e).style('fill-opacity', c.nodeSalientOpacity);
},
unhover: function(e, d) {
d3.selectAll('.sankeyPath').style('stroke-opacity', c.linkOpacity);
d3.select(e).style('fill-opacity', c.nodeOpacity);
},
select: noop
}
});
d3sankey()
.size(c.vertical ? [height, width]: [width, height])
.nodeWidth(c.nodeWidth)
.nodePadding(c.nodePadding)
.nodes(data.nodes)
.links(data.links)
.layout(c.sankeyIterations, renderer);
},{"./d3-sankey":1,"./energy":2}]},{},[3])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Vzci9sb2NhbC9saWIvbm9kZV9tb2R1bGVzL2J1ZG8vbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImQzLXNhbmtleS5qcyIsImVuZXJneS5qcyIsImluZGV4LmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25VQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaElBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8qKlxuICogZDMtc2Fua2V5IENvcHlyaWdodCBNaWtlIEJvc3RvY2tcbiAqXG4gKiBTb3VyY2UgcmVwb3NpdG9yeTogaHR0cHM6Ly9naXRodWIuY29tL2QzL2QzLXNhbmtleVxuICpcbiAqIE1pbm9yIGxvY2FsIG1vZGlmaWNhdGlvbnM6XG4gKiAgICAtIFN0YWJsZSBzb3J0aW5nIGh0dHBzOi8vZ2l0aHViLmNvbS9kMy9kMy1zYW5rZXkvcHVsbC8xOSAoaXJyZWxldmFudCBoZXJlKVxuICogICAgLSBJbmxpbmluZyBjb2RlIGhlcmUgc28gaXQgd29ya3Mgd2l0aCBkMyB2My4qXG4gKiAgICAtIFJlcGxhY2luZyB0aGUgcmVsYXhhdGlvbiBsb29wIHdpdGggYSByQUZcbiAqICAgIC0gT3ZlcnJpZGluZyBhbHBoYSBkZWNheSBhbmQgaXRlcmF0aW9uIGxpbWl0IGNoZWNrIHdpdGggYSBoYWxmLXNpbmUgY3VydmVcbiAqL1xuXG4vLyB2YXIgZDMgPSByZXF1aXJlKCdkMycpO1xudmFyIG5lc3QgPSBkMy5uZXN0O1xudmFyIGludGVycG9sYXRlTnVtYmVyID0gZDMuaW50ZXJwb2xhdGVOdW1iZXI7XG52YXIgYXNjZW5kaW5nID0gZDMuYXNjZW5kaW5nO1xudmFyIG1pbiA9IGQzLm1pbjtcbnZhciBzdW0gPSBkMy5zdW07XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oKSB7XG4gIHZhciBzYW5rZXkgPSB7fSxcbiAgICAgIG5vZGVXaWR0aCA9IDI0LFxuICAgICAgbm9kZVBhZGRpbmcgPSA4LFxuICAgICAgc2l6ZSA9IFsxLCAxXSxcbiAgICAgIG5vZGVzID0gW10sXG4gICAgICBsaW5rcyA9IFtdO1xuXG4gIHNhbmtleS5ub2RlV2lkdGggPSBmdW5jdGlvbihfKSB7XG4gICAgaWYgKCFhcmd1bWVudHMubGVuZ3RoKSByZXR1cm4gbm9kZVdpZHRoO1xuICAgIG5vZGVXaWR0aCA9ICtfO1xuICAgIHJldHVybiBzYW5rZXk7XG4gIH07XG5cbiAgc2Fua2V5Lm5vZGVQYWRkaW5nID0gZnVuY3Rpb24oXykge1xuICAgIGlmICghYXJndW1lbnRzLmxlbmd0aCkgcmV0dXJuIG5vZGVQYWRkaW5nO1xuICAgIG5vZGVQYWRkaW5nID0gK187XG4gICAgcmV0dXJuIHNhbmtleTtcbiAgfTtcblxuICBzYW5rZXkubm9kZXMgPSBmdW5jdGlvbihfKSB7XG4gICAgaWYgKCFhcmd1bWVudHMubGVuZ3RoKSByZXR1cm4gbm9kZXM7XG4gICAgbm9kZXMgPSBfO1xuICAgIHJldHVybiBzYW5rZXk7XG4gIH07XG5cbiAgc2Fua2V5LmxpbmtzID0gZnVuY3Rpb24oXykge1xuICAgIGlmICghYXJndW1lbnRzLmxlbmd0aCkgcmV0dXJuIGxpbmtzO1xuICAgIGxpbmtzID0gXztcbiAgICByZXR1cm4gc2Fua2V5O1xuICB9O1xuXG4gIHNhbmtleS5zaXplID0gZnVuY3Rpb24oXykge1xuICAgIGlmICghYXJndW1lbnRzLmxlbmd0aCkgcmV0dXJuIHNpemU7XG4gICAgc2l6ZSA9IF87XG4gICAgcmV0dXJuIHNhbmtleTtcbiAgfTtcblxuICBzYW5rZXkubGF5b3V0ID0gZnVuY3Rpb24oaXRlcmF0aW9ucywgY2FsbGJhY2spIHtcbiAgICBjb21wdXRlTm9kZUxpbmtzKCk7XG4gICAgY29tcHV0ZU5vZGVWYWx1ZXMoKTtcbiAgICBjb21wdXRlTm9kZUJyZWFkdGhzKCk7XG4gICAgY29tcHV0ZU5vZGVEZXB0aHMoaXRlcmF0aW9ucywgY2FsbGJhY2spO1xuICB9O1xuXG4gIHNhbmtleS5yZWxheW91dCA9IGZ1bmN0aW9uKCkge1xuICAgIGNvbXB1dGVMaW5rRGVwdGhzKCk7XG4gICAgcmV0dXJuIHNhbmtleTtcbiAgfTtcblxuICBzYW5rZXkubGluayA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBjdXJ2YXR1cmUgPSAuNTtcblxuICAgIGZ1bmN0aW9uIGxpbmsoZCkge1xuICAgICAgdmFyIHgwID0gZC5zb3VyY2UueCArIGQuc291cmNlLmR4LFxuICAgICAgICAgIHgxID0gZC50YXJnZXQueCxcbiAgICAgICAgICB4aSA9IGludGVycG9sYXRlTnVtYmVyKHgwLCB4MSksXG4gICAgICAgICAgeDIgPSB4aShjdXJ2YXR1cmUpLFxuICAgICAgICAgIHgzID0geGkoMSAtIGN1cnZhdHVyZSksXG4gICAgICAgICAgeTAgPSBkLnNvdXJjZS55ICsgZC5zeSArIGQuZHkgLyAyLFxuICAgICAgICAgIHkxID0gZC50YXJnZXQueSArIGQudHkgKyBkLmR5IC8gMjtcbiAgICAgIHJldHVybiBcIk1cIiArIHgwICsgXCIsXCIgKyB5MFxuICAgICAgICArIFwiQ1wiICsgeDIgKyBcIixcIiArIHkwXG4gICAgICAgICsgXCIgXCIgKyB4MyArIFwiLFwiICsgeTFcbiAgICAgICAgKyBcIiBcIiArIHgxICsgXCIsXCIgKyB5MTtcbiAgICB9XG5cbiAgICBsaW5rLmN1cnZhdHVyZSA9IGZ1bmN0aW9uKF8pIHtcbiAgICAgIGlmICghYXJndW1lbnRzLmxlbmd0aCkgcmV0dXJuIGN1cnZhdHVyZTtcbiAgICAgIGN1cnZhdHVyZSA9ICtfO1xuICAgICAgcmV0dXJuIGxpbms7XG4gICAgfTtcblxuICAgIHJldHVybiBsaW5rO1xuICB9O1xuXG4gIC8vIFBvcHVsYXRlIHRoZSBzb3VyY2VMaW5rcyBhbmQgdGFyZ2V0TGlua3MgZm9yIGVhY2ggbm9kZS5cbiAgLy8gQWxzbywgaWYgdGhlIHNvdXJjZSBhbmQgdGFyZ2V0IGFyZSBub3Qgb2JqZWN0cywgYXNzdW1lIHRoZXkgYXJlIGluZGljZXMuXG4gIGZ1bmN0aW9uIGNvbXB1dGVOb2RlTGlua3MoKSB7XG4gICAgbm9kZXMuZm9yRWFjaChmdW5jdGlvbihub2RlKSB7XG4gICAgICBub2RlLnNvdXJjZUxpbmtzID0gW107XG4gICAgICBub2RlLnRhcmdldExpbmtzID0gW107XG4gICAgfSk7XG4gICAgbGlua3MuZm9yRWFjaChmdW5jdGlvbihsaW5rLCBpKSB7XG4gICAgICB2YXIgc291cmNlID0gbGluay5zb3VyY2UsXG4gICAgICAgICAgdGFyZ2V0ID0gbGluay50YXJnZXQ7XG4gICAgICBpZiAodHlwZW9mIHNvdXJjZSA9PT0gXCJudW1iZXJcIikgc291cmNlID0gbGluay5zb3VyY2UgPSBub2Rlc1tsaW5rLnNvdXJjZV07XG4gICAgICBpZiAodHlwZW9mIHRhcmdldCA9PT0gXCJudW1iZXJcIikgdGFyZ2V0ID0gbGluay50YXJnZXQgPSBub2Rlc1tsaW5rLnRhcmdldF07XG4gICAgICBsaW5rLm9yaWdpbmFsSW5kZXggPSBpO1xuICAgICAgc291cmNlLnNvdXJjZUxpbmtzLnB1c2gobGluayk7XG4gICAgICB0YXJnZXQudGFyZ2V0TGlua3MucHVzaChsaW5rKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8vIENvbXB1dGUgdGhlIHZhbHVlIChzaXplKSBvZiBlYWNoIG5vZGUgYnkgc3VtbWluZyB0aGUgYXNzb2NpYXRlZCBsaW5rcy5cbiAgZnVuY3Rpb24gY29tcHV0ZU5vZGVWYWx1ZXMoKSB7XG4gICAgbm9kZXMuZm9yRWFjaChmdW5jdGlvbihub2RlKSB7XG4gICAgICBub2RlLnZhbHVlID0gTWF0aC5tYXgoXG4gICAgICAgIHN1bShub2RlLnNvdXJjZUxpbmtzLCB2YWx1ZSksXG4gICAgICAgIHN1bShub2RlLnRhcmdldExpbmtzLCB2YWx1ZSlcbiAgICAgICk7XG4gICAgfSk7XG4gIH1cblxuICAvLyBJdGVyYXRpdmVseSBhc3NpZ24gdGhlIGJyZWFkdGggKHgtcG9zaXRpb24pIGZvciBlYWNoIG5vZGUuXG4gIC8vIE5vZGVzIGFyZSBhc3NpZ25lZCB0aGUgbWF4aW11bSBicmVhZHRoIG9mIGluY29taW5nIG5laWdoYm9ycyBwbHVzIG9uZTtcbiAgLy8gbm9kZXMgd2l0aCBubyBpbmNvbWluZyBsaW5rcyBhcmUgYXNzaWduZWQgYnJlYWR0aCB6ZXJvLCB3aGlsZVxuICAvLyBub2RlcyB3aXRoIG5vIG91dGdvaW5nIGxpbmtzIGFyZSBhc3NpZ25lZCB0aGUgbWF4aW11bSBicmVhZHRoLlxuICBmdW5jdGlvbiBjb21wdXRlTm9kZUJyZWFkdGhzKCkge1xuICAgIHZhciByZW1haW5pbmdOb2RlcyA9IG5vZGVzLFxuICAgICAgICBuZXh0Tm9kZXMsXG4gICAgICAgIHggPSAwO1xuXG4gICAgd2hpbGUgKHJlbWFpbmluZ05vZGVzLmxlbmd0aCkge1xuICAgICAgbmV4dE5vZGVzID0gW107XG4gICAgICByZW1haW5pbmdOb2Rlcy5mb3JFYWNoKGZ1bmN0aW9uKG5vZGUpIHtcbiAgICAgICAgbm9kZS54ID0geDtcbiAgICAgICAgbm9kZS5keCA9IG5vZGVXaWR0aDtcbiAgICAgICAgbm9kZS5zb3VyY2VMaW5rcy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmspIHtcbiAgICAgICAgICBpZiAobmV4dE5vZGVzLmluZGV4T2YobGluay50YXJnZXQpIDwgMCkge1xuICAgICAgICAgICAgbmV4dE5vZGVzLnB1c2gobGluay50YXJnZXQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICAgIHJlbWFpbmluZ05vZGVzID0gbmV4dE5vZGVzO1xuICAgICAgKyt4O1xuICAgIH1cblxuICAgIC8vXG4gICAgbW92ZVNpbmtzUmlnaHQoeCk7XG4gICAgc2NhbGVOb2RlQnJlYWR0aHMoKHNpemVbMF0gLSBub2RlV2lkdGgpIC8gKHggLSAxKSk7XG4gIH1cblxuICAvLyBmdW5jdGlvbiBtb3ZlU291cmNlc1JpZ2h0KCkge1xuICAvLyAgIG5vZGVzLmZvckVhY2goZnVuY3Rpb24obm9kZSkge1xuICAvLyAgICAgaWYgKCFub2RlLnRhcmdldExpbmtzLmxlbmd0aCkge1xuICAvLyAgICAgICBub2RlLnggPSBtaW4obm9kZS5zb3VyY2VMaW5rcywgZnVuY3Rpb24oZCkgeyByZXR1cm4gZC50YXJnZXQueDsgfSkgLSAxO1xuICAvLyAgICAgfVxuICAvLyAgIH0pO1xuICAvLyB9XG5cbiAgZnVuY3Rpb24gbW92ZVNpbmtzUmlnaHQoeCkge1xuICAgIG5vZGVzLmZvckVhY2goZnVuY3Rpb24obm9kZSkge1xuICAgICAgaWYgKCFub2RlLnNvdXJjZUxpbmtzLmxlbmd0aCkge1xuICAgICAgICBub2RlLnggPSB4IC0gMTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNjYWxlTm9kZUJyZWFkdGhzKGt4KSB7XG4gICAgbm9kZXMuZm9yRWFjaChmdW5jdGlvbihub2RlKSB7XG4gICAgICBub2RlLnggKj0ga3g7XG4gICAgfSk7XG4gIH1cblxuICBmdW5jdGlvbiBjb21wdXRlTm9kZURlcHRocyhpdGVyYXRpb25zLCBjYWxsYmFjaykge1xuICAgIHZhciBub2Rlc0J5QnJlYWR0aCA9IG5lc3QoKVxuICAgICAgLmtleShmdW5jdGlvbihkKSB7IHJldHVybiBkLng7IH0pXG4gICAgICAuc29ydEtleXMoYXNjZW5kaW5nKVxuICAgICAgLmVudHJpZXMobm9kZXMpXG4gICAgICAubWFwKGZ1bmN0aW9uKGQpIHsgcmV0dXJuIGQudmFsdWVzOyB9KTtcblxuICAgIC8vXG4gICAgaW5pdGlhbGl6ZU5vZGVEZXB0aCgpO1xuICAgIHJlc29sdmVDb2xsaXNpb25zKCk7XG5cbiAgICB3aW5kb3cucmVxdWVzdEFuaW1hdGlvbkZyYW1lKGZ1bmN0aW9uIHJlbmRlcih0KSB7XG5cbiAgICAgIHZhciBhbHBoYSA9IE1hdGgucG93KE1hdGguc2luKHQgLyAzMDAwKSwgMik7XG5cbiAgICAgIHJlbGF4UmlnaHRUb0xlZnQoYWxwaGEpO1xuICAgICAgcmVzb2x2ZUNvbGxpc2lvbnMoKTtcbiAgICAgIHJlbGF4TGVmdFRvUmlnaHQoYWxwaGEpO1xuICAgICAgcmVzb2x2ZUNvbGxpc2lvbnMoKTtcbiAgICAgIGNvbXB1dGVMaW5rRGVwdGhzKCk7XG4gICAgICBjYWxsYmFjayhzYW5rZXkpO1xuXG4gICAgICBpZih0IC8gMzAwMCA8IE1hdGguUEkpIHtcbiAgICAgICAgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZShyZW5kZXIpO1xuICAgICAgfVxuXG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiBpbml0aWFsaXplTm9kZURlcHRoKCkge1xuICAgICAgdmFyIGt5ID0gbWluKG5vZGVzQnlCcmVhZHRoLCBmdW5jdGlvbihub2Rlcykge1xuICAgICAgICByZXR1cm4gKHNpemVbMV0gLSAobm9kZXMubGVuZ3RoIC0gMSkgKiBub2RlUGFkZGluZykgLyBzdW0obm9kZXMsIHZhbHVlKTtcbiAgICAgIH0pO1xuXG4gICAgICBub2Rlc0J5QnJlYWR0aC5mb3JFYWNoKGZ1bmN0aW9uKG5vZGVzKSB7XG4gICAgICAgIG5vZGVzLmZvckVhY2goZnVuY3Rpb24obm9kZSwgaSkge1xuICAgICAgICAgIG5vZGUueSA9IGk7XG4gICAgICAgICAgbm9kZS5keSA9IG5vZGUudmFsdWUgKiBreTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgbGlua3MuZm9yRWFjaChmdW5jdGlvbihsaW5rKSB7XG4gICAgICAgIGxpbmsuZHkgPSBsaW5rLnZhbHVlICoga3k7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiByZWxheExlZnRUb1JpZ2h0KGFscGhhKSB7XG4gICAgICBub2Rlc0J5QnJlYWR0aC5mb3JFYWNoKGZ1bmN0aW9uKG5vZGVzKSB7XG4gICAgICAgIG5vZGVzLmZvckVhY2goZnVuY3Rpb24obm9kZSkge1xuICAgICAgICAgIGlmIChub2RlLnRhcmdldExpbmtzLmxlbmd0aCkge1xuICAgICAgICAgICAgdmFyIHkgPSBzdW0obm9kZS50YXJnZXRMaW5rcywgd2VpZ2h0ZWRTb3VyY2UpIC8gc3VtKG5vZGUudGFyZ2V0TGlua3MsIHZhbHVlKTtcbiAgICAgICAgICAgIG5vZGUueSArPSAoeSAtIGNlbnRlcihub2RlKSkgKiBhbHBoYTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGZ1bmN0aW9uIHdlaWdodGVkU291cmNlKGxpbmspIHtcbiAgICAgICAgcmV0dXJuIGNlbnRlcihsaW5rLnNvdXJjZSkgKiBsaW5rLnZhbHVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHJlbGF4UmlnaHRUb0xlZnQoYWxwaGEpIHtcbiAgICAgIG5vZGVzQnlCcmVhZHRoLnNsaWNlKCkucmV2ZXJzZSgpLmZvckVhY2goZnVuY3Rpb24obm9kZXMpIHtcbiAgICAgICAgbm9kZXMuZm9yRWFjaChmdW5jdGlvbihub2RlKSB7XG4gICAgICAgICAgaWYgKG5vZGUuc291cmNlTGlua3MubGVuZ3RoKSB7XG4gICAgICAgICAgICB2YXIgeSA9IHN1bShub2RlLnNvdXJjZUxpbmtzLCB3ZWlnaHRlZFRhcmdldCkgLyBzdW0obm9kZS5zb3VyY2VMaW5rcywgdmFsdWUpO1xuICAgICAgICAgICAgbm9kZS55ICs9ICh5IC0gY2VudGVyKG5vZGUpKSAqIGFscGhhO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgZnVuY3Rpb24gd2VpZ2h0ZWRUYXJnZXQobGluaykge1xuICAgICAgICByZXR1cm4gY2VudGVyKGxpbmsudGFyZ2V0KSAqIGxpbmsudmFsdWU7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcmVzb2x2ZUNvbGxpc2lvbnMoKSB7XG4gICAgICBub2Rlc0J5QnJlYWR0aC5mb3JFYWNoKGZ1bmN0aW9uKG5vZGVzKSB7XG4gICAgICAgIHZhciBub2RlLFxuICAgICAgICAgICAgZHksXG4gICAgICAgICAgICB5MCA9IDAsXG4gICAgICAgICAgICBuID0gbm9kZXMubGVuZ3RoLFxuICAgICAgICAgICAgaTtcblxuICAgICAgICAvLyBQdXNoIGFueSBvdmVybGFwcGluZyBub2RlcyBkb3duLlxuICAgICAgICBub2Rlcy5zb3J0KGFzY2VuZGluZ0RlcHRoKTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IG47ICsraSkge1xuICAgICAgICAgIG5vZGUgPSBub2Rlc1tpXTtcbiAgICAgICAgICBkeSA9IHkwIC0gbm9kZS55O1xuICAgICAgICAgIGlmIChkeSA+IDApIG5vZGUueSArPSBkeTtcbiAgICAgICAgICB5MCA9IG5vZGUueSArIG5vZGUuZHkgKyBub2RlUGFkZGluZztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIHRoZSBib3R0b21tb3N0IG5vZGUgZ29lcyBvdXRzaWRlIHRoZSBib3VuZHMsIHB1c2ggaXQgYmFjayB1cC5cbiAgICAgICAgZHkgPSB5MCAtIG5vZGVQYWRkaW5nIC0gc2l6ZVsxXTtcbiAgICAgICAgaWYgKGR5ID4gMCkge1xuICAgICAgICAgIHkwID0gbm9kZS55IC09IGR5O1xuXG4gICAgICAgICAgLy8gUHVzaCBhbnkgb3ZlcmxhcHBpbmcgbm9kZXMgYmFjayB1cC5cbiAgICAgICAgICBmb3IgKGkgPSBuIC0gMjsgaSA+PSAwOyAtLWkpIHtcbiAgICAgICAgICAgIG5vZGUgPSBub2Rlc1tpXTtcbiAgICAgICAgICAgIGR5ID0gbm9kZS55ICsgbm9kZS5keSArIG5vZGVQYWRkaW5nIC0geTA7XG4gICAgICAgICAgICBpZiAoZHkgPiAwKSBub2RlLnkgLT0gZHk7XG4gICAgICAgICAgICB5MCA9IG5vZGUueTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGFzY2VuZGluZ0RlcHRoKGEsIGIpIHtcbiAgICAgIHJldHVybiBhLnkgLSBiLnk7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gY29tcHV0ZUxpbmtEZXB0aHMoKSB7XG4gICAgbm9kZXMuZm9yRWFjaChmdW5jdGlvbihub2RlKSB7XG4gICAgICBub2RlLnNvdXJjZUxpbmtzLnNvcnQoYXNjZW5kaW5nVGFyZ2V0RGVwdGgpO1xuICAgICAgbm9kZS50YXJnZXRMaW5rcy5zb3J0KGFzY2VuZGluZ1NvdXJjZURlcHRoKTtcbiAgICB9KTtcbiAgICBub2Rlcy5mb3JFYWNoKGZ1bmN0aW9uKG5vZGUpIHtcbiAgICAgIHZhciBzeSA9IDAsIHR5ID0gMDtcbiAgICAgIG5vZGUuc291cmNlTGlua3MuZm9yRWFjaChmdW5jdGlvbihsaW5rKSB7XG4gICAgICAgIGxpbmsuc3kgPSBzeTtcbiAgICAgICAgc3kgKz0gbGluay5keTtcbiAgICAgIH0pO1xuICAgICAgbm9kZS50YXJnZXRMaW5rcy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmspIHtcbiAgICAgICAgbGluay50eSA9IHR5O1xuICAgICAgICB0eSArPSBsaW5rLmR5O1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiBhc2NlbmRpbmdTb3VyY2VEZXB0aChhLCBiKSB7XG4gICAgICByZXR1cm4gKGEuc291cmNlLnkgLSBiLnNvdXJjZS55KSB8fCAoYS5vcmlnaW5hbEluZGV4IC0gYi5vcmlnaW5hbEluZGV4KTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBhc2NlbmRpbmdUYXJnZXREZXB0aChhLCBiKSB7XG4gICAgICByZXR1cm4gKGEudGFyZ2V0LnkgLSBiLnRhcmdldC55KSB8fCAoYS5vcmlnaW5hbEluZGV4IC0gYi5vcmlnaW5hbEluZGV4KTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBjZW50ZXIobm9kZSkge1xuICAgIHJldHVybiBub2RlLnkgKyBub2RlLmR5IC8gMjtcbiAgfVxuXG4gIGZ1bmN0aW9uIHZhbHVlKGxpbmspIHtcbiAgICByZXR1cm4gbGluay52YWx1ZTtcbiAgfVxuXG4gIHJldHVybiBzYW5rZXk7XG59XG4iLCIvKipcbiAqIERpcmVjdCBzb3VyY2U6IGh0dHBzOi8vYm9zdC5vY2tzLm9yZy9taWtlL3NhbmtleS8gYnkgTWlrZSBCb3N0b2NrXG4gKiBVbHRpbWF0ZSBzb3VyY2U6IERlcGFydG1lbnQgb2YgRW5lcmd5ICYgQ2xpbWF0ZSBDaGFuZ2UsIFRvbSBDb3Vuc2VsbFxuICogICAgICAgICAgICAgICAgICBodHRwOi8vdGFtYy5naXRodWIuaW8vU2Fua2V5L1xuICovXG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICBcIm5vZGVzXCI6W1xuICAgIHtcIm5hbWVcIjpcIkFncmljdWx0dXJhbCAnd2FzdGUnXCJ9LFxuICAgIHtcIm5hbWVcIjpcIkJpby1jb252ZXJzaW9uXCJ9LFxuICAgIHtcIm5hbWVcIjpcIkxpcXVpZFwifSxcbiAgICB7XCJuYW1lXCI6XCJMb3NzZXNcIn0sXG4gICAge1wibmFtZVwiOlwiU29saWRcIn0sXG4gICAge1wibmFtZVwiOlwiR2FzXCJ9LFxuICAgIHtcIm5hbWVcIjpcIkJpb2Z1ZWwgaW1wb3J0c1wifSxcbiAgICB7XCJuYW1lXCI6XCJCaW9tYXNzIGltcG9ydHNcIn0sXG4gICAge1wibmFtZVwiOlwiQ29hbCBpbXBvcnRzXCJ9LFxuICAgIHtcIm5hbWVcIjpcIkNvYWxcIn0sXG4gICAge1wibmFtZVwiOlwiQ29hbCByZXNlcnZlc1wifSxcbiAgICB7XCJuYW1lXCI6XCJEaXN0cmljdCBoZWF0aW5nXCJ9LFxuICAgIHtcIm5hbWVcIjpcIkluZHVzdHJ5XCJ9LFxuICAgIHtcIm5hbWVcIjpcIkhlYXRpbmcgYW5kIGNvb2xpbmcgLSBjb21tZXJjaWFsXCJ9LFxuICAgIHtcIm5hbWVcIjpcIkhlYXRpbmcgYW5kIGNvb2xpbmcgLSBob21lc1wifSxcbiAgICB7XCJuYW1lXCI6XCJFbGVjdHJpY2l0eSBncmlkXCJ9LFxuICAgIHtcIm5hbWVcIjpcIk92ZXIgZ2VuZXJhdGlvbiAvIGV4cG9ydHNcIn0sXG4gICAge1wibmFtZVwiOlwiSDIgY29udmVyc2lvblwifSxcbiAgICB7XCJuYW1lXCI6XCJSb2FkIHRyYW5zcG9ydFwifSxcbiAgICB7XCJuYW1lXCI6XCJBZ3JpY3VsdHVyZVwifSxcbiAgICB7XCJuYW1lXCI6XCJSYWlsIHRyYW5zcG9ydFwifSxcbiAgICB7XCJuYW1lXCI6XCJMaWdodGluZyAmIGFwcGxpYW5jZXMgLSBjb21tZXJjaWFsXCJ9LFxuICAgIHtcIm5hbWVcIjpcIkxpZ2h0aW5nICYgYXBwbGlhbmNlcyAtIGhvbWVzXCJ9LFxuICAgIHtcIm5hbWVcIjpcIkdhcyBpbXBvcnRzXCJ9LFxuICAgIHtcIm5hbWVcIjpcIk5nYXNcIn0sXG4gICAge1wibmFtZVwiOlwiR2FzIHJlc2VydmVzXCJ9LFxuICAgIHtcIm5hbWVcIjpcIlRoZXJtYWwgZ2VuZXJhdGlvblwifSxcbiAgICB7XCJuYW1lXCI6XCJHZW90aGVybWFsXCJ9LFxuICAgIHtcIm5hbWVcIjpcIkgyXCJ9LFxuICAgIHtcIm5hbWVcIjpcIkh5ZHJvXCJ9LFxuICAgIHtcIm5hbWVcIjpcIkludGVybmF0aW9uYWwgc2hpcHBpbmdcIn0sXG4gICAge1wibmFtZVwiOlwiRG9tZXN0aWMgYXZpYXRpb25cIn0sXG4gICAge1wibmFtZVwiOlwiSW50ZXJuYXRpb25hbCBhdmlhdGlvblwifSxcbiAgICB7XCJuYW1lXCI6XCJOYXRpb25hbCBuYXZpZ2F0aW9uXCJ9LFxuICAgIHtcIm5hbWVcIjpcIk1hcmluZSBhbGdhZVwifSxcbiAgICB7XCJuYW1lXCI6XCJOdWNsZWFyXCJ9LFxuICAgIHtcIm5hbWVcIjpcIk9pbCBpbXBvcnRzXCJ9LFxuICAgIHtcIm5hbWVcIjpcIk9pbFwifSxcbiAgICB7XCJuYW1lXCI6XCJPaWwgcmVzZXJ2ZXNcIn0sXG4gICAge1wibmFtZVwiOlwiT3RoZXIgd2FzdGVcIn0sXG4gICAge1wibmFtZVwiOlwiUHVtcGVkIGhlYXRcIn0sXG4gICAge1wibmFtZVwiOlwiU29sYXIgUFZcIn0sXG4gICAge1wibmFtZVwiOlwiU29sYXIgVGhlcm1hbFwifSxcbiAgICB7XCJuYW1lXCI6XCJTb2xhclwifSxcbiAgICB7XCJuYW1lXCI6XCJUaWRhbFwifSxcbiAgICB7XCJuYW1lXCI6XCJVSyBsYW5kIGJhc2VkIGJpb2VuZXJneVwifSxcbiAgICB7XCJuYW1lXCI6XCJXYXZlXCJ9LFxuICAgIHtcIm5hbWVcIjpcIldpbmRcIn1cbiAgXSxcbiAgXCJsaW5rc1wiOltcbiAgICB7XCJzb3VyY2VcIjowLFwidGFyZ2V0XCI6MSxcInZhbHVlXCI6MTI0LjcyOX0sXG4gICAge1wic291cmNlXCI6MSxcInRhcmdldFwiOjIsXCJ2YWx1ZVwiOjAuNTk3fSxcbiAgICB7XCJzb3VyY2VcIjoxLFwidGFyZ2V0XCI6MyxcInZhbHVlXCI6MjYuODYyfSxcbiAgICB7XCJzb3VyY2VcIjoxLFwidGFyZ2V0XCI6NCxcInZhbHVlXCI6MjgwLjMyMn0sXG4gICAge1wic291cmNlXCI6MSxcInRhcmdldFwiOjUsXCJ2YWx1ZVwiOjgxLjE0NH0sXG4gICAge1wic291cmNlXCI6NixcInRhcmdldFwiOjIsXCJ2YWx1ZVwiOjM1fSxcbiAgICB7XCJzb3VyY2VcIjo3LFwidGFyZ2V0XCI6NCxcInZhbHVlXCI6MzV9LFxuICAgIHtcInNvdXJjZVwiOjgsXCJ0YXJnZXRcIjo5LFwidmFsdWVcIjoxMS42MDZ9LFxuICAgIHtcInNvdXJjZVwiOjEwLFwidGFyZ2V0XCI6OSxcInZhbHVlXCI6NjMuOTY1fSxcbiAgICB7XCJzb3VyY2VcIjo5LFwidGFyZ2V0XCI6NCxcInZhbHVlXCI6NzUuNTcxfSxcbiAgICB7XCJzb3VyY2VcIjoxMSxcInRhcmdldFwiOjEyLFwidmFsdWVcIjoxMC42Mzl9LFxuICAgIHtcInNvdXJjZVwiOjExLFwidGFyZ2V0XCI6MTMsXCJ2YWx1ZVwiOjIyLjUwNX0sXG4gICAge1wic291cmNlXCI6MTEsXCJ0YXJnZXRcIjoxNCxcInZhbHVlXCI6NDYuMTg0fSxcbiAgICB7XCJzb3VyY2VcIjoxNSxcInRhcmdldFwiOjE2LFwidmFsdWVcIjoxMDQuNDUzfSxcbiAgICB7XCJzb3VyY2VcIjoxNSxcInRhcmdldFwiOjE0LFwidmFsdWVcIjoxMTMuNzI2fSxcbiAgICB7XCJzb3VyY2VcIjoxNSxcInRhcmdldFwiOjE3LFwidmFsdWVcIjoyNy4xNH0sXG4gICAge1wic291cmNlXCI6MTUsXCJ0YXJnZXRcIjoxMixcInZhbHVlXCI6MzQyLjE2NX0sXG4gICAge1wic291cmNlXCI6MTUsXCJ0YXJnZXRcIjoxOCxcInZhbHVlXCI6MzcuNzk3fSxcbiAgICB7XCJzb3VyY2VcIjoxNSxcInRhcmdldFwiOjE5LFwidmFsdWVcIjo0LjQxMn0sXG4gICAge1wic291cmNlXCI6MTUsXCJ0YXJnZXRcIjoxMyxcInZhbHVlXCI6NDAuODU4fSxcbiAgICB7XCJzb3VyY2VcIjoxNSxcInRhcmdldFwiOjMsXCJ2YWx1ZVwiOjU2LjY5MX0sXG4gICAge1wic291cmNlXCI6MTUsXCJ0YXJnZXRcIjoyMCxcInZhbHVlXCI6Ny44NjN9LFxuICAgIHtcInNvdXJjZVwiOjE1LFwidGFyZ2V0XCI6MjEsXCJ2YWx1ZVwiOjkwLjAwOH0sXG4gICAge1wic291cmNlXCI6MTUsXCJ0YXJnZXRcIjoyMixcInZhbHVlXCI6OTMuNDk0fSxcbiAgICB7XCJzb3VyY2VcIjoyMyxcInRhcmdldFwiOjI0LFwidmFsdWVcIjo0MC43MTl9LFxuICAgIHtcInNvdXJjZVwiOjI1LFwidGFyZ2V0XCI6MjQsXCJ2YWx1ZVwiOjgyLjIzM30sXG4gICAge1wic291cmNlXCI6NSxcInRhcmdldFwiOjEzLFwidmFsdWVcIjowLjEyOX0sXG4gICAge1wic291cmNlXCI6NSxcInRhcmdldFwiOjMsXCJ2YWx1ZVwiOjEuNDAxfSxcbiAgICB7XCJzb3VyY2VcIjo1LFwidGFyZ2V0XCI6MjYsXCJ2YWx1ZVwiOjE1MS44OTF9LFxuICAgIHtcInNvdXJjZVwiOjUsXCJ0YXJnZXRcIjoxOSxcInZhbHVlXCI6Mi4wOTZ9LFxuICAgIHtcInNvdXJjZVwiOjUsXCJ0YXJnZXRcIjoxMixcInZhbHVlXCI6NDguNTh9LFxuICAgIHtcInNvdXJjZVwiOjI3LFwidGFyZ2V0XCI6MTUsXCJ2YWx1ZVwiOjcuMDEzfSxcbiAgICB7XCJzb3VyY2VcIjoxNyxcInRhcmdldFwiOjI4LFwidmFsdWVcIjoyMC44OTd9LFxuICAgIHtcInNvdXJjZVwiOjE3LFwidGFyZ2V0XCI6MyxcInZhbHVlXCI6Ni4yNDJ9LFxuICAgIHtcInNvdXJjZVwiOjI4LFwidGFyZ2V0XCI6MTgsXCJ2YWx1ZVwiOjIwLjg5N30sXG4gICAge1wic291cmNlXCI6MjksXCJ0YXJnZXRcIjoxNSxcInZhbHVlXCI6Ni45OTV9LFxuICAgIHtcInNvdXJjZVwiOjIsXCJ0YXJnZXRcIjoxMixcInZhbHVlXCI6MTIxLjA2Nn0sXG4gICAge1wic291cmNlXCI6MixcInRhcmdldFwiOjMwLFwidmFsdWVcIjoxMjguNjl9LFxuICAgIHtcInNvdXJjZVwiOjIsXCJ0YXJnZXRcIjoxOCxcInZhbHVlXCI6MTM1LjgzNX0sXG4gICAge1wic291cmNlXCI6MixcInRhcmdldFwiOjMxLFwidmFsdWVcIjoxNC40NTh9LFxuICAgIHtcInNvdXJjZVwiOjIsXCJ0YXJnZXRcIjozMixcInZhbHVlXCI6MjA2LjI2N30sXG4gICAge1wic291cmNlXCI6MixcInRhcmdldFwiOjE5LFwidmFsdWVcIjozLjY0fSxcbiAgICB7XCJzb3VyY2VcIjoyLFwidGFyZ2V0XCI6MzMsXCJ2YWx1ZVwiOjMzLjIxOH0sXG4gICAge1wic291cmNlXCI6MixcInRhcmdldFwiOjIwLFwidmFsdWVcIjo0LjQxM30sXG4gICAge1wic291cmNlXCI6MzQsXCJ0YXJnZXRcIjoxLFwidmFsdWVcIjoxNC4zNzV9LFxuICAgIHtcInNvdXJjZVwiOjI0LFwidGFyZ2V0XCI6NSxcInZhbHVlXCI6MTIyLjk1Mn0sXG4gICAge1wic291cmNlXCI6MzUsXCJ0YXJnZXRcIjoyNixcInZhbHVlXCI6ODM5Ljk3OH0sXG4gICAge1wic291cmNlXCI6MzYsXCJ0YXJnZXRcIjozNyxcInZhbHVlXCI6NTA0LjI4N30sXG4gICAge1wic291cmNlXCI6MzgsXCJ0YXJnZXRcIjozNyxcInZhbHVlXCI6MTA3LjcwM30sXG4gICAge1wic291cmNlXCI6MzcsXCJ0YXJnZXRcIjoyLFwidmFsdWVcIjo2MTEuOTl9LFxuICAgIHtcInNvdXJjZVwiOjM5LFwidGFyZ2V0XCI6NCxcInZhbHVlXCI6NTYuNTg3fSxcbiAgICB7XCJzb3VyY2VcIjozOSxcInRhcmdldFwiOjEsXCJ2YWx1ZVwiOjc3LjgxfSxcbiAgICB7XCJzb3VyY2VcIjo0MCxcInRhcmdldFwiOjE0LFwidmFsdWVcIjoxOTMuMDI2fSxcbiAgICB7XCJzb3VyY2VcIjo0MCxcInRhcmdldFwiOjEzLFwidmFsdWVcIjo3MC42NzJ9LFxuICAgIHtcInNvdXJjZVwiOjQxLFwidGFyZ2V0XCI6MTUsXCJ2YWx1ZVwiOjU5LjkwMX0sXG4gICAge1wic291cmNlXCI6NDIsXCJ0YXJnZXRcIjoxNCxcInZhbHVlXCI6MTkuMjYzfSxcbiAgICB7XCJzb3VyY2VcIjo0MyxcInRhcmdldFwiOjQyLFwidmFsdWVcIjoxOS4yNjN9LFxuICAgIHtcInNvdXJjZVwiOjQzLFwidGFyZ2V0XCI6NDEsXCJ2YWx1ZVwiOjU5LjkwMX0sXG4gICAge1wic291cmNlXCI6NCxcInRhcmdldFwiOjE5LFwidmFsdWVcIjowLjg4Mn0sXG4gICAge1wic291cmNlXCI6NCxcInRhcmdldFwiOjI2LFwidmFsdWVcIjo0MDAuMTJ9LFxuICAgIHtcInNvdXJjZVwiOjQsXCJ0YXJnZXRcIjoxMixcInZhbHVlXCI6NDYuNDc3fSxcbiAgICB7XCJzb3VyY2VcIjoyNixcInRhcmdldFwiOjE1LFwidmFsdWVcIjo1MjUuNTMxfSxcbiAgICB7XCJzb3VyY2VcIjoyNixcInRhcmdldFwiOjMsXCJ2YWx1ZVwiOjc4Ny4xMjl9LFxuICAgIHtcInNvdXJjZVwiOjI2LFwidGFyZ2V0XCI6MTEsXCJ2YWx1ZVwiOjc5LjMyOX0sXG4gICAge1wic291cmNlXCI6NDQsXCJ0YXJnZXRcIjoxNSxcInZhbHVlXCI6OS40NTJ9LFxuICAgIHtcInNvdXJjZVwiOjQ1LFwidGFyZ2V0XCI6MSxcInZhbHVlXCI6MTgyLjAxfSxcbiAgICB7XCJzb3VyY2VcIjo0NixcInRhcmdldFwiOjE1LFwidmFsdWVcIjoxOS4wMTN9LFxuICAgIHtcInNvdXJjZVwiOjQ3LFwidGFyZ2V0XCI6MTUsXCJ2YWx1ZVwiOjI4OS4zNjZ9XG4gIF1cbn07XG4iLCIvKipcbiAqIENvcHlyaWdodCAyMDEyLTIwMTcsIFBsb3RseSwgSW5jLlxuICogQWxsIHJpZ2h0cyByZXNlcnZlZC5cbiAqXG4gKiBUaGlzIHNvdXJjZSBjb2RlIGlzIGxpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZSBmb3VuZCBpbiB0aGVcbiAqIExJQ0VOU0UgZmlsZSBpbiB0aGUgcm9vdCBkaXJlY3Rvcnkgb2YgdGhpcyBzb3VyY2UgdHJlZS5cbiAqL1xuXG4vL3ZhciBkMyA9IHJlcXVpcmUoJ2QzJyk7XG52YXIgZDNzYW5rZXkgPSByZXF1aXJlKCcuL2QzLXNhbmtleScpO1xuXG52YXIgZGF0YSA9IHJlcXVpcmUoJy4vZW5lcmd5Jyk7XG5cbnZhciB3aWR0aCA9IDk2MDtcbnZhciBoZWlnaHQgPSA1MDA7XG52YXIgbWFyZ2luID0ge1xuICBsOiAyMCxcbiAgdDogMjAsXG4gIHI6IDIwMCxcbiAgYjogMjBcbn07XG5cbnZhciBjID0ge1xuICBub2RlVGV4dE9mZnNldDogNSxcbiAgbm9kZVdpZHRoOiAxNSxcbiAgbm9kZVBhZGRpbmc6IDE0LFxuICBzYW5rZXlJdGVyYXRpb25zOiA3MDAsXG4gIHZlcnRpY2FsOiBmYWxzZSxcbiAgbm9kZU9wYWNpdHk6IDAuNyxcbiAgbm9kZVNhbGllbnRPcGFjaXR5OiAxLFxuICBsaW5rT3BhY2l0eTogMC4yLFxuICBsaW5rU2FsaWVudE9wYWNpdHk6IDAuNFxufTtcblxuZnVuY3Rpb24ga2V5RnVuKGQpIHtyZXR1cm4gZC5rZXk7fVxuXG5mdW5jdGlvbiByZXBlYXQoZCkge3JldHVybiBbZF07fVxuXG5mdW5jdGlvbiBub29wKCkge31cblxuZnVuY3Rpb24gdmlld01vZGVsKHNhbmtleSkge1xuXG4gIHJldHVybiB7XG4gICAga2V5OiAwLFxuICAgIHRyYW5zbGF0ZVg6IG1hcmdpbi5sLFxuICAgIHRyYW5zbGF0ZVk6IG1hcmdpbi50LFxuICAgIGRyYWdMZW5ndGg6IGMudmVydGljYWwgPyB3aWR0aCA6IGhlaWdodCxcbiAgICBub2Rlczogc2Fua2V5Lm5vZGVzKCksXG4gICAgbGlua3M6IHNhbmtleS5saW5rcygpLFxuICAgIHNhbmtleTogc2Fua2V5XG4gIH07XG59XG5cbmZ1bmN0aW9uIHJlbmRlcihzdmcsIGNhbGxiYWNrcykge1xuICByZXR1cm4gZnVuY3Rpb24oc2Fua2V5KSB7XG5cbiAgICB2YXIgZHJhZ0luUHJvZ3Jlc3MgPSBmYWxzZTtcbiAgICB2YXIgaG92ZXJlZCA9IGZhbHNlO1xuXG4gICAgZnVuY3Rpb24gYXR0YWNoUG9pbnRlckV2ZW50cyhzZWxlY3Rpb24sIGV2ZW50U2V0KSB7XG4gICAgICBzZWxlY3Rpb25cbiAgICAgICAgLm9uKCdtb3VzZW92ZXInLCBmdW5jdGlvbiAoZCkge1xuICAgICAgICAgIGlmICghZHJhZ0luUHJvZ3Jlc3MpIHtcbiAgICAgICAgICAgIGV2ZW50U2V0LmhvdmVyKHRoaXMsIGQpO1xuICAgICAgICAgICAgaG92ZXJlZCA9IFt0aGlzLCBkXTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICAgIC5vbignbW91c2VvdXQnLCBmdW5jdGlvbiAoZCkge1xuICAgICAgICAgIGlmICghZHJhZ0luUHJvZ3Jlc3MpIHtcbiAgICAgICAgICAgIGV2ZW50U2V0LnVuaG92ZXIodGhpcywgZCk7XG4gICAgICAgICAgICBob3ZlcmVkID0gZmFsc2U7XG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgICAub24oJ2NsaWNrJywgZnVuY3Rpb24gKGQpIHtcbiAgICAgICAgICBpZiAoaG92ZXJlZCkge1xuICAgICAgICAgICAgZXZlbnRTZXQudW5ob3Zlcih0aGlzLCBkKTtcbiAgICAgICAgICAgIGhvdmVyZWQgPSBmYWxzZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKCFkcmFnSW5Qcm9ncmVzcykge1xuICAgICAgICAgICAgZXZlbnRTZXQuc2VsZWN0KHRoaXMsIGQpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbGlua1BhdGgoZCkge1xuICAgICAgcmV0dXJuIGQuc2Fua2V5LmxpbmsoKShkLmxpbmspO1xuICAgIH1cblxuICAgIHZhciBjb2xvcmVyID0gZDMuc2NhbGUuY2F0ZWdvcnkyMCgpO1xuXG4gICAgdmFyIHNhbmtleSA9IHN2Zy5zZWxlY3RBbGwoJy5zYW5rZXknKVxuICAgICAgLmRhdGEoW3ZpZXdNb2RlbChzYW5rZXkpXSwga2V5RnVuKTtcblxuICAgIHNhbmtleS5lbnRlcigpXG4gICAgICAuYXBwZW5kKCdnJylcbiAgICAgIC5jbGFzc2VkKCdzYW5rZXknLCB0cnVlKVxuICAgICAgLmF0dHIoJ292ZXJmbG93JywgJ3Zpc2libGUnKVxuICAgICAgLnN0eWxlKCdib3gtc2l6aW5nJywgJ2NvbnRlbnQtYm94JylcbiAgICAgIC5zdHlsZSgncG9zaXRpb24nLCAnYWJzb2x1dGUnKVxuICAgICAgLnN0eWxlKCdsZWZ0JywgMClcbiAgICAgIC5zdHlsZSgnb3ZlcmZsb3cnLCAndmlzaWJsZScpXG4gICAgICAuc3R5bGUoJ3NoYXBlLXJlbmRlcmluZycsICdnZW9tZXRyaWNQcmVjaXNpb24nKVxuICAgICAgLnN0eWxlKCdwb2ludGVyLWV2ZW50cycsICdhdXRvJylcbiAgICAgIC5zdHlsZSgnYm94LXNpemluZycsICdjb250ZW50LWJveCcpO1xuXG4gICAgc2Fua2V5XG4gICAgICAuYXR0cigndHJhbnNmb3JtJywgZnVuY3Rpb24oZCkge1xuICAgICAgICByZXR1cm4gJ3RyYW5zbGF0ZSgnICsgZC50cmFuc2xhdGVYICsgJywnICsgZC50cmFuc2xhdGVZICsgJyknO1xuICAgICAgfSk7XG5cbiAgICB2YXIgc2Fua2V5TGlua3MgPSBzYW5rZXkuc2VsZWN0QWxsKCcuc2Fua2V5TGlua3MnKVxuICAgICAgLmRhdGEocmVwZWF0LCBrZXlGdW4pO1xuXG4gICAgc2Fua2V5TGlua3MuZW50ZXIoKVxuICAgICAgLmFwcGVuZCgnZycpXG4gICAgICAuY2xhc3NlZCgnc2Fua2V5TGlua3MnLCB0cnVlKVxuICAgICAgLnN0eWxlKCd0cmFuc2Zvcm0nLCBjLnZlcnRpY2FsID8gJ21hdHJpeCgwLDEsMSwwLDAsMCknIDogJ21hdHJpeCgxLDAsMCwxLDAsMCknKVxuICAgICAgLnN0eWxlKCdmaWxsJywgJ25vbmUnKVxuICAgICAgLnN0eWxlKCdzdHJva2UnLCAnYmxhY2snKVxuICAgICAgLnN0eWxlKCdzdHJva2Utb3BhY2l0eScsIGMubGlua09wYWNpdHkpO1xuXG4gICAgdmFyIHNhbmtleUxpbmsgPSBzYW5rZXlMaW5rcy5zZWxlY3RBbGwoJy5zYW5rZXlQYXRoJylcbiAgICAgIC5kYXRhKGZ1bmN0aW9uKGQpIHtcbiAgICAgICAgcmV0dXJuIGQuc2Fua2V5LmxpbmtzKCkubWFwKGZ1bmN0aW9uKGwpIHtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgbGluazogbCxcbiAgICAgICAgICAgIHNhbmtleTogZC5zYW5rZXlcbiAgICAgICAgICB9O1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgc2Fua2V5TGluay5lbnRlcigpXG4gICAgICAuYXBwZW5kKCdwYXRoJylcbiAgICAgIC5jbGFzc2VkKCdzYW5rZXlQYXRoJywgdHJ1ZSlcbiAgICAgIC5jYWxsKGF0dGFjaFBvaW50ZXJFdmVudHMsIGNhbGxiYWNrcy5saW5rRXZlbnRzKTtcblxuICAgIHNhbmtleUxpbmtcbiAgICAgIC5hdHRyKCdkJywgbGlua1BhdGgpXG4gICAgICAuc3R5bGUoJ3N0cm9rZS13aWR0aCcsIGZ1bmN0aW9uKGQpIHtyZXR1cm4gTWF0aC5tYXgoMSwgZC5saW5rLmR5KTt9KTtcblxuICAgIHZhciBzYW5rZXlOb2RlcyA9IHNhbmtleS5zZWxlY3RBbGwoJy5zYW5rZXlOb2RlcycpXG4gICAgICAuZGF0YShyZXBlYXQsIGtleUZ1bik7XG5cbiAgICBzYW5rZXlOb2Rlcy5lbnRlcigpXG4gICAgICAuYXBwZW5kKCdnJylcbiAgICAgIC5zdHlsZSgnc2hhcGUtcmVuZGVyaW5nJywgJ2NyaXNwRWRnZXMnKVxuICAgICAgLmNsYXNzZWQoJ3NhbmtleU5vZGVzJywgdHJ1ZSk7XG5cbiAgICB2YXIgc2Fua2V5Tm9kZSA9IHNhbmtleU5vZGVzLnNlbGVjdEFsbCgnLnNhbmtleU5vZGUnKVxuICAgICAgLmRhdGEoZnVuY3Rpb24oZCkge1xuICAgICAgICByZXR1cm4gZC5zYW5rZXkubm9kZXMoKS5tYXAoZnVuY3Rpb24obCkge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBub2RlOiBsLFxuICAgICAgICAgICAgc2Fua2V5OiBkLnNhbmtleSxcbiAgICAgICAgICAgIG1vZGVsOiBkXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG4gICAgICB9LCBmdW5jdGlvbihkKSB7cmV0dXJuIGQubm9kZS5uYW1lO30pO1xuXG4gICAgc2Fua2V5Tm9kZS5lbnRlcigpXG4gICAgICAuYXBwZW5kKCdnJylcbiAgICAgIC5jbGFzc2VkKCdzYW5rZXlOb2RlJywgdHJ1ZSlcbiAgICAgIC5jYWxsKGQzLmJlaGF2aW9yLmRyYWcoKVxuICAgICAgICAub3JpZ2luKGZ1bmN0aW9uKGQpIHtyZXR1cm4gYy52ZXJ0aWNhbCA/IHt4OiBkLm5vZGUueX0gOiBkLm5vZGU7fSlcbiAgICAgICAgLm9uKCdkcmFnc3RhcnQnLCBmdW5jdGlvbihkKSB7XG4gICAgICAgICAgZC5ub2RlLmRyYWdTdGFydExvY2F0aW9uID0gYy52ZXJ0aWNhbCA/IGQzLmV2ZW50LnggOiBkMy5ldmVudC55O1xuICAgICAgICAgIHRoaXMucGFyZW50Tm9kZS5hcHBlbmRDaGlsZCh0aGlzKTtcbiAgICAgICAgICBkcmFnSW5Qcm9ncmVzcyA9IHRydWU7XG4gICAgICAgICAgaWYoaG92ZXJlZCkge1xuICAgICAgICAgICAgLy9jYWxsYmFja3Mubm9kZUV2ZW50cy51bmhvdmVyLmFwcGx5KDAsIGhvdmVyZWQpO1xuICAgICAgICAgICAgaG92ZXJlZCA9IGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgICAgLm9uKCdkcmFnJywgZnVuY3Rpb24oZCkge1xuICAgICAgICAgICAgaWYoYy52ZXJ0aWNhbCkge1xuICAgICAgICAgICAgICBkLm5vZGUueSA9IE1hdGgubWF4KDAsIE1hdGgubWluKGQubW9kZWwuZHJhZ0xlbmd0aCAtIGQubm9kZS5keSwgZDMuZXZlbnQueCkpO1xuICAgICAgICAgICAgICBkMy5zZWxlY3QodGhpcykuc3R5bGUoJ3RyYW5zZm9ybScsICd0cmFuc2xhdGUoJyArIGQubm9kZS55ICsgJ3B4LCcgKyBkLm5vZGUueCArICdweCknKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGQubm9kZS55ID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oZC5tb2RlbC5kcmFnTGVuZ3RoIC0gZC5ub2RlLmR5LCBkMy5ldmVudC55KSk7XG4gICAgICAgICAgICAgIGQzLnNlbGVjdCh0aGlzKS5zdHlsZSgndHJhbnNmb3JtJywgJ3RyYW5zbGF0ZSgnICsgZC5ub2RlLnggKyAncHgsJyArIGQubm9kZS55ICsgJ3B4KScpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBkLnNhbmtleS5yZWxheW91dCgpO1xuICAgICAgICAgICAgc2Fua2V5TGluay5hdHRyKCdkJywgbGlua1BhdGgpO1xuICAgICAgICAgIH1cbiAgICAgICAgKVxuICAgICAgICAub24oJ2RyYWdlbmQnLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICBkcmFnSW5Qcm9ncmVzcyA9IGZhbHNlO1xuICAgICAgICB9KSk7XG5cbiAgICBzYW5rZXlOb2RlXG4gICAgICAuc3R5bGUoJ3RyYW5zZm9ybScsIGMudmVydGljYWwgP1xuICAgICAgICBmdW5jdGlvbihkKSB7cmV0dXJuICd0cmFuc2xhdGUoJyArIChNYXRoLmZsb29yKGQubm9kZS55KSAtIDAuNSkgKyAncHgsICcgKyAoTWF0aC5mbG9vcihkLm5vZGUueCkgKyAwLjUpICsgJ3B4KSc7fSA6XG4gICAgICAgIGZ1bmN0aW9uKGQpIHtyZXR1cm4gJ3RyYW5zbGF0ZSgnICsgKE1hdGguZmxvb3IoZC5ub2RlLngpIC0gMC41KSArICdweCwgJyArIChNYXRoLmZsb29yKGQubm9kZS55KSArIDAuNSkgKyAncHgpJzt9KTtcblxuICAgIHZhciBub2RlUmVjdCA9IHNhbmtleU5vZGUuc2VsZWN0QWxsKCcubm9kZVJlY3QnKVxuICAgICAgLmRhdGEocmVwZWF0KTtcblxuICAgIG5vZGVSZWN0LmVudGVyKClcbiAgICAgIC5hcHBlbmQoJ3JlY3QnKVxuICAgICAgLmNsYXNzZWQoJ25vZGVSZWN0JywgdHJ1ZSlcbiAgICAgIC5zdHlsZSgnc2hhcGUtcmVuZGVyaW5nJywgJ2NyaXNwRWRnZXMnKVxuICAgICAgLnN0eWxlKCdmaWxsJywgZnVuY3Rpb24oZCkge3JldHVybiBjb2xvcmVyKGQuc2Fua2V5Lm5vZGVzKCkuaW5kZXhPZihkLm5vZGUpKTt9KVxuICAgICAgLnN0eWxlKCdzdHJva2Utd2lkdGgnLCAwLjUpXG4gICAgICAuc3R5bGUoJ3N0cm9rZScsICdibGFjaycpXG4gICAgICAuc3R5bGUoJ3N0cm9rZS1vcGFjaXR5JywgMSlcbiAgICAgIC5zdHlsZSgnZmlsbC1vcGFjaXR5JywgYy5ub2RlT3BhY2l0eSlcbiAgICAgIC5jYWxsKGF0dGFjaFBvaW50ZXJFdmVudHMsIGNhbGxiYWNrcy5ub2RlRXZlbnRzKTtcblxuICAgIG5vZGVSZWN0IC8vIGNlaWwsICsvLTAuNSBhbmQgY3Jpc3BFZGdlcyBpcyB3aXphcmRyeSBmb3IgY29uc2lzdGVudCBib3JkZXIgd2lkdGggb24gYWxsIDQgc2lkZXNcbiAgICAgIC5hdHRyKGMudmVydGljYWwgPyAnaGVpZ2h0JyA6ICd3aWR0aCcsIGZ1bmN0aW9uKGQpIHtyZXR1cm4gTWF0aC5jZWlsKGQubm9kZS5keCArIDAuNSk7fSlcbiAgICAgIC5hdHRyKGMudmVydGljYWwgPyAnd2lkdGgnIDogJ2hlaWdodCcsIGZ1bmN0aW9uKGQpIHtyZXR1cm4gTWF0aC5jZWlsKGQubm9kZS5keSAtIDAuNSk7fSk7XG5cbiAgICB2YXIgbm9kZUxhYmVsID0gc2Fua2V5Tm9kZS5zZWxlY3RBbGwoJy5ub2RlTGFiZWwnKVxuICAgICAgLmRhdGEocmVwZWF0KTtcblxuICAgIG5vZGVMYWJlbC5lbnRlcigpXG4gICAgICAuYXBwZW5kKCd0ZXh0JylcbiAgICAgIC5jbGFzc2VkKCdub2RlTGFiZWwnLCB0cnVlKTtcblxuICAgIG5vZGVMYWJlbFxuICAgICAgLmF0dHIoJ3gnLCBmdW5jdGlvbihkKSB7cmV0dXJuIGMudmVydGljYWwgPyBkLm5vZGUuZHkgLyAyIDogZC5ub2RlLmR4ICsgYy5ub2RlVGV4dE9mZnNldDt9KVxuICAgICAgLmF0dHIoJ3knLCBmdW5jdGlvbihkKSB7cmV0dXJuIGMudmVydGljYWwgPyBkLm5vZGUuZHggLyAyIDogZC5ub2RlLmR5IC8gMjt9KVxuICAgICAgLnRleHQoZnVuY3Rpb24oZCkge3JldHVybiBkLm5vZGUubmFtZTt9KVxuICAgICAgLmF0dHIoJ2FsaWdubWVudC1iYXNlbGluZScsICdtaWRkbGUnKVxuICAgICAgLmF0dHIoJ3RleHQtYW5jaG9yJywgYy52ZXJ0aWNhbCA/ICdtaWRkbGUnIDogJ3N0YXJ0JylcbiAgICAgIC5zdHlsZSgnZm9udC1mYW1pbHknLCAnc2Fucy1zZXJpZicpXG4gICAgICAuc3R5bGUoJ2ZvbnQtc2l6ZScsICcxMHB4Jyk7XG4gIH07XG59O1xuXG52YXIgc3ZnID0gZDMuc2VsZWN0KCdib2R5JykuYXBwZW5kKCdzdmcnKVxuICAuYXR0cignd2lkdGgnLCB3aWR0aCArIG1hcmdpbi5sICsgbWFyZ2luLnIpXG4gIC5hdHRyKCdoZWlnaHQnLCBoZWlnaHQgKyBtYXJnaW4udCArIG1hcmdpbi5iKTtcblxudmFyIHJlbmRlcmVyID0gcmVuZGVyKHN2Zywge1xuICBsaW5rRXZlbnRzOiB7XG4gICAgaG92ZXI6IGZ1bmN0aW9uKGUsIGwpIHtcbiAgICAgIGQzLnNlbGVjdEFsbCgnLm5vZGVSZWN0JylcbiAgICAgICAgLmZpbHRlcihmdW5jdGlvbihuKSB7cmV0dXJuIG4ubm9kZS5uYW1lID09PSBsLmxpbmsuc291cmNlLm5hbWUgfHwgbi5ub2RlLm5hbWUgPT09IGwubGluay50YXJnZXQubmFtZTt9KVxuICAgICAgICAuc3R5bGUoJ2ZpbGwtb3BhY2l0eScsIGMubm9kZVNhbGllbnRPcGFjaXR5KTtcbiAgICAgIGQzLnNlbGVjdChlKS5zdHlsZSgnc3Ryb2tlLW9wYWNpdHknLCBjLmxpbmtTYWxpZW50T3BhY2l0eSk7XG4gICAgfSxcbiAgICB1bmhvdmVyOiBmdW5jdGlvbihlLCBkKSB7XG4gICAgICBkMy5zZWxlY3RBbGwoJy5ub2RlUmVjdCcpLnN0eWxlKCdmaWxsLW9wYWNpdHknLCBjLm5vZGVPcGFjaXR5KTtcbiAgICAgIGQzLnNlbGVjdChlKS5zdHlsZSgnc3Ryb2tlLW9wYWNpdHknLCBjLmxpbmtPcGFjaXR5KTtcbiAgICB9LFxuICAgIHNlbGVjdDogbm9vcFxuICB9LFxuICBub2RlRXZlbnRzOiB7XG4gICAgaG92ZXI6IGZ1bmN0aW9uKGUsIG4pIHtcbiAgICAgIGQzLnNlbGVjdEFsbCgnLnNhbmtleVBhdGgnKVxuICAgICAgICAuZmlsdGVyKGZ1bmN0aW9uKGwpIHtyZXR1cm4gbi5ub2RlLm5hbWUgPT09IGwubGluay5zb3VyY2UubmFtZSB8fCBuLm5vZGUubmFtZSA9PT0gbC5saW5rLnRhcmdldC5uYW1lO30pXG4gICAgICAgIC5zdHlsZSgnc3Ryb2tlLW9wYWNpdHknLCBjLmxpbmtTYWxpZW50T3BhY2l0eSk7XG4gICAgICBkMy5zZWxlY3QoZSkuc3R5bGUoJ2ZpbGwtb3BhY2l0eScsIGMubm9kZVNhbGllbnRPcGFjaXR5KTtcbiAgICB9LFxuICAgIHVuaG92ZXI6IGZ1bmN0aW9uKGUsIGQpIHtcbiAgICAgIGQzLnNlbGVjdEFsbCgnLnNhbmtleVBhdGgnKS5zdHlsZSgnc3Ryb2tlLW9wYWNpdHknLCBjLmxpbmtPcGFjaXR5KTtcbiAgICAgIGQzLnNlbGVjdChlKS5zdHlsZSgnZmlsbC1vcGFjaXR5JywgYy5ub2RlT3BhY2l0eSk7XG4gICAgfSxcbiAgICBzZWxlY3Q6IG5vb3BcbiAgfVxufSk7XG5cbmQzc2Fua2V5KClcbiAgLnNpemUoYy52ZXJ0aWNhbCA/IFtoZWlnaHQsIHdpZHRoXTogW3dpZHRoLCBoZWlnaHRdKVxuICAubm9kZVdpZHRoKGMubm9kZVdpZHRoKVxuICAubm9kZVBhZGRpbmcoYy5ub2RlUGFkZGluZylcbiAgLm5vZGVzKGRhdGEubm9kZXMpXG4gIC5saW5rcyhkYXRhLmxpbmtzKVxuICAubGF5b3V0KGMuc2Fua2V5SXRlcmF0aW9ucywgcmVuZGVyZXIpOyJdfQ==
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment