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

366 lines 55.2 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 each from "lodash/each"; import keyBy from "lodash/keyBy"; import values from "lodash/values"; import { of, Subject } from "rxjs"; // eslint-disable-next-line import/no-deprecated import { filter, map, switchMap, takeUntil } from "rxjs/operators"; import { ChartAssistEventType, ChartAssistRenderStateData, } from "./types"; import { DESTROY_EVENT, HIGHLIGHT_SERIES_EVENT, INTERACTION_DATA_POINTS_EVENT, MOUSE_ACTIVE_EVENT, } from "../../constants"; import { RenderState } from "../../renderers/types"; import { defaultMarkerProvider, defaultPalette, } from "../common/palette/default-providers"; import { InteractionType, } from "../common/types"; /** * Helper class that helps to bootstrap a chart with legend, using data pre-processor. * It will use the most common settings. */ export class ChartAssist { chart; palette; markers; /** * Retrieves the display value for a data point on the specified series * * @param chartSeries The series containing the data point to get a label for * @param dataPoint The data point to get a label for * @param scaleKey The key for the scale potentially containing a formatter that can be used to format the label * @param formatterName The name of the formatter to use for formatting the label * @param dataAccessorKey The accessor key to use for accessing the data value if the accessor key differs from the scale key * * @returns The display value for a data point */ static getLabel(chartSeries, dataPoint, scaleKey, formatterName, dataAccessorKey) { if (!dataPoint || chartSeries.data.length === 0) { return null; } const valueAccessor = chartSeries.accessors.data?.[dataAccessorKey || scaleKey]; if (!valueAccessor) { return null; } const adjustedIndex = dataPoint.index < 0 ? chartSeries.data.length - 1 : dataPoint.index; const data = chartSeries.data[adjustedIndex]; const rawValue = valueAccessor(data, adjustedIndex, chartSeries.data, chartSeries); const scale = chartSeries.scales[scaleKey]; if (!scale || !formatterName) { return rawValue; } const formatter = scale.formatters[formatterName]; if (!formatter) { return rawValue; } return formatter(rawValue); } highlightedDataPoints; isLegendActive = false; inputSeriesSet = []; legendSeriesSet = []; /** * Subject for subscribing to IChartAssistEvents such as * ToggleSeries, EmphasizeSeries, and ResetVisibleSeries */ chartAssistSubject = new Subject(); syncHandlerMap; getVisibleSeriesWithLegendBackup; syncSubscription; legendInteractionAssist; onEvent; constructor(chart, seriesProcessor, palette = defaultPalette(), markers = defaultMarkerProvider()) { this.chart = chart; this.palette = palette; this.markers = markers; this.configureChartEventSubscriptions(chart.getEventBus()); if (seriesProcessor) { this.seriesProcessor = seriesProcessor; } this.legendInteractionAssist = new LegendInteractionAssist(this); this.syncHandlerMap = { [ChartAssistEventType.EmphasizeSeries]: this.emphasizeSeries, [ChartAssistEventType.ResetVisibleSeries]: this.resetVisibleSeries, [ChartAssistEventType.ToggleSeries]: this.toggleSeries, }; } get renderStatesIndex() { return this.legendInteractionAssist.renderStatesIndex; } /** * Convenience stream of highlight events that can be used to populate legend. * It will return highlighted value for the series (while hovering over datapoints) or the last value from series (while not hovering over and if possible), * otherwise it'll return null * @param chartSeries */ legendLabelData$(chartSeries) { const seriesHighlight$ = this.chart .getEventBus() .getStream(INTERACTION_DATA_POINTS_EVENT) .asObservable() .pipe(filter((event) => event.data.interactionType === InteractionType.MouseMove), map((event) => event.data.dataPoints[chartSeries.id])); // if there is no highlightData, or index is "-1", we'll show the last value from series (if possible) const highlightDataPresentPredicate = (highlightData) => highlightData && highlightData.index >= 0; return seriesHighlight$.pipe( // eslint-disable-next-line import/no-deprecated switchMap((highlightData) => highlightDataPresentPredicate(highlightData) ? of(highlightData.data) : of(chartSeries.data && chartSeries.data.length ? chartSeries.data[chartSeries.data.length - 1] : null))); } seriesProcessor(series) { return series; } update(inputSeriesSet, updateLegend = true) { this.inputSeriesSet = inputSeriesSet; const processedSeriesSet = this.seriesProcessor(inputSeriesSet.map((series) => ({ ...series, data: series.data || [], }))); this.legendSeriesSet = processedSeriesSet.filter((s) => s.showInLegend || typeof s.showInLegend === "undefined"); if (updateLegend) { this.legendInteractionAssist.update(processedSeriesSet); } // add render states to the series for use in the chart const seriesSet = processedSeriesSet.map((s) => Object.assign({ renderState: this.renderStatesIndex[s.id]?.state }, s)); this.chart.update(seriesSet); this.publishRenderStates(); } toggleSeries = (seriesId, visible) => { this.legendInteractionAssist.setGroupVisibility(seriesId, visible); this.update(this.inputSeriesSet, false); this.chartAssistSubject.next({ type: ChartAssistEventType.ToggleSeries, payload: { seriesId, visible }, }); }; /** * Resets all visible series to default state */ resetVisibleSeries = () => { this.legendInteractionAssist.resetSeries(); this.publishRenderStates(); this.chartAssistSubject.next({ type: ChartAssistEventType.ResetVisibleSeries, payload: {}, }); }; /** * For series that are currently visible, emphasize the given series and deemphasizes all the other ones * * @param seriesId */ emphasizeSeries = (seriesId) => { this.legendInteractionAssist.emphasizeSeries(seriesId); this.publishRenderStates(); this.chartAssistSubject.next({ type: ChartAssistEventType.EmphasizeSeries, payload: { seriesId }, }); }; isSeriesHidden(seriesId) { return this.legendInteractionAssist.isSeriesHidden(seriesId); } seriesTrackByFn(index, item) { return item.id; } /** * Retrieves the display value for the highlighted data point on the specified series * * @param chartSeries The series containing the highlighted data point to get a label for * @param scaleKey The key for the scale potentially containing a formatter that can be used to format the label * @param formatterName The name of the formatter to use for formatting the label * @param dataAccessorKey The accessor key to use for accessing the data value if the accessor key differs from the scale key * * @returns The display value for the highlighted data point */ getHighlightedValue(chartSeries, scaleKey, formatterName, dataAccessorKey) { if (!this.highlightedDataPoints) { return undefined; } const dataPoint = this.highlightedDataPoints[chartSeries.id]; return ChartAssist.getLabel(chartSeries, dataPoint, scaleKey, formatterName, dataAccessorKey); } getVisibleSeriesWithLegend = () => this.legendSeriesSet.filter((s) => !this.isSeriesHidden(s.id)); /** * Synchronize this chart assist's actions with IChartAssistEvents emitted by the specified * chart assist, and override this chart assist's getVisibleSeriesWithLegend method with the * specified chart assist's getVisibleSeriesWithLegend. * * Note: If the chart instance of the specified chart assist is replaced by a new chart, * this method must be invoked again to resume synchronized behavior. * * @param {ChartAssist} chartAssist The chart assist to synchronize with */ syncWithChartAssist(chartAssist) { this.getVisibleSeriesWithLegendBackup = this.getVisibleSeriesWithLegend; this.getVisibleSeriesWithLegend = chartAssist.getVisibleSeriesWithLegend; this.syncSubscription = chartAssist.chartAssistSubject .pipe(takeUntil(chartAssist.chart.getEventBus().getStream(DESTROY_EVENT))) .subscribe((event) => { const args = Object.keys(event.payload).map((key) => event.payload[key]); this.syncHandlerMap[event.type](...args); }); } /** * Unsynchronize this chart assist's actions from those of the chart assist * specified in a previous syncWithChartAssist call, and restore this chart * assist's getVisibleSeriesWithLegend method with the instance used before * syncWithChartAssist was called. */ unsyncChartAssist() { this.getVisibleSeriesWithLegend = this.getVisibleSeriesWithLegendBackup; if (this.syncSubscription) { this.syncSubscription.unsubscribe(); } } configureChartEventSubscriptions(eventBus) { const eventHandlers = { [INTERACTION_DATA_POINTS_EVENT]: (data) => { if (data.interactionType === InteractionType.MouseMove) { this.highlightedDataPoints = Object.assign({}, data.dataPoints); } }, [HIGHLIGHT_SERIES_EVENT]: (data) => { if (data.index >= 0) { this.emphasizeSeries(data.seriesId); } else { this.resetVisibleSeries(); } }, [MOUSE_ACTIVE_EVENT]: (data) => { this.isLegendActive = data; }, }; each(Object.keys(eventHandlers), (key) => { eventBus.getStream(key).subscribe((event) => { eventHandlers[key](event.data); if (this.onEvent) { this.onEvent(event); } }); }); } publishRenderStates() { this.chart.setSeriesStates(this.legendInteractionAssist.getSeriesStates()); } } export class LegendInteractionAssist { chartAssist; seriesGroups = {}; seriesIndex; renderStatesIndex = {}; constructor(chartAssist) { this.chartAssist = chartAssist; } update(seriesSet) { this.seriesGroups = this.getSeriesGroups(seriesSet); this.seriesIndex = keyBy(seriesSet, (s) => s.id); this.resetSeries(); // override render states for (const series of seriesSet.filter((s) => s.renderState)) { this.renderStatesIndex[series.id] = new ChartAssistRenderStateData(series.id, series, series.renderState === RenderState.hidden ? RenderState.default : series.renderState, series.renderState !== RenderState.hidden); } } getSeriesStates() { return values(this.renderStatesIndex); } isSeriesHidden(seriesId) { const renderState = this.renderStatesIndex[seriesId]; return renderState && !renderState.visible; } getSeriesGroups(seriesSet) { const seriesGroups = {}; for (const s of seriesSet) { const separatorIndex = s.id.indexOf("__"); const parentId = separatorIndex >= 0 ? s.id.substring(0, separatorIndex) : s.id; if (!seriesGroups[parentId]) { seriesGroups[parentId] = []; } seriesGroups[parentId].push(s.id); } return seriesGroups; } /** * @param groupId id of the parent series * @param renderState */ setGroupState(groupId, renderState) { if (!this.seriesGroups[groupId]) { return; } for (const s of this.seriesGroups[groupId]) { this.setRenderState(s, renderState); } } /** * @param groupId id of the parent series * @param visible */ setGroupVisibility(groupId, visible) { if (!this.seriesGroups[groupId]) { return; } for (const s of this.seriesGroups[groupId]) { this.setVisibility(s, visible); } } emphasizeSeries(seriesId) { for (const group of Object.keys(this.seriesGroups)) { this.setGroupState(group, group === seriesId ? RenderState.emphasized : RenderState.deemphasized); } } resetSeries() { const legendSeries = this.chartAssist.getVisibleSeriesWithLegend(); const oneSeriesMode = legendSeries.length === 1; if (oneSeriesMode) { this.emphasizeSeries(legendSeries[0].id); } else { for (const group of Object.keys(this.seriesGroups)) { this.setGroupState(group, RenderState.default); } } } setRenderState(seriesId, state) { let renderState = this.renderStatesIndex[seriesId]; if (renderState) { renderState.emphasisState = state; } else { renderState = new ChartAssistRenderStateData(seriesId, this.seriesIndex[seriesId], state); this.renderStatesIndex[seriesId] = renderState; } } setVisibility(seriesId, visible) { let renderState = this.renderStatesIndex[seriesId]; if (renderState) { renderState.visible = visible; } else { renderState = new ChartAssistRenderStateData(seriesId, this.seriesIndex[seriesId], RenderState.default, visible); this.renderStatesIndex[seriesId] = renderState; } } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2hhcnQtYXNzaXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2NvcmUvY2hhcnQtYXNzaXN0cy9jaGFydC1hc3Npc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEseURBQXlEO0FBQ3pELEVBQUU7QUFDRiwrRUFBK0U7QUFDL0UsNEVBQTRFO0FBQzVFLDhFQUE4RTtBQUM5RSwrRUFBK0U7QUFDL0UsOEVBQThFO0FBQzlFLDREQUE0RDtBQUM1RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLHVEQUF1RDtBQUN2RCxFQUFFO0FBQ0YsNkVBQTZFO0FBQzdFLDRFQUE0RTtBQUM1RSwrRUFBK0U7QUFDL0UsMEVBQTBFO0FBQzFFLGlGQUFpRjtBQUNqRiw2RUFBNkU7QUFDN0UsaUJBQWlCO0FBRWpCLE9BQU8sSUFBSSxNQUFNLGFBQWEsQ0FBQztBQUMvQixPQUFPLEtBQUssTUFBTSxjQUFjLENBQUM7QUFDakMsT0FBTyxNQUFNLE1BQU0sZUFBZSxDQUFDO0FBQ25DLE9BQU8sRUFBYyxFQUFFLEVBQUUsT0FBTyxFQUFnQixNQUFNLE1BQU0sQ0FBQztBQUM3RCxnREFBZ0Q7QUFDaEQsT0FBTyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRW5FLE9BQU8sRUFDSCxvQkFBb0IsRUFDcEIsMEJBQTBCLEdBSTdCLE1BQU0sU0FBUyxDQUFDO0FBQ2pCLE9BQU8sRUFDSCxhQUFhLEVBQ2Isc0JBQXNCLEVBQ3RCLDZCQUE2QixFQUM3QixrQkFBa0IsR0FDckIsTUFBTSxpQkFBaUIsQ0FBQztBQUN6QixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFFcEQsT0FBTyxFQUNILHFCQUFxQixFQUNyQixjQUFjLEdBQ2pCLE1BQU0scUNBQXFDLENBQUM7QUFDN0MsT0FBTyxFQVdILGVBQWUsR0FHbEIsTUFBTSxpQkFBaUIsQ0FBQztBQUV6Qjs7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Q0FBQyxPQUFPLENBQUMsQ0FBQzthQUNsRDtTQUNKO0lBQ0wsQ0FBQztJQUVPLGNBQWMsQ0FBQyxRQUFnQixFQUFFLEtBQWtCO1FBQ3ZELElBQUksV0FBVyxHQUFHLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUNuRCxJQUFJLFdBQVcsRUFBRTtZQUNiLFdBQVcsQ0FBQyxhQUFhLEdBQUcsS0FBSyxDQUFDO1NBQ3JDO2FBQU07WUFDSCxXQUFXLEdBQUcsSUFBSSwwQkFBMEIsQ0FDeEMsUUFBUSxFQUNSLElBQUksQ0FBQyxXQUFXLENBQUMsUUFBUSxDQUFDLEVBQzFCLEtBQUssQ0FDUixDQUFDO1lBQ0YsSUFBSSxDQUFDLGlCQUFpQixDQUFDLFFBQVEsQ0FBQyxHQUFHLFdBQVcsQ0FBQztTQUNsRDtJQUNMLENBQUM7SUFFTyxhQUFhLENBQUMsUUFBZ0IsRUFBRSxPQUFnQjtRQUNwRCxJQUFJLFdBQVcsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDbkQsSUFBSSxXQUFXLEVBQUU7WUFDYixXQUFXLENBQUMsT0FBTyxHQUFHLE9BQU8sQ0FBQztTQUNqQzthQUFNO1lBQ0gsV0FBVyxHQUFHLElBQUksMEJBQTBCLENBQ3hDLFFBQVEsRUFDUixJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxFQUMxQixXQUFXLENBQUMsT0FBTyxFQUNuQixPQUFPLENBQ1YsQ0FBQztZQUNGLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxRQUFRLENBQUMsR0FBRyxXQUFXLENBQUM7U0FDbEQ7SUFDTCxDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyIvLyDCqSAyMDIyIFNvbGFyV2luZHMgV29ybGR3aWRlLCBMTEMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvXG4vLyAgZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGVcbi8vICByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Jcbi8vICBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vICBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IGVhY2ggZnJvbSBcImxvZGFzaC9lYWNoXCI7XG5pbXBvcnQga2V5QnkgZnJvbSBcImxvZGFzaC9rZXlCeVwiO1xuaW1wb3J0IHZhbHVlcyBmcm9tIFwibG9kYXNoL3ZhbHVlc1wiO1xuaW1wb3J0IHsgT2JzZXJ2YWJsZSwgb2YsIFN1YmplY3QsIFN1YnNjcmlwdGlvbiB9IGZyb20gXCJyeGpzXCI7XG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLWRlcHJlY2F0ZWRcbmltcG9ydCB7IGZpbHRlciwgbWFwLCBzd2l0Y2hNYXAsIHRha2VVbnRpbCB9IGZyb20gXCJyeGpzL29wZXJhdG9yc1wiO1xuXG5pbXBvcnQge1xuICAgIENoYXJ0QXNzaXN0RXZlbnRUeXBlLFxuICAgIENoYXJ0QXNzaXN0UmVuZGVyU3RhdGVEYXRhLFxuICAgIElDaGFydEFzc2lzdCxcbiAgICBJQ2hhcnRBc3Npc3RFdmVudCxcbiAgICBJUmVuZGVyU3RhdGVzSW5kZXgsXG59IGZyb20gXCIuL3R5cGVzXCI7XG5pbXBvcnQge1xuICAgIERFU1RST1lfRVZFTlQsXG4gICAgSElHSExJR0hUX1NFUklFU19FVkVOVCxcbiAgICBJTlRFUkFDVElPTl9EQVRBX1BPSU5UU19FVkVOVCxcbiAgICBNT1VTRV9BQ1RJVkVfRVZFTlQsXG59IGZyb20gXCIuLi8uLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IFJlbmRlclN0YXRlIH0gZnJvbSBcIi4uLy4uL3JlbmRlcmVycy90eXBlc1wiO1xuaW1wb3J0IHsgRXZlbnRCdXMgfSBmcm9tIFwiLi4vY29tbW9uL2V2ZW50LWJ1c1wiO1xuaW1wb3J0IHtcbiAgICBkZWZhdWx0TWFya2VyUHJvdmlkZXIsXG4gICAgZGVmYXVsdFBhbGV0dGUsXG59IGZyb20gXCIuLi9jb21tb24vcGFsZXR0ZS9kZWZhdWx0LXByb3ZpZGVyc1wiO1xuaW1wb3J0IHtcbiAgICBJQWNjZXNzb3JzLFxuICAgIElDaGFydCxcbiAgICBJQ2hhcnRBc3Npc3RTZXJpZXMsXG4gICAgSUNoYXJ0RXZlbnQsXG4gICAgSUNoYXJ0TWFya2VyLFxuICAgIElDaGFydFBhbGV0dGUsXG4gICAgSUNoYXJ0U2VyaWVzLFxuICAgIElEYXRhUG9pbnQsXG4gICAgSURhdGFQb2ludHNQYXlsb2FkLFxuICAgIElJbnRlcmFjdGlvbkRhdGFQb2ludHNFdmVudCxcbiAgICBJbnRlcmFjdGlvblR5cGUsXG4gICAgSVJlbmRlclN0YXRlRGF0YSxcbiAgICBJVmFsdWVQcm92aWRlcixcbn0gZnJvbSBcIi4uL2NvbW1vbi90eXBlc1wiO1xuXG4vKipcbiAqIEhlbHBlciBjbGFzcyB0aGF0IGhlbHBzIHRvIGJvb3RzdHJhcCBhIGNoYXJ0IHdpdGggbGVnZW5kLCB1c2luZyBkYXRhIHByZS1wcm9jZXNzb3IuXG4gKiBJdCB3aWxsIHVzZSB0aGUgbW9zdCBjb21tb24gc2V0dGluZ3MuXG4gKi9cbmV4cG9ydCBjbGFzcyBDaGFydEFzc2lzdDxUIGV4dGVuZHMgSUFjY2Vzc29ycyA9IElBY2Nlc3NvcnM+XG4gICAgaW1wbGVtZW50cyBJQ2hhcnRBc3Npc3RcbntcbiAgICAvKipcbiAgICAgKiBSZXRyaWV2ZXMgdGhlIGRpc3BsYXkgdmFsdWUgZm9yIGEgZGF0YSBwb2ludCBvbiB0aGUgc3BlY2lmaWVkIHNlcmllc1xuICAgICAqXG4gICAgICogQHBhcmFtIGNoYXJ0U2VyaWVzIFRoZSBzZXJpZXMgY29udGFpbmluZyB0aGUgZGF0YSBwb2ludCB0byBnZXQgYSBsYWJlbCBmb3JcbiAgICAgKiBAcGFyYW0gZGF0YVBvaW50IFRoZSBkYXRhIHBvaW50IHRvIGdldCBhIGxhYmVsIGZvclxuICAgICAqIEBwYXJhbSBzY2FsZUtleSBUaGUga2V5IGZvciB0aGUgc2NhbGUgcG90ZW50aWFsbHkgY29udGFpbmluZyBhIGZvcm1hdHRlciB0aGF0IGNhbiBiZSB1c2VkIHRvIGZvcm1hdCB0aGUgbGFiZWxcbiAgICAgKiBAcGFyYW0gZm9ybWF0dGVyTmFtZSBUaGUgbmFtZSBvZiB0aGUgZm9ybWF0dGVyIHRvIHVzZSBmb3IgZm9ybWF0dGluZyB0aGUgbGFiZWxcbiAgICAgKiBAcGFyYW0gZGF0YUFjY2Vzc29yS2V5IFRoZSBhY2Nlc3NvciBrZXkgdG8gdXNlIGZvciBhY2Nlc3NpbmcgdGhlIGRhdGEgdmFsdWUgaWYgdGhlIGFjY2Vzc29yIGtleSBkaWZmZXJzIGZyb20gdGhlIHNjYWxlIGtleVxuICAgICAqXG4gICAgICogQHJldHVybnMgVGhlIGRpc3BsYXkgdmFsdWUgZm9yIGEgZGF0YSBwb2ludFxuICAgICAqL1xuICAgIHB1YmxpYyBzdGF0aWMgZ2V0TGFiZWwoXG4gICAgICAgIGNoYXJ0U2VyaWVzOiBJQ2hhcnRTZXJpZXM8SUFjY2Vzc29ycz4sXG4gICAgICAgIGRhdGFQb2ludDogYW55LFxuICAgICAgICBzY2FsZUtleTogc3RyaW5nLFxuICAgICAgICBmb3JtYXR0ZXJOYW1lPzogc3RyaW5nLFxuICAgICAgICBkYXRhQWNjZXNzb3JLZXk/OiBzdHJpbmdcbiAgICApOiBhbnkge1xuICAgICAgICBpZiAoIWRhdGFQb2ludCB8fCBjaGFydFNlcmllcy5kYXRhLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB2YWx1ZUFjY2Vzc29yID1cbiAgICAgICAgICAgIGNoYXJ0U2VyaWVzLmFjY2Vzc29ycy5kYXRhPy5bZGF0YUFjY2Vzc29yS2V5IHx8IHNjYWxlS2V5XTtcbiAgICAgICAgaWYgKCF2YWx1ZUFjY2Vzc29yKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGFkanVzdGVkSW5kZXggPVxuICAgICAgICAgICAgZGF0YVBvaW50LmluZGV4IDwgMCA/IGNoYXJ0U2VyaWVzLmRhdGEubGVuZ3RoIC0gMSA6IGRhdGFQb2ludC5pbmRleDtcbiAgICAgICAgY29uc3QgZGF0YSA9IGNoYXJ0U2VyaWVzLmRhdGFbYWRqdXN0ZWRJbmRleF07XG5cbiAgICAgICAgY29uc3QgcmF3VmFsdWUgPSB2YWx1ZUFjY2Vzc29yKFxuICAgICAgICAgICAgZGF0YSxcbiAgICAgICAgICAgIGFkanVzdGVkSW5kZXgsXG4gICAgICAgICAgICBjaGFydFNlcmllcy5kYXRhLFxuICAgICAgICAgICAgY2hhcnRTZXJpZXNcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3Qgc2NhbGUgPSBjaGFydFNlcmllcy5zY2FsZXNbc2NhbGVLZXldO1xuICAgICAgICBpZiAoIXNjYWxlIHx8ICFmb3JtYXR0ZXJOYW1lKSB7XG4gICAgICAgICAgICByZXR1cm4gcmF3VmFsdWU7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBmb3JtYXR0ZXIgPSBzY2FsZS5mb3JtYXR0ZXJzW2Zvcm1hdHRlck5hbWVdO1xuICAgICAgICBpZiAoIWZvcm1hdHRlcikge1xuICAgICAgICAgICAgcmV0dXJuIHJhd1ZhbHVlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZvcm1hdHRlcihyYXdWYWx1ZSk7XG4gICAgfVxuXG4gICAgcHVibGljIGhpZ2hsaWdodGVkRGF0YVBvaW50czogSURhdGFQb2ludHNQYXlsb2FkO1xuICAgIHB1YmxpYyBpc0xlZ2VuZEFjdGl2ZSA9IGZhbHNlO1xuICAgIHB1YmxpYyBpbnB1dFNlcmllc1NldDogSUNoYXJ0QXNzaXN0U2VyaWVzPElBY2Nlc3NvcnM+W10gPSBbXTtcbiAgICBwdWJsaWMgbGVnZW5kU2VyaWVzU2V0OiBJQ2hhcnRBc3Npc3RTZXJpZXM8SUFjY2Vzc29ycz5bXSA9IFtdO1xuXG4gICAgLyoqXG4gICAgICogU3ViamVjdCBmb3Igc3Vic2NyaWJpbmcgdG8gSUNoYXJ0QXNzaXN0RXZlbnRzIHN1Y2ggYXNcbiAgICAgKiBUb2dnbGVTZXJpZXMsIEVtcGhhc2l6ZVNlcmllcywgYW5kIFJlc2V0VmlzaWJsZVNlcmllc1xuICAgICAqL1xuICAgIHB1YmxpYyBjaGFydEFzc2lzdFN1YmplY3QgPSBuZXcgU3ViamVjdDxJQ2hhcnRBc3Npc3RFdmVudD4oKTtcblxuICAgIHByaXZhdGUgc3luY0hhbmRsZXJNYXA6IFJlY29yZDxDaGFydEFzc2lzdEV2ZW50VHlwZSwgYW55PjtcbiAgICBwcml2YXRlIGdldFZpc2libGVTZXJpZXNXaXRoTGVnZW5kQmFja3VwOiAoKSA9PiBJQ2hhcnRBc3Npc3RTZXJpZXM8XG4gICAgICAgIElBY2Nlc3NvcnM8YW55PlxuICAgID5bXTtcbiAgICBwcml2YXRlIHN5bmNTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgICBwcml2YXRlIGxlZ2VuZEludGVyYWN0aW9uQXNzaXN0OiBMZWdlbmRJbnRlcmFjdGlvbkFzc2lzdDtcblxuICAgIHB1YmxpYyBvbkV2ZW50OiAoZXZlbnQ6IElDaGFydEV2ZW50KSA9PiB2b2lkO1xuXG4gICAgY29uc3RydWN0b3IoXG4gICAgICAgIHB1YmxpYyBjaGFydDogSUNoYXJ0LFxuICAgICAgICBzZXJpZXNQcm9jZXNzb3I/OiAoXG4gICAgICAgICAgICBzZXJpZXM6IElDaGFydEFzc2lzdFNlcmllczxUPltdXG4gICAgICAgICkgPT4gSUNoYXJ0QXNzaXN0U2VyaWVzPFQ+W10sXG4gICAgICAgIHB1YmxpYyBwYWxldHRlOiBJQ2hhcnRQYWxldHRlID0gZGVmYXVsdFBhbGV0dGUoKSxcbiAgICAgICAgcHVibGljIG1hcmtlcnM6IElWYWx1ZVByb3ZpZGVyPElDaGFydE1hcmtlcj4gPSBkZWZhdWx0TWFya2VyUHJvdmlkZXIoKVxuICAgICkge1xuICAgICAgICB0aGlzLmNvbmZpZ3VyZUNoYXJ0RXZlbnRTdWJzY3JpcHRpb25zKGNoYXJ0LmdldEV2ZW50QnVzKCkpO1xuICAgICAgICBpZiAoc2VyaWVzUHJvY2Vzc29yKSB7XG4gICAgICAgICAgICB0aGlzLnNlcmllc1Byb2Nlc3NvciA9IHNlcmllc1Byb2Nlc3NvcjtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMubGVnZW5kSW50ZXJhY3Rpb25Bc3Npc3QgPSBuZXcgTGVnZW5kSW50ZXJhY3Rpb25Bc3Npc3QodGhpcyk7XG5cbiAgICAgICAgdGhpcy5zeW5jSGFuZGxlck1hcCA9IHtcbiAgICAgICAgICAgIFtDaGFydEFzc2lzdEV2ZW50VHlwZS5FbXBoYXNpemVTZXJpZXNdOiB0aGlzLmVtcGhhc2l6ZVNlcmllcyxcbiAgICAgICAgICAgIFtDaGFydEFzc2lzdEV2ZW50VHlwZS5SZXNldFZpc2libGVTZXJpZXNdOiB0aGlzLnJlc2V0VmlzaWJsZVNlcmllcyxcbiAgICAgICAgICAgIFtDaGFydEFzc2lzdEV2ZW50VHlwZS5Ub2dnbGVTZXJpZXNdOiB0aGlzLnRvZ2dsZVNlcmllcyxcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0IHJlbmRlclN0YXRlc0luZGV4KCk6IElSZW5kZXJTdGF0ZXNJbmRleCB7XG4gICAgICAgIHJldHVybiB0aGlzLmxlZ2VuZEludGVyYWN0aW9uQXNzaXN0LnJlbmRlclN0YXRlc0luZGV4O1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIENvbnZlbmllbmNlIHN0cmVhbSBvZiBoaWdobGlnaHQgZXZlbnRzIHRoYXQgY2FuIGJlIHVzZWQgdG8gcG9wdWxhdGUgbGVnZW5kLlxuICAgICAqIEl0IHdpbGwgcmV0dXJuIGhpZ2hsaWdodGVkIHZhbHVlIGZvciB0aGUgc2VyaWVzICh3aGlsZSBob3ZlcmluZyBvdmVyIGRhdGFwb2ludHMpIG9yIHRoZSBsYXN0IHZhbHVlIGZyb20gc2VyaWVzICh3aGlsZSBub3QgaG92ZXJpbmcgb3ZlciBhbmQgaWYgcG9zc2libGUpLFxuICAgICAqIG90aGVyd2lzZSBpdCdsbCByZXR1cm4gbnVsbFxuICAgICAqIEBwYXJhbSBjaGFydFNlcmllc1xuICAgICAqL1xuICAgIHB1YmxpYyBsZWdlbmRMYWJlbERhdGEkKFxuICAgICAgICBjaGFydFNlcmllczogSUNoYXJ0U2VyaWVzPElBY2Nlc3NvcnM+XG4gICAgKTogT2JzZXJ2YWJsZTxhbnk+IHtcbiAgICAgICAgY29uc3Qgc2VyaWVzSGlnaGxpZ2h0JCA9IHRoaXMuY2hhcnRcbiAgICAgICAgICAgIC5nZXRFdmVudEJ1cygpXG4gICAgICAgICAgICAuZ2V0U3RyZWFtKElOVEVSQUNUSU9OX0RBVEFfUE9JTlRTX0VWRU5UKVxuICAgICAgICAgICAgLmFzT2JzZXJ2YWJsZSgpXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgICBmaWx0ZXIoXG4gICAgICAgICAgICAgICAgICAgIChldmVudCkgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50LmRhdGEuaW50ZXJhY3Rpb25UeXBlID09PSBJbnRlcmFjdGlvblR5cGUuTW91c2VNb3ZlXG4gICAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgICAgICBtYXAoKGV2ZW50KSA9PiBldmVudC5kYXRhLmRhdGFQb2ludHNbY2hhcnRTZXJpZXMuaWRdKVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAvLyBpZiB0aGVyZSBpcyBubyBoaWdobGlnaHREYXRhLCBvciBpbmRleCBpcyBcIi0xXCIsIHdlJ2xsIHNob3cgdGhlIGxhc3QgdmFsdWUgZnJvbSBzZXJpZXMgKGlmIHBvc3NpYmxlKVxuICAgICAgICBjb25zdCBoaWdobGlnaHREYXRhUHJlc2VudFByZWRpY2F0ZSA9IChoaWdobGlnaHREYXRhOiBhbnkpID0+XG4gICAgICAgICAgICBoaWdobGlnaHREYXRhICYmIGhpZ2hsaWdodERhdGEuaW5kZXggPj0gMDtcblxuICAgICAgICByZXR1cm4gc2VyaWVzSGlnaGxpZ2h0JC5waXBlKFxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1kZXByZWNhdGVkXG4gICAgICAgICAgICBzd2l0Y2hNYXAoKGhpZ2hsaWdodERhdGEpID0+XG4gICAgICAgICAgICAgICAgaGlnaGxpZ2h0RGF0YVByZXNlbnRQcmVkaWNhdGUoaGlnaGxpZ2h0RGF0YSlcbiAgICAgICAgICAgICAgICAgICAgPyBvZihoaWdobGlnaHREYXRhLmRhdGEpXG4gICAgICAgICAgICAgICAgICAgIDogb2YoXG4gICAgICAgICAgICAgICAgICAgICAgICAgIGNoYXJ0U2VyaWVzLmRhdGEgJiYgY2hhcnRTZXJpZXMuZGF0YS5sZW5ndGhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID8gY2hhcnRTZXJpZXMuZGF0YVtjaGFydFNlcmllcy5kYXRhLmxlbmd0aCAtIDFdXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IG51bGxcbiAgICAgICAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICApXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIHNlcmllc1Byb2Nlc3NvcihcbiAgICAgICAgc2VyaWVzOiBJQ2hhcnRBc3Npc3RTZXJpZXM8SUFjY2Vzc29ycz5bXVxuICAgICk6IElDaGFydEFzc2lzdFNlcmllczxJQWNjZXNzb3JzPltdIHtcbiAgICAgICAgcmV0dXJuIHNlcmllcztcbiAgICB9XG5cbiAgICBwdWJsaWMgdXBkYXRlKFxuICAgICAgICBpbnB1dFNlcmllc1NldDogSUNoYXJ0QXNzaXN0U2VyaWVzPElBY2Nlc3NvcnM+W10sXG4gICAgICAgIHVwZGF0ZUxlZ2VuZCA9IHRydWVcbiAgICApOiB2b2lkIHtcbiAgICAgICAgdGhpcy5pbnB1dFNlcmllc1NldCA9IGlucHV0U2VyaWVzU2V0O1xuXG4gICAgICAgIGNvbnN0IHByb2Nlc3NlZFNlcmllc1NldCA9IHRoaXMuc2VyaWVzUHJvY2Vzc29yKFxuICAgICAgICAgICAgaW5wdXRTZXJpZXNTZXQubWFwKChzZXJpZXMpID0+ICh7XG4gICAgICAgICAgICAgICAgLi4uc2VyaWVzLFxuICAgICAgICAgICAgICAgIGRhdGE6IHNlcmllcy5kYXRhIHx8IFtdLFxuICAgICAgICAgICAgfSkpXG4gICAgICAgICk7XG5cbiAgICAgICAgdGhpcy5sZWdlbmRTZXJpZXNTZXQgPSBwcm9jZXNzZWRTZXJpZXNTZXQuZmlsdGVyKFxuICAgICAgICAgICAgKHMpID0+IHMuc2hvd0luTGVnZW5kIHx8IHR5cGVvZiBzLnNob3dJbkxlZ2VuZCA9PT0gXCJ1bmRlZmluZWRcIlxuICAgICAgICApO1xuXG4gICAgICAgIGlmICh1cGRhdGVMZWdlbmQpIHtcbiAgICAgICAgICAgIHRoaXMubGVnZW5kSW50ZXJhY3Rpb25Bc3Npc3QudXBkYXRlKHByb2Nlc3NlZFNlcmllc1NldCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gYWRkIHJlbmRlciBzdGF0ZXMgdG8gdGhlIHNlcmllcyBmb3IgdXNlIGluIHRoZSBjaGFydFxuICAgICAgICBjb25zdCBzZXJpZXNTZXQgPSBwcm9jZXNzZWRTZXJpZXNTZXQubWFwKChzKSA9PlxuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbihcbiAgICAgICAgICAgICAgICB7IHJlbmRlclN0YXRlOiB0aGlzLnJlbmRlclN0YXRlc0luZGV4W3MuaWRdPy5zdGF0ZSB9LFxuICAgICAgICAgICAgICAgIHNcbiAgICAgICAgICAgIClcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLmNoYXJ0LnVwZGF0ZShzZXJpZXNTZXQpO1xuXG4gICAgICAgIHRoaXMucHVibGlzaFJlbmRlclN0YXRlcygpO1xuICAgIH1cblxuICAgIHB1YmxpYyB0b2dnbGVTZXJpZXMgPSAoc2VyaWVzSWQ6IHN0cmluZywgdmlzaWJsZTogYm9vbGVhbik6IHZvaWQgPT4ge1xuICAgICAgICB0aGlzLmxlZ2VuZEludGVyYWN0aW9uQXNzaXN0LnNldEdyb3VwVmlzaWJpbGl0eShzZXJpZXNJZCwgdmlzaWJsZSk7XG5cbiAgICAgICAgdGhpcy51cGRhdGUodGhpcy5pbnB1dFNlcmllc1NldCwgZmFsc2UpO1xuICAgICAgICB0aGlzLmNoYXJ0QXNzaXN0U3ViamVjdC5uZXh0KHtcbiAgICAgICAgICAgIHR5cGU6IENoYXJ0QXNzaXN0RXZlbnRUeXBlLlRvZ2dsZVNlcmllcyxcbiAgICAgICAgICAgIHBheWxvYWQ6IHsgc2VyaWVzSWQsIHZpc2libGUgfSxcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlc2V0cyBhbGwgdmlzaWJsZSBzZXJpZXMgdG8gZGVmYXVsdCBzdGF0ZVxuICAgICAqL1xuICAgIHB1YmxpYyByZXNldFZpc2libGVTZXJpZXMgPSAoKTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMubGVnZW5kSW50ZXJhY3Rpb25Bc3Npc3QucmVzZXRTZXJpZXMoKTtcblxuICAgICAgICB0aGlzLnB1Ymxpc2hSZW5kZXJTdGF0ZXMoKTtcbiAgICAgICAgdGhpcy5jaGFydEFzc2lzdFN1YmplY3QubmV4dCh7XG4gICAgICAgICAgICB0eXBlOiBDaGFydEFzc2lzdEV2ZW50VHlwZS5SZXNldFZpc2libGVTZXJpZXMsXG4gICAgICAgICAgICBwYXlsb2FkOiB7fSxcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEZvciBzZXJpZXMgdGhhdCBhcmUgY3VycmVudGx5IHZpc2libGUsIGVtcGhhc2l6ZSB0aGUgZ2l2ZW4gc2VyaWVzIGFuZCBkZWVtcGhhc2l6ZXMgYWxsIHRoZSBvdGhlciBvbmVzXG4gICAgICpcbiAgICAgKiBAcGFyYW0gc2VyaWVzSWRcbiAgICAgKi9cbiAgICBwdWJsaWMgZW1waGFzaXplU2VyaWVzID0gKHNlcmllc0lkOiBzdHJpbmcpOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy5sZWdlbmRJbnRlcmFjdGlvbkFzc2lzdC5lbXBoYXNpemVTZXJpZXMoc2VyaWVzSWQpO1xuXG4gICAgICAgIHRoaXMucHVibGlzaFJlbmRlclN0YXRlcygpO1xuICAgICAgICB0aGlzLmNoYXJ0QXNzaXN0U3ViamVjdC5uZXh0KHtcbiAgICAgICAgICAgIHR5cGU6IENoYXJ0QXNzaXN0RXZlbnRUeXBlLkVtcGhhc2l6ZVNlcmllcyxcbiAgICAgICAgICAgIHBheWxvYWQ6IHsgc2VyaWVzSWQgfSxcbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIHB1YmxpYyBpc1Nlcmllc0hpZGRlbihzZXJpZXNJZDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgICAgIHJldHVybiB0aGlzLmxlZ2VuZEludGVyYWN0aW9uQXNzaXN0LmlzU2VyaWVzSGlkZGVuKHNlcmllc0lkKTtcbiAgICB9XG5cbiAgICBwdWJsaWMgc2VyaWVzVHJhY2tCeUZuKFxuICAgICAgICBpbmRleDogbnVtYmVyLFxuICAgICAgICBpdGVtOiBJQ2hhcnRBc3Npc3RTZXJpZXM8SUFjY2Vzc29ycz5cbiAgICApOiBzdHJpbmcge1xuICAgICAgICByZXR1cm4gaXRlbS5pZDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXRyaWV2ZXMgdGhlIGRpc3BsYXkgdmFsdWUgZm9yIHRoZSBoaWdobGlnaHRlZCBkYXRhIHBvaW50IG9uIHRoZSBzcGVjaWZpZWQgc2VyaWVzXG4gICAgICpcbiAgICAgKiBAcGFyYW0gY2hhcnRTZXJpZXMgVGhlIHNlcmllcyBjb250YWluaW5nIHRoZSBoaWdobGlnaHRlZCBkYXRhIHBvaW50IHRvIGdldCBhIGxhYmVsIGZvclxuICAgICAqIEBwYXJhbSBzY2FsZUtleSBUaGUga2V5IGZvciB0aGUgc2NhbGUgcG90ZW50aWFsbHkgY29udGFpbmluZyBhIGZvcm1hdHRlciB0aGF0IGNhbiBiZSB1c2VkIHRvIGZvcm1hdCB0aGUgbGFiZWxcbiAgICAgKiBAcGFyYW0gZm9ybWF0dGVyTmFtZSBUaGUgbmFtZSBvZiB0aGUgZm9ybWF0dGVyIHRvIHVzZSBmb3IgZm9ybWF0dGluZyB0aGUgbGFiZWxcbiAgICAgKiBAcGFyYW0gZGF0YUFjY2Vzc29yS2V5IFRoZSBhY2Nlc3NvciBrZXkgdG8gdXNlIGZvciBhY2Nlc3NpbmcgdGhlIGRhdGEgdmFsdWUgaWYgdGhlIGFjY2Vzc29yIGtleSBkaWZmZXJzIGZyb20gdGhlIHNjYWxlIGtleVxuICAgICAqXG4gICAgICogQHJldHVybnMgVGhlIGRpc3BsYXkgdmFsdWUgZm9yIHRoZSBoaWdobGlnaHRlZCBkYXRhIHBvaW50XG4gICAgICovXG4gICAgcHVibGljIGdldEhpZ2hsaWdodGVkVmFsdWUoXG4gICAgICAgIGNoYXJ0U2VyaWVzOiBJQ2hhcnRTZXJpZXM8SUFjY2Vzc29ycz4sXG4gICAgICAgIHNjYWxlS2V5OiBzdHJpbmcsXG4gICAgICAgIGZvcm1hdHRlck5hbWU/OiBzdHJpbmcsXG4gICAgICAgIGRhdGFBY2Nlc3NvcktleT86IHN0cmluZ1xuICAgICk6IHN0cmluZyB8IG51bWJlciB8IHVuZGVmaW5lZCB7XG4gICAgICAgIGlmICghdGhpcy5oaWdobGlnaHRlZERhdGFQb2ludHMpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBkYXRhUG9pbnQgPSB0aGlzLmhpZ2hsaWdodGVkRGF0YVBvaW50c1tjaGFydFNlcmllcy5pZF07XG4gICAgICAgIHJldHVybiBDaGFydEFzc2lzdC5nZXRMYWJlbChcbiAgICAgICAgICAgIGNoYXJ0U2VyaWVzLFxuICAgICAgICAgICAgZGF0YVBvaW50LFxuICAgICAgICAgICAgc2NhbGVLZXksXG4gICAgICAgICAgICBmb3JtYXR0ZXJOYW1lLFxuICAgICAgICAgICAgZGF0YUFjY2Vzc29yS2V5XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgcHVibGljIGdldFZpc2libGVTZXJpZXNXaXRoTGVnZW5kID0gKCk6IElDaGFydEFzc2lzdFNlcmllczxcbiAgICAgICAgSUFjY2Vzc29yczxhbnk+XG4gICAgPltdID0+IHRoaXMubGVnZW5kU2VyaWVzU2V0LmZpbHRlcigocykgPT4gIXRoaXMuaXNTZXJpZXNIaWRkZW4ocy5pZCkpO1xuXG4gICAgLyoqXG4gICAgICogU3luY2hyb25pemUgdGhpcyBjaGFydCBhc3Npc3QncyBhY3Rpb25zIHdpdGggSUNoYXJ0QXNzaXN0RXZlbnRzIGVtaXR0ZWQgYnkgdGhlIHNwZWNpZmllZFxuICAgICAqIGNoYXJ0IGFzc2lzdCwgYW5kIG92ZXJyaWRlIHRoaXMgY2hhcnQgYXNzaXN0J3MgZ2V0VmlzaWJsZVNlcmllc1dpdGhMZWdlbmQgbWV0aG9kIHdpdGggdGhlXG4gICAgICogc3BlY2lmaWVkIGNoYXJ0IGFzc2lzdCdzIGdldFZpc2libGVTZXJpZXNXaXRoTGVnZW5kLlxuICAgICAqXG4gICAgICogTm90ZTogSWYgdGhlIGNoYXJ0IGluc3RhbmNlIG9mIHRoZSBzcGVjaWZpZWQgY2hhcnQgYXNzaXN0IGlzIHJlcGxhY2VkIGJ5IGEgbmV3IGNoYXJ0LFxuICAgICAqIHRoaXMgbWV0aG9kIG11c3QgYmUgaW52b2tlZCBhZ2FpbiB0byByZXN1bWUgc3luY2hyb25pemVkIGJlaGF2aW9yLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtDaGFydEFzc2lzdH0gY2hhcnRBc3Npc3QgVGhlIGNoYXJ0IGFzc2lzdCB0byBzeW5jaHJvbml6ZSB3aXRoXG4gICAgICovXG4gICAgcHVibGljIHN5bmNXaXRoQ2hhcnRBc3Npc3QoY2hhcnRBc3Npc3Q6IENoYXJ0QXNzaXN0KTogdm9pZCB7XG4gICAgICAgIHRoaXMuZ2V0VmlzaWJsZVNlcmllc1dpdGhMZWdlbmRCYWNrdXAgPSB0aGlzLmdldFZpc2libGVTZXJpZXNXaXRoTGVnZW5kO1xuICAgICAgICB0aGlzLmdldFZpc2libGVTZXJpZXNXaXRoTGVnZW5kID1cbiAgICAgICAgICAgIGNoYXJ0QXNzaXN0LmdldFZpc2libGVTZXJpZXNXaXRoTGVnZW5kO1xuXG4gICAgICAgIHRoaXMuc3luY1N1YnNjcmlwdGlvbiA9IGNoYXJ0QXNzaXN0LmNoYXJ0QXNzaXN0U3ViamVjdFxuICAgICAgICAgICAgLnBpcGUoXG4gICAgICAgICAgICAgICAgdGFrZVVudGlsKFxuICAgICAgICAgICAgICAgICAgICBjaGFydEFzc2lzdC5jaGFydC5nZXRFdmVudEJ1cygpLmdldFN0cmVhbShERVNUUk9ZX0VWRU5UKVxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoKGV2ZW50OiBJQ2hhcnRBc3Npc3RFdmVudCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGFyZ3MgPSBPYmplY3Qua2V5cyhldmVudC5wYXlsb2FkKS5tYXAoXG4gICAgICAgICAgICAgICAgICAgIChrZXkpID0+IGV2ZW50LnBheWxvYWRba2V5XVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgdGhpcy5zeW5jSGFuZGxlck1hcFtldmVudC50eXBlXSguLi5hcmdzKTtcbiAgICAgICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFVuc3luY2hyb25pemUgdGhpcyBjaGFydCBhc3Npc3QncyBhY3Rpb25zIGZyb20gdGhvc2Ugb2YgdGhlIGNoYXJ0IGFzc2lzdFxuICAgICAqIHNwZWNpZmllZCBpbiBhIHByZXZpb3VzIHN5bmNXaXRoQ2hhcnRBc3Npc3QgY2FsbCwgYW5kIHJlc3RvcmUgdGhpcyBjaGFydFxuICAgICAqIGFzc2lzdCdzIGdldFZpc2libGVTZXJpZXNXaXRoTGVnZW5kIG1ldGhvZCB3aXRoIHRoZSBpbnN0YW5jZSB1c2VkIGJlZm9yZVxuICAgICAqIHN5bmNXaXRoQ2hhcnRBc3Npc3Qgd2FzIGNhbGxlZC5cbiAgICAgKi9cbiAgICBwdWJsaWMgdW5zeW5jQ2hhcnRBc3Npc3QoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuZ2V0VmlzaWJsZVNlcmllc1dpdGhMZWdlbmQgPSB0aGlzLmdldFZpc2libGVTZXJpZXNXaXRoTGVnZW5kQmFja3VwO1xuXG4gICAgICAgIGlmICh0aGlzLnN5bmNTdWJzY3JpcHRpb24pIHtcbiAgICAgICAgICAgIHRoaXMuc3luY1N1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBjb25maWd1cmVDaGFydEV2ZW50U3Vic2NyaXB0aW9ucyhcbiAgICAgICAgZXZlbnRCdXM6IEV2ZW50QnVzPElDaGFydEV2ZW50PlxuICAgICk6IHZvaWQge1xuICAgICAgICBjb25zdCBldmVudEhhbmRsZXJzOiB7IFtldmVudE5hbWU6IHN0cmluZ106IChkYXRhPzogYW55KSA9PiB2b2lkIH0gPSB7XG4gICAgICAgICAgICBbSU5URVJBQ1RJT05fREFUQV9QT0lOVFNfRVZFTlRdOiAoXG4gICAgICAgICAgICAgICAgZGF0YTogSUludGVyYWN0aW9uRGF0YVBvaW50c0V2ZW50XG4gICAgICAgICAgICApID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoZGF0YS5pbnRlcmFjdGlvblR5cGUgPT09IEludGVyYWN0aW9uVHlwZS5Nb3VzZU1vdmUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5oaWdobGlnaHRlZERhdGFQb2ludHMgPSBPYmplY3QuYXNzaWduKFxuICAgICAgICAgICAgICAgICAgICAgICAge30sXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhLmRhdGFQb2ludHNcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgW0hJR0hMSUdIVF9TRVJJRVNfRVZFTlRdOiAoZGF0YTogSURhdGFQb2ludCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChkYXRhLmluZGV4ID49IDApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5lbXBoYXNpemVTZXJpZXMoZGF0YS5zZXJpZXNJZCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXNldFZpc2libGVTZXJpZXMoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgW01PVVNFX0FDVElWRV9FVkVOVF06IChkYXRhOiBib29sZWFuKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5pc0xlZ2VuZEFjdGl2ZSA9IGRhdGE7XG4gICAgICAgICAgICB9LFxuICAgICAgICB9O1xuXG4gICAgICAgIGVhY2goT2JqZWN0LmtleXMoZXZlbnRIYW5kbGVycyksIChrZXkpID0+IHtcbiAgICAgICAgICAgIGV2ZW50QnVzLmdldFN0cmVhbShrZXkpLnN1YnNjcmliZSgoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBldmVudEhhbmRsZXJzW2tleV0oZXZlbnQuZGF0YSk7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMub25FdmVudCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm9uRXZlbnQoZXZlbnQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIHB1Ymxpc2hSZW5kZXJTdGF0ZXMoKTogdm9pZCB7XG4gICAgICAgIHRoaXMuY2hhcnQuc2V0U2VyaWVzU3RhdGVzKFxuICAgICAgICAgICAgdGhpcy5sZWdlbmRJbnRlcmFjdGlvbkFzc2lzdC5nZXRTZXJpZXNTdGF0ZXMoKVxuICAgICAgICApO1xuICAgIH1cbn1cblxuZXhwb3J0IGNsYXNzIExlZ2VuZEludGVyYWN0aW9uQXNzaXN0IHtcbiAgICBwcml2YXRlIHNlcmllc0dyb3VwczogUmVjb3JkPHN0cmluZywgc3RyaW5nW10+ID0ge307XG4gICAgcHJpdmF0ZSBzZXJpZXNJbmRleDogUmVjb3JkPHN0cmluZywgSUNoYXJ0QXNzaXN0U2VyaWVzPElBY2Nlc3NvcnM+PjtcblxuICAgIHB1YmxpYyByZW5kZXJTdGF0ZXNJbmRleDogSVJlbmRlclN0YXRlc0luZGV4ID0ge307XG5cbiAgICBjb25zdHJ1Y3Rvcihwcml2YXRlIGNoYXJ0QXNzaXN0OiBDaGFydEFzc2lzdCkge31cblxuICAgIHB1YmxpYyB1cGRhdGUoc2VyaWVzU2V0OiBJQ2hhcnRBc3Npc3RTZXJpZXM8SUFjY2Vzc29ycz5bXSk6IHZvaWQge1xuICAgICAgICB0aGlzLnNlcmllc0dyb3VwcyA9IHRoaXMuZ2V0U2VyaWVzR3JvdXBzKHNlcmllc1NldCk7XG4gICAgICAgIHRoaXM