UNPKG

kepler.gl

Version:

kepler.gl is a webgl based application to visualize large scale location data in the browser

601 lines (569 loc) 77.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.addCategoricalValuesToColorMap = addCategoricalValuesToColorMap; exports.colorBreaksToCategoricalColorMap = colorBreaksToCategoricalColorMap; exports.colorBreaksToColorMap = colorBreaksToColorMap; exports.colorMapToCategoricalColorBreaks = colorMapToCategoricalColorBreaks; exports.colorMapToColorBreaks = colorMapToColorBreaks; exports.getCategoricalColorMap = getCategoricalColorMap; exports.getCategoricalColorScale = getCategoricalColorScale; exports.getDomainStepsbyZoom = getDomainStepsbyZoom; exports.getHistogramDomain = getHistogramDomain; exports.getLayerColorScale = getLayerColorScale; exports.getLegendOfScale = getLegendOfScale; exports.getLinearDomain = getLinearDomain; exports.getLogDomain = getLogDomain; exports.getOrdinalDomain = getOrdinalDomain; exports.getOrdinalLegends = getOrdinalLegends; exports.getQuantLabelFormat = getQuantLabelFormat; exports.getQuantLegends = getQuantLegends; exports.getQuantileDomain = getQuantileDomain; exports.getScaleFunction = getScaleFunction; exports.getThresholdsFromQuantiles = getThresholdsFromQuantiles; exports.getVisualChannelScaleByZoom = getVisualChannelScaleByZoom; exports.initCustomPaletteByCustomScale = initCustomPaletteByCustomScale; exports.initializeLayerColorMap = initializeLayerColorMap; exports.isDomainQuantile = isDomainQuantile; exports.isDomainStops = isDomainStops; exports.isNumericColorBreaks = isNumericColorBreaks; exports.removeCategoricalValueFromColorMap = removeCategoricalValueFromColorMap; exports.resetCategoricalColorMapByIndex = resetCategoricalColorMapByIndex; exports.selectRestCategoricalColorMapByIndex = selectRestCategoricalColorMapByIndex; var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _d3Array = require("d3-array"); var _uniq = _interopRequireDefault(require("lodash/uniq")); var _moment = _interopRequireDefault(require("moment")); var _commonUtils = require("@kepler.gl/common-utils"); var _constants = require("@kepler.gl/constants"); var _colorUtils = require("./color-utils"); var _dataUtils = require("./data-utils"); var _filterUtils = require("./filter-utils"); var _utils = require("./utils"); function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project // import {FilterProps, KeplerTable} from '@kepler.gl/layers'; // TODO isolate types - depends on @kepler.gl/layers /** * return quantile domain for an array of data */ function getQuantileDomain(data, valueAccessor, sortFunc) { var values = typeof valueAccessor === 'function' ? data.map(valueAccessor) : data; return values.filter(_commonUtils.notNullorUndefined).sort(sortFunc); } /** * return ordinal domain for a data container */ function getOrdinalDomain(dataContainer, valueAccessor) { var values = dataContainer.mapIndex(valueAccessor); return (0, _dataUtils.unique)(values).filter(_commonUtils.notNullorUndefined).sort(); } /** * return linear domain for an array of data */ function getLinearDomain(data, valueAccessor) { var range = typeof valueAccessor === 'function' ? (0, _d3Array.extent)(data, valueAccessor) : (0, _d3Array.extent)(data); return range.map(function (d, i) { return d === undefined ? i : d; }); } /** * return linear domain for an array of data. A log scale domain cannot contain 0 */ function getLogDomain(data, valueAccessor) { var _getLinearDomain = getLinearDomain(data, valueAccessor), _getLinearDomain2 = (0, _slicedToArray2["default"])(_getLinearDomain, 2), d0 = _getLinearDomain2[0], d1 = _getLinearDomain2[1]; return [d0 === 0 ? 1e-5 : d0, d1]; } /** * whether field domain is stops */ function isDomainStops(domain) { return (0, _utils.isPlainObject)(domain) && Array.isArray(domain.stops) && Array.isArray(domain.z); } /** * whether field domain is quantiles */ function isDomainQuantile(domain) { return (0, _utils.isPlainObject)(domain) && Array.isArray(domain.quantiles) && Array.isArray(domain.z); } /** * get the domain at zoom */ function getThresholdsFromQuantiles(quantiles, buckets) { var thresholds = []; if (!Number.isFinite(buckets) || buckets < 1) { return [quantiles[0], quantiles[quantiles.length - 1]]; } for (var i = 1; i < buckets; i++) { // position in sorted array var position = i / buckets; // @ts-ignore thresholds.push((0, _d3Array.quantileSorted)(quantiles, position)); } return thresholds; } /** * get the domain at zoom */ function getDomainStepsbyZoom(domain, steps, z) { var i = (0, _d3Array.bisectLeft)(steps, z); if (steps[i] === z) { // If z is an integer value exactly matching a step, return the corresponding domain return domain[i]; } // Otherwise, return the next coarsest domain return domain[Math.max(i - 1, 0)]; } /** * Get d3 scale function */ function getScaleFunction(scale, range, domain, fixed) { var scaleFunction = _constants.SCALE_FUNC[fixed ? 'linear' : scale]().domain(domain).range(fixed ? domain : range); scaleFunction.scaleType = fixed ? 'linear' : scale; return scaleFunction; } /** * Get threshold scale color labels */ function getThresholdLabels(scale, labelFormat) { var genLength = scale.range().length; return scale.range().map(function (d, i) { var invert = scale.invertExtent(d); var inputs = [i === 0 ? null : (0, _dataUtils.reverseFormatNumber)(labelFormat(invert[0])), i === genLength - 1 ? null : (0, _dataUtils.reverseFormatNumber)(labelFormat(invert[1]))]; return { // raw value range: invert, // formatted value inputs: inputs, label: i === 0 ? "Less than ".concat(labelFormat(invert[1])) : i === genLength - 1 ? "".concat(labelFormat(invert[0]), " or more") : "".concat(labelFormat(invert[0]), " to ").concat(labelFormat(invert[1])) }; }); } /** * Get linear / quant scale color labels */ function getScaleLabels(scale, labelFormat) { return scale.range().map(function (d) { // @ts-ignore var invert = scale.invertExtent(d); var inputs = [(0, _dataUtils.reverseFormatNumber)(labelFormat(invert[0])), (0, _dataUtils.reverseFormatNumber)(labelFormat(invert[1]))]; return { label: "".concat(labelFormat(invert[0]), " to ").concat(labelFormat(invert[1])), // raw value range: invert, // formatted value inputs: inputs }; }); } var customScaleLabelFormat = function customScaleLabelFormat(n) { return n ? (0, _dataUtils.formatNumber)(n, 'real') : 'no value'; }; /** * Get linear / quant scale color breaks */ function getQuantLegends(scale, labelFormat) { if (typeof scale.invertExtent !== 'function') { return []; } var thresholdLabelFormat = function thresholdLabelFormat(n, type) { return n && labelFormat ? labelFormat(n) : n ? (0, _dataUtils.formatNumber)(n, type) : 'no value'; }; var labels = scale.scaleType === 'threshold' ? getThresholdLabels(scale, thresholdLabelFormat) : scale.scaleType === 'custom' ? getThresholdLabels(scale, customScaleLabelFormat) : getScaleLabels(scale, labelFormat); var data = scale.range(); return labels.map(function (label, index) { return _objectSpread({ data: Array.isArray(data[index]) ? (0, _colorUtils.rgbToHex)(data[index]) : data[index] }, label); }); } /** * Get ordinal color scale legends */ function getOrdinalLegends(scale) { var domain = scale.domain(); var labels = scale.domain(); var data = domain.map(scale); return data.map(function (datum, index) { return { data: (0, _colorUtils.isRgbColor)(datum) ? (0, _colorUtils.rgbToHex)(datum) : datum, label: labels[index] }; }); } var defaultFormat = function defaultFormat(d) { return d; }; var getTimeLabelFormat = function getTimeLabelFormat(domain) { var formatter = (0, _filterUtils.getTimeWidgetHintFormatter)(domain); return function (val) { return _moment["default"].utc(val).format(formatter); }; }; function getQuantLabelFormat(domain, fieldType) { // quant scale can only be assigned to linear Fields: real, timestamp, integer return fieldType === _constants.ALL_FIELD_TYPES.timestamp ? getTimeLabelFormat(domain) : !fieldType ? defaultFormat : function (n) { return (0, _dataUtils.isNumber)(n) ? (0, _dataUtils.formatNumber)(n, fieldType) : 'no value'; }; } /** * Get legends for scale */ function getLegendOfScale(_ref) { var scale = _ref.scale, scaleType = _ref.scaleType, labelFormat = _ref.labelFormat, fieldType = _ref.fieldType; if (!scale || scale.byZoom) { return []; } if (scaleType === _constants.SCALE_TYPES.ordinal || scaleType === _constants.SCALE_TYPES.customOrdinal || fieldType === _constants.ALL_FIELD_TYPES.string) { return getOrdinalLegends(scale); } var formatLabel = labelFormat || getQuantLabelFormat(scale.domain(), fieldType); return getQuantLegends(scale, formatLabel); } /** * Get color scale function */ function getLayerColorScale(_ref2) { var range = _ref2.range, domain = _ref2.domain, scaleType = _ref2.scaleType, layer = _ref2.layer; if (range && domain && scaleType) { return layer.getColorScale(scaleType, domain, range); } return null; } /** * Convert colorRange.colorMap into color breaks UI input */ function initializeLayerColorMap(layer, visualChannel) { var domain = layer.config[visualChannel.domain]; var range = layer.config.visConfig[visualChannel.range]; var scaleType = layer.config[visualChannel.scale]; var field = layer.config[visualChannel.field]; var scale = getLayerColorScale({ range: range, domain: domain, scaleType: scaleType, layer: layer }); var colorBreaks = getLegendOfScale({ scale: scale !== null && scale !== void 0 && scale.byZoom ? scale(0) : scale, scaleType: scaleType, fieldType: field.type }); return colorBreaksToColorMap(colorBreaks); } /** * Get visual chanel scale function if it's based on zoom */ function getVisualChannelScaleByZoom(_ref3) { var _scale; var scale = _ref3.scale, layer = _ref3.layer, mapState = _ref3.mapState; if ((_scale = scale) !== null && _scale !== void 0 && _scale.byZoom) { var _layer$meta; var z = (_layer$meta = layer.meta) !== null && _layer$meta !== void 0 && _layer$meta.getZoom ? layer.meta.getZoom(mapState) : mapState === null || mapState === void 0 ? void 0 : mapState.zoom; scale = Number.isFinite(z) ? scale(z) : null; } return scale; } /** * Get categorical colorMap from colors and domain (unique values) */ function getCategoricalColorMap(colors, domain) { // colorMap: [string | string[], hexstring] var colorToUniqueValues = {}; var uniqueValues = (0, _dataUtils.unique)(domain).filter(_commonUtils.notNullorUndefined).sort(); // each unique value assign to a color, the rest unique values assign to last color var lastColor = colors[colors.length - 1]; for (var i = 0; i < uniqueValues.length; ++i) { if (i < colors.length) { colorToUniqueValues[colors[i]] = uniqueValues[i]; } else { colorToUniqueValues[lastColor] = [].concat((0, _toConsumableArray2["default"])(Array.isArray(colorToUniqueValues[lastColor]) ? colorToUniqueValues[lastColor] : [colorToUniqueValues[lastColor]]), [uniqueValues[i]]); } } var colorMap = colors.map(function (color) { if (color in colorToUniqueValues) { return [colorToUniqueValues[color], color]; } return [null, color]; }); return colorMap; } /** * Get categorical colorBreaks from colorMap */ function colorMapToCategoricalColorBreaks(colorMap) { if (!colorMap) { return null; } var colorBreaks = colorMap.map(function (_ref4) { var _ref5 = (0, _slicedToArray2["default"])(_ref4, 2), value = _ref5[0], color = _ref5[1]; return { data: color, label: value }; }); return colorBreaks; } /** * create categorical colorMap from colorBreaks */ function colorBreaksToCategoricalColorMap(colorBreaks) { // colorMap: [string | string[], hexstring] var colors = (0, _uniq["default"])(colorBreaks.map(function (cb) { return cb.data; })); var values = (0, _uniq["default"])(colorBreaks.map(function (cb) { return cb.label; })); return getCategoricalColorMap(colors, values); } /** * Convert color breaks UI input into colorRange.colorMap */ function colorBreaksToColorMap(colorBreaks) { var colorMap = colorBreaks.map(function (colorBreak, i) { // [value, hex] return [colorBreak.inputs ? i === colorBreaks.length - 1 ? null // last : colorBreak.inputs[1] : colorBreak.label, colorBreak.data]; }); // @ts-ignore tuple return colorMap; } /** * Convert colorRange.colorMap into color breaks UI input */ function colorMapToColorBreaks(colorMap) { if (!colorMap) { return null; } var colorBreaks = colorMap.map(function (_ref6, i) { var _ref7 = (0, _slicedToArray2["default"])(_ref6, 2), value = _ref7[0], color = _ref7[1]; var range = i === 0 ? // first [-Infinity, value] : // last i === colorMap.length - 1 ? [colorMap[i - 1][0], Infinity] : // else [colorMap[i - 1][0], value]; return { data: color, range: range, inputs: range, label: // first i === 0 ? "Less than ".concat(value) : // last i === colorMap.length - 1 ? "".concat(colorMap[i - 1][0], " or more") : "".concat(colorMap[i - 1][0], " to ").concat(value) }; }); // @ts-ignore implement conversion for ordinal return colorBreaks; } /** * Whether color breaks is for numeric field */ function isNumericColorBreaks(colorBreaks) { return Boolean(Array.isArray(colorBreaks) && colorBreaks.length && colorBreaks[0].inputs); } // return domainMin, domainMax, histogramMean function getHistogramDomain(_ref8) { var aggregatedBins = _ref8.aggregatedBins, columnStats = _ref8.columnStats, dataset = _ref8.dataset, fieldValueAccessor = _ref8.fieldValueAccessor; var domainMin = Number.POSITIVE_INFINITY; var domainMax = Number.NEGATIVE_INFINITY; var nValid = 0; var domainSum = 0; if (aggregatedBins) { Object.values(aggregatedBins).forEach(function (bin) { var val = bin.value; if ((0, _dataUtils.isNumber)(val)) { if (val < domainMin) domainMin = val; if (val > domainMax) domainMax = val; domainSum += val; nValid += 1; } }); } else { if (columnStats && columnStats.quantiles && columnStats.mean) { // no need to recalcuate min/max/mean if its already in columnStats return [columnStats.quantiles[0].value, columnStats.quantiles[columnStats.quantiles.length - 1].value, columnStats.mean]; } if (dataset && fieldValueAccessor) { dataset.allIndexes.forEach(function (x) { var val = fieldValueAccessor(x); if ((0, _dataUtils.isNumber)(val)) { if (val < domainMin) domainMin = val; if (val > domainMax) domainMax = val; domainSum += val; nValid += 1; } }); } } var histogramMean = nValid > 0 ? domainSum / nValid : 0; return [nValid > 0 ? domainMin : 0, nValid > 0 ? domainMax : 0, histogramMean]; } function resetCategoricalColorMapByIndex(colorMap, index) { if (!colorMap) { return colorMap; } var newColorMap = colorMap.map(function (cm, i) { if (i === index) { return [null, cm[1]]; } return cm; }); return newColorMap; } /** * select rest categorical values for a colorMap by its index */ function selectRestCategoricalColorMapByIndex(colorMap, index, uniqueValues) { if (!colorMap || !uniqueValues) { return colorMap; } // find unique values that has not been used in current colorMap var uniqValueDict = Object.fromEntries(uniqueValues.map(function (val) { return [val, false]; })); colorMap.forEach(function (cm) { (0, _commonUtils.toArray)(cm[0]).forEach(function (v) { if (v) uniqValueDict[v] = true; }); }); var rest = Object.keys(uniqValueDict).filter(function (v) { return !uniqValueDict[v]; }); // use the not used unique values in the selected color map var newColorMap = colorMap.map(function (cm, i) { if (i === index) { return [[].concat((0, _toConsumableArray2["default"])(rest), (0, _toConsumableArray2["default"])((0, _commonUtils.toArray)(cm[0]))), cm[1]]; } return cm; }); return newColorMap; } /** * remove a categorical value from a colorMap by its index */ function removeCategoricalValueFromColorMap(colorMap, item, index) { if (!colorMap) { return colorMap; } var newColorMap = colorMap.map(function (cm, i) { if (i === index) { if (!cm[0]) { return [null, cm[1]]; } var currentUniqueValues = (0, _commonUtils.toArray)(cm[0]); var updatedUniqueValues = currentUniqueValues.filter(function (v) { return v !== item; }); return [updatedUniqueValues, cm[1]]; } return cm; }); return newColorMap; } /** * add categorical values (from multisel dropdown) to a colorMap by its index */ function addCategoricalValuesToColorMap(colorMap, items, index) { if (!colorMap) { return colorMap; } var newColorMap = colorMap.map(function (cm, i) { if (i === index) { if (!cm[0]) { return [items, cm[1]]; } var _currentUniqueValues = (0, _commonUtils.toArray)(cm[0]); var updatedUniqueValues = (0, _uniq["default"])(_currentUniqueValues.concat(items)); return [updatedUniqueValues, cm[1]]; } // remove value from other colorMap var currentUniqueValues = cm[0]; if (Array.isArray(currentUniqueValues)) { var _updatedUniqueValues = currentUniqueValues.filter(function (v) { return !items.includes(v); }); return [_updatedUniqueValues, cm[1]]; } else if (currentUniqueValues && items.includes(currentUniqueValues)) { return [null, cm[1]]; } return cm; }); return newColorMap; } /** * get a color scale func for categorical (custom ordinal) scale */ function getCategoricalColorScale(colorDomain, colorRange) { var useRgb = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; var cMap = colorRange.colorMap ? colorRange.colorMap : getCategoricalColorMap(colorRange.colors, colorDomain); var range = []; var domain = []; cMap.forEach(function (cm) { if (Array.isArray(cm[0])) { cm[0].forEach(function (val) { domain.push(val); range.push(useRgb ? (0, _colorUtils.hexToRgb)(cm[1]) : cm[1]); }); } else { domain.push(cm[0]); range.push(useRgb ? (0, _colorUtils.hexToRgb)(cm[1]) : cm[1]); } }); var scale = getScaleFunction(_constants.SCALE_TYPES.customOrdinal, range, domain, false); scale.unknown(_constants.NO_VALUE_COLOR); return scale; } /** * initialize customPalette by custom scale or customOrdinal scale */ function initCustomPaletteByCustomScale(_ref9) { var scale = _ref9.scale, field = _ref9.field, ordinalDomain = _ref9.ordinalDomain, range = _ref9.range, colorBreaks = _ref9.colorBreaks; var customPaletteName = "color.customPalette.".concat(scale, ".").concat(field.name); // reuse range.colorMap if the field and scale not changed var reuseColorMap = range.colorMap && range.name === customPaletteName && range.type === scale; var colorMap = reuseColorMap ? range.colorMap : scale === _constants.SCALE_TYPES.customOrdinal && ordinalDomain ? getCategoricalColorMap(range.colors, ordinalDomain) : colorBreaks && isNumericColorBreaks(colorBreaks) ? colorBreaksToColorMap(colorBreaks) : null; var colors = reuseColorMap ? range.colors : colorMap ? colorMap.map(function (cm) { return cm[1]; }) : range.colors; // update custom breaks var customPalette = { category: 'Custom', name: customPaletteName, type: scale, colorMap: colorMap, colors: colors || [] }; return customPalette; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZDNBcnJheSIsInJlcXVpcmUiLCJfdW5pcSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfbW9tZW50IiwiX2NvbW1vblV0aWxzIiwiX2NvbnN0YW50cyIsIl9jb2xvclV0aWxzIiwiX2RhdGFVdGlscyIsIl9maWx0ZXJVdGlscyIsIl91dGlscyIsIm93bktleXMiLCJlIiwiciIsInQiLCJPYmplY3QiLCJrZXlzIiwiZ2V0T3duUHJvcGVydHlTeW1ib2xzIiwibyIsImZpbHRlciIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsImVudW1lcmFibGUiLCJwdXNoIiwiYXBwbHkiLCJfb2JqZWN0U3ByZWFkIiwiYXJndW1lbnRzIiwibGVuZ3RoIiwiZm9yRWFjaCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzIiwiZGVmaW5lUHJvcGVydGllcyIsImRlZmluZVByb3BlcnR5IiwiZ2V0UXVhbnRpbGVEb21haW4iLCJkYXRhIiwidmFsdWVBY2Nlc3NvciIsInNvcnRGdW5jIiwidmFsdWVzIiwibWFwIiwibm90TnVsbG9yVW5kZWZpbmVkIiwic29ydCIsImdldE9yZGluYWxEb21haW4iLCJkYXRhQ29udGFpbmVyIiwibWFwSW5kZXgiLCJ1bmlxdWUiLCJnZXRMaW5lYXJEb21haW4iLCJyYW5nZSIsImV4dGVudCIsImQiLCJpIiwidW5kZWZpbmVkIiwiZ2V0TG9nRG9tYWluIiwiX2dldExpbmVhckRvbWFpbiIsIl9nZXRMaW5lYXJEb21haW4yIiwiX3NsaWNlZFRvQXJyYXkyIiwiZDAiLCJkMSIsImlzRG9tYWluU3RvcHMiLCJkb21haW4iLCJpc1BsYWluT2JqZWN0IiwiQXJyYXkiLCJpc0FycmF5Iiwic3RvcHMiLCJ6IiwiaXNEb21haW5RdWFudGlsZSIsInF1YW50aWxlcyIsImdldFRocmVzaG9sZHNGcm9tUXVhbnRpbGVzIiwiYnVja2V0cyIsInRocmVzaG9sZHMiLCJOdW1iZXIiLCJpc0Zpbml0ZSIsInBvc2l0aW9uIiwiZDNRdWFudGlsZSIsImdldERvbWFpblN0ZXBzYnlab29tIiwic3RlcHMiLCJiaXNlY3RMZWZ0IiwiTWF0aCIsIm1heCIsImdldFNjYWxlRnVuY3Rpb24iLCJzY2FsZSIsImZpeGVkIiwic2NhbGVGdW5jdGlvbiIsIlNDQUxFX0ZVTkMiLCJzY2FsZVR5cGUiLCJnZXRUaHJlc2hvbGRMYWJlbHMiLCJsYWJlbEZvcm1hdCIsImdlbkxlbmd0aCIsImludmVydCIsImludmVydEV4dGVudCIsImlucHV0cyIsInJldmVyc2VGb3JtYXROdW1iZXIiLCJsYWJlbCIsImNvbmNhdCIsImdldFNjYWxlTGFiZWxzIiwiY3VzdG9tU2NhbGVMYWJlbEZvcm1hdCIsIm4iLCJmb3JtYXROdW1iZXIiLCJnZXRRdWFudExlZ2VuZHMiLCJ0aHJlc2hvbGRMYWJlbEZvcm1hdCIsInR5cGUiLCJsYWJlbHMiLCJpbmRleCIsInJnYlRvSGV4IiwiZ2V0T3JkaW5hbExlZ2VuZHMiLCJkYXR1bSIsImlzUmdiQ29sb3IiLCJkZWZhdWx0Rm9ybWF0IiwiZ2V0VGltZUxhYmVsRm9ybWF0IiwiZm9ybWF0dGVyIiwiZ2V0VGltZVdpZGdldEhpbnRGb3JtYXR0ZXIiLCJ2YWwiLCJtb21lbnQiLCJ1dGMiLCJmb3JtYXQiLCJnZXRRdWFudExhYmVsRm9ybWF0IiwiZmllbGRUeXBlIiwiQUxMX0ZJRUxEX1RZUEVTIiwidGltZXN0YW1wIiwiaXNOdW1iZXIiLCJnZXRMZWdlbmRPZlNjYWxlIiwiX3JlZiIsImJ5Wm9vbSIsIlNDQUxFX1RZUEVTIiwib3JkaW5hbCIsImN1c3RvbU9yZGluYWwiLCJzdHJpbmciLCJmb3JtYXRMYWJlbCIsImdldExheWVyQ29sb3JTY2FsZSIsIl9yZWYyIiwibGF5ZXIiLCJnZXRDb2xvclNjYWxlIiwiaW5pdGlhbGl6ZUxheWVyQ29sb3JNYXAiLCJ2aXN1YWxDaGFubmVsIiwiY29uZmlnIiwidmlzQ29uZmlnIiwiZmllbGQiLCJjb2xvckJyZWFrcyIsImNvbG9yQnJlYWtzVG9Db2xvck1hcCIsImdldFZpc3VhbENoYW5uZWxTY2FsZUJ5Wm9vbSIsIl9yZWYzIiwiX3NjYWxlIiwibWFwU3RhdGUiLCJfbGF5ZXIkbWV0YSIsIm1ldGEiLCJnZXRab29tIiwiem9vbSIsImdldENhdGVnb3JpY2FsQ29sb3JNYXAiLCJjb2xvcnMiLCJjb2xvclRvVW5pcXVlVmFsdWVzIiwidW5pcXVlVmFsdWVzIiwibGFzdENvbG9yIiwiX3RvQ29uc3VtYWJsZUFycmF5MiIsImNvbG9yTWFwIiwiY29sb3IiLCJjb2xvck1hcFRvQ2F0ZWdvcmljYWxDb2xvckJyZWFrcyIsIl9yZWY0IiwiX3JlZjUiLCJ2YWx1ZSIsImNvbG9yQnJlYWtzVG9DYXRlZ29yaWNhbENvbG9yTWFwIiwidW5pcSIsImNiIiwiY29sb3JCcmVhayIsImNvbG9yTWFwVG9Db2xvckJyZWFrcyIsIl9yZWY2IiwiX3JlZjciLCJJbmZpbml0eSIsImlzTnVtZXJpY0NvbG9yQnJlYWtzIiwiQm9vbGVhbiIsImdldEhpc3RvZ3JhbURvbWFpbiIsIl9yZWY4IiwiYWdncmVnYXRlZEJpbnMiLCJjb2x1bW5TdGF0cyIsImRhdGFzZXQiLCJmaWVsZFZhbHVlQWNjZXNzb3IiLCJkb21haW5NaW4iLCJQT1NJVElWRV9JTkZJTklUWSIsImRvbWFpbk1heCIsIk5FR0FUSVZFX0lORklOSVRZIiwiblZhbGlkIiwiZG9tYWluU3VtIiwiYmluIiwibWVhbiIsImFsbEluZGV4ZXMiLCJ4IiwiaGlzdG9ncmFtTWVhbiIsInJlc2V0Q2F0ZWdvcmljYWxDb2xvck1hcEJ5SW5kZXgiLCJuZXdDb2xvck1hcCIsImNtIiwic2VsZWN0UmVzdENhdGVnb3JpY2FsQ29sb3JNYXBCeUluZGV4IiwidW5pcVZhbHVlRGljdCIsImZyb21FbnRyaWVzIiwidG9BcnJheSIsInYiLCJyZXN0IiwicmVtb3ZlQ2F0ZWdvcmljYWxWYWx1ZUZyb21Db2xvck1hcCIsIml0ZW0iLCJjdXJyZW50VW5pcXVlVmFsdWVzIiwidXBkYXRlZFVuaXF1ZVZhbHVlcyIsImFkZENhdGVnb3JpY2FsVmFsdWVzVG9Db2xvck1hcCIsIml0ZW1zIiwiaW5jbHVkZXMiLCJnZXRDYXRlZ29yaWNhbENvbG9yU2NhbGUiLCJjb2xvckRvbWFpbiIsImNvbG9yUmFuZ2UiLCJ1c2VSZ2IiLCJjTWFwIiwiaGV4VG9SZ2IiLCJ1bmtub3duIiwiTk9fVkFMVUVfQ09MT1IiLCJpbml0Q3VzdG9tUGFsZXR0ZUJ5Q3VzdG9tU2NhbGUiLCJfcmVmOSIsIm9yZGluYWxEb21haW4iLCJjdXN0b21QYWxldHRlTmFtZSIsIm5hbWUiLCJyZXVzZUNvbG9yTWFwIiwiY3VzdG9tUGFsZXR0ZSIsImNhdGVnb3J5Il0sInNvdXJjZXMiOlsiLi4vc3JjL2RhdGEtc2NhbGUtdXRpbHMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVFxuLy8gQ29weXJpZ2h0IGNvbnRyaWJ1dG9ycyB0byB0aGUga2VwbGVyLmdsIHByb2plY3RcblxuaW1wb3J0IHtiaXNlY3RMZWZ0LCBxdWFudGlsZVNvcnRlZCBhcyBkM1F1YW50aWxlLCBleHRlbnR9IGZyb20gJ2QzLWFycmF5JztcbmltcG9ydCB1bmlxIGZyb20gJ2xvZGFzaC91bmlxJztcbmltcG9ydCBtb21lbnQgZnJvbSAnbW9tZW50JztcblxuaW1wb3J0IHtub3ROdWxsb3JVbmRlZmluZWQsIHRvQXJyYXl9IGZyb20gJ0BrZXBsZXIuZ2wvY29tbW9uLXV0aWxzJztcbmltcG9ydCB7QUxMX0ZJRUxEX1RZUEVTLCBTQ0FMRV9GVU5DLCBTQ0FMRV9UWVBFUywgTk9fVkFMVUVfQ09MT1J9IGZyb20gJ0BrZXBsZXIuZ2wvY29uc3RhbnRzJztcbi8vIGltcG9ydCB7RmlsdGVyUHJvcHMsIEtlcGxlclRhYmxlfSBmcm9tICdAa2VwbGVyLmdsL2xheWVycyc7XG5pbXBvcnQge1xuICBBZ2dyZWdhdGVkQmluLFxuICBDb2xvck1hcCxcbiAgQ29sb3JSYW5nZSxcbiAgSGV4Q29sb3IsXG4gIEtlcGxlckxheWVyIGFzIExheWVyLFxuICBNYXBTdGF0ZSxcbiAgVmlzdWFsQ2hhbm5lbCxcbiAgVmlzdWFsQ2hhbm5lbERvbWFpbixcbiAgUkdCQ29sb3IsXG4gIFJHQkFDb2xvcixcbiAgQ29sb3JVSSxcbiAgRmllbGRcbn0gZnJvbSAnQGtlcGxlci5nbC90eXBlcyc7XG5cbmltcG9ydCB7aXNSZ2JDb2xvciwgcmdiVG9IZXgsIGhleFRvUmdifSBmcm9tICcuL2NvbG9yLXV0aWxzJztcbmltcG9ydCB7RGF0YUNvbnRhaW5lckludGVyZmFjZX0gZnJvbSAnLi9kYXRhLWNvbnRhaW5lci1pbnRlcmZhY2UnO1xuaW1wb3J0IHtmb3JtYXROdW1iZXIsIGlzTnVtYmVyLCByZXZlcnNlRm9ybWF0TnVtYmVyLCB1bmlxdWV9IGZyb20gJy4vZGF0YS11dGlscyc7XG5pbXBvcnQge2dldFRpbWVXaWRnZXRIaW50Rm9ybWF0dGVyfSBmcm9tICcuL2ZpbHRlci11dGlscyc7XG5pbXBvcnQge2lzUGxhaW5PYmplY3R9IGZyb20gJy4vdXRpbHMnO1xuXG5leHBvcnQgdHlwZSBDb2xvckJyZWFrID0ge1xuICBkYXRhOiBIZXhDb2xvcjtcbiAgbGFiZWw6IHN0cmluZztcbiAgcmFuZ2U6IG51bWJlcltdO1xuICBpbnB1dHM6IG51bWJlcltdO1xufTtcbmV4cG9ydCB0eXBlIENvbG9yQnJlYWtPcmRpbmFsID0ge1xuICBkYXRhOiBIZXhDb2xvcjtcbiAgbGFiZWw6IHN0cmluZyB8IG51bWJlciB8IHN0cmluZ1tdIHwgbnVtYmVyW10gfCBudWxsO1xufTtcblxuZXhwb3J0IHR5cGUgRDNTY2FsZUZ1bmN0aW9uID0gUmVjb3JkPHN0cmluZywgYW55PiAmICgoeDogYW55KSA9PiBhbnkpO1xuXG4vLyBUT0RPIGlzb2xhdGUgdHlwZXMgLSBkZXBlbmRzIG9uIEBrZXBsZXIuZ2wvbGF5ZXJzXG50eXBlIEZpbHRlclByb3BzID0gYW55O1xudHlwZSBLZXBsZXJUYWJsZSA9IGFueTtcblxuZXhwb3J0IHR5cGUgTGFiZWxGb3JtYXQgPSAobjogbnVtYmVyLCB0eXBlPzogc3RyaW5nKSA9PiBzdHJpbmc7XG50eXBlIGRhdGFWYWx1ZUFjY2Vzc29yID0gPFQ+KHBhcmFtOiBUKSA9PiBUO1xudHlwZSBkYXRhQ29udGFpbmVyVmFsdWVBY2Nlc3NvciA9IChkOiB7aW5kZXg6IG51bWJlcn0sIGRjOiBEYXRhQ29udGFpbmVySW50ZXJmYWNlKSA9PiBhbnk7XG50eXBlIHNvcnQgPSAoYTogYW55LCBiOiBhbnkpID0+IGFueTtcbi8qKlxuICogcmV0dXJuIHF1YW50aWxlIGRvbWFpbiBmb3IgYW4gYXJyYXkgb2YgZGF0YVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UXVhbnRpbGVEb21haW4oXG4gIGRhdGE6IGFueVtdLFxuICB2YWx1ZUFjY2Vzc29yPzogZGF0YVZhbHVlQWNjZXNzb3IsXG4gIHNvcnRGdW5jPzogc29ydFxuKTogbnVtYmVyW10ge1xuICBjb25zdCB2YWx1ZXMgPSB0eXBlb2YgdmFsdWVBY2Nlc3NvciA9PT0gJ2Z1bmN0aW9uJyA/IGRhdGEubWFwKHZhbHVlQWNjZXNzb3IpIDogZGF0YTtcblxuICByZXR1cm4gdmFsdWVzLmZpbHRlcihub3ROdWxsb3JVbmRlZmluZWQpLnNvcnQoc29ydEZ1bmMpO1xufVxuXG4vKipcbiAqIHJldHVybiBvcmRpbmFsIGRvbWFpbiBmb3IgYSBkYXRhIGNvbnRhaW5lclxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0T3JkaW5hbERvbWFpbihcbiAgZGF0YUNvbnRhaW5lcjogRGF0YUNvbnRhaW5lckludGVyZmFjZSxcbiAgdmFsdWVBY2Nlc3NvcjogZGF0YUNvbnRhaW5lclZhbHVlQWNjZXNzb3Jcbik6IHN0cmluZ1tdIHtcbiAgY29uc3QgdmFsdWVzID0gZGF0YUNvbnRhaW5lci5tYXBJbmRleCh2YWx1ZUFjY2Vzc29yKTtcblxuICByZXR1cm4gdW5pcXVlKHZhbHVlcykuZmlsdGVyKG5vdE51bGxvclVuZGVmaW5lZCkuc29ydCgpO1xufVxuXG4vKipcbiAqIHJldHVybiBsaW5lYXIgZG9tYWluIGZvciBhbiBhcnJheSBvZiBkYXRhXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRMaW5lYXJEb21haW4oXG4gIGRhdGE6IG51bWJlcltdLFxuICB2YWx1ZUFjY2Vzc29yPzogZGF0YVZhbHVlQWNjZXNzb3Jcbik6IFtudW1iZXIsIG51bWJlcl0ge1xuICBjb25zdCByYW5nZSA9IHR5cGVvZiB2YWx1ZUFjY2Vzc29yID09PSAnZnVuY3Rpb24nID8gZXh0ZW50KGRhdGEsIHZhbHVlQWNjZXNzb3IpIDogZXh0ZW50KGRhdGEpO1xuICByZXR1cm4gcmFuZ2UubWFwKChkOiB1bmRlZmluZWQgfCBudW1iZXIsIGk6IG51bWJlcikgPT4gKGQgPT09IHVuZGVmaW5lZCA/IGkgOiBkKSkgYXMgW1xuICAgIG51bWJlcixcbiAgICBudW1iZXJcbiAgXTtcbn1cblxuLyoqXG4gKiByZXR1cm4gbGluZWFyIGRvbWFpbiBmb3IgYW4gYXJyYXkgb2YgZGF0YS4gQSBsb2cgc2NhbGUgZG9tYWluIGNhbm5vdCBjb250YWluIDBcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExvZ0RvbWFpbihkYXRhOiBhbnlbXSwgdmFsdWVBY2Nlc3NvcjogZGF0YVZhbHVlQWNjZXNzb3IpOiBbbnVtYmVyLCBudW1iZXJdIHtcbiAgY29uc3QgW2QwLCBkMV0gPSBnZXRMaW5lYXJEb21haW4oZGF0YSwgdmFsdWVBY2Nlc3Nvcik7XG4gIHJldHVybiBbZDAgPT09IDAgPyAxZS01IDogZDAsIGQxXTtcbn1cblxuZXhwb3J0IHR5cGUgRG9tYWluU3RvcHMgPSB7XG4gIHN0b3BzOiBudW1iZXJbXTtcbiAgejogbnVtYmVyW107XG59O1xuXG4vKipcbiAqIHdoZXRoZXIgZmllbGQgZG9tYWluIGlzIHN0b3BzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0RvbWFpblN0b3BzKGRvbWFpbjogdW5rbm93bik6IGRvbWFpbiBpcyBEb21haW5TdG9wcyB7XG4gIHJldHVybiBpc1BsYWluT2JqZWN0KGRvbWFpbikgJiYgQXJyYXkuaXNBcnJheShkb21haW4uc3RvcHMpICYmIEFycmF5LmlzQXJyYXkoZG9tYWluLnopO1xufVxuXG5leHBvcnQgdHlwZSBEb21haW5RdWFudGlsZXMgPSB7XG4gIHF1YW50aWxlczogbnVtYmVyW107XG4gIHo6IG51bWJlcltdO1xufTtcblxuLyoqXG4gKiB3aGV0aGVyIGZpZWxkIGRvbWFpbiBpcyBxdWFudGlsZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzRG9tYWluUXVhbnRpbGUoZG9tYWluOiBhbnkpOiBkb21haW4gaXMgRG9tYWluUXVhbnRpbGVzIHtcbiAgcmV0dXJuIGlzUGxhaW5PYmplY3QoZG9tYWluKSAmJiBBcnJheS5pc0FycmF5KGRvbWFpbi5xdWFudGlsZXMpICYmIEFycmF5LmlzQXJyYXkoZG9tYWluLnopO1xufVxuXG4vKipcbiAqIGdldCB0aGUgZG9tYWluIGF0IHpvb21cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFRocmVzaG9sZHNGcm9tUXVhbnRpbGVzKFxuICBxdWFudGlsZXM6IG51bWJlcltdLFxuICBidWNrZXRzOiBudW1iZXJcbik6IChudW1iZXIgfCB1bmRlZmluZWQpW10ge1xuICBjb25zdCB0aHJlc2hvbGRzID0gW107XG4gIGlmICghTnVtYmVyLmlzRmluaXRlKGJ1Y2tldHMpIHx8IGJ1Y2tldHMgPCAxKSB7XG4gICAgcmV0dXJuIFtxdWFudGlsZXNbMF0sIHF1YW50aWxlc1txdWFudGlsZXMubGVuZ3RoIC0gMV1dO1xuICB9XG4gIGZvciAobGV0IGkgPSAxOyBpIDwgYnVja2V0czsgaSsrKSB7XG4gICAgLy8gcG9zaXRpb24gaW4gc29ydGVkIGFycmF5XG4gICAgY29uc3QgcG9zaXRpb24gPSBpIC8gYnVja2V0cztcbiAgICAvLyBAdHMtaWdub3JlXG4gICAgdGhyZXNob2xkcy5wdXNoKGQzUXVhbnRpbGUocXVhbnRpbGVzLCBwb3NpdGlvbikpO1xuICB9XG5cbiAgcmV0dXJuIHRocmVzaG9sZHM7XG59XG5cbi8qKlxuICogZ2V0IHRoZSBkb21haW4gYXQgem9vbVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0RG9tYWluU3RlcHNieVpvb20oZG9tYWluOiBhbnlbXSwgc3RlcHM6IG51bWJlcltdLCB6OiBudW1iZXIpOiBhbnkge1xuICBjb25zdCBpID0gYmlzZWN0TGVmdChzdGVwcywgeik7XG5cbiAgaWYgKHN0ZXBzW2ldID09PSB6KSB7XG4gICAgLy8gSWYgeiBpcyBhbiBpbnRlZ2VyIHZhbHVlIGV4YWN0bHkgbWF0Y2hpbmcgYSBzdGVwLCByZXR1cm4gdGhlIGNvcnJlc3BvbmRpbmcgZG9tYWluXG4gICAgcmV0dXJuIGRvbWFpbltpXTtcbiAgfVxuICAvLyBPdGhlcndpc2UsIHJldHVybiB0aGUgbmV4dCBjb2Fyc2VzdCBkb21haW5cbiAgcmV0dXJuIGRvbWFpbltNYXRoLm1heChpIC0gMSwgMCldO1xufVxuXG4vKipcbiAqIEdldCBkMyBzY2FsZSBmdW5jdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2NhbGVGdW5jdGlvbihcbiAgc2NhbGU6IHN0cmluZyxcbiAgcmFuZ2U6IGFueVtdIHwgSXRlcmFibGVJdGVyYXRvcjxhbnk+LFxuICBkb21haW46IChudW1iZXIgfCB1bmRlZmluZWQpW10gfCBzdHJpbmdbXSB8IEl0ZXJhYmxlSXRlcmF0b3I8YW55PixcbiAgZml4ZWQ/OiBib29sZWFuXG4pOiBEM1NjYWxlRnVuY3Rpb24ge1xuICBjb25zdCBzY2FsZUZ1bmN0aW9uID0gU0NBTEVfRlVOQ1tmaXhlZCA/ICdsaW5lYXInIDogc2NhbGVdKClcbiAgICAuZG9tYWluKGRvbWFpbilcbiAgICAucmFuZ2UoZml4ZWQgPyBkb21haW4gOiByYW5nZSk7XG4gIHNjYWxlRnVuY3Rpb24uc2NhbGVUeXBlID0gZml4ZWQgPyAnbGluZWFyJyA6IHNjYWxlO1xuICByZXR1cm4gc2NhbGVGdW5jdGlvbjtcbn1cblxuLyoqXG4gKiBHZXQgdGhyZXNob2xkIHNjYWxlIGNvbG9yIGxhYmVsc1xuICovXG5mdW5jdGlvbiBnZXRUaHJlc2hvbGRMYWJlbHMoXG4gIHNjYWxlOiBEM1NjYWxlRnVuY3Rpb24sXG4gIGxhYmVsRm9ybWF0OiBMYWJlbEZvcm1hdFxuKTogT21pdDxDb2xvckJyZWFrLCAnZGF0YSc+W10ge1xuICBjb25zdCBnZW5MZW5ndGggPSBzY2FsZS5yYW5nZSgpLmxlbmd0aDtcbiAgcmV0dXJuIHNjYWxlLnJhbmdlKCkubWFwKChkLCBpKSA9PiB7XG4gICAgY29uc3QgaW52ZXJ0ID0gc2NhbGUuaW52ZXJ0RXh0ZW50KGQpO1xuICAgIGNvbnN0IGlucHV0cyA9IFtcbiAgICAgIGkgPT09IDAgPyBudWxsIDogcmV2ZXJzZUZvcm1hdE51bWJlcihsYWJlbEZvcm1hdChpbnZlcnRbMF0pKSxcbiAgICAgIGkgPT09IGdlbkxlbmd0aCAtIDEgPyBudWxsIDogcmV2ZXJzZUZvcm1hdE51bWJlcihsYWJlbEZvcm1hdChpbnZlcnRbMV0pKVxuICAgIF07XG4gICAgcmV0dXJuIHtcbiAgICAgIC8vIHJhdyB2YWx1ZVxuICAgICAgcmFuZ2U6IGludmVydCxcbiAgICAgIC8vIGZvcm1hdHRlZCB2YWx1ZVxuICAgICAgaW5wdXRzLFxuICAgICAgbGFiZWw6XG4gICAgICAgIGkgPT09IDBcbiAgICAgICAgICA/IGBMZXNzIHRoYW4gJHtsYWJlbEZvcm1hdChpbnZlcnRbMV0pfWBcbiAgICAgICAgICA6IGkgPT09IGdlbkxlbmd0aCAtIDFcbiAgICAgICAgICA/IGAke2xhYmVsRm9ybWF0KGludmVydFswXSl9IG9yIG1vcmVgXG4gICAgICAgICAgOiBgJHtsYWJlbEZvcm1hdChpbnZlcnRbMF0pfSB0byAke2xhYmVsRm9ybWF0KGludmVydFsxXSl9YFxuICAgIH07XG4gIH0pO1xufVxuXG4vKipcbiAqIEdldCBsaW5lYXIgLyBxdWFudCBzY2FsZSBjb2xvciBsYWJlbHNcbiAqL1xuZnVuY3Rpb24gZ2V0U2NhbGVMYWJlbHMoXG4gIHNjYWxlOiBEM1NjYWxlRnVuY3Rpb24sXG4gIGxhYmVsRm9ybWF0OiBMYWJlbEZvcm1hdFxuKTogT21pdDxDb2xvckJyZWFrLCAnZGF0YSc+W10ge1xuICByZXR1cm4gc2NhbGUucmFuZ2UoKS5tYXAoZCA9PiB7XG4gICAgLy8gQHRzLWlnbm9yZVxuICAgIGNvbnN0IGludmVydCA9IHNjYWxlLmludmVydEV4dGVudChkKTtcbiAgICBjb25zdCBpbnB1dHMgPSBbXG4gICAgICByZXZlcnNlRm9ybWF0TnVtYmVyKGxhYmVsRm9ybWF0KGludmVydFswXSkpLFxuICAgICAgcmV2ZXJzZUZvcm1hdE51bWJlcihsYWJlbEZvcm1hdChpbnZlcnRbMV0pKVxuICAgIF07XG5cbiAgICByZXR1cm4ge1xuICAgICAgbGFiZWw6IGAke2xhYmVsRm9ybWF0KGludmVydFswXSl9IHRvICR7bGFiZWxGb3JtYXQoaW52ZXJ0WzFdKX1gLFxuICAgICAgLy8gcmF3IHZhbHVlXG4gICAgICByYW5nZTogaW52ZXJ0LFxuICAgICAgLy8gZm9ybWF0dGVkIHZhbHVlXG4gICAgICBpbnB1dHNcbiAgICB9O1xuICB9KTtcbn1cblxuY29uc3QgY3VzdG9tU2NhbGVMYWJlbEZvcm1hdCA9IG4gPT4gKG4gPyBmb3JtYXROdW1iZXIobiwgJ3JlYWwnKSA6ICdubyB2YWx1ZScpO1xuLyoqXG4gKiBHZXQgbGluZWFyIC8gcXVhbnQgc2NhbGUgY29sb3IgYnJlYWtzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRRdWFudExlZ2VuZHMoc2NhbGU6IEQzU2NhbGVGdW5jdGlvbiwgbGFiZWxGb3JtYXQ6IExhYmVsRm9ybWF0KTogQ29sb3JCcmVha1tdIHtcbiAgaWYgKHR5cGVvZiBzY2FsZS5pbnZlcnRFeHRlbnQgIT09ICdmdW5jdGlvbicpIHtcbiAgICByZXR1cm4gW107XG4gIH1cbiAgY29uc3QgdGhyZXNob2xkTGFiZWxGb3JtYXQgPSAobiwgdHlwZSkgPT5cbiAgICBuICYmIGxhYmVsRm9ybWF0ID8gbGFiZWxGb3JtYXQobikgOiBuID8gZm9ybWF0TnVtYmVyKG4sIHR5cGUpIDogJ25vIHZhbHVlJztcbiAgY29uc3QgbGFiZWxzID1cbiAgICBzY2FsZS5zY2FsZVR5cGUgPT09ICd0aHJlc2hvbGQnXG4gICAgICA/IGdldFRocmVzaG9sZExhYmVscyhzY2FsZSwgdGhyZXNob2xkTGFiZWxGb3JtYXQpXG4gICAgICA6IHNjYWxlLnNjYWxlVHlwZSA9PT0gJ2N1c3RvbSdcbiAgICAgID8gZ2V0VGhyZXNob2xkTGFiZWxzKHNjYWxlLCBjdXN0b21TY2FsZUxhYmVsRm9ybWF0KVxuICAgICAgOiBnZXRTY2FsZUxhYmVscyhzY2FsZSwgbGFiZWxGb3JtYXQpO1xuXG4gIGNvbnN0IGRhdGEgPSBzY2FsZS5yYW5nZSgpO1xuXG4gIHJldHVybiBsYWJlbHMubWFwKChsYWJlbCwgaW5kZXgpID0+ICh7XG4gICAgZGF0YTogQXJyYXkuaXNBcnJheShkYXRhW2luZGV4XSkgPyByZ2JUb0hleChkYXRhW2luZGV4XSkgOiBkYXRhW2luZGV4XSxcbiAgICAuLi5sYWJlbFxuICB9KSk7XG59XG5cbi8qKlxuICogR2V0IG9yZGluYWwgY29sb3Igc2NhbGUgbGVnZW5kc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0T3JkaW5hbExlZ2VuZHMoc2NhbGU6IEQzU2NhbGVGdW5jdGlvbik6IENvbG9yQnJlYWtPcmRpbmFsW10ge1xuICBjb25zdCBkb21haW4gPSBzY2FsZS5kb21haW4oKTtcbiAgY29uc3QgbGFiZWxzID0gc2NhbGUuZG9tYWluKCk7XG4gIGNvbnN0IGRhdGEgPSBkb21haW4ubWFwKHNjYWxlKTtcblxuICByZXR1cm4gZGF0YS5tYXAoKGRhdHVtLCBpbmRleCkgPT4gKHtcbiAgICBkYXRhOiBpc1JnYkNvbG9yKGRhdHVtKSA/IHJnYlRvSGV4KGRhdHVtKSA6IGRhdHVtLFxuICAgIGxhYmVsOiBsYWJlbHNbaW5kZXhdXG4gIH0pKTtcbn1cblxuY29uc3QgZGVmYXVsdEZvcm1hdCA9IGQgPT4gZDtcblxuY29uc3QgZ2V0VGltZUxhYmVsRm9ybWF0ID0gZG9tYWluID0+IHtcbiAgY29uc3QgZm9ybWF0dGVyID0gZ2V0VGltZVdpZGdldEhpbnRGb3JtYXR0ZXIoZG9tYWluKTtcbiAgcmV0dXJuIHZhbCA9PiBtb21lbnQudXRjKHZhbCkuZm9ybWF0KGZvcm1hdHRlcik7XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gZ2V0UXVhbnRMYWJlbEZvcm1hdChkb21haW4sIGZpZWxkVHlwZSkge1xuICAvLyBxdWFudCBzY2FsZSBjYW4gb25seSBiZSBhc3NpZ25lZCB0byBsaW5lYXIgRmllbGRzOiByZWFsLCB0aW1lc3RhbXAsIGludGVnZXJcbiAgcmV0dXJuIGZpZWxkVHlwZSA9PT0gQUxMX0ZJRUxEX1RZUEVTLnRpbWVzdGFtcFxuICAgID8gZ2V0VGltZUxhYmVsRm9ybWF0KGRvbWFpbilcbiAgICA6ICFmaWVsZFR5cGVcbiAgICA/IGRlZmF1bHRGb3JtYXRcbiAgICA6IG4gPT4gKGlzTnVtYmVyKG4pID8gZm9ybWF0TnVtYmVyKG4sIGZpZWxkVHlwZSkgOiAnbm8gdmFsdWUnKTtcbn1cblxuLyoqXG4gKiBHZXQgbGVnZW5kcyBmb3Igc2NhbGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExlZ2VuZE9mU2NhbGUoe1xuICBzY2FsZSxcbiAgc2NhbGVUeXBlLFxuICBsYWJlbEZvcm1hdCxcbiAgZmllbGRUeXBlXG59OiB7XG4gIHNjYWxlPzogRDNTY2FsZUZ1bmN0aW9uIHwgbnVsbDtcbiAgc2NhbGVUeXBlOiBzdHJpbmc7XG4gIGxhYmVsRm9ybWF0PzogTGFiZWxGb3JtYXQ7XG4gIGZpZWxkVHlwZTogc3RyaW5nIHwgbnVsbCB8IHVuZGVmaW5lZDtcbn0pOiBDb2xvckJyZWFrW10gfCBDb2xvckJyZWFrT3JkaW5hbFtdIHtcbiAgaWYgKCFzY2FsZSB8fCBzY2FsZS5ieVpvb20pIHtcbiAgICByZXR1cm4gW107XG4gIH1cbiAgaWYgKFxuICAgIHNjYWxlVHlwZSA9PT0gU0NBTEVfVFlQRVMub3JkaW5hbCB8fFxuICAgIHNjYWxlVHlwZSA9PT0gU0NBTEVfVFlQRVMuY3VzdG9tT3JkaW5hbCB8fFxuICAgIGZpZWxkVHlwZSA9PT0gQUxMX0ZJRUxEX1RZUEVTLnN0cmluZ1xuICApIHtcbiAgICByZXR1cm4gZ2V0T3JkaW5hbExlZ2VuZHMoc2NhbGUpO1xuICB9XG5cbiAgY29uc3QgZm9ybWF0TGFiZWwgPSBsYWJlbEZvcm1hdCB8fCBnZXRRdWFudExhYmVsRm9ybWF0KHNjYWxlLmRvbWFpbigpLCBmaWVsZFR5cGUpO1xuXG4gIHJldHVybiBnZXRRdWFudExlZ2VuZHMoc2NhbGUsIGZvcm1hdExhYmVsKTtcbn1cblxuLyoqXG4gKiBHZXQgY29sb3Igc2NhbGUgZnVuY3Rpb25cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExheWVyQ29sb3JTY2FsZSh7XG4gIHJhbmdlLFxuICBkb21haW4sXG4gIHNjYWxlVHlwZSxcbiAgbGF5ZXJcbn06IHtcbiAgcmFuZ2U6IENvbG9yUmFuZ2UgfCBudWxsIHwgdW5kZWZpbmVkO1xuICBkb21haW46IFZpc3VhbENoYW5uZWxEb21haW47XG4gIHNjYWxlVHlwZTogc3RyaW5nO1xuICBsYXllcjogTGF5ZXI7XG4gIGlzRml4ZWQ/OiBib29sZWFuO1xufSk6IEQzU2NhbGVGdW5jdGlvbiB8IG51bGwge1xuICBpZiAocmFuZ2UgJiYgZG9tYWluICYmIHNjYWxlVHlwZSkge1xuICAgIHJldHVybiBsYXllci5nZXRDb2xvclNjYWxlKHNjYWxlVHlwZSwgZG9tYWluLCByYW5nZSk7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogQ29udmVydCBjb2xvclJhbmdlLmNvbG9yTWFwIGludG8gY29sb3IgYnJlYWtzIFVJIGlucHV0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbml0aWFsaXplTGF5ZXJDb2xvck1hcChsYXllcjogTGF5ZXIsIHZpc3VhbENoYW5uZWw6IFZpc3VhbENoYW5uZWwpOiBDb2xvck1hcCB7XG4gIGNvbnN0IGRvbWFpbiA9IGxheWVyLmNvbmZpZ1t2aXN1YWxDaGFubmVsLmRvbWFpbl07XG4gIGNvbnN0IHJhbmdlID0gbGF5ZXIuY29uZmlnLnZpc0NvbmZpZ1t2aXN1YWxDaGFubmVsLnJhbmdlXTtcbiAgY29uc3Qgc2NhbGVUeXBlID0gbGF5ZXIuY29uZmlnW3Zpc3VhbENoYW5uZWwuc2NhbGVdO1xuICBjb25zdCBmaWVsZCA9IGxheWVyLmNvbmZpZ1t2aXN1YWxDaGFubmVsLmZpZWxkXTtcblxuICBjb25zdCBzY2FsZSA9IGdldExheWVyQ29sb3JTY2FsZSh7XG4gICAgcmFuZ2UsXG4gICAgZG9tYWluLFxuICAgIHNjYWxlVHlwZSxcbiAgICBsYXllclxuICB9KTtcblxuICBjb25zdCBjb2xvckJyZWFrcyA9IGdldExlZ2VuZE9mU2NhbGUoe1xuICAgIHNjYWxlOiBzY2FsZT8uYnlab29tID8gc2NhbGUoMCkgOiBzY2FsZSxcbiAgICBzY2FsZVR5cGUsXG4gICAgZmllbGRUeXBlOiBmaWVsZC50eXBlXG4gIH0pO1xuICByZXR1cm4gY29sb3JCcmVha3NUb0NvbG9yTWFwKGNvbG9yQnJlYWtzKTtcbn1cblxuLyoqXG4gKiBHZXQgdmlzdWFsIGNoYW5lbCBzY2FsZSBmdW5jdGlvbiBpZiBpdCdzIGJhc2VkIG9uIHpvb21cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFZpc3VhbENoYW5uZWxTY2FsZUJ5Wm9vbSh7XG4gIHNjYWxlLFxuICBsYXllcixcbiAgbWFwU3RhdGVcbn06IHtcbiAgc2NhbGU6IEQzU2NhbGVGdW5jdGlvbiB8IG51bGw7XG4gIGxheWVyOiBMYXllcjtcbiAgbWFwU3RhdGU/OiBNYXBTdGF0ZTtcbn0pOiBEM1NjYWxlRnVuY3Rpb24gfCBudWxsIHtcbiAgaWYgKHNjYWxlPy5ieVpvb20pIHtcbiAgICBjb25zdCB6ID0gbGF5ZXIubWV0YT8uZ2V0Wm9vbSA/IGxheWVyLm1ldGEuZ2V0Wm9vbShtYXBTdGF0ZSkgOiBtYXBTdGF0ZT8uem9vbTtcbiAgICBzY2FsZSA9IE51bWJlci5pc0Zpbml0ZSh6KSA/IHNjYWxlKHopIDogbnVsbDtcbiAgfVxuICByZXR1cm4gc2NhbGU7XG59XG5cbi8qKlxuICogR2V0IGNhdGVnb3JpY2FsIGNvbG9yTWFwIGZyb20gY29sb3JzIGFuZCBkb21haW4gKHVuaXF1ZSB2YWx1ZXMpXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRDYXRlZ29yaWNhbENvbG9yTWFwKFxuICBjb2xvcnM6IHN0cmluZ1tdLFxuICBkb21haW46IChzdHJpbmcgfCBudW1iZXIgfCBzdHJpbmdbXSB8IG51bWJlcltdIHwgbnVsbClbXVxuKTogYW55IHtcbiAgLy8gY29sb3JNYXA6IFtzdHJpbmcgfCBzdHJpbmdbXSwgaGV4c3RyaW5nXVxuICBjb25zdCBjb2xvclRvVW5pcXVlVmFsdWVzID0ge307XG4gIGNvbnN0IHVuaXF1ZVZhbHVlcyA9IHVuaXF1ZShkb21haW4pLmZpbHRlcihub3ROdWxsb3JVbmRlZmluZWQpLnNvcnQoKTtcbiAgLy8gZWFjaCB1bmlxdWUgdmFsdWUgYXNzaWduIHRvIGEgY29sb3IsIHRoZSByZXN0IHVuaXF1ZSB2YWx1ZXMgYXNzaWduIHRvIGxhc3QgY29sb3JcbiAgY29uc3QgbGFzdENvbG9yID0gY29sb3JzW2NvbG9ycy5sZW5ndGggLSAxXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCB1bmlxdWVWYWx1ZXMubGVuZ3RoOyArK2kpIHtcbiAgICBpZiAoaSA8IGNvbG9ycy5sZW5ndGgpIHtcbiAgICAgIGNvbG9yVG9VbmlxdWVWYWx1ZXNbY29sb3JzW2ldXSA9IHVuaXF1ZVZhbHVlc1tpXTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29sb3JUb1VuaXF1ZVZhbHVlc1tsYXN0Q29sb3JdID0gW1xuICAgICAgICAuLi4oQXJyYXkuaXNBcnJheShjb2xvclRvVW5pcXVlVmFsdWVzW2xhc3RDb2xvcl0pXG4gICAgICAgICAgPyBjb2xvclRvVW5pcXVlVmFsdWVzW2xhc3RDb2xvcl1cbiAgICAgICAgICA6IFtjb2xvclRvVW5pcXVlVmFsdWVzW2xhc3RDb2xvcl1dKSxcbiAgICAgICAgdW5pcXVlVmFsdWVzW2ldXG4gICAgICBdO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGNvbG9yTWFwID0gY29sb3JzLm1hcChjb2xvciA9PiB7XG4gICAgaWYgKGNvbG9yIGluIGNvbG9yVG9VbmlxdWVWYWx1ZXMpIHtcbiAgICAgIHJldHVybiBbY29sb3JUb1VuaXF1ZVZhbHVlc1tjb2xvcl0sIGNvbG9yXTtcbiAgICB9XG4gICAgcmV0dXJuIFtudWxsLCBjb2xvcl07XG4gIH0pO1xuXG4gIHJldHVybiBjb2xvck1hcDtcbn1cblxuLyoqXG4gKiBHZXQgY2F0ZWdvcmljYWwgY29sb3JCcmVha3MgZnJvbSBjb2xvck1hcFxuICovXG5leHBvcnQgZnVuY3Rpb24gY29sb3JNYXBUb0NhdGVnb3JpY2FsQ29sb3JCcmVha3MoXG4gIGNvbG9yTWFwPzogQ29sb3JNYXAgfCBudWxsXG4pOiBDb2xvckJyZWFrT3JkaW5hbFtdIHwgbnVsbCB7XG4gIGlmICghY29sb3JNYXApIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBjb25zdCBjb2xvckJyZWFrcyA9IGNvbG9yTWFwLm1hcCgoW3ZhbHVlLCBjb2xvcl0pID0+IHtcbiAgICByZXR1cm4ge1xuICAgICAgZGF0YTogY29sb3IsXG4gICAgICBsYWJlbDogdmFsdWVcbiAgICB9O1xuICB9KTtcblxuICByZXR1cm4gY29sb3JCcmVha3M7XG59XG5cbi8qKlxuICogY3JlYXRlIGNhdGVnb3JpY2FsIGNvbG9yTWFwIGZyb20gY29sb3JCcmVha3NcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbG9yQnJlYWtzVG9DYXRlZ29yaWNhbENvbG9yTWFwKGNvbG9yQnJlYWtzOiBDb2xvckJyZWFrT3JkaW5hbFtdKTogQ29sb3JNYXAge1xuICAvLyBjb2xvck1hcDogW3N0cmluZyB8IHN0cmluZ1tdLCBoZXhzdHJpbmddXG4gIGNvbnN0IGNvbG9ycyA9IHVuaXEoY29sb3JCcmVha3MubWFwKGNiID0+IGNiLmRhdGEpKTtcbiAgY29uc3QgdmFsdWVzID0gdW5pcShjb2xvckJyZWFrcy5tYXAoY2IgPT4gY2IubGFiZWwpKTtcblxuICByZXR1cm4gZ2V0Q2F0ZWdvcmljYWxDb2xvck1hcChjb2xvcnMsIHZhbHVlcyk7XG59XG5cbi8qKlxuICogQ29udmVydCBjb2xvciBicmVha3MgVUkgaW5wdXQgaW50byBjb2xvclJhbmdlLmNvbG9yTWFwXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb2xvckJyZWFrc1RvQ29sb3JNYXAoY29sb3JCcmVha3M6IENvbG9yQnJlYWtbXSB8IENvbG9yQnJlYWtPcmRpbmFsW10pOiBDb2xvck1hcCB7XG4gIGNvbnN0IGNvbG9yTWFwID0gY29sb3JCcmVha3MubWFwKChjb2xvckJyZWFrLCBpKSA9PiB7XG4gICAgLy8gW3ZhbHVlLCBoZXhdXG4gICAgcmV0dXJuIFtcbiAgICAgIGNvbG9yQnJlYWsuaW5wdXRzXG4gICAgICAgID8gaSA9PT0gY29sb3JCcmVha3MubGVuZ3RoIC0gMVxuICAgICAgICAgID8gbnVsbCAvLyBsYXN0XG4gICAgICAgICAgOiBjb2xvckJyZWFrLmlucHV0c1sxXVxuICAgICAgICA6IGNvbG9yQnJlYWsubGFiZWwsXG4gICAgICBjb2xvckJyZWFrLmRhdGFcbiAgICBdO1xuICB9KTtcblxuICAvLyBAdHMtaWdub3JlIHR1cGxlXG4gIHJldHVybiBjb2xvck1hcDtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGNvbG9yUmFuZ2UuY29sb3JNYXAgaW50byBjb2xvciBicmVha3MgVUkgaW5wdXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbG9yTWFwVG9Db2xvckJyZWFrcyhjb2xvck1hcD86IENvbG9yTWFwIHwgbnVsbCk6IENvbG9yQnJlYWtbXSB8IG51bGwge1xuICBpZiAoIWNvbG9yTWFwKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgY29uc3QgY29sb3JCcmVha3MgPSBjb2xvck1hcC5tYXAoKFt2YWx1ZSwgY29sb3JdLCBpKSA9PiB7XG4gICAgY29uc3QgcmFuZ2UgPVxuICAgICAgaSA9PT0gMFxuICAgICAgICA/IC8vIGZpcnN0XG4gICAgICAgICAgWy1JbmZpbml0eSwgdmFsdWVdXG4gICAgICAgIDogLy8gbGFzdFxuICAgICAgICBpID09PSBjb2xvck1hcC5sZW5ndGggLSAxXG4gICAgICAgID8gW2NvbG9yTWFwW2kgLSAxXVswXSwgSW5maW5pdHldXG4gICAgICAgIDogLy8gZWxzZVxuICAgICAgICAgIFtjb2xvck1hcFtpIC0gMV1bMF0sIHZhbHVlXTtcbiAgICByZXR1cm4ge1xuICAgICAgZGF0YTogY29sb3IsXG4gICAgICByYW5nZSxcbiAgICAgIGlucHV0czogcmFuZ2UsXG4gICAgICBsYWJlbDpcbiAgICAgICAgLy8gZmlyc3RcbiAgICAgICAgaSA9PT0gMFxuICAgICAgICAgID8gYExlc3MgdGhhbiAke3ZhbHVlfWBcbiAgICAgICAgICA6IC8vIGxhc3RcbiAgICAgICAgICBpID09PSBjb2xvck1hcC5sZW5ndGggLSAxXG4gICAgICAgICAgPyBgJHtjb2xvck1hcFtpIC0gMV1bMF19IG9yIG1vcmVgXG4gICAgICAgICAgOiBgJHtjb2xvck1hcFtpIC0gMV1bMF19IHRvICR7dmFsdWV9YFxuICAgIH07XG4gIH0pO1xuXG4gIC8vIEB0cy1pZ25vcmUgaW1wbGVtZW50IGNvbnZlcnNpb24gZm9yIG9yZGluYWxcbiAgcmV0dXJuIGNvbG9yQnJlYWtzO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgY29sb3IgYnJlYWtzIGlzIGZvciBudW1lcmljIGZpZWxkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc051bWVyaWNDb2xvckJyZWFrcyhjb2xvckJyZWFrczogdW5rbm93bik6IGNvbG9yQnJlYWtzIGlzIENvbG9yQnJlYWtbXSB7XG4gIHJldHVybiBCb29sZWFuKEFycmF5LmlzQXJyYXkoY29sb3JCcmVha3MpICYmIGNvbG9yQnJlYWtzLmxlbmd0aCAmJiBjb2xvckJyZWFrc1swXS5pbnB1dHMpO1xufVxuXG4vLyByZXR1cm4gZG9tYWluTWluLCBkb21haW5NYXgsIGhpc3RvZ3JhbU1lYW5cbmV4cG9ydCBmdW5jdGlvbiBnZXRIaXN0b2dyYW1Eb21haW4oe1xuICBhZ2dyZWdhdGVkQmlucyxcbiAgY29sdW1uU3RhdHMsXG4gIGRhdGFzZXQsXG4gIGZpZWxkVmFsdWVBY2Nlc3NvclxufToge1xuICBhZ2dyZWdhdGVkQmlucz86IEFnZ3JlZ2F0ZWRCaW5bXTtcbiAgY29sdW1uU3RhdHM/OiBGaWx0ZXJQcm9wc1snY29sdW1uU3RhdHMnXTtcbiAgZGF0YXNldD86IEtlcGxlclRhYmxlO1xuICBmaWVsZFZhbHVlQWNjZXNzb3I6IChpZHg6IHVua25vd24pID0+IG51bWJlcjtcbn0pIHtcbiAgbGV0IGRvbWFpbk1pbiA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWTtcbiAgbGV0IGRvbWFpbk1heCA9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWTtcbiAgbGV0IG5WYWxpZCA9IDA7XG4gIGxldCBkb21haW5TdW0gPSAwO1xuXG4gIGlmIChhZ2dyZWdhdGVkQmlucykge1xuICAgIE9iamVjdC52YWx1ZXMoYWdncmVnYXRlZEJpbnMpLmZvckVhY2goYmluID0+IHtcbiAgICAgIGNvbnN0IHZhbCA9IGJpbi52YWx1ZTtcbiAgICAgIGlmIChpc051bWJlcih2YWwpKSB7XG4gICAgICAgIGlmICh2YWwgPCBkb21haW5NaW4pIGRvbWFpbk1pbiA9IHZhbDtcbiAgICAgICAgaWYgKHZhbCA+IGRvbWFpbk1heCkgZG9tYWluTWF4ID0gdmFsO1xuICAgICAgICBkb21haW5TdW0gKz0gdmFsO1xuICAgICAgICBuVmFsaWQgKz0gMTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSBlbHNlIHtcbiAgICBpZiAoY29sdW1uU3RhdHMgJiYgY29sdW1uU3RhdHMucXVhbnRpbGVzICYmIGNvbHVtblN0YXRzLm1lYW4pIHtcbiAgICAgIC8vIG5vIG5lZWQgdG8gcmVjYWxjdWF0ZSBtaW4vbWF4L21lYW4gaWYgaXRzIGFscmVhZHkgaW4gY29sdW1uU3RhdHNcbiAgICAgIHJldHVybiBbXG4gICAgICAgIGNvbHVtblN0YXRzLnF1YW50aWxlc1swXS52YWx1ZSxcbiAgICAgICAgY29sdW1uU3RhdHMucXVhbnRpbGVzW2NvbHVtblN0YXRzLnF1YW50aWxlcy5sZW5ndGggLSAxXS52YWx1ZSxcbiAgICAgICAgY29sdW1uU3RhdHMubWVhblxuICAgICAgXTtcbiAgICB9XG4gICAgaWYgKGRhdGFzZXQgJiYgZmllbGRWYWx1ZUFjY2Vzc29yKSB7XG4gICAgICBkYXRhc2V0LmFsbEluZGV4ZXMuZm9yRWFjaCh4ID0+IHtcbiAgICAgICAgY29uc3QgdmFsID0gZmllbGRWYWx1ZUFjY2Vzc29yKHgpO1xuICAgICAgICBpZiAoaXNOdW1iZXIodmFsKSkge1xuICAgICAgICAgIGlmICh2YWwgPCBkb21haW5NaW4pIGRvbWFpbk1pbiA9IHZhbDtcbiAgICAgICAgICBpZiAodmFsID4gZG9tYWluTWF4KSBkb21haW5NYXggPSB2YWw7XG4gICAgICAgICAgZG9tYWluU3VtICs9IHZhbDtcbiAgICAgICAgICBuVmFsaWQgKz0gMTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG4gIGNvbnN0IGhpc3RvZ3JhbU1lYW4gPSBuVmFsaWQgPiAwID8gZG9tYWluU3VtIC8gblZhbGlkIDogMDtcbiAgcmV0dXJuIFtuVmFsaWQgPiAwID8gZG9tYWluTWluIDogMCwgblZhbGlkID4gMCA/IGRvbWFpbk1heCA6IDAsIGhpc3RvZ3JhbU1lYW5dO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRDYXRlZ29yaWNhbENvbG9yTWFwQnlJbmRleChjb2xvck1hcDogQ29sb3JNYXAsIGluZGV4OiBudW1iZXIpOiBhbnkge1xuICBpZiAoIWNvbG9yTWFwKSB7XG4gICAgcmV0dXJuIGNvbG9yTWFwO1xuICB9XG4gIGNvbnN0IG5ld0NvbG9yTWFwID0gY29sb3JNYXAubWFwKChjbSwgaSkgPT4ge1xuICAgIGlmIChpID09PSBpbmRleCkge1xuICAgICAgcmV0dXJuIFtudWxsLCBjbVsxXV07XG4gICAgfVxuICAgIHJldHVybiBjbTtcbiAgfSk7XG4gIHJldHVybiBuZXdDb2xvck1hcDtcbn1cblxuLyoqXG4gKiBzZWxlY3QgcmVzdCBjYXRlZ29yaWNhbCB2YWx1ZXMgZm9yIGEgY29sb3JNYXAgYnkgaXRzIGluZGV4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZWxlY3RSZXN0Q2F0ZWdvcmljYWxDb2xvck1hcEJ5SW5kZXgoXG4gIGNvbG9yTWFwOiBDb2xvck1hcCB8IG51bGwsXG4gIGluZGV4OiBudW1iZXIsXG4gIHVuaXF1ZVZhbHVlcz86IG51bWJlcltdIHwgc3RyaW5nW11cbik6IENvbG9yTWFwIHwgdW5kZWZpbmVkIHwgbnVsbCB7XG4gIGlmICghY29sb3JNYXAgfHwgIXVuaXF1ZVZhbHVlcykge1xuICAgIHJldHVybiBjb2xvck1hcDtcbiAgfVxuXG4gIC8vIGZpbmQgdW5pcXVlIHZhbHVlcyB0aGF0IGhhcyBub3QgYmVlbiB1c2VkIGluIGN1cnJlbnQgY29sb3JNYXBcbiAgY29uc3QgdW5pcVZhbHVlRGljdCA9IE9iamVjdC5mcm9tRW50cmllcyh1bmlxdWVWYWx1ZXMubWFwKHZhbCA9PiBbdmFsLCBmYWxzZV0pKTtcbiAgY29sb3JNYXAuZm9yRWFjaChjbSA9PiB7XG4gICAgdG9BcnJheShjbVswXSkuZm9yRWFjaCh2ID0+IHtcbiAgICAgIGlmICh2KSB1bmlxVmFsdWVEaWN0W3ZdID0gdHJ1ZTtcbiAgICB9KTtcbiAgfSk7XG4gIGNvbnN0IHJlc3QgPSBPYmplY3Qua2V5cyh1bmlxVmFsdWVEaWN0KS5maWx0ZXIodiA9PiAhdW5pcVZhbHVlRGljdFt2XSk7XG5cbiAgLy8gdXNlIHRoZSBub3QgdXNlZCB1bmlxdWUgdmFsdWVzIGluIHRoZSBzZWxlY3RlZCBjb2xvciBtYXBcbiAgY29uc3QgbmV3Q29sb3JNYXAgPSBjb2xvck1hcC5tYXAoKGNtLCBpKSA9PiB7XG4gICAgaWYgKGkgPT09IGluZGV4KSB7XG4gICAgICByZXR1cm4gW1suLi5yZXN0LCAuLi50b0FycmF5KGNtWzBdKV0sIGNtWzFdXTtcbiAgICB9XG4gICAgcmV0dXJuIGNtO1xuICB9KSBhcyBDb2xvck1hcDtcblxuICByZXR1cm4gbmV3Q29sb3JNYXA7XG59XG5cbi8qKlxuICogcmVtb3ZlIGEgY2F0ZWdvcmljYWwgdmFsdWUgZnJvbSBhIGNvbG9yTWFwIGJ5IGl0cyBpbmRleFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVtb3ZlQ2F0ZWdvcmljYWxWYWx1ZUZyb21Db2xvck1hcChcbiAgY29sb3JNYXA6IENvbG9yTWFwIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgaXRlbTogbnVtYmVyIHwgc3RyaW5nLFxuICBpbmRleDogbnVtYmVyXG4pOiBDb2xvck1hcCB8IG51bGwgfCB1bmRlZmluZWQge1xuICBpZiAoIWNvbG9yTWFwKSB7XG4gICAgcmV0dXJuIGNvbG9yTWFwO1xuICB9XG4gIGNvbnN0IG5ld0NvbG9yTWFwID0gY29sb3JNYXAubWFwKChjbSwgaSkgPT4ge1xuICAgIGlmIChpID09PSBpbmRleCkge1xuICAgICAgaWYgKCFjbVswXSkge1xuICAgICAgICByZXR1cm4gW251bGwsIGNtWzFdXTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGN1cnJlbnRVbmlxdWVWYWx1ZXMgPSB0b0FycmF5KGNtWzBdKTtcbiAgICAgIGNvbnN0IHVwZGF0ZWRVbmlxdWVWYWx1ZXMgPSBjdXJyZW50VW5pcXVlVmFsdWVzLmZpbHRlcih2ID0+IHYgIT09IGl0ZW0pO1xuICAgICAgcmV0dXJuIFt1cGRhdGVkVW5pcXVlVmFsdWVzLCBjbVsxXV07XG4gICAgfVxuICAgIHJldHVybiBjbTtcbiAgfSkgYXMgQ29sb3JNYXA7XG5cbiAgcmV0dXJuIG5ld0NvbG9yTWFwO1xufVxuXG4vKipcbiAqIGFkZCBjYXRlZ29yaWNhbCB2YWx1ZXMgKGZyb20gbXVsdGlzZWwgZHJvcGRvd24pIHRvIGEgY29sb3JNYXAgYnkgaXRzIGluZGV4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZGRDYXRlZ29yaWNhbFZhbHVlc1RvQ29sb3JNYXAoXG4gIGNvbG9yTWFwOiBDb2xvck1hcCxcbiAgaXRlbXM6IChzdHJpbmcgfCBudW1iZXIpW10sXG4gIGluZGV4OiBudW1iZXJcbik6IENvbG9yTWFwIHtcbiAgaWYgKCFjb2xvck1hcCkge1xuICAgIHJldHVybiBjb2xvck1hcDtcbiAgfVxuXG4gIGNvbnN0IG5ld0NvbG9yTWFwID0gY29sb3JNYXAubWFwKChjbSwgaSkgPT4ge1xuICAgIGlmIChpID09PSBpbmRleCkge1xuICAgICAgaWYgKCFjbVswXSkge1xuICAgICAgICByZXR1cm4gW2l0ZW1zLCBjbVsxXV07XG4gICAgICB9XG4gICAgICBjb25zdCBjdXJyZW50VW5pcXVlVmFsdWVzID0gdG9BcnJheShjbVswXSk7XG4gICAgICBjb25zdCB1cGRhdGVkVW5pcXVlVmFsdWVzID0gdW5pcShjdXJyZW50VW5pcXVlVmFsdWVzLmNvbmNhdChpdGVtcykpO1xuICAgICAgcmV0dXJuIFt1cGRhdGVkVW5pcXVlVmFsdWVzLCBjbVsxXV07XG4gICAgfVxuICAgIC8vIHJlbW92ZSB2YWx1ZSBmcm9tIG90aGVyIGNvbG9yTWFwXG4gICAgY29uc3QgY3VycmVudFVuaXF1ZVZhbHVlcyA9IGNtWzBdO1xuICAgIGlmIChBcnJheS5pc0FycmF5KGN1cnJlbnRVbmlxdWVWYWx1ZXMpKSB7XG4gICAgICBjb25zdCB1cGRhdGVkVW5pcXVlVmFsdWVzOiBzdHJpbmdbXSB8IG51bWJlcltdID0gKGN1cnJlbnRVbmlxdWVWYWx1ZXMgYXMgYW55W10pLmZpbHRlcihcbiAgICAgICAgdiA9PiAhaXRlbXMuaW5jbHVkZXModilcbiAgICAgICk7XG4gICAgICByZXR1cm4gW3VwZGF0ZWRVbmlxdWVWYWx1ZXMsIGNtWzFdXTtcbiAgICB9IGVsc2UgaWYgKGN1cnJlbnRVbmlxdWVWYWx1ZXMgJiYgaXRlbXMuaW5jbHVkZXMoY3VycmVudFVuaXF1ZVZhbHVlcykpIHtcbiAgICAgIHJldHVybiBbbnVsbCwgY21bMV1dO1xuICAgIH1cblxuICAgIHJldHVybiBjbTtcbiAgfSkgYXMgQ29sb3JNYXA7XG5cbiAgcmV0dXJuIG5ld0NvbG9yTWFwO1xufVxuXG4vKipcbiAqIGdldCBhIGNvbG9yIHNjYWxlIGZ1bmMgZm9yIGNhdGVnb3JpY2FsIChjdXN0b20gb3JkaW5hbCkgc2NhbGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldENhdGVnb3JpY2FsQ29sb3JTY2FsZShcbiAgY29sb3JEb21haW46IG51bWJlcltdIHwgc3RyaW5nW10sXG4gIGNvbG9yUmFuZ2U6IENvbG9yUmFuZ2UsXG4gIHVzZVJnYiA9IHRydWVcbik6IChjYXRlZ29yeVZhbHVlOiBzdHJpbmcgfCBudW1iZXIpID0+IFJHQkNvbG9yIHwgUkdCQUNvbG9yIHtcbiAgY29uc3QgY01hcCA9IGNvbG9yUmFuZ2UuY29sb3JNYXBcbiAgICA/IGNvbG9yUmFuZ2UuY29sb3JNYXBcbiAgICA6IGdldENhdGVnb3JpY2FsQ29sb3JNYXAoY29sb3JSYW5nZS5jb2