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

158 lines 25.5 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 { arc } from "d3-shape"; import cloneDeep from "lodash/cloneDeep"; import defaultsDeep from "lodash/defaultsDeep"; import isUndefined from "lodash/isUndefined"; import { Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { GAUGE_LABELS_CONTAINER_CLASS, GAUGE_LABEL_FORMATTER_NAME_DEFAULT, GAUGE_THRESHOLD_LABEL_CLASS, } from "./constants"; import { DATA_POINT_NOT_FOUND, INTERACTION_DATA_POINTS_EVENT, STANDARD_RENDER_LAYERS, } from "../../../constants"; import { DonutGaugeRenderingUtil } from "../../../renderers/radial/gauge/donut-gauge-rendering-util"; import { DonutGaugeThresholdsRenderer } from "../../../renderers/radial/gauge/donut-gauge-thresholds-renderer"; import { RenderLayerName } from "../../../renderers/types"; import { ChartPlugin } from "../../common/chart-plugin"; /** * A chart plugin that handles the rendering of labels for a donut gauge */ export class DonutGaugeLabelsPlugin extends ChartPlugin { config; static MARGIN_DEFAULT = 25; /** The default plugin configuration */ DEFAULT_CONFIG = { padding: 5, formatterName: GAUGE_LABEL_FORMATTER_NAME_DEFAULT, disableThresholdLabels: false, }; destroy$ = new Subject(); lasagnaLayer; constructor(config = {}) { super(); this.config = config; this.config = defaultsDeep(this.config, this.DEFAULT_CONFIG); } initialize() { this.lasagnaLayer = this.chart.getGrid().getLasagna().addLayer({ name: GAUGE_LABELS_CONTAINER_CLASS, order: STANDARD_RENDER_LAYERS[RenderLayerName.data].order, clipped: false, }); this.chart .getEventBus() .getStream(INTERACTION_DATA_POINTS_EVENT) .pipe(takeUntil(this.destroy$)) .subscribe((event) => { const gaugeThresholdLabelsGroup = this.lasagnaLayer.select(`.${GAUGE_LABELS_CONTAINER_CLASS}`); if (!gaugeThresholdLabelsGroup.empty()) { const dataPoints = event.data.dataPoints; const labelOpacity = Object.keys(dataPoints).find((key, index) => dataPoints[key].index === DATA_POINT_NOT_FOUND) ? 0 : 1; gaugeThresholdLabelsGroup.style("opacity", labelOpacity); } }); } update() { this.drawThresholdLabels(); } updateDimensions() { this.drawThresholdLabels(); } destroy() { if (this.destroy$) { this.destroy$.next(); this.destroy$.complete(); } } drawThresholdLabels() { const thresholdsSeries = this.chart .getDataManager() .chartSeriesSet.find((series) => series.renderer instanceof DonutGaugeThresholdsRenderer); if (isUndefined(thresholdsSeries)) { console.warn("Threshold series is undefined. As a result, threshold labels for the donut gauge will not be rendered."); return; } let gaugeThresholdsLabelsGroup = this.lasagnaLayer.select(`.${GAUGE_LABELS_CONTAINER_CLASS}`); if (gaugeThresholdsLabelsGroup.empty()) { gaugeThresholdsLabelsGroup = this.lasagnaLayer .append("svg:g") .attr("class", GAUGE_LABELS_CONTAINER_CLASS) .style("opacity", 0); } const renderer = thresholdsSeries?.renderer; const labelRadius = renderer?.getOuterRadius(thresholdsSeries?.scales.r.range() ?? [0, 0], 0) + this.config.padding; if (isUndefined(labelRadius)) { throw new Error("Radius is undefined"); } const labelGenerator = arc() .outerRadius(labelRadius) .innerRadius(labelRadius); const formatter = thresholdsSeries?.scales.r.formatters[this.config.formatterName] ?? ((d) => d); const data = cloneDeep(this.config.disableThresholdLabels ? [] : thresholdsSeries?.data); if (isUndefined(data)) { throw new Error("Gauge threshold series data is undefined"); } // ensure the data is sorted in ascending order by value since we're using it to calculate circle arcs data.sort((a, b) => a.value - b.value); const labelSelection = gaugeThresholdsLabelsGroup .selectAll(`text.${GAUGE_THRESHOLD_LABEL_CLASS}`) .data(DonutGaugeRenderingUtil.generateThresholdArcData(data)); labelSelection.exit().remove(); labelSelection .enter() .append("text") .attr("class", GAUGE_THRESHOLD_LABEL_CLASS) .merge(labelSelection) .attr("transform", (d) => `translate(${labelGenerator.centroid(d)})`) .attr("title", (d, i) => formatter(data[i].value)) .style("text-anchor", (d) => this.getTextAnchor(d.startAngle)) .style("dominant-baseline", (d) => this.getAlignmentBaseline(d.startAngle)) .text((d, i) => formatter(data[i].value)); } getTextAnchor(angle) { // pie charts start on the top, so we need to subtract Math.PI / 2 (90 degrees) const cosine = Math.cos(angle - Math.PI / 2); if (cosine > 0.5) { // used for right 120 degrees of chart return "start"; } if (cosine < -0.5) { // used for left 120 degrees of chart return "end"; } // used for top 60 degrees and bottom 60 degrees of chart return "middle"; } getAlignmentBaseline(angle) { // pie charts start on the top, so we need to add Math.PI / 2 (90 degrees) const sine = Math.sin(angle + Math.PI / 2); if (sine > 0.5) { // used for top 120 degrees of chart return "text-after-edge"; } if (sine < -0.5) { // used for bottom 120 degrees of chart return "text-before-edge"; } // used for left 60 degrees and right 60 degrees of chart return "central"; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZG9udXQtZ2F1Z2UtbGFiZWxzLXBsdWdpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9jb3JlL3BsdWdpbnMvZ2F1Z2UvZG9udXQtZ2F1Z2UtbGFiZWxzLXBsdWdpbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx5REFBeUQ7QUFDekQsRUFBRTtBQUNGLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSw4RUFBOEU7QUFDOUUsNERBQTREO0FBQzVELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsdURBQXVEO0FBQ3ZELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSwwRUFBMEU7QUFDMUUsaUZBQWlGO0FBQ2pGLDZFQUE2RTtBQUM3RSxpQkFBaUI7QUFFakIsT0FBTyxFQUFPLEdBQUcsRUFBb0IsTUFBTSxVQUFVLENBQUM7QUFDdEQsT0FBTyxTQUFTLE1BQU0sa0JBQWtCLENBQUM7QUFDekMsT0FBTyxZQUFZLE1BQU0scUJBQXFCLENBQUM7QUFDL0MsT0FBTyxXQUFXLE1BQU0sb0JBQW9CLENBQUM7QUFDN0MsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUMvQixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFM0MsT0FBTyxFQUNILDRCQUE0QixFQUM1QixrQ0FBa0MsRUFDbEMsMkJBQTJCLEdBQzlCLE1BQU0sYUFBYSxDQUFDO0FBRXJCLE9BQU8sRUFDSCxvQkFBb0IsRUFDcEIsNkJBQTZCLEVBQzdCLHNCQUFzQixHQUN6QixNQUFNLG9CQUFvQixDQUFDO0FBQzVCLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLDREQUE0RCxDQUFDO0FBQ3JHLE9BQU8sRUFBRSw0QkFBNEIsRUFBRSxNQUFNLGlFQUFpRSxDQUFDO0FBQy9HLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFB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LENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7SUFDbEQsQ0FBQztJQUVPLGFBQWEsQ0FBQyxLQUFVO1FBQzVCLCtFQUErRTtRQUMvRSxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQzdDLElBQUksTUFBTSxHQUFHLEdBQUcsRUFBRTtZQUNkLHNDQUFzQztZQUN0QyxPQUFPLE9BQU8sQ0FBQztTQUNsQjtRQUVELElBQUksTUFBTSxHQUFHLENBQUMsR0FBRyxFQUFFO1lBQ2YscUNBQXFDO1lBQ3JDLE9BQU8sS0FBSyxDQUFDO1NBQ2hCO1FBRUQseURBQXlEO1FBQ3pELE9BQU8sUUFBUSxDQUFDO0lBQ3BCLENBQUM7SUFFTyxvQkFBb0IsQ0FBQyxLQUFVO1FBQ25DLDBFQUEwRTtRQUMxRSxNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQyxDQUFDO1FBQzNDLElBQUksSUFBSSxHQUFHLEdBQUcsRUFBRTtZQUNaLG9DQUFvQztZQUNwQyxPQUFPLGlCQUFpQixDQUFDO1NBQzVCO1FBRUQsSUFBSSxJQUFJLEdBQUcsQ0FBQyxHQUFHLEVBQUU7WUFDYix1Q0FBdUM7WUFDdkMsT0FBTyxrQkFBa0IsQ0FBQztTQUM3QjtRQUVELHlEQUF5RDtRQUN6RCxPQUFPLFNBQVMsQ0FBQztJQUNyQixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7IEFyYywgYXJjLCBEZWZhdWx0QXJjT2JqZWN0IH0gZnJvbSBcImQzLXNoYXBlXCI7XG5pbXBvcnQgY2xvbmVEZWVwIGZyb20gXCJsb2Rhc2gvY2xvbmVEZWVwXCI7XG5pbXBvcnQgZGVmYXVsdHNEZWVwIGZyb20gXCJsb2Rhc2gvZGVmYXVsdHNEZWVwXCI7XG5pbXBvcnQgaXNVbmRlZmluZWQgZnJvbSBcImxvZGFzaC9pc1VuZGVmaW5lZFwiO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQgeyB0YWtlVW50aWwgfSBmcm9tIFwicnhqcy9vcGVyYXRvcnNcIjtcblxuaW1wb3J0IHtcbiAgICBHQVVHRV9MQUJFTFNfQ09OVEFJTkVSX0NMQVNTLFxuICAgIEdBVUdFX0xBQkVMX0ZPUk1BVFRFUl9OQU1FX0RFRkFVTFQsXG4gICAgR0FVR0VfVEhSRVNIT0xEX0xBQkVMX0NMQVNTLFxufSBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IElHYXVnZUxhYmVsc1BsdWdpbkNvbmZpZyB9IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQge1xuICAgIERBVEFfUE9JTlRfTk9UX0ZPVU5ELFxuICAgIElOVEVSQUNUSU9OX0RBVEFfUE9JTlRTX0VWRU5ULFxuICAgIFNUQU5EQVJEX1JFTkRFUl9MQVlFUlMsXG59IGZyb20gXCIuLi8uLi8uLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IERvbnV0R2F1Z2VSZW5kZXJpbmdVdGlsIH0gZnJvbSBcIi4uLy4uLy4uL3JlbmRlcmVycy9yYWRpYWwvZ2F1Z2UvZG9udXQtZ2F1Z2UtcmVuZGVyaW5nLXV0aWxcIjtcbmltcG9ydCB7IERvbnV0R2F1Z2VUaHJlc2hvbGRzUmVuZGVyZXIgfSBmcm9tIFwiLi4vLi4vLi4vcmVuZGVyZXJzL3JhZGlhbC9nYXVnZS9kb251dC1nYXVnZS10aHJlc2hvbGRzLXJlbmRlcmVyXCI7XG5pbXBvcnQgeyBSZW5kZXJMYXllck5hbWUgfSBmcm9tIFwiLi4vLi4vLi4vcmVuZGVyZXJzL3R5cGVzXCI7XG5pbXBvcnQgeyBDaGFydFBsdWdpbiB9IGZyb20gXCIuLi8uLi9jb21tb24vY2hhcnQtcGx1Z2luXCI7XG5pbXBvcnQge1xuICAgIEQzU2VsZWN0aW9uLFxuICAgIElBY2Nlc3NvcnMsXG4gICAgSUNoYXJ0RXZlbnQsXG4gICAgSUNoYXJ0U2VyaWVzLFxufSBmcm9tIFwiLi4vLi4vY29tbW9uL3R5cGVzXCI7XG5cbi8qKlxuICogQSBjaGFydCBwbHVnaW4gdGhhdCBoYW5kbGVzIHRoZSByZW5kZXJpbmcgb2YgbGFiZWxzIGZvciBhIGRvbnV0IGdhdWdlXG4gKi9cbmV4cG9ydCBjbGFzcyBEb251dEdhdWdlTGFiZWxzUGx1Z2luIGV4dGVuZHMgQ2hhcnRQbHVnaW4ge1xuICAgIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgTUFSR0lOX0RFRkFVTFQgPSAyNTtcblxuICAgIC8qKiBUaGUgZGVmYXVsdCBwbHVnaW4gY29uZmlndXJhdGlvbiAqL1xuICAgIHB1YmxpYyBERUZBVUxUX0NPTkZJRzogSUdhdWdlTGFiZWxzUGx1Z2luQ29uZmlnID0ge1xuICAgICAgICBwYWRkaW5nOiA1LFxuICAgICAgICBmb3JtYXR0ZXJOYW1lOiBHQVVHRV9MQUJFTF9GT1JNQVRURVJfTkFNRV9ERUZBVUxULFxuICAgICAgICBkaXNhYmxlVGhyZXNob2xkTGFiZWxzOiBmYWxzZSxcbiAgICB9O1xuXG4gICAgcHJpdmF0ZSByZWFkb25seSBkZXN0cm95JCA9IG5ldyBTdWJqZWN0PHZvaWQ+KCk7XG4gICAgcHJpdmF0ZSBsYXNhZ25hTGF5ZXI6IEQzU2VsZWN0aW9uPFNWR0VsZW1lbnQ+O1xuXG4gICAgY29uc3RydWN0b3IocHVibGljIGNvbmZpZzogSUdhdWdlTGFiZWxzUGx1Z2luQ29uZmlnID0ge30pIHtcbiAgICAgICAgc3VwZXIoKTtcbiAgICAgICAgdGhpcy5jb25maWcgPSBkZWZhdWx0c0RlZXAodGhpcy5jb25maWcsIHRoaXMuREVGQVVMVF9DT05GSUcpO1xuICAgIH1cblxuICAgIHB1YmxpYyBpbml0aWFsaXplKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmxhc2FnbmFMYXllciA9IHRoaXMuY2hhcnQuZ2V0R3JpZCgpLmdldExhc2FnbmEoKS5hZGRMYXllcih7XG4gICAgICAgICAgICBuYW1lOiBHQVVHRV9MQUJFTFNfQ09OVEFJTkVSX0NMQVNTLFxuICAgICAgICAgICAgb3JkZXI6IFNUQU5EQVJEX1JFTkRFUl9MQVlFUlNbUmVuZGVyTGF5ZXJOYW1lLmRhdGFdLm9yZGVyLFxuICAgICAgICAgICAgY2xpcHBlZDogZmFsc2UsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuY2hhcnRcbiAgICAgICAgICAgIC5nZXRFdmVudEJ1cygpXG4gICAgICAgICAgICAuZ2V0U3RyZWFtKElOVEVSQUNUSU9OX0RBVEFfUE9JTlRTX0VWRU5UIGFzIHN0cmluZylcbiAgICAgICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKGV2ZW50OiBJQ2hhcnRFdmVudCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGdhdWdlVGhyZXNob2xkTGFiZWxzR3JvdXAgPSB0aGlzLmxhc2FnbmFMYXllci5zZWxlY3QoXG4gICAgICAgICAgICAgICAgICAgIGAuJHtHQVVHRV9MQUJFTFNfQ09OVEFJTkVSX0NMQVNTfWBcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGlmICghZ2F1Z2VUaHJlc2hvbGRMYWJlbHNHcm91cC5lbXB0eSgpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGRhdGFQb2ludHMgPSBldmVudC5kYXRhLmRhdGFQb2ludHM7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGxhYmVsT3BhY2l0eSA9IE9iamVjdC5rZXlzKGRhdGFQb2ludHMpLmZpbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICAoa2V5LCBpbmRleCkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhUG9pbnRzW2tleV0uaW5kZXggPT09IERBVEFfUE9JTlRfTk9UX0ZPVU5EXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgICAgID8gMFxuICAgICAgICAgICAgICAgICAgICAgICAgOiAxO1xuICAgICAgICAgICAgICAgICAgICBnYXVnZVRocmVzaG9sZExhYmVsc0dyb3VwLnN0eWxlKFwib3BhY2l0eVwiLCBsYWJlbE9wYWNpdHkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIHB1YmxpYyB1cGRhdGUoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZHJhd1RocmVzaG9sZExhYmVscygpO1xuICAgIH1cblxuICAgIHB1YmxpYyB1cGRhdGVEaW1lbnNpb25zKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmRyYXdUaHJlc2hvbGRMYWJlbHMoKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZGVzdHJveSgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuZGVzdHJveSQpIHtcbiAgICAgICAgICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xuICAgICAgICAgICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBkcmF3VGhyZXNob2xkTGFiZWxzKCkge1xuICAgICAgICBjb25zdCB0aHJlc2hvbGRzU2VyaWVzID0gdGhpcy5jaGFydFxuICAgICAgICAgICAgLmdldERhdGFNYW5hZ2VyKClcbiAgICAgICAgICAgIC5jaGFydFNlcmllc1NldC5maW5kKFxuICAgICAgICAgICAgICAgIChzZXJpZXM6IElDaGFydFNlcmllczxJQWNjZXNzb3JzPGFueT4+KSA9PlxuICAgICAgICAgICAgICAgICAgICBzZXJpZXMucmVuZGVyZXIgaW5zdGFuY2VvZiBEb251dEdhdWdlVGhyZXNob2xkc1JlbmRlcmVyXG4gICAgICAgICAgICApO1xuXG4gICAgICAgIGlmIChpc1VuZGVmaW5lZCh0aHJlc2hvbGRzU2VyaWVzKSkge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgICAgICAgIFwiVGhyZXNob2xkIHNlcmllcyBpcyB1bmRlZmluZWQuIEFzIGEgcmVzdWx0LCB0aHJlc2hvbGQgbGFiZWxzIGZvciB0aGUgZG9udXQgZ2F1Z2Ugd2lsbCBub3QgYmUgcmVuZGVyZWQuXCJcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgZ2F1Z2VUaHJlc2hvbGRzTGFiZWxzR3JvdXAgPSB0aGlzLmxhc2FnbmFMYXllci5zZWxlY3QoXG4gICAgICAgICAgICBgLiR7R0FVR0VfTEFCRUxTX0NPTlRBSU5FUl9DTEFTU31gXG4gICAgICAgICk7XG4gICAgICAgIGlmIChnYXVnZVRocmVzaG9sZHNMYWJlbHNHcm91cC5lbXB0eSgpKSB7XG4gICAgICAgICAgICBnYXVnZVRocmVzaG9sZHNMYWJlbHNHcm91cCA9IHRoaXMubGFzYWduYUxheWVyXG4gICAgICAgICAgICAgICAgLmFwcGVuZChcInN2ZzpnXCIpXG4gICAgICAgICAgICAgICAgLmF0dHIoXCJjbGFzc1wiLCBHQVVHRV9MQUJFTFNfQ09OVEFJTkVSX0NMQVNTKVxuICAgICAgICAgICAgICAgIC5zdHlsZShcIm9wYWNpdHlcIiwgMCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCByZW5kZXJlciA9XG4gICAgICAgICAgICB0aHJlc2hvbGRzU2VyaWVzPy5yZW5kZXJlciBhcyBEb251dEdhdWdlVGhyZXNob2xkc1JlbmRlcmVyO1xuICAgICAgICBjb25zdCBsYWJlbFJhZGl1cyA9XG4gICAgICAgICAgICByZW5kZXJlcj8uZ2V0T3V0ZXJSYWRpdXMoXG4gICAgICAgICAgICAgICAgdGhyZXNob2xkc1Nlcmllcz8uc2NhbGVzLnIucmFuZ2UoKSA/PyBbMCwgMF0sXG4gICAgICAgICAgICAgICAgMFxuICAgICAgICAgICAgKSArICh0aGlzLmNvbmZpZy5wYWRkaW5nIGFzIG51bWJlcik7XG4gICAgICAgIGlmIChpc1VuZGVmaW5lZChsYWJlbFJhZGl1cykpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlJhZGl1cyBpcyB1bmRlZmluZWRcIik7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBsYWJlbEdlbmVyYXRvcjogQXJjPGFueSwgRGVmYXVsdEFyY09iamVjdD4gPSBhcmMoKVxuICAgICAgICAgICAgLm91dGVyUmFkaXVzKGxhYmVsUmFkaXVzKVxuICAgICAgICAgICAgLmlubmVyUmFkaXVzKGxhYmVsUmFkaXVzKTtcblxuICAgICAgICBjb25zdCBmb3JtYXR0ZXIgPVxuICAgICAgICAgICAgdGhyZXNob2xkc1Nlcmllcz8uc2NhbGVzLnIuZm9ybWF0dGVyc1tcbiAgICAgICAgICAgICAgICB0aGlzLmNvbmZpZy5mb3JtYXR0ZXJOYW1lIGFzIHN0cmluZ1xuICAgICAgICAgICAgXSA/PyAoKGQpID0+IGQpO1xuXG4gICAgICAgIGNvbnN0IGRhdGEgPSBjbG9uZURlZXAoXG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5kaXNhYmxlVGhyZXNob2xkTGFiZWxzID8gW10gOiB0aHJlc2hvbGRzU2VyaWVzPy5kYXRhXG4gICAgICAgICk7XG4gICAgICAgIGlmIChpc1VuZGVmaW5lZChkYXRhKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiR2F1Z2UgdGhyZXNob2xkIHNlcmllcyBkYXRhIGlzIHVuZGVmaW5lZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGVuc3VyZSB0aGUgZGF0YSBpcyBzb3J0ZWQgaW4gYXNjZW5kaW5nIG9yZGVyIGJ5IHZhbHVlIHNpbmNlIHdlJ3JlIHVzaW5nIGl0IHRvIGNhbGN1bGF0ZSBjaXJjbGUgYXJjc1xuICAgICAgICBkYXRhLnNvcnQoKGEsIGIpID0+IGEudmFsdWUgLSBiLnZhbHVlKTtcblxuICAgICAgICBjb25zdCBsYWJlbFNlbGVjdGlvbiA9IGdhdWdlVGhyZXNob2xkc0xhYmVsc0dyb3VwXG4gICAgICAgICAgICAuc2VsZWN0QWxsKGB0ZXh0LiR7R0FVR0VfVEhSRVNIT0xEX0xBQkVMX0NMQVNTfWApXG4gICAgICAgICAgICAuZGF0YShEb251dEdhdWdlUmVuZGVyaW5nVXRpbC5nZW5lcmF0ZVRocmVzaG9sZEFyY0RhdGEoZGF0YSkpO1xuICAgICAgICBsYWJlbFNlbGVjdGlvbi5leGl0KCkucmVtb3ZlKCk7XG4gICAgICAgIGxhYmVsU2VsZWN0aW9uXG4gICAgICAgICAgICAuZW50ZXIoKVxuICAgICAgICAgICAgLmFwcGVuZChcInRleHRcIilcbiAgICAgICAgICAgIC5hdHRyKFwiY2xhc3NcIiwgR0FVR0VfVEhSRVNIT0xEX0xBQkVMX0NMQVNTKVxuICAgICAgICAgICAgLm1lcmdlKGxhYmVsU2VsZWN0aW9uIGFzIGFueSlcbiAgICAgICAgICAgIC5hdHRyKFxuICAgICAgICAgICAgICAgIFwidHJhbnNmb3JtXCIsXG4gICAgICAgICAgICAgICAgKGQpID0+IGB0cmFuc2xhdGUoJHtsYWJlbEdlbmVyYXRvci5jZW50cm9pZChkKX0pYFxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgLmF0dHIoXCJ0aXRsZVwiLCAoZCwgaSkgPT4gZm9ybWF0dGVyKGRhdGFbaV0udmFsdWUpKVxuICAgICAgICAgICAgLnN0eWxlKFwidGV4dC1hbmNob3JcIiwgKGQpID0+IHRoaXMuZ2V0VGV4dEFuY2hvcihkLnN0YXJ0QW5nbGUpKVxuICAgICAgICAgICAgLnN0eWxlKFwiZG9taW5hbnQtYmFzZWxpbmVcIiwgKGQpID0+XG4gICAgICAgICAgICAgICAgdGhpcy5nZXRBbGlnbm1lbnRCYXNlbGluZShkLnN0YXJ0QW5nbGUpXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAudGV4dCgoZCwgaSkgPT4gZm9ybWF0dGVyKGRhdGFbaV0udmFsdWUpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGdldFRleHRBbmNob3IoYW5nbGU6IGFueSk6IHN0cmluZyB7XG4gICAgICAgIC8vIHBpZSBjaGFydHMgc3RhcnQgb24gdGhlIHRvcCwgc28gd2UgbmVlZCB0byBzdWJ0cmFjdCBNYXRoLlBJIC8gMiAoOTAgZGVncmVlcylcbiAgICAgICAgY29uc3QgY29zaW5lID0gTWF0aC5jb3MoYW5nbGUgLSBNYXRoLlBJIC8gMik7XG4gICAgICAgIGlmIChjb3NpbmUgPiAwLjUpIHtcbiAgICAgICAgICAgIC8vIHVzZWQgZm9yIHJpZ2h0IDEyMCBkZWdyZWVzIG9mIGNoYXJ0XG4gICAgICAgICAgICByZXR1cm4gXCJzdGFydFwiO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNvc2luZSA8IC0wLjUpIHtcbiAgICAgICAgICAgIC8vIHVzZWQgZm9yIGxlZnQgMTIwIGRlZ3JlZXMgb2YgY2hhcnRcbiAgICAgICAgICAgIHJldHVybiBcImVuZFwiO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gdXNlZCBmb3IgdG9wIDYwIGRlZ3JlZXMgYW5kIGJvdHRvbSA2MCBkZWdyZWVzIG9mIGNoYXJ0XG4gICAgICAgIHJldHVybiBcIm1pZGRsZVwiO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0QWxpZ25tZW50QmFzZWxpbmUoYW5nbGU6IGFueSk6IHN0cmluZyB7XG4gICAgICAgIC8vIHBpZSBjaGFydHMgc3RhcnQgb24gdGhlIHRvcCwgc28gd2UgbmVlZCB0byBhZGQgTWF0aC5QSSAvIDIgKDkwIGRlZ3JlZXMpXG4gICAgICAgIGNvbnN0IHNpbmUgPSBNYXRoLnNpbihhbmdsZSArIE1hdGguUEkgLyAyKTtcbiAgICAgICAgaWYgKHNpbmUgPiAwLjUpIHtcbiAgICAgICAgICAgIC8vIHVzZWQgZm9yIHRvcCAxMjAgZGVncmVlcyBvZiBjaGFydFxuICAgICAgICAgICAgcmV0dXJuIFwidGV4dC1hZnRlci1lZGdlXCI7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoc2luZSA8IC0wLjUpIHtcbiAgICAgICAgICAgIC8vIHVzZWQgZm9yIGJvdHRvbSAxMjAgZGVncmVlcyBvZiBjaGFydFxuICAgICAgICAgICAgcmV0dXJuIFwidGV4dC1iZWZvcmUtZWRnZVwiO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gdXNlZCBmb3IgbGVmdCA2MCBkZWdyZWVzIGFuZCByaWdodCA2MCBkZWdyZWVzIG9mIGNoYXJ0XG4gICAgICAgIHJldHVybiBcImNlbnRyYWxcIjtcbiAgICB9XG59XG4iXX0=