@nova-ui/charts
Version:
Nova Charts is a library created to provide potential consumers with solutions for various data visualizations that conform with the Nova Design Language. It's designed to solve common patterns identified by UX designers, but also be very flexible so that
205 lines • 27.3 kB
JavaScript
// © 2022 SolarWinds Worldwide, LLC. All rights reserved.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import each from "lodash/each";
import pickBy from "lodash/pickBy";
import values from "lodash/values";
import { Subject } from "rxjs";
import { takeUntil } from "rxjs/operators";
import { CHART_VIEW_STATUS_EVENT, INTERACTION_DATA_POINTS_EVENT, SERIES_STATE_CHANGE_EVENT, } from "../../../constants";
import { RenderState } from "../../../renderers/types";
import { ChartPlugin } from "../../common/chart-plugin";
import { InteractionType, } from "../../common/types";
/** How far away from the data point position will the tooltip be positioned */
export const TOOLTIP_POSITION_OFFSET = 10;
/** @ignore
* Used for charts where tooltips should be placed aside of some vertical line */
export const getVerticalSetup = (offset) => [
{
originX: "end",
originY: "top",
overlayX: "start",
overlayY: "center",
offsetX: offset,
},
{
originX: "start",
originY: "center",
overlayX: "end",
overlayY: "center",
offsetX: -offset,
},
];
/** @ignore
* Used for charts where tooltips should be placed aligned to some horizontal line (as Horizontal Bar Charts) */
export const getHorizontalSetup = (offset) => [
{
originX: "end",
originY: "top",
overlayX: "center",
overlayY: "bottom",
offsetY: -offset,
},
{
originX: "end",
originY: "bottom",
overlayX: "center",
overlayY: "top",
offsetY: offset,
},
];
/**
* This plugin listens to the INTERACTION_DATA_POINTS_EVENT and transforms received data into tooltips inputs.
* The actual tooltips are handled by the ChartTooltipsComponent.
*/
export class ChartTooltipsPlugin extends ChartPlugin {
tooltipPositionOffset;
orientation;
/** Highlighted data points received from the chart */
dataPoints;
/** Calculated positions for the data point tooltips */
dataPointPositions = {};
/**
* This publishes an event to show tooltips
*/
showSubject = new Subject();
/**
* This publishes an event to hide tooltips
*/
hideSubject = new Subject();
overlaySetup;
isChartInView = false;
destroy$ = new Subject();
seriesVisibilityMap = {};
/**
* @param tooltipPositionOffset Offset of a tooltip from edge of a highlighted element
* @param orientation
*/
constructor(tooltipPositionOffset = TOOLTIP_POSITION_OFFSET, orientation = "right") {
super();
this.tooltipPositionOffset = tooltipPositionOffset;
this.orientation = orientation;
if (orientation === "right") {
this.overlaySetup = getVerticalSetup(tooltipPositionOffset);
}
else if (orientation === "top") {
this.overlaySetup = getHorizontalSetup(tooltipPositionOffset);
}
}
initialize() {
this.chart
.getEventBus()
.getStream(INTERACTION_DATA_POINTS_EVENT)
.pipe(takeUntil(this.destroy$))
.subscribe((event) => {
if (event.data.interactionType === InteractionType.MouseMove &&
this.isChartInView) {
const dataPoints = event.data.dataPoints;
this.processHighlightedDataPoints(dataPoints);
}
});
this.chart
.getEventBus()
.getStream(SERIES_STATE_CHANGE_EVENT)
.pipe(takeUntil(this.destroy$))
.subscribe((event) => {
event.data.forEach((series) => {
this.seriesVisibilityMap[series.seriesId] =
series.state !== RenderState.hidden;
});
});
this.chart
.getEventBus()
.getStream(CHART_VIEW_STATUS_EVENT)
.pipe(takeUntil(this.destroy$))
.subscribe((event) => {
this.isChartInView = event.data.isChartInView;
if (!this.isChartInView) {
this.hideSubject.next();
}
});
}
destroy() {
this.destroy$.next();
this.destroy$.complete();
}
processHighlightedDataPoints(dataPoints) {
const validDataPoints = pickBy(dataPoints, (d) => d.index >= 0 &&
d.position &&
this.seriesVisibilityMap[d.seriesId] !== false);
if (values(validDataPoints).length === 0) {
this.hideSubject.next();
return;
}
this.dataPoints = validDataPoints;
const chartElement = this.chart.target?.node()?.parentNode; // the one above svg
if (!chartElement) {
throw new Error("Chart parent node is not defined");
}
const bbox = chartElement.getBoundingClientRect();
const offsetParentBbox = chartElement.offsetParent.getBoundingClientRect();
const chartPosition = {
x: bbox.left - offsetParentBbox.left,
y: bbox.top - offsetParentBbox.top,
};
each(Object.keys(this.dataPoints), (seriesId) => {
const dataPoint = this.dataPoints[seriesId];
const chartSeries = this.chart
.getDataManager()
.getChartSeries(dataPoint.seriesId);
const tooltipRelativePosition = this.getTooltipPosition(dataPoint, chartSeries);
this.dataPointPositions[seriesId] = this.getAbsolutePosition(tooltipRelativePosition, chartPosition);
});
this.showSubject.next();
}
/**
* Calculate tooltip position. Default implementation shows the tooltip on left / right with
* @param dataPoint
* @param chartSeries
*/
getTooltipPosition(dataPoint, chartSeries) {
if (!dataPoint.position) {
throw new Error("Unable to get tooltip position");
}
return {
x: dataPoint.position.x,
y: dataPoint.position.y,
height: dataPoint.position?.height || 1,
width: dataPoint.position?.width || 1,
overlayPositions: this.overlaySetup,
};
}
/**
* Converts the relative position within a chart into an absolute position on the screen
*
* @param relativePosition
* @param chartPosition
*/
getAbsolutePosition(relativePosition, chartPosition) {
return Object.assign({}, relativePosition, {
x: chartPosition.x +
this.chart.getGrid().config().dimension.margin.left +
relativePosition.x,
y: chartPosition.y +
this.chart.getGrid().config().dimension.margin.top +
relativePosition.y,
});
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnQtdG9vbHRpcHMtcGx1Z2luLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vc3JjL2NvcmUvcGx1Z2lucy90b29sdGlwcy9jaGFydC10b29sdGlwcy1wbHVnaW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEseURBQXlEO0FBQ3pELEVBQUU7QUFDRiwrRUFBK0U7QUFDL0UsNEVBQTRFO0FBQzVFLDhFQUE4RTtBQUM5RSwrRUFBK0U7QUFDL0UsOEVBQThFO0FBQzlFLDREQUE0RDtBQUM1RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLHVEQUF1RDtBQUN2RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLDRFQUE0RTtBQUM1RSwrRUFBK0U7QUFDL0UsMEVBQTBFO0FBQzFFLGlGQUFpRjtBQUNqRiw2RUFBNkU7QUFDN0UsaUJBQWlCO0FBR2pCLE9BQU8sSUFBSSxNQUFNLGFBQWEsQ0FBQztBQUMvQixPQUFPLE1BQU0sTUFBTSxlQUFlLENBQUM7QUFDbkMsT0FBTyxNQUFNLE1BQU0sZUFBZSxDQUFDO0FBQ25DLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTNDLE9BQU8sRUFDSCx1QkFBdUIsRUFDdkIsNkJBQTZCLEVBQzdCLHlCQUF5QixHQUM1QixNQUFNLG9CQUFvQixDQUFDO0FBQzVCLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDeEQsT0FBTyxFQU9ILGVBQWUsR0FHbEIsTUFBTSxvQkFBb0IsQ0FBQztBQU81QiwrRUFBK0U7QUFDL0UsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsRUFBRSxDQUFDO0FBRTFDO2lGQUNpRjtBQUNqRixNQUFNLENBQUMsTUFBTSxnQkFBZ0IsR0FBRyxDQUFDLE1BQWMsRUFBdUIs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QixDQUN4QixTQUFxQixFQUNyQixXQUFxQztRQUVyQyxJQUFJLENBQUMsU0FBUyxDQUFDLFFBQVEsRUFBRTtZQUNyQixNQUFNLElBQUksS0FBSyxDQUFDLGdDQUFnQyxDQUFDLENBQUM7U0FDckQ7UUFFRCxPQUFPO1lBQ0gsQ0FBQyxFQUFFLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN2QixDQUFDLEVBQUUsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3ZCLE1BQU0sRUFBRSxTQUFTLENBQUMsUUFBUSxFQUFFLE1BQU0sSUFBSSxDQUFDO1lBQ3ZDLEtBQUssRUFBRSxTQUFTLENBQUMsUUFBUSxFQUFFLEtBQUssSUFBSSxDQUFDO1lBQ3JDLGdCQUFnQixFQUFFLElBQUksQ0FBQyxZQUFZO1NBQ3RDLENBQUM7SUFDTixDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDTyxtQkFBbUIsQ0FDekIsZ0JBQWtDLEVBQ2xDLGFBQXdCO1FBRXhCLE9BQU8sTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsZ0JBQWdCLEVBQUU7WUFDdkMsQ0FBQyxFQUNHLGFBQWEsQ0FBQyxDQUFDO2dCQUNmLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxJQUFJO2dCQUNuRCxnQkFBZ0IsQ0FBQyxDQUFDO1lBQ3RCLENBQUMsRUFDRyxhQUFhLENBQUMsQ0FBQztnQkFDZixJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsR0FBRztnQkFDbEQsZ0JBQWdCLENBQUMsQ0FBQztTQUN6QixDQUFDLENBQUM7SUFDUCxDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyIvLyDCqSAyMDIyIFNvbGFyV2luZHMgV29ybGR3aWRlLCBMTEMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvXG4vLyAgZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGVcbi8vICByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Jcbi8vICBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vICBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IHsgQ29ubmVjdGVkUG9zaXRpb24gfSBmcm9tIFwiQGFuZ3VsYXIvY2RrL292ZXJsYXlcIjtcbmltcG9ydCBlYWNoIGZyb20gXCJsb2Rhc2gvZWFjaFwiO1xuaW1wb3J0IHBpY2tCeSBmcm9tIFwibG9kYXNoL3BpY2tCeVwiO1xuaW1wb3J0IHZhbHVlcyBmcm9tIFwibG9kYXNoL3ZhbHVlc1wiO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQgeyB0YWtlVW50aWwgfSBmcm9tIFwicnhqcy9vcGVyYXRvcnNcIjtcblxuaW1wb3J0IHtcbiAgICBDSEFSVF9WSUVXX1NUQVRVU19FVkVOVCxcbiAgICBJTlRFUkFDVElPTl9EQVRBX1BPSU5UU19FVkVOVCxcbiAgICBTRVJJRVNfU1RBVEVfQ0hBTkdFX0VWRU5ULFxufSBmcm9tIFwiLi4vLi4vLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBSZW5kZXJTdGF0ZSB9IGZyb20gXCIuLi8uLi8uLi9yZW5kZXJlcnMvdHlwZXNcIjtcbmltcG9ydCB7IENoYXJ0UGx1Z2luIH0gZnJvbSBcIi4uLy4uL2NvbW1vbi9jaGFydC1wbHVnaW5cIjtcbmltcG9ydCB7XG4gICAgSUFjY2Vzc29ycyxcbiAgICBJQ2hhcnRFdmVudCxcbiAgICBJQ2hhcnRTZXJpZXMsXG4gICAgSUNoYXJ0Vmlld1N0YXR1c0V2ZW50UGF5bG9hZCxcbiAgICBJRGF0YVBvaW50LFxuICAgIElEYXRhUG9pbnRzUGF5bG9hZCxcbiAgICBJbnRlcmFjdGlvblR5cGUsXG4gICAgSVBvc2l0aW9uLFxuICAgIElSZW5kZXJTdGF0ZURhdGEsXG59IGZyb20gXCIuLi8uLi9jb21tb24vdHlwZXNcIjtcblxuLyoqIFBvc2l0aW9uIHdpdGggZXh0ZW5kZWQgaW5mb3JtYXRpb24gZm9yIHBvc2l0aW9uaW5nIGEgdG9vbHRpcCAqL1xuZXhwb3J0IGludGVyZmFjZSBJVG9vbHRpcFBvc2l0aW9uIGV4dGVuZHMgSVBvc2l0aW9uIHtcbiAgICBvdmVybGF5UG9zaXRpb25zOiBDb25uZWN0ZWRQb3NpdGlvbltdO1xufVxuXG4vKiogSG93IGZhciBhd2F5IGZyb20gdGhlIGRhdGEgcG9pbnQgcG9zaXRpb24gd2lsbCB0aGUgdG9vbHRpcCBiZSBwb3NpdGlvbmVkICovXG5leHBvcnQgY29uc3QgVE9PTFRJUF9QT1NJVElPTl9PRkZTRVQgPSAxMDtcblxuLyoqIEBpZ25vcmVcbiAqIFVzZWQgZm9yIGNoYXJ0cyB3aGVyZSB0b29sdGlwcyBzaG91bGQgYmUgcGxhY2VkIGFzaWRlIG9mIHNvbWUgdmVydGljYWwgbGluZSAqL1xuZXhwb3J0IGNvbnN0IGdldFZlcnRpY2FsU2V0dXAgPSAob2Zmc2V0OiBudW1iZXIpOiBDb25uZWN0ZWRQb3NpdGlvbltdID0+IFtcbiAgICB7XG4gICAgICAgIG9yaWdpblg6IFwiZW5kXCIsXG4gICAgICAgIG9yaWdpblk6IFwidG9wXCIsXG4gICAgICAgIG92ZXJsYXlYOiBcInN0YXJ0XCIsXG4gICAgICAgIG92ZXJsYXlZOiBcImNlbnRlclwiLFxuICAgICAgICBvZmZzZXRYOiBvZmZzZXQsXG4gICAgfSxcbiAgICB7XG4gICAgICAgIG9yaWdpblg6IFwic3RhcnRcIixcbiAgICAgICAgb3JpZ2luWTogXCJjZW50ZXJcIixcbiAgICAgICAgb3ZlcmxheVg6IFwiZW5kXCIsXG4gICAgICAgIG92ZXJsYXlZOiBcImNlbnRlclwiLFxuICAgICAgICBvZmZzZXRYOiAtb2Zmc2V0LFxuICAgIH0sXG5dO1xuXG4vKiogQGlnbm9yZVxuICogVXNlZCBmb3IgY2hhcnRzIHdoZXJlIHRvb2x0aXBzIHNob3VsZCBiZSBwbGFjZWQgYWxpZ25lZCB0byBzb21lIGhvcml6b250YWwgbGluZSAoYXMgSG9yaXpvbnRhbCBCYXIgQ2hhcnRzKSAqL1xuZXhwb3J0IGNvbnN0IGdldEhvcml6b250YWxTZXR1cCA9IChvZmZzZXQ6IG51bWJlcik6IENvbm5lY3RlZFBvc2l0aW9uW10gPT4gW1xuICAgIHtcbiAgICAgICAgb3JpZ2luWDogXCJlbmRcIixcbiAgICAgICAgb3JpZ2luWTogXCJ0b3BcIixcbiAgICAgICAgb3ZlcmxheVg6IFwiY2VudGVyXCIsXG4gICAgICAgIG92ZXJsYXlZOiBcImJvdHRvbVwiLFxuICAgICAgICBvZmZzZXRZOiAtb2Zmc2V0LFxuICAgIH0sXG4gICAge1xuICAgICAgICBvcmlnaW5YOiBcImVuZFwiLFxuICAgICAgICBvcmlnaW5ZOiBcImJvdHRvbVwiLFxuICAgICAgICBvdmVybGF5WDogXCJjZW50ZXJcIixcbiAgICAgICAgb3ZlcmxheVk6IFwidG9wXCIsXG4gICAgICAgIG9mZnNldFk6IG9mZnNldCxcbiAgICB9LFxuXTtcblxuLyoqXG4gKiBUaGlzIHBsdWdpbiBsaXN0ZW5zIHRvIHRoZSBJTlRFUkFDVElPTl9EQVRBX1BPSU5UU19FVkVOVCBhbmQgdHJhbnNmb3JtcyByZWNlaXZlZCBkYXRhIGludG8gdG9vbHRpcHMgaW5wdXRzLlxuICogVGhlIGFjdHVhbCB0b29sdGlwcyBhcmUgaGFuZGxlZCBieSB0aGUgQ2hhcnRUb29sdGlwc0NvbXBvbmVudC5cbiAqL1xuZXhwb3J0IGNsYXNzIENoYXJ0VG9vbHRpcHNQbHVnaW4gZXh0ZW5kcyBDaGFydFBsdWdpbiB7XG4gICAgLyoqIEhpZ2hsaWdodGVkIGRhdGEgcG9pbnRzIHJlY2VpdmVkIGZyb20gdGhlIGNoYXJ0ICovXG4gICAgcHVibGljIGRhdGFQb2ludHM6IElEYXRhUG9pbnRzUGF5bG9hZDtcbiAgICAvKiogQ2FsY3VsYXRlZCBwb3NpdGlvbnMgZm9yIHRoZSBkYXRhIHBvaW50IHRvb2x0aXBzICovXG4gICAgcHVibGljIGRhdGFQb2ludFBvc2l0aW9uczogeyBbc3RyaW5nSWQ6IHN0cmluZ106IElUb29sdGlwUG9zaXRpb24gfSA9IHt9O1xuXG4gICAgLyoqXG4gICAgICogVGhpcyBwdWJsaXNoZXMgYW4gZXZlbnQgdG8gc2hvdyB0b29sdGlwc1xuICAgICAqL1xuICAgIHB1YmxpYyBzaG93U3ViamVjdCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG5cbiAgICAvKipcbiAgICAgKiBUaGlzIHB1Ymxpc2hlcyBhbiBldmVudCB0byBoaWRlIHRvb2x0aXBzXG4gICAgICovXG4gICAgcHVibGljIGhpZGVTdWJqZWN0ID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICAgIHByb3RlY3RlZCBvdmVybGF5U2V0dXA6IENvbm5lY3RlZFBvc2l0aW9uW107XG5cbiAgICBwcml2YXRlIGlzQ2hhcnRJblZpZXcgPSBmYWxzZTtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgICBwcml2YXRlIHNlcmllc1Zpc2liaWxpdHlNYXA6IFJlY29yZDxzdHJpbmcsIGJvb2xlYW4+ID0ge307XG5cbiAgICAvKipcbiAgICAgKiBAcGFyYW0gdG9vbHRpcFBvc2l0aW9uT2Zmc2V0IE9mZnNldCBvZiBhIHRvb2x0aXAgZnJvbSBlZGdlIG9mIGEgaGlnaGxpZ2h0ZWQgZWxlbWVudFxuICAgICAqIEBwYXJhbSBvcmllbnRhdGlvblxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKFxuICAgICAgICByZWFkb25seSB0b29sdGlwUG9zaXRpb25PZmZzZXQ6IG51bWJlciA9IFRPT0xUSVBfUE9TSVRJT05fT0ZGU0VULFxuICAgICAgICBwdWJsaWMgb3JpZW50YXRpb246IFwicmlnaHRcIiB8IFwidG9wXCIgPSBcInJpZ2h0XCJcbiAgICApIHtcbiAgICAgICAgc3VwZXIoKTtcblxuICAgICAgICBpZiAob3JpZW50YXRpb24gPT09IFwicmlnaHRcIikge1xuICAgICAgICAgICAgdGhpcy5vdmVybGF5U2V0dXAgPSBnZXRWZXJ0aWNhbFNldHVwKHRvb2x0aXBQb3NpdGlvbk9mZnNldCk7XG4gICAgICAgIH0gZWxzZSBpZiAob3JpZW50YXRpb24gPT09IFwidG9wXCIpIHtcbiAgICAgICAgICAgIHRoaXMub3ZlcmxheVNldHVwID0gZ2V0SG9yaXpvbnRhbFNldHVwKHRvb2x0aXBQb3NpdGlvbk9mZnNldCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgaW5pdGlhbGl6ZSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5jaGFydFxuICAgICAgICAgICAgLmdldEV2ZW50QnVzKClcbiAgICAgICAgICAgIC5nZXRTdHJlYW0oSU5URVJBQ1RJT05fREFUQV9QT0lOVFNfRVZFTlQpXG4gICAgICAgICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpXG4gICAgICAgICAgICAuc3Vic2NyaWJlKChldmVudDogSUNoYXJ0RXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgIGV2ZW50LmRhdGEuaW50ZXJhY3Rpb25UeXBlID09PSBJbnRlcmFjdGlvblR5cGUuTW91c2VNb3ZlICYmXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaXNDaGFydEluVmlld1xuICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBkYXRhUG9pbnRzOiBJRGF0YVBvaW50c1BheWxvYWQgPVxuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQuZGF0YS5kYXRhUG9pbnRzO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnByb2Nlc3NIaWdobGlnaHRlZERhdGFQb2ludHMoZGF0YVBvaW50cyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5jaGFydFxuICAgICAgICAgICAgLmdldEV2ZW50QnVzKClcbiAgICAgICAgICAgIC5nZXRTdHJlYW0oU0VSSUVTX1NUQVRFX0NIQU5HRV9FVkVOVClcbiAgICAgICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKGV2ZW50OiBJQ2hhcnRFdmVudDxJUmVuZGVyU3RhdGVEYXRhW10+KSA9PiB7XG4gICAgICAgICAgICAgICAgZXZlbnQuZGF0YS5mb3JFYWNoKChzZXJpZXMpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXJpZXNWaXNpYmlsaXR5TWFwW3Nlcmllcy5zZXJpZXNJZF0gPVxuICAgICAgICAgICAgICAgICAgICAgICAgc2VyaWVzLnN0YXRlICE9PSBSZW5kZXJTdGF0ZS5oaWRkZW47XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmNoYXJ0XG4gICAgICAgICAgICAuZ2V0RXZlbnRCdXMoKVxuICAgICAgICAgICAgLmdldFN0cmVhbShDSEFSVF9WSUVXX1NUQVRVU19FVkVOVClcbiAgICAgICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKGV2ZW50OiBJQ2hhcnRFdmVudDxJQ2hhcnRWaWV3U3RhdHVzRXZlbnRQYXlsb2FkPikgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuaXNDaGFydEluVmlldyA9IGV2ZW50LmRhdGEuaXNDaGFydEluVmlldztcbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuaXNDaGFydEluVmlldykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmhpZGVTdWJqZWN0Lm5leHQoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZGVzdHJveSgpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5kZXN0cm95JC5uZXh0KCk7XG4gICAgICAgIHRoaXMuZGVzdHJveSQuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgcHJvY2Vzc0hpZ2hsaWdodGVkRGF0YVBvaW50cyhkYXRhUG9pbnRzOiBJRGF0YVBvaW50c1BheWxvYWQpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgdmFsaWREYXRhUG9pbnRzID0gcGlja0J5KFxuICAgICAgICAgICAgZGF0YVBvaW50cyxcbiAgICAgICAgICAgIChkOiBJRGF0YVBvaW50KSA9PlxuICAgICAgICAgICAgICAgIGQuaW5kZXggPj0gMCAmJlxuICAgICAgICAgICAgICAgIGQucG9zaXRpb24gJiZcbiAgICAgICAgICAgICAgICB0aGlzLnNlcmllc1Zpc2liaWxpdHlNYXBbZC5zZXJpZXNJZF0gIT09IGZhbHNlXG4gICAgICAgICk7XG5cbiAgICAgICAgaWYgKHZhbHVlcyh2YWxpZERhdGFQb2ludHMpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy5oaWRlU3ViamVjdC5uZXh0KCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLmRhdGFQb2ludHMgPSB2YWxpZERhdGFQb2ludHM7XG4gICAgICAgIGNvbnN0IGNoYXJ0RWxlbWVudDogYW55ID0gdGhpcy5jaGFydC50YXJnZXQ/Lm5vZGUoKT8ucGFyZW50Tm9kZTsgLy8gdGhlIG9uZSBhYm92ZSBzdmdcblxuICAgICAgICBpZiAoIWNoYXJ0RWxlbWVudCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2hhcnQgcGFyZW50IG5vZGUgaXMgbm90IGRlZmluZWRcIik7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBiYm94ID0gY2hhcnRFbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBjb25zdCBvZmZzZXRQYXJlbnRCYm94ID1cbiAgICAgICAgICAgIGNoYXJ0RWxlbWVudC5vZmZzZXRQYXJlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIGNvbnN0IGNoYXJ0UG9zaXRpb246IElQb3NpdGlvbiA9IHtcbiAgICAgICAgICAgIHg6IGJib3gubGVmdCAtIG9mZnNldFBhcmVudEJib3gubGVmdCxcbiAgICAgICAgICAgIHk6IGJib3gudG9wIC0gb2Zmc2V0UGFyZW50QmJveC50b3AsXG4gICAgICAgIH07XG5cbiAgICAgICAgZWFjaChPYmplY3Qua2V5cyh0aGlzLmRhdGFQb2ludHMpLCAoc2VyaWVzSWQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGRhdGFQb2ludCA9IHRoaXMuZGF0YVBvaW50c1tzZXJpZXNJZF07XG5cbiAgICAgICAgICAgIGNvbnN0IGNoYXJ0U2VyaWVzID0gdGhpcy5jaGFydFxuICAgICAgICAgICAgICAgIC5nZXREYXRhTWFuYWdlcigpXG4gICAgICAgICAgICAgICAgLmdldENoYXJ0U2VyaWVzKGRhdGFQb2ludC5zZXJpZXNJZCk7XG4gICAgICAgICAgICBjb25zdCB0b29sdGlwUmVsYXRpdmVQb3NpdGlvbiA9IHRoaXMuZ2V0VG9vbHRpcFBvc2l0aW9uKFxuICAgICAgICAgICAgICAgIGRhdGFQb2ludCxcbiAgICAgICAgICAgICAgICBjaGFydFNlcmllc1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHRoaXMuZGF0YVBvaW50UG9zaXRpb25zW3Nlcmllc0lkXSA9IHRoaXMuZ2V0QWJzb2x1dGVQb3NpdGlvbihcbiAgICAgICAgICAgICAgICB0b29sdGlwUmVsYXRpdmVQb3NpdGlvbixcbiAgICAgICAgICAgICAgICBjaGFydFBvc2l0aW9uXG4gICAgICAgICAgICApO1xuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLnNob3dTdWJqZWN0Lm5leHQoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBDYWxjdWxhdGUgdG9vbHRpcCBwb3NpdGlvbi4gRGVmYXVsdCBpbXBsZW1lbnRhdGlvbiBzaG93cyB0aGUgdG9vbHRpcCBvbiBsZWZ0IC8gcmlnaHQgd2l0aFxuICAgICAqIEBwYXJhbSBkYXRhUG9pbnRcbiAgICAgKiBAcGFyYW0gY2hhcnRTZXJpZXNcbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgZ2V0VG9vbHRpcFBvc2l0aW9uKFxuICAgICAgICBkYXRhUG9pbnQ6IElEYXRhUG9pbnQsXG4gICAgICAgIGNoYXJ0U2VyaWVzOiBJQ2hhcnRTZXJpZXM8SUFjY2Vzc29ycz5cbiAgICApOiBJVG9vbHRpcFBvc2l0aW9uIHtcbiAgICAgICAgaWYgKCFkYXRhUG9pbnQucG9zaXRpb24pIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlVuYWJsZSB0byBnZXQgdG9vbHRpcCBwb3NpdGlvblwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB4OiBkYXRhUG9pbnQucG9zaXRpb24ueCxcbiAgICAgICAgICAgIHk6IGRhdGFQb2ludC5wb3NpdGlvbi55LFxuICAgICAgICAgICAgaGVpZ2h0OiBkYXRhUG9pbnQucG9zaXRpb24/LmhlaWdodCB8fCAxLFxuICAgICAgICAgICAgd2lkdGg6IGRhdGFQb2ludC5wb3NpdGlvbj8ud2lkdGggfHwgMSxcbiAgICAgICAgICAgIG92ZXJsYXlQb3NpdGlvbnM6IHRoaXMub3ZlcmxheVNldHVwLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENvbnZlcnRzIHRoZSByZWxhdGl2ZSBwb3NpdGlvbiB3aXRoaW4gYSBjaGFydCBpbnRvIGFuIGFic29sdXRlIHBvc2l0aW9uIG9uIHRoZSBzY3JlZW5cbiAgICAgKlxuICAgICAqIEBwYXJhbSByZWxhdGl2ZVBvc2l0aW9uXG4gICAgICogQHBhcmFtIGNoYXJ0UG9zaXRpb25cbiAgICAgKi9cbiAgICBwcm90ZWN0ZWQgZ2V0QWJzb2x1dGVQb3NpdGlvbihcbiAgICAgICAgcmVsYXRpdmVQb3NpdGlvbjogSVRvb2x0aXBQb3NpdGlvbixcbiAgICAgICAgY2hhcnRQb3NpdGlvbjogSVBvc2l0aW9uXG4gICAgKTogSVRvb2x0aXBQb3NpdGlvbiB7XG4gICAgICAgIHJldHVybiBPYmplY3QuYXNzaWduKHt9LCByZWxhdGl2ZVBvc2l0aW9uLCB7XG4gICAgICAgICAgICB4OlxuICAgICAgICAgICAgICAgIGNoYXJ0UG9zaXRpb24ueCArXG4gICAgICAgICAgICAgICAgdGhpcy5jaGFydC5nZXRHcmlkKCkuY29uZmlnKCkuZGltZW5zaW9uLm1hcmdpbi5sZWZ0ICtcbiAgICAgICAgICAgICAgICByZWxhdGl2ZVBvc2l0aW9uLngsXG4gICAgICAgICAgICB5OlxuICAgICAgICAgICAgICAgIGNoYXJ0UG9zaXRpb24ueSArXG4gICAgICAgICAgICAgICAgdGhpcy5jaGFydC5nZXRHcmlkKCkuY29uZmlnKCkuZGltZW5zaW9uLm1hcmdpbi50b3AgK1xuICAgICAgICAgICAgICAgIHJlbGF0aXZlUG9zaXRpb24ueSxcbiAgICAgICAgfSk7XG4gICAgfVxufVxuIl19