@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
149 lines • 25.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 { UtilService } from "@nova-ui/bits";
import { DATA_POINT_INTERACTION_RESET, INTERACTION_DATA_POINT_EVENT, } from "../constants";
import { DEFAULT_MARKER_INTERACTION_CONFIG } from "./constants";
import { isInRange } from "../core/common/scales/helpers/is-in-range";
import { InteractionType, } from "../core/common/types";
export class MarkerUtils {
/** The default class for the marker's container */
static DEFAULT_MARKER_CONTAINER_CLASS = "marker";
/** The class used for the marker's svg path */
static MARKER_PATH_CLASS = "marker-path";
/**
* This method impersonates marker related logic used in various renderers
*
* @param dataSeries
* @param scales
* @param dataPointIndex
* @param container
* @param rendererSubject
*/
static manageMarker(dataSeries, scales, dataPointIndex, container, rendererSubject, markerInteractionConfig = DEFAULT_MARKER_INTERACTION_CONFIG) {
if (!container) {
throw new Error("Container doesn't exist!");
}
if (dataSeries.data.length === 0) {
MarkerUtils.removeMarker(container);
return;
}
const accessors = dataSeries.accessors;
if (dataPointIndex < 0) {
dataPointIndex = dataSeries.data.length - 1;
}
const dataPoint = dataSeries.data[dataPointIndex];
if (!accessors.data?.x || !accessors.data.y) {
throw new Error("Color or marker are undefined");
}
const x = scales.x.convert(accessors.data.x(dataPoint, dataPointIndex, dataSeries.data, dataSeries));
const y = scales.y.convert(accessors.data.y(dataPoint, dataPointIndex, dataSeries.data, dataSeries));
if (typeof x !== "undefined" &&
typeof y !== "undefined" &&
isInRange(scales.x, x) &&
isInRange(scales.y, y)) {
const seriesId = dataSeries.id;
const dataPointInfo = {
index: dataPointIndex,
data: dataPoint,
seriesId: seriesId,
position: { x, y },
dataSeries,
};
if (!accessors.series?.marker || !accessors.series?.color) {
throw new Error("Color or marker are undefined");
}
MarkerUtils.drawMarker(dataPointInfo, accessors.series.marker(seriesId, dataSeries), accessors.series.color(seriesId, dataSeries), container, rendererSubject, MarkerUtils.DEFAULT_MARKER_CONTAINER_CLASS, markerInteractionConfig);
}
else {
MarkerUtils.removeMarker(container);
}
}
static drawMarker(dataPoint, marker, color, target, dataPointSubject, className = MarkerUtils.DEFAULT_MARKER_CONTAINER_CLASS, markerInteractionConfig = DEFAULT_MARKER_INTERACTION_CONFIG) {
let markerTarget = target.select(`g.${className}`);
const xCoord = dataPoint?.position?.x;
const yCoord = dataPoint?.position?.y;
const attrs = {
transform: `translate(${xCoord}, ${yCoord})`,
cursor: "crosshair",
};
const getPointerEventsClass = () => `${markerInteractionConfig.enabled ? " pointer-events" : ""}`;
const getPointerEventsClickClass = () => `${markerInteractionConfig.enabled &&
markerInteractionConfig.clickable
? " pointer-events-click"
: ""}`;
if (markerTarget.empty()) {
markerTarget = target
.append("g")
.classed(`${className}${getPointerEventsClass()}${getPointerEventsClickClass()}`, true);
}
marker.setColor(color);
markerTarget.attrs(attrs);
markerTarget.on("mouseenter", () => {
dataPointSubject.next({
eventName: INTERACTION_DATA_POINT_EVENT,
data: { interactionType: InteractionType.Hover, dataPoint },
});
});
markerTarget.on("mouseleave", () => {
dataPointSubject.next({
eventName: INTERACTION_DATA_POINT_EVENT,
data: {
interactionType: InteractionType.Hover,
dataPoint: {
...dataPoint,
index: DATA_POINT_INTERACTION_RESET,
},
},
});
});
markerTarget.on("click", () => {
dataPointSubject.next({
eventName: INTERACTION_DATA_POINT_EVENT,
data: { interactionType: InteractionType.Click, dataPoint },
});
});
if (!markerTarget
.selectAll("g > *")
.size() &&
markerTarget.node()) {
markerTarget
.node()
?.appendChild(UtilService.getSvgFromString(marker.getSvg()));
markerTarget
.select("path")
.classed(MarkerUtils.MARKER_PATH_CLASS, true);
}
const path = markerTarget
.select("path")
.node();
if (path && markerInteractionConfig.enabled) {
// Hack to accommodate existing Firefox hack in MouseInteractiveArea
const pathRect = path.getBoundingClientRect();
// 'x' in this case represents the absolute position of the left side of the marker
path.setAttribute("x", Math.ceil(dataPoint?.position?.x - pathRect.width / 2).toString());
// 'y' in this case represents the absolute position of the top side of the marker
path.setAttribute("y", Math.ceil(dataPoint?.position?.y - pathRect.height / 2).toString());
}
}
static removeMarker(target, className = MarkerUtils.DEFAULT_MARKER_CONTAINER_CLASS) {
target.select(`g.${className}`).remove();
}
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFya2VyLXV0aWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JlbmRlcmVycy9tYXJrZXItdXRpbHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEseURBQXlEO0FBQ3pELEVBQUU7QUFDRiwrRUFBK0U7QUFDL0UsNEVBQTRFO0FBQzVFLDhFQUE4RTtBQUM5RSwrRUFBK0U7QUFDL0UsOEVBQThFO0FBQzlFLDREQUE0RDtBQUM1RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLHVEQUF1RDtBQUN2RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLDRFQUE0RTtBQUM1RSwrRUFBK0U7QUFDL0UsMEVBQTBFO0FBQzFFLGlGQUFpRjtBQUNqRiw2RUFBNkU7QUFDN0UsaUJBQWlCO0FBSWpCLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFNUMsT0FBTyxFQUNILDRCQUE0QixFQUM1Qiw0QkFBNEIsR0FDL0IsTUFBTSxjQUFjLENBQUM7QUFDdEIsT0FBTyxFQUFFLGlDQUFpQyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ2hFLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSwyQ0FBMkMsQ0FBQztBQUV0RSxPQUFPLEVBT0gsZUFBZSxHQUVsQixNQUFNLHNCQUFzQixDQUFDO0FBRTlCLE1BQU0sT0FBTyxXQUFXO0lBQ3BCLG1EQUFtRDtJQUM1QyxNQUFNLENBQVUsOEJBQThCLEdBQUcsUUFBUSxDQUFDO0lBRWpFLCtDQUErQztJQUN4QyxNQUFNLENBQVUsaUJBQWlCLEdBQUcsYUFBYSxDQUFDO0lBRXpEOzs7Ozs7OztPQVFHO0lBQ0ksTUFBTSxDQUFDLFlBQVksQ0FDdEIsVUFBbUMsRUFDbkMsTUFBaUIsRUFDakIsY0FBc0IsRUFDdEIsU0FBbUMsRUFDbkMsZUFBK0MsRUFDL0MsdUJBQXVCLEdBQUcsaUNBQWlDO1FBRTNELElBQUksQ0FBQyxTQUFTLEVBQUU7WUFDWixNQUFNLElBQUksS0FBSyxDQUFDLDBCQUEwQixD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QUFDLENBQzFELENBQUMsUUFBUSxFQUFFLENBQ2YsQ0FBQztZQUNGLGtGQUFrRjtZQUNsRixJQUFJLENBQUMsWUFBWSxDQUNiLEdBQUcsRUFDSCxJQUFJLENBQUMsSUFBSSxDQUNKLFNBQVMsRUFBRSxRQUFRLEVBQUUsQ0FBWSxHQUFHLFFBQVEsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUMzRCxDQUFDLFFBQVEsRUFBRSxDQUNmLENBQUM7U0FDTDtJQUNMLENBQUM7SUFFTSxNQUFNLENBQUMsWUFBWSxDQUN0QixNQUFnQyxFQUNoQyxZQUFvQixXQUFXLENBQUMsOEJBQThCO1FBRTlELE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBSyxTQUFTLEVBQUUsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQzdDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyDCqSAyMDIyIFNvbGFyV2luZHMgV29ybGR3aWRlLCBMTEMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvXG4vLyAgZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGVcbi8vICByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Jcbi8vICBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vICBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gXCJyeGpzXCI7XG5cbmltcG9ydCB7IFV0aWxTZXJ2aWNlIH0gZnJvbSBcIkBub3ZhLXVpL2JpdHNcIjtcblxuaW1wb3J0IHtcbiAgICBEQVRBX1BPSU5UX0lOVEVSQUNUSU9OX1JFU0VULFxuICAgIElOVEVSQUNUSU9OX0RBVEFfUE9JTlRfRVZFTlQsXG59IGZyb20gXCIuLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IERFRkFVTFRfTUFSS0VSX0lOVEVSQUNUSU9OX0NPTkZJRyB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgaXNJblJhbmdlIH0gZnJvbSBcIi4uL2NvcmUvY29tbW9uL3NjYWxlcy9oZWxwZXJzL2lzLWluLXJhbmdlXCI7XG5pbXBvcnQgeyBJWFlTY2FsZXMgfSBmcm9tIFwiLi4vY29yZS9jb21tb24vc2NhbGVzL3R5cGVzXCI7XG5pbXBvcnQge1xuICAgIEQzU2VsZWN0aW9uLFxuICAgIElBY2Nlc3NvcnMsXG4gICAgSUNoYXJ0TWFya2VyLFxuICAgIElEYXRhUG9pbnQsXG4gICAgSURhdGFTZXJpZXMsXG4gICAgSUludGVyYWN0aW9uRGF0YVBvaW50RXZlbnQsXG4gICAgSW50ZXJhY3Rpb25UeXBlLFxuICAgIElSZW5kZXJlckV2ZW50UGF5bG9hZCxcbn0gZnJvbSBcIi4uL2NvcmUvY29tbW9uL3R5cGVzXCI7XG5cbmV4cG9ydCBjbGFzcyBNYXJrZXJVdGlscyB7XG4gICAgLyoqIFRoZSBkZWZhdWx0IGNsYXNzIGZvciB0aGUgbWFya2VyJ3MgY29udGFpbmVyICovXG4gICAgcHVibGljIHN0YXRpYyByZWFkb25seSBERUZBVUxUX01BUktFUl9DT05UQUlORVJfQ0xBU1MgPSBcIm1hcmtlclwiO1xuXG4gICAgLyoqIFRoZSBjbGFzcyB1c2VkIGZvciB0aGUgbWFya2VyJ3Mgc3ZnIHBhdGggKi9cbiAgICBwdWJsaWMgc3RhdGljIHJlYWRvbmx5IE1BUktFUl9QQVRIX0NMQVNTID0gXCJtYXJrZXItcGF0aFwiO1xuXG4gICAgLyoqXG4gICAgICogVGhpcyBtZXRob2QgaW1wZXJzb25hdGVzIG1hcmtlciByZWxhdGVkIGxvZ2ljIHVzZWQgaW4gdmFyaW91cyByZW5kZXJlcnNcbiAgICAgKlxuICAgICAqIEBwYXJhbSBkYXRhU2VyaWVzXG4gICAgICogQHBhcmFtIHNjYWxlc1xuICAgICAqIEBwYXJhbSBkYXRhUG9pbnRJbmRleFxuICAgICAqIEBwYXJhbSBjb250YWluZXJcbiAgICAgKiBAcGFyYW0gcmVuZGVyZXJTdWJqZWN0XG4gICAgICovXG4gICAgcHVibGljIHN0YXRpYyBtYW5hZ2VNYXJrZXIoXG4gICAgICAgIGRhdGFTZXJpZXM6IElEYXRhU2VyaWVzPElBY2Nlc3NvcnM+LFxuICAgICAgICBzY2FsZXM6IElYWVNjYWxlcyxcbiAgICAgICAgZGF0YVBvaW50SW5kZXg6IG51bWJlcixcbiAgICAgICAgY29udGFpbmVyOiBEM1NlbGVjdGlvbjxTVkdHRWxlbWVudD4sXG4gICAgICAgIHJlbmRlcmVyU3ViamVjdDogU3ViamVjdDxJUmVuZGVyZXJFdmVudFBheWxvYWQ+LFxuICAgICAgICBtYXJrZXJJbnRlcmFjdGlvbkNvbmZpZyA9IERFRkFVTFRfTUFSS0VSX0lOVEVSQUNUSU9OX0NPTkZJR1xuICAgICk6IHZvaWQge1xuICAgICAgICBpZiAoIWNvbnRhaW5lcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29udGFpbmVyIGRvZXNuJ3QgZXhpc3QhXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGRhdGFTZXJpZXMuZGF0YS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIE1hcmtlclV0aWxzLnJlbW92ZU1hcmtlcihjb250YWluZXIpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgYWNjZXNzb3JzID0gZGF0YVNlcmllcy5hY2Nlc3NvcnM7XG5cbiAgICAgICAgaWYgKGRhdGFQb2ludEluZGV4IDwgMCkge1xuICAgICAgICAgICAgZGF0YVBvaW50SW5kZXggPSBkYXRhU2VyaWVzLmRhdGEubGVuZ3RoIC0gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRhdGFQb2ludCA9IGRhdGFTZXJpZXMuZGF0YVtkYXRhUG9pbnRJbmRleF07XG5cbiAgICAgICAgaWYgKCFhY2Nlc3NvcnMuZGF0YT8ueCB8fCAhYWNjZXNzb3JzLmRhdGEueSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29sb3Igb3IgbWFya2VyIGFyZSB1bmRlZmluZWRcIik7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB4ID0gc2NhbGVzLnguY29udmVydChcbiAgICAgICAgICAgIGFjY2Vzc29ycy5kYXRhLngoXG4gICAgICAgICAgICAgICAgZGF0YVBvaW50LFxuICAgICAgICAgICAgICAgIGRhdGFQb2ludEluZGV4LFxuICAgICAgICAgICAgICAgIGRhdGFTZXJpZXMuZGF0YSxcbiAgICAgICAgICAgICAgICBkYXRhU2VyaWVzXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IHkgPSBzY2FsZXMueS5jb252ZXJ0KFxuICAgICAgICAgICAgYWNjZXNzb3JzLmRhdGEueShcbiAgICAgICAgICAgICAgICBkYXRhUG9pbnQsXG4gICAgICAgICAgICAgICAgZGF0YVBvaW50SW5kZXgsXG4gICAgICAgICAgICAgICAgZGF0YVNlcmllcy5kYXRhLFxuICAgICAgICAgICAgICAgIGRhdGFTZXJpZXNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoXG4gICAgICAgICAgICB0eXBlb2YgeCAhPT0gXCJ1bmRlZmluZWRcIiAmJlxuICAgICAgICAgICAgdHlwZW9mIHkgIT09IFwidW5kZWZpbmVkXCIgJiZcbiAgICAgICAgICAgIGlzSW5SYW5nZShzY2FsZXMueCwgeCkgJiZcbiAgICAgICAgICAgIGlzSW5SYW5nZShzY2FsZXMueSwgeSlcbiAgICAgICAgKSB7XG4gICAgICAgICAgICBjb25zdCBzZXJpZXNJZCA9IGRhdGFTZXJpZXMuaWQ7XG4gICAgICAgICAgICBjb25zdCBkYXRhUG9pbnRJbmZvOiBJRGF0YVBvaW50ID0ge1xuICAgICAgICAgICAgICAgIGluZGV4OiBkYXRhUG9pbnRJbmRleCxcbiAgICAgICAgICAgICAgICBkYXRhOiBkYXRhUG9pbnQsXG4gICAgICAgICAgICAgICAgc2VyaWVzSWQ6IHNlcmllc0lkLFxuICAgICAgICAgICAgICAgIHBvc2l0aW9uOiB7IHgsIHkgfSxcbiAgICAgICAgICAgICAgICBkYXRhU2VyaWVzLFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgaWYgKCFhY2Nlc3NvcnMuc2VyaWVzPy5tYXJrZXIgfHwgIWFjY2Vzc29ycy5zZXJpZXM/LmNvbG9yKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29sb3Igb3IgbWFya2VyIGFyZSB1bmRlZmluZWRcIik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIE1hcmtlclV0aWxzLmRyYXdNYXJrZXIoXG4gICAgICAgICAgICAgICAgZGF0YVBvaW50SW5mbyxcbiAgICAgICAgICAgICAgICBhY2Nlc3NvcnMuc2VyaWVzLm1hcmtlcihzZXJpZXNJZCwgZGF0YVNlcmllcyksXG4gICAgICAgICAgICAgICAgYWNjZXNzb3JzLnNlcmllcy5jb2xvcihzZXJpZXNJZCwgZGF0YVNlcmllcyksXG4gICAgICAgICAgICAgICAgY29udGFpbmVyLFxuICAgICAgICAgICAgICAgIHJlbmRlcmVyU3ViamVjdCxcbiAgICAgICAgICAgICAgICBNYXJrZXJVdGlscy5ERUZBVUxUX01BUktFUl9DT05UQUlORVJfQ0xBU1MsXG4gICAgICAgICAgICAgICAgbWFya2VySW50ZXJhY3Rpb25Db25maWdcbiAgICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBNYXJrZXJVdGlscy5yZW1vdmVNYXJrZXIoY29udGFpbmVyKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgZHJhd01hcmtlcihcbiAgICAgICAgZGF0YVBvaW50OiBJRGF0YVBvaW50LFxuICAgICAgICBtYXJrZXI6IElDaGFydE1hcmtlcixcbiAgICAgICAgY29sb3I6IHN0cmluZyxcbiAgICAgICAgdGFyZ2V0OiBEM1NlbGVjdGlvbjxTVkdHRWxlbWVudD4sXG4gICAgICAgIGRhdGFQb2ludFN1YmplY3Q6IFN1YmplY3Q8XG4gICAgICAgICAgICBJUmVuZGVyZXJFdmVudFBheWxvYWQ8SUludGVyYWN0aW9uRGF0YVBvaW50RXZlbnQ+XG4gICAgICAgID4sXG4gICAgICAgIGNsYXNzTmFtZTogc3RyaW5nID0gTWFya2VyVXRpbHMuREVGQVVMVF9NQVJLRVJfQ09OVEFJTkVSX0NMQVNTLFxuICAgICAgICBtYXJrZXJJbnRlcmFjdGlvbkNvbmZpZyA9IERFRkFVTFRfTUFSS0VSX0lOVEVSQUNUSU9OX0NPTkZJR1xuICAgICk6IHZvaWQge1xuICAgICAgICBsZXQgbWFya2VyVGFyZ2V0OiBEM1NlbGVjdGlvbiB8IEQzU2VsZWN0aW9uPFNWR0dFbGVtZW50PiA9XG4gICAgICAgICAgICB0YXJnZXQuc2VsZWN0KGBnLiR7Y2xhc3NOYW1lfWApO1xuICAgICAgICBjb25zdCB4Q29vcmQgPSBkYXRhUG9pbnQ/LnBvc2l0aW9uPy54O1xuICAgICAgICBjb25zdCB5Q29vcmQgPSBkYXRhUG9pbnQ/LnBvc2l0aW9uPy55O1xuICAgICAgICBjb25zdCBhdHRycyA9IHtcbiAgICAgICAgICAgIHRyYW5zZm9ybTogYHRyYW5zbGF0ZSgke3hDb29yZH0sICR7eUNvb3JkfSlgLFxuICAgICAgICAgICAgY3Vyc29yOiBcImNyb3NzaGFpclwiLFxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGdldFBvaW50ZXJFdmVudHNDbGFzcyA9ICgpID0+XG4gICAgICAgICAgICBgJHttYXJrZXJJbnRlcmFjdGlvbkNvbmZpZy5lbmFibGVkID8gXCIgcG9pbnRlci1ldmVudHNcIiA6IFwiXCJ9YDtcbiAgICAgICAgY29uc3QgZ2V0UG9pbnRlckV2ZW50c0NsaWNrQ2xhc3MgPSAoKSA9PlxuICAgICAgICAgICAgYCR7XG4gICAgICAgICAgICAgICAgbWFya2VySW50ZXJhY3Rpb25Db25maWcuZW5hYmxlZCAmJlxuICAgICAgICAgICAgICAgIG1hcmtlckludGVyYWN0aW9uQ29uZmlnLmNsaWNrYWJsZVxuICAgICAgICAgICAgICAgICAgICA/IFwiIHBvaW50ZXItZXZlbnRzLWNsaWNrXCJcbiAgICAgICAgICAgICAgICAgICAgOiBcIlwiXG4gICAgICAgICAgICB9YDtcblxuICAgICAgICBpZiAobWFya2VyVGFyZ2V0LmVtcHR5KCkpIHtcbiAgICAgICAgICAgIG1hcmtlclRhcmdldCA9IHRhcmdldFxuICAgICAgICAgICAgICAgIC5hcHBlbmQoXCJnXCIpXG4gICAgICAgICAgICAgICAgLmNsYXNzZWQoXG4gICAgICAgICAgICAgICAgICAgIGAke2NsYXNzTmFtZX0ke2dldFBvaW50ZXJFdmVudHNDbGFzcygpfSR7Z2V0UG9pbnRlckV2ZW50c0NsaWNrQ2xhc3MoKX1gLFxuICAgICAgICAgICAgICAgICAgICB0cnVlXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIG1hcmtlci5zZXRDb2xvcihjb2xvcik7XG4gICAgICAgIG1hcmtlclRhcmdldC5hdHRycyhhdHRycyk7XG5cbiAgICAgICAgbWFya2VyVGFyZ2V0Lm9uKFwibW91c2VlbnRlclwiLCAoKSA9PiB7XG4gICAgICAgICAgICBkYXRhUG9pbnRTdWJqZWN0Lm5leHQoe1xuICAgICAgICAgICAgICAgIGV2ZW50TmFtZTogSU5URVJBQ1RJT05fREFUQV9QT0lOVF9FVkVOVCxcbiAgICAgICAgICAgICAgICBkYXRhOiB7IGludGVyYWN0aW9uVHlwZTogSW50ZXJhY3Rpb25UeXBlLkhvdmVyLCBkYXRhUG9pbnQgfSxcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgbWFya2VyVGFyZ2V0Lm9uKFwibW91c2VsZWF2ZVwiLCAoKSA9PiB7XG4gICAgICAgICAgICBkYXRhUG9pbnRTdWJqZWN0Lm5leHQoe1xuICAgICAgICAgICAgICAgIGV2ZW50TmFtZTogSU5URVJBQ1RJT05fREFUQV9QT0lOVF9FVkVOVCxcbiAgICAgICAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICAgICAgICAgIGludGVyYWN0aW9uVHlwZTogSW50ZXJhY3Rpb25UeXBlLkhvdmVyLFxuICAgICAgICAgICAgICAgICAgICBkYXRhUG9pbnQ6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLmRhdGFQb2ludCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGluZGV4OiBEQVRBX1BPSU5UX0lOVEVSQUNUSU9OX1JFU0VULFxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIG1hcmtlclRhcmdldC5vbihcImNsaWNrXCIsICgpID0+IHtcbiAgICAgICAgICAgIGRhdGFQb2ludFN1YmplY3QubmV4dCh7XG4gICAgICAgICAgICAgICAgZXZlbnROYW1lOiBJTlRFUkFDVElPTl9EQVRBX1BPSU5UX0VWRU5ULFxuICAgICAgICAgICAgICAgIGRhdGE6IHsgaW50ZXJhY3Rpb25UeXBlOiBJbnRlcmFjdGlvblR5cGUuQ2xpY2ssIGRhdGFQb2ludCB9LFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmIChcbiAgICAgICAgICAgICEoPEQzU2VsZWN0aW9uPFNWR0dFbGVtZW50Pj5tYXJrZXJUYXJnZXQpXG4gICAgICAgICAgICAgICAgLnNlbGVjdEFsbChcImcgPiAqXCIpXG4gICAgICAgICAgICAgICAgLnNpemUoKSAmJlxuICAgICAgICAgICAgbWFya2VyVGFyZ2V0Lm5vZGUoKVxuICAgICAgICApIHtcbiAgICAgICAgICAgIG1hcmtlclRhcmdldFxuICAgICAgICAgICAgICAgIC5ub2RlKClcbiAgICAgICAgICAgICAgICA/LmFwcGVuZENoaWxkKFV0aWxTZXJ2aWNlLmdldFN2Z0Zyb21TdHJpbmcobWFya2VyLmdldFN2ZygpKSk7XG4gICAgICAgICAgICAoPEQzU2VsZWN0aW9uPFNWR0dFbGVtZW50Pj5tYXJrZXJUYXJnZXQpXG4gICAgICAgICAgICAgICAgLnNlbGVjdChcInBhdGhcIilcbiAgICAgICAgICAgICAgICAuY2xhc3NlZChNYXJrZXJVdGlscy5NQVJLRVJfUEFUSF9DTEFTUywgdHJ1ZSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBwYXRoID0gKDxEM1NlbGVjdGlvbjxTVkdHRWxlbWVudD4+bWFya2VyVGFyZ2V0KVxuICAgICAgICAgICAgLnNlbGVjdChcInBhdGhcIilcbiAgICAgICAgICAgIC5ub2RlKCkgYXMgSFRNTEVsZW1lbnQ7XG4gICAgICAgIGlmIChwYXRoICYmIG1hcmtlckludGVyYWN0aW9uQ29uZmlnLmVuYWJsZWQpIHtcbiAgICAgICAgICAgIC8vIEhhY2sgdG8gYWNjb21tb2RhdGUgZXhpc3RpbmcgRmlyZWZveCBoYWNrIGluIE1vdXNlSW50ZXJhY3RpdmVBcmVhXG4gICAgICAgICAgICBjb25zdCBwYXRoUmVjdCA9IHBhdGguZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgICAgICAvLyAneCcgaW4gdGhpcyBjYXNlIHJlcHJlc2VudHMgdGhlIGFic29sdXRlIHBvc2l0aW9uIG9mIHRoZSBsZWZ0IHNpZGUgb2YgdGhlIG1hcmtlclxuICAgICAgICAgICAgcGF0aC5zZXRBdHRyaWJ1dGUoXG4gICAgICAgICAgICAgICAgXCJ4XCIsXG4gICAgICAgICAgICAgICAgTWF0aC5jZWlsKFxuICAgICAgICAgICAgICAgICAgICAoZGF0YVBvaW50Py5wb3NpdGlvbj8ueCBhcyBudW1iZXIpIC0gcGF0aFJlY3Qud2lkdGggLyAyXG4gICAgICAgICAgICAgICAgKS50b1N0cmluZygpXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgLy8gJ3knIGluIHRoaXMgY2FzZSByZXByZXNlbnRzIHRoZSBhYnNvbHV0ZSBwb3NpdGlvbiBvZiB0aGUgdG9wIHNpZGUgb2YgdGhlIG1hcmtlclxuICAgICAgICAgICAgcGF0aC5zZXRBdHRyaWJ1dGUoXG4gICAgICAgICAgICAgICAgXCJ5XCIsXG4gICAgICAgICAgICAgICAgTWF0aC5jZWlsKFxuICAgICAgICAgICAgICAgICAgICAoZGF0YVBvaW50Py5wb3NpdGlvbj8ueSBhcyBudW1iZXIpIC0gcGF0aFJlY3QuaGVpZ2h0IC8gMlxuICAgICAgICAgICAgICAgICkudG9TdHJpbmcoKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgcmVtb3ZlTWFya2VyKFxuICAgICAgICB0YXJnZXQ6IEQzU2VsZWN0aW9uPFNWR0dFbGVtZW50PixcbiAgICAgICAgY2xhc3NOYW1lOiBzdHJpbmcgPSBNYXJrZXJVdGlscy5ERUZBVUxUX01BUktFUl9DT05UQUlORVJfQ0xBU1NcbiAgICApOiB2b2lkIHtcbiAgICAgICAgdGFyZ2V0LnNlbGVjdChgZy4ke2NsYXNzTmFtZX1gKS5yZW1vdmUoKTtcbiAgICB9XG59XG4iXX0=