@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
JavaScript
// © 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