UNPKG

@kepler.gl/utils

Version:

kepler.gl constants used by kepler.gl components, actions and reducers

620 lines (586 loc) 79.5 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) { var uniqueValues = (0, _dataUtils.unique)(domain).sort(); var colorMap = colors.map(function (color) { return [null, color]; }); if (colors.length === 0 || uniqueValues.length === 0) { return colorMap; } var lastIndex = colors.length - 1; var assignCount = Math.min(lastIndex, uniqueValues.length); // Assign first values one-to-one up to the penultimate color (if any) for (var i = 0; i < assignCount; i++) { // @ts-ignore tuple colorMap[i][0] = uniqueValues[i]; } if (uniqueValues.length > colors.length) { // Aggregate the rest (including the value that would have gone to last color) // Build aggregated array incrementally to match legacy behavior var aggregatedValues = []; for (var _i = lastIndex; _i < uniqueValues.length; _i++) { var value = uniqueValues[_i]; if (Array.isArray(value)) { // Spread array elements to match legacy flattening behavior aggregatedValues.push.apply(aggregatedValues, (0, _toConsumableArray2["default"])(value)); } else { aggregatedValues.push(value); } } // @ts-ignore tuple colorMap[lastIndex][0] = aggregatedValues; } else if (uniqueValues.length === colors.length) { // Exactly one per color // @ts-ignore tuple colorMap[lastIndex][0] = uniqueValues[lastIndex]; } // @ts-ignore tuple 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 === null || field === void 0 ? void 0 : field.name) || 'point-count'); // 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,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfZDNBcnJheSIsInJlcXVpcmUiLCJfdW5pcSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfbW9tZW50IiwiX2NvbW1vblV0aWxzIiwiX2NvbnN0YW50cyIsIl9jb2xvclV0aWxzIiwiX2RhdGFVdGlscyIsIl9maWx0ZXJVdGlscyIsIl91dGlscyIsIm93bktleXMiLCJlIiwiciIsInQiLCJPYmplY3QiLCJrZXlzIiwiZ2V0T3duUHJvcGVydHlTeW1ib2xzIiwibyIsImZpbHRlciIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsImVudW1lcmFibGUiLCJwdXNoIiwiYXBwbHkiLCJfb2JqZWN0U3ByZWFkIiwiYXJndW1lbnRzIiwibGVuZ3RoIiwiZm9yRWFjaCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzIiwiZGVmaW5lUHJvcGVydGllcyIsImRlZmluZVByb3BlcnR5IiwiZ2V0UXVhbnRpbGVEb21haW4iLCJkYXRhIiwidmFsdWVBY2Nlc3NvciIsInNvcnRGdW5jIiwidmFsdWVzIiwibWFwIiwibm90TnVsbG9yVW5kZWZpbmVkIiwic29ydCIsImdldE9yZGluYWxEb21haW4iLCJkYXRhQ29udGFpbmVyIiwibWFwSW5kZXgiLCJ1bmlxdWUiLCJnZXRMaW5lYXJEb21haW4iLCJyYW5nZSIsImV4dGVudCIsImQiLCJpIiwidW5kZWZpbmVkIiwiZ2V0TG9nRG9tYWluIiwiX2dldExpbmVhckRvbWFpbiIsIl9nZXRMaW5lYXJEb21haW4yIiwiX3NsaWNlZFRvQXJyYXkyIiwiZDAiLCJkMSIsImlzRG9tYWluU3RvcHMiLCJkb21haW4iLCJpc1BsYWluT2JqZWN0IiwiQXJyYXkiLCJpc0FycmF5Iiwic3RvcHMiLCJ6IiwiaXNEb21haW5RdWFudGlsZSIsInF1YW50aWxlcyIsImdldFRocmVzaG9sZHNGcm9tUXVhbnRpbGVzIiwiYnVja2V0cyIsInRocmVzaG9sZHMiLCJOdW1iZXIiLCJpc0Zpbml0ZSIsInBvc2l0aW9uIiwiZDNRdWFudGlsZSIsImdldERvbWFpblN0ZXBzYnlab29tIiwic3RlcHMiLCJiaXNlY3RMZWZ0IiwiTWF0aCIsIm1heCIsImdldFNjYWxlRnVuY3Rpb24iLCJzY2FsZSIsImZpeGVkIiwic2NhbGVGdW5jdGlvbiIsIlNDQUxFX0ZVTkMiLCJzY2FsZVR5cGUiLCJnZXRUaHJlc2hvbGRMYWJlbHMiLCJsYWJlbEZvcm1hdCIsImdlbkxlbmd0aCIsImludmVydCIsImludmVydEV4dGVudCIsImlucHV0cyIsInJldmVyc2VGb3JtYXROdW1iZXIiLCJsYWJlbCIsImNvbmNhdCIsImdldFNjYWxlTGFiZWxzIiwiY3VzdG9tU2NhbGVMYWJlbEZvcm1hdCIsIm4iLCJmb3JtYXROdW1iZXIiLCJnZXRRdWFudExlZ2VuZHMiLCJ0aHJlc2hvbGRMYWJlbEZvcm1hdCIsInR5cGUiLCJsYWJlbHMiLCJpbmRleCIsInJnYlRvSGV4IiwiZ2V0T3JkaW5hbExlZ2VuZHMiLCJkYXR1bSIsImlzUmdiQ29sb3IiLCJkZWZhdWx0Rm9ybWF0IiwiZ2V0VGltZUxhYmVsRm9ybWF0IiwiZm9ybWF0dGVyIiwiZ2V0VGltZVdpZGdldEhpbnRGb3JtYXR0ZXIiLCJ2YWwiLCJtb21lbnQiLCJ1dGMiLCJmb3JtYXQiLCJnZXRRdWFudExhYmVsRm9ybWF0IiwiZmllbGRUeXBlIiwiQUxMX0ZJRUxEX1RZUEVTIiwidGltZXN0YW1wIiwiaXNOdW1iZXIiLCJnZXRMZWdlbmRPZlNjYWxlIiwiX3JlZiIsImJ5Wm9vbSIsIlNDQUxFX1RZUEVTIiwib3JkaW5hbCIsImN1c3RvbU9yZGluYWwiLCJzdHJpbmciLCJmb3JtYXRMYWJlbCIsImdldExheWVyQ29sb3JTY2FsZSIsIl9yZWYyIiwibGF5ZXIiLCJnZXRDb2xvclNjYWxlIiwiaW5pdGlhbGl6ZUxheWVyQ29sb3JNYXAiLCJ2aXN1YWxDaGFubmVsIiwiY29uZmlnIiwidmlzQ29uZmlnIiwiZmllbGQiLCJjb2xvckJyZWFrcyIsImNvbG9yQnJlYWtzVG9Db2xvck1hcCIsImdldFZpc3VhbENoYW5uZWxTY2FsZUJ5Wm9vbSIsIl9yZWYzIiwiX3NjYWxlIiwibWFwU3RhdGUiLCJfbGF5ZXIkbWV0YSIsIm1ldGEiLCJnZXRab29tIiwiem9vbSIsImdldENhdGVnb3JpY2FsQ29sb3JNYXAiLCJjb2xvcnMiLCJ1bmlxdWVWYWx1ZXMiLCJjb2xvck1hcCIsImNvbG9yIiwibGFzdEluZGV4IiwiYXNzaWduQ291bnQiLCJtaW4iLCJhZ2dyZWdhdGVkVmFsdWVzIiwidmFsdWUiLCJfdG9Db25zdW1hYmxlQXJyYXkyIiwiY29sb3JNYXBUb0NhdGVnb3JpY2FsQ29sb3JCcmVha3MiLCJfcmVmNCIsIl9yZWY1IiwiY29sb3JCcmVha3NUb0NhdGVnb3JpY2FsQ29sb3JNYXAiLCJ1bmlxIiwiY2IiLCJjb2xvckJyZWFrIiwiY29sb3JNYXBUb0NvbG9yQnJlYWtzIiwiX3JlZjYiLCJfcmVmNyIsIkluZmluaXR5IiwiaXNOdW1lcmljQ29sb3JCcmVha3MiLCJCb29sZWFuIiwiZ2V0SGlzdG9ncmFtRG9tYWluIiwiX3JlZjgiLCJhZ2dyZWdhdGVkQmlucyIsImNvbHVtblN0YXRzIiwiZGF0YXNldCIsImZpZWxkVmFsdWVBY2Nlc3NvciIsImRvbWFpbk1pbiIsIlBPU0lUSVZFX0lORklOSVRZIiwiZG9tYWluTWF4IiwiTkVHQVRJVkVfSU5GSU5JVFkiLCJuVmFsaWQiLCJkb21haW5TdW0iLCJiaW4iLCJtZWFuIiwiYWxsSW5kZXhlcyIsIngiLCJoaXN0b2dyYW1NZWFuIiwicmVzZXRDYXRlZ29yaWNhbENvbG9yTWFwQnlJbmRleCIsIm5ld0NvbG9yTWFwIiwiY20iLCJzZWxlY3RSZXN0Q2F0ZWdvcmljYWxDb2xvck1hcEJ5SW5kZXgiLCJ1bmlxVmFsdWVEaWN0IiwiZnJvbUVudHJpZXMiLCJ0b0FycmF5IiwidiIsInJlc3QiLCJyZW1vdmVDYXRlZ29yaWNhbFZhbHVlRnJvbUNvbG9yTWFwIiwiaXRlbSIsImN1cnJlbnRVbmlxdWVWYWx1ZXMiLCJ1cGRhdGVkVW5pcXVlVmFsdWVzIiwiYWRkQ2F0ZWdvcmljYWxWYWx1ZXNUb0NvbG9yTWFwIiwiaXRlbXMiLCJpbmNsdWRlcyIsImdldENhdGVnb3JpY2FsQ29sb3JTY2FsZSIsImNvbG9yRG9tYWluIiwiY29sb3JSYW5nZSIsInVzZVJnYiIsImNNYXAiLCJoZXhUb1JnYiIsInVua25vd24iLCJOT19WQUxVRV9DT0xPUiIsImluaXRDdXN0b21QYWxldHRlQnlDdXN0b21TY2FsZSIsIl9yZWY5Iiwib3JkaW5hbERvbWFpbiIsImN1c3RvbVBhbGV0dGVOYW1lIiwibmFtZSIsInJldXNlQ29sb3JNYXAiLCJjdXN0b21QYWxldHRlIiwiY2F0ZWdvcnkiXSwic291cmNlcyI6WyIuLi9zcmMvZGF0YS1zY2FsZS11dGlscy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4vLyBDb3B5cmlnaHQgY29udHJpYnV0b3JzIHRvIHRoZSBrZXBsZXIuZ2wgcHJvamVjdFxuXG5pbXBvcnQge2Jpc2VjdExlZnQsIHF1YW50aWxlU29ydGVkIGFzIGQzUXVhbnRpbGUsIGV4dGVudH0gZnJvbSAnZDMtYXJyYXknO1xuaW1wb3J0IHVuaXEgZnJvbSAnbG9kYXNoL3VuaXEnO1xuaW1wb3J0IG1vbWVudCBmcm9tICdtb21lbnQnO1xuXG5pbXBvcnQge25vdE51bGxvclVuZGVmaW5lZCwgdG9BcnJheX0gZnJvbSAnQGtlcGxlci5nbC9jb21tb24tdXRpbHMnO1xuaW1wb3J0IHtBTExfRklFTERfVFlQRVMsIFNDQUxFX0ZVTkMsIFNDQUxFX1RZUEVTLCBOT19WQUxVRV9DT0xPUn0gZnJvbSAnQGtlcGxlci5nbC9jb25zdGFudHMnO1xuLy8gaW1wb3J0IHtGaWx0ZXJQcm9wcywgS2VwbGVyVGFibGV9IGZyb20gJ0BrZXBsZXIuZ2wvbGF5ZXJzJztcbmltcG9ydCB7XG4gIEFnZ3JlZ2F0ZWRCaW4sXG4gIENvbG9yTWFwLFxuICBDb2xvclJhbmdlLFxuICBIZXhDb2xvcixcbiAgS2VwbGVyTGF5ZXIgYXMgTGF5ZXIsXG4gIE1hcFN0YXRlLFxuICBWaXN1YWxDaGFubmVsLFxuICBWaXN1YWxDaGFubmVsRG9tYWluLFxuICBSR0JDb2xvcixcbiAgUkdCQUNvbG9yLFxuICBDb2xvclVJLFxuICBGaWVsZFxufSBmcm9tICdAa2VwbGVyLmdsL3R5cGVzJztcblxuaW1wb3J0IHtpc1JnYkNvbG9yLCByZ2JUb0hleCwgaGV4VG9SZ2J9IGZyb20gJy4vY29sb3ItdXRpbHMnO1xuaW1wb3J0IHtEYXRhQ29udGFpbmVySW50ZXJmYWNlfSBmcm9tICcuL2RhdGEtY29udGFpbmVyLWludGVyZmFjZSc7XG5pbXBvcnQge2Zvcm1hdE51bWJlciwgaXNOdW1iZXIsIHJldmVyc2VGb3JtYXROdW1iZXIsIHVuaXF1ZX0gZnJvbSAnLi9kYXRhLXV0aWxzJztcbmltcG9ydCB7Z2V0VGltZVdpZGdldEhpbnRGb3JtYXR0ZXJ9IGZyb20gJy4vZmlsdGVyLXV0aWxzJztcbmltcG9ydCB7aXNQbGFpbk9iamVjdH0gZnJvbSAnLi91dGlscyc7XG5cbmV4cG9ydCB0eXBlIENvbG9yQnJlYWsgPSB7XG4gIGRhdGE6IEhleENvbG9yO1xuICBsYWJlbDogc3RyaW5nO1xuICByYW5nZTogbnVtYmVyW107XG4gIGlucHV0czogbnVtYmVyW107XG59O1xuZXhwb3J0IHR5cGUgQ29sb3JCcmVha09yZGluYWwgPSB7XG4gIGRhdGE6IEhleENvbG9yO1xuICBsYWJlbDogc3RyaW5nIHwgbnVtYmVyIHwgc3RyaW5nW10gfCBudW1iZXJbXSB8IG51bGw7XG59O1xuXG5leHBvcnQgdHlwZSBEM1NjYWxlRnVuY3Rpb24gPSBSZWNvcmQ8c3RyaW5nLCBhbnk+ICYgKCh4OiBhbnkpID0+IGFueSk7XG5cbi8vIFRPRE8gaXNvbGF0ZSB0eXBlcyAtIGRlcGVuZHMgb24gQGtlcGxlci5nbC9sYXllcnNcbnR5cGUgRmlsdGVyUHJvcHMgPSBhbnk7XG50eXBlIEtlcGxlclRhYmxlID0gYW55O1xuXG5leHBvcnQgdHlwZSBMYWJlbEZvcm1hdCA9IChuOiBudW1iZXIsIHR5cGU/OiBzdHJpbmcpID0+IHN0cmluZztcbnR5cGUgZGF0YVZhbHVlQWNjZXNzb3IgPSA8VD4ocGFyYW06IFQpID0+IFQ7XG50eXBlIGRhdGFDb250YWluZXJWYWx1ZUFjY2Vzc29yID0gKGQ6IHtpbmRleDogbnVtYmVyfSwgZGM6IERhdGFDb250YWluZXJJbnRlcmZhY2UpID0+IGFueTtcbnR5cGUgc29ydCA9IChhOiBhbnksIGI6IGFueSkgPT4gYW55O1xuLyoqXG4gKiByZXR1cm4gcXVhbnRpbGUgZG9tYWluIGZvciBhbiBhcnJheSBvZiBkYXRhXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRRdWFudGlsZURvbWFpbihcbiAgZGF0YTogYW55W10sXG4gIHZhbHVlQWNjZXNzb3I/OiBkYXRhVmFsdWVBY2Nlc3NvcixcbiAgc29ydEZ1bmM/OiBzb3J0XG4pOiBudW1iZXJbXSB7XG4gIGNvbnN0IHZhbHVlcyA9IHR5cGVvZiB2YWx1ZUFjY2Vzc29yID09PSAnZnVuY3Rpb24nID8gZGF0YS5tYXAodmFsdWVBY2Nlc3NvcikgOiBkYXRhO1xuXG4gIHJldHVybiB2YWx1ZXMuZmlsdGVyKG5vdE51bGxvclVuZGVmaW5lZCkuc29ydChzb3J0RnVuYyk7XG59XG5cbi8qKlxuICogcmV0dXJuIG9yZGluYWwgZG9tYWluIGZvciBhIGRhdGEgY29udGFpbmVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRPcmRpbmFsRG9tYWluKFxuICBkYXRhQ29udGFpbmVyOiBEYXRhQ29udGFpbmVySW50ZXJmYWNlLFxuICB2YWx1ZUFjY2Vzc29yOiBkYXRhQ29udGFpbmVyVmFsdWVBY2Nlc3NvclxuKTogc3RyaW5nW10ge1xuICBjb25zdCB2YWx1ZXMgPSBkYXRhQ29udGFpbmVyLm1hcEluZGV4KHZhbHVlQWNjZXNzb3IpO1xuXG4gIHJldHVybiB1bmlxdWUodmFsdWVzKS5maWx0ZXIobm90TnVsbG9yVW5kZWZpbmVkKS5zb3J0KCk7XG59XG5cbi8qKlxuICogcmV0dXJuIGxpbmVhciBkb21haW4gZm9yIGFuIGFycmF5IG9mIGRhdGFcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldExpbmVhckRvbWFpbihcbiAgZGF0YTogbnVtYmVyW10sXG4gIHZhbHVlQWNjZXNzb3I/OiBkYXRhVmFsdWVBY2Nlc3NvclxuKTogW251bWJlciwgbnVtYmVyXSB7XG4gIGNvbnN0IHJhbmdlID0gdHlwZW9mIHZhbHVlQWNjZXNzb3IgPT09ICdmdW5jdGlvbicgPyBleHRlbnQoZGF0YSwgdmFsdWVBY2Nlc3NvcikgOiBleHRlbnQoZGF0YSk7XG4gIHJldHVybiByYW5nZS5tYXAoKGQ6IHVuZGVmaW5lZCB8IG51bWJlciwgaTogbnVtYmVyKSA9PiAoZCA9PT0gdW5kZWZpbmVkID8gaSA6IGQpKSBhcyBbXG4gICAgbnVtYmVyLFxuICAgIG51bWJlclxuICBdO1xufVxuXG4vKipcbiAqIHJldHVybiBsaW5lYXIgZG9tYWluIGZvciBhbiBhcnJheSBvZiBkYXRhLiBBIGxvZyBzY2FsZSBkb21haW4gY2Fubm90IGNvbnRhaW4gMFxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TG9nRG9tYWluKGRhdGE6IGFueVtdLCB2YWx1ZUFjY2Vzc29yOiBkYXRhVmFsdWVBY2Nlc3Nvcik6IFtudW1iZXIsIG51bWJlcl0ge1xuICBjb25zdCBbZDAsIGQxXSA9IGdldExpbmVhckRvbWFpbihkYXRhLCB2YWx1ZUFjY2Vzc29yKTtcbiAgcmV0dXJuIFtkMCA9PT0gMCA/IDFlLTUgOiBkMCwgZDFdO1xufVxuXG5leHBvcnQgdHlwZSBEb21haW5TdG9wcyA9IHtcbiAgc3RvcHM6IG51bWJlcltdO1xuICB6OiBudW1iZXJbXTtcbn07XG5cbi8qKlxuICogd2hldGhlciBmaWVsZCBkb21haW4gaXMgc3RvcHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzRG9tYWluU3RvcHMoZG9tYWluOiB1bmtub3duKTogZG9tYWluIGlzIERvbWFpblN0b3BzIHtcbiAgcmV0dXJuIGlzUGxhaW5PYmplY3QoZG9tYWluKSAmJiBBcnJheS5pc0FycmF5KGRvbWFpbi5zdG9wcykgJiYgQXJyYXkuaXNBcnJheShkb21haW4ueik7XG59XG5cbmV4cG9ydCB0eXBlIERvbWFpblF1YW50aWxlcyA9IHtcbiAgcXVhbnRpbGVzOiBudW1iZXJbXTtcbiAgejogbnVtYmVyW107XG59O1xuXG4vKipcbiAqIHdoZXRoZXIgZmllbGQgZG9tYWluIGlzIHF1YW50aWxlc1xuICovXG5leHBvcnQgZnVuY3Rpb24gaXNEb21haW5RdWFudGlsZShkb21haW46IGFueSk6IGRvbWFpbiBpcyBEb21haW5RdWFudGlsZXMge1xuICByZXR1cm4gaXNQbGFpbk9iamVjdChkb21haW4pICYmIEFycmF5LmlzQXJyYXkoZG9tYWluLnF1YW50aWxlcykgJiYgQXJyYXkuaXNBcnJheShkb21haW4ueik7XG59XG5cbi8qKlxuICogZ2V0IHRoZSBkb21haW4gYXQgem9vbVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0VGhyZXNob2xkc0Zyb21RdWFudGlsZXMoXG4gIHF1YW50aWxlczogbnVtYmVyW10sXG4gIGJ1Y2tldHM6IG51bWJlclxuKTogKG51bWJlciB8IHVuZGVmaW5lZClbXSB7XG4gIGNvbnN0IHRocmVzaG9sZHMgPSBbXTtcbiAgaWYgKCFOdW1iZXIuaXNGaW5pdGUoYnVja2V0cykgfHwgYnVja2V0cyA8IDEpIHtcbiAgICByZXR1cm4gW3F1YW50aWxlc1swXSwgcXVhbnRpbGVzW3F1YW50aWxlcy5sZW5ndGggLSAxXV07XG4gIH1cbiAgZm9yIChsZXQgaSA9IDE7IGkgPCBidWNrZXRzOyBpKyspIHtcbiAgICAvLyBwb3NpdGlvbiBpbiBzb3J0ZWQgYXJyYXlcbiAgICBjb25zdCBwb3NpdGlvbiA9IGkgLyBidWNrZXRzO1xuICAgIC8vIEB0cy1pZ25vcmVcbiAgICB0aHJlc2hvbGRzLnB1c2goZDNRdWFudGlsZShxdWFudGlsZXMsIHBvc2l0aW9uKSk7XG4gIH1cblxuICByZXR1cm4gdGhyZXNob2xkcztcbn1cblxuLyoqXG4gKiBnZXQgdGhlIGRvbWFpbiBhdCB6b29tXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXREb21haW5TdGVwc2J5Wm9vbShkb21haW46IGFueVtdLCBzdGVwczogbnVtYmVyW10sIHo6IG51bWJlcik6IGFueSB7XG4gIGNvbnN0IGkgPSBiaXNlY3RMZWZ0KHN0ZXBzLCB6KTtcblxuICBpZiAoc3RlcHNbaV0gPT09IHopIHtcbiAgICAvLyBJZiB6IGlzIGFuIGludGVnZXIgdmFsdWUgZXhhY3RseSBtYXRjaGluZyBhIHN0ZXAsIHJldHVybiB0aGUgY29ycmVzcG9uZGluZyBkb21haW5cbiAgICByZXR1cm4gZG9tYWluW2ldO1xuICB9XG4gIC8vIE90aGVyd2lzZSwgcmV0dXJuIHRoZSBuZXh0IGNvYXJzZXN0IGRvbWFpblxuICByZXR1cm4gZG9tYWluW01hdGgubWF4KGkgLSAxLCAwKV07XG59XG5cbi8qKlxuICogR2V0IGQzIHNjYWxlIGZ1bmN0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTY2FsZUZ1bmN0aW9uKFxuICBzY2FsZTogc3RyaW5nLFxuICByYW5nZTogYW55W10gfCBJdGVyYWJsZUl0ZXJhdG9yPGFueT4sXG4gIGRvbWFpbjogKG51bWJlciB8IHVuZGVmaW5lZClbXSB8IHN0cmluZ1tdIHwgSXRlcmFibGVJdGVyYXRvcjxhbnk+LFxuICBmaXhlZD86IGJvb2xlYW5cbik6IEQzU2NhbGVGdW5jdGlvbiB7XG4gIGNvbnN0IHNjYWxlRnVuY3Rpb24gPSBTQ0FMRV9GVU5DW2ZpeGVkID8gJ2xpbmVhcicgOiBzY2FsZV0oKVxuICAgIC5kb21haW4oZG9tYWluKVxuICAgIC5yYW5nZShmaXhlZCA/IGRvbWFpbiA6IHJhbmdlKTtcbiAgc2NhbGVGdW5jdGlvbi5zY2FsZVR5cGUgPSBmaXhlZCA/ICdsaW5lYXInIDogc2NhbGU7XG4gIHJldHVybiBzY2FsZUZ1bmN0aW9uO1xufVxuXG4vKipcbiAqIEdldCB0aHJlc2hvbGQgc2NhbGUgY29sb3IgbGFiZWxzXG4gKi9cbmZ1bmN0aW9uIGdldFRocmVzaG9sZExhYmVscyhcbiAgc2NhbGU6IEQzU2NhbGVGdW5jdGlvbixcbiAgbGFiZWxGb3JtYXQ6IExhYmVsRm9ybWF0XG4pOiBPbWl0PENvbG9yQnJlYWssICdkYXRhJz5bXSB7XG4gIGNvbnN0IGdlbkxlbmd0aCA9IHNjYWxlLnJhbmdlKCkubGVuZ3RoO1xuICByZXR1cm4gc2NhbGUucmFuZ2UoKS5tYXAoKGQsIGkpID0+IHtcbiAgICBjb25zdCBpbnZlcnQgPSBzY2FsZS5pbnZlcnRFeHRlbnQoZCk7XG4gICAgY29uc3QgaW5wdXRzID0gW1xuICAgICAgaSA9PT0gMCA/IG51bGwgOiByZXZlcnNlRm9ybWF0TnVtYmVyKGxhYmVsRm9ybWF0KGludmVydFswXSkpLFxuICAgICAgaSA9PT0gZ2VuTGVuZ3RoIC0gMSA/IG51bGwgOiByZXZlcnNlRm9ybWF0TnVtYmVyKGxhYmVsRm9ybWF0KGludmVydFsxXSkpXG4gICAgXTtcbiAgICByZXR1cm4ge1xuICAgICAgLy8gcmF3IHZhbHVlXG4gICAgICByYW5nZTogaW52ZXJ0LFxuICAgICAgLy8gZm9ybWF0dGVkIHZhbHVlXG4gICAgICBpbnB1dHMsXG4gICAgICBsYWJlbDpcbiAgICAgICAgaSA9PT0gMFxuICAgICAgICAgID8gYExlc3MgdGhhbiAke2xhYmVsRm9ybWF0KGludmVydFsxXSl9YFxuICAgICAgICAgIDogaSA9PT0gZ2VuTGVuZ3RoIC0gMVxuICAgICAgICAgID8gYCR7bGFiZWxGb3JtYXQoaW52ZXJ0WzBdKX0gb3IgbW9yZWBcbiAgICAgICAgICA6IGAke2xhYmVsRm9ybWF0KGludmVydFswXSl9IHRvICR7bGFiZWxGb3JtYXQoaW52ZXJ0WzFdKX1gXG4gICAgfTtcbiAgfSk7XG59XG5cbi8qKlxuICogR2V0IGxpbmVhciAvIHF1YW50IHNjYWxlIGNvbG9yIGxhYmVsc1xuICovXG5mdW5jdGlvbiBnZXRTY2FsZUxhYmVscyhcbiAgc2NhbGU6IEQzU2NhbGVGdW5jdGlvbixcbiAgbGFiZWxGb3JtYXQ6IExhYmVsRm9ybWF0XG4pOiBPbWl0PENvbG9yQnJlYWssICdkYXRhJz5bXSB7XG4gIHJldHVybiBzY2FsZS5yYW5nZSgpLm1hcChkID0+IHtcbiAgICAvLyBAdHMtaWdub3JlXG4gICAgY29uc3QgaW52ZXJ0ID0gc2NhbGUuaW52ZXJ0RXh0ZW50KGQpO1xuICAgIGNvbnN0IGlucHV0cyA9IFtcbiAgICAgIHJldmVyc2VGb3JtYXROdW1iZXIobGFiZWxGb3JtYXQoaW52ZXJ0WzBdKSksXG4gICAgICByZXZlcnNlRm9ybWF0TnVtYmVyKGxhYmVsRm9ybWF0KGludmVydFsxXSkpXG4gICAgXTtcblxuICAgIHJldHVybiB7XG4gICAgICBsYWJlbDogYCR7bGFiZWxGb3JtYXQoaW52ZXJ0WzBdKX0gdG8gJHtsYWJlbEZvcm1hdChpbnZlcnRbMV0pfWAsXG4gICAgICAvLyByYXcgdmFsdWVcbiAgICAgIHJhbmdlOiBpbnZlcnQsXG4gICAgICAvLyBmb3JtYXR0ZWQgdmFsdWVcbiAgICAgIGlucHV0c1xuICAgIH07XG4gIH0pO1xufVxuXG5jb25zdCBjdXN0b21TY2FsZUxhYmVsRm9ybWF0ID0gbiA9PiAobiA/IGZvcm1hdE51bWJlcihuLCAncmVhbCcpIDogJ25vIHZhbHVlJyk7XG4vKipcbiAqIEdldCBsaW5lYXIgLyBxdWFudCBzY2FsZSBjb2xvciBicmVha3NcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFF1YW50TGVnZW5kcyhzY2FsZTogRDNTY2FsZUZ1bmN0aW9uLCBsYWJlbEZvcm1hdDogTGFiZWxGb3JtYXQpOiBDb2xvckJyZWFrW10ge1xuICBpZiAodHlwZW9mIHNjYWxlLmludmVydEV4dGVudCAhPT0gJ2Z1bmN0aW9uJykge1xuICAgIHJldHVybiBbXTtcbiAgfVxuICBjb25zdCB0aHJlc2hvbGRMYWJlbEZvcm1hdCA9IChuLCB0eXBlKSA9PlxuICAgIG4gJiYgbGFiZWxGb3JtYXQgPyBsYWJlbEZvcm1hdChuKSA6IG4gPyBmb3JtYXROdW1iZXIobiwgdHlwZSkgOiAnbm8gdmFsdWUnO1xuICBjb25zdCBsYWJlbHMgPVxuICAgIHNjYWxlLnNjYWxlVHlwZSA9PT0gJ3RocmVzaG9sZCdcbiAgICAgID8gZ2V0VGhyZXNob2xkTGFiZWxzKHNjYWxlLCB0aHJlc2hvbGRMYWJlbEZvcm1hdClcbiAgICAgIDogc2NhbGUuc2NhbGVUeXBlID09PSAnY3VzdG9tJ1xuICAgICAgPyBnZXRUaHJlc2hvbGRMYWJlbHMoc2NhbGUsIGN1c3RvbVNjYWxlTGFiZWxGb3JtYXQpXG4gICAgICA6IGdldFNjYWxlTGFiZWxzKHNjYWxlLCBsYWJlbEZvcm1hdCk7XG5cbiAgY29uc3QgZGF0YSA9IHNjYWxlLnJhbmdlKCk7XG5cbiAgcmV0dXJuIGxhYmVscy5tYXAoKGxhYmVsLCBpbmRleCkgPT4gKHtcbiAgICBkYXRhOiBBcnJheS5pc0FycmF5KGRhdGFbaW5kZXhdKSA/IHJnYlRvSGV4KGRhdGFbaW5kZXhdKSA6IGRhdGFbaW5kZXhdLFxuICAgIC4uLmxhYmVsXG4gIH0pKTtcbn1cblxuLyoqXG4gKiBHZXQgb3JkaW5hbCBjb2xvciBzY2FsZSBsZWdlbmRzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRPcmRpbmFsTGVnZW5kcyhzY2FsZTogRDNTY2FsZUZ1bmN0aW9uKTogQ29sb3JCcmVha09yZGluYWxbXSB7XG4gIGNvbnN0IGRvbWFpbiA9IHNjYWxlLmRvbWFpbigpO1xuICBjb25zdCBsYWJlbHMgPSBzY2FsZS5kb21haW4oKTtcbiAgY29uc3QgZGF0YSA9IGRvbWFpbi5tYXAoc2NhbGUpO1xuXG4gIHJldHVybiBkYXRhLm1hcCgoZGF0dW0sIGluZGV4KSA9PiAoe1xuICAgIGRhdGE6IGlzUmdiQ29sb3IoZGF0dW0pID8gcmdiVG9IZXgoZGF0dW0pIDogZGF0dW0sXG4gICAgbGFiZWw6IGxhYmVsc1tpbmRleF1cbiAgfSkpO1xufVxuXG5jb25zdCBkZWZhdWx0Rm9ybWF0ID0gZCA9PiBkO1xuXG5jb25zdCBnZXRUaW1lTGFiZWxGb3JtYXQgPSBkb21haW4gPT4ge1xuICBjb25zdCBmb3JtYXR0ZXIgPSBnZXRUaW1lV2lkZ2V0SGludEZvcm1hdHRlcihkb21haW4pO1xuICByZXR1cm4gdmFsID0+IG1vbWVudC51dGModmFsKS5mb3JtYXQoZm9ybWF0dGVyKTtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRRdWFudExhYmVsRm9ybWF0KGRvbWFpbiwgZmllbGRUeXBlKSB7XG4gIC8vIHF1YW50IHNjYWxlIGNhbiBvbmx5IGJlIGFzc2lnbmVkIHRvIGxpbmVhciBGaWVsZHM6IHJlYWwsIHRpbWVzdGFtcCwgaW50ZWdlclxuICByZXR1cm4gZmllbGRUeXBlID09PSBBTExfRklFTERfVFlQRVMudGltZXN0YW1wXG4gICAgPyBnZXRUaW1lTGFiZWxGb3JtYXQoZG9tYWluKVxuICAgIDogIWZpZWxkVHlwZVxuICAgID8gZGVmYXVsdEZvcm1hdFxuICAgIDogbiA9PiAoaXNOdW1iZXIobikgPyBmb3JtYXROdW1iZXIobiwgZmllbGRUeXBlKSA6ICdubyB2YWx1ZScpO1xufVxuXG4vKipcbiAqIEdldCBsZWdlbmRzIGZvciBzY2FsZVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TGVnZW5kT2ZTY2FsZSh7XG4gIHNjYWxlLFxuICBzY2FsZVR5cGUsXG4gIGxhYmVsRm9ybWF0LFxuICBmaWVsZFR5cGVcbn06IHtcbiAgc2NhbGU/OiBEM1NjYWxlRnVuY3Rpb24gfCBudWxsO1xuICBzY2FsZVR5cGU6IHN0cmluZztcbiAgbGFiZWxGb3JtYXQ/OiBMYWJlbEZvcm1hdDtcbiAgZmllbGRUeXBlOiBzdHJpbmcgfCBudWxsIHwgdW5kZWZpbmVkO1xufSk6IENvbG9yQnJlYWtbXSB8IENvbG9yQnJlYWtPcmRpbmFsW10ge1xuICBpZiAoIXNjYWxlIHx8IHNjYWxlLmJ5Wm9vbSkge1xuICAgIHJldHVybiBbXTtcbiAgfVxuICBpZiAoXG4gICAgc2NhbGVUeXBlID09PSBTQ0FMRV9UWVBFUy5vcmRpbmFsIHx8XG4gICAgc2NhbGVUeXBlID09PSBTQ0FMRV9UWVBFUy5jdXN0b21PcmRpbmFsIHx8XG4gICAgZmllbGRUeXBlID09PSBBTExfRklFTERfVFlQRVMuc3RyaW5nXG4gICkge1xuICAgIHJldHVybiBnZXRPcmRpbmFsTGVnZW5kcyhzY2FsZSk7XG4gIH1cblxuICBjb25zdCBmb3JtYXRMYWJlbCA9IGxhYmVsRm9ybWF0IHx8IGdldFF1YW50TGFiZWxGb3JtYXQoc2NhbGUuZG9tYWluKCksIGZpZWxkVHlwZSk7XG5cbiAgcmV0dXJuIGdldFF1YW50TGVnZW5kcyhzY2FsZSwgZm9ybWF0TGFiZWwpO1xufVxuXG4vKipcbiAqIEdldCBjb2xvciBzY2FsZSBmdW5jdGlvblxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0TGF5ZXJDb2xvclNjYWxlKHtcbiAgcmFuZ2UsXG4gIGRvbWFpbixcbiAgc2NhbGVUeXBlLFxuICBsYXllclxufToge1xuICByYW5nZTogQ29sb3JSYW5nZSB8IG51bGwgfCB1bmRlZmluZWQ7XG4gIGRvbWFpbjogVmlzdWFsQ2hhbm5lbERvbWFpbjtcbiAgc2NhbGVUeXBlOiBzdHJpbmc7XG4gIGxheWVyOiBMYXllcjtcbiAgaXNGaXhlZD86IGJvb2xlYW47XG59KTogRDNTY2FsZUZ1bmN0aW9uIHwgbnVsbCB7XG4gIGlmIChyYW5nZSAmJiBkb21haW4gJiYgc2NhbGVUeXBlKSB7XG4gICAgcmV0dXJuIGxheWVyLmdldENvbG9yU2NhbGUoc2NhbGVUeXBlLCBkb21haW4sIHJhbmdlKTtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGNvbG9yUmFuZ2UuY29sb3JNYXAgaW50byBjb2xvciBicmVha3MgVUkgaW5wdXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGluaXRpYWxpemVMYXllckNvbG9yTWFwKGxheWVyOiBMYXllciwgdmlzdWFsQ2hhbm5lbDogVmlzdWFsQ2hhbm5lbCk6IENvbG9yTWFwIHtcbiAgY29uc3QgZG9tYWluID0gbGF5ZXIuY29uZmlnW3Zpc3VhbENoYW5uZWwuZG9tYWluXTtcbiAgY29uc3QgcmFuZ2UgPSBsYXllci5jb25maWcudmlzQ29uZmlnW3Zpc3VhbENoYW5uZWwucmFuZ2VdO1xuICBjb25zdCBzY2FsZVR5cGUgPSBsYXllci5jb25maWdbdmlzdWFsQ2hhbm5lbC5zY2FsZV07XG4gIGNvbnN0IGZpZWxkID0gbGF5ZXIuY29uZmlnW3Zpc3VhbENoYW5uZWwuZmllbGRdO1xuXG4gIGNvbnN0IHNjYWxlID0gZ2V0TGF5ZXJDb2xvclNjYWxlKHtcbiAgICByYW5nZSxcbiAgICBkb21haW4sXG4gICAgc2NhbGVUeXBlLFxuICAgIGxheWVyXG4gIH0pO1xuXG4gIGNvbnN0IGNvbG9yQnJlYWtzID0gZ2V0TGVnZW5kT2ZTY2FsZSh7XG4gICAgc2NhbGU6IHNjYWxlPy5ieVpvb20gPyBzY2FsZSgwKSA6IHNjYWxlLFxuICAgIHNjYWxlVHlwZSxcbiAgICBmaWVsZFR5cGU6IGZpZWxkLnR5cGVcbiAgfSk7XG4gIHJldHVybiBjb2xvckJyZWFrc1RvQ29sb3JNYXAoY29sb3JCcmVha3MpO1xufVxuXG4vKipcbiAqIEdldCB2aXN1YWwgY2hhbmVsIHNjYWxlIGZ1bmN0aW9uIGlmIGl0J3MgYmFzZWQgb24gem9vbVxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0VmlzdWFsQ2hhbm5lbFNjYWxlQnlab29tKHtcbiAgc2NhbGUsXG4gIGxheWVyLFxuICBtYXBTdGF0ZVxufToge1xuICBzY2FsZTogRDNTY2FsZUZ1bmN0aW9uIHwgbnVsbDtcbiAgbGF5ZXI6IExheWVyO1xuICBtYXBTdGF0ZT86IE1hcFN0YXRlO1xufSk6IEQzU2NhbGVGdW5jdGlvbiB8IG51bGwge1xuICBpZiAoc2NhbGU/LmJ5Wm9vbSkge1xuICAgIGNvbnN0IHogPSBsYXllci5tZXRhPy5nZXRab29tID8gbGF5ZXIubWV0YS5nZXRab29tKG1hcFN0YXRlKSA6IG1hcFN0YXRlPy56b29tO1xuICAgIHNjYWxlID0gTnVtYmVyLmlzRmluaXRlKHopID8gc2NhbGUoeikgOiBudWxsO1xuICB9XG4gIHJldHVybiBzY2FsZTtcbn1cblxuLyoqXG4gKiBHZXQgY2F0ZWdvcmljYWwgY29sb3JNYXAgZnJvbSBjb2xvcnMgYW5kIGRvbWFpbiAodW5pcXVlIHZhbHVlcylcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldENhdGVnb3JpY2FsQ29sb3JNYXAoXG4gIGNvbG9yczogc3RyaW5nW10sXG4gIGRvbWFpbjogKHN0cmluZyB8IG51bWJlciB8IHN0cmluZ1tdIHwgbnVtYmVyW10gfCBudWxsKVtdXG4pOiBhbnkge1xuICBjb25zdCB1bmlxdWVWYWx1ZXMgPSB1bmlxdWUoZG9tYWluKS5zb3J0KCk7XG4gIGNvbnN0IGNvbG9yTWFwID0gY29sb3JzLm1hcChjb2xvciA9PiBbbnVsbCwgY29sb3JdKTtcblxuICBpZiAoY29sb3JzLmxlbmd0aCA9PT0gMCB8fCB1bmlxdWVWYWx1ZXMubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIGNvbG9yTWFwO1xuICB9XG5cbiAgY29uc3QgbGFzdEluZGV4ID0gY29sb3JzLmxlbmd0aCAtIDE7XG4gIGNvbnN0IGFzc2lnbkNvdW50ID0gTWF0aC5taW4obGFzdEluZGV4LCB1bmlxdWVWYWx1ZXMubGVuZ3RoKTtcblxuICAvLyBBc3NpZ24gZmlyc3QgdmFsdWVzIG9uZS10by1vbmUgdXAgdG8gdGhlIHBlbnVsdGltYXRlIGNvbG9yIChpZiBhbnkpXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXNzaWduQ291bnQ7IGkrKykge1xuICAgIC8vIEB0cy1pZ25vcmUgdHVwbGVcbiAgICBjb2xvck1hcFtpXVswXSA9IHVuaXF1ZVZhbHVlc1tpXTtcbiAgfVxuXG4gIGlmICh1bmlxdWVWYWx1ZXMubGVuZ3RoID4gY29sb3JzLmxlbmd0aCkge1xuICAgIC8vIEFnZ3JlZ2F0ZSB0aGUgcmVzdCAoaW5jbHVkaW5nIHRoZSB2YWx1ZSB0aGF0IHdvdWxkIGhhdmUgZ29uZSB0byBsYXN0IGNvbG9yKVxuICAgIC8vIEJ1aWxkIGFnZ3JlZ2F0ZWQgYXJyYXkgaW5jcmVtZW50YWxseSB0byBtYXRjaCBsZWdhY3kgYmVoYXZpb3JcbiAgICBjb25zdCBhZ2dyZWdhdGVkVmFsdWVzOiBhbnlbXSA9IFtdO1xuICAgIGZvciAobGV0IGkgPSBsYXN0SW5kZXg7IGkgPCB1bmlxdWVWYWx1ZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IHZhbHVlID0gdW5pcXVlVmFsdWVzW2ldO1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgIC8vIFNwcmVhZCBhcnJheSBlbGVtZW50cyB0byBtYXRjaCBsZWdhY3kgZmxhdHRlbmluZyBiZWhhdmlvclxuICAgICAgICBhZ2dyZWdhdGVkVmFsdWVzLnB1c2goLi4uKHZhbHVlIGFzIGFueVtdKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhZ2dyZWdhdGVkVmFsdWVzLnB1c2godmFsdWUpO1xuICAgICAgfVxuICAgIH1cbiAgICAvLyBAdHMtaWdub3JlIHR1cGxlXG4gICAgY29sb3JNYXBbbGFzdEluZGV4XVswXSA9IGFnZ3JlZ2F0ZWRWYWx1ZXM7XG4gIH0gZWxzZSBpZiAodW5pcXVlVmFsdWVzLmxlbmd0aCA9PT0gY29sb3JzLmxlbmd0aCkge1xuICAgIC8vIEV4YWN0bHkgb25lIHBlciBjb2xvclxuICAgIC8vIEB0cy1pZ25vcmUgdHVwbGVcbiAgICBjb2xvck1hcFtsYXN0SW5kZXhdWzBdID0gdW5pcXVlVmFsdWVzW2xhc3RJbmRleF07XG4gIH1cblxuICAvLyBAdHMtaWdub3JlIHR1cGxlXG4gIHJldHVybiBjb2xvck1hcDtcbn1cblxuLyoqXG4gKiBHZXQgY2F0ZWdvcmljYWwgY29sb3JCcmVha3MgZnJvbSBjb2xvck1hcFxuICovXG5leHBvcnQgZnVuY3Rpb24gY29sb3JNYXBUb0NhdGVnb3JpY2FsQ29sb3JCcmVha3MoXG4gIGNvbG9yTWFwPzogQ29sb3JNYXAgfCBudWxsXG4pOiBDb2xvckJyZWFrT3JkaW5hbFtdIHwgbnVsbCB7XG4gIGlmICghY29sb3JNYXApIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBjb25zdCBjb2xvckJyZWFrcyA9IGNvbG9yTWFwLm1hcCgoW3ZhbHVlLCBjb2xvcl0pID0+IHtcbiAgICByZXR1cm4ge1xuICAgICAgZGF0YTogY29sb3IsXG4gICAgICBsYWJlbDogdmFsdWVcbiAgICB9O1xuICB9KTtcblxuICByZXR1cm4gY29sb3JCcmVha3M7XG59XG5cbi8qKlxuICogY3JlYXRlIGNhdGVnb3JpY2FsIGNvbG9yTWFwIGZyb20gY29sb3JCcmVha3NcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbG9yQnJlYWtzVG9DYXRlZ29yaWNhbENvbG9yTWFwKGNvbG9yQnJlYWtzOiBDb2xvckJyZWFrT3JkaW5hbFtdKTogQ29sb3JNYXAge1xuICAvLyBjb2xvck1hcDogW3N0cmluZyB8IHN0cmluZ1tdLCBoZXhzdHJpbmddXG4gIGNvbnN0IGNvbG9ycyA9IHVuaXEoY29sb3JCcmVha3MubWFwKGNiID0+IGNiLmRhdGEpKTtcbiAgY29uc3QgdmFsdWVzID0gdW5pcShjb2xvckJyZWFrcy5tYXAoY2IgPT4gY2IubGFiZWwpKTtcblxuICByZXR1cm4gZ2V0Q2F0ZWdvcmljYWxDb2xvck1hcChjb2xvcnMsIHZhbHVlcyk7XG59XG5cbi8qKlxuICogQ29udmVydCBjb2xvciBicmVha3MgVUkgaW5wdXQgaW50byBjb2xvclJhbmdlLmNvbG9yTWFwXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb2xvckJyZWFrc1RvQ29sb3JNYXAoY29sb3JCcmVha3M6IENvbG9yQnJlYWtbXSB8IENvbG9yQnJlYWtPcmRpbmFsW10pOiBDb2xvck1hcCB7XG4gIGNvbnN0IGNvbG9yTWFwID0gY29sb3JCcmVha3MubWFwKChjb2xvckJyZWFrLCBpKSA9PiB7XG4gICAgLy8gW3ZhbHVlLCBoZXhdXG4gICAgcmV0dXJuIFtcbiAgICAgIGNvbG9yQnJlYWsuaW5wdXRzXG4gICAgICAgID8gaSA9PT0gY29sb3JCcmVha3MubGVuZ3RoIC0gMVxuICAgICAgICAgID8gbnVsbCAvLyBsYXN0XG4gICAgICAgICAgOiBjb2xvckJyZWFrLmlucHV0c1sxXVxuICAgICAgICA6IGNvbG9yQnJlYWsubGFiZWwsXG4gICAgICBjb2xvckJyZWFrLmRhdGFcbiAgICBdO1xuICB9KTtcblxuICAvLyBAdHMtaWdub3JlIHR1cGxlXG4gIHJldHVybiBjb2xvck1hcDtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGNvbG9yUmFuZ2UuY29sb3JNYXAgaW50byBjb2xvciBicmVha3MgVUkgaW5wdXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbG9yTWFwVG9Db2xvckJyZWFrcyhjb2xvck1hcD86IENvbG9yTWFwIHwgbnVsbCk6IENvbG9yQnJlYWtbXSB8IG51bGwge1xuICBpZiAoIWNvbG9yTWFwKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgY29uc3QgY29sb3JCcmVha3MgPSBjb2xvck1hcC5tYXAoKFt2YWx1ZSwgY29sb3JdLCBpKSA9PiB7XG4gICAgY29uc3QgcmFuZ2UgPVxuICAgICAgaSA9PT0gMFxuICAgICAgICA/IC8vIGZpcnN0XG4gICAgICAgICAgWy1JbmZpbml0eSwgdmFsdWVdXG4gICAgICAgIDogLy8gbGFzdFxuICAgICAgICBpID09PSBjb2xvck1hcC5sZW5ndGggLSAxXG4gICAgICAgID8gW2NvbG9yTWFwW2kgLSAxXVswXSwgSW5maW5pdHldXG4gICAgICAgIDogLy8gZWxzZVxuICAgICAgICAgIFtjb2xvck1hcFtpIC0gMV1bMF0sIHZhbHVlXTtcbiAgICByZXR1cm4ge1xuICAgICAgZGF0YTogY29sb3IsXG4gICAgICByYW5nZSxcbiAgICAgIGlucHV0czogcmFuZ2UsXG4gICAgICBsYWJlbDpcbiAgICAgICAgLy8gZmlyc3RcbiAgICAgICAgaSA9PT0gMFxuICAgICAgICAgID8gYExlc3MgdGhhbiAke3ZhbHVlfWBcbiAgICAgICAgICA6IC8vIGxhc3RcbiAgICAgICAgICBpID09PSBjb2xvck1hcC5sZW5ndGggLSAxXG4gICAgICAgICAgPyBgJHtjb2xvck1hcFtpIC0gMV1bMF19IG9yIG1vcmVgXG4gICAgICAgICAgOiBgJHtjb2xvck1hcFtpIC0gMV1bMF19IHRvICR7dmFsdWV9YFxuICAgIH07XG4gIH0pO1xuXG4gIC8vIEB0cy1pZ25vcmUgaW1wbGVtZW50IGNvbnZlcnNpb24gZm9yIG9yZGluYWxcbiAgcmV0dXJuIGNvbG9yQnJlYWtzO1xufVxuXG4vKipcbiAqIFdoZXRoZXIgY29sb3IgYnJlYWtzIGlzIGZvciBudW1lcmljIGZpZWxkXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc051bWVyaWNDb2xvckJyZWFrcyhjb2xvckJyZWFrczogdW5rbm93bik6IGNvbG9yQnJlYWtzIGlzIENvbG9yQnJlYWtbXSB7XG4gIHJldHVybiBCb29sZWFuKEFycmF5LmlzQXJyYXkoY29sb3JCcmVha3MpICYmIGNvbG9yQnJlYWtzLmxlbmd0aCAmJiBjb2xvckJyZWFrc1swXS5pbnB1dHMpO1xufVxuXG4vLyByZXR1cm4gZG9tYWluTWluLCBkb21haW5NYXgsIGhpc3RvZ3JhbU1lYW5cbmV4cG9ydCBmdW5jdGlvbiBnZXRIaXN0b2dyYW1Eb21haW4oe1xuICBhZ2dyZWdhdGVkQmlucyxcbiAgY29sdW1uU3RhdHMsXG4gIGRhdGFzZXQsXG4gIGZpZWxkVmFsdWVBY2Nlc3NvclxufToge1xuICBhZ2dyZWdhdGVkQmlucz86IEFnZ3JlZ2F0ZWRCaW5bXTtcbiAgY29sdW1uU3RhdHM/OiBGaWx0ZXJQcm9wc1snY29sdW1uU3RhdHMnXTtcbiAgZGF0YXNldD86IEtlcGxlclRhYmxlO1xuICBmaWVsZFZhbHVlQWNjZXNzb3I6IChpZHg6IHVua25vd24pID0+IG51bWJlcjtcbn0pIHtcbiAgbGV0IGRvbWFpbk1pbiA9IE51bWJlci5QT1NJVElWRV9JTkZJTklUWTtcbiAgbGV0IGRvbWFpbk1heCA9IE51bWJlci5ORUdBVElWRV9JTkZJTklUWTtcbiAgbGV0IG5WYWxpZCA9IDA7XG4gIGxldCBkb21haW5TdW0gPSAwO1xuXG4gIGlmIChhZ2dyZWdhdGVkQmlucykge1xuICAgIE9iamVjdC52YWx1ZXMoYWdncmVnYXRlZEJpbnMpLmZvckVhY2goYmluID0+IHtcbiAgICAgIGNvbnN0IHZhbCA9IGJpbi52YWx1ZTtcbiAgICAgIGlmIChpc051bWJlcih2YWwpKSB7XG4gICAgICAgIGlmICh2YWwgPCBkb21haW5NaW4pIGRvbWFpbk1pbiA9IHZhbDtcbiAgICAgICAgaWYgKHZhbCA+IGRvbWFpbk1heCkgZG9tYWluTWF4ID0gdmFsO1xuICAgICAgICBkb21haW5TdW0gKz0gdmFsO1xuICAgICAgICBuVmFsaWQgKz0gMTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSBlbHNlIHtcbiAgICBpZiAoY29sdW1uU3RhdHMgJiYgY29sdW1uU3RhdHMucXVhbnRpbGVzICYmIGNvbHVtblN0YXRzLm1lYW4pIHtcbiAgICAgIC8vIG5vIG5lZWQgdG8gcmVjYWxjdWF0ZSBtaW4vbWF4L21lYW4gaWYgaXRzIGFscmVhZHkgaW4gY29sdW1uU3RhdHNcbiAgICAgIHJldHVybiBbXG4gICAgICAgIGNvbHVtblN0YXRzLnF1YW50aWxlc1swXS52YWx1ZSxcbiAgICAgICAgY29sdW1uU3RhdHMucXVhbnRpbGVzW2NvbHVtblN0YXRzLnF1YW50aWxlcy5sZW5ndGggLSAxXS52YWx1ZSxcbiAgICAgICAgY29sdW1uU3RhdHMubWVhblxuICAgICAgXTtcbiAgICB9XG4gICAgaWYgKGRhdGFzZXQgJiYgZmllbGRWYWx1ZUFjY2Vzc29yKSB7XG4gICAgICBkYXRhc2V0LmFsbEluZGV4ZXMuZm9yRWFjaCh4ID0+IHtcbiAgICAgICAgY29uc3QgdmFsID0gZmllbGRWYWx1ZUFjY2Vzc29yKHgpO1xuICAgICAgICBpZiAoaXNOdW1iZXIodmFsKSkge1xuICAgICAgICAgIGlmICh2YWwgPCBkb21haW5NaW4pIGRvbWFpbk1pbiA9IHZhbDtcbiAgICAgICAgICBpZiAodmFsID4gZG9tYWluTWF4KSBkb21haW5NYXggPSB2YWw7XG4gICAgICAgICAgZG9tYWluU3VtICs9IHZhbDtcbiAgICAgICAgICBuVmFsaWQgKz0gMTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuICB9XG4gIGNvbnN0IGhpc3RvZ3JhbU1lYW4gPSBuVmFsaWQgPiAwID8gZG9tYWluU3VtIC8gblZhbGlkIDogMDtcbiAgcmV0dXJuIFtuVmFsaWQgPiAwID8gZG9tYWluTWluIDogMCwgblZhbGlkID4gMCA/IGRvbWFpbk1heCA6IDAsIGhpc3RvZ3JhbU1lYW5dO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcmVzZXRDYXRlZ29yaWNhbENvbG9yTWFwQnlJbmRleChjb2xvck1hcDogQ29sb3JNYXAsIGluZGV4OiBudW1iZXIpOiBhbnkge1xuICBpZiAoIWNvbG9yTWFwKSB7XG4gICAgcmV0dXJuIGNvbG9yTWFwO1xuICB9XG4gIGNvbnN0IG5ld0NvbG9yTWFwID0gY29sb3JNYXAubWFwKChjbSwgaSkgPT4ge1xuICAgIGlmIChpID09PSBpbmRleCkge1xuICAgICAgcmV0dXJuIFtudWxsLCBjbVsxXV07XG4gICAgfVxuICAgIHJldHVybiBjbTtcbiAgfSk7XG4gIHJldHVybiBuZXdDb2xvck1hcDtcbn1cblxuLyoqXG4gKiBzZWxlY3QgcmVzdCBjYXRlZ29yaWNhbCB2YWx1ZXMgZm9yIGEgY29sb3JNYXAgYnkgaXRzIGluZGV4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZWxlY3RSZXN0Q2F0ZWdvcmljYWxDb2xvck1hcEJ5SW5kZXgoXG4gIGNvbG9yTWFwOiBDb2xvck1hcCB8IG51bGwsXG4gIGluZGV4OiBudW1iZXIsXG4gIHVuaXF1ZVZhbHVlcz86IG51bWJlcltdIHwgc3RyaW5nW11cbik6IENvbG9yTWFwIHwgdW5kZWZpbmVkIHwgbnVsbCB7XG4gIGlmICghY29sb3JNYXAgfHwgIXVuaXF1ZVZhbHVlcykge1xuICAgIHJldHVybiBjb2xvck1hcDtcbiAgfVxuXG4gIC8vIGZpbmQgdW5pcXVlIHZhbHVlcyB0aGF0IGhhcyBub3QgYmVlbiB1c2VkIGluIGN1cnJlbnQgY29sb3JNYXBcbiAgY29uc3QgdW5pcVZhbHVlRGljdCA9IE9iamVjdC5mcm9tRW50cmllcyh1bmlxdWVWYWx1ZXMubWFwKHZhbCA9PiBbdmFsLCBmYWxzZV0pKTtcbiAgY29sb3JNYXAuZm9yRWFjaChjbSA9PiB7XG4gICAgdG9BcnJheShjbVswXSkuZm9yRWFjaCh2ID0+IHtcbiAgICAgIGlmICh2KSB1bmlxVmFsdWVEaWN0W3ZdID0gdHJ1ZTtcbiAgICB9KTtcbiAgfSk7XG4gIGNvbnN0IHJlc3QgPSBPYmplY3Qua2V5cyh1bmlxVmFsdWVEaWN0KS5maWx0ZXIodiA9PiAhdW5pcVZhbHVlRGljdFt2XSk7XG5cbiAgLy8gdXNlIHRoZSBub3QgdXNlZCB1bmlxdWUgdmFsdWVzIGluIHRoZSBzZWxlY3RlZCBjb2xvciBtYXBcbiAgY29uc3QgbmV3Q29sb3JNYXAgPSBjb2xvck1hcC5tYXAoKGNtLCBpKSA9PiB7XG4gICAgaWYgKGkgPT09IGluZGV4KSB7XG4gICAgICByZXR1cm4gW1suLi5yZXN0LCAuLi50b0FycmF5KGNtWzBdKV0sIGNtWzFdXTtcbiAgICB9XG4gICAgcmV0dXJuIGNtO1xuICB9KSBhcyBDb2xvck1hcDtcblxuICByZXR1cm4gbmV3Q29sb3JNYXA7XG59XG5cbi8qKlxuICogcmVtb3ZlIGEgY2F0ZWdvcmljYWwgdmFsdWUgZnJvbSBhIGNvbG9yTWFwIGJ5IGl0cyBpbmRleFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVtb3ZlQ2F0ZWdvcmljYWxWYWx1ZUZyb21Db2xvck1hcChcbiAgY29sb3JNYXA6IENvbG9yTWFwIHwgbnVsbCB8IHVuZGVmaW5lZCxcbiAgaXRlbTogbnVtYmVyIHwgc3RyaW5nLFxuICBpbmRleDogbnVtYmVyXG4pOiBDb2xvck1hcCB8IG51bGwgfCB1bmRlZmluZWQge1xuICBpZiAoIWNvbG9yTWFwKSB7XG4gICAgcmV0dXJuIGNvbG9yTWFwO1xuICB9XG4gIGNvbnN0IG5ld0NvbG9yTWFwID0gY29sb3JNYXAubWFwKChjbSwgaSkgPT4ge1xuICAgIGlmIChpID09PSBpbmRleCkge1xuICAgICAgaWYgKCFjbVswXSkge1xuICAgICAgICByZXR1cm4gW251bGwsIGNtWzFdXTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IGN1cnJlbnRVbmlxdWVWYWx1ZXMgPSB0b0FycmF5KGNtWzBdKTtcbiAgICAgIGNvbnN0IHVwZGF0ZWRVbmlxdWVWYWx1ZXMgPSBjdXJyZW50VW5pcXVlVmFsdWVzLmZpbHRlcih2ID0+IHYgIT09IGl0ZW0pO1xuICAgICAgcmV0dXJuIFt1cGRhdGVkVW5pcXVlVmFsdWVzLCBjbVsxXV07XG4gICAgfVxuICAgIHJldHVybiBjbTtcbiAgfSkgYXMgQ29sb3JNYXA7XG5cbiAgcmV0dXJuIG5ld0NvbG9yTWFwO1xufVxuXG4vKipcbiAqIGFkZCBjYXRlZ29yaWNhbCB2YWx1ZXMgKGZyb20gbXVsdGlzZWwgZHJvcGRvd24pIHRvIGEgY29sb3JNYXAgYnkgaXRzIGluZGV4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBhZGRDYXRlZ29yaWNhbFZhbHVlc1RvQ29sb3JNYXAoXG4gIGNvbG9yTWFwOiBDb2xvck1hcCxcbiAgaXRlbXM6IChzdHJpbmcgfCBudW1iZXIpW10sXG4gIGluZGV4OiBudW1iZXJcbik6IENvbG9yTWFwIHtcbiAgaWYgKCFjb2xvck1hcCkge1xuICAgIHJldHVybiBjb2xvck1hcDtcbiAgfVxuXG4gIGNvbnN0IG5ld0NvbG9yTWFwID0gY29sb3JNYXAubWFwKChjbSwgaSkgPT4ge1xuICAgIGlmIChpID09PSBpbmRleCkge1xuICAgICAgaWYgKCFjbVswXSkge1xuICAgICAgICByZXR1cm4gW2l0ZW1zLCBjbVsxXV07XG4gICAgICB9XG4gICAgICBjb25zdCBjdXJyZW50VW5pcXVlVmFsdWVzID0gdG9BcnJheShjbVswXSk7XG4gICAgICBjb25zdCB1cGRhdGVkVW5pcXVlVmFsdWVzID0gdW5pcShjdXJyZW50VW5pcXVlVmFsdWVzLmNvbmNhdChpdGVtcykpO1xuICAgICAgcmV0dX