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

204 lines 28.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 { select } from "d3-selection"; import each from "lodash/each"; import { BehaviorSubject, Subject } from "rxjs"; import { takeUntil } from "rxjs/operators"; import { DESTROY_EVENT, SERIES_STATE_CHANGE_EVENT } from "../constants"; import { DataManager } from "./common/data-manager"; import { EventBus } from "./common/event-bus"; import { RenderEngine } from "./common/render-engine"; import { RenderEnginePlugin } from "./plugins/render-engine-plugin"; import { CssFilterId, GRAYSCALE_COLOR_MATRIX } from "./types"; export class Chart { grid; configuration; eventBus = new EventBus(); element; target; filterDefs; dataManager; // TODO: interface renderEngine; // TODO: interface updateSubject = new BehaviorSubject([]); updateDimensionsSubject = new Subject(); seriesStatesSubject = new BehaviorSubject([]); plugins = []; constructor(grid, configuration) { this.grid = grid; this.configuration = configuration; if (!grid) { throw new Error("Grid has to be defined!"); } grid.updateChartDimensionsSubject = this.updateDimensionsSubject; grid.eventBus = this.eventBus; } getEventBus() { return this.eventBus; } getDataManager() { return this.dataManager; } getRenderEngine() { return this.renderEngine; } getGrid() { return this.grid; } addPlugin(plugin) { plugin.chart = this; this.plugins.push(plugin); } removePlugin(classRef) { const pluginIndex = this.plugins.findIndex((plugin) => plugin instanceof classRef); if (-1 !== pluginIndex) { this.plugins[pluginIndex].destroy(); this.plugins.splice(pluginIndex, 1); } } addPlugins(...plugins) { for (const plugin of plugins) { this.addPlugin(plugin); } } removePlugins(...classRefs) { for (const classRef of classRefs) { this.removePlugin(classRef); } } hasPlugin(classRef) { return (-1 !== this.plugins.findIndex((plugin) => plugin instanceof classRef)); } build(element) { this.element = element; // @ts-ignore: Workaround to avoid strict build crash because of type this.target = select(this.element) .append("svg") .attrs({ class: "nui-chart", height: "100%", width: "100%", }); this.configureCssFilters(); this.buildGrid(); this.dataManager = this.buildDataManager(); this.renderEngine = this.buildRenderEngine(this.grid.getLasagna(), this.dataManager); // Put the render engine at the front of the list since other plugins may be relying on renderers to be updated first const renderEnginePlugin = new RenderEnginePlugin(); renderEnginePlugin.chart = this; this.plugins.unshift(renderEnginePlugin); for (const gridPlugin of this.getGrid().buildPlugins(this)) { this.addPlugin(gridPlugin); } this.initialize(); const untilDestroy = () => takeUntil(this.getEventBus().getStream(DESTROY_EVENT)); this.updateSubject .pipe(untilDestroy()) .subscribe((d) => this.onUpdate(d)); this.updateDimensionsSubject .pipe(untilDestroy()) .subscribe(() => this.onUpdateDimensions()); this.seriesStatesSubject .pipe(untilDestroy()) .subscribe((rs) => this.onSetSeriesStates(rs)); } configureCssFilters() { this.filterDefs = this.target?.append("defs"); // filter for applying a grayscale appearance to svg elements this.filterDefs ?.append("filter") .attr("id", CssFilterId.Grayscale) .append("feColorMatrix") .attr("type", "matrix") .attr("values", GRAYSCALE_COLOR_MATRIX); } buildDataManager() { return new DataManager(this); } buildGrid() { if (this.target) { this.grid.target(this.target); this.grid.build(); this.updateTargetDimensions(this.grid.config().dimension); } } buildRenderEngine(lasagna, dataManager) { return new RenderEngine(lasagna, dataManager); } update(seriesSet) { this.updateSubject.next(seriesSet); } updateDimensions() { this.updateDimensionsSubject.next(); } initialize() { each(this.plugins, (p) => { p.initialize(); }); } destroy() { this.eventBus.getStream(DESTROY_EVENT).next({ data: null }); this.eventBus.destroy(); this.plugins.forEach((p) => p.destroy()); this.target?.remove(); this.target = undefined; } setSeriesStates(renderStateData) { this.seriesStatesSubject.next(renderStateData); this.eventBus .getStream(SERIES_STATE_CHANGE_EVENT) .next({ data: renderStateData }); } onUpdate(seriesSet) { this.dataManager.update(seriesSet); this.grid.scales = this.dataManager.scalesIndexByKey; this.dataManager.updateScaleDomains(); this.grid.updateRanges(); this.plugins.forEach((p) => p.update()); } onUpdateDimensions() { const dimensionConfig = this.grid.config().dimension; // if the chart is reused with different grid dimensions, the chart's container dimensions need to be adjusted as well this.updateTargetDimensions(dimensionConfig); const dimensions = {}; if (dimensionConfig.autoHeight) { dimensions.height = this.element.clientHeight; } if (dimensionConfig.autoWidth) { dimensions.width = this.element.clientWidth; } this.grid.updateDimensions(dimensions); this.plugins.forEach((p) => p.updateDimensions()); } updateTargetDimensions(dimensionConfig) { if (!dimensionConfig.autoHeight) { // use style instead of attr to override css style this.target?.style("height", dimensionConfig.outerHeight() + "px"); } if (!dimensionConfig.autoWidth) { // use style instead of attr to override css style this.target?.style("width", dimensionConfig.outerWidth() + "px"); } } onSetSeriesStates(renderStateData) { this.renderEngine.setSeriesStates(renderStateData); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29yZS9jaGFydC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx5REFBeUQ7QUFDekQsRUFBRTtBQUNGLCtFQUErRTtBQUMvRSw0RUFBNEU7QUFDNUUsOEVBQThFO0FBQzlFLCtFQUErRTtBQUMvRSw4RUFBOEU7QUFDOUUsNERBQTREO0FBQzVELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsdURBQXVEO0FBQ3ZELEVBQUU7QUFDRiw2RUFBNkU7QUFDN0UsNEVBQTRFO0FBQzVFLCtFQUErRTtBQUMvRSwwRUFBMEU7QUFDMUUsaUZBQWlGO0FBQ2pGLDZFQUE2RTtBQUM3RSxpQkFBaUI7QUFFakIsT0FBTyxFQUFFLE1BQU0sRUFBYSxNQUFNLGNBQWMsQ0FBQztBQUNqRCxPQUFPLElBQUksTUFBTSxhQUFhLENBQUM7QUFDL0IsT0FBTyxFQUFFLGVBQWUsRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDaEQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTNDLE9BQU8sRUFBRSxhQUFhLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFeEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQ3BELE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUU5QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFZdEQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDcEUsT0FBTyxFQUFFLFdBQVcsRUFBRSxzQkFBc0IsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUU5RCxNQUFNLE9BQU8sS0FBSztJQWdCRjtJQUNEO0lBaEJLLFFBQVEsR0FBRyxJQUFJLFFBQVEsRUFBZSxDQUFDO0lBQ2hELE9BQU8sQ0FBYztJQUNyQixNQUFNLENBQThCO0lBQ3BD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QUFDO0lBRU8saUJBQWlCLENBQUMsZUFBbUM7UUFDekQsSUFBSSxDQUFDLFlBQVksQ0FBQyxlQUFlLENBQUMsZUFBZSxDQUFDLENBQUM7SUFDdkQsQ0FBQztDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiLy8gwqkgMjAyMiBTb2xhcldpbmRzIFdvcmxkd2lkZSwgTExDLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vICBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0b1xuLy8gIGRlYWwgaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlXG4vLyAgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yXG4vLyAgc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vICBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyAgYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vICBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vICBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7IHNlbGVjdCwgU2VsZWN0aW9uIH0gZnJvbSBcImQzLXNlbGVjdGlvblwiO1xuaW1wb3J0IGVhY2ggZnJvbSBcImxvZGFzaC9lYWNoXCI7XG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIFN1YmplY3QgfSBmcm9tIFwicnhqc1wiO1xuaW1wb3J0IHsgdGFrZVVudGlsIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XG5cbmltcG9ydCB7IERFU1RST1lfRVZFTlQsIFNFUklFU19TVEFURV9DSEFOR0VfRVZFTlQgfSBmcm9tIFwiLi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBDaGFydFBsdWdpbiB9IGZyb20gXCIuL2NvbW1vbi9jaGFydC1wbHVnaW5cIjtcbmltcG9ydCB7IERhdGFNYW5hZ2VyIH0gZnJvbSBcIi4vY29tbW9uL2RhdGEtbWFuYWdlclwiO1xuaW1wb3J0IHsgRXZlbnRCdXMgfSBmcm9tIFwiLi9jb21tb24vZXZlbnQtYnVzXCI7XG5pbXBvcnQgeyBMYXNhZ25hIH0gZnJvbSBcIi4vY29tbW9uL2xhc2FnbmFcIjtcbmltcG9ydCB7IFJlbmRlckVuZ2luZSB9IGZyb20gXCIuL2NvbW1vbi9yZW5kZXItZW5naW5lXCI7XG5pbXBvcnQge1xuICAgIEQzU2VsZWN0aW9uLFxuICAgIElBY2Nlc3NvcnMsXG4gICAgSUNoYXJ0LFxuICAgIElDaGFydENvbmZpZ3VyYXRpb24sXG4gICAgSUNoYXJ0RXZlbnQsXG4gICAgSUNoYXJ0UGx1Z2luLFxuICAgIElDaGFydFNlcmllcyxcbiAgICBJUmVuZGVyU3RhdGVEYXRhLFxufSBmcm9tIFwiLi9jb21tb24vdHlwZXNcIjtcbmltcG9ydCB7IElEaW1lbnNpb25Db25maWcsIElEaW1lbnNpb25zLCBJR3JpZCB9IGZyb20gXCIuL2dyaWQvdHlwZXNcIjtcbmltcG9ydCB7IFJlbmRlckVuZ2luZVBsdWdpbiB9IGZyb20gXCIuL3BsdWdpbnMvcmVuZGVyLWVuZ2luZS1wbHVnaW5cIjtcbmltcG9ydCB7IENzc0ZpbHRlcklkLCBHUkFZU0NBTEVfQ09MT1JfTUFUUklYIH0gZnJvbSBcIi4vdHlwZXNcIjtcblxuZXhwb3J0IGNsYXNzIENoYXJ0IGltcGxlbWVudHMgSUNoYXJ0IHtcbiAgICBwdWJsaWMgcmVhZG9ubHkgZXZlbnRCdXMgPSBuZXcgRXZlbnRCdXM8SUNoYXJ0RXZlbnQ+KCk7XG4gICAgcHVibGljIGVsZW1lbnQ6IEhUTUxFbGVtZW50O1xuICAgIHB1YmxpYyB0YXJnZXQ/OiBEM1NlbGVjdGlvbjxTVkdTVkdFbGVtZW50PjtcbiAgICBwdWJsaWMgZmlsdGVyRGVmcz86IFNlbGVjdGlvbjxTVkdEZWZzRWxlbWVudCwgYW55LCBTVkdFbGVtZW50LCBhbnk+O1xuXG4gICAgcHJpdmF0ZSBkYXRhTWFuYWdlcjogRGF0YU1hbmFnZXI7IC8vIFRPRE86IGludGVyZmFjZVxuICAgIHByaXZhdGUgcmVuZGVyRW5naW5lOiBSZW5kZXJFbmdpbmU7IC8vIFRPRE86IGludGVyZmFjZVxuXG4gICAgcHJpdmF0ZSB1cGRhdGVTdWJqZWN0ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxJQ2hhcnRTZXJpZXM8SUFjY2Vzc29ycz5bXT4oW10pO1xuICAgIHByaXZhdGUgdXBkYXRlRGltZW5zaW9uc1N1YmplY3QgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xuICAgIHByaXZhdGUgc2VyaWVzU3RhdGVzU3ViamVjdCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8SVJlbmRlclN0YXRlRGF0YVtdPihbXSk7XG5cbiAgICBwcml2YXRlIHBsdWdpbnM6IElDaGFydFBsdWdpbltdID0gW107XG5cbiAgICBjb25zdHJ1Y3RvcihcbiAgICAgICAgcHJpdmF0ZSBncmlkOiBJR3JpZCxcbiAgICAgICAgcHVibGljIGNvbmZpZ3VyYXRpb24/OiBJQ2hhcnRDb25maWd1cmF0aW9uXG4gICAgKSB7XG4gICAgICAgIGlmICghZ3JpZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiR3JpZCBoYXMgdG8gYmUgZGVmaW5lZCFcIik7XG4gICAgICAgIH1cbiAgICAgICAgZ3JpZC51cGRhdGVDaGFydERpbWVuc2lvbnNTdWJqZWN0ID0gdGhpcy51cGRhdGVEaW1lbnNpb25zU3ViamVjdDtcbiAgICAgICAgZ3JpZC5ldmVudEJ1cyA9IHRoaXMuZXZlbnRCdXM7XG4gICAgfVxuXG4gICAgcHVibGljIGdldEV2ZW50QnVzKCk6IEV2ZW50QnVzPElDaGFydEV2ZW50PiB7XG4gICAgICAgIHJldHVybiB0aGlzLmV2ZW50QnVzO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXREYXRhTWFuYWdlcigpOiBEYXRhTWFuYWdlciB7XG4gICAgICAgIHJldHVybiB0aGlzLmRhdGFNYW5hZ2VyO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRSZW5kZXJFbmdpbmUoKTogUmVuZGVyRW5naW5lIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVuZGVyRW5naW5lO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXRHcmlkKCk6IElHcmlkIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ3JpZDtcbiAgICB9XG5cbiAgICBwdWJsaWMgYWRkUGx1Z2luKHBsdWdpbjogSUNoYXJ0UGx1Z2luKTogdm9pZCB7XG4gICAgICAgIHBsdWdpbi5jaGFydCA9IHRoaXM7XG4gICAgICAgIHRoaXMucGx1Z2lucy5wdXNoKHBsdWdpbik7XG4gICAgfVxuXG4gICAgcHVibGljIHJlbW92ZVBsdWdpbihjbGFzc1JlZjogdHlwZW9mIENoYXJ0UGx1Z2luKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHBsdWdpbkluZGV4ID0gdGhpcy5wbHVnaW5zLmZpbmRJbmRleChcbiAgICAgICAgICAgIChwbHVnaW4pID0+IHBsdWdpbiBpbnN0YW5jZW9mIGNsYXNzUmVmXG4gICAgICAgICk7XG4gICAgICAgIGlmICgtMSAhPT0gcGx1Z2luSW5kZXgpIHtcbiAgICAgICAgICAgIHRoaXMucGx1Z2luc1twbHVnaW5JbmRleF0uZGVzdHJveSgpO1xuICAgICAgICAgICAgdGhpcy5wbHVnaW5zLnNwbGljZShwbHVnaW5JbmRleCwgMSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgYWRkUGx1Z2lucyguLi5wbHVnaW5zOiBJQ2hhcnRQbHVnaW5bXSk6IHZvaWQge1xuICAgICAgICBmb3IgKGNvbnN0IHBsdWdpbiBvZiBwbHVnaW5zKSB7XG4gICAgICAgICAgICB0aGlzLmFkZFBsdWdpbihwbHVnaW4pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHVibGljIHJlbW92ZVBsdWdpbnMoLi4uY2xhc3NSZWZzOiAodHlwZW9mIENoYXJ0UGx1Z2luKVtdKTogdm9pZCB7XG4gICAgICAgIGZvciAoY29uc3QgY2xhc3NSZWYgb2YgY2xhc3NSZWZzKSB7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZVBsdWdpbihjbGFzc1JlZik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwdWJsaWMgaGFzUGx1Z2luKGNsYXNzUmVmOiB0eXBlb2YgQ2hhcnRQbHVnaW4pOiBib29sZWFuIHtcbiAgICAgICAgcmV0dXJuIChcbiAgICAgICAgICAgIC0xICE9PVxuICAgICAgICAgICAgdGhpcy5wbHVnaW5zLmZpbmRJbmRleCgocGx1Z2luKSA9PiBwbHVnaW4gaW5zdGFuY2VvZiBjbGFzc1JlZilcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgYnVpbGQoZWxlbWVudDogSFRNTEVsZW1lbnQpOiB2b2lkIHtcbiAgICAgICAgdGhpcy5lbGVtZW50ID0gZWxlbWVudDtcblxuICAgICAgICAvLyBAdHMtaWdub3JlOiBXb3JrYXJvdW5kIHRvIGF2b2lkIHN0cmljdCBidWlsZCBjcmFzaCBiZWNhdXNlIG9mIHR5cGVcbiAgICAgICAgdGhpcy50YXJnZXQgPSBzZWxlY3Q8SFRNTEVsZW1lbnQsIFNWR0VsZW1lbnQ+KHRoaXMuZWxlbWVudClcbiAgICAgICAgICAgIC5hcHBlbmQoXCJzdmdcIilcbiAgICAgICAgICAgIC5hdHRycyh7XG4gICAgICAgICAgICAgICAgY2xhc3M6IFwibnVpLWNoYXJ0XCIsXG4gICAgICAgICAgICAgICAgaGVpZ2h0OiBcIjEwMCVcIixcbiAgICAgICAgICAgICAgICB3aWR0aDogXCIxMDAlXCIsXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLmNvbmZpZ3VyZUNzc0ZpbHRlcnMoKTtcbiAgICAgICAgdGhpcy5idWlsZEdyaWQoKTtcblxuICAgICAgICB0aGlzLmRhdGFNYW5hZ2VyID0gdGhpcy5idWlsZERhdGFNYW5hZ2VyKCk7XG4gICAgICAgIHRoaXMucmVuZGVyRW5naW5lID0gdGhpcy5idWlsZFJlbmRlckVuZ2luZShcbiAgICAgICAgICAgIHRoaXMuZ3JpZC5nZXRMYXNhZ25hKCksXG4gICAgICAgICAgICB0aGlzLmRhdGFNYW5hZ2VyXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gUHV0IHRoZSByZW5kZXIgZW5naW5lIGF0IHRoZSBmcm9udCBvZiB0aGUgbGlzdCBzaW5jZSBvdGhlciBwbHVnaW5zIG1heSBiZSByZWx5aW5nIG9uIHJlbmRlcmVycyB0byBiZSB1cGRhdGVkIGZpcnN0XG4gICAgICAgIGNvbnN0IHJlbmRlckVuZ2luZVBsdWdpbiA9IG5ldyBSZW5kZXJFbmdpbmVQbHVnaW4oKTtcbiAgICAgICAgcmVuZGVyRW5naW5lUGx1Z2luLmNoYXJ0ID0gdGhpcztcbiAgICAgICAgdGhpcy5wbHVnaW5zLnVuc2hpZnQocmVuZGVyRW5naW5lUGx1Z2luKTtcblxuICAgICAgICBmb3IgKGNvbnN0IGdyaWRQbHVnaW4gb2YgdGhpcy5nZXRHcmlkKCkuYnVpbGRQbHVnaW5zKHRoaXMpKSB7XG4gICAgICAgICAgICB0aGlzLmFkZFBsdWdpbihncmlkUGx1Z2luKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuaW5pdGlhbGl6ZSgpO1xuXG4gICAgICAgIGNvbnN0IHVudGlsRGVzdHJveSA9IDxUPigpID0+XG4gICAgICAgICAgICB0YWtlVW50aWw8VD4odGhpcy5nZXRFdmVudEJ1cygpLmdldFN0cmVhbShERVNUUk9ZX0VWRU5UKSk7XG4gICAgICAgIHRoaXMudXBkYXRlU3ViamVjdFxuICAgICAgICAgICAgLnBpcGUodW50aWxEZXN0cm95KCkpXG4gICAgICAgICAgICAuc3Vic2NyaWJlKChkOiBJQ2hhcnRTZXJpZXM8SUFjY2Vzc29ycz5bXSkgPT4gdGhpcy5vblVwZGF0ZShkKSk7XG4gICAgICAgIHRoaXMudXBkYXRlRGltZW5zaW9uc1N1YmplY3RcbiAgICAgICAgICAgIC5waXBlKHVudGlsRGVzdHJveSgpKVxuICAgICAgICAgICAgLnN1YnNjcmliZSgoKSA9PiB0aGlzLm9uVXBkYXRlRGltZW5zaW9ucygpKTtcbiAgICAgICAgdGhpcy5zZXJpZXNTdGF0ZXNTdWJqZWN0XG4gICAgICAgICAgICAucGlwZSh1bnRpbERlc3Ryb3koKSlcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKHJzOiBJUmVuZGVyU3RhdGVEYXRhW10pID0+IHRoaXMub25TZXRTZXJpZXNTdGF0ZXMocnMpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGNvbmZpZ3VyZUNzc0ZpbHRlcnMoKSB7XG4gICAgICAgIHRoaXMuZmlsdGVyRGVmcyA9IHRoaXMudGFyZ2V0Py5hcHBlbmQoXCJkZWZzXCIpO1xuXG4gICAgICAgIC8vIGZpbHRlciBmb3IgYXBwbHlpbmcgYSBncmF5c2NhbGUgYXBwZWFyYW5jZSB0byBzdmcgZWxlbWVudHNcbiAgICAgICAgdGhpcy5maWx0ZXJEZWZzXG4gICAgICAgICAgICA/LmFwcGVuZChcImZpbHRlclwiKVxuICAgICAgICAgICAgLmF0dHIoXCJpZFwiLCBDc3NGaWx0ZXJJZC5HcmF5c2NhbGUpXG4gICAgICAgICAgICAuYXBwZW5kKFwiZmVDb2xvck1hdHJpeFwiKVxuICAgICAgICAgICAgLmF0dHIoXCJ0eXBlXCIsIFwibWF0cml4XCIpXG4gICAgICAgICAgICAuYXR0cihcInZhbHVlc1wiLCBHUkFZU0NBTEVfQ09MT1JfTUFUUklYKTtcbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYnVpbGREYXRhTWFuYWdlcigpOiBEYXRhTWFuYWdlciB7XG4gICAgICAgIHJldHVybiBuZXcgRGF0YU1hbmFnZXIodGhpcyk7XG4gICAgfVxuXG4gICAgcHJvdGVjdGVkIGJ1aWxkR3JpZCgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMudGFyZ2V0KSB7XG4gICAgICAgICAgICB0aGlzLmdyaWQudGFyZ2V0KHRoaXMudGFyZ2V0KTtcbiAgICAgICAgICAgIHRoaXMuZ3JpZC5idWlsZCgpO1xuXG4gICAgICAgICAgICB0aGlzLnVwZGF0ZVRhcmdldERpbWVuc2lvbnModGhpcy5ncmlkLmNvbmZpZygpLmRpbWVuc2lvbik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcm90ZWN0ZWQgYnVpbGRSZW5kZXJFbmdpbmUoXG4gICAgICAgIGxhc2FnbmE6IExhc2FnbmEsXG4gICAgICAgIGRhdGFNYW5hZ2VyOiBEYXRhTWFuYWdlclxuICAgICk6IFJlbmRlckVuZ2luZSB7XG4gICAgICAgIHJldHVybiBuZXcgUmVuZGVyRW5naW5lKGxhc2FnbmEsIGRhdGFNYW5hZ2VyKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgdXBkYXRlKHNlcmllc1NldDogSUNoYXJ0U2VyaWVzPElBY2Nlc3NvcnM+W10pOiB2b2lkIHtcbiAgICAgICAgdGhpcy51cGRhdGVTdWJqZWN0Lm5leHQoc2VyaWVzU2V0KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgdXBkYXRlRGltZW5zaW9ucygpOiB2b2lkIHtcbiAgICAgICAgdGhpcy51cGRhdGVEaW1lbnNpb25zU3ViamVjdC5uZXh0KCk7XG4gICAgfVxuXG4gICAgcHVibGljIGluaXRpYWxpemUoKTogdm9pZCB7XG4gICAgICAgIGVhY2godGhpcy5wbHVnaW5zLCAocDogSUNoYXJ0UGx1Z2luKSA9PiB7XG4gICAgICAgICAgICBwLmluaXRpYWxpemUoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHVibGljIGRlc3Ryb3koKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZXZlbnRCdXMuZ2V0U3RyZWFtKERFU1RST1lfRVZFTlQpLm5leHQoeyBkYXRhOiBudWxsIH0pO1xuICAgICAgICB0aGlzLmV2ZW50QnVzLmRlc3Ryb3koKTtcblxuICAgICAgICB0aGlzLnBsdWdpbnMuZm9yRWFjaCgocCkgPT4gcC5kZXN0cm95KCkpO1xuXG4gICAgICAgIHRoaXMudGFyZ2V0Py5yZW1vdmUoKTtcbiAgICAgICAgdGhpcy50YXJnZXQgPSB1bmRlZmluZWQ7XG4gICAgfVxuXG4gICAgcHVibGljIHNldFNlcmllc1N0YXRlcyhyZW5kZXJTdGF0ZURhdGE6IElSZW5kZXJTdGF0ZURhdGFbXSk6IHZvaWQge1xuICAgICAgICB0aGlzLnNlcmllc1N0YXRlc1N1YmplY3QubmV4dChyZW5kZXJTdGF0ZURhdGEpO1xuICAgICAgICB0aGlzLmV2ZW50QnVzXG4gICAgICAgICAgICAuZ2V0U3RyZWFtKFNFUklFU19TVEFURV9DSEFOR0VfRVZFTlQpXG4gICAgICAgICAgICAubmV4dCh7IGRhdGE6IHJlbmRlclN0YXRlRGF0YSB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIG9uVXBkYXRlKHNlcmllc1NldDogSUNoYXJ0U2VyaWVzPElBY2Nlc3NvcnM+W10pIHtcbiAgICAgICAgdGhpcy5kYXRhTWFuYWdlci51cGRhdGUoc2VyaWVzU2V0KTtcblxuICAgICAgICB0aGlzLmdyaWQuc2NhbGVzID0gdGhpcy5kYXRhTWFuYWdlci5zY2FsZXNJbmRleEJ5S2V5O1xuICAgICAgICB0aGlzLmRhdGFNYW5hZ2VyLnVwZGF0ZVNjYWxlRG9tYWlucygpO1xuICAgICAgICB0aGlzLmdyaWQudXBkYXRlUmFuZ2VzKCk7XG5cbiAgICAgICAgdGhpcy5wbHVnaW5zLmZvckVhY2goKHApID0+IHAudXBkYXRlKCkpO1xuICAgIH1cblxuICAgIHByaXZhdGUgb25VcGRhdGVEaW1lbnNpb25zKCkge1xuICAgICAgICBjb25zdCBkaW1lbnNpb25Db25maWcgPSB0aGlzLmdyaWQuY29uZmlnKCkuZGltZW5zaW9uO1xuXG4gICAgICAgIC8vIGlmIHRoZSBjaGFydCBpcyByZXVzZWQgd2l0aCBkaWZmZXJlbnQgZ3JpZCBkaW1lbnNpb25zLCB0aGUgY2hhcnQncyBjb250YWluZXIgZGltZW5zaW9ucyBuZWVkIHRvIGJlIGFkanVzdGVkIGFzIHdlbGxcbiAgICAgICAgdGhpcy51cGRhdGVUYXJnZXREaW1lbnNpb25zKGRpbWVuc2lvbkNvbmZpZyk7XG5cbiAgICAgICAgY29uc3QgZGltZW5zaW9uczogUGFydGlhbDxJRGltZW5zaW9ucz4gPSB7fTtcbiAgICAgICAgaWYgKGRpbWVuc2lvbkNvbmZpZy5hdXRvSGVpZ2h0KSB7XG4gICAgICAgICAgICBkaW1lbnNpb25zLmhlaWdodCA9IHRoaXMuZWxlbWVudC5jbGllbnRIZWlnaHQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRpbWVuc2lvbkNvbmZpZy5hdXRvV2lkdGgpIHtcbiAgICAgICAgICAgIGRpbWVuc2lvbnMud2lkdGggPSB0aGlzLmVsZW1lbnQuY2xpZW50V2lkdGg7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5ncmlkLnVwZGF0ZURpbWVuc2lvbnMoZGltZW5zaW9ucyk7XG5cbiAgICAgICAgdGhpcy5wbHVnaW5zLmZvckVhY2goKHApID0+IHAudXBkYXRlRGltZW5zaW9ucygpKTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHVwZGF0ZVRhcmdldERpbWVuc2lvbnMoZGltZW5zaW9uQ29uZmlnOiBJRGltZW5zaW9uQ29uZmlnKSB7XG4gICAgICAgIGlmICghZGltZW5zaW9uQ29uZmlnLmF1dG9IZWlnaHQpIHtcbiAgICAgICAgICAgIC8vIHVzZSBzdHlsZSBpbnN0ZWFkIG9mIGF0dHIgdG8gb3ZlcnJpZGUgY3NzIHN0eWxlXG4gICAgICAgICAgICB0aGlzLnRhcmdldD8uc3R5bGUoXCJoZWlnaHRcIiwgZGltZW5zaW9uQ29uZmlnLm91dGVySGVpZ2h0KCkgKyBcInB4XCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghZGltZW5zaW9uQ29uZmlnLmF1dG9XaWR0aCkge1xuICAgICAgICAgICAgLy8gdXNlIHN0eWxlIGluc3RlYWQgb2YgYXR0ciB0byBvdmVycmlkZSBjc3Mgc3R5bGVcbiAgICAgICAgICAgIHRoaXMudGFyZ2V0Py5zdHlsZShcIndpZHRoXCIsIGRpbWVuc2lvbkNvbmZpZy5vdXRlcldpZHRoKCkgKyBcInB4XCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBvblNldFNlcmllc1N0YXRlcyhyZW5kZXJTdGF0ZURhdGE6IElSZW5kZXJTdGF0ZURhdGFbXSkge1xuICAgICAgICB0aGlzLnJlbmRlckVuZ2luZS5zZXRTZXJpZXNTdGF0ZXMocmVuZGVyU3RhdGVEYXRhKTtcbiAgICB9XG59XG4iXX0=