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

167 lines 26 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 { brushX } from "d3-brush"; import { event } from "d3-selection"; import defaultsDeep from "lodash/defaultsDeep"; import isEmpty from "lodash/isEmpty"; import isUndefined from "lodash/isUndefined"; import { Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { INTERACTION_COORDINATES_EVENT, INTERACTION_VALUES_ACTIVE_EVENT, SET_DOMAIN_EVENT, STANDARD_RENDER_LAYERS, } from "../../constants"; import { RenderLayerName } from "../../renderers/types"; import { ChartPlugin } from "../common/chart-plugin"; import { InteractionType, } from "../common/types"; import { Grid } from "../grid/grid"; export class ZoomPlugin extends ChartPlugin { config; // *Note:* This plugin manually moves the d3 brush across the screen to accommodate a known Firefox // bug in which mouse events report an incorrect pointer position for svg children of an element // transformed by a translate function: https://github.com/d3/d3-selection/issues/81 static LAYER_NAME = "zoom-brush"; static DEFAULT_CONFIG = { enableExternalEvents: false, }; grid; brush; zoomBrushLayer; brushElement; destroy$ = new Subject(); brushStartX; interactionHandlerMap; constructor(config = {}) { super(); this.config = config; this.config = defaultsDeep(this.config, ZoomPlugin.DEFAULT_CONFIG); this.interactionHandlerMap = { [InteractionType.MouseDown]: this.brushStart, [InteractionType.MouseMove]: this.brushMove, [InteractionType.MouseUp]: this.brushEnd, }; } initialize() { this.grid = this.chart.getGrid(); this.zoomBrushLayer = this.grid.getLasagna().addLayer({ name: ZoomPlugin.LAYER_NAME, // add 1 to the foreground layer's order to ensure the brush is rendered in front of it order: STANDARD_RENDER_LAYERS[RenderLayerName.foreground].order + 1, clipped: true, }); this.chart .getEventBus() .getStream(INTERACTION_COORDINATES_EVENT) .pipe(takeUntil(this.destroy$)) .subscribe((chartEvent) => { if (chartEvent.broadcast && !this.config.enableExternalEvents) { return; } const data = chartEvent.data; if (isEmpty(this.grid.scales) || isEmpty(data.coordinates)) { return; } if (this.interactionHandlerMap[data.interactionType]) { const xCoord = data.coordinates && data.coordinates.x; this.interactionHandlerMap[data.interactionType](xCoord); } }); this.brush = brushX(); this.brushElement = this.zoomBrushLayer .append("g") .attr("class", "brush"); // engage pointer capture to confine mouse events to the interactive area // (in other words, if the 'mouseup' is physically triggered outside the interactive area, // the pointer capture allows us to still zoom based on that event) this.chart .getGrid() .getInteractiveArea() .on("pointerdown", () => event.target.setPointerCapture(event.pointerId)) .on("pointerup", () => event.target.releasePointerCapture(event.pointerId)); } updateDimensions() { const dimension = this.grid.config().dimension; // set the brush area's dimensions this.brush.extent([ [0, 0], [dimension.width(), dimension.height()], ]); // render the brush area after we have dimensions this.brush(this.zoomBrushLayer.select(".brush")); // prevent the brush from handling its own pointer events this.brushElement.select(".overlay").style("pointer-events", "none"); // remove stroke per mockups this.brushElement.select(".selection").attr("stroke", null); } destroy() { this.grid.getLasagna().removeLayer(ZoomPlugin.LAYER_NAME); this.destroy$.next(); this.destroy$.complete(); } brushStart = (xCoord) => { if (!isUndefined(this.brushStartX)) { return; } this.chart .getEventBus() .getStream(INTERACTION_VALUES_ACTIVE_EVENT) .next({ data: false }); this.brushStartX = xCoord; }; brushMove = (xCoord) => { if (isUndefined(this.brushStartX)) { return; } const selection = [this.brushStartX, xCoord].sort((a, b) => a - b); this.brush.move(this.brushElement, selection); }; brushEnd = (xCoord) => { if (isUndefined(this.brushStartX)) { return; } const selection = [this.brushStartX, xCoord].sort((a, b) => a - b); this.brushStartX = undefined; this.chart .getEventBus() .getStream(INTERACTION_VALUES_ACTIVE_EVENT) .next({ data: true }); // remove the brush this.brush.move(this.brushElement, null); const xScales = this.grid.scales.x.list; if (!xScales || selection[0] === selection[1]) { return; } let widthCorrection = 0; const gridConfig = this.grid.config(); if (!gridConfig.disableRenderAreaWidthCorrection && selection[1] === gridConfig.dimension.width() - Grid.RENDER_AREA_WIDTH_CORRECTION) { // Width correction to accommodate similar adjustment in grid. This ensures that the right-most column of pixels on the chart is selectable. widthCorrection = Grid.RENDER_AREA_WIDTH_CORRECTION; } const data = xScales.reduce((result, next) => { result[next.id] = [ selection[0], selection[1] + widthCorrection, ].map((x) => next.invert(x)); return result; }, {}); // zoom the chart this.chart.getEventBus().getStream(SET_DOMAIN_EVENT).next({ data }); }; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiem9vbS1wbHVnaW4uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvY29yZS9wbHVnaW5zL3pvb20tcGx1Z2luLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHlEQUF5RDtBQUN6RCxFQUFFO0FBQ0YsK0VBQStFO0FBQy9FLDRFQUE0RTtBQUM1RSw4RUFBOEU7QUFDOUUsK0VBQStFO0FBQy9FLDhFQUE4RTtBQUM5RSw0REFBNEQ7QUFDNUQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSx1REFBdUQ7QUFDdkQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSw0RUFBNEU7QUFDNUUsK0VBQStFO0FBQy9FLDBFQUEwRTtBQUMxRSxpRkFBaUY7QUFDakYsNkVBQTZFO0FBQzdFLGlCQUFpQjtBQUVqQixPQUFPLEVBQWlDLE1BQU0sRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNqRSxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3JDLE9BQU8sWUFBWSxNQUFNLHFCQUFxQixDQUFDO0FBQy9DLE9BQU8sT0FBTyxNQUFNLGdCQUFnQixDQUFDO0FBQ3JDLE9BQU8sV0FBVyxNQUFNLG9CQUFvQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRzNDLE9BQU8sRUFDSCw2QkFBNkIsRUFDN0IsK0JBQStCLEVBQy9CLGdCQUFnQixFQUNoQixzQkFBc0IsR0FDekIsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDeEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHdCQUF3QixDQUFDO0FBRXJELE9BQU8sRUFHSCxlQUFlLEdBRWxCLE1BQU0saUJBQWlCLENBQUM7QUFDekIsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGNBQWMsQ0FBQztBQU9wQyxN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Q0FBQztRQUVGLGlCQUFpQjtRQUNqQixJQUFJLENBQUMsS0FBSyxDQUFDLFdBQVcsRUFBRSxDQUFDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLElBQUksQ0FBQyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUM7SUFDeEUsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7IEJydXNoQmVoYXZpb3IsIEJydXNoU2VsZWN0aW9uLCBicnVzaFggfSBmcm9tIFwiZDMtYnJ1c2hcIjtcbmltcG9ydCB7IGV2ZW50IH0gZnJvbSBcImQzLXNlbGVjdGlvblwiO1xuaW1wb3J0IGRlZmF1bHRzRGVlcCBmcm9tIFwibG9kYXNoL2RlZmF1bHRzRGVlcFwiO1xuaW1wb3J0IGlzRW1wdHkgZnJvbSBcImxvZGFzaC9pc0VtcHR5XCI7XG5pbXBvcnQgaXNVbmRlZmluZWQgZnJvbSBcImxvZGFzaC9pc1VuZGVmaW5lZFwiO1xuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gXCJyeGpzXCI7XG5pbXBvcnQgeyB0YWtlVW50aWwgfSBmcm9tIFwicnhqcy9vcGVyYXRvcnNcIjtcblxuaW1wb3J0IHsgSUludGVyYWN0aW9uQ29vcmRpbmF0ZXNQYXlsb2FkIH0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7XG4gICAgSU5URVJBQ1RJT05fQ09PUkRJTkFURVNfRVZFTlQsXG4gICAgSU5URVJBQ1RJT05fVkFMVUVTX0FDVElWRV9FVkVOVCxcbiAgICBTRVRfRE9NQUlOX0VWRU5ULFxuICAgIFNUQU5EQVJEX1JFTkRFUl9MQVlFUlMsXG59IGZyb20gXCIuLi8uLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IFJlbmRlckxheWVyTmFtZSB9IGZyb20gXCIuLi8uLi9yZW5kZXJlcnMvdHlwZXNcIjtcbmltcG9ydCB7IENoYXJ0UGx1Z2luIH0gZnJvbSBcIi4uL2NvbW1vbi9jaGFydC1wbHVnaW5cIjtcbmltcG9ydCB7IElTY2FsZSB9IGZyb20gXCIuLi9jb21tb24vc2NhbGVzL3R5cGVzXCI7XG5pbXBvcnQge1xuICAgIEQzU2VsZWN0aW9uLFxuICAgIElDaGFydEV2ZW50LFxuICAgIEludGVyYWN0aW9uVHlwZSxcbiAgICBJU2V0RG9tYWluRXZlbnRQYXlsb2FkLFxufSBmcm9tIFwiLi4vY29tbW9uL3R5cGVzXCI7XG5pbXBvcnQgeyBHcmlkIH0gZnJvbSBcIi4uL2dyaWQvZ3JpZFwiO1xuaW1wb3J0IHsgWFlHcmlkIH0gZnJvbSBcIi4uL2dyaWQveHktZ3JpZFwiO1xuXG5leHBvcnQgaW50ZXJmYWNlIElab29tUGx1Z2luQ29uZmlndXJhdGlvbiB7XG4gICAgZW5hYmxlRXh0ZXJuYWxFdmVudHM/OiBib29sZWFuO1xufVxuXG5leHBvcnQgY2xhc3MgWm9vbVBsdWdpbiBleHRlbmRzIENoYXJ0UGx1Z2luIHtcbiAgICAvLyAqTm90ZToqIFRoaXMgcGx1Z2luIG1hbnVhbGx5IG1vdmVzIHRoZSBkMyBicnVzaCBhY3Jvc3MgdGhlIHNjcmVlbiB0byBhY2NvbW1vZGF0ZSBhIGtub3duIEZpcmVmb3hcbiAgICAvLyBidWcgaW4gd2hpY2ggbW91c2UgZXZlbnRzIHJlcG9ydCBhbiBpbmNvcnJlY3QgcG9pbnRlciBwb3NpdGlvbiBmb3Igc3ZnIGNoaWxkcmVuIG9mIGFuIGVsZW1lbnRcbiAgICAvLyB0cmFuc2Zvcm1lZCBieSBhIHRyYW5zbGF0ZSBmdW5jdGlvbjogaHR0cHM6Ly9naXRodWIuY29tL2QzL2QzLXNlbGVjdGlvbi9pc3N1ZXMvODFcblxuICAgIHB1YmxpYyBzdGF0aWMgTEFZRVJfTkFNRSA9IFwiem9vbS1icnVzaFwiO1xuICAgIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgREVGQVVMVF9DT05GSUc6IElab29tUGx1Z2luQ29uZmlndXJhdGlvbiA9IHtcbiAgICAgICAgZW5hYmxlRXh0ZXJuYWxFdmVudHM6IGZhbHNlLFxuICAgIH07XG5cbiAgICBwcml2YXRlIGdyaWQ6IFhZR3JpZDtcbiAgICBwcml2YXRlIGJydXNoOiBCcnVzaEJlaGF2aW9yPGFueT47XG4gICAgcHJpdmF0ZSB6b29tQnJ1c2hMYXllcjogRDNTZWxlY3Rpb247XG4gICAgcHJpdmF0ZSBicnVzaEVsZW1lbnQ6IEQzU2VsZWN0aW9uPFNWR0dFbGVtZW50PjtcbiAgICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcbiAgICBwcml2YXRlIGJydXNoU3RhcnRYOiBudW1iZXIgfCB1bmRlZmluZWQ7XG4gICAgcHJpdmF0ZSBpbnRlcmFjdGlvbkhhbmRsZXJNYXA6IFJlY29yZDxzdHJpbmcsIEZ1bmN0aW9uPjtcblxuICAgIGNvbnN0cnVjdG9yKHB1YmxpYyBjb25maWc6IElab29tUGx1Z2luQ29uZmlndXJhdGlvbiA9IHt9KSB7XG4gICAgICAgIHN1cGVyKCk7XG4gICAgICAgIHRoaXMuY29uZmlnID0gZGVmYXVsdHNEZWVwKHRoaXMuY29uZmlnLCBab29tUGx1Z2luLkRFRkFVTFRfQ09ORklHKTtcbiAgICAgICAgdGhpcy5pbnRlcmFjdGlvbkhhbmRsZXJNYXAgPSB7XG4gICAgICAgICAgICBbSW50ZXJhY3Rpb25UeXBlLk1vdXNlRG93bl06IHRoaXMuYnJ1c2hTdGFydCxcbiAgICAgICAgICAgIFtJbnRlcmFjdGlvblR5cGUuTW91c2VNb3ZlXTogdGhpcy5icnVzaE1vdmUsXG4gICAgICAgICAgICBbSW50ZXJhY3Rpb25UeXBlLk1vdXNlVXBdOiB0aGlzLmJydXNoRW5kLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHB1YmxpYyBpbml0aWFsaXplKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmdyaWQgPSB0aGlzLmNoYXJ0LmdldEdyaWQoKSBhcyBYWUdyaWQ7XG4gICAgICAgIHRoaXMuem9vbUJydXNoTGF5ZXIgPSB0aGlzLmdyaWQuZ2V0TGFzYWduYSgpLmFkZExheWVyKHtcbiAgICAgICAgICAgIG5hbWU6IFpvb21QbHVnaW4uTEFZRVJfTkFNRSxcbiAgICAgICAgICAgIC8vIGFkZCAxIHRvIHRoZSBmb3JlZ3JvdW5kIGxheWVyJ3Mgb3JkZXIgdG8gZW5zdXJlIHRoZSBicnVzaCBpcyByZW5kZXJlZCBpbiBmcm9udCBvZiBpdFxuICAgICAgICAgICAgb3JkZXI6IFNUQU5EQVJEX1JFTkRFUl9MQVlFUlNbUmVuZGVyTGF5ZXJOYW1lLmZvcmVncm91bmRdLm9yZGVyICsgMSxcbiAgICAgICAgICAgIGNsaXBwZWQ6IHRydWUsXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMuY2hhcnRcbiAgICAgICAgICAgIC5nZXRFdmVudEJ1cygpXG4gICAgICAgICAgICAuZ2V0U3RyZWFtKElOVEVSQUNUSU9OX0NPT1JESU5BVEVTX0VWRU5UKVxuICAgICAgICAgICAgLnBpcGUodGFrZVVudGlsKHRoaXMuZGVzdHJveSQpKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoY2hhcnRFdmVudDogSUNoYXJ0RXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoY2hhcnRFdmVudC5icm9hZGNhc3QgJiYgIXRoaXMuY29uZmlnLmVuYWJsZUV4dGVybmFsRXZlbnRzKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBjb25zdCBkYXRhOiBJSW50ZXJhY3Rpb25Db29yZGluYXRlc1BheWxvYWQgPSBjaGFydEV2ZW50LmRhdGE7XG4gICAgICAgICAgICAgICAgaWYgKGlzRW1wdHkodGhpcy5ncmlkLnNjYWxlcykgfHwgaXNFbXB0eShkYXRhLmNvb3JkaW5hdGVzKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuaW50ZXJhY3Rpb25IYW5kbGVyTWFwW2RhdGEuaW50ZXJhY3Rpb25UeXBlXSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB4Q29vcmQgPSBkYXRhLmNvb3JkaW5hdGVzICYmIGRhdGEuY29vcmRpbmF0ZXMueDtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pbnRlcmFjdGlvbkhhbmRsZXJNYXBbZGF0YS5pbnRlcmFjdGlvblR5cGVdKHhDb29yZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5icnVzaCA9IGJydXNoWCgpO1xuICAgICAgICB0aGlzLmJydXNoRWxlbWVudCA9IHRoaXMuem9vbUJydXNoTGF5ZXJcbiAgICAgICAgICAgIC5hcHBlbmQoXCJnXCIpXG4gICAgICAgICAgICAuYXR0cihcImNsYXNzXCIsIFwiYnJ1c2hcIik7XG5cbiAgICAgICAgLy8gZW5nYWdlIHBvaW50ZXIgY2FwdHVyZSB0byBjb25maW5lIG1vdXNlIGV2ZW50cyB0byB0aGUgaW50ZXJhY3RpdmUgYXJlYVxuICAgICAgICAvLyAoaW4gb3RoZXIgd29yZHMsIGlmIHRoZSAnbW91c2V1cCcgaXMgcGh5c2ljYWxseSB0cmlnZ2VyZWQgb3V0c2lkZSB0aGUgaW50ZXJhY3RpdmUgYXJlYSxcbiAgICAgICAgLy8gdGhlIHBvaW50ZXIgY2FwdHVyZSBhbGxvd3MgdXMgdG8gc3RpbGwgem9vbSBiYXNlZCBvbiB0aGF0IGV2ZW50KVxuICAgICAgICB0aGlzLmNoYXJ0XG4gICAgICAgICAgICAuZ2V0R3JpZCgpXG4gICAgICAgICAgICAuZ2V0SW50ZXJhY3RpdmVBcmVhKClcbiAgICAgICAgICAgIC5vbihcInBvaW50ZXJkb3duXCIsICgpID0+XG4gICAgICAgICAgICAgICAgZXZlbnQudGFyZ2V0LnNldFBvaW50ZXJDYXB0dXJlKGV2ZW50LnBvaW50ZXJJZClcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC5vbihcInBvaW50ZXJ1cFwiLCAoKSA9PlxuICAgICAgICAgICAgICAgIGV2ZW50LnRhcmdldC5yZWxlYXNlUG9pbnRlckNhcHR1cmUoZXZlbnQucG9pbnRlcklkKVxuICAgICAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgdXBkYXRlRGltZW5zaW9ucygpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgZGltZW5zaW9uID0gdGhpcy5ncmlkLmNvbmZpZygpLmRpbWVuc2lvbjtcblxuICAgICAgICAvLyBzZXQgdGhlIGJydXNoIGFyZWEncyBkaW1lbnNpb25zXG4gICAgICAgIHRoaXMuYnJ1c2guZXh0ZW50KFtcbiAgICAgICAgICAgIFswLCAwXSxcbiAgICAgICAgICAgIFtkaW1lbnNpb24ud2lkdGgoKSwgZGltZW5zaW9uLmhlaWdodCgpXSxcbiAgICAgICAgXSk7XG5cbiAgICAgICAgLy8gcmVuZGVyIHRoZSBicnVzaCBhcmVhIGFmdGVyIHdlIGhhdmUgZGltZW5zaW9uc1xuICAgICAgICB0aGlzLmJydXNoKHRoaXMuem9vbUJydXNoTGF5ZXIuc2VsZWN0KFwiLmJydXNoXCIpKTtcblxuICAgICAgICAvLyBwcmV2ZW50IHRoZSBicnVzaCBmcm9tIGhhbmRsaW5nIGl0cyBvd24gcG9pbnRlciBldmVudHNcbiAgICAgICAgdGhpcy5icnVzaEVsZW1lbnQuc2VsZWN0KFwiLm92ZXJsYXlcIikuc3R5bGUoXCJwb2ludGVyLWV2ZW50c1wiLCBcIm5vbmVcIik7XG5cbiAgICAgICAgLy8gcmVtb3ZlIHN0cm9rZSBwZXIgbW9ja3Vwc1xuICAgICAgICB0aGlzLmJydXNoRWxlbWVudC5zZWxlY3QoXCIuc2VsZWN0aW9uXCIpLmF0dHIoXCJzdHJva2VcIiwgbnVsbCk7XG4gICAgfVxuXG4gICAgcHVibGljIGRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZ3JpZC5nZXRMYXNhZ25hKCkucmVtb3ZlTGF5ZXIoWm9vbVBsdWdpbi5MQVlFUl9OQU1FKTtcbiAgICAgICAgdGhpcy5kZXN0cm95JC5uZXh0KCk7XG4gICAgICAgIHRoaXMuZGVzdHJveSQuY29tcGxldGUoKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGJydXNoU3RhcnQgPSAoeENvb3JkOiBudW1iZXIpID0+IHtcbiAgICAgICAgaWYgKCFpc1VuZGVmaW5lZCh0aGlzLmJydXNoU3RhcnRYKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5jaGFydFxuICAgICAgICAgICAgLmdldEV2ZW50QnVzKClcbiAgICAgICAgICAgIC5nZXRTdHJlYW0oSU5URVJBQ1RJT05fVkFMVUVTX0FDVElWRV9FVkVOVClcbiAgICAgICAgICAgIC5uZXh0KHsgZGF0YTogZmFsc2UgfSk7XG4gICAgICAgIHRoaXMuYnJ1c2hTdGFydFggPSB4Q29vcmQ7XG4gICAgfTtcblxuICAgIHByaXZhdGUgYnJ1c2hNb3ZlID0gKHhDb29yZDogbnVtYmVyKSA9PiB7XG4gICAgICAgIGlmIChpc1VuZGVmaW5lZCh0aGlzLmJydXNoU3RhcnRYKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qgc2VsZWN0aW9uID0gW3RoaXMuYnJ1c2hTdGFydFgsIHhDb29yZF0uc29ydCgoYSwgYikgPT4gYSAtIGIpO1xuICAgICAgICB0aGlzLmJydXNoLm1vdmUodGhpcy5icnVzaEVsZW1lbnQsIHNlbGVjdGlvbiBhcyBCcnVzaFNlbGVjdGlvbik7XG4gICAgfTtcblxuICAgIHByaXZhdGUgYnJ1c2hFbmQgPSAoeENvb3JkOiBudW1iZXIpID0+IHtcbiAgICAgICAgaWYgKGlzVW5kZWZpbmVkKHRoaXMuYnJ1c2hTdGFydFgpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBzZWxlY3Rpb24gPSBbdGhpcy5icnVzaFN0YXJ0WCwgeENvb3JkXS5zb3J0KChhLCBiKSA9PiBhIC0gYik7XG4gICAgICAgIHRoaXMuYnJ1c2hTdGFydFggPSB1bmRlZmluZWQ7XG4gICAgICAgIHRoaXMuY2hhcnRcbiAgICAgICAgICAgIC5nZXRFdmVudEJ1cygpXG4gICAgICAgICAgICAuZ2V0U3RyZWFtKElOVEVSQUNUSU9OX1ZBTFVFU19BQ1RJVkVfRVZFTlQpXG4gICAgICAgICAgICAubmV4dCh7IGRhdGE6IHRydWUgfSk7XG5cbiAgICAgICAgLy8gcmVtb3ZlIHRoZSBicnVzaFxuICAgICAgICB0aGlzLmJydXNoLm1vdmUodGhpcy5icnVzaEVsZW1lbnQsIG51bGwpO1xuXG4gICAgICAgIGNvbnN0IHhTY2FsZXMgPSB0aGlzLmdyaWQuc2NhbGVzLngubGlzdDtcbiAgICAgICAgaWYgKCF4U2NhbGVzIHx8IHNlbGVjdGlvblswXSA9PT0gc2VsZWN0aW9uWzFdKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBsZXQgd2lkdGhDb3JyZWN0aW9uID0gMDtcbiAgICAgICAgY29uc3QgZ3JpZENvbmZpZyA9IHRoaXMuZ3JpZC5jb25maWcoKTtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgIWdyaWRDb25maWcuZGlzYWJsZVJlbmRlckFyZWFXaWR0aENvcnJlY3Rpb24gJiZcbiAgICAgICAgICAgIHNlbGVjdGlvblsxXSA9PT1cbiAgICAgICAgICAgICAgICBncmlkQ29uZmlnLmRpbWVuc2lvbi53aWR0aCgpIC0gR3JpZC5SRU5ERVJfQVJFQV9XSURUSF9DT1JSRUNUSU9OXG4gICAgICAgICkge1xuICAgICAgICAgICAgLy8gV2lkdGggY29ycmVjdGlvbiB0byBhY2NvbW1vZGF0ZSBzaW1pbGFyIGFkanVzdG1lbnQgaW4gZ3JpZC4gVGhpcyBlbnN1cmVzIHRoYXQgdGhlIHJpZ2h0LW1vc3QgY29sdW1uIG9mIHBpeGVscyBvbiB0aGUgY2hhcnQgaXMgc2VsZWN0YWJsZS5cbiAgICAgICAgICAgIHdpZHRoQ29ycmVjdGlvbiA9IEdyaWQuUkVOREVSX0FSRUFfV0lEVEhfQ09SUkVDVElPTjtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGRhdGE6IElTZXREb21haW5FdmVudFBheWxvYWQgPSB4U2NhbGVzLnJlZHVjZShcbiAgICAgICAgICAgIChyZXN1bHQsIG5leHQ6IElTY2FsZTxhbnk+KSA9PiB7XG4gICAgICAgICAgICAgICAgcmVzdWx0W25leHQuaWRdID0gW1xuICAgICAgICAgICAgICAgICAgICBzZWxlY3Rpb25bMF0sXG4gICAgICAgICAgICAgICAgICAgIChzZWxlY3Rpb25bMV0gYXMgbnVtYmVyKSArIHdpZHRoQ29ycmVjdGlvbixcbiAgICAgICAgICAgICAgICBdLm1hcCgoeCkgPT4gbmV4dC5pbnZlcnQoeCBhcyBudW1iZXIpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIDxJU2V0RG9tYWluRXZlbnRQYXlsb2FkPnt9XG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gem9vbSB0aGUgY2hhcnRcbiAgICAgICAgdGhpcy5jaGFydC5nZXRFdmVudEJ1cygpLmdldFN0cmVhbShTRVRfRE9NQUlOX0VWRU5UKS5uZXh0KHsgZGF0YSB9KTtcbiAgICB9O1xufVxuIl19