UNPKG

@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

211 lines 35.9 kB
// © 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 { curveLinear, line } from "d3-shape"; import defaultsDeep from "lodash/defaultsDeep"; import { STANDARD_RENDER_LAYERS } from "../../constants"; import { DEFAULT_MARKER_INTERACTION_CONFIG } from "../constants"; import { MarkerUtils } from "../marker-utils"; import { RenderLayerName } from "../types"; import { XYRenderer } from "../xy-renderer"; /** * Renderer that is able to draw line chart */ export class LineRenderer extends XYRenderer { config; static UNCLIPPED_DATA_LAYER_NAME = "unclipped-data"; static LINE_CAP_CLASS_NAME = "nui-chart-line-cap"; static getStrokeStyleDashed(width) { const dash = width * 2; return `${dash},${dash}`; } static getStrokeStyleDotted(width) { return `${width},${width}`; } DEFAULT_CONFIG = { strokeWidth: 2, curveType: curveLinear, interactive: true, strokeStyle: "", strokeLinecap: "round", markerInteraction: DEFAULT_MARKER_INTERACTION_CONFIG, useEnhancedLineCaps: false, enhancedLineCap: { radius: 3, }, }; /** * Creates an instance of LineRenderer. * @param {ILineRendererConfig} [config={}] Renderer configuration object */ constructor(config = {}) { super(config); this.config = config; // setting default values to the properties that were not set by user this.config = defaultsDeep(this.config, this.DEFAULT_CONFIG); } /** See {@link Renderer#draw} */ draw(renderSeries, rendererSubject) { const target = renderSeries.containers[RenderLayerName.data]; const strokeValue = renderSeries.dataSeries.accessors.series.color?.(renderSeries.dataSeries.id, renderSeries.dataSeries); let path = target.select("path.main"); if (path.empty()) { path = target .append("path") .classed("main", true) // Assigning null value to match ValueMap<GElement, Datum> D3's signature .attrs({ stroke: strokeValue ?? null, "stroke-width": this.config.strokeWidth ?? null, "stroke-dasharray": this.config.strokeStyle ?? null, "stroke-linecap": this.config.strokeLinecap ?? null, fill: "none", }); } this.drawLine(renderSeries, path); if (this.config.interactionStrategy) { this.config.interactionStrategy.draw(this, renderSeries, rendererSubject); } } /** * When the data contains only one data point with undefined 'x' value, it is considered an infinite line and special approach is applied * * @param renderSeries */ isInfiniteLineData(renderSeries) { const dataSeries = renderSeries.dataSeries; return (dataSeries.data.length === 1 && typeof dataSeries.accessors.data.x(dataSeries.data[0], 0, dataSeries.data, dataSeries) === "undefined"); } /** * Renders the line in prepared <path> element * * @param {IRenderSeries<ILineAccessors>} renderSeries * @param {D3Selection} path D3 Selection with <path> element pre-created and pre-styled */ drawLine(renderSeries, path) { if (this.isInfiniteLineData(renderSeries)) { this.drawInfiniteLine(renderSeries, path); } else { this.drawStandardLine(renderSeries, path); } } /** See {@link Renderer#highlightDataPoint} */ highlightDataPoint(renderSeries, dataPointIndex, rendererSubject) { if (!this.config.interactive) { return; } const dataSeries = renderSeries.dataSeries; const accessors = dataSeries.accessors; if (!accessors.series.marker) { return; } MarkerUtils.manageMarker(dataSeries, renderSeries.scales, dataPointIndex, renderSeries.containers[RenderLayerName.foreground], rendererSubject, this.config.markerInteraction); } /** See {@link Renderer#getRequiredLayers} */ getRequiredLayers() { return [ STANDARD_RENDER_LAYERS[RenderLayerName.data], STANDARD_RENDER_LAYERS[RenderLayerName.foreground], STANDARD_RENDER_LAYERS[RenderLayerName.unclippedData], ]; } /** See {@link Renderer#getDataPointPosition} */ getDataPointPosition(dataSeries, index, scales) { // TODO: consider including size of the marker once we have them rendered as symbols return super.getDataPointPosition(dataSeries, index, scales); } drawStandardLine(renderSeries, path) { const dataSeries = renderSeries.dataSeries; const accessors = dataSeries.accessors; let warned = false; const validatedData = dataSeries.data.filter((d, i) => { const valid = typeof accessors.data.x(d, i, dataSeries.data, dataSeries) !== "undefined" && typeof accessors.data.y(d, i, dataSeries.data, dataSeries) !== "undefined"; if (!valid && !warned) { console.warn("Data point", d, "was skipped as accessors didn't manage to extract any data."); console.warn(" -> accessors.data.x:", accessors.data.x); console.warn(" -> accessors.data.y:", accessors.data.y); warned = true; } return valid; }); if (!this.config.curveType) { throw new Error("curveType is not defined"); } const lineFunc = line() .x((d, i) => renderSeries.scales.x.convert(accessors.data.x(d, i, dataSeries.data, dataSeries))) .y((d, i) => renderSeries.scales.y.convert(accessors.data.y(d, i, dataSeries.data, dataSeries))) .defined((d, i) => accessors.data.defined ? accessors.data.defined(d, i, dataSeries.data, dataSeries) : true) .curve(this.config.curveType); path.attr("d", lineFunc(validatedData) ?? ""); if (this.config.useEnhancedLineCaps) { this.updateLineCaps(validatedData, renderSeries, this.config.enhancedLineCap?.fill || path.attr("stroke")); } } drawInfiniteLine(renderSeries, path) { const dataSeries = renderSeries.dataSeries; const accessors = dataSeries.accessors; const y = renderSeries.scales.y.convert(accessors.data.y(dataSeries.data[0], 0, dataSeries.data, dataSeries)); const data = [ [renderSeries.scales.x.range()[0], y], [renderSeries.scales.x.range()[1], y], ]; const lineFunc = line() .x((d) => d[0]) .y((d) => d[1]); const result = lineFunc(data); if (!result) { throw new Error("Line cannot be computed"); } path.attr("shape-rendering", "crispEdges").attr("d", result); } updateLineCaps(validatedData, renderSeries, fill) { const dataSeries = renderSeries.dataSeries; const accessors = dataSeries.accessors; const definedData = validatedData.filter((d, i) => accessors?.data?.defined ? accessors?.data?.defined(d, i, dataSeries.data, dataSeries) : true); const updateCx = (d, i) => renderSeries.scales.x.convert(accessors.data.x(d, i, dataSeries.data, dataSeries)); const updateCy = (d, i) => renderSeries.scales.y.convert(accessors.data.y(d, i, dataSeries.data, dataSeries)); // use an unclipped layer to ensure the line caps on the left and right sides of the chart don't get clipped const lineCaps = renderSeries.containers[RenderLayerName.unclippedData] .selectAll(`.${LineRenderer.LINE_CAP_CLASS_NAME}`) .data(definedData) .attr("cx", updateCx) .attr("cy", updateCy); lineCaps .enter() .append("circle") .attr("class", LineRenderer.LINE_CAP_CLASS_NAME) .attr("r", this.config.enhancedLineCap?.radius) .attr("cx", updateCx) .attr("cy", updateCy) .style("stroke-width", this.config.enhancedLineCap?.strokeWidth) .style("fill", fill) .style("stroke", this.config.enhancedLineCap?.stroke); lineCaps.exit().remove(); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGluZS1yZW5kZXJlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9yZW5kZXJlcnMvbGluZS9saW5lLXJlbmRlcmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHlEQUF5RDtBQUN6RCxFQUFFO0FBQ0YsK0VBQStFO0FBQy9FLDRFQUE0RTtBQUM1RSw4RUFBOEU7QUFDOUUsK0VBQStFO0FBQy9FLDhFQUE4RTtBQUM5RSw0REFBNEQ7QUFDNUQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSx1REFBdUQ7QUFDdkQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSw0RUFBNEU7QUFDNUUsK0VBQStFO0FBQy9FLDBFQUEwRTtBQUMxRSxpRkFBaUY7QUFDakYsNkVBQTZFO0FBQzdFLGlCQUFpQjtBQUVqQixPQUFPLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUM3QyxPQUFPLFlBQVksTUFBTSxxQkFBcUIsQ0FBQztBQUcvQyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQVN6RCxPQUFPLEVBQUUsaUNBQWlDLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDakUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQzlDLE9BQU8sRUFBc0MsZUFBZSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQy9FLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUc1Qzs7R0FFRztBQUNILE1BQU0sT0FBTyxZQUFhLFNBQVEsVUFBMEI7SUE4QjVCO0lBN0JyQixNQUFNLENBQUMseUJBQXlCLEdBQUcsZ0JBQWdCLENBQUM7SUFDcEQsTUFBTSxDQUFDLG1CQUFtQixHQUFHLG9CQUFvQixDQUFDO0lBRWxELE1BQU0sQ0FBQyxvQkFBb0IsQ0FBQyxLQUFhO1FBQzVDLE1BQU0sSUFBSSxHQUFHLEtBQUssR0FBRyxDQUFDLENBQUM7UUFDdkIsT0FBTyxHQUFHLElB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LFFBQVE7YUFDSCxLQUFLLEVBQUU7YUFDUCxNQUFNLENBQUMsUUFBUSxDQUFDO2FBQ2hCLElBQUksQ0FBQyxPQUFPLEVBQUUsWUFBWSxDQUFDLG1CQUFtQixDQUFDO2FBQy9DLElBQUksQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUUsTUFBZ0IsQ0FBQzthQUN4RCxJQUFJLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQzthQUNwQixJQUFJLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQzthQUNwQixLQUFLLENBQ0YsY0FBYyxFQUNkLElBQUksQ0FBQyxNQUFNLENBQUMsZUFBZSxFQUFFLFdBQXFCLENBQ3JEO2FBQ0EsS0FBSyxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUM7YUFDbkIsS0FBSyxDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLGVBQWUsRUFBRSxNQUFnQixDQUFDLENBQUM7UUFFcEUsUUFBUSxDQUFDLElBQUksRUFBRSxDQUFDLE1BQU0sRUFBRSxDQUFDO0lBQzdCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyDCqSAyMDIyIFNvbGFyV2luZHMgV29ybGR3aWRlLCBMTEMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvXG4vLyAgZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGVcbi8vICByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Jcbi8vICBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vICBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IHsgY3VydmVMaW5lYXIsIGxpbmUgfSBmcm9tIFwiZDMtc2hhcGVcIjtcbmltcG9ydCBkZWZhdWx0c0RlZXAgZnJvbSBcImxvZGFzaC9kZWZhdWx0c0RlZXBcIjtcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tIFwicnhqc1wiO1xuXG5pbXBvcnQgeyBTVEFOREFSRF9SRU5ERVJfTEFZRVJTIH0gZnJvbSBcIi4uLy4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgSVhZU2NhbGVzLCBTY2FsZXMgfSBmcm9tIFwiLi4vLi4vY29yZS9jb21tb24vc2NhbGVzL3R5cGVzXCI7XG5pbXBvcnQge1xuICAgIEQzU2VsZWN0aW9uLFxuICAgIElEYXRhU2VyaWVzLFxuICAgIElMYXNhZ25hTGF5ZXIsXG4gICAgSVBvc2l0aW9uLFxuICAgIElSZW5kZXJlckV2ZW50UGF5bG9hZCxcbn0gZnJvbSBcIi4uLy4uL2NvcmUvY29tbW9uL3R5cGVzXCI7XG5pbXBvcnQgeyBERUZBVUxUX01BUktFUl9JTlRFUkFDVElPTl9DT05GSUcgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBNYXJrZXJVdGlscyB9IGZyb20gXCIuLi9tYXJrZXItdXRpbHNcIjtcbmltcG9ydCB7IElMaW5lUmVuZGVyZXJDb25maWcsIElSZW5kZXJTZXJpZXMsIFJlbmRlckxheWVyTmFtZSB9IGZyb20gXCIuLi90eXBlc1wiO1xuaW1wb3J0IHsgWFlSZW5kZXJlciB9IGZyb20gXCIuLi94eS1yZW5kZXJlclwiO1xuaW1wb3J0IHsgSUxpbmVBY2Nlc3NvcnMgfSBmcm9tIFwiLi9saW5lLWFjY2Vzc29yc1wiO1xuXG4vKipcbiAqIFJlbmRlcmVyIHRoYXQgaXMgYWJsZSB0byBkcmF3IGxpbmUgY2hhcnRcbiAqL1xuZXhwb3J0IGNsYXNzIExpbmVSZW5kZXJlciBleHRlbmRzIFhZUmVuZGVyZXI8SUxpbmVBY2Nlc3NvcnM+IHtcbiAgICBwdWJsaWMgc3RhdGljIFVOQ0xJUFBFRF9EQVRBX0xBWUVSX05BTUUgPSBcInVuY2xpcHBlZC1kYXRhXCI7XG4gICAgcHVibGljIHN0YXRpYyBMSU5FX0NBUF9DTEFTU19OQU1FID0gXCJudWktY2hhcnQtbGluZS1jYXBcIjtcblxuICAgIHB1YmxpYyBzdGF0aWMgZ2V0U3Ryb2tlU3R5bGVEYXNoZWQod2lkdGg6IG51bWJlcik6IHN0cmluZyB7XG4gICAgICAgIGNvbnN0IGRhc2ggPSB3aWR0aCAqIDI7XG4gICAgICAgIHJldHVybiBgJHtkYXNofSwke2Rhc2h9YDtcbiAgICB9XG5cbiAgICBwdWJsaWMgc3RhdGljIGdldFN0cm9rZVN0eWxlRG90dGVkKHdpZHRoOiBudW1iZXIpOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gYCR7d2lkdGh9LCR7d2lkdGh9YDtcbiAgICB9XG5cbiAgICBwcml2YXRlIERFRkFVTFRfQ09ORklHOiBJTGluZVJlbmRlcmVyQ29uZmlnID0ge1xuICAgICAgICBzdHJva2VXaWR0aDogMixcbiAgICAgICAgY3VydmVUeXBlOiBjdXJ2ZUxpbmVhcixcbiAgICAgICAgaW50ZXJhY3RpdmU6IHRydWUsXG4gICAgICAgIHN0cm9rZVN0eWxlOiBcIlwiLFxuICAgICAgICBzdHJva2VMaW5lY2FwOiBcInJvdW5kXCIsXG4gICAgICAgIG1hcmtlckludGVyYWN0aW9uOiBERUZBVUxUX01BUktFUl9JTlRFUkFDVElPTl9DT05GSUcsXG4gICAgICAgIHVzZUVuaGFuY2VkTGluZUNhcHM6IGZhbHNlLFxuICAgICAgICBlbmhhbmNlZExpbmVDYXA6IHtcbiAgICAgICAgICAgIHJhZGl1czogMyxcbiAgICAgICAgfSxcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBMaW5lUmVuZGVyZXIuXG4gICAgICogQHBhcmFtIHtJTGluZVJlbmRlcmVyQ29uZmlnfSBbY29uZmlnPXt9XSBSZW5kZXJlciBjb25maWd1cmF0aW9uIG9iamVjdFxuICAgICAqL1xuICAgIGNvbnN0cnVjdG9yKHB1YmxpYyByZWFkb25seSBjb25maWc6IElMaW5lUmVuZGVyZXJDb25maWcgPSB7fSkge1xuICAgICAgICBzdXBlcihjb25maWcpO1xuICAgICAgICAvLyBzZXR0aW5nIGRlZmF1bHQgdmFsdWVzIHRvIHRoZSBwcm9wZXJ0aWVzIHRoYXQgd2VyZSBub3Qgc2V0IGJ5IHVzZXJcbiAgICAgICAgdGhpcy5jb25maWcgPSBkZWZhdWx0c0RlZXAodGhpcy5jb25maWcsIHRoaXMuREVGQVVMVF9DT05GSUcpO1xuICAgIH1cblxuICAgIC8qKiBTZWUge0BsaW5rIFJlbmRlcmVyI2RyYXd9ICovXG4gICAgcHVibGljIGRyYXcoXG4gICAgICAgIHJlbmRlclNlcmllczogSVJlbmRlclNlcmllczxJTGluZUFjY2Vzc29ycz4sXG4gICAgICAgIHJlbmRlcmVyU3ViamVjdDogU3ViamVjdDxJUmVuZGVyZXJFdmVudFBheWxvYWQ+XG4gICAgKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHRhcmdldCA9IHJlbmRlclNlcmllcy5jb250YWluZXJzW1JlbmRlckxheWVyTmFtZS5kYXRhXTtcblxuICAgICAgICBjb25zdCBzdHJva2VWYWx1ZSA9IHJlbmRlclNlcmllcy5kYXRhU2VyaWVzLmFjY2Vzc29ycy5zZXJpZXMuY29sb3I/LihcbiAgICAgICAgICAgIHJlbmRlclNlcmllcy5kYXRhU2VyaWVzLmlkLFxuICAgICAgICAgICAgcmVuZGVyU2VyaWVzLmRhdGFTZXJpZXNcbiAgICAgICAgKTtcbiAgICAgICAgbGV0IHBhdGg6IEQzU2VsZWN0aW9uPFNWR1BhdGhFbGVtZW50PiA9IHRhcmdldC5zZWxlY3QoXCJwYXRoLm1haW5cIik7XG5cbiAgICAgICAgaWYgKHBhdGguZW1wdHkoKSkge1xuICAgICAgICAgICAgcGF0aCA9IHRhcmdldFxuICAgICAgICAgICAgICAgIC5hcHBlbmQoXCJwYXRoXCIpXG4gICAgICAgICAgICAgICAgLmNsYXNzZWQoXCJtYWluXCIsIHRydWUpXG4gICAgICAgICAgICAgICAgLy8gQXNzaWduaW5nIG51bGwgdmFsdWUgdG8gbWF0Y2ggVmFsdWVNYXA8R0VsZW1lbnQsIERhdHVtPiBEMydzIHNpZ25hdHVyZVxuICAgICAgICAgICAgICAgIC5hdHRycyh7XG4gICAgICAgICAgICAgICAgICAgIHN0cm9rZTogc3Ryb2tlVmFsdWUgPz8gbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgXCJzdHJva2Utd2lkdGhcIjogdGhpcy5jb25maWcuc3Ryb2tlV2lkdGggPz8gbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgXCJzdHJva2UtZGFzaGFycmF5XCI6IHRoaXMuY29uZmlnLnN0cm9rZVN0eWxlID8/IG51bGwsXG4gICAgICAgICAgICAgICAgICAgIFwic3Ryb2tlLWxpbmVjYXBcIjogdGhpcy5jb25maWcuc3Ryb2tlTGluZWNhcCA/PyBudWxsLFxuICAgICAgICAgICAgICAgICAgICBmaWxsOiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmRyYXdMaW5lKHJlbmRlclNlcmllcywgcGF0aCk7XG5cbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmludGVyYWN0aW9uU3RyYXRlZ3kpIHtcbiAgICAgICAgICAgIHRoaXMuY29uZmlnLmludGVyYWN0aW9uU3RyYXRlZ3kuZHJhdyhcbiAgICAgICAgICAgICAgICB0aGlzLFxuICAgICAgICAgICAgICAgIHJlbmRlclNlcmllcyxcbiAgICAgICAgICAgICAgICByZW5kZXJlclN1YmplY3RcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBXaGVuIHRoZSBkYXRhIGNvbnRhaW5zIG9ubHkgb25lIGRhdGEgcG9pbnQgd2l0aCB1bmRlZmluZWQgJ3gnIHZhbHVlLCBpdCBpcyBjb25zaWRlcmVkIGFuIGluZmluaXRlIGxpbmUgYW5kIHNwZWNpYWwgYXBwcm9hY2ggaXMgYXBwbGllZFxuICAgICAqXG4gICAgICogQHBhcmFtIHJlbmRlclNlcmllc1xuICAgICAqL1xuICAgIHB1YmxpYyBpc0luZmluaXRlTGluZURhdGEoXG4gICAgICAgIHJlbmRlclNlcmllczogSVJlbmRlclNlcmllczxJTGluZUFjY2Vzc29ycz5cbiAgICApOiBib29sZWFuIHtcbiAgICAgICAgY29uc3QgZGF0YVNlcmllcyA9IHJlbmRlclNlcmllcy5kYXRhU2VyaWVzO1xuICAgICAgICByZXR1cm4gKFxuICAgICAgICAgICAgZGF0YVNlcmllcy5kYXRhLmxlbmd0aCA9PT0gMSAmJlxuICAgICAgICAgICAgdHlwZW9mIGRhdGFTZXJpZXMuYWNjZXNzb3JzLmRhdGEueChcbiAgICAgICAgICAgICAgICBkYXRhU2VyaWVzLmRhdGFbMF0sXG4gICAgICAgICAgICAgICAgMCxcbiAgICAgICAgICAgICAgICBkYXRhU2VyaWVzLmRhdGEsXG4gICAgICAgICAgICAgICAgZGF0YVNlcmllc1xuICAgICAgICAgICAgKSA9PT0gXCJ1bmRlZmluZWRcIlxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJlbmRlcnMgdGhlIGxpbmUgaW4gcHJlcGFyZWQgPHBhdGg+IGVsZW1lbnRcbiAgICAgKlxuICAgICAqIEBwYXJhbSB7SVJlbmRlclNlcmllczxJTGluZUFjY2Vzc29ycz59IHJlbmRlclNlcmllc1xuICAgICAqIEBwYXJhbSB7RDNTZWxlY3Rpb259IHBhdGggRDMgU2VsZWN0aW9uIHdpdGggPHBhdGg+IGVsZW1lbnQgcHJlLWNyZWF0ZWQgYW5kIHByZS1zdHlsZWRcbiAgICAgKi9cbiAgICBwdWJsaWMgZHJhd0xpbmUoXG4gICAgICAgIHJlbmRlclNlcmllczogSVJlbmRlclNlcmllczxJTGluZUFjY2Vzc29ycz4sXG4gICAgICAgIHBhdGg6IEQzU2VsZWN0aW9uPFNWR1BhdGhFbGVtZW50PlxuICAgICk6IHZvaWQge1xuICAgICAgICBpZiAodGhpcy5pc0luZmluaXRlTGluZURhdGEocmVuZGVyU2VyaWVzKSkge1xuICAgICAgICAgICAgdGhpcy5kcmF3SW5maW5pdGVMaW5lKHJlbmRlclNlcmllcywgcGF0aCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmRyYXdTdGFuZGFyZExpbmUocmVuZGVyU2VyaWVzLCBwYXRoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIC8qKiBTZWUge0BsaW5rIFJlbmRlcmVyI2hpZ2hsaWdodERhdGFQb2ludH0gKi9cbiAgICBwdWJsaWMgaGlnaGxpZ2h0RGF0YVBvaW50KFxuICAgICAgICByZW5kZXJTZXJpZXM6IElSZW5kZXJTZXJpZXM8SUxpbmVBY2Nlc3NvcnM+LFxuICAgICAgICBkYXRhUG9pbnRJbmRleDogbnVtYmVyLFxuICAgICAgICByZW5kZXJlclN1YmplY3Q6IFN1YmplY3Q8SVJlbmRlcmVyRXZlbnRQYXlsb2FkPlxuICAgICk6IHZvaWQge1xuICAgICAgICBpZiAoIXRoaXMuY29uZmlnLmludGVyYWN0aXZlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZGF0YVNlcmllcyA9IHJlbmRlclNlcmllcy5kYXRhU2VyaWVzO1xuICAgICAgICBjb25zdCBhY2Nlc3NvcnMgPSBkYXRhU2VyaWVzLmFjY2Vzc29ycztcbiAgICAgICAgaWYgKCFhY2Nlc3NvcnMuc2VyaWVzLm1hcmtlcikge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgTWFya2VyVXRpbHMubWFuYWdlTWFya2VyKFxuICAgICAgICAgICAgZGF0YVNlcmllcyxcbiAgICAgICAgICAgIHJlbmRlclNlcmllcy5zY2FsZXMgYXMgSVhZU2NhbGVzLFxuICAgICAgICAgICAgZGF0YVBvaW50SW5kZXgsXG4gICAgICAgICAgICByZW5kZXJTZXJpZXMuY29udGFpbmVyc1tSZW5kZXJMYXllck5hbWUuZm9yZWdyb3VuZF0sXG4gICAgICAgICAgICByZW5kZXJlclN1YmplY3QsXG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5tYXJrZXJJbnRlcmFjdGlvblxuICAgICAgICApO1xuICAgIH1cblxuICAgIC8qKiBTZWUge0BsaW5rIFJlbmRlcmVyI2dldFJlcXVpcmVkTGF5ZXJzfSAqL1xuICAgIHB1YmxpYyBnZXRSZXF1aXJlZExheWVycygpOiBJTGFzYWduYUxheWVyW10ge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgU1RBTkRBUkRfUkVOREVSX0xBWUVSU1tSZW5kZXJMYXllck5hbWUuZGF0YV0sXG4gICAgICAgICAgICBTVEFOREFSRF9SRU5ERVJfTEFZRVJTW1JlbmRlckxheWVyTmFtZS5mb3JlZ3JvdW5kXSxcbiAgICAgICAgICAgIFNUQU5EQVJEX1JFTkRFUl9MQVlFUlNbUmVuZGVyTGF5ZXJOYW1lLnVuY2xpcHBlZERhdGFdLFxuICAgICAgICBdO1xuICAgIH1cblxuICAgIC8qKiBTZWUge0BsaW5rIFJlbmRlcmVyI2dldERhdGFQb2ludFBvc2l0aW9ufSAqL1xuICAgIHB1YmxpYyBnZXREYXRhUG9pbnRQb3NpdGlvbihcbiAgICAgICAgZGF0YVNlcmllczogSURhdGFTZXJpZXM8SUxpbmVBY2Nlc3NvcnM+LFxuICAgICAgICBpbmRleDogbnVtYmVyLFxuICAgICAgICBzY2FsZXM6IFNjYWxlc1xuICAgICk6IElQb3NpdGlvbiB8IHVuZGVmaW5lZCB7XG4gICAgICAgIC8vIFRPRE86IGNvbnNpZGVyIGluY2x1ZGluZyBzaXplIG9mIHRoZSBtYXJrZXIgb25jZSB3ZSBoYXZlIHRoZW0gcmVuZGVyZWQgYXMgc3ltYm9sc1xuICAgICAgICByZXR1cm4gc3VwZXIuZ2V0RGF0YVBvaW50UG9zaXRpb24oZGF0YVNlcmllcywgaW5kZXgsIHNjYWxlcyk7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBkcmF3U3RhbmRhcmRMaW5lKFxuICAgICAgICByZW5kZXJTZXJpZXM6IElSZW5kZXJTZXJpZXM8SUxpbmVBY2Nlc3NvcnM+LFxuICAgICAgICBwYXRoOiBEM1NlbGVjdGlvbjxTVkdQYXRoRWxlbWVudD5cbiAgICApIHtcbiAgICAgICAgY29uc3QgZGF0YVNlcmllcyA9IHJlbmRlclNlcmllcy5kYXRhU2VyaWVzO1xuICAgICAgICBjb25zdCBhY2Nlc3NvcnMgPSBkYXRhU2VyaWVzLmFjY2Vzc29ycztcblxuICAgICAgICBsZXQgd2FybmVkID0gZmFsc2U7XG4gICAgICAgIGNvbnN0IHZhbGlkYXRlZERhdGEgPSBkYXRhU2VyaWVzLmRhdGEuZmlsdGVyKChkLCBpKSA9PiB7XG4gICAgICAgICAgICBjb25zdCB2YWxpZCA9XG4gICAgICAgICAgICAgICAgdHlwZW9mIGFjY2Vzc29ycy5kYXRhLngoZCwgaSwgZGF0YVNlcmllcy5kYXRhLCBkYXRhU2VyaWVzKSAhPT1cbiAgICAgICAgICAgICAgICAgICAgXCJ1bmRlZmluZWRcIiAmJlxuICAgICAgICAgICAgICAgIHR5cGVvZiBhY2Nlc3NvcnMuZGF0YS55KGQsIGksIGRhdGFTZXJpZXMuZGF0YSwgZGF0YVNlcmllcykgIT09XG4gICAgICAgICAgICAgICAgICAgIFwidW5kZWZpbmVkXCI7XG4gICAgICAgICAgICBpZiAoIXZhbGlkICYmICF3YXJuZWQpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgICAgICAgICAgICAgIFwiRGF0YSBwb2ludFwiLFxuICAgICAgICAgICAgICAgICAgICBkLFxuICAgICAgICAgICAgICAgICAgICBcIndhcyBza2lwcGVkIGFzIGFjY2Vzc29ycyBkaWRuJ3QgbWFuYWdlIHRvIGV4dHJhY3QgYW55IGRhdGEuXCJcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcIiAtPiBhY2Nlc3NvcnMuZGF0YS54OlwiLCBhY2Nlc3NvcnMuZGF0YS54KTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXCIgLT4gYWNjZXNzb3JzLmRhdGEueTpcIiwgYWNjZXNzb3JzLmRhdGEueSk7XG4gICAgICAgICAgICAgICAgd2FybmVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB2YWxpZDtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKCF0aGlzLmNvbmZpZy5jdXJ2ZVR5cGUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImN1cnZlVHlwZSBpcyBub3QgZGVmaW5lZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGxpbmVGdW5jID0gbGluZSgpXG4gICAgICAgICAgICAueCgoZDogYW55LCBpOiBudW1iZXIpID0+XG4gICAgICAgICAgICAgICAgcmVuZGVyU2VyaWVzLnNjYWxlcy54LmNvbnZlcnQoXG4gICAgICAgICAgICAgICAgICAgIGFjY2Vzc29ycy5kYXRhLngoZCwgaSwgZGF0YVNlcmllcy5kYXRhLCBkYXRhU2VyaWVzKVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC55KChkOiBhbnksIGk6IG51bWJlcikgPT5cbiAgICAgICAgICAgICAgICByZW5kZXJTZXJpZXMuc2NhbGVzLnkuY29udmVydChcbiAgICAgICAgICAgICAgICAgICAgYWNjZXNzb3JzLmRhdGEueShkLCBpLCBkYXRhU2VyaWVzLmRhdGEsIGRhdGFTZXJpZXMpXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgLmRlZmluZWQoKGQ6IGFueSwgaTogbnVtYmVyKSA9PlxuICAgICAgICAgICAgICAgIGFjY2Vzc29ycy5kYXRhLmRlZmluZWRcbiAgICAgICAgICAgICAgICAgICAgPyBhY2Nlc3NvcnMuZGF0YS5kZWZpbmVkKGQsIGksIGRhdGFTZXJpZXMuZGF0YSwgZGF0YVNlcmllcylcbiAgICAgICAgICAgICAgICAgICAgOiB0cnVlXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuY3VydmUodGhpcy5jb25maWcuY3VydmVUeXBlKTtcblxuICAgICAgICBwYXRoLmF0dHIoXCJkXCIsIGxpbmVGdW5jKHZhbGlkYXRlZERhdGEpID8/IFwiXCIpO1xuXG4gICAgICAgIGlmICh0aGlzLmNvbmZpZy51c2VFbmhhbmNlZExpbmVDYXBzKSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUxpbmVDYXBzKFxuICAgICAgICAgICAgICAgIHZhbGlkYXRlZERhdGEsXG4gICAgICAgICAgICAgICAgcmVuZGVyU2VyaWVzLFxuICAgICAgICAgICAgICAgIHRoaXMuY29uZmlnLmVuaGFuY2VkTGluZUNhcD8uZmlsbCB8fCBwYXRoLmF0dHIoXCJzdHJva2VcIilcbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIGRyYXdJbmZpbml0ZUxpbmUoXG4gICAgICAgIHJlbmRlclNlcmllczogSVJlbmRlclNlcmllczxJTGluZUFjY2Vzc29ycz4sXG4gICAgICAgIHBhdGg6IEQzU2VsZWN0aW9uPFNWR1BhdGhFbGVtZW50PlxuICAgICkge1xuICAgICAgICBjb25zdCBkYXRhU2VyaWVzID0gcmVuZGVyU2VyaWVzLmRhdGFTZXJpZXM7XG4gICAgICAgIGNvbnN0IGFjY2Vzc29ycyA9IGRhdGFTZXJpZXMuYWNjZXNzb3JzO1xuXG4gICAgICAgIGNvbnN0IHkgPSByZW5kZXJTZXJpZXMuc2NhbGVzLnkuY29udmVydChcbiAgICAgICAgICAgIGFjY2Vzc29ycy5kYXRhLnkoZGF0YVNlcmllcy5kYXRhWzBdLCAwLCBkYXRhU2VyaWVzLmRhdGEsIGRhdGFTZXJpZXMpXG4gICAgICAgICk7XG4gICAgICAgIGNvbnN0IGRhdGE6IFtudW1iZXIsIG51bWJlcl1bXSA9IFtcbiAgICAgICAgICAgIFtyZW5kZXJTZXJpZXMuc2NhbGVzLngucmFuZ2UoKVswXSwgeV0sXG4gICAgICAgICAgICBbcmVuZGVyU2VyaWVzLnNjYWxlcy54LnJhbmdlKClbMV0sIHldLFxuICAgICAgICBdO1xuXG4gICAgICAgIGNvbnN0IGxpbmVGdW5jID0gbGluZSgpXG4gICAgICAgICAgICAueCgoZDogYW55KSA9PiBkWzBdKVxuICAgICAgICAgICAgLnkoKGQ6IGFueSkgPT4gZFsxXSk7XG5cbiAgICAgICAgY29uc3QgcmVzdWx0OiBzdHJpbmcgfCBudWxsID0gbGluZUZ1bmMoZGF0YSk7XG5cbiAgICAgICAgaWYgKCFyZXN1bHQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkxpbmUgY2Fubm90IGJlIGNvbXB1dGVkXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgcGF0aC5hdHRyKFwic2hhcGUtcmVuZGVyaW5nXCIsIFwiY3Jpc3BFZGdlc1wiKS5hdHRyKFwiZFwiLCByZXN1bHQpO1xuICAgIH1cblxuICAgIHByaXZhdGUgdXBkYXRlTGluZUNhcHMoXG4gICAgICAgIHZhbGlkYXRlZERhdGE6IGFueVtdLFxuICAgICAgICByZW5kZXJTZXJpZXM6IElSZW5kZXJTZXJpZXM8SUxpbmVBY2Nlc3NvcnM+LFxuICAgICAgICBmaWxsOiBzdHJpbmdcbiAgICApIHtcbiAgICAgICAgY29uc3QgZGF0YVNlcmllcyA9IHJlbmRlclNlcmllcy5kYXRhU2VyaWVzO1xuICAgICAgICBjb25zdCBhY2Nlc3NvcnMgPSBkYXRhU2VyaWVzLmFjY2Vzc29ycztcbiAgICAgICAgY29uc3QgZGVmaW5lZERhdGEgPSB2YWxpZGF0ZWREYXRhLmZpbHRlcigoZCwgaSkgPT5cbiAgICAgICAgICAgIGFjY2Vzc29ycz8uZGF0YT8uZGVmaW5lZFxuICAgICAgICAgICAgICAgID8gYWNjZXNzb3JzPy5kYXRhPy5kZWZpbmVkKGQsIGksIGRhdGFTZXJpZXMuZGF0YSwgZGF0YVNlcmllcylcbiAgICAgICAgICAgICAgICA6IHRydWVcbiAgICAgICAgKTtcblxuICAgICAgICBjb25zdCB1cGRhdGVDeCA9IChkOiBhbnksIGk6IG51bWJlcikgPT5cbiAgICAgICAgICAgIHJlbmRlclNlcmllcy5zY2FsZXMueC5jb252ZXJ0KFxuICAgICAgICAgICAgICAgIGFjY2Vzc29ycy5kYXRhLngoZCwgaSwgZGF0YVNlcmllcy5kYXRhLCBkYXRhU2VyaWVzKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgY29uc3QgdXBkYXRlQ3kgPSAoZDogYW55LCBpOiBudW1iZXIpID0+XG4gICAgICAgICAgICByZW5kZXJTZXJpZXMuc2NhbGVzLnkuY29udmVydChcbiAgICAgICAgICAgICAgICBhY2Nlc3NvcnMuZGF0YS55KGQsIGksIGRhdGFTZXJpZXMuZGF0YSwgZGF0YVNlcmllcylcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgLy8gdXNlIGFuIHVuY2xpcHBlZCBsYXllciB0byBlbnN1cmUgdGhlIGxpbmUgY2FwcyBvbiB0aGUgbGVmdCBhbmQgcmlnaHQgc2lkZXMgb2YgdGhlIGNoYXJ0IGRvbid0IGdldCBjbGlwcGVkXG4gICAgICAgIGNvbnN0IGxpbmVDYXBzID0gcmVuZGVyU2VyaWVzLmNvbnRhaW5lcnNbUmVuZGVyTGF5ZXJOYW1lLnVuY2xpcHBlZERhdGFdXG4gICAgICAgICAgICAuc2VsZWN0QWxsKGAuJHtMaW5lUmVuZGVyZXIuTElORV9DQVBfQ0xBU1NfTkFNRX1gKVxuICAgICAgICAgICAgLmRhdGEoZGVmaW5lZERhdGEpXG4gICAgICAgICAgICAuYXR0cihcImN4XCIsIHVwZGF0ZUN4KVxuICAgICAgICAgICAgLmF0dHIoXCJjeVwiLCB1cGRhdGVDeSk7XG5cbiAgICAgICAgbGluZUNhcHNcbiAgICAgICAgICAgIC5lbnRlcigpXG4gICAgICAgICAgICAuYXBwZW5kKFwiY2lyY2xlXCIpXG4gICAgICAgICAgICAuYXR0cihcImNsYXNzXCIsIExpbmVSZW5kZXJlci5MSU5FX0NBUF9DTEFTU19OQU1FKVxuICAgICAgICAgICAgLmF0dHIoXCJyXCIsIHRoaXMuY29uZmlnLmVuaGFuY2VkTGluZUNhcD8ucmFkaXVzIGFzIG51bWJlcilcbiAgICAgICAgICAgIC5hdHRyKFwiY3hcIiwgdXBkYXRlQ3gpXG4gICAgICAgICAgICAuYXR0cihcImN5XCIsIHVwZGF0ZUN5KVxuICAgICAgICAgICAgLnN0eWxlKFxuICAgICAgICAgICAgICAgIFwic3Ryb2tlLXdpZHRoXCIsXG4gICAgICAgICAgICAgICAgdGhpcy5jb25maWcuZW5oYW5jZWRMaW5lQ2FwPy5zdHJva2VXaWR0aCBhcyBudW1iZXJcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC5zdHlsZShcImZpbGxcIiwgZmlsbClcbiAgICAgICAgICAgIC5zdHlsZShcInN0cm9rZVwiLCB0aGlzLmNvbmZpZy5lbmhhbmNlZExpbmVDYXA/LnN0cm9rZSBhcyBzdHJpbmcpO1xuXG4gICAgICAgIGxpbmVDYXBzLmV4aXQoKS5yZW1vdmUoKTtcbiAgICB9XG59XG4iXX0=