angular-sunburst-radar-chart
Version:
A Sunburst Radar chart with SVG,No Dependencies
408 lines • 65.7 kB
JavaScript
import { __decorate } from "tslib";
import { Component, Input } from '@angular/core';
import { createCircle, createLine, createPath } from './utils/elements';
import { createArcToWriteText, getTextForAngle, writeTextOnArc } from './utils/textelement';
import { createInnerChartBarWithInArc, createOuterChartBarWithInArc } from './utils/arc-bar-charts';
import { calculatePointBetween, getGlobalPositions } from './utils/positions';
import { distanceBetweenTwoPoints, polarToCartesian } from './utils/trignometry';
import { createLegends, createLegendWithOptions } from './utils/legend';
import { formatItems, generateRandomColor, getFormattedAngle, getOptionsOrEmpty, hashCode } from './utils/utils';
import { getAllAnglesBasedOnChild, getAllAnglesBasedOnParent, getPointsOnCircleAtAngels, positionsOnAngles } from './utils/angels';
import { createSvgHandlerWithSelector } from './utils/svg-rotator';
let AngularSunburstRadarChartComponent = class AngularSunburstRadarChartComponent {
constructor() {
this.componentDisplayed = false;
this.showToolTip = false;
this.tooltipTopInPx = '0px';
this.tooltipLeftInPx = '0px';
this.tooltipText = '';
this.svgId = null;
this.svgGroupId = null;
this.svgHandler = null;
this.currentRotationAngle = 10;
this.svgCursor = 'default';
this.initialized = false;
this.innerBorderHeight = 30;
this.outerBorderHeight = 30;
this.elements = [];
this.hasChildren = false;
this.outerBorderCircleRef = 'outerBorderCircle';
this.error = null;
this.hasError = false;
this.startRotation = false;
}
showError(msg) {
this.error = msg;
this.hasError = true;
}
hideError() {
this.error = null;
this.hasError = false;
}
appendToSvg(element) {
this.elements.push(element);
}
ngOnChanges(changes) {
this.hideError();
const isFirstChange = Object.values(changes).some(c => c.isFirstChange());
this.modifyOnFirstChange(isFirstChange);
}
modifyOnFirstChange(isFirstChange) {
if (!isFirstChange) {
this.initialize();
}
}
ngOnInit() {
this.hideError();
this.initialize();
}
initialize() {
const defaults = { size: 300, maxScore: 100, animateChart: true, splitBasedOnChildren: true, legendAxisLinePosition: 1 };
const options = Object.assign(Object.assign({}, defaults), (getOptionsOrEmpty(this.options)));
this.size = options.size;
this.maxScore = options.maxScore;
this.animateChart = options.animateChart;
this.splitBasedOnChildren = options.splitBasedOnChildren;
this.legendAxisLinePosition = options.legendAxisLinePosition;
if (!this.hasValidParameters()) {
this.showError('Input Values not set or Items was improper');
return;
}
this.initialized = false;
this.svgId = 'svg' + hashCode(this.items);
this.svgGroupId = 'svg-group' + hashCode(this.items);
this.viewBox = '0 0 ' + this.size + ' ' + this.size;
this.innerCircleRadius = Math.abs(this.size / 5.33);
this.innerBorderHeight = this.innerCircleRadius / 5;
this.outerBorderHeight = this.innerCircleRadius / 5;
this.globalPosition = getGlobalPositions({
size: this.size,
maxScore: this.maxScore,
items: this.items
});
this.hasChildren = this.items.filter(item => !!item.children).length > 0;
this.drawLayout();
const { innerRadius, innerTextRadius, textSize, outerTextSize, outerRadiusBorder, outerTextRadius, center } = this.globalPosition;
const [centerX, centerY] = [center.x, center.y];
let items = this.items;
let allAngels = [];
const hasChildren = this.hasChildren;
if (this.splitBasedOnChildren) {
// Cannot have no children
items = formatItems(items);
allAngels = getAllAnglesBasedOnChild(items);
}
else {
allAngels = getAllAnglesBasedOnParent(items);
}
const angleDifference = 360 / items.length;
const angles = allAngels.map(value => value.startDegree);
const middleAngles = allAngels.map(value => value.middleDegree);
const points = positionsOnAngles(centerX, centerY, this.chartBorder, angles);
const lines = [];
let elements = [];
let nextLevelElements = [];
for (let i = 0; i < points.length; i++) {
const { x, y } = points[i];
let endAngleIndex = i + 1;
if (endAngleIndex >= points.length) {
endAngleIndex = 0;
}
const endAngle = angles[endAngleIndex];
const startAngle = angles[i];
const middleAngle = middleAngles[i];
let item = items[i];
if (!!item.color === false) {
const colorDefaults = {
color: generateRandomColor()
};
item = Object.assign(Object.assign({}, colorDefaults), item);
}
if (this.hasChildren && item.children && item.children.length > 0) {
const childAngels = allAngels[i].children;
nextLevelElements = nextLevelElements.concat(this.drawOnLevel({
items: item.children,
totalDegrees: angleDifference,
childAngels,
color: item.color
}));
}
lines.push(createLine({ x1: centerX, y1: centerY, x2: x, y2: y, width: 2 }));
// Create Arc for inner values
const barWithinArc = createInnerChartBarWithInArc({
startPoint: center,
item,
radius: innerRadius,
startAngle,
endAngle,
maxScore: this.maxScore
});
elements.push(barWithinArc);
const innerTextElements = this.addArcText({
arcForTextId: 'arc-text-inner' + this.getUniqueCode() + '-' + i,
radius: innerTextRadius,
fontSize: textSize,
startAngle,
endAngle,
perAngle: angleDifference,
item
});
elements = elements.concat(innerTextElements);
if (hasChildren) {
elements.push(this.drawOuterBackgroundWithMiddle({ item, startAngle, middleAngle, endAngle }));
const outerBackgroundTextElements = this.addArcText({
arcForTextId: 'arc-text-outer' + this.getUniqueCode() + '-' + i,
radius: outerTextRadius,
fontSize: outerTextSize,
perAngle: angleDifference,
startAngle,
endAngle,
item
});
elements = elements.concat(outerBackgroundTextElements);
}
}
nextLevelElements.forEach(line => {
this.appendToSvg(line);
});
this.drawInnerBorders();
elements.forEach(line => {
this.appendToSvg(line);
});
lines.forEach(line => {
this.appendToSvg(line);
});
const legendAxisIndex = this.getLegendAxisIndex(angles);
this.drawLegends(angles[legendAxisIndex]);
this.addSmallCirclesAtCenter(centerX, centerY);
this.initialized = true;
this.currentRotationAngle = 10;
this.rotationPoint = getFormattedAngle(this.currentRotationAngle, center);
}
getLegendAxisIndex(angles) {
let legendAxisIndex = this.legendAxisLinePosition - 1;
if (legendAxisIndex < 0 || legendAxisIndex >= angles.length) {
legendAxisIndex = 0;
}
return legendAxisIndex;
}
hasValidParameters() {
return this.items && this.items.length > 1;
}
drawOuterBackgroundWithMiddle({ item, startAngle, middleAngle, endAngle }) {
const color = item.color;
const { outerTextRadius, center } = this.globalPosition;
const [centerX, centerY] = [center.x, center.y];
const middleCircle = calculatePointBetween({ centerX, centerY, startAngle, middleAngle, endAngle, radius: outerTextRadius });
const d = [
'M', middleCircle.start.x, middleCircle.start.y,
'A', outerTextRadius, outerTextRadius, 0, 0, 1, middleCircle.end.x, middleCircle.end.y
];
const title = item.name + '-' + item.value;
const strokeWidth = 0.0775 * this.size;
return createPath({ d: d.join(' '), stroke: color, 'stroke-width': strokeWidth, title });
}
drawOnLevel({ items, totalDegrees, childAngels, color }) {
const { innerRadiusBorder, middleRadius, textSize, middleTextRadius, center } = this.globalPosition;
const [centerX, centerY] = [center.x, center.y];
const angles = childAngels.map(item => item.startDegree);
const middleAngles = childAngels.map(item => item.middleDegree);
const endAngles = childAngels.map(item => item.endDegree);
const perAngle = totalDegrees / items.length;
const pointsOnInnerRadiusBorder = getPointsOnCircleAtAngels(centerX, centerY, innerRadiusBorder, angles);
const pointsOnMiddle = getPointsOnCircleAtAngels(centerX, centerY, middleRadius, angles);
let elements = [];
const lines = [];
let currentDegree = angles[0];
for (let i = 0; i < pointsOnInnerRadiusBorder.length; i++) {
const pointOnInnerRadiusBorder = pointsOnInnerRadiusBorder[i];
const pointOnMiddle = pointsOnMiddle[i];
lines.push(createLine({
x1: pointOnInnerRadiusBorder.x, y1: pointOnInnerRadiusBorder.y,
x2: pointOnMiddle.x, y2: pointOnMiddle.y, width: 0.5
}));
const startAngle = angles[i];
const middleAngle = middleAngles[i];
const endAngle = endAngles[i];
const item = items[i];
const params = {
startPoint: pointOnInnerRadiusBorder,
item,
startAngle,
endAngle,
middleAngle,
middleRadius,
innerRadiusBorder,
center,
maxScore: this.maxScore,
color,
index: i
};
const arcForChart = createOuterChartBarWithInArc(params);
elements.push(arcForChart);
const middleTextElements = this.addArcText({
arcForTextId: 'arc-text-middle' + this.getUniqueCode() + '-' + startAngle + i,
radius: middleTextRadius,
fontSize: textSize,
perAngle,
startAngle,
endAngle,
item
});
elements = elements.concat(middleTextElements);
currentDegree = currentDegree + perAngle;
}
lines.forEach(line => {
elements.push(line);
});
return elements;
}
getUniqueCode() {
return hashCode(this.items) + '-' + this.size;
}
drawInnerBorders() {
const { innerRadius, innerRadiusBorder, center } = this.globalPosition;
const [centerX, centerY] = [center.x, center.y];
const innerContainer = createCircle({
x: centerX,
y: centerY,
radius: innerRadius,
fillColor: 'none'
});
const innerBorderContainer = createCircle({
x: centerX,
y: centerY,
radius: innerRadiusBorder,
fillColor: '#FFFFFF'
});
this.appendToSvg(innerBorderContainer);
this.appendToSvg(innerContainer);
}
addSmallCirclesAtCenter(centerX, centerY) {
const outerRadius = 0.0025 * 2 * this.size;
const innerRadius = 0.0005 * 2 * this.size;
this.appendToSvg(createCircle({
x: centerX,
y: centerY,
radius: outerRadius,
fillColor: '#FFFFFF'
}));
this.appendToSvg(createCircle({
x: centerX,
y: centerY,
radius: innerRadius,
fillColor: '#FFFFFF'
}));
}
drawLegends(degreeToBeDrawn) {
const { innerRadius, innerRadiusBorder, middleRadius, center } = this.globalPosition;
const [centerX, centerY] = [center.x, center.y];
const maxScore = this.maxScore;
let legends = createLegends({ startPoint: center, radius: innerRadius, degreeToBeDrawn, maxScore });
const startFrom = polarToCartesian(centerX, centerY, innerRadiusBorder, degreeToBeDrawn);
if (this.hasChildren) {
const nextLevelLegends = createLegendWithOptions({
startPoint: startFrom,
center,
startRadius: innerRadiusBorder,
endRadius: middleRadius,
maxScore,
degreeToBeDrawn
});
legends = legends.concat(nextLevelLegends);
}
legends.forEach(elem => {
this.appendToSvg(elem);
});
}
addArcText({ arcForTextId, radius, startAngle, fontSize, endAngle, perAngle, item }) {
const elements = [];
const { center } = this.globalPosition;
const [centerX, centerY] = [center.x, center.y];
const arcForText = createArcToWriteText({ id: arcForTextId, startPoint: center, radius, startAngle, endAngle });
elements.push(arcForText);
const distance = distanceBetweenTwoPoints(centerX, centerY, radius, startAngle, endAngle);
const label = getTextForAngle(item.name, distance, fontSize);
elements.push(writeTextOnArc({ label, text: item.name, pathId: arcForTextId, 'font-size': fontSize + 'px' }));
return elements;
}
drawLayout() {
const { innerRadius, innerRadiusBorder, middleRadius, middleRadiusBorder, outerRadius, outerRadiusBorder, center } = this.globalPosition;
const [centerX, centerY] = [center.x, center.y];
let innerRadiusEnd = innerRadius;
let innerRadiusBorderEnd = innerRadiusBorder;
this.chartBorder = innerRadiusBorder;
if (this.hasChildren) {
const outerBorderCircle = createCircle({
x: centerX,
y: centerY,
radius: outerRadiusBorder,
fillColor: 'none',
'stroke-width': '5',
ref: this.outerBorderCircleRef
});
this.appendToSvg(outerBorderCircle);
const outerCircle = createCircle({
x: centerX,
y: centerY,
radius: outerRadius,
fillColor: 'none'
});
this.appendToSvg(outerCircle);
innerRadiusEnd = middleRadius;
innerRadiusBorderEnd = middleRadiusBorder;
this.chartBorder = outerRadiusBorder;
}
this.appendToSvg(createCircle({ x: centerX, y: centerY, radius: innerRadiusEnd }));
this.appendToSvg(createCircle({ x: centerX, y: centerY, radius: innerRadiusBorderEnd }));
}
hideTooltip() {
this.showToolTip = false;
}
showTooltipText($event, text) {
this.tooltipLeftInPx = $event.pageX + 10 + 'px';
this.tooltipTopInPx = $event.pageY + 10 + 'px';
this.tooltipText = text;
this.showToolTip = true;
}
onOutOfComponent() {
this.hideTooltip();
this.stopRotate();
}
stopRotate() {
this.svgCursor = 'default';
this.startRotation = false;
}
startRotate($event) {
this.startRotation = true;
this.svgCursor = 'grab';
const { outerRadiusBorder, center } = this.globalPosition;
this.svgHandler = createSvgHandlerWithSelector('#' + this.svgId, center);
this.svgHandler.startDrag($event, this.currentRotationAngle);
$event.preventDefault();
}
rotateChart($event) {
if (this.startRotation == false) {
return;
}
this.svgCursor = 'grabbing';
const { center } = this.globalPosition;
this.currentRotationAngle = this.svgHandler.getRotationAngle($event);
this.rotationPoint = getFormattedAngle(Math.round(this.currentRotationAngle), center);
}
};
__decorate([
Input()
], AngularSunburstRadarChartComponent.prototype, "items", void 0);
__decorate([
Input()
], AngularSunburstRadarChartComponent.prototype, "options", void 0);
AngularSunburstRadarChartComponent = __decorate([
Component({
selector: 'lib-sunburst-radar-chart',
template: "<ng-container (mouseout)=\"onOutOfComponent();\">\n\n\n <div *ngIf=\"hasError\" style=\" color: #a94442;\n background-color: #f2dede;\n border-color: #ebccd1;\n margin-top: 5px;\npadding: 15px;\n margin-bottom: 20px;\n border: 1px solid transparent;\n border-radius: 4px;\n\">\n <strong>Error!</strong> {{error}}\n </div>\n\n\n\n<div class=\"app-tooltip\" *ngIf=\"showToolTip\" style=\"position: absolute; display: block;background: cornsilk; border: 1px solid black; border-radius: 5px; padding: 5px; z-index: 1002;\"\n\n [style.left]=\"tooltipLeftInPx\" [style.top]=\"tooltipTopInPx\" >\n {{tooltipText}}\n</div>\n\n<svg [attr.id]=\"svgId\"\n [attr.height]=\"size\"\n [attr.width]=\"size\"\n [attr.viewBox]=\"viewBox\"\n [style.cursor]=\"svgCursor\"\n xmlns=\"http://www.w3.org/2000/svg\">\n\n\n\n\n <animateTransform\n *ngIf=\"animateChart\"\n attributeName=\"transform\"\n begin=\"4s\"\n dur=\"500ms\"\n type=\"rotate\"\n from=\"0\"\n to=\"10\"\n\n additive=\"sum\"\n fill=\"freeze\"\n repeatCount=\"1\"\n />\n\n\n<g\n (mousemove)=\"rotateChart($event);\"\n (mousedown)=\"startRotate($event)\"\n (mouseup)=\"stopRotate()\"\n (touchmove)=\"rotateChart($event);\"\n (touchstart)=\"startRotate($event)\"\n (touchend)=\"stopRotate()\"\n [attr.transform]=\"rotationPoint\"\n [attr.id]=\"svgGroupId\"\n\n\n >\n <ng-container *ngFor=\"let element of elements\" >\n\n\n\n <ng-container [ngSwitch]=\"element.name\" >\n\n\n <circle *ngSwitchCase=\"'circle'\" [attr.cx]=\"element.options.x\" [attr.cy]=[element.options.y]\n [attr.r]=\"element.options.radius\"\n [attr.stroke-width]=\"element.options['stroke-width']\"\n [attr.stroke]=\"element.options['stroke']\"\n [attr.stroke-dasharray]=\"element.options['stroke-dasharray']\"\n [attr.stroke-opacity]=\"element.options['stroke-opacity']\"\n [attr.fill]=\"element.options['fillColor']\"\n >\n\n\n\n\n </circle>\n\n <path *ngSwitchCase=\"'path'\" [attr.d]=\"element.options.d\" [attr.fill]=[element.options.fill]\n\n [attr.stroke]=\"element.options['stroke']\"\n [attr.stroke-width]=\"element.options['stroke-width']\"\n [attr.id]=\"element.options['id']\"\n (mousemove)=\"showTooltipText($event, element.options['title']);\"\n (mouseout)=\"hideTooltip()\" >\n\n\n\n\n\n </path>\n\n<g *ngSwitchCase=\"'path-bar'\" >\n\n\n\n <path [attr.d]=\"element.options.d\"\n [attr.fill]=[element.options.fill]\n\n [attr.stroke]=\"element.options['stroke']\"\n [attr.stroke-width]=\"element.options['stroke-width']\"\n [attr.stroke-opacity]=\"element.options['stroke-opacity']\"\n [attr.fill-opacity]=\"element.options['fill-opacity']\"\n [attr.id]=\"element.options['id']\"\n (mousemove)=\"showTooltipText($event, element.options['title']);\" (mouseout)=\"hideTooltip()\" >\n\n\n\n\n <ng-container\n\n *ngIf=\"animateChart\"\n >\n\n <animate\n attributeName=\"fill\"\n [attr.from]=\"element.options['fill']\"\n to=\"transparent\"\n dur=\"1ms\"\n fill=\"freeze\" />\n <animate\n attributeName=\"stroke\"\n [attr.from]=\"element.options['fill']\"\n [attr.to]=\"element.options['fill']\"\n dur=\"1ms\"\n fill=\"freeze\" />\n <animate\n attributeName=\"stroke-width\"\n from=\"8\"\n to=\"8\"\n dur=\"1ms\"\n fill=\"freeze\" />\n <animate\n attributeName=\"stroke-dasharray\"\n from=\"1000\"\n to=\"1000\"\n dur=\"1ms\"\n fill=\"freeze\" />\n\n\n <animate\n attributeName=\"fill\"\n from=\"#FFFFFF\"\n [attr.to]=\"element.options['fill']\"\n begin=\"2s\"\n dur=\"3s\"\n fill=\"freeze\" />\n\n <animate\n attributeName=\"stroke-dashoffset\"\n from=\"1000\"\n to=\"0\"\n begin=\"1ms\"\n dur=\"3s\"\n fill=\"freeze\" />\n\n <animate\n attributeName=\"stroke-width\"\n from=\"8\"\n [attr.to]=\"element.options['stroke']\"\n begin=\"3s\"\n dur=\"1s\"\n fill=\"freeze\" />\n </ng-container>\n </path>\n\n\n\n\n</g>\n\n <text *ngSwitchCase=\"'text-on-arc'\"\n [attr.font-size]=\"element.options['font-size']\"\n\n >\n <textPath\n [attr.href]=\"element.options.href\"\n [attr.startOffset]=\"element.options.startOffset\"\n [attr.text-anchor]=\"element.options['text-anchor']\"\n >{{element.options['label']}}</textPath>\n <title>{{element.options['title']}}</title>\n\n </text>\n\n\n <line *ngSwitchCase=\"'line'\"\n [attr.x1]=\"element.options.x1\"\n [attr.y1]=\"element.options.y1\"\n [attr.x2]=\"element.options.x2\"\n [attr.y2]=\"element.options.y2\"\n [attr.stroke-width]=\"element.options.width\"\n\n [attr.stroke]=\"element.options['color']\" >\n <title>{{element.options['title']}}</title>\n </line>\n\n\n <text *ngSwitchCase=\"'text'\"\n [attr.x]=\"element.options.x\"\n [attr.y]=\"element.options.y\"\n [attr.stroke]=\"element.options.stroke\"\n [attr.stroke-width]=\"element.options['stroke-width']\"\n [attr.font-size]=\"element.options['font-size']\"\n [attr.text-anchor]=\"element.options['text-anchor']\"\n >{{element.options.content}}\n <title>{{element.options['content']}}</title>\n </text>\n\n </ng-container>\n\n\n\n </ng-container>\n\n\n </g>\n</svg>\n</ng-container>\n",
styles: [".app-tooltip{background:#fff8dc;border:1px solid #000;border-radius:5px;padding:5px;z-index:1002}.growAnimation{-moz-transition:transform 2s ease-in-out;-webkit-transition:transform 2s ease-in-out;-o-transition:transform 2s ease-in-out;transform:scale(1)}.growAnimation:active{transform:scale(.5)}"]
})
], AngularSunburstRadarChartComponent);
export { AngularSunburstRadarChartComponent };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5ndWxhci1zdW5idXJzdC1yYWRhci1jaGFydC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290Ijoibmc6Ly9hbmd1bGFyLXN1bmJ1cnN0LXJhZGFyLWNoYXJ0LyIsInNvdXJjZXMiOlsibGliL2FuZ3VsYXItc3VuYnVyc3QtcmFkYXItY2hhcnQuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQSxPQUFPLEVBQWdCLFNBQVMsRUFBRSxLQUFLLEVBQW1DLE1BQU0sZUFBZSxDQUFDO0FBQ2hHLE9BQU8sRUFBQyxZQUFZLEVBQUUsVUFBVSxFQUFFLFVBQVUsRUFBQyxNQUFNLGtCQUFrQixDQUFDO0FBQ3RFLE9BQU8sRUFBQyxvQkFBb0IsRUFBRSxlQUFlLEVBQUUsY0FBYyxFQUFDLE1BQU0scUJBQXFCLENBQUM7QUFDMUYsT0FBTyxFQUFDLDRCQUE0QixFQUFFLDRCQUE0QixFQUFDLE1BQU0sd0JBQXdCLENBQUM7QUFDbEcsT0FBTyxFQUFDLHFCQUFxQixFQUFFLGtCQUFrQixFQUFpQixNQUFNLG1CQUFtQixDQUFDO0FBQzVGLE9BQU8sRUFBQyx3QkFBd0IsRUFBRSxnQkFBZ0IsRUFBQyxNQUFNLHFCQUFxQixDQUFDO0FBQy9FLE9BQU8sRUFBQyxhQUFhLEVBQUUsdUJBQXVCLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUN0RSxPQUFPLEVBQUMsV0FBVyxFQUFFLG1CQUFtQixFQUFFLGlCQUFpQixFQUFFLGlCQUFpQixFQUFFLFFBQVEsRUFBQyxNQUFNLGVBQWUsQ0FBQztBQUMvRyxPQUFPLEVBQUMsd0JBQXdCLEVBQUUseUJBQXlCLEVBQUUseUJBQXlCLEVBQUUsaUJBQWlCLEVBQUMsTUFBTSxnQkFBZ0IsQ0FBQztBQUdqSSxPQUFPLEVBQUMsNEJBQTRCLEVBQUMsTUFBTSxxQkFBcUIsQ0FBQztBQVFqRSxJQUFhLGtDQUFrQyxHQUEvQyxNQUFhLGtDQUFrQztJQUk3QztRQUlBLHVCQUFrQixHQUFDLEtBQUssQ0FBQztRQUN6QixnQkFBVyxH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QztHQUNXLGtDQUFrQyxDQWtuQjlDO1NBbG5CWSxrQ0FBa0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge0FmdGVyVmlld0luaXQsIENvbXBvbmVudCwgSW5wdXQsIE9uQ2hhbmdlcywgT25Jbml0LCBTaW1wbGVDaGFuZ2VzfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7Y3JlYXRlQ2lyY2xlLCBjcmVhdGVMaW5lLCBjcmVhdGVQYXRofSBmcm9tICcuL3V0aWxzL2VsZW1lbnRzJztcbmltcG9ydCB7Y3JlYXRlQXJjVG9Xcml0ZVRleHQsIGdldFRleHRGb3JBbmdsZSwgd3JpdGVUZXh0T25BcmN9IGZyb20gJy4vdXRpbHMvdGV4dGVsZW1lbnQnO1xuaW1wb3J0IHtjcmVhdGVJbm5lckNoYXJ0QmFyV2l0aEluQXJjLCBjcmVhdGVPdXRlckNoYXJ0QmFyV2l0aEluQXJjfSBmcm9tICcuL3V0aWxzL2FyYy1iYXItY2hhcnRzJztcbmltcG9ydCB7Y2FsY3VsYXRlUG9pbnRCZXR3ZWVuLCBnZXRHbG9iYWxQb3NpdGlvbnMsIEdsb2JhbFBvc2l0aW9ufSBmcm9tICcuL3V0aWxzL3Bvc2l0aW9ucyc7XG5pbXBvcnQge2Rpc3RhbmNlQmV0d2VlblR3b1BvaW50cywgcG9sYXJUb0NhcnRlc2lhbn0gZnJvbSAnLi91dGlscy90cmlnbm9tZXRyeSc7XG5pbXBvcnQge2NyZWF0ZUxlZ2VuZHMsIGNyZWF0ZUxlZ2VuZFdpdGhPcHRpb25zfSBmcm9tICcuL3V0aWxzL2xlZ2VuZCc7XG5pbXBvcnQge2Zvcm1hdEl0ZW1zLCBnZW5lcmF0ZVJhbmRvbUNvbG9yLCBnZXRGb3JtYXR0ZWRBbmdsZSwgZ2V0T3B0aW9uc09yRW1wdHksIGhhc2hDb2RlfSBmcm9tICcuL3V0aWxzL3V0aWxzJztcbmltcG9ydCB7Z2V0QWxsQW5nbGVzQmFzZWRPbkNoaWxkLCBnZXRBbGxBbmdsZXNCYXNlZE9uUGFyZW50LCBnZXRQb2ludHNPbkNpcmNsZUF0QW5nZWxzLCBwb3NpdGlvbnNPbkFuZ2xlc30gZnJvbSAnLi91dGlscy9hbmdlbHMnO1xuaW1wb3J0IHtBbmd1bGFyU3ZnRWxlbWVudH0gZnJvbSAnLi91dGlscy9tb2RlbHMnO1xuXG5pbXBvcnQge2NyZWF0ZVN2Z0hhbmRsZXJXaXRoU2VsZWN0b3J9IGZyb20gJy4vdXRpbHMvc3ZnLXJvdGF0b3InO1xuXG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2xpYi1zdW5idXJzdC1yYWRhci1jaGFydCcsXG4gIHRlbXBsYXRlVXJsOiAnLi9hbmd1bGFyLXN1bmJ1cnN0LXJhZGFyLWNoYXJ0LmNvbXBvbmVudC5odG1sJyxcbiAgc3R5bGVVcmxzOiBbJy4vYW5ndWxhci1zdW5idXJzdC1yYWRhci1jaGFydC5jb21wb25lbnQuc2NzcyddXG59KVxuZXhwb3J0IGNsYXNzIEFuZ3VsYXJTdW5idXJzdFJhZGFyQ2hhcnRDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcyB7XG5cblxuXG4gIGNvbnN0cnVjdG9yKCkge1xuICB9XG5cblxuICBjb21wb25lbnREaXNwbGF5ZWQ9ZmFsc2U7XG4gIHNob3dUb29sVGlwID0gZmFsc2U7XG4gIHRvb2x0aXBUb3BJblB4ID0gJzBweCc7XG4gIHRvb2x0aXBMZWZ0SW5QeCA9ICcwcHgnO1xuICB0b29sdGlwVGV4dCA9ICcnO1xuICBzdmdJZCA9IG51bGw7XG4gIHN2Z0dyb3VwSWQgPSBudWxsO1xuXG4gIHN2Z0hhbmRsZXIgPSBudWxsO1xuXG4gIGN1cnJlbnRSb3RhdGlvbkFuZ2xlID0gMTA7XG4gIHJvdGF0aW9uUG9pbnQ7XG4gIHN2Z0N1cnNvciA9ICdkZWZhdWx0JztcblxuXG4gIEBJbnB1dCgpXG4gIGl0ZW1zO1xuXG4gIEBJbnB1dCgpXG4gIG9wdGlvbnM7XG5cbiAgc2l6ZTogbnVtYmVyO1xuXG5cbiAgbWF4U2NvcmU6IG51bWJlcjtcblxuICBsZWdlbmRBeGlzTGluZVBvc2l0aW9uOiBudW1iZXI7XG5cbiAgYW5pbWF0ZUNoYXJ0O1xuXG4gIHNwbGl0QmFzZWRPbkNoaWxkcmVuO1xuXG4gIHZpZXdCb3g7XG5cbiAgaW5pdGlhbGl6ZWQgPSBmYWxzZTtcbiAgaW5uZXJDaXJjbGVSYWRpdXM7XG5cbiAgaW5uZXJCb3JkZXJIZWlnaHQgPSAzMDtcbiAgb3V0ZXJCb3JkZXJIZWlnaHQgPSAzMDtcblxuXG4gIGVsZW1lbnRzOiBBbmd1bGFyU3ZnRWxlbWVudFtdID0gW107XG4gIGdsb2JhbFBvc2l0aW9uOiBHbG9iYWxQb3NpdGlvbjtcbiAgaGFzQ2hpbGRyZW4gPSBmYWxzZTtcbiAgY2hhcnRCb3JkZXI7XG4gIG91dGVyQm9yZGVyQ2lyY2xlUmVmID0gJ291dGVyQm9yZGVyQ2lyY2xlJztcbiAgZXJyb3I6IGFueSA9IG51bGw7XG4gIGhhc0Vycm9yID0gZmFsc2U7XG5cbiAgc3RhcnRSb3RhdGlvbiA9IGZhbHNlO1xuXG4gIHNob3dFcnJvcihtc2cpIHtcblxuICAgIHRoaXMuZXJyb3IgPSBtc2c7XG4gICAgdGhpcy5oYXNFcnJvciA9IHRydWU7XG4gIH1cblxuICBoaWRlRXJyb3IoKSB7XG5cbiAgICB0aGlzLmVycm9yID0gbnVsbDtcbiAgICB0aGlzLmhhc0Vycm9yID0gZmFsc2U7XG4gIH1cblxuICBhcHBlbmRUb1N2ZyhlbGVtZW50OiBBbmd1bGFyU3ZnRWxlbWVudCkge1xuXG4gICAgdGhpcy5lbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICB9XG5cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XG5cblxuICAgIHRoaXMuaGlkZUVycm9yKCk7XG4gICAgY29uc3QgaXNGaXJzdENoYW5nZSA9IE9iamVjdC52YWx1ZXMoY2hhbmdlcykuc29tZShjID0+IGMuaXNGaXJzdENoYW5nZSgpKTtcbiAgICB0aGlzLm1vZGlmeU9uRmlyc3RDaGFuZ2UoaXNGaXJzdENoYW5nZSk7XG5cblxuICB9XG5cbiAgbW9kaWZ5T25GaXJzdENoYW5nZShpc0ZpcnN0Q2hhbmdlOiBib29sZWFuKSB7XG4gICAgaWYgKCFpc0ZpcnN0Q2hhbmdlKSB7XG5cbiAgICAgIHRoaXMuaW5pdGlhbGl6ZSgpO1xuICAgIH1cbiAgfVxuXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIHRoaXMuaGlkZUVycm9yKCk7XG4gICAgdGhpcy5pbml0aWFsaXplKCk7XG4gIH1cblxuXG4gIGluaXRpYWxpemUoKTogdm9pZCB7XG5cblxuICAgIGNvbnN0IGRlZmF1bHRzID0ge3NpemU6IDMwMCwgbWF4U2NvcmU6IDEwMCwgYW5pbWF0ZUNoYXJ0OiB0cnVlLCBzcGxpdEJhc2VkT25DaGlsZHJlbjogdHJ1ZSwgbGVnZW5kQXhpc0xpbmVQb3NpdGlvbjogMX07XG4gICAgY29uc3Qgb3B0aW9ucyA9IHsuLi5kZWZhdWx0cywgLi4uKGdldE9wdGlvbnNPckVtcHR5KHRoaXMub3B0aW9ucykpfTtcblxuICAgIHRoaXMuc2l6ZSA9IG9wdGlvbnMuc2l6ZTtcbiAgICB0aGlzLm1heFNjb3JlID0gb3B0aW9ucy5tYXhTY29yZTtcbiAgICB0aGlzLmFuaW1hdGVDaGFydCA9IG9wdGlvbnMuYW5pbWF0ZUNoYXJ0O1xuICAgIHRoaXMuc3BsaXRCYXNlZE9uQ2hpbGRyZW4gPSBvcHRpb25zLnNwbGl0QmFzZWRPbkNoaWxkcmVuO1xuICAgIHRoaXMubGVnZW5kQXhpc0xpbmVQb3NpdGlvbiA9IG9wdGlvbnMubGVnZW5kQXhpc0xpbmVQb3NpdGlvbjtcblxuXG4gICAgaWYgKCF0aGlzLmhhc1ZhbGlkUGFyYW1ldGVycygpKSB7XG5cbiAgICAgIHRoaXMuc2hvd0Vycm9yKCdJbnB1dCBWYWx1ZXMgbm90IHNldCBvciBJdGVtcyB3YXMgaW1wcm9wZXInKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5pbml0aWFsaXplZCA9IGZhbHNlO1xuICAgIHRoaXMuc3ZnSWQgPSAnc3ZnJyArIGhhc2hDb2RlKHRoaXMuaXRlbXMpO1xuICAgIHRoaXMuc3ZnR3JvdXBJZCA9ICdzdmctZ3JvdXAnICsgaGFzaENvZGUodGhpcy5pdGVtcyk7XG5cblxuICAgIHRoaXMudmlld0JveCA9ICcwIDAgJyArIHRoaXMuc2l6ZSArICcgJyArIHRoaXMuc2l6ZTtcblxuXG4gICAgdGhpcy5pbm5lckNpcmNsZVJhZGl1cyA9IE1hdGguYWJzKHRoaXMuc2l6ZSAvIDUuMzMpO1xuXG4gICAgdGhpcy5pbm5lckJvcmRlckhlaWdodCA9IHRoaXMuaW5uZXJDaXJjbGVSYWRpdXMgLyA1O1xuICAgIHRoaXMub3V0ZXJCb3JkZXJIZWlnaHQgPSB0aGlzLmlubmVyQ2lyY2xlUmFkaXVzIC8gNTtcblxuICAgIHRoaXMuZ2xvYmFsUG9zaXRpb24gPSBnZXRHbG9iYWxQb3NpdGlvbnMoe1xuICAgICAgc2l6ZTogdGhpcy5zaXplLFxuICAgICAgbWF4U2NvcmU6IHRoaXMubWF4U2NvcmUsXG4gICAgICBpdGVtczogdGhpcy5pdGVtc1xuXG4gICAgfSk7XG5cbiAgICB0aGlzLmhhc0NoaWxkcmVuID0gdGhpcy5pdGVtcy5maWx0ZXIoaXRlbSA9PiAhIWl0ZW0uY2hpbGRyZW4pLmxlbmd0aCA+IDA7XG5cblxuICAgIHRoaXMuZHJhd0xheW91dCgpO1xuXG5cbiAgICBjb25zdCB7aW5uZXJSYWRpdXMsIGlubmVyVGV4dFJhZGl1cywgdGV4dFNpemUsIG91dGVyVGV4dFNpemUsIG91dGVyUmFkaXVzQm9yZGVyLCBvdXRlclRleHRSYWRpdXMsIGNlbnRlcn0gPSB0aGlzLmdsb2JhbFBvc2l0aW9uO1xuICAgIGNvbnN0IFtjZW50ZXJYLCBjZW50ZXJZXSA9IFtjZW50ZXIueCwgY2VudGVy