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

251 lines 44.9 kB
// © 2022 SolarWinds Worldwide, LLC. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. import { max, min } from "d3-array"; import { local } from "d3-selection"; import defaultsDeep from "lodash/defaultsDeep"; import flatten from "lodash/flatten"; import isArray from "lodash/isArray"; import isUndefined from "lodash/isUndefined"; import uniq from "lodash/uniq"; import { DATA_POINT_INTERACTION_RESET, SELECT_DATA_POINT_EVENT, } from "../../constants"; import { convert } from "../../core/common/scales/helpers/convert"; import { EMPTY_CONTINUOUS_DOMAIN, isBandScale, } from "../../core/common/scales/types"; import { RenderLayerName } from "../types"; import { XYRenderer } from "../xy-renderer"; /** * Renderer that is able to draw bar chart */ export class BarRenderer extends XYRenderer { config; /** * Creates an instance of BarRenderer. * @param {IBarRendererConfig} [config] Renderer configuration object */ constructor(config = {}) { super(config); this.config = config; // setting default values to the properties that were not set by user this.config = defaultsDeep(this.config, this.DEFAULT_CONFIG); } static THICK = 11; // 10px + 1 to compensate outline static THIN = 3; // 2px + 1 to compensate outline static MIN_BAR_SIZE_FOR_ICON = 10; // Min bar size to render an icon inside. static MIN_BAR_THICKNESS = 2; static BAR_RECT_CLASS = "bar"; DEFAULT_CONFIG = { transitionDuration: 300, padding: 1, barClass: "bar-outline", highlightStrategy: undefined, pointerEvents: true, enableMinBarThickness: true, }; barContainerClass = "bar-container"; /** See {@link Renderer#draw} */ draw(renderSeries, rendererSubject) { const target = renderSeries.containers[RenderLayerName.data]; const dataSeries = renderSeries.dataSeries; const accessors = dataSeries.accessors; const attrsGenerator = this.getAttrsGenerator(dataSeries, renderSeries.scales); // We define here a local d3 variable to later re-use saved here data const generatedAttrs = local(); // TODO: This is tricky: we should not draw anything for hidden data // (seriesOffset will be undefined and this means we should provide empty array to d3). // TODO fix this const bars = target .selectAll(`g.${this.barContainerClass}`) .data(dataSeries.data); bars.exit().remove(); const barContainers = bars .enter() .append("g") .classed(this.barContainerClass, true); barContainers.append("rect").on("click", (d, i) => { this.emitBarClick(renderSeries, d, i, rendererSubject); }); const getCssClass = (d, i) => (typeof accessors.data?.cssClass !== "undefined" && " " + accessors.data.cssClass(d, i, dataSeries.data, dataSeries)) || ""; barContainers .merge(bars) .property(generatedAttrs, (d, i) => attrsGenerator(d, i)) // This saves attrsGenerator() output to local d3 variable generatedAttrs .select("rect") .attr("class", (d, i) => `${BarRenderer.BAR_RECT_CLASS} ${this.config.barClass}${this.config.pointerEvents ? " pointer-events" : ""}` + getCssClass(d, i)) .style("cursor", this.config.cursor ?? "") .style("stroke-width", this.config?.strokeWidth ?? "") .style("fill", (d, i) => accessors.data.color ? accessors.data.color(d, i, dataSeries.data, dataSeries) : accessors.series.color?.(dataSeries.id, dataSeries)) .attrs(function () { // @ts-ignore: Suppressing shadowed this and implicit any type error return generatedAttrs.get(this); }) .select("rect") .style("fill", (d, i) => accessors.data.color ? accessors.data.color(d, i, dataSeries.data, dataSeries) : accessors.series.color?.(dataSeries.id, dataSeries)) .attrs(generatedAttrs.get); // TODO: find a way to convert to ValueMap<> if (accessors.data.marker) { barContainers.append("g").classed("bar-icon", true); barContainers .merge(bars) .select("g.bar-icon") .html(function (d, i) { const barSize = generatedAttrs.get(this); if (!barSize || isUndefined(barSize?.height) || isUndefined(barSize?.width)) { throw new Error("barSize is undefined"); } const minBarSide = Math.min(barSize.height, barSize.width) - 1; if (minBarSide >= BarRenderer.MIN_BAR_SIZE_FOR_ICON) { return accessors.data.marker?.(d, i, dataSeries.data, dataSeries); } }) .attr("transform", function () { const barAttrs = generatedAttrs.get(this); if (!barAttrs || isUndefined(barAttrs?.height) || isUndefined(barAttrs?.width)) { throw new Error("barAttrs is undefined"); } return `translate(${barAttrs.x + barAttrs.width / 2}, ${barAttrs.y + barAttrs.height / 2})`; }); } } /** See {@link Renderer#getDataPointIndex} */ getDataPointIndex(series, values, scales) { return this.config.highlightStrategy ? this.config.highlightStrategy.getDataPointIndex(this, series, values, scales) : DATA_POINT_INTERACTION_RESET; } /** See {@link Renderer#highlightDataPoint} */ highlightDataPoint(renderSeries, dataPointIndex, rendererSubject) { if (this.config.highlightStrategy) { this.config.highlightStrategy.highlightDataPoint(this, renderSeries, dataPointIndex, rendererSubject); } } /** See {@link Renderer#getDataPointPosition} */ getDataPointPosition(dataSeries, index, scales) { const d = dataSeries.data[index]; return d && this.getAttrsGenerator(dataSeries, scales)(d, index); } getDataPoint(renderSeries, data, i) { return { seriesId: renderSeries.dataSeries.id, dataSeries: renderSeries.dataSeries, index: i, data: data, position: data ? this.getDataPointPosition(renderSeries.dataSeries, i, renderSeries.scales) : undefined, }; } filterDataByDomain(data) { return data; } getDomain(data, dataSeries, scaleKey, scale) { const accessors = dataSeries.accessors.data; const accessorSuffix = scaleKey.toUpperCase(); const accessor = (name) => (d, i, arr) => accessors[name + accessorSuffix]?.(d, i, Array.from(arr), dataSeries); if (scale.isContinuous()) { return !data || data.length === 0 ? EMPTY_CONTINUOUS_DOMAIN : [min(data, accessor("start")), max(data, accessor("end"))]; } else { const values = data && data.length > 0 ? data.map(accessor("start")) : []; const maxLength = Math.max(...values.map((d) => (isArray(d) ? d.length : -1))); if (maxLength >= 0) { return Array.from(Array(maxLength)).map((e, i) => { const scalesDomains = values.map((d) => i < d.length ? d[i] : []); return uniq(flatten(scalesDomains)); }); } else { return [uniq(values)]; } } } emitBarClick(renderSeries, data, i, rendererSubject) { rendererSubject.next({ eventName: SELECT_DATA_POINT_EVENT, data: this.getDataPoint(renderSeries, data, i), }); } /** * Returns function to generate attributes to draw bar from dataSeries that typically comes from preprocessor with help of accessors that * are aware of how to access renderParameters to draw individual bars * @param dataSeries Series to draw * @param scales Scales used to draw bars * Except of bars this is also used for highlights (which may have a bit different values) */ getAttrsGenerator(dataSeries, scales) { const accessors = dataSeries.accessors.data; return (d, i) => { const x = this.getDimensions(accessors, d, i, dataSeries, scales.x, "X"); const y = this.getDimensions(accessors, d, i, dataSeries, scales.y, "Y"); return { x: x.start, width: x.thickness, y: y.start, height: y.thickness, }; }; } getDimensions(accessors, d, i, dataSeries, scale, accessorSuffix) { let start; let thickness; const thicknessAccessor = accessors["thickness" + accessorSuffix]; const startAccessor = dataSeries.accessors.data["start" + accessorSuffix]; const endAccessor = dataSeries.accessors.data["end" + accessorSuffix]; thickness = thicknessAccessor?.(d, i, dataSeries.data, dataSeries); if (!isUndefined(thickness)) { if (!startAccessor) { throw new Error("Can't compute dimensions"); } start = convert(scale, startAccessor(d, i, dataSeries.data, dataSeries), 0.5) - thickness / 2; } else { if (!startAccessor || !endAccessor) { throw new Error("Can't compute dimensions"); } const x1 = convert(scale, startAccessor(d, i, dataSeries.data, dataSeries), 0); const x2 = convert(scale, endAccessor(d, i, dataSeries.data, dataSeries), 1); start = Math.min(x1, x2); thickness = Math.abs(x1 - x2); if (isBandScale(scale)) { if (isUndefined(this.config.padding)) { throw new Error("Config is not defined"); } start += this.config.padding; thickness -= this.config.padding * 2; } if (this.config.enableMinBarThickness) { thickness = Math.max(thickness, BarRenderer.MIN_BAR_THICKNESS); } } return { start, thickness }; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFyLXJlbmRlcmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3JlbmRlcmVycy9iYXIvYmFyLXJlbmRlcmVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLHlEQUF5RDtBQUN6RCxFQUFFO0FBQ0YsK0VBQStFO0FBQy9FLDRFQUE0RTtBQUM1RSw4RUFBOEU7QUFDOUUsK0VBQStFO0FBQy9FLDhFQUE4RTtBQUM5RSw0REFBNEQ7QUFDNUQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSx1REFBdUQ7QUFDdkQsRUFBRTtBQUNGLDZFQUE2RTtBQUM3RSw0RUFBNEU7QUFDNUUsK0VBQStFO0FBQy9FLDBFQUEwRTtBQUMxRSxpRkFBaUY7QUFDakYsNkVBQTZFO0FBQzdFLGlCQUFpQjtBQUVqQixPQUFPLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUNwQyxPQUFPLEVBQUUsS0FBSyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3JDLE9BQU8sWUFBWSxNQUFNLHFCQUFxQixDQUFDO0FBQy9DLE9BQU8sT0FBTyxNQUFNLGdCQUFnQixDQUFDO0FBQ3JDLE9BQU8sT0FBTyxNQUFNLGdCQUFnQixDQUFDO0FBQ3JDLE9BQU8sV0FBVyxNQUFNLG9CQUFvQixDQUFDO0FBQzdDLE9BQU8sSUFBSSxNQUFNLGFBQWEsQ0FBQztBQUcvQixPQUFPLEVBQ0gsNEJBQTRCLEVBQzVCLHVCQUF1QixHQUMxQixNQUFNLGlCQUFpQixDQUFDO0FBQ3pCLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSwwQ0FBMEMsQ0FBQztBQUNuRSxPQUFPLEVBQ0gsdUJBQXVCLEVBQ3ZCLFdBQVcsR0FHZCxNQUFNLGdDQUFnQyxDQUFDO0FBV3hDLE9BQU8sRUFBcUMsZUFBZSxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBQzlFLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUU1Qzs7R0FFRztBQUNILE1BQU0sT0FBTyxX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QUFDLEVBQUUsVUFBVSxDQUFDLElBQUksRUFBRSxVQUFVLENBQUMsRUFDOUMsQ0FBQyxDQUNKLENBQUM7WUFFRixLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDekIsU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO1lBRTlCLElBQUksV0FBVyxDQUFDLEtBQUssQ0FBQyxFQUFFO2dCQUNwQixJQUFJLFdBQVcsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFO29CQUNsQyxNQUFNLElBQUksS0FBSyxDQUFDLHVCQUF1QixDQUFDLENBQUM7aUJBQzVDO2dCQUNELEtBQUssSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQztnQkFDN0IsU0FBUyxJQUFJLElBQUksQ0FBQyxNQUFNLENBQUMsT0FBTyxHQUFHLENBQUMsQ0FBQzthQUN4QztZQUVELElBQUksSUFBSSxDQUFDLE1BQU0sQ0FBQyxxQkFBcUIsRUFBRTtnQkFDbkMsU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLFdBQVcsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO2FBQ2xFO1NBQ0o7UUFDRCxPQUFPLEVBQUUsS0FBSyxFQUFFLFNBQVMsRUFBRSxDQUFDO0lBQ2hDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyDCqSAyMDIyIFNvbGFyV2luZHMgV29ybGR3aWRlLCBMTEMuIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvXG4vLyAgZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGVcbi8vICByaWdodHMgdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Jcbi8vICBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vICBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyAgSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyAgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyAgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyAgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IHsgbWF4LCBtaW4gfSBmcm9tIFwiZDMtYXJyYXlcIjtcbmltcG9ydCB7IGxvY2FsIH0gZnJvbSBcImQzLXNlbGVjdGlvblwiO1xuaW1wb3J0IGRlZmF1bHRzRGVlcCBmcm9tIFwibG9kYXNoL2RlZmF1bHRzRGVlcFwiO1xuaW1wb3J0IGZsYXR0ZW4gZnJvbSBcImxvZGFzaC9mbGF0dGVuXCI7XG5pbXBvcnQgaXNBcnJheSBmcm9tIFwibG9kYXNoL2lzQXJyYXlcIjtcbmltcG9ydCBpc1VuZGVmaW5lZCBmcm9tIFwibG9kYXNoL2lzVW5kZWZpbmVkXCI7XG5pbXBvcnQgdW5pcSBmcm9tIFwibG9kYXNoL3VuaXFcIjtcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tIFwicnhqc1wiO1xuXG5pbXBvcnQge1xuICAgIERBVEFfUE9JTlRfSU5URVJBQ1RJT05fUkVTRVQsXG4gICAgU0VMRUNUX0RBVEFfUE9JTlRfRVZFTlQsXG59IGZyb20gXCIuLi8uLi9jb25zdGFudHNcIjtcbmltcG9ydCB7IGNvbnZlcnQgfSBmcm9tIFwiLi4vLi4vY29yZS9jb21tb24vc2NhbGVzL2hlbHBlcnMvY29udmVydFwiO1xuaW1wb3J0IHtcbiAgICBFTVBUWV9DT05USU5VT1VTX0RPTUFJTixcbiAgICBpc0JhbmRTY2FsZSxcbiAgICBJU2NhbGUsXG4gICAgU2NhbGVzLFxufSBmcm9tIFwiLi4vLi4vY29yZS9jb21tb24vc2NhbGVzL3R5cGVzXCI7XG5pbXBvcnQge1xuICAgIElEYXRhUG9pbnQsXG4gICAgSURhdGFTZXJpZXMsXG4gICAgSVBvc2l0aW9uLFxuICAgIElSZW5kZXJlckV2ZW50UGF5bG9hZCxcbn0gZnJvbSBcIi4uLy4uL2NvcmUvY29tbW9uL3R5cGVzXCI7XG5pbXBvcnQge1xuICAgIElSZWN0YW5nbGVBY2Nlc3NvcnMsXG4gICAgSVJlY3RhbmdsZURhdGFBY2Nlc3NvcnMsXG59IGZyb20gXCIuLi9hY2Nlc3NvcnMvcmVjdGFuZ2xlLWFjY2Vzc29yc1wiO1xuaW1wb3J0IHsgSUJhclJlbmRlcmVyQ29uZmlnLCBJUmVuZGVyU2VyaWVzLCBSZW5kZXJMYXllck5hbWUgfSBmcm9tIFwiLi4vdHlwZXNcIjtcbmltcG9ydCB7IFhZUmVuZGVyZXIgfSBmcm9tIFwiLi4veHktcmVuZGVyZXJcIjtcblxuLyoqXG4gKiBSZW5kZXJlciB0aGF0IGlzIGFibGUgdG8gZHJhdyBiYXIgY2hhcnRcbiAqL1xuZXhwb3J0IGNsYXNzIEJhclJlbmRlcmVyIGV4dGVuZHMgWFlSZW5kZXJlcjxJUmVjdGFuZ2xlQWNjZXNzb3JzPiB7XG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBCYXJSZW5kZXJlci5cbiAgICAgKiBAcGFyYW0ge0lCYXJSZW5kZXJlckNvbmZpZ30gW2NvbmZpZ10gUmVuZGVyZXIgY29uZmlndXJhdGlvbiBvYmplY3RcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3RvcihwdWJsaWMgY29uZmlnOiBJQmFyUmVuZGVyZXJDb25maWcgPSB7fSkge1xuICAgICAgICBzdXBlcihjb25maWcpO1xuICAgICAgICAvLyBzZXR0aW5nIGRlZmF1bHQgdmFsdWVzIHRvIHRoZSBwcm9wZXJ0aWVzIHRoYXQgd2VyZSBub3Qgc2V0IGJ5IHVzZXJcbiAgICAgICAgdGhpcy5jb25maWcgPSBkZWZhdWx0c0RlZXAodGhpcy5jb25maWcsIHRoaXMuREVGQVVMVF9DT05GSUcpO1xuICAgIH1cblxuICAgIHB1YmxpYyBzdGF0aWMgVEhJQ0sgPSAxMTsgLy8gMTBweCArIDEgdG8gY29tcGVuc2F0ZSBvdXRsaW5lXG4gICAgcHVibGljIHN0YXRpYyBUSElOID0gMzsgLy8gMnB4ICsgMSB0byBjb21wZW5zYXRlIG91dGxpbmVcbiAgICBwdWJsaWMgc3RhdGljIE1JTl9CQVJfU0laRV9GT1JfSUNPTiA9IDEwOyAvLyBNaW4gYmFyIHNpemUgdG8gcmVuZGVyIGFuIGljb24gaW5zaWRlLlxuICAgIHB1YmxpYyBzdGF0aWMgTUlOX0JBUl9USElDS05FU1MgPSAyO1xuICAgIHB1YmxpYyBzdGF0aWMgcmVhZG9ubHkgQkFSX1JFQ1RfQ0xBU1MgPSBcImJhclwiO1xuXG4gICAgcHVibGljIERFRkFVTFRfQ09ORklHOiBJQmFyUmVuZGVyZXJDb25maWcgPSB7XG4gICAgICAgIHRyYW5zaXRpb25EdXJhdGlvbjogMzAwLFxuICAgICAgICBwYWRkaW5nOiAxLFxuICAgICAgICBiYXJDbGFzczogXCJiYXItb3V0bGluZVwiLFxuICAgICAgICBoaWdobGlnaHRTdHJhdGVneTogdW5kZWZpbmVkLFxuICAgICAgICBwb2ludGVyRXZlbnRzOiB0cnVlLFxuICAgICAgICBlbmFibGVNaW5CYXJUaGlja25lc3M6IHRydWUsXG4gICAgfTtcblxuICAgIHB1YmxpYyByZWFkb25seSBiYXJDb250YWluZXJDbGFzcyA9IFwiYmFyLWNvbnRhaW5lclwiO1xuXG4gICAgLyoqIFNlZSB7QGxpbmsgUmVuZGVyZXIjZHJhd30gKi9cbiAgICBwdWJsaWMgZHJhdyhcbiAgICAgICAgcmVuZGVyU2VyaWVzOiBJUmVuZGVyU2VyaWVzPElSZWN0YW5nbGVBY2Nlc3NvcnM+LFxuICAgICAgICByZW5kZXJlclN1YmplY3Q6IFN1YmplY3Q8SVJlbmRlcmVyRXZlbnRQYXlsb2FkPlxuICAgICk6IHZvaWQge1xuICAgICAgICBjb25zdCB0YXJnZXQgPSByZW5kZXJTZXJpZXMuY29udGFpbmVyc1tSZW5kZXJMYXllck5hbWUuZGF0YV07XG4gICAgICAgIGNvbnN0IGRhdGFTZXJpZXMgPSByZW5kZXJTZXJpZXMuZGF0YVNlcmllcztcbiAgICAgICAgY29uc3QgYWNjZXNzb3JzID0gZGF0YVNlcmllcy5hY2Nlc3NvcnM7XG5cbiAgICAgICAgY29uc3QgYXR0cnNHZW5lcmF0b3IgPSB0aGlzLmdldEF0dHJzR2VuZXJhdG9yKFxuICAgICAgICAgICAgZGF0YVNlcmllcyxcbiAgICAgICAgICAgIHJlbmRlclNlcmllcy5zY2FsZXNcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBXZSBkZWZpbmUgaGVyZSBhIGxvY2FsIGQzIHZhcmlhYmxlIHRvIGxhdGVyIHJlLXVzZSBzYXZlZCBoZXJlIGRhdGFcbiAgICAgICAgY29uc3QgZ2VuZXJhdGVkQXR0cnMgPSBsb2NhbDxJUG9zaXRpb24+KCk7XG5cbiAgICAgICAgLy8gVE9ETzogVGhpcyBpcyB0cmlja3k6IHdlIHNob3VsZCBub3QgZHJhdyBhbnl0aGluZyBmb3IgaGlkZGVuIGRhdGFcbiAgICAgICAgLy8gKHNlcmllc09mZnNldCB3aWxsIGJlIHVuZGVmaW5lZCBhbmQgdGhpcyBtZWFucyB3ZSBzaG91bGQgcHJvdmlkZSBlbXB0eSBhcnJheSB0byBkMykuXG4gICAgICAgIC8vIFRPRE8gZml4IHRoaXNcbiAgICAgICAgY29uc3QgYmFycyA9IHRhcmdldFxuICAgICAgICAgICAgLnNlbGVjdEFsbChgZy4ke3RoaXMuYmFyQ29udGFpbmVyQ2xhc3N9YClcbiAgICAgICAgICAgIC5kYXRhKGRhdGFTZXJpZXMuZGF0YSk7XG5cbiAgICAgICAgYmFycy5leGl0KCkucmVtb3ZlKCk7XG5cbiAgICAgICAgY29uc3QgYmFyQ29udGFpbmVycyA9IGJhcnNcbiAgICAgICAgICAgIC5lbnRlcigpXG4gICAgICAgICAgICAuYXBwZW5kKFwiZ1wiKVxuICAgICAgICAgICAgLmNsYXNzZWQodGhpcy5iYXJDb250YWluZXJDbGFzcywgdHJ1ZSk7XG5cbiAgICAgICAgYmFyQ29udGFpbmVycy5hcHBlbmQoXCJyZWN0XCIpLm9uKFwiY2xpY2tcIiwgKGQ6IGFueSwgaTogbnVtYmVyKSA9PiB7XG4gICAgICAgICAgICB0aGlzLmVtaXRCYXJDbGljayhyZW5kZXJTZXJpZXMsIGQsIGksIHJlbmRlcmVyU3ViamVjdCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGNvbnN0IGdldENzc0NsYXNzID0gKGQ6IGFueSwgaTogbnVtYmVyKSA9PlxuICAgICAgICAgICAgKHR5cGVvZiBhY2Nlc3NvcnMuZGF0YT8uY3NzQ2xhc3MgIT09IFwidW5kZWZpbmVkXCIgJiZcbiAgICAgICAgICAgICAgICBcIiBcIiArXG4gICAgICAgICAgICAgICAgICAgIGFjY2Vzc29ycy5kYXRhLmNzc0NsYXNzKFxuICAgICAgICAgICAgICAgICAgICAgICAgZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGksXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhU2VyaWVzLmRhdGEsXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhU2VyaWVzXG4gICAgICAgICAgICAgICAgICAgICkpIHx8XG4gICAgICAgICAgICBcIlwiO1xuXG4gICAgICAgIGJhckNvbnRhaW5lcnNcbiAgICAgICAgICAgIC5tZXJnZShiYXJzIGFzIGFueSlcbiAgICAgICAgICAgIC5wcm9wZXJ0eShnZW5lcmF0ZWRBdHRycywgKGQsIGkpID0+IGF0dHJzR2VuZXJhdG9yKGQsIGkpKSAvLyBUaGlzIHNhdmVzIGF0dHJzR2VuZXJhdG9yKCkgb3V0cHV0IHRvIGxvY2FsIGQzIHZhcmlhYmxlIGdlbmVyYXRlZEF0dHJzXG4gICAgICAgICAgICAuc2VsZWN0PEVsZW1lbnQ+KFwicmVjdFwiKVxuICAgICAgICAgICAgLmF0dHIoXG4gICAgICAgICAgICAgICAgXCJjbGFzc1wiLFxuICAgICAgICAgICAgICAgIChkLCBpKSA9PlxuICAgICAgICAgICAgICAgICAgICBgJHtCYXJSZW5kZXJlci5CQVJfUkVDVF9DTEFTU30gJHt0aGlzLmNvbmZpZy5iYXJDbGFzc30ke1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25maWcucG9pbnRlckV2ZW50cyA/IFwiIHBvaW50ZXItZXZlbnRzXCIgOiBcIlwiXG4gICAgICAgICAgICAgICAgICAgIH1gICsgZ2V0Q3NzQ2xhc3MoZCwgaSlcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC5zdHlsZShcImN1cnNvclwiLCB0aGlzLmNvbmZpZy5jdXJzb3IgPz8gXCJcIilcbiAgICAgICAgICAgIC5zdHlsZShcInN0cm9rZS13aWR0aFwiLCB0aGlzLmNvbmZpZz8uc3Ryb2tlV2lkdGggPz8gXCJcIilcbiAgICAgICAgICAgIC5zdHlsZShcImZpbGxcIiwgKGQ6IGFueSwgaTogbnVtYmVyKSA9PlxuICAgICAgICAgICAgICAgIGFjY2Vzc29ycy5kYXRhLmNvbG9yXG4gICAgICAgICAgICAgICAgICAgID8gYWNjZXNzb3JzLmRhdGEuY29sb3IoZCwgaSwgZGF0YVNlcmllcy5kYXRhLCBkYXRhU2VyaWVzKVxuICAgICAgICAgICAgICAgICAgICA6IGFjY2Vzc29ycy5zZXJpZXMuY29sb3I/LihkYXRhU2VyaWVzLmlkLCBkYXRhU2VyaWVzKVxuICAgICAgICAgICAgKVxuICAgICAgICAgICAgLmF0dHJzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyBAdHMtaWdub3JlOiBTdXBwcmVzc2luZyBzaGFkb3dlZCB0aGlzIGFuZCBpbXBsaWNpdCBhbnkgdHlwZSBlcnJvclxuICAgICAgICAgICAgICAgIHJldHVybiBnZW5lcmF0ZWRBdHRycy5nZXQodGhpcykgYXMgYW55O1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIC5zZWxlY3Q8RWxlbWVudD4oXCJyZWN0XCIpXG4gICAgICAgICAgICAuc3R5bGUoXCJmaWxsXCIsIChkOiBhbnksIGk6IG51bWJlcikgPT5cbiAgICAgICAgICAgICAgICBhY2Nlc3NvcnMuZGF0YS5jb2xvclxuICAgICAgICAgICAgICAgICAgICA/IGFjY2Vzc29ycy5kYXRhLmNvbG9yKGQsIGksIGRhdGFTZXJpZXMuZGF0YSwgZGF0YVNlcmllcylcbiAgICAgICAgICAgICAgICAgICAgOiBhY2Nlc3NvcnMuc2VyaWVzLmNvbG9yPy4oZGF0YVNlcmllcy5pZCwgZGF0YVNlcmllcylcbiAgICAgICAgICAgIClcbiAgICAgICAgICAgIC5hdHRycyhnZW5lcmF0ZWRBdHRycy5nZXQgYXMgYW55KTsgLy8gVE9ETzogZmluZCBhIHdheSB0byBjb252ZXJ0IHRvIFZhbHVlTWFwPD5cblxuICAgICAgICBpZiAoYWNjZXNzb3JzLmRhdGEubWFya2VyKSB7XG4gICAgICAgICAgICBiYXJDb250YWluZXJzLmFwcGVuZChcImdcIikuY2xhc3NlZChcImJhci1pY29uXCIsIHRydWUpO1xuXG4gICAgICAgICAgICBiYXJDb250YWluZXJzXG4gICAgICAgICAgICAgICAgLm1lcmdlKGJhcnMgYXMgYW55KVxuICAgICAgICAgICAgICAgIC5zZWxlY3Q8RWxlbWVudD4oXCJnLmJhci1pY29uXCIpXG4gICAgICAgICAgICAgICAgLmh0bWwoZnVuY3Rpb24gKGQsIGkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgYmFyU2l6ZSA9IGdlbmVyYXRlZEF0dHJzLmdldCh0aGlzKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoXG4gICAgICAgICAgICAgICAgICAgICAgICAhYmFyU2l6ZSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNVbmRlZmluZWQoYmFyU2l6ZT8uaGVpZ2h0KSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNVbmRlZmluZWQoYmFyU2l6ZT8ud2lkdGgpXG4gICAgICAgICAgICAgICAgICAgICkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiYmFyU2l6ZSBpcyB1bmRlZmluZWRcIik7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBjb25zdCBtaW5CYXJTaWRlID1cbiAgICAgICAgICAgICAgICAgICAgICAgIE1hdGgubWluKGJhclNpemUuaGVpZ2h0LCBiYXJTaXplLndpZHRoKSAtIDE7XG4gICAgICAgICAgICAgICAgICAgIGlmIChtaW5CYXJTaWRlID49IEJhclJlbmRlcmVyLk1JTl9CQVJfU0laRV9GT1JfSUNPTikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGFjY2Vzc29ycy5kYXRhLm1hcmtlcj8uKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhU2VyaWVzLmRhdGEsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YVNlcmllc1xuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmF0dHIoXCJ0cmFuc2Zvcm1cIiwgZnVuY3Rpb24gKHRoaXMpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgYmFyQXR0cnMgPSBnZW5lcmF0ZWRBdHRycy5nZXQodGhpcyk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICAgICAgICAgICAgIWJhckF0dHJzIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICBpc1VuZGVmaW5lZChiYXJBdHRycz8uaGVpZ2h0KSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNVbmRlZmluZWQoYmFyQXR0cnM/LndpZHRoKVxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImJhckF0dHJzIGlzIHVuZGVmaW5lZFwiKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBgdHJhbnNsYXRlKCR7XG4gICAgICAgICAgICAgICAgICAgICAgICBiYXJBdHRycy54ICsgYmFyQXR0cnMud2lkdGggLyAyXG4gICAgICAgICAgICAgICAgICAgIH0sICR7YmFyQXR0cnMueSArIGJhckF0dHJzLmhlaWdodCAvIDJ9KWA7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICAvKiogU2VlIHtAbGluayBSZW5kZXJlciNnZXREYXRhUG9pbnRJbmRleH0gKi9cbiAgICBwdWJsaWMgZ2V0RGF0YVBvaW50SW5kZXgoXG4gICAgICAgIHNlcmllczogSURhdGFTZXJpZXM8SVJlY3RhbmdsZUFjY2Vzc29ycz4sXG4gICAgICAgIHZhbHVlczogeyBbcDogc3RyaW5nXTogYW55IH0sXG4gICAgICAgIHNjYWxlczogU2NhbGVzXG4gICAgKTogbnVtYmVyIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29uZmlnLmhpZ2hsaWdodFN0cmF0ZWd5XG4gICAgICAgICAgICA/IHRoaXMuY29uZmlnLmhpZ2hsaWdodFN0cmF0ZWd5LmdldERhdGFQb2ludEluZGV4KFxuICAgICAgICAgICAgICAgICAgdGhpcyxcbiAgICAgICAgICAgICAgICAgIHNlcmllcyxcbiAgICAgICAgICAgICAgICAgIHZhbHVlcyxcbiAgICAgICAgICAgICAgICAgIHNjYWxlc1xuICAgICAgICAgICAgICApXG4gICAgICAgICAgICA6IERBVEFfUE9JTlRfSU5URVJBQ1RJT05fUkVTRVQ7XG4gICAgfVxuXG4gICAgLyoqIFNlZSB7QGxpbmsgUmVuZGVyZXIjaGlnaGxpZ2h0RGF0YVBvaW50fSAqL1xuICAgIHB1YmxpYyBoaWdobGlnaHREYXRhUG9pbnQoXG4gICAgICAgIHJlbmRlclNlcmllczogSVJlbmRlclNlcmllczxJUmVjdGFuZ2xlQWNjZXNzb3JzPixcbiAgICAgICAgZGF0YVBvaW50SW5kZXg6IG51bWJlcixcbiAgICAgICAgcmVuZGVyZXJTdWJqZWN0OiBTdWJqZWN0PElSZW5kZXJlckV2ZW50UGF5bG9hZD5cbiAgICApOiB2b2lkIHtcbiAgICAgICAgaWYgKHRoaXMuY29uZmlnLmhpZ2hsaWdodFN0cmF0ZWd5KSB7XG4gICAgICAgICAgICB0aGlzLmNvbmZpZy5oaWdobGlnaHRTdHJhdGVneS5oaWdobGlnaHREYXRhUG9pbnQoXG4gICAgICAgICAgICAgICAgdGhpcyxcbiAgICAgICAgICAgICAgICByZW5kZXJTZXJpZXMsXG4gICAgICAgICAgICAgICAgZGF0YVBvaW50SW5kZXgsXG4gICAgICAgICAgICAgICAgcmVuZGVyZXJTdWJqZWN0XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLyoqIFNlZSB7QGxpbmsgUmVuZGVyZXIjZ2V0RGF0YVBvaW50UG9zaXRpb259ICovXG4gICAgcHVibGljIGdldERhdGFQb2ludFBvc2l0aW9uKFxuICAgICAgICBkYXRhU2VyaWVzOiBJRGF0YVNlcmllczxJUmVjdGFuZ2xlQWNjZXNzb3JzPixcbiAgICAgICAgaW5kZXg6IG51bWJlcixcbiAgICAgICAgc2NhbGVzOiBTY2FsZXNcbiAgICApOiBJUG9zaXRpb24ge1xuICAgICAgICBjb25zdCBkID0gZGF0YVNlcmllcy5kYXRhW2luZGV4XTtcbiAgICAgICAgcmV0dXJuIGQgJiYgdGhpcy5nZXRBdHRyc0dlbmVyYXRvcihkYXRhU2VyaWVzLCBzY2FsZXMpKGQsIGluZGV4KTtcbiAgICB9XG5cbiAgICBwdWJsaWMgZ2V0RGF0YVBvaW50KFxuICAgICAgICByZW5kZXJTZXJpZXM6IElSZW5kZXJTZXJpZXM8SVJlY3RhbmdsZUFjY2Vzc29ycz4sXG4gICAgICAgIGRhdGE6IGFueSxcbiAgICAgICAgaTogbnVtYmVyXG4gICAgKTogSURhdGFQb2ludCB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzZXJpZXNJZDogcmVuZGVyU2VyaWVzLmRhdGFTZXJpZXMuaWQsXG4gICAgICAgICAgICBkYXRhU2VyaWVzOiByZW5kZXJTZXJpZXMuZGF0YVNlcmllcyxcbiAgICAgICAgICAgIGluZGV4OiBpLFxuICAgICAgICAgICAgZGF0YTogZGF0YSxcbiAgICAgICAgICAgIHBvc2l0aW9uOiBkYXRhXG4gICAgICAgICAgICAgICAgPyB0aGlzLmdldERhdGFQb2ludFBvc2l0aW9uKFxuICAgICAgICAgICAgICAgICAgICAgIHJlbmRlclNlcmllcy5kYXRhU2VyaWVzLFxuICAgICAgICAgICAgICAgICAgICAgIGksXG4gICAgICAgICAgICAgICAgICAgICAgcmVuZGVyU2VyaWVzLnNjYWxlc1xuICAgICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICAgIDogdW5kZWZpbmVkLFxuICAgICAgICB9O1xuICAgIH1cblxuICAgIHB1YmxpYyBmaWx0ZXJEYXRhQnlEb21haW4oZGF0YTogYW55W10pOiBhbnlbXSB7XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH1cblxuICAgIHB1YmxpYyBnZXREb21haW4oXG4gICAgICAgIGRhdGE6IGFueVtdLFxuICAgICAgICBkYXRhU2VyaWVzOiBJRGF0YVNlcmllczxJUmVjdGFuZ2xlQWNjZXNzb3JzPixcbiAgICAgICAgc2NhbGVLZXk6IHN0cmluZyxcbiAgICAgICAgc2NhbGU6IElTY2FsZTxhbnk+XG4gICAgKTogYW55W10ge1xuICAgICAgICBjb25zdCBhY2Nlc3NvcnMgPSBkYXRhU2VyaWVzLmFjY2Vzc29ycy5kYXRhO1xuICAgICAgICBjb25zdCBhY2Nlc3NvclN1ZmZpeCA9IHNjYWxlS2V5LnRvVXBwZXJDYXNlKCk7XG4gICAgICAgIGNvbnN0IGFjY2Vzc29yID1cbiAgICAgICAgICAgIChuYW1lOiBzdHJpbmcpID0+IChkOiBhbnksIGk6IG51bWJlciwgYXJyOiBBcnJheUxpa2U8dW5rbm93bj4pID0+XG4gICAgICAgICAgICAgICAgYWNjZXNzb3JzW25hbWUgKyBhY2Nlc3NvclN1ZmZpeF0/LihcbiAgICAgICAgICAgICAgICAgICAgZCxcbiAgICAgICAgICAgICAgICAgICAgaSxcbiAgICAgICAgICAgICAgICAgICAgQXJyYXkuZnJvbShhcnIpLFxuICAgICAgICAgICAgICAgICAgICBkYXRhU2VyaWVzXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgaWYgKHNjYWxlLmlzQ29udGludW91cygpKSB7XG4gICAgICAgICAgICByZXR1cm4gIWRhdGEgfHwgZGF0YS5sZW5ndGggPT09IDBcbiAgICAgICAgICAgICAgICA/IEVNUFRZX0NPTlRJTlVPVVNfRE9NQUlOXG4gICAgICAgICAgICAgICAgOiBbbWluKGRhdGEsIGFjY2Vzc29yKFwic3RhcnRcIikpLCBtYXgoZGF0YSwgYWNjZXNzb3IoXCJlbmRcIikpXTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IHZhbHVlcyA9XG4gICAgICAgICAgICAgICAgZGF0YSAmJiBkYXRhLmxlbmd0aCA+IDAgPyBkYXRhLm1hcChhY2Nlc3NvcihcInN0YXJ0XCIpKSA6IFtdO1xuICAgICAgICAgICAgY29uc3QgbWF4TGVuZ3RoID0gTWF0aC5tYXgoXG4gICAgICAgICAgICAgICAgLi4udmFsdWVzLm1hcCgoZCkgPT4gKGlzQXJyYXkoZCkgPyBkLmxlbmd0aCA6IC0xKSlcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBpZiAobWF4TGVuZ3RoID49IDApIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gQXJyYXkuZnJvbShBcnJheShtYXhMZW5ndGgpKS5tYXAoKGUsIGkpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2NhbGVzRG9tYWlucyA9IHZhbHVlcy5tYXAoKGQpID0+XG4gICAgICAgICAgICAgICAgICAgICAgICBpIDwgZC5sZW5ndGggPyBkW2ldIDogW11cbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVuaXEoZmxhdHRlbihzY2FsZXNEb21haW5zKSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJldHVybiBbdW5pcSh2YWx1ZXMpXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHByb3RlY3RlZCBlbWl0QmFyQ2xpY2soXG4gICAgICAgIHJlbmRlclNlcmllczogSVJlbmRlclNlcmllczxJUmVjdGFuZ2xlQWNjZXNzb3JzPixcbiAgICAgICAgZGF0YTogYW55LFxuICAgICAgICBpOiBudW1iZXIsXG4gICAgICAgIHJlbmRlcmVyU3ViamVjdDogU3ViamVjdDxJUmVuZGVyZXJFdmVudFBheWxvYWQ+XG4gICAgKTogdm9pZCB7XG4gICAgICAgIHJlbmRlcmVyU3ViamVjdC5uZXh0KHtcbiAgICAgICAgICAgIGV2ZW50TmFtZTogU0VMRUNUX0RBVEFfUE9JTlRfRVZFTlQsXG4gICAgICAgICAgICBkYXRhOiB0aGlzLmdldERhdGFQb2ludChyZW5kZXJTZXJpZXMsIGRhdGEsIGkpLFxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIGZ1bmN0aW9uIHRvIGdlbmVyYXRlIGF0dHJpYnV0ZXMgdG8gZHJhdyBiYXIgZnJvbSBkYXRhU2VyaWVzIHRoYXQgdHlwaWNhbGx5IGNvbWVzIGZyb20gcHJlcHJvY2Vzc29yIHdpdGggaGVscCBvZiBhY2Nlc3NvcnMgdGhhdFxuICAgICAqIGFyZSBhd2FyZSBvZiBob3cgdG8gYWNjZXNzIHJlbmRlclBhcmFtZXRlcnMgdG8gZHJhdyBpbmRpdmlkdWFsIGJhcnNcbiAgICAgKiBAcGFyYW0gZGF0YVNlcmllcyBTZXJpZXMgdG8gZHJhd1xuICAgICAqIEBwYXJhbSBzY2FsZXMgU2NhbGVzIHVzZWQgdG8gZHJhdyBiYXJzXG4gICAgICogRXhjZXB0IG9mIGJhcnMgdGhpcyBpcyBhbHNvIHVzZWQgZm9yIGhpZ2hsaWdodHMgKHdoaWNoIG1heSBoYXZlIGEgYml0IGRpZmZlcmVudCB2YWx1ZXMpXG4gICAgICovXG4gICAgcHJvdGVjdGVkIGdldEF0dHJzR2VuZXJhdG9yKFxuICAgICAgICBkYXRhU2VyaWVzOiBJRGF0YVNlcmllczxJUmVjdGFuZ2xlQWNjZXNzb3JzPixcbiAgICAgICAgc2NhbGVzOiBTY2FsZXNcbiAgICApOiAoZDogYW55LCBpOiBudW1iZXIpID0+IElQb3NpdGlvbiB7XG4gICAgICAgIGNvbnN0IGFjY2Vzc29ycyA9IGRhdGFTZXJpZXMuYWNjZXNzb3JzLmRhdGE7XG4gICAgICAgIHJldHVybiAoZDogYW55LCBpOiBudW1iZXIpOiBJUG9zaXRpb24gPT4ge1xuICAgICAgICAgICAgY29uc3QgeCA9IHRoaXMuZ2V0RGltZW5zaW9ucyhcbiAgICAgICAgICAgICAgICBhY2Nlc3NvcnMsXG4gICAgICAgICAgICAgICAgZCxcbiAgICAgICAgICAgICAgICBpLFxuICAgICAgICAgICAgICAgIGRhdGFTZXJpZXMsXG4gICAgICAgICAgICAgICAgc2NhbGVzLngsXG4gICAgICAgICAgICAgICAgXCJYXCJcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBjb25zdCB5ID0gdGhpcy5nZXREaW1lbnNpb25zKFxuICAgICAgICAgICAgICAgIGFjY2Vzc29ycyxcbiAgICAgICAgICAgICAgICBkLFxuICAgICAgICAgICAgICAgIGksXG4gICAgICAgICAgICAgICAgZGF0YVNlcmllcyxcbiAgICAgICAgICAgICAgICBzY2FsZXMueSxcbiAgICAgICAgICAgICAgICBcIllcIlxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB4OiB4LnN0YXJ0LFxuICAgICAgICAgICAgICAgIHdpZHRoOiB4LnRoaWNrbmVzcyxcbiAgICAgICAgICAgICAgICB5OiB5LnN0YXJ0LFxuICAgICAgICAgICAgICAgIGhlaWdodDogeS50aGlja25lc3MsXG4gICAgICAgICAgICB9O1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIHByaXZhdGUgZ2V0RGltZW5zaW9ucyhcbiAgICAgICAgYWNjZXNzb3JzOiBJUmVjdGFuZ2xlRGF0YUFjY2Vzc29ycyxcbiAgICAgICAgZDogYW55LFxuICAgICAgICBpOiBudW1iZXIsXG4gICAgICAgIGRhdGFTZXJpZXM6IElEYXRhU2VyaWVzPElSZWN0YW5nbGVBY2Nlc3NvcnM+LFxuICAgICAgICBzY2FsZTogSVNjYWxlPGFueT4sXG4gICAgICAgIGFjY2Vzc29yU3VmZml4OiBzdHJpbmdcbiAgICApOiB7IHRoaWNrbmVzczogbnVtYmVyOyBzdGFydDogbnVtYmVyIH0ge1xuICAgICAgICBsZXQgc3RhcnQ6IG51bWJlcjtcbiAgICAgICAgbGV0IHRoaWNrbmVzczogbnVtYmVyO1xuXG4gICAgICAgIGNvbnN0IHRoaWNrbmVzc0FjY2Vzc29yID0gYWNjZXNzb3JzW1widGhpY2tuZXNzXCIgKyBhY2Nlc3NvclN1ZmZpeF07XG4gICAgICAgIGNvbnN0IHN0YXJ0QWNjZXNzb3IgPVxuICAgICAgICAgICAgZGF0YVNlcmllcy5hY2Nlc3NvcnMuZGF0YVtcInN0YXJ0XCIgKyBhY2Nlc3NvclN1ZmZpeF07XG4gICAgICAgIGNvbnN0IGVuZEFjY2Vzc29yID0gZGF0YVNlcmllcy5hY2Nlc3NvcnMuZGF0YVtcImVuZFwiICsgYWNjZXNzb3JTdWZmaXhdO1xuICAgICAgICB0aGlja25lc3MgPSB0aGlja25lc3NBY2Nlc3Nvcj8uKGQsIGksIGRhdGFTZXJpZXMuZGF0YSwgZGF0YVNlcmllcyk7XG5cbiAgICAgICAgaWYgKCFpc1VuZGVmaW5lZCh0aGlja25lc3MpKSB7XG4gICAgICAgICAgICBpZiAoIXN0YXJ0QWNjZXNzb3IpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW4ndCBjb21wdXRlIGRpbWVuc2lvbnNcIik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHN0YXJ0ID1cbiAgICAgICAgICAgICAgICBjb252ZXJ0KFxuICAgICAgICAgICAgICAgICAgICBzY2FsZSxcbiAgICAgICAgICAgICAgICAgICAgc3RhcnRBY2Nlc3NvcihkLCBpLCBkYXRhU2VyaWVzLmRhdGEsIGRhdGFTZXJpZXMpLFxuICAgICAgICAgICAgICAgICAgICAwLjVcbiAgICAgICAgICAgICAgICApIC1cbiAgICAgICAgICAgICAgICB0aGlja25lc3MgLyAyO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKCFzdGFydEFjY2Vzc29yIHx8ICFlbmRBY2Nlc3Nvcikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkNhbid0IGNvbXB1dGUgZGltZW5zaW9uc1wiKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY29uc3QgeDEgPSBjb252ZXJ0KFxuICAgICAgICAgICAgICAgIHNjYWxlLFxuICAgICAgICAgICAgICAgIHN0YXJ0QWNjZXNzb3IoZCwgaSwgZGF0YVNlcmllcy5kYXRhLCBkYXRhU2VyaWVzKSxcbiAgICAgICAgICAgICAgICAwXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgY29uc3QgeDIgPSBjb252ZXJ0KFxuICAgICAgICAgICAgICAgIHNjYWxlLFxuICAgICAgICAgICAgICAgIGVuZEFjY2Vzc29yKGQsIGksIGRhdGFTZXJpZXMuZGF0YSwgZGF0YVNlcmllcyksXG4gICAgICAgICAgICAgICAgMVxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgc3RhcnQgPSBNYXRoLm1pbih4MSwgeDIpO1xuICAgICAgICAgICAgdGhpY2tuZXNzID0gTWF0aC5hYnMoeDEgLSB4Mik7XG5cbiAgICAgICAgICAgIGlmIChpc0JhbmRTY2FsZShzY2FsZSkpIHtcbiAgICAgICAgICAgICAgICBpZiAoaXNVbmRlZmluZWQodGhpcy5jb25maWcucGFkZGluZykpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ29uZmlnIGlzIG5vdCBkZWZpbmVkXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBzdGFydCArPSB0aGlzLmNvbmZpZy5wYWRkaW5nO1xuICAgICAgICAgICAgICAgIHRoaWNrbmVzcyAtPSB0aGlzLmNvbmZpZy5wYWRkaW5nICogMjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMuY29uZmlnLmVuYWJsZU1pbkJhclRoaWNrbmVzcykge1xuICAgICAgICAgICAgICAgIHRoaWNrbmVzcyA9IE1hdGgubWF4KHRoaWNrbmVzcywgQmFyUmVuZGVyZXIuTUlOX0JBUl9USElDS05FU1MpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IHN0YXJ0LCB0aGlja25lc3MgfTtcbiAgICB9XG59XG4iXX0=