UNPKG

kepler.gl

Version:

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

534 lines (511 loc) 63.5 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof3 = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.MIN_LONGITUDE = exports.MIN_LATITUDE = exports.MAX_LONGITUDE = exports.MAX_LATITUDE = exports.FIELD_DISPLAY_FORMAT = void 0; exports.applyCustomFormat = applyCustomFormat; exports.applyDefaultFormat = applyDefaultFormat; exports.applyValueMap = applyValueMap; exports.clamp = clamp; exports.datetimeFormatter = datetimeFormatter; exports.floatFormatter = exports.defaultFormatter = void 0; exports.formatNumber = formatNumber; exports.getBooleanFormatter = getBooleanFormatter; exports.getColumnFormatter = getColumnFormatter; exports.getFormatter = getFormatter; exports.getLatLngBounds = getLatLngBounds; exports.getRoundingDecimalFromStep = getRoundingDecimalFromStep; exports.getSampleData = getSampleData; exports.getSortingFunction = getSortingFunction; exports.hasOwnProperty = hasOwnProperty; exports.isNumber = isNumber; exports.normalizeSliderValue = normalizeSliderValue; exports.numberSort = numberSort; exports.parseFieldValue = void 0; exports.preciseRound = preciseRound; exports.reverseFormatNumber = reverseFormatNumber; exports.roundToFour = roundToFour; exports.roundValToStep = roundValToStep; exports.timeToUnixMilli = timeToUnixMilli; exports.uint8ArrayToHex = uint8ArrayToHex; exports.unique = unique; exports.validateCoordinate = validateCoordinate; exports.validateLatitude = validateLatitude; exports.validateLongitude = validateLongitude; var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var arrow = _interopRequireWildcard(require("apache-arrow")); var _assert = _interopRequireDefault(require("assert")); var _d3Format = require("d3-format"); var _momentTimezone = _interopRequireDefault(require("moment-timezone")); var _arrow = require("@loaders.gl/arrow"); var _constants = require("@kepler.gl/constants"); var _commonUtils = require("@kepler.gl/common-utils"); var _plot = require("./plot"); var _utils = require("./utils"); var _FIELD_DISPLAY_FORMAT; // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof3(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } // We need threat latitude differently otherwise mercator project view throws // a projection matrix error // Uncaught Error: Pixel project matrix not invertible // at WebMercatorViewport16.Viewport6 (viewport.js:81:13) var MAX_LATITUDE = exports.MAX_LATITUDE = 89.9; var MIN_LATITUDE = exports.MIN_LATITUDE = -89.9; var MAX_LONGITUDE = exports.MAX_LONGITUDE = 180; var MIN_LONGITUDE = exports.MIN_LONGITUDE = -180; /** * Validates a latitude value. * Ensures that the latitude is within the defined minimum and maximum latitude bounds. * If the value is out of bounds, it returns the nearest bound value. * @param latitude - The latitude value to validate. * @returns The validated latitude value. */ function validateLatitude(latitude) { return validateCoordinate(latitude !== null && latitude !== void 0 ? latitude : 0, MIN_LATITUDE, MAX_LATITUDE); } /** * Validates a longitude value. * Ensures that the longitude is within the defined minimum and maximum longitude bounds. * If the value is out of bounds, it returns the nearest bound value. * @param longitude - The longitude value to validate. * @returns The validated longitude value. */ function validateLongitude(longitude) { return validateCoordinate(longitude !== null && longitude !== void 0 ? longitude : 0, MIN_LONGITUDE, MAX_LONGITUDE); } /** * Validates a coordinate value. * Ensures that the value is within the specified minimum and maximum bounds. * If the value is out of bounds, it returns the nearest bound value. * @param value - The coordinate value to validate. * @param minValue - The minimum bound for the value. * @param maxValue - The maximum bound for the value. * @returns The validated coordinate value. */ function validateCoordinate(value, minValue, maxValue) { if (value <= minValue) { return minValue; } if (value >= maxValue) { return maxValue; } return value; } /** * simple getting unique values of an array * * @param values * @returns unique values */ function unique(values) { var results = []; var uniqueSet = new Set(values); uniqueSet.forEach(function (v) { if ((0, _commonUtils.notNullorUndefined)(v)) { results.push(v); } }); return results; } function getLatLngBounds(points, idx, limit) { var lats = points.map(function (d) { return Number(Array.isArray(d)) && d[idx]; }).filter(Number.isFinite).sort(numberSort); if (!lats.length) { return null; } // clamp to limit return [Math.max(lats[0], limit[0]), Math.min(lats[lats.length - 1], limit[1])]; } function clamp(_ref) { var _ref2 = (0, _slicedToArray2["default"])(_ref, 2), min = _ref2[0], max = _ref2[1]; var val = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; return val <= min ? min : val >= max ? max : val; } function getSampleData(data) { var sampleSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500; var getValue = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : function (d) { return d; }; var sampleStep = Math.max(Math.floor(data.length / sampleSize), 1); var output = []; for (var i = 0; i < data.length; i += sampleStep) { output.push(getValue(data[i])); } return output; } /** * Convert different time format to unix milliseconds */ function timeToUnixMilli(value, format) { if ((0, _commonUtils.notNullorUndefined)(value)) { if (typeof value === 'string') { return _momentTimezone["default"].utc(value, format).valueOf(); } if (typeof value === 'number') { return format === 'x' ? value * 1000 : value; } if (value instanceof Date) { return value.valueOf(); } } return null; } /** * Whether d is a number, this filtered out NaN as well */ function isNumber(d) { return Number.isFinite(d); } /** * whether object has property * @param {string} prop * @returns {boolean} - yes or no */ function hasOwnProperty(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } function numberSort(a, b) { return a - b; } function getSortingFunction(fieldType) { switch (fieldType) { case _constants.ALL_FIELD_TYPES.real: case _constants.ALL_FIELD_TYPES.integer: case _constants.ALL_FIELD_TYPES.timestamp: return numberSort; default: return undefined; } } /** * round number with exact number of decimals * return as a string */ function preciseRound(num, decimals) { var t = Math.pow(10, decimals); return (Math.round(num * t + (decimals > 0 ? 1 : 0) * (Math.sign(num) * (10 / Math.pow(100, decimals)))) / t).toFixed(decimals); } /** * round a giving number at most 4 decimal places * e.g. 10 -> 10, 1.12345 -> 1.2345, 2.0 -> 2 */ function roundToFour(num) { // @ts-expect-error return Number("".concat(Math.round("".concat(num, "e+4")), "e-4")); } /** * get number of decimals to round to for slider from step * @param step * @returns- number of decimal */ function getRoundingDecimalFromStep(step) { if (isNaN(step)) { (0, _assert["default"])('step is not a number'); (0, _assert["default"])(step); } var stepStr = step.toString(); // in case the step is a very small number e.g. 1e-7, return decimal e.g. 7 directly var splitExponential = stepStr.split('e-'); if (splitExponential.length === 2) { var coeffZero = splitExponential[0].split('.'); var coeffDecimal = coeffZero.length === 1 ? 0 : coeffZero[1].length; return parseInt(splitExponential[1], 10) + coeffDecimal; } var splitZero = stepStr.split('.'); if (splitZero.length === 1) { return 0; } return splitZero[1].length; } /** * If marks is provided, snap to marks, if not normalize to step * @param val * @param minValue * @param step * @param marks */ function normalizeSliderValue(val, minValue, step, marks) { if (marks && marks.length) { // Use in slider, given a number and an array of numbers, return the nears number from the array return (0, _plot.snapToMarks)(val, marks); } return roundValToStep(minValue, step, val); } /** * round the value to step for the slider * @param minValue * @param step * @param val * @returns - rounded number */ function roundValToStep(minValue, step, val) { if (!isNumber(step) || !isNumber(minValue)) { return val; } var decimal = getRoundingDecimalFromStep(step); var steps = Math.floor((val - minValue) / step); var remain = val - (steps * step + minValue); // has to round because javascript turns 0.1 into 0.9999999999999987 remain = Number(preciseRound(remain, 8)); var closest; if (remain === 0) { closest = val; } else if (remain < step / 2) { closest = steps * step + minValue; } else { closest = (steps + 1) * step + minValue; } // precise round return a string rounded to the defined decimal var rounded = preciseRound(closest, decimal); return Number(rounded); } /** * Get the value format based on field and format options * Used in render tooltip value */ var defaultFormatter = exports.defaultFormatter = function defaultFormatter(v) { return (0, _commonUtils.notNullorUndefined)(v) ? String(v) : ''; }; var floatFormatter = exports.floatFormatter = function floatFormatter(v) { return isNumber(v) ? String(roundToFour(v)) : ''; }; /** * Transforms a WKB in Uint8Array form into a hex WKB string. * @param uint8Array WKB in Uint8Array form. * @returns hex WKB string. */ function uint8ArrayToHex(data) { return Array.from(data).map(function (_byte) { return _byte.toString(16).padStart(2, '0'); }).join(''); } var FIELD_DISPLAY_FORMAT = exports.FIELD_DISPLAY_FORMAT = (_FIELD_DISPLAY_FORMAT = {}, (0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])((0, _defineProperty2["default"])(_FIELD_DISPLAY_FORMAT, _constants.ALL_FIELD_TYPES.string, defaultFormatter), _constants.ALL_FIELD_TYPES.timestamp, defaultFormatter), _constants.ALL_FIELD_TYPES.integer, defaultFormatter), _constants.ALL_FIELD_TYPES.real, defaultFormatter), _constants.ALL_FIELD_TYPES["boolean"], defaultFormatter), _constants.ALL_FIELD_TYPES.date, defaultFormatter), _constants.ALL_FIELD_TYPES.geojson, function (d) { return typeof d === 'string' ? d : (0, _utils.isPlainObject)(d) ? JSON.stringify(d) : Array.isArray(d) ? "[".concat(String(d), "]") : ''; }), _constants.ALL_FIELD_TYPES.geoarrow, function (data, field) { if (data instanceof arrow.Vector) { try { var _field$metadata; var encoding = field === null || field === void 0 || (_field$metadata = field.metadata) === null || _field$metadata === void 0 ? void 0 : _field$metadata.get('ARROW:extension:name'); if (encoding) { var geometry = (0, _arrow.parseGeometryFromArrow)(data, encoding); return JSON.stringify(geometry); } } catch (error) { // ignore for now } } else if (data instanceof Uint8Array) { return uint8ArrayToHex(data); } return data; }), _constants.ALL_FIELD_TYPES.object, function (value) { try { return JSON.stringify(value); } catch (e) { return String(value); } }), _constants.ALL_FIELD_TYPES.array, function (d) { return JSON.stringify(d); }), (0, _defineProperty2["default"])(_FIELD_DISPLAY_FORMAT, _constants.ALL_FIELD_TYPES.h3, defaultFormatter)); /** * Parse field value and type and return a string representation */ var parseFieldValue = exports.parseFieldValue = function parseFieldValue(value, type, field) { if (!(0, _commonUtils.notNullorUndefined)(value)) { return ''; } // BigInt values cannot be serialized with JSON.stringify() directly // We need to explicitly convert them to strings using .toString() // See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt#use_within_json if (typeof value === 'bigint') { return value.toString(); } return FIELD_DISPLAY_FORMAT[type] ? FIELD_DISPLAY_FORMAT[type](value, field) : String(value); }; /** * Get the value format based on field and format options * Used in render tooltip value * @param format * @param field */ function getFormatter(format, field) { if (!format) { return defaultFormatter; } var tooltipFormat = Object.values(_constants.TOOLTIP_FORMATS).find(function (f) { return f[_constants.TOOLTIP_KEY] === format; }); if (tooltipFormat) { return applyDefaultFormat(tooltipFormat); } else if (typeof format === 'string' && field) { return applyCustomFormat(format, field); } return defaultFormatter; } function getColumnFormatter(field) { var format = field.format, displayFormat = field.displayFormat; if (!format && !displayFormat) { return FIELD_DISPLAY_FORMAT[field.type]; } var tooltipFormat = Object.values(_constants.TOOLTIP_FORMATS).find(function (f) { return f[_constants.TOOLTIP_KEY] === displayFormat; }); if (tooltipFormat) { return applyDefaultFormat(tooltipFormat); } else if (typeof displayFormat === 'string' && field) { return applyCustomFormat(displayFormat, field); } else if ((0, _typeof2["default"])(displayFormat) === 'object') { return applyValueMap(displayFormat); } return defaultFormatter; } function applyValueMap(format) { return function (v) { return format[v]; }; } function applyDefaultFormat(tooltipFormat) { if (!tooltipFormat || !tooltipFormat.format) { return defaultFormatter; } switch (tooltipFormat.type) { case _constants.TOOLTIP_FORMAT_TYPES.DECIMAL: return (0, _d3Format.format)(tooltipFormat.format); case _constants.TOOLTIP_FORMAT_TYPES.DATE: case _constants.TOOLTIP_FORMAT_TYPES.DATE_TIME: return datetimeFormatter(null)(tooltipFormat.format); case _constants.TOOLTIP_FORMAT_TYPES.PERCENTAGE: return function (v) { return "".concat((0, _d3Format.format)(_constants.TOOLTIP_FORMATS.DECIMAL_DECIMAL_FIXED_2.format)(v), "%"); }; case _constants.TOOLTIP_FORMAT_TYPES.BOOLEAN: return getBooleanFormatter(tooltipFormat.format); default: return defaultFormatter; } } function getBooleanFormatter(format) { switch (format) { case '01': return function (v) { return v ? '1' : '0'; }; case 'yn': return function (v) { return v ? 'yes' : 'no'; }; default: return defaultFormatter; } } // Allow user to specify custom tooltip format via config function applyCustomFormat(format, field) { switch (field.type) { case _constants.ALL_FIELD_TYPES.real: case _constants.ALL_FIELD_TYPES.integer: return (0, _d3Format.format)(format); case _constants.ALL_FIELD_TYPES.date: case _constants.ALL_FIELD_TYPES.timestamp: return datetimeFormatter(null)(format); default: return function (v) { return v; }; } } function formatLargeNumber(n) { // SI-prefix with 4 significant digits return (0, _d3Format.format)('.4~s')(n); } function formatNumber(n, type) { switch (type) { case _constants.ALL_FIELD_TYPES.integer: if (n < 0) { return "-".concat(formatNumber(-n, 'integer')); } if (n < 1000) { return "".concat(Math.round(n)); } if (n < 10 * 1000) { return (0, _d3Format.format)(',')(Math.round(n)); } return formatLargeNumber(n); case _constants.ALL_FIELD_TYPES.real: if (n < 0) { return "-".concat(formatNumber(-n, 'number')); } if (n < 1000) { return (0, _d3Format.format)('.4~r')(n); } if (n < 10 * 1000) { return (0, _d3Format.format)(',.2~f')(n); } return formatLargeNumber(n); default: return formatNumber(n, 'real'); } } var transformation = { Y: Math.pow(10, 24), Z: Math.pow(10, 21), E: Math.pow(10, 18), P: Math.pow(10, 15), T: Math.pow(10, 12), G: Math.pow(10, 9), M: Math.pow(10, 6), k: Math.pow(10, 3), h: Math.pow(10, 2), da: Math.pow(10, 1), d: Math.pow(10, -1), c: Math.pow(10, -2), m: Math.pow(10, -3), μ: Math.pow(10, -6), n: Math.pow(10, -9), p: Math.pow(10, -12), f: Math.pow(10, -15), a: Math.pow(10, -18), z: Math.pow(10, -21), y: Math.pow(10, -24) }; /** * Convert a formatted number from string back to number */ function reverseFormatNumber(str) { var returnValue = null; var strNum = str.trim().replace(/,/g, ''); Object.entries(transformation).forEach(function (d) { if (strNum.includes(d[0])) { returnValue = parseFloat(strNum) * d[1]; return true; } return false; }); // if no transformer found, convert to nuber regardless return returnValue === null ? Number(strNum) : returnValue; } /** * Format epoch milliseconds with a format string * @type timezone */ function datetimeFormatter(timezone) { return timezone ? function (format) { return function (ts) { return _momentTimezone["default"].utc(ts).tz(timezone).format(format); }; } : // return empty string instead of 'Invalid date' if ts is undefined/null function (format) { return function (ts) { return ts ? _momentTimezone["default"].utc(ts).format(format) : ''; }; }; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJhcnJvdyIsIl9pbnRlcm9wUmVxdWlyZVdpbGRjYXJkIiwicmVxdWlyZSIsIl9hc3NlcnQiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwiX2QzRm9ybWF0IiwiX21vbWVudFRpbWV6b25lIiwiX2Fycm93IiwiX2NvbnN0YW50cyIsIl9jb21tb25VdGlscyIsIl9wbG90IiwiX3V0aWxzIiwiX0ZJRUxEX0RJU1BMQVlfRk9STUFUIiwiX2dldFJlcXVpcmVXaWxkY2FyZENhY2hlIiwiZSIsIldlYWtNYXAiLCJyIiwidCIsIl9fZXNNb2R1bGUiLCJfdHlwZW9mMyIsImhhcyIsImdldCIsIm4iLCJfX3Byb3RvX18iLCJhIiwiT2JqZWN0IiwiZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IiLCJ1IiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiaSIsInNldCIsIk1BWF9MQVRJVFVERSIsImV4cG9ydHMiLCJNSU5fTEFUSVRVREUiLCJNQVhfTE9OR0lUVURFIiwiTUlOX0xPTkdJVFVERSIsInZhbGlkYXRlTGF0aXR1ZGUiLCJsYXRpdHVkZSIsInZhbGlkYXRlQ29vcmRpbmF0ZSIsInZhbGlkYXRlTG9uZ2l0dWRlIiwibG9uZ2l0dWRlIiwidmFsdWUiLCJtaW5WYWx1ZSIsIm1heFZhbHVlIiwidW5pcXVlIiwidmFsdWVzIiwicmVzdWx0cyIsInVuaXF1ZVNldCIsIlNldCIsImZvckVhY2giLCJ2Iiwibm90TnVsbG9yVW5kZWZpbmVkIiwicHVzaCIsImdldExhdExuZ0JvdW5kcyIsInBvaW50cyIsImlkeCIsImxpbWl0IiwibGF0cyIsIm1hcCIsImQiLCJOdW1iZXIiLCJBcnJheSIsImlzQXJyYXkiLCJmaWx0ZXIiLCJpc0Zpbml0ZSIsInNvcnQiLCJudW1iZXJTb3J0IiwibGVuZ3RoIiwiTWF0aCIsIm1heCIsIm1pbiIsImNsYW1wIiwiX3JlZiIsIl9yZWYyIiwiX3NsaWNlZFRvQXJyYXkyIiwidmFsIiwiYXJndW1lbnRzIiwidW5kZWZpbmVkIiwiZ2V0U2FtcGxlRGF0YSIsImRhdGEiLCJzYW1wbGVTaXplIiwiZ2V0VmFsdWUiLCJzYW1wbGVTdGVwIiwiZmxvb3IiLCJvdXRwdXQiLCJ0aW1lVG9Vbml4TWlsbGkiLCJmb3JtYXQiLCJtb21lbnQiLCJ1dGMiLCJ2YWx1ZU9mIiwiRGF0ZSIsImlzTnVtYmVyIiwib2JqIiwicHJvcCIsInByb3RvdHlwZSIsImIiLCJnZXRTb3J0aW5nRnVuY3Rpb24iLCJmaWVsZFR5cGUiLCJBTExfRklFTERfVFlQRVMiLCJyZWFsIiwiaW50ZWdlciIsInRpbWVzdGFtcCIsInByZWNpc2VSb3VuZCIsIm51bSIsImRlY2ltYWxzIiwicG93Iiwicm91bmQiLCJzaWduIiwidG9GaXhlZCIsInJvdW5kVG9Gb3VyIiwiY29uY2F0IiwiZ2V0Um91bmRpbmdEZWNpbWFsRnJvbVN0ZXAiLCJzdGVwIiwiaXNOYU4iLCJhc3NlcnQiLCJzdGVwU3RyIiwidG9TdHJpbmciLCJzcGxpdEV4cG9uZW50aWFsIiwic3BsaXQiLCJjb2VmZlplcm8iLCJjb2VmZkRlY2ltYWwiLCJwYXJzZUludCIsInNwbGl0WmVybyIsIm5vcm1hbGl6ZVNsaWRlclZhbHVlIiwibWFya3MiLCJzbmFwVG9NYXJrcyIsInJvdW5kVmFsVG9TdGVwIiwiZGVjaW1hbCIsInN0ZXBzIiwicmVtYWluIiwiY2xvc2VzdCIsInJvdW5kZWQiLCJkZWZhdWx0Rm9ybWF0dGVyIiwiU3RyaW5nIiwiZmxvYXRGb3JtYXR0ZXIiLCJ1aW50OEFycmF5VG9IZXgiLCJmcm9tIiwiYnl0ZSIsInBhZFN0YXJ0Iiwiam9pbiIsIkZJRUxEX0RJU1BMQVlfRk9STUFUIiwiX2RlZmluZVByb3BlcnR5MiIsInN0cmluZyIsImRhdGUiLCJnZW9qc29uIiwiaXNQbGFpbk9iamVjdCIsIkpTT04iLCJzdHJpbmdpZnkiLCJnZW9hcnJvdyIsImZpZWxkIiwiVmVjdG9yIiwiX2ZpZWxkJG1ldGFkYXRhIiwiZW5jb2RpbmciLCJtZXRhZGF0YSIsImdlb21ldHJ5IiwicGFyc2VHZW9tZXRyeUZyb21BcnJvdyIsImVycm9yIiwiVWludDhBcnJheSIsIm9iamVjdCIsImFycmF5IiwiaDMiLCJwYXJzZUZpZWxkVmFsdWUiLCJ0eXBlIiwiZ2V0Rm9ybWF0dGVyIiwidG9vbHRpcEZvcm1hdCIsIlRPT0xUSVBfRk9STUFUUyIsImZpbmQiLCJmIiwiVE9PTFRJUF9LRVkiLCJhcHBseURlZmF1bHRGb3JtYXQiLCJhcHBseUN1c3RvbUZvcm1hdCIsImdldENvbHVtbkZvcm1hdHRlciIsImRpc3BsYXlGb3JtYXQiLCJfdHlwZW9mMiIsImFwcGx5VmFsdWVNYXAiLCJUT09MVElQX0ZPUk1BVF9UWVBFUyIsIkRFQ0lNQUwiLCJkM0Zvcm1hdCIsIkRBVEUiLCJEQVRFX1RJTUUiLCJkYXRldGltZUZvcm1hdHRlciIsIlBFUkNFTlRBR0UiLCJERUNJTUFMX0RFQ0lNQUxfRklYRURfMiIsIkJPT0xFQU4iLCJnZXRCb29sZWFuRm9ybWF0dGVyIiwiZm9ybWF0TGFyZ2VOdW1iZXIiLCJmb3JtYXROdW1iZXIiLCJ0cmFuc2Zvcm1hdGlvbiIsIlkiLCJaIiwiRSIsIlAiLCJUIiwiRyIsIk0iLCJrIiwiaCIsImRhIiwiYyIsIm0iLCLOvCIsInAiLCJ6IiwieSIsInJldmVyc2VGb3JtYXROdW1iZXIiLCJzdHIiLCJyZXR1cm5WYWx1ZSIsInN0ck51bSIsInRyaW0iLCJyZXBsYWNlIiwiZW50cmllcyIsImluY2x1ZGVzIiwicGFyc2VGbG9hdCIsInRpbWV6b25lIiwidHMiLCJ0eiJdLCJzb3VyY2VzIjpbIi4uL3NyYy9kYXRhLXV0aWxzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVRcbi8vIENvcHlyaWdodCBjb250cmlidXRvcnMgdG8gdGhlIGtlcGxlci5nbCBwcm9qZWN0XG5cbmltcG9ydCAqIGFzIGFycm93IGZyb20gJ2FwYWNoZS1hcnJvdyc7XG5pbXBvcnQgYXNzZXJ0IGZyb20gJ2Fzc2VydCc7XG5pbXBvcnQge2Zvcm1hdCBhcyBkM0Zvcm1hdH0gZnJvbSAnZDMtZm9ybWF0JztcbmltcG9ydCBtb21lbnQgZnJvbSAnbW9tZW50LXRpbWV6b25lJztcblxuaW1wb3J0IHtwYXJzZUdlb21ldHJ5RnJvbUFycm93fSBmcm9tICdAbG9hZGVycy5nbC9hcnJvdyc7XG5cbmltcG9ydCB7XG4gIEFMTF9GSUVMRF9UWVBFUyxcbiAgVE9PTFRJUF9GT1JNQVRTLFxuICBUT09MVElQX0ZPUk1BVF9UWVBFUyxcbiAgVE9PTFRJUF9LRVksXG4gIFRvb2x0aXBGb3JtYXRcbn0gZnJvbSAnQGtlcGxlci5nbC9jb25zdGFudHMnO1xuaW1wb3J0IHtub3ROdWxsb3JVbmRlZmluZWR9IGZyb20gJ0BrZXBsZXIuZ2wvY29tbW9uLXV0aWxzJztcbmltcG9ydCB7RmllbGQsIE1pbGxpc2Vjb25kLCBQcm90b0RhdGFzZXRGaWVsZH0gZnJvbSAnQGtlcGxlci5nbC90eXBlcyc7XG5cbmltcG9ydCB7c25hcFRvTWFya3N9IGZyb20gJy4vcGxvdCc7XG5pbXBvcnQge2lzUGxhaW5PYmplY3R9IGZyb20gJy4vdXRpbHMnO1xuXG5leHBvcnQgdHlwZSBGaWVsZEZvcm1hdHRlciA9ICh2YWx1ZTogYW55LCBmaWVsZD86IFByb3RvRGF0YXNldEZpZWxkKSA9PiBzdHJpbmc7XG5cbi8vIFdlIG5lZWQgdGhyZWF0IGxhdGl0dWRlIGRpZmZlcmVudGx5IG90aGVyd2lzZSBtZXJjYXRvciBwcm9qZWN0IHZpZXcgdGhyb3dzXG4vLyBhIHByb2plY3Rpb24gbWF0cml4IGVycm9yXG4vLyBVbmNhdWdodCBFcnJvcjogUGl4ZWwgcHJvamVjdCBtYXRyaXggbm90IGludmVydGlibGVcbi8vIGF0IFdlYk1lcmNhdG9yVmlld3BvcnQxNi5WaWV3cG9ydDYgKHZpZXdwb3J0LmpzOjgxOjEzKVxuZXhwb3J0IGNvbnN0IE1BWF9MQVRJVFVERSA9IDg5Ljk7XG5leHBvcnQgY29uc3QgTUlOX0xBVElUVURFID0gLTg5Ljk7XG5leHBvcnQgY29uc3QgTUFYX0xPTkdJVFVERSA9IDE4MDtcbmV4cG9ydCBjb25zdCBNSU5fTE9OR0lUVURFID0gLTE4MDtcblxuLyoqXG4gKiBWYWxpZGF0ZXMgYSBsYXRpdHVkZSB2YWx1ZS5cbiAqIEVuc3VyZXMgdGhhdCB0aGUgbGF0aXR1ZGUgaXMgd2l0aGluIHRoZSBkZWZpbmVkIG1pbmltdW0gYW5kIG1heGltdW0gbGF0aXR1ZGUgYm91bmRzLlxuICogSWYgdGhlIHZhbHVlIGlzIG91dCBvZiBib3VuZHMsIGl0IHJldHVybnMgdGhlIG5lYXJlc3QgYm91bmQgdmFsdWUuXG4gKiBAcGFyYW0gbGF0aXR1ZGUgLSBUaGUgbGF0aXR1ZGUgdmFsdWUgdG8gdmFsaWRhdGUuXG4gKiBAcmV0dXJucyBUaGUgdmFsaWRhdGVkIGxhdGl0dWRlIHZhbHVlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVMYXRpdHVkZShsYXRpdHVkZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogbnVtYmVyIHtcbiAgcmV0dXJuIHZhbGlkYXRlQ29vcmRpbmF0ZShsYXRpdHVkZSA/PyAwLCBNSU5fTEFUSVRVREUsIE1BWF9MQVRJVFVERSk7XG59XG5cbi8qKlxuICogVmFsaWRhdGVzIGEgbG9uZ2l0dWRlIHZhbHVlLlxuICogRW5zdXJlcyB0aGF0IHRoZSBsb25naXR1ZGUgaXMgd2l0aGluIHRoZSBkZWZpbmVkIG1pbmltdW0gYW5kIG1heGltdW0gbG9uZ2l0dWRlIGJvdW5kcy5cbiAqIElmIHRoZSB2YWx1ZSBpcyBvdXQgb2YgYm91bmRzLCBpdCByZXR1cm5zIHRoZSBuZWFyZXN0IGJvdW5kIHZhbHVlLlxuICogQHBhcmFtIGxvbmdpdHVkZSAtIFRoZSBsb25naXR1ZGUgdmFsdWUgdG8gdmFsaWRhdGUuXG4gKiBAcmV0dXJucyBUaGUgdmFsaWRhdGVkIGxvbmdpdHVkZSB2YWx1ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlTG9uZ2l0dWRlKGxvbmdpdHVkZTogbnVtYmVyIHwgdW5kZWZpbmVkKTogbnVtYmVyIHtcbiAgcmV0dXJuIHZhbGlkYXRlQ29vcmRpbmF0ZShsb25naXR1ZGUgPz8gMCwgTUlOX0xPTkdJVFVERSwgTUFYX0xPTkdJVFVERSk7XG59XG5cbi8qKlxuICogVmFsaWRhdGVzIGEgY29vcmRpbmF0ZSB2YWx1ZS5cbiAqIEVuc3VyZXMgdGhhdCB0aGUgdmFsdWUgaXMgd2l0aGluIHRoZSBzcGVjaWZpZWQgbWluaW11bSBhbmQgbWF4aW11bSBib3VuZHMuXG4gKiBJZiB0aGUgdmFsdWUgaXMgb3V0IG9mIGJvdW5kcywgaXQgcmV0dXJucyB0aGUgbmVhcmVzdCBib3VuZCB2YWx1ZS5cbiAqIEBwYXJhbSB2YWx1ZSAtIFRoZSBjb29yZGluYXRlIHZhbHVlIHRvIHZhbGlkYXRlLlxuICogQHBhcmFtIG1pblZhbHVlIC0gVGhlIG1pbmltdW0gYm91bmQgZm9yIHRoZSB2YWx1ZS5cbiAqIEBwYXJhbSBtYXhWYWx1ZSAtIFRoZSBtYXhpbXVtIGJvdW5kIGZvciB0aGUgdmFsdWUuXG4gKiBAcmV0dXJucyBUaGUgdmFsaWRhdGVkIGNvb3JkaW5hdGUgdmFsdWUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZUNvb3JkaW5hdGUodmFsdWU6IG51bWJlciwgbWluVmFsdWU6IG51bWJlciwgbWF4VmFsdWU6IG51bWJlcik6IG51bWJlciB7XG4gIGlmICh2YWx1ZSA8PSBtaW5WYWx1ZSkge1xuICAgIHJldHVybiBtaW5WYWx1ZTtcbiAgfVxuICBpZiAodmFsdWUgPj0gbWF4VmFsdWUpIHtcbiAgICByZXR1cm4gbWF4VmFsdWU7XG4gIH1cblxuICByZXR1cm4gdmFsdWU7XG59XG5cbi8qKlxuICogc2ltcGxlIGdldHRpbmcgdW5pcXVlIHZhbHVlcyBvZiBhbiBhcnJheVxuICpcbiAqIEBwYXJhbSB2YWx1ZXNcbiAqIEByZXR1cm5zIHVuaXF1ZSB2YWx1ZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVuaXF1ZTxUPih2YWx1ZXM6IFRbXSkge1xuICBjb25zdCByZXN1bHRzOiBUW10gPSBbXTtcbiAgY29uc3QgdW5pcXVlU2V0ID0gbmV3IFNldCh2YWx1ZXMpO1xuICB1bmlxdWVTZXQuZm9yRWFjaCh2ID0+IHtcbiAgICBpZiAobm90TnVsbG9yVW5kZWZpbmVkKHYpKSB7XG4gICAgICByZXN1bHRzLnB1c2godik7XG4gICAgfVxuICB9KTtcbiAgcmV0dXJuIHJlc3VsdHM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRMYXRMbmdCb3VuZHMoXG4gIHBvaW50czogbnVtYmVyW11bXSxcbiAgaWR4OiBudW1iZXIsXG4gIGxpbWl0OiBbbnVtYmVyLCBudW1iZXJdXG4pOiBbbnVtYmVyLCBudW1iZXJdIHwgbnVsbCB7XG4gIGNvbnN0IGxhdHMgPSBwb2ludHNcbiAgICAubWFwKGQgPT4gTnVtYmVyKEFycmF5LmlzQXJyYXkoZCkpICYmIGRbaWR4XSlcbiAgICAuZmlsdGVyKE51bWJlci5pc0Zpbml0ZSlcbiAgICAuc29ydChudW1iZXJTb3J0KTtcblxuICBpZiAoIWxhdHMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvLyBjbGFtcCB0byBsaW1pdFxuICByZXR1cm4gW01hdGgubWF4KGxhdHNbMF0sIGxpbWl0WzBdKSwgTWF0aC5taW4obGF0c1tsYXRzLmxlbmd0aCAtIDFdLCBsaW1pdFsxXSldO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY2xhbXAoW21pbiwgbWF4XTogW251bWJlciwgbnVtYmVyXSwgdmFsID0gMCk6IG51bWJlciB7XG4gIHJldHVybiB2YWwgPD0gbWluID8gbWluIDogdmFsID49IG1heCA/IG1heCA6IHZhbDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFNhbXBsZURhdGEoZGF0YSwgc2FtcGxlU2l6ZSA9IDUwMCwgZ2V0VmFsdWUgPSBkID0+IGQpIHtcbiAgY29uc3Qgc2FtcGxlU3RlcCA9IE1hdGgubWF4KE1hdGguZmxvb3IoZGF0YS5sZW5ndGggLyBzYW1wbGVTaXplKSwgMSk7XG4gIGNvbnN0IG91dHB1dDogYW55W10gPSBbXTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgaSArPSBzYW1wbGVTdGVwKSB7XG4gICAgb3V0cHV0LnB1c2goZ2V0VmFsdWUoZGF0YVtpXSkpO1xuICB9XG5cbiAgcmV0dXJuIG91dHB1dDtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGRpZmZlcmVudCB0aW1lIGZvcm1hdCB0byB1bml4IG1pbGxpc2Vjb25kc1xuICovXG5leHBvcnQgZnVuY3Rpb24gdGltZVRvVW5peE1pbGxpKHZhbHVlOiBzdHJpbmcgfCBudW1iZXIgfCBEYXRlLCBmb3JtYXQ6IHN0cmluZyk6IE1pbGxpc2Vjb25kIHwgbnVsbCB7XG4gIGlmIChub3ROdWxsb3JVbmRlZmluZWQodmFsdWUpKSB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHJldHVybiBtb21lbnQudXRjKHZhbHVlLCBmb3JtYXQpLnZhbHVlT2YoKTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICAgIHJldHVybiBmb3JtYXQgPT09ICd4JyA/IHZhbHVlICogMTAwMCA6IHZhbHVlO1xuICAgIH1cbiAgICBpZiAodmFsdWUgaW5zdGFuY2VvZiBEYXRlKSB7XG4gICAgICByZXR1cm4gdmFsdWUudmFsdWVPZigpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cblxuLyoqXG4gKiBXaGV0aGVyIGQgaXMgYSBudW1iZXIsIHRoaXMgZmlsdGVyZWQgb3V0IE5hTiBhcyB3ZWxsXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc051bWJlcihkOiB1bmtub3duKTogZCBpcyBudW1iZXIge1xuICByZXR1cm4gTnVtYmVyLmlzRmluaXRlKGQpO1xufVxuXG4vKipcbiAqIHdoZXRoZXIgb2JqZWN0IGhhcyBwcm9wZXJ0eVxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIHllcyBvciBub1xuICovXG5leHBvcnQgZnVuY3Rpb24gaGFzT3duUHJvcGVydHk8WCBleHRlbmRzIG9iamVjdCwgWSBleHRlbmRzIFByb3BlcnR5S2V5PihcbiAgb2JqOiBYLFxuICBwcm9wOiBZXG4pOiBvYmogaXMgWCAmIFJlY29yZDxZLCB1bmtub3duPiB7XG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBwcm9wKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG51bWJlclNvcnQoYTogbnVtYmVyLCBiOiBudW1iZXIpOiBudW1iZXIge1xuICByZXR1cm4gYSAtIGI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRTb3J0aW5nRnVuY3Rpb24oZmllbGRUeXBlOiBzdHJpbmcpOiB0eXBlb2YgbnVtYmVyU29ydCB8IHVuZGVmaW5lZCB7XG4gIHN3aXRjaCAoZmllbGRUeXBlKSB7XG4gICAgY2FzZSBBTExfRklFTERfVFlQRVMucmVhbDpcbiAgICBjYXNlIEFMTF9GSUVMRF9UWVBFUy5pbnRlZ2VyOlxuICAgIGNhc2UgQUxMX0ZJRUxEX1RZUEVTLnRpbWVzdGFtcDpcbiAgICAgIHJldHVybiBudW1iZXJTb3J0O1xuICAgIGRlZmF1bHQ6XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG59XG5cbi8qKlxuICogcm91bmQgbnVtYmVyIHdpdGggZXhhY3QgbnVtYmVyIG9mIGRlY2ltYWxzXG4gKiByZXR1cm4gYXMgYSBzdHJpbmdcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByZWNpc2VSb3VuZChudW06IG51bWJlciwgZGVjaW1hbHM6IG51bWJlcik6IHN0cmluZyB7XG4gIGNvbnN0IHQgPSBNYXRoLnBvdygxMCwgZGVjaW1hbHMpO1xuICByZXR1cm4gKFxuICAgIE1hdGgucm91bmQoXG4gICAgICBudW0gKiB0ICsgKGRlY2ltYWxzID4gMCA/IDEgOiAwKSAqIChNYXRoLnNpZ24obnVtKSAqICgxMCAvIE1hdGgucG93KDEwMCwgZGVjaW1hbHMpKSlcbiAgICApIC8gdFxuICApLnRvRml4ZWQoZGVjaW1hbHMpO1xufVxuXG4vKipcbiAqIHJvdW5kIGEgZ2l2aW5nIG51bWJlciBhdCBtb3N0IDQgZGVjaW1hbCBwbGFjZXNcbiAqIGUuZy4gMTAgLT4gMTAsIDEuMTIzNDUgLT4gMS4yMzQ1LCAyLjAgLT4gMlxuICovXG5leHBvcnQgZnVuY3Rpb24gcm91bmRUb0ZvdXIobnVtOiBudW1iZXIpOiBudW1iZXIge1xuICAvLyBAdHMtZXhwZWN0LWVycm9yXG4gIHJldHVybiBOdW1iZXIoYCR7TWF0aC5yb3VuZChgJHtudW19ZSs0YCl9ZS00YCk7XG59XG4vKipcbiAqIGdldCBudW1iZXIgb2YgZGVjaW1hbHMgdG8gcm91bmQgdG8gZm9yIHNsaWRlciBmcm9tIHN0ZXBcbiAqIEBwYXJhbSBzdGVwXG4gKiBAcmV0dXJucy0gbnVtYmVyIG9mIGRlY2ltYWxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFJvdW5kaW5nRGVjaW1hbEZyb21TdGVwKHN0ZXA6IG51bWJlcik6IG51bWJlciB7XG4gIGlmIChpc05hTihzdGVwKSkge1xuICAgIGFzc2VydCgnc3RlcCBpcyBub3QgYSBudW1iZXInKTtcbiAgICBhc3NlcnQoc3RlcCk7XG4gIH1cblxuICBjb25zdCBzdGVwU3RyID0gc3RlcC50b1N0cmluZygpO1xuXG4gIC8vIGluIGNhc2UgdGhlIHN0ZXAgaXMgYSB2ZXJ5IHNtYWxsIG51bWJlciBlLmcuIDFlLTcsIHJldHVybiBkZWNpbWFsIGUuZy4gNyBkaXJlY3RseVxuICBjb25zdCBzcGxpdEV4cG9uZW50aWFsID0gc3RlcFN0ci5zcGxpdCgnZS0nKTtcbiAgaWYgKHNwbGl0RXhwb25lbnRpYWwubGVuZ3RoID09PSAyKSB7XG4gICAgY29uc3QgY29lZmZaZXJvID0gc3BsaXRFeHBvbmVudGlhbFswXS5zcGxpdCgnLicpO1xuICAgIGNvbnN0IGNvZWZmRGVjaW1hbCA9IGNvZWZmWmVyby5sZW5ndGggPT09IDEgPyAwIDogY29lZmZaZXJvWzFdLmxlbmd0aDtcbiAgICByZXR1cm4gcGFyc2VJbnQoc3BsaXRFeHBvbmVudGlhbFsxXSwgMTApICsgY29lZmZEZWNpbWFsO1xuICB9XG5cbiAgY29uc3Qgc3BsaXRaZXJvID0gc3RlcFN0ci5zcGxpdCgnLicpO1xuICBpZiAoc3BsaXRaZXJvLmxlbmd0aCA9PT0gMSkge1xuICAgIHJldHVybiAwO1xuICB9XG4gIHJldHVybiBzcGxpdFplcm9bMV0ubGVuZ3RoO1xufVxuXG4vKipcbiAqIElmIG1hcmtzIGlzIHByb3ZpZGVkLCBzbmFwIHRvIG1hcmtzLCBpZiBub3Qgbm9ybWFsaXplIHRvIHN0ZXBcbiAqIEBwYXJhbSB2YWxcbiAqIEBwYXJhbSBtaW5WYWx1ZVxuICogQHBhcmFtIHN0ZXBcbiAqIEBwYXJhbSBtYXJrc1xuICovXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplU2xpZGVyVmFsdWUoXG4gIHZhbDogbnVtYmVyLFxuICBtaW5WYWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkLFxuICBzdGVwOiBudW1iZXIsXG4gIG1hcmtzPzogbnVtYmVyW10gfCBudWxsXG4pOiBudW1iZXIge1xuICBpZiAobWFya3MgJiYgbWFya3MubGVuZ3RoKSB7XG4gICAgLy8gVXNlIGluIHNsaWRlciwgZ2l2ZW4gYSBudW1iZXIgYW5kIGFuIGFycmF5IG9mIG51bWJlcnMsIHJldHVybiB0aGUgbmVhcnMgbnVtYmVyIGZyb20gdGhlIGFycmF5XG4gICAgcmV0dXJuIHNuYXBUb01hcmtzKHZhbCwgbWFya3MpO1xuICB9XG5cbiAgcmV0dXJuIHJvdW5kVmFsVG9TdGVwKG1pblZhbHVlLCBzdGVwLCB2YWwpO1xufVxuXG4vKipcbiAqIHJvdW5kIHRoZSB2YWx1ZSB0byBzdGVwIGZvciB0aGUgc2xpZGVyXG4gKiBAcGFyYW0gbWluVmFsdWVcbiAqIEBwYXJhbSBzdGVwXG4gKiBAcGFyYW0gdmFsXG4gKiBAcmV0dXJucyAtIHJvdW5kZWQgbnVtYmVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByb3VuZFZhbFRvU3RlcChtaW5WYWx1ZTogbnVtYmVyIHwgdW5kZWZpbmVkLCBzdGVwOiBudW1iZXIsIHZhbDogbnVtYmVyKTogbnVtYmVyIHtcbiAgaWYgKCFpc051bWJlcihzdGVwKSB8fCAhaXNOdW1iZXIobWluVmFsdWUpKSB7XG4gICAgcmV0dXJuIHZhbDtcbiAgfVxuXG4gIGNvbnN0IGRlY2ltYWwgPSBnZXRSb3VuZGluZ0RlY2ltYWxGcm9tU3RlcChzdGVwKTtcbiAgY29uc3Qgc3RlcHMgPSBNYXRoLmZsb29yKCh2YWwgLSBtaW5WYWx1ZSkgLyBzdGVwKTtcbiAgbGV0IHJlbWFpbiA9IHZhbCAtIChzdGVwcyAqIHN0ZXAgKyBtaW5WYWx1ZSk7XG5cbiAgLy8gaGFzIHRvIHJvdW5kIGJlY2F1c2UgamF2YXNjcmlwdCB0dXJucyAwLjEgaW50byAwLjk5OTk5OTk5OTk5OTk5ODdcbiAgcmVtYWluID0gTnVtYmVyKHByZWNpc2VSb3VuZChyZW1haW4sIDgpKTtcblxuICBsZXQgY2xvc2VzdDogbnVtYmVyO1xuICBpZiAocmVtYWluID09PSAwKSB7XG4gICAgY2xvc2VzdCA9IHZhbDtcbiAgfSBlbHNlIGlmIChyZW1haW4gPCBzdGVwIC8gMikge1xuICAgIGNsb3Nlc3QgPSBzdGVwcyAqIHN0ZXAgKyBtaW5WYWx1ZTtcbiAgfSBlbHNlIHtcbiAgICBjbG9zZXN0ID0gKHN0ZXBzICsgMSkgKiBzdGVwICsgbWluVmFsdWU7XG4gIH1cblxuICAvLyBwcmVjaXNlIHJvdW5kIHJldHVybiBhIHN0cmluZyByb3VuZGVkIHRvIHRoZSBkZWZpbmVkIGRlY2ltYWxcbiAgY29uc3Qgcm91bmRlZCA9IHByZWNpc2VSb3VuZChjbG9zZXN0LCBkZWNpbWFsKTtcblxuICByZXR1cm4gTnVtYmVyKHJvdW5kZWQpO1xufVxuXG4vKipcbiAqIEdldCB0aGUgdmFsdWUgZm9ybWF0IGJhc2VkIG9uIGZpZWxkIGFuZCBmb3JtYXQgb3B0aW9uc1xuICogVXNlZCBpbiByZW5kZXIgdG9vbHRpcCB2YWx1ZVxuICovXG5leHBvcnQgY29uc3QgZGVmYXVsdEZvcm1hdHRlcjogRmllbGRGb3JtYXR0ZXIgPSB2ID0+IChub3ROdWxsb3JVbmRlZmluZWQodikgPyBTdHJpbmcodikgOiAnJyk7XG5cbmV4cG9ydCBjb25zdCBmbG9hdEZvcm1hdHRlciA9IHYgPT4gKGlzTnVtYmVyKHYpID8gU3RyaW5nKHJvdW5kVG9Gb3VyKHYpKSA6ICcnKTtcblxuLyoqXG4gKiBUcmFuc2Zvcm1zIGEgV0tCIGluIFVpbnQ4QXJyYXkgZm9ybSBpbnRvIGEgaGV4IFdLQiBzdHJpbmcuXG4gKiBAcGFyYW0gdWludDhBcnJheSBXS0IgaW4gVWludDhBcnJheSBmb3JtLlxuICogQHJldHVybnMgaGV4IFdLQiBzdHJpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1aW50OEFycmF5VG9IZXgoZGF0YTogVWludDhBcnJheSk6IHN0cmluZyB7XG4gIHJldHVybiBBcnJheS5mcm9tKGRhdGEpXG4gICAgLm1hcChieXRlID0+IChieXRlIGFzIGFueSkudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDIsICcwJykpXG4gICAgLmpvaW4oJycpO1xufVxuXG5leHBvcnQgY29uc3QgRklFTERfRElTUExBWV9GT1JNQVQ6IHtcbiAgW2tleTogc3RyaW5nXTogRmllbGRGb3JtYXR0ZXI7XG59ID0ge1xuICBbQUxMX0ZJRUxEX1RZUEVTLnN0cmluZ106IGRlZmF1bHRGb3JtYXR0ZXIsXG4gIFtBTExfRklFTERfVFlQRVMudGltZXN0YW1wXTogZGVmYXVsdEZvcm1hdHRlcixcbiAgW0FMTF9GSUVMRF9UWVBFUy5pbnRlZ2VyXTogZGVmYXVsdEZvcm1hdHRlcixcbiAgW0FMTF9GSUVMRF9UWVBFUy5yZWFsXTogZGVmYXVsdEZvcm1hdHRlcixcbiAgW0FMTF9GSUVMRF9UWVBFUy5ib29sZWFuXTogZGVmYXVsdEZvcm1hdHRlcixcbiAgW0FMTF9GSUVMRF9UWVBFUy5kYXRlXTogZGVmYXVsdEZvcm1hdHRlcixcbiAgW0FMTF9GSUVMRF9UWVBFUy5nZW9qc29uXTogZCA9PlxuICAgIHR5cGVvZiBkID09PSAnc3RyaW5nJ1xuICAgICAgPyBkXG4gICAgICA6IGlzUGxhaW5PYmplY3QoZClcbiAgICAgID8gSlNPTi5zdHJpbmdpZnkoZClcbiAgICAgIDogQXJyYXkuaXNBcnJheShkKVxuICAgICAgPyBgWyR7U3RyaW5nKGQpfV1gXG4gICAgICA6ICcnLFxuICBbQUxMX0ZJRUxEX1RZUEVTLmdlb2Fycm93XTogKGRhdGEsIGZpZWxkKSA9PiB7XG4gICAgaWYgKGRhdGEgaW5zdGFuY2VvZiBhcnJvdy5WZWN0b3IpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IGVuY29kaW5nID0gZmllbGQ/Lm1ldGFkYXRhPy5nZXQoJ0FSUk9XOmV4dGVuc2lvbjpuYW1lJyk7XG4gICAgICAgIGlmIChlbmNvZGluZykge1xuICAgICAgICAgIGNvbnN0IGdlb21ldHJ5ID0gcGFyc2VHZW9tZXRyeUZyb21BcnJvdyhkYXRhLCBlbmNvZGluZyk7XG4gICAgICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGdlb21ldHJ5KTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgLy8gaWdub3JlIGZvciBub3dcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGRhdGEgaW5zdGFuY2VvZiBVaW50OEFycmF5KSB7XG4gICAgICByZXR1cm4gdWludDhBcnJheVRvSGV4KGRhdGEpO1xuICAgIH1cbiAgICByZXR1cm4gZGF0YTtcbiAgfSxcbiAgW0FMTF9GSUVMRF9UWVBFUy5vYmplY3RdOiAodmFsdWU6IGFueSkgPT4ge1xuICAgIHRyeSB7XG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkodmFsdWUpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBTdHJpbmcodmFsdWUpO1xuICAgIH1cbiAgfSxcbiAgW0FMTF9GSUVMRF9UWVBFUy5hcnJheV06IGQgPT4gSlNPTi5zdHJpbmdpZnkoZCksXG4gIFtBTExfRklFTERfVFlQRVMuaDNdOiBkZWZhdWx0Rm9ybWF0dGVyXG59O1xuXG4vKipcbiAqIFBhcnNlIGZpZWxkIHZhbHVlIGFuZCB0eXBlIGFuZCByZXR1cm4gYSBzdHJpbmcgcmVwcmVzZW50YXRpb25cbiAqL1xuZXhwb3J0IGNvbnN0IHBhcnNlRmllbGRWYWx1ZSA9ICh2YWx1ZTogYW55LCB0eXBlOiBzdHJpbmcsIGZpZWxkPzogRmllbGQpOiBzdHJpbmcgPT4ge1xuICBpZiAoIW5vdE51bGxvclVuZGVmaW5lZCh2YWx1ZSkpIHtcbiAgICByZXR1cm4gJyc7XG4gIH1cbiAgLy8gQmlnSW50IHZhbHVlcyBjYW5ub3QgYmUgc2VyaWFsaXplZCB3aXRoIEpTT04uc3RyaW5naWZ5KCkgZGlyZWN0bHlcbiAgLy8gV2UgbmVlZCB0byBleHBsaWNpdGx5IGNvbnZlcnQgdGhlbSB0byBzdHJpbmdzIHVzaW5nIC50b1N0cmluZygpXG4gIC8vIFNlZTogaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQmlnSW50I3VzZV93aXRoaW5fanNvblxuICBpZiAodHlwZW9mIHZhbHVlID09PSAnYmlnaW50Jykge1xuICAgIHJldHVybiB2YWx1ZS50b1N0cmluZygpO1xuICB9XG4gIHJldHVybiBGSUVMRF9ESVNQTEFZX0ZPUk1BVFt0eXBlXSA/IEZJRUxEX0RJU1BMQVlfRk9STUFUW3R5cGVdKHZhbHVlLCBmaWVsZCkgOiBTdHJpbmcodmFsdWUpO1xufTtcblxuLyoqXG4gKiBHZXQgdGhlIHZhbHVlIGZvcm1hdCBiYXNlZCBvbiBmaWVsZCBhbmQgZm9ybWF0IG9wdGlvbnNcbiAqIFVzZWQgaW4gcmVuZGVyIHRvb2x0aXAgdmFsdWVcbiAqIEBwYXJhbSBmb3JtYXRcbiAqIEBwYXJhbSBmaWVsZFxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0Rm9ybWF0dGVyKFxuICBmb3JtYXQ/OiBzdHJpbmcgfCBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IHwgbnVsbCxcbiAgZmllbGQ/OiBGaWVsZFxuKTogRmllbGRGb3JtYXR0ZXIge1xuICBpZiAoIWZvcm1hdCkge1xuICAgIHJldHVybiBkZWZhdWx0Rm9ybWF0dGVyO1xuICB9XG4gIGNvbnN0IHRvb2x0aXBGb3JtYXQgPSBPYmplY3QudmFsdWVzKFRPT0xUSVBfRk9STUFUUykuZmluZChmID0+IGZbVE9PTFRJUF9LRVldID09PSBmb3JtYXQpO1xuXG4gIGlmICh0b29sdGlwRm9ybWF0KSB7XG4gICAgcmV0dXJuIGFwcGx5RGVmYXVsdEZvcm1hdCh0b29sdGlwRm9ybWF0IGFzIFRvb2x0aXBGb3JtYXQpO1xuICB9IGVsc2UgaWYgKHR5cGVvZiBmb3JtYXQgPT09ICdzdHJpbmcnICYmIGZpZWxkKSB7XG4gICAgcmV0dXJuIGFwcGx5Q3VzdG9tRm9ybWF0KGZvcm1hdCwgZmllbGQpO1xuICB9XG5cbiAgcmV0dXJuIGRlZmF1bHRGb3JtYXR0ZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRDb2x1bW5Gb3JtYXR0ZXIoXG4gIGZpZWxkOiBQaWNrPEZpZWxkLCAndHlwZSc+ICYgUGFydGlhbDxQaWNrPEZpZWxkLCAnZm9ybWF0JyB8ICdkaXNwbGF5Rm9ybWF0Jz4+XG4pOiBGaWVsZEZvcm1hdHRlciB7XG4gIGNvbnN0IHtmb3JtYXQsIGRpc3BsYXlGb3JtYXR9ID0gZmllbGQ7XG5cbiAgaWYgKCFmb3JtYXQgJiYgIWRpc3BsYXlGb3JtYXQpIHtcbiAgICByZXR1cm4gRklFTERfRElTUExBWV9GT1JNQVRbZmllbGQudHlwZV07XG4gIH1cbiAgY29uc3QgdG9vbHRpcEZvcm1hdCA9IE9iamVjdC52YWx1ZXMoVE9PTFRJUF9GT1JNQVRTKS5maW5kKGYgPT4gZltUT09MVElQX0tFWV0gPT09IGRpc3BsYXlGb3JtYXQpO1xuXG4gIGlmICh0b29sdGlwRm9ybWF0KSB7XG4gICAgcmV0dXJuIGFwcGx5RGVmYXVsdEZvcm1hdCh0b29sdGlwRm9ybWF0KTtcbiAgfSBlbHNlIGlmICh0eXBlb2YgZGlzcGxheUZvcm1hdCA9PT0gJ3N0cmluZycgJiYgZmllbGQpIHtcbiAgICByZXR1cm4gYXBwbHlDdXN0b21Gb3JtYXQoZGlzcGxheUZvcm1hdCwgZmllbGQpO1xuICB9IGVsc2UgaWYgKHR5cGVvZiBkaXNwbGF5Rm9ybWF0ID09PSAnb2JqZWN0Jykge1xuICAgIHJldHVybiBhcHBseVZhbHVlTWFwKGRpc3BsYXlGb3JtYXQpO1xuICB9XG5cbiAgcmV0dXJuIGRlZmF1bHRGb3JtYXR0ZXI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhcHBseVZhbHVlTWFwKGZvcm1hdCkge1xuICByZXR1cm4gdiA9PiBmb3JtYXRbdl07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhcHBseURlZmF1bHRGb3JtYXQodG9vbHRpcEZvcm1hdDogVG9vbHRpcEZvcm1hdCk6ICh2OiBhbnkpID0+IHN0cmluZyB7XG4gIGlmICghdG9vbHRpcEZvcm1hdCB8fCAhdG9vbHRpcEZvcm1hdC5mb3JtYXQpIHtcbiAgICByZXR1cm4gZGVmYXVsdEZvcm1hdHRlcjtcbiAgfVxuXG4gIHN3aXRjaCAodG9vbHRpcEZvcm1hdC50eXBlKSB7XG4gICAgY2FzZSBUT09MVElQX0ZPUk1BVF9UWVBFUy5ERUNJTUFMOlxuICAgICAgcmV0dXJuIGQzRm9ybWF0KHRvb2x0aXBGb3JtYXQuZm9ybWF0KTtcbiAgICBjYXNlIFRPT0xUSVBfRk9STUFUX1RZUEVTLkRBVEU6XG4gICAgY2FzZSBUT09MVElQX0ZPUk1BVF9UWVBFUy5EQVRFX1RJTUU6XG4gICAgICByZXR1cm4gZGF0ZXRpbWVGb3JtYXR0ZXIobnVsbCkodG9vbHRpcEZvcm1hdC5mb3JtYXQpO1xuICAgIGNhc2UgVE9PTFRJUF9GT1JNQVRfVFlQRVMuUEVSQ0VOVEFHRTpcbiAgICAgIHJldHVybiB2ID0+IGAke2QzRm9ybWF0KFRPT0xUSVBfRk9STUFUUy5ERUNJTUFMX0RFQ0lNQUxfRklYRURfMi5mb3JtYXQpKHYpfSVgO1xuICAgIGNhc2UgVE9PTFRJUF9GT1JNQVRfVFlQRVMuQk9PTEVBTjpcbiAgICAgIHJldHVybiBnZXRCb29sZWFuRm9ybWF0dGVyKHRvb2x0aXBGb3JtYXQuZm9ybWF0KTtcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuIGRlZmF1bHRGb3JtYXR0ZXI7XG4gIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldEJvb2xlYW5Gb3JtYXR0ZXIoZm9ybWF0OiBzdHJpbmcpOiBGaWVsZEZvcm1hdHRlciB7XG4gIHN3aXRjaCAoZm9ybWF0KSB7XG4gICAgY2FzZSAnMDEnOlxuICAgICAgcmV0dXJuICh2OiBib29sZWFuKSA9PiAodiA/ICcxJyA6ICcwJyk7XG4gICAgY2FzZSAneW4nOlxuICAgICAgcmV0dXJuICh2OiBib29sZWFuKSA9PiAodiA/ICd5ZXMnIDogJ25vJyk7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBkZWZhdWx0Rm9ybWF0dGVyO1xuICB9XG59XG4vLyBBbGxvdyB1c2VyIHRvIHNwZWNpZnkgY3VzdG9tIHRvb2x0aXAgZm9ybWF0IHZpYSBjb25maWdcbmV4cG9ydCBmdW5jdGlvbiBhcHBseUN1c3RvbUZvcm1hdChmb3JtYXQsIGZpZWxkOiB7dHlwZT86IHN0cmluZ30pOiBGaWVsZEZvcm1hdHRlciB7XG4gIHN3aXRjaCAoZmllbGQudHlwZSkge1xuICAgIGNhc2UgQUxMX0ZJRUxEX1RZUEVTLnJlYWw6XG4gICAgY2FzZSBBTExfRklFTERfVFlQRVMuaW50ZWdlcjpcbiAgICAgIHJldHVybiBkM0Zvcm1hdChmb3JtYXQpO1xuICAgIGNhc2UgQUxMX0ZJRUxEX1RZUEVTLmRhdGU6XG4gICAgY2FzZSBBTExfRklFTERfVFlQRVMudGltZXN0YW1wOlxuICAgICAgcmV0dXJuIGRhdGV0aW1lRm9ybWF0dGVyKG51bGwpKGZvcm1hdCk7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiB2ID0+IHY7XG4gIH1cbn1cblxuZnVuY3Rpb24gZm9ybWF0TGFyZ2VOdW1iZXIobikge1xuICAvLyBTSS1wcmVmaXggd2l0aCA0IHNpZ25pZmljYW50IGRpZ2l0c1xuICByZXR1cm4gZDNGb3JtYXQoJy40fnMnKShuKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdE51bWJlcihuOiBudW1iZXIsIHR5cGU/OiBzdHJpbmcpOiBzdHJpbmcge1xuICBzd2l0Y2ggKHR5cGUpIHtcbiAgICBjYXNlIEFMTF9GSUVMRF9UWVBFUy5pbnRlZ2VyOlxuICAgICAgaWYgKG4gPCAwKSB7XG4gICAgICAgIHJldHVybiBgLSR7Zm9ybWF0TnVtYmVyKC1uLCAnaW50ZWdlcicpfWA7XG4gICAgICB9XG4gICAgICBpZiAobiA8IDEwMDApIHtcbiAgICAgICAgcmV0dXJuIGAke01hdGgucm91bmQobil9YDtcbiAgICAgIH1cbiAgICAgIGlmIChuIDwgMTAgKiAxMDAwKSB7XG4gICAgICAgIHJldHVybiBkM0Zvcm1hdCgnLCcpKE1hdGgucm91bmQobikpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGZvcm1hdExhcmdlTnVtYmVyKG4pO1xuICAgIGNhc2UgQUxMX0ZJRUxEX1RZUEVTLnJlYWw6XG4gICAgICBpZiAobiA8IDApIHtcbiAgICAgICAgcmV0dXJuIGAtJHtmb3JtYXROdW1iZXIoLW4sICdudW1iZXInKX1gO1xuICAgICAgfVxuICAgICAgaWYgKG4gPCAxMDAwKSB7XG4gICAgICAgIHJldHVybiBkM0Zvcm1hdCgnLjR+cicpKG4pO1xuICAgICAgfVxuICAgICAgaWYgKG4gPCAxMCAqIDEwMDApIHtcbiAgICAgICAgcmV0dXJuIGQzRm9ybWF0KCcsLjJ+ZicpKG4pO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGZvcm1hdExhcmdlTnVtYmVyKG4pO1xuXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBmb3JtYXROdW1iZXIobiwgJ3JlYWwnKTtcbiAgfVxufVxuXG5jb25zdCB0cmFuc2Zvcm1hdGlvbiA9IHtcbiAgWTogTWF0aC5wb3coMTAsIDI0KSxcbiAgWjogTWF0aC5wb3coMTAsIDIxKSxcbiAgRTogTWF0aC5wb3coMTAsIDE4KSxcbiAgUDogTWF0aC5wb3coMTAsIDE1KSxcbiAgVDogTWF0aC5wb3coMTAsIDEyKSxcbiAgRzogTWF0aC5wb3coMTAsIDkpLFxuICBNOiBNYXRoLnBvdygxMCwgNiksXG4gIGs6IE1hdGgucG93KDEwLCAzKSxcbiAgaDogTWF0aC5wb3coMTAsIDIpLFxuICBkYTogTWF0aC5wb3coMTAsIDEpLFxuICBkOiBNYXRoLnBvdygxMCwgLTEpLFxuICBjOiBNYXRoLnBvdygxMCwgLTIpLFxuICBtOiBNYXRoLnBvdygxMCwgLTMpLFxuICDOvDogTWF0aC5wb3coMTAsIC02KSxcbiAgbjogTWF0aC5wb3coMTAsIC05KSxcbiAgcDogTWF0aC5wb3coMTAsIC0xMiksXG4gIGY6IE1hdGgucG93KDEwLCAtMTUpLFxuICBhOiBNYXRoLnBvdygxMCwgLTE4KSxcbiAgejogTWF0aC5wb3coMTAsIC0yMSksXG4gIHk6IE1hdGgucG93KDEwLCAtMjQpXG59O1xuXG4vKipcbiAqIENvbnZlcnQgYSBmb3JtYXR0ZWQgbnVtYmVyIGZyb20gc3RyaW5nIGJhY2sgdG8gbnVtYmVyXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZXZlcnNlRm9ybWF0TnVtYmVyKHN0cjogc3RyaW5nKTogbnVtYmVyIHtcbiAgbGV0IHJldHVyblZhbHVlOiBudW1iZXIgfCBudWxsID0gbnVsbDtcbiAgY29uc3Qgc3RyTnVtID0gc3RyLnRyaW0oKS5yZXBsYWNlKC8sL2csICcnKTtcbiAgT2JqZWN0LmVudHJpZXModHJhbnNmb3JtYXRpb24pLmZvckVhY2goZCA9PiB7XG4gICAgaWYgKHN0ck51bS5pbmNsdWRlcyhkWzBdKSkge1xuICAgICAgcmV0dXJuVmFsdWUgPSBwYXJzZUZsb2F0KHN0ck51bSkgKiBkWzFdO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfSk7XG5cbiAgLy8gaWYgbm8gdHJhbnNmb3JtZXIgZm91bmQsIGNvbnZlcnQgdG8gbnViZXIgcmVnYXJkbGVzc1xuICByZXR1cm4gcmV0dXJuVmFsdWUgPT09IG51bGwgPyBOdW1iZXIoc3RyTnVtKSA6IHJldHVyblZhbHVlO1xufVxuXG4vKipcbiAqIEZvcm1hdCBlcG9jaCBtaWxsaXNlY29uZHMgd2l0aCBhIGZvcm1hdCBzdHJpbmdcbiAqIEB0eXBlIHRpbWV6b25lXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkYXRldGltZUZvcm1hdHRlcihcbiAgdGltZXpvbmU/OiBzdHJpbmcgfCBudWxsXG4pOiAoZm9ybWF0Pzogc3RyaW5nKSA9PiAodHM6IG51bWJlcikgPT4gc3RyaW5nIHtcbiAgcmV0dXJuIHRpbWV6b25lXG4gICAgPyBmb3JtYXQgPT4gdHMgPT4gbW9tZW50LnV0Yyh0cykudHoodGltZXpvbmUpLmZvcm1hdChmb3JtYXQpXG4gICAgOiAvLyByZXR1cm4gZW1wdHkgc3RyaW5nIGluc3RlYWQgb2YgJ0ludmFsaWQgZGF0ZScgaWYgdHMgaXMgdW5kZWZpbmVkL251bGxcbiAgICAgIGZvcm1hdCA9PiB0cyA9PiB0cyA/IG1vbWVudC51dGModHMpLmZvcm1hdChmb3JtYXQpIDogJyc7XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFHQSxJQUFBQSxLQUFBLEdBQUFDLHVCQUFBLENBQUFDLE9BQUE7QUFDQSxJQUFBQyxPQUFBLEdBQUFDLHNCQUFBLENBQUFGLE9BQUE7QUFDQSxJQUFBRyxTQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxlQUFBLEdBQUFGLHNCQUFBLENBQUFGLE9BQUE7QUFFQSxJQUFBSyxNQUFBLEdBQUFMLE9BQUE7QUFFQSxJQUFBTSxVQUFBLEdBQUFOLE9BQUE7QUFPQSxJQUFBTyxZQUFBLEdBQUFQLE9BQUE7QUFHQSxJQUFBUSxLQUFBLEdBQUFSLE9BQUE7QUFDQSxJQUFBUyxNQUFBLEdBQUFULE9BQUE7QUFBc0MsSUFBQVUscUJBQUEsRUFyQnRDO0FBQ0E7QUFBQSxTQUFBQyx5QkFBQUMsQ0FBQSw2QkFBQUMsT0FBQSxtQkFBQUMsQ0FBQSxPQUFBRCxPQUFBLElBQUFFLENBQUEsT0FBQUYsT0FBQSxZQUFBRix3QkFBQSxZQUFBQSx5QkFBQUMsQ0FBQSxXQUFBQSxDQUFBLEdBQUFHLENBQUEsR0FBQUQsQ0FBQSxLQUFBRixDQUFBO0FBQUEsU0FBQWIsd0JBQUFhLENBQUEsRUFBQUUsQ0FBQSxTQUFBQSxDQUFBLElBQUFGLENBQUEsSUFBQUEsQ0FBQSxDQUFBSSxVQUFBLFNBQUFKLENBQUEsZUFBQUEsQ0FBQSxnQkFBQUssUUFBQSxDQUFBTCxDQUFBLDBCQUFBQSxDQUFBLHNCQUFBQSxDQUFBLFFB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