@rinminase/ng-charts
Version:
Reactive, responsive, beautiful charts for Angular based on ng2-charts
327 lines • 48.3 kB
JavaScript
export function monkeyPatchChartJsLegend() {
if (typeof Chart === "undefined") {
console.log("Chart not defined");
return;
}
const plugins = Chart.plugins.getAll();
const legend = plugins.filter((p) => p.id === "legend")[0];
legend._element.prototype.fit = fit;
legend._element.prototype.draw = draw;
const helpers = Chart.helpers;
const defaults = Chart.defaults;
const valueOrDefault = helpers.valueOrDefault;
function getBoxWidth(labelOpts, fontSize) {
return labelOpts.usePointStyle && labelOpts.boxWidth > fontSize
? fontSize
: labelOpts.boxWidth;
}
function fit() {
let me = this;
let opts = me.options;
let labelOpts = opts.labels;
let display = opts.display;
let ctx = me.ctx;
let labelFont = helpers.options._parseFont(labelOpts);
let fontSize = labelFont.size;
// Reset hit boxes
let hitboxes = (me.legendHitBoxes = []);
let minSize = me.minSize;
let isHorizontal = me.isHorizontal();
if (isHorizontal) {
minSize.width = me.maxWidth; // fill all the width
minSize.height = display ? 10 : 0;
}
else {
minSize.width = display ? 10 : 0;
minSize.height = me.maxHeight; // fill all the height
}
let getMaxLineWidth = function (textLines) {
return textLines
.map(function (textLine) {
return ctx.measureText(textLine).width;
})
.reduce(function (acc, v) {
return v > acc ? v : acc;
}, 0);
};
// Increase sizes here
if (display) {
ctx.font = labelFont.string;
if (isHorizontal) {
// Width of each line of legend boxes. Labels wrap onto multiple lines when there are too many to fit on one
let lineWidths = (me.lineWidths = [0]);
let lineHeights = (me.lineHeights = []);
let currentLineHeight = 0;
let lineIndex = 0;
ctx.textAlign = "left";
ctx.textBaseline = "top";
helpers.each(me.legendItems, function (legendItem, i) {
let width, height;
if (helpers.isArray(legendItem.text)) {
width = getMaxLineWidth(legendItem.text);
height = fontSize * legendItem.text.length + labelOpts.padding;
}
else {
width = ctx.measureText(legendItem.text).width;
height = fontSize + labelOpts.padding;
}
width += getBoxWidth(labelOpts, fontSize) + fontSize / 2;
if (lineWidths[lineWidths.length - 1] + width + 2 * labelOpts.padding >
minSize.width) {
lineHeights.push(currentLineHeight);
currentLineHeight = 0;
lineWidths[lineWidths.length - (i > 0 ? 0 : 1)] = 0;
lineIndex++;
}
legendItem.lineOrColumnIndex = lineIndex;
if (height > currentLineHeight) {
currentLineHeight = height;
}
// Store the hitbox width and height here. Final position will be updated in `draw`
hitboxes[i] = {
left: 0,
top: 0,
width: width,
height: height,
};
lineWidths[lineWidths.length - 1] += width + labelOpts.padding;
});
lineHeights.push(currentLineHeight);
minSize.height += lineHeights.reduce(function (acc, v) {
return acc + v;
}, 0);
}
else {
let vPadding = labelOpts.padding;
let columnWidths = (me.columnWidths = []);
let columnHeights = (me.columnHeights = []);
let totalWidth = labelOpts.padding;
let currentColWidth = 0;
let currentColHeight = 0;
let columnIndex = 0;
helpers.each(me.legendItems, function (legendItem, i) {
let itemWidth;
let height;
if (helpers.isArray(legendItem.text)) {
itemWidth = getMaxLineWidth(legendItem.text);
height = fontSize * legendItem.text.length;
}
else {
itemWidth = ctx.measureText(legendItem.text).width;
height = fontSize;
}
itemWidth += getBoxWidth(labelOpts, fontSize) + fontSize / 2;
// If too tall, go to new column
if (currentColHeight + fontSize + 2 * vPadding > minSize.height) {
totalWidth += currentColWidth + labelOpts.padding;
columnWidths.push(currentColWidth); // previous column width
columnHeights.push(currentColHeight);
currentColWidth = 0;
currentColHeight = 0;
columnIndex++;
}
legendItem.lineOrColumnIndex = columnIndex;
// Get max width
currentColWidth = Math.max(currentColWidth, itemWidth);
currentColHeight += height + vPadding;
// Store the hitbox width and height here. Final position will be updated in `draw`
hitboxes[i] = {
left: 0,
top: 0,
width: itemWidth,
height: height,
};
});
totalWidth += currentColWidth;
columnWidths.push(currentColWidth);
columnHeights.push(currentColHeight);
minSize.width += totalWidth;
}
}
me.width = minSize.width;
me.height = minSize.height;
}
function draw() {
let me = this;
let opts = me.options;
let labelOpts = opts.labels;
let globalDefaults = defaults.global;
let defaultColor = globalDefaults.defaultColor;
let lineDefault = globalDefaults.elements.line;
let legendHeight = me.height;
let columnHeights = me.columnHeights;
let columnWidths = me.columnWidths;
let legendWidth = me.width;
let lineWidths = me.lineWidths;
let lineHeights = me.lineHeights;
if (opts.display) {
let ctx = me.ctx;
let fontColor = valueOrDefault(labelOpts.fontColor, globalDefaults.defaultFontColor);
let labelFont = helpers.options._parseFont(labelOpts);
let fontSize = labelFont.size;
let cursor;
// Canvas setup
ctx.textAlign = "left";
ctx.textBaseline = "middle";
ctx.lineWidth = 0.5;
ctx.strokeStyle = fontColor; // for strikethrough effect
ctx.fillStyle = fontColor; // render in correct colour
ctx.font = labelFont.string;
let boxWidth = getBoxWidth(labelOpts, fontSize);
let hitboxes = me.legendHitBoxes;
// current position
let drawLegendBox = function (x, y, legendItem) {
if (isNaN(boxWidth) || boxWidth <= 0) {
return;
}
// Set the ctx for the box
ctx.save();
let lineWidth = valueOrDefault(legendItem.lineWidth, lineDefault.borderWidth);
ctx.fillStyle = valueOrDefault(legendItem.fillStyle, defaultColor);
ctx.lineCap = valueOrDefault(legendItem.lineCap, lineDefault.borderCapStyle);
ctx.lineDashOffset = valueOrDefault(legendItem.lineDashOffset, lineDefault.borderDashOffset);
ctx.lineJoin = valueOrDefault(legendItem.lineJoin, lineDefault.borderJoinStyle);
ctx.lineWidth = lineWidth;
ctx.strokeStyle = valueOrDefault(legendItem.strokeStyle, defaultColor);
if (ctx.setLineDash) {
// IE 9 and 10 do not support line dash
ctx.setLineDash(valueOrDefault(legendItem.lineDash, lineDefault.borderDash));
}
if (opts.labels && opts.labels.usePointStyle) {
// Recalculate x and y for drawPoint() because its expecting
// x and y to be center of figure (instead of top left)
let radius = (boxWidth * Math.SQRT2) / 2;
let centerX = x + boxWidth / 2;
let centerY = y + fontSize / 2;
// Draw pointStyle as legend symbol
helpers.canvas.drawPoint(ctx, legendItem.pointStyle, radius, centerX, centerY);
}
else {
// Draw box as legend symbol
if (lineWidth !== 0) {
ctx.strokeRect(x, y, boxWidth, fontSize);
}
ctx.fillRect(x, y, boxWidth, fontSize);
}
ctx.restore();
};
let drawStrikeThrough = function (x, y, w) {
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x, y);
ctx.lineTo(x + w, y);
ctx.stroke();
};
let drawCrossOver = function (x, y, w, h) {
ctx.beginPath();
ctx.lineWidth = 2;
ctx.moveTo(x, y);
ctx.lineTo(x + w, y + h);
ctx.moveTo(x, y + h);
ctx.lineTo(x + w, y);
ctx.stroke();
};
let fillText = function (x, y, legendItem, textWidth) {
let halfFontSize = fontSize / 2;
let xLeft = boxWidth + halfFontSize + x;
let yMiddle = y + halfFontSize;
if (helpers.isArray(legendItem.text)) {
helpers.each(legendItem.text, function (textLine, index) {
let lineOffset = index * fontSize;
ctx.fillText(textLine, xLeft, yMiddle + lineOffset);
});
}
else {
ctx.fillText(legendItem.text, xLeft, yMiddle);
}
if (legendItem.hidden) {
if (helpers.isArray(legendItem.text)) {
drawCrossOver(xLeft, yMiddle, textWidth, (legendItem.text.length - 1) * (fontSize - 1));
}
else {
drawStrikeThrough(xLeft, yMiddle, textWidth);
}
}
};
let alignmentOffset = function (dimension, blockSize) {
switch (opts.align) {
case "start":
return labelOpts.padding;
case "end":
return dimension - blockSize;
default:
// center
return (dimension - blockSize + labelOpts.padding) / 2;
}
};
// Horizontal
let isHorizontal = me.isHorizontal();
if (isHorizontal) {
cursor = {
x: me.left + alignmentOffset(legendWidth, lineWidths[0]),
y: me.top + labelOpts.padding,
line: 0,
};
}
else {
cursor = {
x: me.left + labelOpts.padding,
y: me.top + alignmentOffset(legendHeight, columnHeights[0]),
line: 0,
};
}
helpers.each(me.legendItems, function (legendItem, i) {
let textWidth, height, boxTopOffset;
if (legendItem.lineOrColumnIndex > cursor.line) {
if (isHorizontal) {
cursor.y += lineHeights[cursor.line];
cursor.line = legendItem.lineOrColumnIndex;
cursor.x =
me.left + alignmentOffset(legendWidth, lineWidths[cursor.line]);
}
else {
cursor.x += columnWidths[cursor.line] + labelOpts.padding;
cursor.line = legendItem.lineOrColumnIndex;
cursor.y =
me.top +
alignmentOffset(legendHeight, columnHeights[cursor.line]);
}
}
if (helpers.isArray(legendItem.text)) {
textWidth = legendItem.text
.map(function (textLine) {
return ctx.measureText(textLine).width;
})
.reduce(function (acc, v) {
return v > acc ? v : acc;
}, 0);
boxTopOffset = (fontSize / 2) * (legendItem.text.length - 1);
height = fontSize * legendItem.text.length;
}
else {
textWidth = ctx.measureText(legendItem.text).width;
boxTopOffset = 0;
height = fontSize;
}
let width = boxWidth + fontSize / 2 + textWidth;
let x = cursor.x;
let y = cursor.y;
let topOffset = isHorizontal
? Math.trunc((lineHeights[cursor.line] - hitboxes[i].height) / 2)
: 0;
drawLegendBox(x, y + boxTopOffset + topOffset, legendItem);
hitboxes[i].left = x;
hitboxes[i].top = y;
// Fill the actual label
fillText(x, y + topOffset, legendItem, textWidth);
if (isHorizontal) {
cursor.x += width + labelOpts.padding;
}
else {
cursor.y += height + labelOpts.padding;
}
});
}
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9ua2V5LXBhdGNoLWNoYXJ0LWpzLWxlZ2VuZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvbW9ua2V5LXBhdGNoLWNoYXJ0LWpzLWxlZ2VuZC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFRQSxNQUFNLFVBQVUsd0JBQXdCO0lBQ3RDLElBQUksT0FBTyxLQUFLLEtBQUssV0FBVyxFQUFFO1FBQ2hDLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUNqQyxPQUFPO0tBQ1I7SUFDRCxNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQ3ZDLE1BQU0sTUFBTSxHQUFHLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0QsTUFBTSxDQUFDLFFBQVEsQ0FBQyxTQUFTLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQztJQUNwQyxNQUFNLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDO0lBRXRDLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUM7SUFDOUIsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLFFBQVEsQ0FBQztJQUNoQyxNQUFNLGNBQWMsR0FBRyxPQUFPLENBQUMsY0FBYyxDQUFDO0lBRTlDLFNBQVMsV0FBVyxDQUFDLFNBQVMsRUFBRSxRQUFRO1FBQ3RDLE9BQU8sU0FBUyxDQUFDLGFBQWEsSUFBSSxTQUFTLENBQUMsUUFBUSxHQUFHLFFBQVE7WUFDN0QsQ0FBQyxDQUFDLFFBQVE7WUFDVixDQUFDLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQztJQUN6QixDQUFDO0lBRUQsU0FBUyxHQUFHO1FBQ1YsSUFBSSxFQUFFLEdBQUcsSUFBSSxDQUFDO1FBQ2QsSUFBSSxJQUFJLEdB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QUM7Z0JBRWpCLElBQUksU0FBUyxHQUFHLFlBQVk7b0JBQzFCLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsV0FBVyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO29CQUNqRSxDQUFDLENBQUMsQ0FBQyxDQUFDO2dCQUVOLGFBQWEsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxHQUFHLFlBQVksR0FBRyxTQUFTLEVBQUUsVUFBVSxDQUFDLENBQUM7Z0JBRTNELFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDO2dCQUNyQixRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQztnQkFFcEIsd0JBQXdCO2dCQUN4QixRQUFRLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxTQUFTLEVBQUUsVUFBVSxFQUFFLFNBQVMsQ0FBQyxDQUFDO2dCQUVsRCxJQUFJLFlBQVksRUFBRTtvQkFDaEIsTUFBTSxDQUFDLENBQUMsSUFBSSxLQUFLLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQztpQkFDdkM7cUJBQU07b0JBQ0wsTUFBTSxDQUFDLENBQUMsSUFBSSxNQUFNLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQztpQkFDeEM7WUFDSCxDQUFDLENBQUMsQ0FBQztTQUNKO0lBQ0gsQ0FBQztBQUNILENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJkZWNsYXJlIGNsYXNzIENoYXJ0IHtcbiAgc3RhdGljIHJlYWRvbmx5IENoYXJ0OiB0eXBlb2YgQ2hhcnQ7XG4gIHN0YXRpYyByZWFkb25seSBUb29sdGlwOiBhbnk7XG4gIHN0YXRpYyByZWFkb25seSBoZWxwZXJzOiBhbnk7XG4gIHN0YXRpYyByZWFkb25seSBkZWZhdWx0czogYW55O1xuICBzdGF0aWMgcmVhZG9ubHkgcGx1Z2luczogYW55O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbW9ua2V5UGF0Y2hDaGFydEpzTGVnZW5kKCkge1xuICBpZiAodHlwZW9mIENoYXJ0ID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgY29uc29sZS5sb2coXCJDaGFydCBub3QgZGVmaW5lZFwiKTtcbiAgICByZXR1cm47XG4gIH1cbiAgY29uc3QgcGx1Z2lucyA9IENoYXJ0LnBsdWdpbnMuZ2V0QWxsKCk7XG4gIGNvbnN0IGxlZ2VuZCA9IHBsdWdpbnMuZmlsdGVyKChwKSA9PiBwLmlkID09PSBcImxlZ2VuZFwiKVswXTtcbiAgbGVnZW5kLl9lbGVtZW50LnByb3RvdHlwZS5maXQgPSBmaXQ7XG4gIGxlZ2VuZC5fZWxlbWVudC5wcm90b3R5cGUuZHJhdyA9IGRyYXc7XG5cbiAgY29uc3QgaGVscGVycyA9IENoYXJ0LmhlbHBlcnM7XG4gIGNvbnN0IGRlZmF1bHRzID0gQ2hhcnQuZGVmYXVsdHM7XG4gIGNvbnN0IHZhbHVlT3JEZWZhdWx0ID0gaGVscGVycy52YWx1ZU9yRGVmYXVsdDtcblxuICBmdW5jdGlvbiBnZXRCb3hXaWR0aChsYWJlbE9wdHMsIGZvbnRTaXplKSB7XG4gICAgcmV0dXJuIGxhYmVsT3B0cy51c2VQb2ludFN0eWxlICYmIGxhYmVsT3B0cy5ib3hXaWR0aCA+IGZvbnRTaXplXG4gICAgICA/IGZvbnRTaXplXG4gICAgICA6IGxhYmVsT3B0cy5ib3hXaWR0aDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGZpdCgpIHtcbiAgICBsZXQgbWUgPSB0aGlzO1xuICAgIGxldCBvcHRzID0gbWUub3B0aW9ucztcbiAgICBsZXQgbGFiZWxPcHRzID0gb3B0cy5sYWJlbHM7XG4gICAgbGV0IGRpc3BsYXkgPSBvcHRzLmRpc3BsYXk7XG5cbiAgICBsZXQgY3R4ID0gbWUuY3R4O1xuXG4gICAgbGV0IGxhYmVsRm9udCA9IGhlbHBlcnMub3B0aW9ucy5fcGFyc2VGb250KGxhYmVsT3B0cyk7XG4gICAgbGV0IGZvbnRTaXplID0gbGFiZWxGb250LnNpemU7XG5cbiAgICAvLyBSZXNldCBoaXQgYm94ZXNcbiAgICBsZXQgaGl0Ym94ZXMgPSAobWUubGVnZW5kSGl0Qm94ZXMgPSBbXSk7XG5cbiAgICBsZXQgbWluU2l6ZSA9IG1lLm1pblNpemU7XG4gICAgbGV0IGlzSG9yaXpvbnRhbCA9IG1lLmlzSG9yaXpvbnRhbCgpO1xuXG4gICAgaWYgKGlzSG9yaXpvbnRhbCkge1xuICAgICAgbWluU2l6ZS53aWR0aCA9IG1lLm1heFdpZHRoOyAvLyBmaWxsIGFsbCB0aGUgd2lkdGhcbiAgICAgIG1pblNpemUuaGVpZ2h0ID0gZGlzcGxheSA/IDEwIDogMDtcbiAgICB9IGVsc2Uge1xuICAgICAgbWluU2l6ZS53aWR0aCA9IGRpc3BsYXkgPyAxMCA6IDA7XG4gICAgICBtaW5TaXplLmhlaWdodCA9IG1lLm1heEhlaWdodDsgLy8gZmlsbCBhbGwgdGhlIGhlaWdodFxuICAgIH1cblxuICAgIGxldCBnZXRNYXhMaW5lV2lkdGggPSBmdW5jdGlvbiAodGV4dExpbmVzKSB7XG4gICAgICByZXR1cm4gdGV4dExpbmVzXG4gICAgICAgIC5tYXAoZnVuY3Rpb24gKHRleHRMaW5lKSB7XG4gICAgICAgICAgcmV0dXJuIGN0eC5tZWFzdXJlVGV4dCh0ZXh0TGluZSkud2lkdGg7XG4gICAgICAgIH0pXG4gICAgICAgIC5yZWR1Y2UoZnVuY3Rpb24gKGFjYywgdikge1xuICAgICAgICAgIHJldHVybiB2ID4gYWNjID8gdiA6IGFjYztcbiAgICAgICAgfSwgMCk7XG4gICAgfTtcblxuICAgIC8vIEluY3JlYXNlIHNpemVzIGhlcmVcbiAgICBpZiAoZGlzcGxheSkge1xuICAgICAgY3R4LmZvbnQgPSBsYWJlbEZvbnQuc3RyaW5nO1xuXG4gICAgICBpZiAoaXNIb3Jpem9udGFsKSB7XG4gICAgICAgIC8vIFdpZHRoIG9mIGVhY2ggbGluZSBvZiBsZWdlbmQgYm94ZXMuIExhYmVscyB3cmFwIG9udG8gbXVsdGlwbGUgbGluZXMgd2hlbiB0aGVyZSBhcmUgdG9vIG1hbnkgdG8gZml0IG9uIG9uZVxuICAgICAgICBsZXQgbGluZVdpZHRocyA9IChtZS5saW5lV2lkdGhzID0gWzBdKTtcbiAgICAgICAgbGV0IGxpbmVIZWlnaHRzID0gKG1lLmxpbmVIZWlnaHRzID0gW10pO1xuICAgICAgICBsZXQgY3VycmVudExpbmVIZWlnaHQgPSAwO1xuICAgICAgICBsZXQgbGluZUluZGV4ID0gMDtcblxuICAgICAgICBjdHgudGV4dEFsaWduID0gXCJsZWZ0XCI7XG4gICAgICAgIGN0eC50ZXh0QmFzZWxpbmUgPSBcInRvcFwiO1xuXG4gICAgICAgIGhlbHBlcnMuZWFjaChtZS5sZWdlbmRJdGVtcywgZnVuY3Rpb24gKGxlZ2VuZEl0ZW0sIGkpIHtcbiAgICAgICAgICBsZXQgd2lkdGgsIGhlaWdodDtcblxuICAgICAgICAgIGlmIChoZWxwZXJzLmlzQXJyYXkobGVnZW5kSXRlbS50ZXh0KSkge1xuICAgICAgICAgICAgd2lkdGggPSBnZXRNYXhMaW5lV2lkdGgobGVnZW5kSXRlbS50ZXh0KTtcbiAgICAgICAgICAgIGhlaWdodCA9IGZvbnRTaXplICogbGVnZW5kSXRlbS50ZXh0Lmxlbmd0aCArIGxhYmVsT3B0cy5wYWRkaW5nO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB3aWR0aCA9IGN0eC5tZWFzdXJlVGV4dChsZWdlbmRJdGVtLnRleHQpLndpZHRoO1xuICAgICAgICAgICAgaGVpZ2h0ID0gZm9udFNpemUgKyBsYWJlbE9wdHMucGFkZGluZztcbiAgICAgICAgICB9XG4gICAgICAgICAgd2lkdGggKz0gZ2V0Qm94V2lkdGgobGFiZWxPcHRzLCBmb250U2l6ZSkgKyBmb250U2l6ZSAvIDI7XG5cbiAgICAgICAgICBpZiAoXG4gICAgICAgICAgICBsaW5lV2lkdGhzW2xpbmVXaWR0aHMubGVuZ3RoIC0gMV0gKyB3aWR0aCArIDIgKiBsYWJlbE9wdHMucGFkZGluZyA+XG4gICAgICAgICAgICBtaW5TaXplLndpZHRoXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBsaW5lSGVpZ2h0cy5wdXNoKGN1cnJlbnRMaW5lSGVpZ2h0KTtcbiAgICAgICAgICAgIGN1cnJlbnRMaW5lSGVpZ2h0ID0gMDtcbiAgICAgICAgICAgIGxpbmVXaWR0aHNbbGluZVdpZHRocy5sZW5ndGggLSAoaSA+IDAgPyAwIDogMSldID0gMDtcbiAgICAgICAgICAgIGxpbmVJbmRleCsrO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGxlZ2VuZEl0ZW0ubGluZU9yQ29sdW1uSW5kZXggPSBsaW5lSW5kZXg7XG5cbiAgICAgICAgICBpZiAoaGVpZ2h0ID4gY3VycmVudExpbmVIZWlnaHQpIHtcbiAgICAgICAgICAgIGN1cnJlbnRMaW5lSGVpZ2h0ID0gaGVpZ2h0O1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFN0b3JlIHRoZSBoaXRib3ggd2lkdGggYW5kIGhlaWdodCBoZXJlLiBGaW5hbCBwb3NpdGlvbiB3aWxsIGJlIHVwZGF0ZWQgaW4gYGRyYXdgXG4gICAgICAgICAgaGl0Ym94ZXNbaV0gPSB7XG4gICAgICAgICAgICBsZWZ0OiAwLFxuICAgICAgICAgICAgdG9wOiAwLFxuICAgICAgICAgICAgd2lkdGg6IHdpZHRoLFxuICAgICAgICAgICAgaGVpZ2h0OiBoZWlnaHQsXG4gICAgICAgICAgfTtcblxuICAgICAgICAgIGxpbmVXaWR0aHNbbGluZVdpZHRocy5sZW5ndGggLSAxXSArPSB3aWR0aCArIGxhYmVsT3B0cy5wYWRkaW5nO1xuICAgICAgICB9KTtcblxuICAgICAgICBsaW5lSGVpZ2h0cy5wdXNoKGN1cnJlbnRMaW5lSGVpZ2h0KTtcbiAgICAgICAgbWluU2l6ZS5oZWlnaHQgKz0gbGluZUhlaWdodHMucmVkdWNlKGZ1bmN0aW9uIChhY2MsIHYpIHtcbiAgICAgICAgICByZXR1cm4gYWNjICsgdjtcbiAgICAgICAgfSwgMCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgdlBhZGRpbmcgPSBsYWJlbE9wdHMucGFkZGluZztcbiAgICAgICAgbGV0IGNvbHVtbldpZHRocyA9IChtZS5jb2x1bW5XaWR0aHMgPSBbXSk7XG4gICAgICAgIGxldCBjb2x1bW5IZWlnaHRzID0gKG1lLmNvbHVtbkhlaWdodHMgPSBbXSk7XG4gICAgICAgIGxldCB0b3RhbFdpZHRoID0gbGFiZWxPcHRzLnBhZGRpbmc7XG4gICAgICAgIGxldCBjdXJyZW50Q29sV2lkdGggPSAwO1xuICAgICAgICBsZXQgY3VycmVudENvbEhlaWdodCA9IDA7XG4gICAgICAgIGxldCBjb2x1bW5JbmRleCA9IDA7XG5cbiAgICAgICAgaGVscGVycy5lYWNoKG1lLmxlZ2VuZEl0ZW1zLCBmdW5jdGlvbiAobGVnZW5kSXRlbSwgaSkge1xuICAgICAgICAgIGxldCBpdGVtV2lkdGg7XG4gICAgICAgICAgbGV0IGhlaWdodDtcblxuICAgICAgICAgIGlmIChoZWxwZXJzLmlzQXJyYXkobGVnZW5kSXRlbS50ZXh0KSkge1xuICAgICAgICAgICAgaXRlbVdpZHRoID0gZ2V0TWF4TGluZVdpZHRoKGxlZ2VuZEl0ZW0udGV4dCk7XG4gICAgICAgICAgICBoZWlnaHQgPSBmb250U2l6ZSAqIGxlZ2VuZEl0ZW0udGV4dC5sZW5ndGg7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGl0ZW1XaWR0aCA9IGN0eC5tZWFzdXJlVGV4dChsZWdlbmRJdGVtLnRleHQpLndpZHRoO1xuICAgICAgICAgICAgaGVpZ2h0ID0gZm9udFNpemU7XG4gICAgICAgICAgfVxuICAgICAgICAgIGl0ZW1XaWR0aCArPSBnZXRCb3hXaWR0aChsYWJlbE9wdHMsIGZvbnRTaXplKSArIGZvbnRTaXplIC8gMjtcblxuICAgICAgICAgIC8vIElmIHRvbyB0YWxsLCBnbyB0byBuZXcgY29sdW1uXG4gICAgICAgICAgaWYgKGN1cnJlbnRDb2xIZWlnaHQgKyBmb250U2l6ZSArIDIgKiB2UGFkZGluZyA+IG1pblNpemUuaGVpZ2h0KSB7XG4gICAgICAgICAgICB0b3RhbFdpZHRoICs9IGN1cnJlbnRDb2xXaWR0aCArIGxhYmVsT3B0cy5wYWRkaW5nO1xuICAgICAgICAgICAgY29sdW1uV2lkdGhzLnB1c2goY3VycmVudENvbFdpZHRoKTsgLy8gcHJldmlvdXMgY29sdW1uIHdpZHRoXG4gICAgICAgICAgICBjb2x1bW5IZWlnaHRzLnB1c2goY3VycmVudENvbEhlaWdodCk7XG4gICAgICAgICAgICBjdXJyZW50Q29sV2lkdGggPSAwO1xuICAgICAgICAgICAgY3VycmVudENvbEhlaWdodCA9IDA7XG4gICAgICAgICAgICBjb2x1bW5JbmRleCsrO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGxlZ2VuZEl0ZW0ubGluZU9yQ29sdW1uSW5kZXggPSBjb2x1bW5JbmRleDtcblxuICAgICAgICAgIC8vIEdldCBtYXggd2lkdGhcbiAgICAgICAgICBjdXJyZW50Q29sV2lkdGggPSBNYXRoLm1heChjdXJyZW50Q29sV2lkdGgsIGl0ZW1XaWR0aCk7XG4gICAgICAgICAgY3VycmVudENvbEhlaWdodCArPSBoZWlnaHQgKyB2UGFkZGluZztcblxuICAgICAgICAgIC8vIFN0b3JlIHRoZSBoaXRib3ggd2lkdGggYW5kIGhlaWdodCBoZXJlLiBGaW5hbCBwb3NpdGlvbiB3aWxsIGJlIHVwZGF0ZWQgaW4gYGRyYXdgXG4gICAgICAgICAgaGl0Ym94ZXNbaV0gPSB7XG4gICAgICAgICAgICBsZWZ0OiAwLFxuICAgICAgICAgICAgdG9wOiAwLFxuICAgICAgICAgICAgd2lkdGg6IGl0ZW1XaWR0aCxcbiAgICAgICAgICAgIGhlaWdodDogaGVpZ2h0LFxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRvdGFsV2lkdGggKz0gY3VycmVudENvbFdpZHRoO1xuICAgICAgICBjb2x1bW5XaWR0aHMucHVzaChjdXJyZW50Q29sV2lkdGgpO1xuICAgICAgICBjb2x1bW5IZWlnaHRzLnB1c2goY3VycmVudENvbEhlaWdodCk7XG4gICAgICAgIG1pblNpemUud2lkdGggKz0gdG90YWxXaWR0aDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBtZS53aWR0aCA9IG1pblNpemUud2lkdGg7XG4gICAgbWUuaGVpZ2h0ID0gbWluU2l6ZS5oZWlnaHQ7XG4gIH1cblxuICBmdW5jdGlvbiBkcmF3KCkge1xuICAgIGxldCBtZSA9IHRoaXM7XG4gICAgbGV0IG9wdHMgPSBtZS5vcHRpb25zO1xuICAgIGxldCBsYWJlbE9wdHMgPSBvcHRzLmxhYmVscztcbiAgICBsZXQgZ2xvYmFsRGVmYXVsdHMgPSBkZWZhdWx0cy5nbG9iYWw7XG4gICAgbGV0IGRlZmF1bHRDb2xvciA9IGdsb2JhbERlZmF1bHRzLmRlZmF1bHRDb2xvcjtcbiAgICBsZXQgbGluZURlZmF1bHQgPSBnbG9iYWxEZWZhdWx0cy5lbGVtZW50cy5saW5lO1xuICAgIGxldCBsZWdlbmRIZWlnaHQgPSBtZS5oZWlnaHQ7XG4gICAgbGV0IGNvbHVtbkhlaWdodHMgPSBtZS5jb2x1bW5IZWlnaHRzO1xuICAgIGxldCBjb2x1bW5XaWR0aHMgPSBtZS5jb2x1bW5XaWR0aHM7XG4gICAgbGV0IGxlZ2VuZFdpZHRoID0gbWUud2lkdGg7XG4gICAgbGV0IGxpbmVXaWR0aHMgPSBtZS5saW5lV2lkdGhzO1xuICAgIGxldCBsaW5lSGVpZ2h0cyA9IG1lLmxpbmVIZWlnaHRzO1xuXG4gICAgaWYgKG9wdHMuZGlzcGxheSkge1xuICAgICAgbGV0IGN0eCA9IG1lLmN0eDtcbiAgICAgIGxldCBmb250Q29sb3IgPSB2YWx1ZU9yRGVmYXVsdChcbiAgICAgICAgbGFiZWxPcHRzLmZvbnRDb2xvcixcbiAgICAgICAgZ2xvYmFsRGVmYXVsdHMuZGVmYXVsdEZvbnRDb2xvclxuICAgICAgKTtcbiAgICAgIGxldCBsYWJlbEZvbnQgPSBoZWxwZXJzLm9wdGlvbnMuX3BhcnNlRm9udChsYWJlbE9wdHMpO1xuICAgICAgbGV0IGZvbnRTaXplID0gbGFiZWxGb250LnNpemU7XG4gICAgICBsZXQgY3Vyc29yO1xuXG4gICAgICAvLyBDYW52YXMgc2V0dXBcbiAgICAgIGN0eC50ZXh0QWxpZ24gPSBcImxlZnRcIjtcbiAgICAgIGN0eC50ZXh0QmFzZWxpbmUgPSBcIm1pZGRsZVwiO1xuICAgICAgY3R4LmxpbmVXaWR0aCA9IDAuNTtcbiAgICAgIGN0eC5zdHJva2VTdHlsZSA9IGZvbnRDb2xvcjsgLy8gZm9yIHN0cmlrZXRocm91Z2ggZWZmZWN0XG4gICAgICBjdHguZmlsbFN0eWxlID0gZm9udENvbG9yOyAvLyByZW5kZXIgaW4gY29ycmVjdCBjb2xvdXJcbiAgICAgIGN0eC5mb250ID0gbGFiZWxGb250LnN0cmluZztcblxuICAgICAgbGV0IGJveFdpZHRoID0gZ2V0Qm94V2lkdGgobGFiZWxPcHRzLCBmb250U2l6ZSk7XG4gICAgICBsZXQgaGl0Ym94ZXMgPSBtZS5sZWdlbmRIaXRCb3hlcztcblxuICAgICAgLy8gY3VycmVudCBwb3NpdGlvblxuICAgICAgbGV0IGRyYXdMZWdlbmRCb3ggPSBmdW5jdGlvbiAoeCwgeSwgbGVnZW5kSXRlbSkge1xuICAgICAgICBpZiAoaXNOYU4oYm94V2lkdGgpIHx8IGJveFdpZHRoIDw9IDApIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTZXQgdGhlIGN0eCBmb3IgdGhlIGJveFxuICAgICAgICBjdHguc2F2ZSgpO1xuXG4gICAgICAgIGxldCBsaW5lV2lkdGggPSB2YWx1ZU9yRGVmYXVsdChcbiAgICAgICAgICBsZWdlbmRJdGVtLmxpbmVXaWR0aCxcbiAgICAgICAgICBsaW5lRGVmYXVsdC5ib3JkZXJXaWR0aFxuICAgICAgICApO1xuICAgICAgICBjdHguZmlsbFN0eWxlID0gdmFsdWVPckRlZmF1bHQobGVnZW5kSXRlbS5maWxsU3R5bGUsIGRlZmF1bHRDb2xvcik7XG4gICAgICAgIGN0eC5saW5lQ2FwID0gdmFsdWVPckRlZmF1bHQoXG4gICAgICAgICAgbGVnZW5kSXRlbS5saW5lQ2FwLFxuICAgICAgICAgIGxpbmVEZWZhdWx0LmJvcmRlckNhcFN0eWxlXG4gICAgICAgICk7XG4gICAgICAgIGN0eC5saW5lRGFzaE9mZnNldCA9IHZhbHVlT3JEZWZhdWx0KFxuICAgICAgICAgIGxlZ2VuZEl0ZW0ubGluZURhc2hPZmZzZXQsXG4gICAgICAgICAgbGluZURlZmF1bHQuYm9yZGVyRGFzaE9mZnNldFxuICAgICAgICApO1xuICAgICAgICBjdHgubGluZUpvaW4gPSB2YWx1ZU9yRGVmYXVsdChcbiAgICAgICAgICBsZWdlbmRJdGVtLmxpbmVKb2luLFxuICAgICAgICAgIGxpbmVEZWZhdWx0LmJvcmRlckpvaW5TdHlsZVxuICAgICAgICApO1xuICAgICAgICBjdHgubGluZVdpZHRoID0gbGluZVdpZHRoO1xuICAgICAgICBjdHguc3Ryb2tlU3R5bGUgPSB2YWx1ZU9yRGVmYXVsdChsZWdlbmRJdGVtLnN0cm9rZVN0eWxlLCBkZWZhdWx0Q29sb3IpO1xuXG4gICAgICAgIGlmIChjdHguc2V0TGluZURhc2gpIHtcbiAgICAgICAgICAvLyBJRSA5IGFuZCAxMCBkbyBub3Qgc3VwcG9ydCBsaW5lIGRhc2hcbiAgICAgICAgICBjdHguc2V0TGluZURhc2goXG4gICAgICAgICAgICB2YWx1ZU9yRGVmYXVsdChsZWdlbmRJdGVtLmxpbmVEYXNoLCBsaW5lRGVmYXVsdC5ib3JkZXJEYXNoKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAob3B0cy5sYWJlbHMgJiYgb3B0cy5sYWJlbHMudXNlUG9pbnRTdHlsZSkge1xuICAgICAgICAgIC8vIFJlY2FsY3VsYXRlIHggYW5kIHkgZm9yIGRyYXdQb2ludCgpIGJlY2F1c2UgaXRzIGV4cGVjdGluZ1xuICAgICAgICAgIC8vIHggYW5kIHkgdG8gYmUgY2VudGVyIG9mIGZpZ3VyZSAoaW5zdGVhZCBvZiB0b3AgbGVmdClcbiAgICAgICAgICBsZXQgcmFkaXVzID0gKGJveFdpZHRoICogTWF0aC5TUVJUMikgLyAyO1xuICAgICAgICAgIGxldCBjZW50ZXJYID0geCArIGJveFdpZHRoIC8gMjtcbiAgICAgICAgICBsZXQgY2VudGVyWSA9IHkgKyBmb250U2l6ZSAvIDI7XG5cbiAgICAgICAgICAvLyBEcmF3IHBvaW50U3R5bGUgYXMgbGVnZW5kIHN5bWJvbFxuICAgICAgICAgIGhlbHBlcnMuY2FudmFzLmRyYXdQb2ludChcbiAgICAgICAgICAgIGN0eCxcbiAgICAgICAgICAgIGxlZ2VuZEl0ZW0ucG9pbnRTdHlsZSxcbiAgICAgICAgICAgIHJhZGl1cyxcbiAgICAgICAgICAgIGNlbnRlclgsXG4gICAgICAgICAgICBjZW50ZXJZXG4gICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyBEcmF3IGJveCBhcyBsZWdlbmQgc3ltYm9sXG4gICAgICAgICAgaWYgKGxpbmVXaWR0aCAhPT0gMCkge1xuICAgICAgICAgICAgY3R4LnN0cm9rZVJlY3QoeCwgeSwgYm94V2lkdGgsIGZvbnRTaXplKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgY3R4LmZpbGxSZWN0KHgsIHksIGJveFdpZHRoLCBmb250U2l6ZSk7XG4gICAgICAgIH1cblxuICAgICAgICBjdHgucmVzdG9yZSgpO1xuICAgICAgfTtcblxuICAgICAgbGV0IGRyYXdTdHJpa2VUaHJvdWdoID0gZnVuY3Rpb24gKHgsIHksIHcpIHtcbiAgICAgICAgY3R4LmJlZ2luUGF0aCgpO1xuICAgICAgICBjdHgubGluZVdpZHRoID0gMjtcbiAgICAgICAgY3R4Lm1vdmVUbyh4LCB5KTtcbiAgICAgICAgY3R4LmxpbmVUbyh4ICsgdywgeSk7XG4gICAgICAgIGN0eC5zdHJva2UoKTtcbiAgICAgIH07XG5cbiAgICAgIGxldCBkcmF3Q3Jvc3NPdmVyID0gZnVuY3Rpb24gKHgsIHksIHcsIGgpIHtcbiAgICAgICAgY3R4LmJlZ2luUGF0aCgpO1xuICAgICAgICBjdHgubGluZVdpZHRoID0gMjtcbiAgICAgICAgY3R4Lm1vdmVUbyh4LCB5KTtcbiAgICAgICAgY3R4LmxpbmVUbyh4ICsgdywgeSArIGgpO1xuICAgICAgICBjdHgubW92ZVRvKHgsIHkgKyBoKTtcbiAgICAgICAgY3R4LmxpbmVUbyh4ICsgdywgeSk7XG4gICAgICAgIGN0eC5zdHJva2UoKTtcbiAgICAgIH07XG5cbiAgICAgIGxldCBmaWxsVGV4dCA9IGZ1bmN0aW9uICh4LCB5LCBsZWdlbmRJdGVtLCB0ZXh0V2lkdGgpIHtcbiAgICAgICAgbGV0IGhhbGZGb250U2l6ZSA9IGZvbnRTaXplIC8gMjtcbiAgICAgICAgbGV0IHhMZWZ0ID0gYm94V2lkdGggKyBoYWxmRm9udFNpemUgKyB4O1xuICAgICAgICBsZXQgeU1pZGRsZSA9IHkgKyBoYWxmRm9udFNpemU7XG5cbiAgICAgICAgaWYgKGhlbHBlcnMuaXNBcnJheShsZWdlbmRJdGVtLnRleHQpKSB7XG4gICAgICAgICAgaGVscGVycy5lYWNoKGxlZ2VuZEl0ZW0udGV4dCwgZnVuY3Rpb24gKHRleHRMaW5lLCBpbmRleCkge1xuICAgICAgICAgICAgbGV0IGxpbmVPZmZzZXQgPSBpbmRleCAqIGZvbnRTaXplO1xuICAgICAgICAgICAgY3R4LmZpbGxUZXh0KHRleHRMaW5lLCB4TGVmdCwgeU1pZGRsZSArIGxpbmVPZmZzZXQpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGN0eC5maWxsVGV4dChsZWdlbmRJdGVtLnRleHQsIHhMZWZ0LCB5TWlkZGxlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChsZWdlbmRJdGVtLmhpZGRlbikge1xuICAgICAgICAgIGlmIChoZWxwZXJzLmlzQXJyYXkobGVnZW5kSXRlbS50ZXh0KSkge1xuICAgICAgICAgICAgZHJhd0Nyb3NzT3ZlcihcbiAgICAgICAgICAgICAgeExlZnQsXG4gICAgICAgICAgICAgIHlNaWRkbGUsXG4gICAgICAgICAgICAgIHRleHRXaWR0aCxcbiAgICAgICAgICAgICAgKGxlZ2VuZEl0ZW0udGV4dC5sZW5ndGggLSAxKSAqIChmb250U2l6ZSAtIDEpXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkcmF3U3RyaWtlVGhyb3VnaCh4TGVmdCwgeU1pZGRsZSwgdGV4dFdpZHRoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIGxldCBhbGlnbm1lbnRPZmZzZXQgPSBmdW5jdGlvbiAoZGltZW5zaW9uLCBibG9ja1NpemUpIHtcbiAgICAgICAgc3dpdGNoIChvcHRzLmFsaWduKSB7XG4gICAgICAgICAgY2FzZSBcInN0YXJ0XCI6XG4gICAgICAgICAgICByZXR1cm4gbGFiZWxPcHRzLnBhZGRpbmc7XG4gICAgICAgICAgY2FzZSBcImVuZFwiOlxuICAgICAgICAgICAgcmV0dXJuIGRpbWVuc2lvbiAtIGJsb2NrU2l6ZTtcbiAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgLy8gY2VudGVyXG4gICAgICAgICAgICByZXR1cm4gKGRpbWVuc2lvbiAtIGJsb2NrU2l6ZSArIGxhYmVsT3B0cy5wYWRkaW5nKSAvIDI7XG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIC8vIEhvcml6b250YWxcbiAgICAgIGxldCBpc0hvcml6b250YWwgPSBtZS5pc0hvcml6b250YWwoKTtcbiAgICAgIGlmIChpc0hvcml6b250YWwpIHtcbiAgICAgICAgY3Vyc29yID0ge1xuICAgICAgICAgIHg6IG1lLmxlZnQgKyBhbGlnbm1lbnRPZmZzZXQobGVnZW5kV2lkdGgsIGxpbmVXaWR0aHNbMF0pLFxuICAgICAgICAgIHk6IG1lLnRvcCArIGxhYmVsT3B0cy5wYWRkaW5nLFxuICAgICAgICAgIGxpbmU6IDAsXG4gICAgICAgIH07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjdXJzb3IgPSB7XG4gICAgICAgICAgeDogbWUubGVmdCArIGxhYmVsT3B0cy5wYWRkaW5nLFxuICAgICAgICAgIHk6IG1lLnRvcCArIGFsaWdubWVudE9mZnNldChsZWdlbmRIZWlnaHQsIGNvbHVtbkhlaWdodHNbMF0pLFxuICAgICAgICAgIGxpbmU6IDAsXG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGhlbHBlcnMuZWFjaChtZS5sZWdlbmRJdGVtcywgZnVuY3Rpb24gKGxlZ2VuZEl0ZW0sIGkpIHtcbiAgICAgICAgbGV0IHRleHRXaWR0aCwgaGVpZ2h0LCBib3hUb3BPZmZzZXQ7XG5cbiAgICAgICAgaWYgKGxlZ2VuZEl0ZW0ubGluZU9yQ29sdW1uSW5kZXggPiBjdXJzb3IubGluZSkge1xuICAgICAgICAgIGlmIChpc0hvcml6b250YWwpIHtcbiAgICAgICAgICAgIGN1cnNvci55ICs9IGxpbmVIZWlnaHRzW2N1cnNvci5saW5lXTtcbiAgICAgICAgICAgIGN1cnNvci5saW5lID0gbGVnZW5kSXRlbS5saW5lT3JDb2x1bW5JbmRleDtcbiAgICAgICAgICAgIGN1cnNvci54ID1cbiAgICAgICAgICAgICAgbWUubGVmdCArIGFsaWdubWVudE9mZnNldChsZWdlbmRXaWR0aCwgbGluZVdpZHRoc1tjdXJzb3IubGluZV0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjdXJzb3IueCArPSBjb2x1bW5XaWR0aHNbY3Vyc29yLmxpbmVdICsgbGFiZWxPcHRzLnBhZGRpbmc7XG4gICAgICAgICAgICBjdXJzb3IubGluZSA9IGxlZ2VuZEl0ZW0ubGluZU9yQ29sdW1uSW5kZXg7XG4gICAgICAgICAgICBjdXJzb3IueSA9XG4gICAgICAgICAgICAgIG1lLnRvcCArXG4gICAgICAgICAgICAgIGFsaWdubWVudE9mZnNldChsZWdlbmRIZWlnaHQsIGNvbHVtbkhlaWdodHNbY3Vyc29yLmxpbmVdKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaGVscGVycy5pc0FycmF5KGxlZ2VuZEl0ZW0udGV4dCkpIHtcbiAgICAgICAgICB0ZXh0V2lkdGggPSBsZWdlbmRJdGVtLnRleHRcbiAgICAgICAgICAgIC5tYXAoZnVuY3Rpb24gKHRleHRMaW5lKSB7XG4gICAgICAgICAgICAgIHJldHVybiBjdHgubWVhc3VyZVRleHQodGV4dExpbmUpLndpZHRoO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5yZWR1Y2UoZnVuY3Rpb24gKGFjYywgdikge1xuICAgICAgICAgICAgICByZXR1cm4gdiA+IGFjYyA/IHYgOiBhY2M7XG4gICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICBib3hUb3BPZmZzZXQgPSAoZm9udFNpemUgLyAyKSAqIChsZWdlbmRJdGVtLnRleHQubGVuZ3RoIC0gMSk7XG4gICAgICAgICAgaGVpZ2h0ID0gZm9udFNpemUgKiBsZWdlbmRJdGVtLnRleHQubGVuZ3RoO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRleHRXaWR0aCA9IGN0eC5tZWFzdXJlVGV4dChsZWdlbmRJdGVtLnRleHQpLndpZHRoO1xuICAgICAgICAgIGJveFRvcE9mZnNldCA9IDA7XG4gICAgICAgICAgaGVpZ2h0ID0gZm9udFNpemU7XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgd2lkdGggPSBib3hXaWR0aCArIGZvbnRTaXplIC8gMiArIHRleHRXaWR0aDtcbiAgICAgICAgbGV0IHggPSBjdXJzb3IueDtcbiAgICAgICAgbGV0IHkgPSBjdXJzb3IueTtcblxuICAgICAgICBsZXQgdG9wT2Zmc2V0ID0gaXNIb3Jpem9udGFsXG4gICAgICAgICAgPyBNYXRoLnRydW5jKChsaW5lSGVpZ2h0c1tjdXJzb3IubGluZV0gLSBoaXRib3hlc1tpXS5oZWlnaHQpIC8gMilcbiAgICAgICAgICA6IDA7XG5cbiAgICAgICAgZHJhd0xlZ2VuZEJveCh4LCB5ICsgYm94VG9wT2Zmc2V0ICsgdG9wT2Zmc2V0LCBsZWdlbmRJdGVtKTtcblxuICAgICAgICBoaXRib3hlc1tpXS5sZWZ0ID0geDtcbiAgICAgICAgaGl0Ym94ZXNbaV0udG9wID0geTtcblxuICAgICAgICAvLyBGaWxsIHRoZSBhY3R1YWwgbGFiZWxcbiAgICAgICAgZmlsbFRleHQoeCwgeSArIHRvcE9mZnNldCwgbGVnZW5kSXRlbSwgdGV4dFdpZHRoKTtcblxuICAgICAgICBpZiAoaXNIb3Jpem9udGFsKSB7XG4gICAgICAgICAgY3Vyc29yLnggKz0gd2lkdGggKyBsYWJlbE9wdHMucGFkZGluZztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjdXJzb3IueSArPSBoZWlnaHQgKyBsYWJlbE9wdHMucGFkZGluZztcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG59XG4iXX0=