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

255 lines 41.1 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 isEqual from "lodash/isEqual"; import isUndefined from "lodash/isUndefined"; import values from "lodash/values"; import { Subject } from "rxjs"; import { InteractionType, } from "./types"; import { UtilityService } from "./utility.service"; import { DATA_POINT_INTERACTION_RESET, HIGHLIGHT_DATA_POINT_EVENT, STANDARD_RENDER_LAYERS, } from "../../constants"; /** * @ignore * * Manages and executes drawing and data point highlighting for each data series renderer and handles the setting of series display states */ export class RenderEngine { lasagna; dataManager; /** Subject for emitting events to the outside world about data points closest to an interaction on the chart */ interactionDataPointsSubject = new Subject(); /** Subject passed to the renderer for triggering events regarding a data point */ rendererSubject = new Subject(); highlightDataPointSubscription; highlightedDataPoints = {}; renderLayers = {}; layerIndex = {}; constructor(lasagna, dataManager) { this.lasagna = lasagna; this.dataManager = dataManager; this.highlightDataPointSubscription = this.rendererSubject.subscribe((event) => { if (event.eventName === HIGHLIGHT_DATA_POINT_EVENT) { this.highlightDataPoint(event.data.seriesId, event.data.index); } }); } /** * Invokes the draw method on each of the series renderers */ update() { const scaleValidity = {}; each(this.dataManager.chartSeriesSet, (chartSeries) => { const childContainers = this.getSeriesChildContainers(chartSeries.id); const areDomainsValid = -1 === Object.values(chartSeries.scales).findIndex((scale) => { if (typeof scaleValidity[scale.id] === "undefined") { const isValid = scale.isDomainValid(); if (!isValid) { console.warn("Invalid scale domain detected for scale:", scale); } scaleValidity[scale.id] = isValid; } return !scaleValidity[scale.id]; }); if (areDomainsValid) { chartSeries.renderer.draw({ dataSeries: chartSeries, containers: childContainers, scales: chartSeries.scales, }, this.rendererSubject); } }); } /** * Updates the lasagna layers and series containers based on the current series set */ updateSeriesContainers() { this.layerIndex = this.buildLayerIndex(this.dataManager.chartSeriesSet); this.removeUnusedLayers(); this.addNeededLayers(); this.updateLayerContents(); } /** * Emits the HIGHLIGHT_DATA_POINT_EVENT if the highlighted index changes for a particular series. * Emits an event with information about all of the highlighted data points if the highlighted index changes for any series. * * @param {IHighlightXYPayload} highlightedValues The highlighted values for each scale */ emitInteractionDataPoints(payload) { let highlightChangeDetected = false; const interactionDataPoints = this.dataManager.chartSeriesSet.reduce((result, chartSeries) => { const chartValues = {}; each(Object.keys(payload.values), (scaleKey) => { const myScaleId = chartSeries.scales[scaleKey].id; chartValues[scaleKey] = UtilityService.getInteractionValues(payload.values[scaleKey], myScaleId); }); let dataIndex = DATA_POINT_INTERACTION_RESET; if (chartSeries.data && chartSeries.data.length > 0) { dataIndex = chartSeries.renderer.getDataPointIndex(chartSeries, chartValues, chartSeries.scales); } const position = chartSeries.renderer.getDataPointPosition(chartSeries, dataIndex, chartSeries.scales); const dataPoint = { seriesId: chartSeries.id, dataSeries: chartSeries, index: dataIndex, data: dataIndex >= 0 ? chartSeries.data[dataIndex] : null, position: position, }; if (payload.interactionType === InteractionType.MouseMove) { const prevHighlight = this.highlightedDataPoints[chartSeries.id]; if (!isUndefined(dataIndex) && (isUndefined(prevHighlight) || dataIndex === DATA_POINT_INTERACTION_RESET || dataIndex !== prevHighlight.index)) { highlightChangeDetected = true; this.rendererSubject.next({ eventName: HIGHLIGHT_DATA_POINT_EVENT, data: dataPoint, }); } } // Note that dataIndex that is equal to -1 or -2 will be treated as "please show last value" by the legend, so it is valuable result[chartSeries.id] = dataPoint; return result; }, {}); if (payload.interactionType !== InteractionType.MouseMove || highlightChangeDetected) { this.interactionDataPointsSubject.next({ interactionType: payload.interactionType, dataPoints: interactionDataPoints, }); } if (highlightChangeDetected) { this.highlightedDataPoints = interactionDataPoints; } } /** * Invokes the renderer highlightDataPoint method for the specified series * * @param {string} seriesId The series on which to highlight a data point * @param {number} index The data point index to highlight */ highlightDataPoint(seriesId, index) { const childContainers = this.getSeriesChildContainers(seriesId); const chartSeries = this.dataManager.getChartSeries(seriesId); const renderSeries = { dataSeries: chartSeries, containers: childContainers, scales: chartSeries.scales, parentContainer: this.renderLayers.data, }; chartSeries.renderer.highlightDataPoint(renderSeries, index, this.rendererSubject); } /** * Sets attributes specified in each state data object to the appropriate the series containers. * Invokes a renderer's setSeriesState method when the state of its series container has been updated. * * @param {IRenderStateData[]} stateDataSet A collection of series states */ setSeriesStates(stateDataSet) { each(stateDataSet, ({ seriesId, state }) => { const chartSeries = this.dataManager.getChartSeries(seriesId); if (!chartSeries) { return; } const childContainers = this.getSeriesChildContainers(seriesId); const attrs = chartSeries.renderer.getContainerStateStyles(state); each(values(childContainers), (cc) => { cc.attrs(attrs); }); chartSeries.renderer.setSeriesState(childContainers, state); }); } destroy() { if (this.highlightDataPointSubscription) { this.highlightDataPointSubscription.unsubscribe(); } if (this.rendererSubject) { this.rendererSubject.complete(); } } buildLayerIndex(chartSeriesSet) { const layerIndex = {}; each(chartSeriesSet, (chartSeries) => { each(chartSeries.renderer.getRequiredLayers(), (layerDef) => { if (STANDARD_RENDER_LAYERS[layerDef.name] && !isEqual(STANDARD_RENDER_LAYERS[layerDef.name], layerDef)) { throw new Error(`Custom definition detected for render layer "${layerDef.name}". ` + `Custom layers must use a name not already taken by the predefined layer set.`); } let layer = layerIndex[layerDef.name]; if (!layer) { layer = { seriesUsing: [], layerDefinition: layerDef, }; layerIndex[layerDef.name] = layer; } layer.seriesUsing.push(chartSeries); }); }); return layerIndex; } removeUnusedLayers() { each(Object.keys(this.renderLayers), (layerName) => { if (!this.layerIndex[layerName]) { this.lasagna.removeLayer(layerName); delete this.renderLayers[layerName]; } }); } addNeededLayers() { each(this.layerIndex, (layerData) => { if (!this.renderLayers[layerData.layerDefinition.name]) { this.renderLayers[layerData.layerDefinition.name] = this.lasagna.addLayer(layerData.layerDefinition); } }); } updateLayerContents() { each(Object.keys(this.renderLayers), (layerName) => { const renderLayer = this.renderLayers[layerName]; const containers = renderLayer .selectAll("g.data-series-container") .data(this.layerIndex[layerName].seriesUsing, (d) => d.id) .order(); containers .enter() .append("g") .attrs({ id: (d) => this.getChildContainerId(layerName, d.id), class: "data-series-container", }); containers.exit().remove(); }); } getSeriesChildContainers(seriesId) { const childContainers = {}; each(Object.keys(this.renderLayers), (layerName) => { const renderLayer = this.renderLayers[layerName]; childContainers[layerName] = renderLayer.selectAll(`#${layerName}-${UtilityService.cssEscape(seriesId)}`); }); return childContainers; } getChildContainerId(layerName, seriesId) { return layerName + "-" + seriesId; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVuZGVyLWVuZ2luZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9jb3JlL2NvbW1vbi9yZW5kZXItZW5naW5lLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHlEQUF5RDtBQUN6RCxFQUFFO0FBQ0YsK0VBQStFO0FBQy9FLDRFQUE0RTtBQUM1RSw4RUFBOEU7QUFDOUUsK0VBQStFO0FBQy9FLDhFQUE4RTtBQUM5RSw0REFBNEQ7QUFDNUQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSx1REFBdUQ7QUFDdkQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSw0RUFBNEU7QUFDNUUsK0VBQStFO0FBQy9FLDBFQUEwRTtBQUMxRSxpRkFBaUY7QUFDakYsNkVBQTZFO0FBQzdFLGlCQUFpQjtBQUVqQixPQUFPLElBQUksTUFBTSxhQUFhLENBQUM7QUFDL0IsT0FBTyxPQUFPLE1BQU0sZ0JBQWdCLENBQUM7QUFDckMsT0FBTyxXQUFXLE1BQU0sb0JBQW9CLENBQUM7QUFDN0MsT0FBTyxNQUFNLE1BQU0sZUFBZSxDQUFDO0FBQ25DLE9BQU8sRUFBRSxPQUFPLEVBQWdCLE1BQU0sTUFBTSxDQUFDO0FBSTdDLE9BQU8sRUFRSCxlQUFlLEdBS2xCLE1BQU0sU0FBUyxDQUFDO0FBQ2pCLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUNuRCxPQUFPLEVBQ0gsNEJBQTRCLEVBQzVCLDBCQUEwQixFQUMxQixzQkFBc0IsR0FDekIsTUFBTSxpQkFBaUIsQ0FBQztBQWN6Qjs7OztHQUlHO0FBQ0gsTUFBTSxPQUFPLFlBQVk7SUFZRDtJQUEwQjtJQVg5QyxnSEFBZ0g7SUFDekcsNEJBQTRCLEdBQy9CLElBQUksT0FBTyxFQUErQixDQUFDO0lBQy9DLGtGQUFrRjtJQUMzRSxlQUFlLEdBQUcsSUFBSSxPQUFPLEVBQXlCLENBQUM7SUFFdEQsOEJBQThCLENBQWU7SUFDN0MscUJBQXFCLEdBQXVCLEVBQUUsQ0FBQztJQUMv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QyxNQUFNLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDLFNBQVMsRUFBRSxFQUFFO1lBQy9DLE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUM7WUFDakQsZUFBZSxDQUFDLFNBQVMsQ0FBQyxHQUFHLFdBQVcsQ0FBQyxTQUFTLENBQzlDLElBQUksU0FBUyxJQUFJLGNBQWMsQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FDeEQsQ0FBQztRQUNOLENBQUMsQ0FBQyxDQUFDO1FBQ0gsT0FBTyxlQUFlLENBQUM7SUFDM0IsQ0FBQztJQUVPLG1CQUFtQixDQUFDLFNBQWlCLEVBQUUsUUFBZ0I7UUFDM0QsT0FBTyxTQUFTLEdBQUcsR0FBRyxHQUFHLFFBQVEsQ0FBQztJQUN0QyxDQUFDO0NBQ0oiLCJzb3VyY2VzQ29udGVudCI6WyIvLyDCqSAyMDIyIFNvbGFyV2luZHMgV29ybGR3aWRlLCBMTEMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvXG4vLyAgZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGVcbi8vICByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Jcbi8vICBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vICBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IGVhY2ggZnJvbSBcImxvZGFzaC9lYWNoXCI7XG5pbXBvcnQgaXNFcXVhbCBmcm9tIFwibG9kYXNoL2lzRXF1YWxcIjtcbmltcG9ydCBpc1VuZGVmaW5lZCBmcm9tIFwibG9kYXNoL2lzVW5kZWZpbmVkXCI7XG5pbXBvcnQgdmFsdWVzIGZyb20gXCJsb2Rhc2gvdmFsdWVzXCI7XG5pbXBvcnQgeyBTdWJqZWN0LCBTdWJzY3JpcHRpb24gfSBmcm9tIFwicnhqc1wiO1xuXG5pbXBvcnQgeyBEYXRhTWFuYWdlciB9IGZyb20gXCIuL2RhdGEtbWFuYWdlclwiO1xuaW1wb3J0IHsgTGFzYWduYSB9IGZyb20gXCIuL2xhc2FnbmFcIjtcbmltcG9ydCB7XG4gICAgRDNTZWxlY3Rpb24sXG4gICAgSUFjY2Vzc29ycyxcbiAgICBJQ2hhcnRTZXJpZXMsXG4gICAgSURhdGFQb2ludCxcbiAgICBJRGF0YVBvaW50c1BheWxvYWQsXG4gICAgSUludGVyYWN0aW9uRGF0YVBvaW50c0V2ZW50LFxuICAgIElMYXNhZ25hTGF5ZXIsXG4gICAgSW50ZXJhY3Rpb25UeXBlLFxuICAgIElQb3NpdGlvbixcbiAgICBJUmVuZGVyQ29udGFpbmVycyxcbiAgICBJUmVuZGVyZXJFdmVudFBheWxvYWQsXG4gICAgSVJlbmRlclN0YXRlRGF0YSxcbn0gZnJvbSBcIi4vdHlwZXNcIjtcbmltcG9ydCB7IFV0aWxpdHlTZXJ2aWNlIH0gZnJvbSBcIi4vdXRpbGl0eS5zZXJ2aWNlXCI7XG5pbXBvcnQge1xuICAgIERBVEFfUE9JTlRfSU5URVJBQ1RJT05fUkVTRVQsXG4gICAgSElHSExJR0hUX0RBVEFfUE9JTlRfRVZFTlQsXG4gICAgU1RBTkRBUkRfUkVOREVSX0xBWUVSUyxcbn0gZnJvbSBcIi4uLy4uL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgSUludGVyYWN0aW9uVmFsdWVzUGF5bG9hZCB9IGZyb20gXCIuLi9wbHVnaW5zL3R5cGVzXCI7XG5cbi8qKlxuICogQGlnbm9yZVxuICogRW50cnkgZm9yIGEgbGFzYWduYSBsYXllciBpbmRleCB1c2VkIGZvciBrZWVwaW5nIHRyYWNrIG9mIHRoZSBjdXJyZW50IHNlcmllcyBjb250YWluZXIgc3RydWN0dXJlXG4gKi9cbmludGVyZmFjZSBJTGF5ZXJJbmRleEVudHJ5IHtcbiAgICAvKiogVGhlIHNlcmllcyB0aGF0IGhhdmUgY29udGFpbmVycyBpbiBhIGxheWVyICovXG4gICAgc2VyaWVzVXNpbmc6IElDaGFydFNlcmllczxJQWNjZXNzb3JzPltdO1xuICAgIC8qKiBUaGUgZGVmaW5pdGlvbiBmb3IgdGhlIGxheWVyICovXG4gICAgbGF5ZXJEZWZpbml0aW9uOiBJTGFzYWduYUxheWVyO1xufVxuXG4vKipcbiAqIEBpZ25vcmVcbiAqXG4gKiBNYW5hZ2VzIGFuZCBleGVjdXRlcyBkcmF3aW5nIGFuZCBkYXRhIHBvaW50IGhpZ2hsaWdodGluZyBmb3IgZWFjaCBkYXRhIHNlcmllcyByZW5kZXJlciBhbmQgaGFuZGxlcyB0aGUgc2V0dGluZyBvZiBzZXJpZXMgZGlzcGxheSBzdGF0ZXNcbiAqL1xuZXhwb3J0IGNsYXNzIFJlbmRlckVuZ2luZSB7XG4gICAgLyoqIFN1YmplY3QgZm9yIGVtaXR0aW5nIGV2ZW50cyB0byB0aGUgb3V0c2lkZSB3b3JsZCBhYm91dCBkYXRhIHBvaW50cyBjbG9zZXN0IHRvIGFuIGludGVyYWN0aW9uIG9uIHRoZSBjaGFydCAqL1xuICAgIHB1YmxpYyBpbnRlcmFjdGlvbkRhdGFQb2ludHNTdWJqZWN0ID1cbiAgICAgICAgbmV3IFN1YmplY3Q8SUludGVyYWN0aW9uRGF0YVBvaW50c0V2ZW50PigpO1xuICAgIC8qKiBTdWJqZWN0IHBhc3NlZCB0byB0aGUgcmVuZGVyZXIgZm9yIHRyaWdnZXJpbmcgZXZlbnRzIHJlZ2FyZGluZyBhIGRhdGEgcG9pbnQgKi9cbiAgICBwdWJsaWMgcmVuZGVyZXJTdWJqZWN0ID0gbmV3IFN1YmplY3Q8SVJlbmRlcmVyRXZlbnRQYXlsb2FkPigpO1xuXG4gICAgcHJpdmF0ZSBoaWdobGlnaHREYXRhUG9pbnRTdWJzY3JpcHRpb246IFN1YnNjcmlwdGlvbjtcbiAgICBwcml2YXRlIGhpZ2hsaWdodGVkRGF0YVBvaW50czogSURhdGFQb2ludHNQYXlsb2FkID0ge307XG4gICAgcHJpdmF0ZSByZW5kZXJMYXllcnM6IHsgW2xheWVyTmFtZTogc3RyaW5nXTogRDNTZWxlY3Rpb24gfSA9IHt9O1xuICAgIHByaXZhdGUgbGF5ZXJJbmRleDogeyBbbGF5ZXJOYW1lOiBzdHJpbmddOiBJTGF5ZXJJbmRleEVudHJ5IH0gPSB7fTtcblxuICAgIGNvbnN0cnVjdG9yKHByaXZhdGUgbGFzYWduYTogTGFzYWduYSwgcHJpdmF0ZSBkYXRhTWFuYWdlcjogRGF0YU1hbmFnZXIpIHtcbiAgICAgICAgdGhpcy5oaWdobGlnaHREYXRhUG9pbnRTdWJzY3JpcHRpb24gPSB0aGlzLnJlbmRlcmVyU3ViamVjdC5zdWJzY3JpYmUoXG4gICAgICAgICAgICAoZXZlbnQ6IElSZW5kZXJlckV2ZW50UGF5bG9hZCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChldmVudC5ldmVudE5hbWUgPT09IEhJR0hMSUdIVF9EQVRBX1BPSU5UX0VWRU5UKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaGlnaGxpZ2h0RGF0YVBvaW50KFxuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQuZGF0YS5zZXJpZXNJZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50LmRhdGEuaW5kZXhcbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW52b2tlcyB0aGUgZHJhdyBtZXRob2Qgb24gZWFjaCBvZiB0aGUgc2VyaWVzIHJlbmRlcmVyc1xuICAgICAqL1xuICAgIHB1YmxpYyB1cGRhdGUoKTogdm9pZCB7XG4gICAgICAgIGNvbnN0IHNjYWxlVmFsaWRpdHk6IFJlY29yZDxzdHJpbmcsIGJvb2xlYW4+ID0ge307XG4gICAgICAgIGVhY2goXG4gICAgICAgICAgICB0aGlzLmRhdGFNYW5hZ2VyLmNoYXJ0U2VyaWVzU2V0LFxuICAgICAgICAgICAgKGNoYXJ0U2VyaWVzOiBJQ2hhcnRTZXJpZXM8SUFjY2Vzc29ycz4pID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjaGlsZENvbnRhaW5lcnMgPSB0aGlzLmdldFNlcmllc0NoaWxkQ29udGFpbmVycyhcbiAgICAgICAgICAgICAgICAgICAgY2hhcnRTZXJpZXMuaWRcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGNvbnN0IGFyZURvbWFpbnNWYWxpZCA9XG4gICAgICAgICAgICAgICAgICAgIC0xID09PVxuICAgICAgICAgICAgICAgICAgICBPYmplY3QudmFsdWVzKGNoYXJ0U2VyaWVzLnNjYWxlcykuZmluZEluZGV4KChzY2FsZSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBzY2FsZVZhbGlkaXR5W3NjYWxlLmlkXSA9PT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGlzVmFsaWQgPSBzY2FsZS5pc0RvbWFpblZhbGlkKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFpc1ZhbGlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiSW52YWxpZCBzY2FsZSBkb21haW4gZGV0ZWN0ZWQgZm9yIHNjYWxlOlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGVWYWxpZGl0eVtzY2FsZS5pZF0gPSBpc1ZhbGlkO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICFzY2FsZVZhbGlkaXR5W3NjYWxlLmlkXTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgaWYgKGFyZURvbWFpbnNWYWxpZCkge1xuICAgICAgICAgICAgICAgICAgICBjaGFydFNlcmllcy5yZW5kZXJlci5kcmF3KFxuICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFTZXJpZXM6IGNoYXJ0U2VyaWVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lcnM6IGNoaWxkQ29udGFpbmVycyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZXM6IGNoYXJ0U2VyaWVzLnNjYWxlcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlbmRlcmVyU3ViamVjdFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHRoZSBsYXNhZ25hIGxheWVycyBhbmQgc2VyaWVzIGNvbnRhaW5lcnMgYmFzZWQgb24gdGhlIGN1cnJlbnQgc2VyaWVzIHNldFxuICAgICAqL1xuICAgIHB1YmxpYyB1cGRhdGVTZXJpZXNDb250YWluZXJzKCk6IHZvaWQge1xuICAgICAgICB0aGlzLmxheWVySW5kZXggPSB0aGlzLmJ1aWxkTGF5ZXJJbmRleCh0aGlzLmRhdGFNYW5hZ2VyLmNoYXJ0U2VyaWVzU2V0KTtcbiAgICAgICAgdGhpcy5yZW1vdmVVbnVzZWRMYXllcnMoKTtcbiAgICAgICAgdGhpcy5hZGROZWVkZWRMYXllcnMoKTtcbiAgICAgICAgdGhpcy51cGRhdGVMYXllckNvbnRlbnRzKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRW1pdHMgdGhlIEhJR0hMSUdIVF9EQVRBX1BPSU5UX0VWRU5UIGlmIHRoZSBoaWdobGlnaHRlZCBpbmRleCBjaGFuZ2VzIGZvciBhIHBhcnRpY3VsYXIgc2VyaWVzLlxuICAgICAqIEVtaXRzIGFuIGV2ZW50IHdpdGggaW5mb3JtYXRpb24gYWJvdXQgYWxsIG9mIHRoZSBoaWdobGlnaHRlZCBkYXRhIHBvaW50cyBpZiB0aGUgaGlnaGxpZ2h0ZWQgaW5kZXggY2hhbmdlcyBmb3IgYW55IHNlcmllcy5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7SUhpZ2hsaWdodFhZUGF5bG9hZH0gaGlnaGxpZ2h0ZWRWYWx1ZXMgVGhlIGhpZ2hsaWdodGVkIHZhbHVlcyBmb3IgZWFjaCBzY2FsZVxuICAgICAqL1xuICAgIHB1YmxpYyBlbWl0SW50ZXJhY3Rpb25EYXRhUG9pbnRzKHBheWxvYWQ6IElJbnRlcmFjdGlvblZhbHVlc1BheWxvYWQpOiB2b2lkIHtcbiAgICAgICAgbGV0IGhpZ2hsaWdodENoYW5nZURldGVjdGVkID0gZmFsc2U7XG5cbiAgICAgICAgY29uc3QgaW50ZXJhY3Rpb25EYXRhUG9pbnRzID0gdGhpcy5kYXRhTWFuYWdlci5jaGFydFNlcmllc1NldC5yZWR1Y2UoXG4gICAgICAgICAgICAocmVzdWx0LCBjaGFydFNlcmllczogSUNoYXJ0U2VyaWVzPElBY2Nlc3NvcnM+KSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgY2hhcnRWYWx1ZXM6IHsgW2F4aXM6IHN0cmluZ106IGFueSB9ID0ge307XG4gICAgICAgICAgICAgICAgZWFjaChPYmplY3Qua2V5cyhwYXlsb2FkLnZhbHVlcyksIChzY2FsZUtleSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBteVNjYWxlSWQgPSBjaGFydFNlcmllcy5zY2FsZXNbc2NhbGVLZXldLmlkO1xuICAgICAgICAgICAgICAgICAgICBjaGFydFZhbHVlc1tzY2FsZUtleV0gPSBVdGlsaXR5U2VydmljZS5nZXRJbnRlcmFjdGlvblZhbHVlcyhcbiAgICAgICAgICAgICAgICAgICAgICAgIHBheWxvYWQudmFsdWVzW3NjYWxlS2V5XSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG15U2NhbGVJZFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgbGV0IGRhdGFJbmRleCA9IERBVEFfUE9JTlRfSU5URVJBQ1RJT05fUkVTRVQ7XG4gICAgICAgICAgICAgICAgaWYgKGNoYXJ0U2VyaWVzLmRhdGEgJiYgY2hhcnRTZXJpZXMuZGF0YS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGFJbmRleCA9IGNoYXJ0U2VyaWVzLnJlbmRlcmVyLmdldERhdGFQb2ludEluZGV4KFxuICAgICAgICAgICAgICAgICAgICAgICAgY2hhcnRTZXJpZXMsXG4gICAgICAgICAgICAgICAgICAgICAgICBjaGFydFZhbHVlcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNoYXJ0U2VyaWVzLnNjYWxlc1xuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCBwb3NpdGlvbjogSVBvc2l0aW9uIHwgdW5kZWZpbmVkID1cbiAgICAgICAgICAgICAgICAgICAgY2hhcnRTZXJpZXMucmVuZGVyZXIuZ2V0RGF0YVBvaW50UG9zaXRpb24oXG4gICAgICAgICAgICAgICAgICAgICAgICBjaGFydFNlcmllcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFJbmRleCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGNoYXJ0U2VyaWVzLnNjYWxlc1xuICAgICAgICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgICAgY29uc3QgZGF0YVBvaW50OiBJRGF0YVBvaW50ID0ge1xuICAgICAgICAgICAgICAgICAgICBzZXJpZXNJZDogY2hhcnRTZXJpZXMuaWQsXG4gICAgICAgICAgICAgICAgICAgIGRhdGFTZXJpZXM6IGNoYXJ0U2VyaWVzLFxuICAgICAgICAgICAgICAgICAgICBpbmRleDogZGF0YUluZGV4LFxuICAgICAgICAgICAgICAgICAgICBkYXRhOiBkYXRhSW5kZXggPj0gMCA/IGNoYXJ0U2VyaWVzLmRhdGFbZGF0YUluZGV4XSA6IG51bGwsXG4gICAgICAgICAgICAgICAgICAgIHBvc2l0aW9uOiBwb3NpdGlvbixcbiAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgaWYgKHBheWxvYWQuaW50ZXJhY3Rpb25UeXBlID09PSBJbnRlcmFjdGlvblR5cGUuTW91c2VNb3ZlKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHByZXZIaWdobGlnaHQgPVxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5oaWdobGlnaHRlZERhdGFQb2ludHNbY2hhcnRTZXJpZXMuaWRdO1xuICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAhaXNVbmRlZmluZWQoZGF0YUluZGV4KSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgKGlzVW5kZWZpbmVkKHByZXZIaWdobGlnaHQpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YUluZGV4ID09PSBEQVRBX1BPSU5UX0lOVEVSQUNUSU9OX1JFU0VUIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YUluZGV4ICE9PSBwcmV2SGlnaGxpZ2h0LmluZGV4KVxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hsaWdodENoYW5nZURldGVjdGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyZXJTdWJqZWN0Lm5leHQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TmFtZTogSElHSExJR0hUX0RBVEFfUE9JTlRfRVZFTlQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogZGF0YVBvaW50LFxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBOb3RlIHRoYXQgZGF0YUluZGV4IHRoYXQgaXMgZXF1YWwgdG8gLTEgb3IgLTIgd2lsbCBiZSB0cmVhdGVkIGFzIFwicGxlYXNlIHNob3cgbGFzdCB2YWx1ZVwiIGJ5IHRoZSBsZWdlbmQsIHNvIGl0IGlzIHZhbHVhYmxlXG4gICAgICAgICAgICAgICAgcmVzdWx0W2NoYXJ0U2VyaWVzLmlkXSA9IGRhdGFQb2ludDtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIDxJRGF0YVBvaW50c1BheWxvYWQ+e31cbiAgICAgICAgKTtcblxuICAgICAgICBpZiAoXG4gICAgICAgICAgICBwYXlsb2FkLmludGVyYWN0aW9uVHlwZSAhPT0gSW50ZXJhY3Rpb25UeXBlLk1vdXNlTW92ZSB8fFxuICAgICAgICAgICAgaGlnaGxpZ2h0Q2hhbmdlRGV0ZWN0ZWRcbiAgICAgICAgKSB7XG4gICAgICAgICAgICB0aGlzLmludGVyYWN0aW9uRGF0YVBvaW50c1N1YmplY3QubmV4dCh7XG4gICAgICAgICAgICAgICAgaW50ZXJhY3Rpb25UeXBlOiBwYXlsb2FkLmludGVyYWN0aW9uVHlwZSxcbiAgICAgICAgICAgICAgICBkYXRhUG9pbnRzOiBpbnRlcmFjdGlvbkRhdGFQb2ludHMsXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChoaWdobGlnaHRDaGFuZ2VEZXRlY3RlZCkge1xuICAgICAgICAgICAgdGhpcy5oaWdobGlnaHRlZERhdGFQb2ludHMgPSBpbnRlcmFjdGlvbkRhdGFQb2ludHM7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBJbnZva2VzIHRoZSByZW5kZXJlciBoaWdobGlnaHREYXRhUG9pbnQgbWV0aG9kIGZvciB0aGUgc3BlY2lmaWVkIHNlcmllc1xuICAgICAqXG4gICAgICogQHBhcmFtIHtzdHJpbmd9IHNlcmllc0lkIFRoZSBzZXJpZXMgb24gd2hpY2ggdG8gaGlnaGxpZ2h0IGEgZGF0YSBwb2ludFxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBUaGUgZGF0YSBwb2ludCBpbmRleCB0byBoaWdobGlnaHRcbiAgICAgKi9cbiAgICBwdWJsaWMgaGlnaGxpZ2h0RGF0YVBvaW50KHNlcmllc0lkOiBzdHJpbmcsIGluZGV4OiBudW1iZXIpOiB2b2lkIHtcbiAgICAgICAgY29uc3QgY2hpbGRDb250YWluZXJzID0gdGhpcy5nZXRTZXJpZXNDaGlsZENvbnRhaW5lcnMoc2VyaWVzSWQpO1xuICAgICAgICBjb25zdCBjaGFydFNlcmllcyA9IHRoaXMuZGF0YU1hbmFnZXIuZ2V0Q2hhcnRTZXJpZXMoc2VyaWVzSWQpO1xuXG4gICAgICAgIGNvbnN0IHJlbmRlclNlcmllcyA9IHtcbiAgICAgICAgICAgIGRhdGFTZXJpZXM6IGNoYXJ0U2VyaWVzLFxuICAgICAgICAgICAgY29udGFpbmVyczogY2hpbGRDb250YWluZXJzLFxuICAgICAgICAgICAgc2NhbGVzOiBjaGFydFNlcmllcy5zY2FsZXMsXG4gICAgICAgICAgICBwYXJlbnRDb250YWluZXI6IHRoaXMucmVuZGVyTGF5ZXJzLmRhdGEsXG4gICAgICAgIH07XG4gICAgICAgIGNoYXJ0U2VyaWVzLnJlbmRlcmVyLmhpZ2hsaWdodERhdGFQb2ludChcbiAgICAgICAgICAgIHJlbmRlclNlcmllcyxcbiAgICAgICAgICAgIGluZGV4LFxuICAgICAgICAgICAgdGhpcy5yZW5kZXJlclN1YmplY3RcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIGF0dHJpYnV0ZXMgc3BlY2lmaWVkIGluIGVhY2ggc3RhdGUgZGF0YSBvYmplY3QgdG8gdGhlIGFwcHJvcHJpYXRlIHRoZSBzZXJpZXMgY29udGFpbmVycy5cbiAgICAgKiBJbnZva2VzIGEgcmVuZGVyZXIncyBzZXRTZXJpZXNTdGF0ZSBtZXRob2Qgd2hlbiB0aGUgc3RhdGUgb2YgaXRzIHNlcmllcyBjb250YWluZXIgaGFzIGJlZW4gdXBkYXRlZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7SVJlbmRlclN0YXRlRGF0YVtdfSBzdGF0ZURhdGFTZXQgQSBjb2xsZWN0aW9uIG9mIHNlcmllcyBzdGF0ZXNcbiAgICAgKi9cbiAgICBwdWJsaWMgc2V0U2VyaWVzU3RhdGVzKHN0YXRlRGF0YVNldDogSVJlbmRlclN0YXRlRGF0YVtdKTogdm9pZCB7XG4gICAgICAgIGVhY2goc3RhdGVEYXRhU2V0LCAoeyBzZXJpZXNJZCwgc3RhdGUgfSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgY2hhcnRTZXJpZXMgPSB0aGlzLmRhdGFNYW5hZ2VyLmdldENoYXJ0U2VyaWVzKHNlcmllc0lkKTtcbiAgICAgICAgICAgIGlmICghY2hhcnRTZXJpZXMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBjaGlsZENvbnRhaW5lcnMgPSB0aGlzLmdldFNlcmllc0NoaWxkQ29udGFpbmVycyhzZXJpZXNJZCk7XG5cbiAgICAgICAgICAgIGNvbnN0IGF0dHJzID0gY2hhcnRTZXJpZXMucmVuZGVyZXIuZ2V0Q29udGFpbmVyU3RhdGVTdHlsZXMoc3RhdGUpO1xuICAgICAgICAgICAgZWFjaCh2YWx1ZXMoY2hpbGRDb250YWluZXJzKSwgKGNjKSA9PiB7XG4gICAgICAgICAgICAgICAgY2MuYXR0cnMoYXR0cnMpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGNoYXJ0U2VyaWVzLnJlbmRlcmVyLnNldFNlcmllc1N0YXRlKGNoaWxkQ29udGFpbmVycywgc3RhdGUpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZGVzdHJveSgpOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuaGlnaGxpZ2h0RGF0YVBvaW50U3Vic2NyaXB0aW9uKSB7XG4gICAgICAgICAgICB0aGlzLmhpZ2hsaWdodERhdGFQb2ludFN1YnNjcmlwdGlvbi51bnN1YnNjcmliZSgpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLnJlbmRlcmVyU3ViamVjdCkge1xuICAgICAgICAgICAgdGhpcy5yZW5kZXJlclN1YmplY3QuY29tcGxldGUoKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByaXZhdGUgYnVpbGRMYXllckluZGV4KGNoYXJ0U2VyaWVzU2V0OiBJQ2hhcnRTZXJpZXM8SUFjY2Vzc29ycz5bXSk6IHtcbiAgICAgICAgW2xheWVyTmFtZTogc3RyaW5nXTogSUxheWVySW5kZXhFbnRyeTtcbiAgICB9IHtcbiAgICAgICAgY29uc3QgbGF5ZXJJbmRleDogeyBbbGF5ZXJOYW1lOiBzdHJpbmddOiBJTGF5ZXJJbmRleEVudHJ5IH0gPSB7fTtcbiAgICAgICAgZWFjaChjaGFydFNlcmllc1NldCwgKGNoYXJ0U2VyaWVzKSA9PiB7XG4gICAgICAgICAgICBlYWNoKGNoYXJ0U2VyaWVzLnJlbmRlcmVyLmdldFJlcXVpcmVkTGF5ZXJzKCksIChsYXllckRlZikgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgU1RBTkRBUkRfUkVOREVSX0xBWUVSU1tsYXllckRlZi5uYW1lXSAmJlxuICAgICAgICAgICAgICAgICAgICAhaXNFcXVhbChTVEFOREFSRF9SRU5ERVJfTEFZRVJTW2xheWVyRGVmLm5hbWVdLCBsYXllckRlZilcbiAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICAgICAgICAgYEN1c3RvbSBkZWZpbml0aW9uIGRldGVjdGVkIGZvciByZW5kZXIgbGF5ZXIgXCIke2xheWVyRGVmLm5hbWV9XCIuIGAgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBDdXN0b20gbGF5ZXJzIG11c3QgdXNlIGEgbmFtZSBub3QgYWxyZWFkeSB0YWtlbiBieSB0aGUgcHJlZGVmaW5lZCBsYXllciBzZXQuYFxuICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGxldCBsYXllciA9IGxheWVySW5kZXhbbGF5ZXJEZWYubmFtZV07XG4gICAgICAgICAgICAgICAgaWYgKCFsYXllcikge1xuICAgICAgICAgICAgICAgICAgICBsYXllciA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlcmllc1VzaW5nOiBbXSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGxheWVyRGVmaW5pdGlvbjogbGF5ZXJEZWYsXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIGxheWVySW5kZXhbbGF5ZXJEZWYubmFtZV0gPSBsYXllcjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbGF5ZXIuc2VyaWVzVXNpbmcucHVzaChjaGFydFNlcmllcyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBsYXllckluZGV4O1xuICAgIH1cblxuICAgIHByaXZhdGUgcmVtb3ZlVW51c2VkTGF5ZXJzKCk6IHZvaWQge1xuICAgICAgICBlYWNoKE9iamVjdC5rZXlzKHRoaXMucmVuZGVyTGF5ZXJzKSwgKGxheWVyTmFtZSkgPT4ge1xuICAgICAgICAgICAgaWYgKCF0aGlzLmxheWVySW5kZXhbbGF5ZXJOYW1lXSkge1xuICAgICAgICAgICAgICAgIHRoaXMubGFzYWduYS5yZW1vdmVMYXllcihsYXllck5hbWUpO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnJlbmRlckxheWVyc1tsYXllck5hbWVdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBwcml2YXRlIGFkZE5lZWRlZExheWVycygpOiB2b2lkIHtcbiAgICAgICAgZWFjaCh0aGlzLmxheWVySW5kZXgsIChsYXllckRhdGEpID0+IHtcbiAgICAgICAgICAgIGlmICghdGhpcy5yZW5kZXJMYXllcnNbbGF5ZXJEYXRhLmxheWVyRGVmaW5pdGlvbi5uYW1lXSkge1xuICAgICAgICAgICAgICAgIHRoaXMucmVuZGVyTGF5ZXJzW2xheWVyRGF0YS5sYXllckRlZmluaXRpb24ubmFtZV0gPVxuICAgICAgICAgICAgICAgICAgICB0aGlzLmxhc2FnbmEuYWRkTGF5ZXIobGF5ZXJEYXRhLmxheWVyRGVmaW5pdGlvbik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgdXBkYXRlTGF5ZXJDb250ZW50cygpOiB2b2lkIHtcbiAgICAgICAgZWFjaChPYmplY3Qua2V5cyh0aGlzLnJlbmRlckxheWVycyksIChsYXllck5hbWUpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHJlbmRlckxheWVyID0gdGhpcy5yZW5kZXJMYXllcnNbbGF5ZXJOYW1lXTtcbiAgICAgICAgICAgIGNvbnN0IGNvbnRhaW5lcnMgPSByZW5kZXJMYXllclxuICAgICAgICAgICAgICAgIC5zZWxlY3RBbGw8U1ZHRWxlbWVudCwgSUNoYXJ0U2VyaWVzPElBY2Nlc3NvcnM+PihcbiAgICAgICAgICAgICAgICAgICAgXCJnLmRhdGEtc2VyaWVzLWNvbnRhaW5lclwiXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIC5kYXRhKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLmxheWVySW5kZXhbbGF5ZXJOYW1lXS5zZXJpZXNVc2luZyxcbiAgICAgICAgICAgICAgICAgICAgKGQ6IElDaGFydFNlcmllczxJQWNjZXNzb3JzPikgPT4gZC5pZFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAub3JkZXIoKTtcblxuICAgICAgICAgICAgY29udGFpbmVyc1xuICAgICAgICAgICAgICAgIC5lbnRlcigpXG4gICAgICAgICAgICAgICAgLmFwcGVuZChcImdcIilcbiAgICAgICAgICAgICAgICAuYXR0cnMoe1xuICAgICAgICAgICAgICAgICAgICBpZDogKGQ6IElDaGFydFNlcmllczxJQWNjZXNzb3JzPikgPT5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZ2V0Q2hpbGRDb250YWluZXJJZChsYXllck5hbWUsIGQuaWQpLFxuICAgICAgICAgICAgICAgICAgICBjbGFzczogXCJkYXRhLXNlcmllcy1jb250YWluZXJcIixcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgY29udGFpbmVycy5leGl0KCkucmVtb3ZlKCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0U2VyaWVzQ2hpbGRDb250YWluZXJzKHNlcmllc0lkOiBzdHJpbmcpOiBJUmVuZGVyQ29udGFpbmVycyB7XG4gICAgICAgIGNvbnN0IGNoaWxkQ29udGFpbmVyczogeyBbbmFtZTogc3RyaW5nXTogRDNTZWxlY3Rpb248U1ZHR0VsZW1lbnQ+IH0gPVxuICAgICAgICAgICAge307XG4gICAgICAgIGVhY2goT2JqZWN0LmtleXModGhpcy5yZW5kZXJMYXllcnMpLCAobGF5ZXJOYW1lKSA9PiB7XG4gICAgICAgICAgICBjb25zdCByZW5kZXJMYXllciA9IHRoaXMucmVuZGVyTGF5ZXJzW2xheWVyTmFtZV07XG4gICAgICAgICAgICBjaGlsZENvbnRhaW5lcnNbbGF5ZXJOYW1lXSA9IHJlbmRlckxheWVyLnNlbGVjdEFsbChcbiAgICAgICAgICAgICAgICBgIyR7bGF5ZXJOYW1lfS0ke1V0aWxpdHlTZXJ2aWNlLmNzc0VzY2FwZShzZXJpZXNJZCl9YFxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBjaGlsZENvbnRhaW5lcnM7XG4gICAgfVxuXG4gICAgcHJpdmF0ZSBnZXRDaGlsZENvbnRhaW5lcklkKGxheWVyTmFtZTogc3RyaW5nLCBzZXJpZXNJZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIGxheWVyTmFtZSArIFwiLVwiICsgc2VyaWVzSWQ7XG4gICAgfVxufVxuIl19