kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
223 lines (190 loc) • 22.2 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.unique = unique;
exports.findMapBounds = findMapBounds;
exports.getLatLngBounds = getLatLngBounds;
exports.getSampleData = getSampleData;
exports.maybeToDate = maybeToDate;
exports.notNullorUndefined = notNullorUndefined;
exports.isPlainObject = isPlainObject;
exports.numberSort = numberSort;
exports.getSortingFunction = getSortingFunction;
exports.preciseRound = preciseRound;
exports.getRoundingDecimalFromStep = getRoundingDecimalFromStep;
exports.roundValToStep = roundValToStep;
var _moment = require('moment');
var _moment2 = _interopRequireDefault(_moment);
var _assert = require('assert');
var _assert2 = _interopRequireDefault(_assert);
var _defaultSettings = require('../constants/default-settings');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var MAX_LATITUDE = 90; // Copyright (c) 2018 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
var MIN_LATITUDE = -90;
var MAX_LONGITUDE = 180;
var MIN_LONGITUDE = -180;
/**
* simple getting unique values of an array
*
* @param {array} values
* @returns {array} unique values
*/
function unique(values) {
var results = [];
values.forEach(function (v) {
if (!results.includes(v) && v !== null && v !== undefined) {
results.push(v);
}
});
return results;
}
/* eslint-disable max-statements */
/**
* return center of map from given points
* @param {array} layers
* @param {string} dataId
* @returns {object} coordinates of map center, empty if not found
*/
function findMapBounds(layers) {
// find bounds in formatted layerData
// take ALL layers into account when finding map bounds
var availableLayerBounds = layers.reduce(function (res, l) {
if (l.meta && l.meta.bounds) {
res.push(l.meta.bounds);
}
return res;
}, []);
// return null if no layer is available
if (availableLayerBounds.length === 0) {
return null;
}
// merge bounds in each layer
var newBounds = availableLayerBounds.reduce(function (res, b) {
return [Math.min(res[0], b[0]), Math.min(res[1], b[1]), Math.max(res[2], b[2]), Math.max(res[3], b[3])];
}, [MAX_LONGITUDE, MAX_LATITUDE, MIN_LONGITUDE, MIN_LATITUDE]);
return newBounds;
}
/* eslint-enable max-statements */
function getLatLngBounds(points, idx, limit) {
var lats = points.map(function (d) {
return Array.isArray(d) && d[idx];
}).filter(Number.isFinite).sort(numberSort);
if (!lats.length) {
return null;
}
// use 99 percentile to filter out outliers
// clamp to limit
return [Math.max(lats[Math.floor(0.01 * (lats.length - 1))], limit[0]), Math.min(lats[Math.ceil(0.99 * (lats.length - 1))], limit[1])];
}
function getSampleData(data) {
var sampleSize = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 500;
var sampleStep = Math.max(Math.floor(data.length / sampleSize), 1);
var output = [];
for (var i = 0; i < data.length; i += sampleStep) {
output.push(data[i]);
}
return output;
}
function maybeToDate(isTime, fieldIdx, format, d) {
if (isTime) {
if (notNullorUndefined(d[fieldIdx])) {
return typeof d[fieldIdx] === 'string' ? _moment2.default.utc(d[fieldIdx], format).valueOf() : format === 'x' ? d[fieldIdx] * 1000 : d[fieldIdx];
}
return null;
}
return d[fieldIdx];
}
function notNullorUndefined(d) {
return d !== undefined && d !== null;
}
function isPlainObject(obj) {
return obj === Object(obj) && typeof obj !== 'function' && !Array.isArray(obj);
}
function numberSort(a, b) {
return a - b;
}
function getSortingFunction(fieldType) {
switch (fieldType) {
case _defaultSettings.ALL_FIELD_TYPES.real:
case _defaultSettings.ALL_FIELD_TYPES.integer:
case _defaultSettings.ALL_FIELD_TYPES.timestamp:
return numberSort;
default:
return undefined;
}
}
/**
* round number with exact number of decimals
* return as a string
* @param {number} num
* @param {number} decimals
* @returns {string} - a rounded number in string format
*/
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);
}
/**
* get number of decimals to round to for slider from step
* @param {number} step
* @returns {number} - number of decimal
*/
function getRoundingDecimalFromStep(step) {
if (isNaN(step)) {
(0, _assert2.default)('step is not a number');
(0, _assert2.default)(step);
}
var splitZero = step.toString().split('.');
if (splitZero.length === 1) {
return 0;
}
return splitZero[1].length;
}
/**
* round the value to step for the slider
* @param {number} minValue
* @param {number} step
* @param {number} val
* @returns {number} - rounded number
*/
function roundValToStep(minValue, step, val) {
if (isNaN(step)) {
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 = void 0;
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);
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9kYXRhLXV0aWxzLmpzIl0sIm5hbWVzIjpbInVuaXF1ZSIsImZpbmRNYXBCb3VuZHMiLCJnZXRMYXRMbmdCb3VuZHMiLCJnZXRTYW1wbGVEYXRhIiwibWF5YmVUb0RhdGUiLCJub3ROdWxsb3JVbmRlZmluZWQiLCJpc1BsYWluT2JqZWN0IiwibnVtYmVyU29ydCIsImdldFNvcnRpbmdGdW5jdGlvbiIsInByZWNpc2VSb3VuZCIsImdldFJvdW5kaW5nRGVjaW1hbEZyb21TdGVwIiwicm91bmRWYWxUb1N0ZXAiLCJNQVhfTEFUSVRVREUiLCJNSU5fTEFUSVRVREUiLCJNQVhfTE9OR0lUVURFIiwiTUlOX0xPTkdJVFVERSIsInZhbHVlcyIsInJlc3VsdHMiLCJmb3JFYWNoIiwiaW5jbHVkZXMiLCJ2IiwidW5kZWZpbmVkIiwicHVzaCIsImxheWVycyIsImF2YWlsYWJsZUxheWVyQm91bmRzIiwicmVkdWNlIiwicmVzIiwibCIsIm1ldGEiLCJib3VuZHMiLCJsZW5ndGgiLCJuZXdCb3VuZHMiLCJiIiwiTWF0aCIsIm1pbiIsIm1heCIsInBvaW50cyIsImlkeCIsImxpbWl0IiwibGF0cyIsIm1hcCIsIkFycmF5IiwiaXNBcnJheSIsImQiLCJmaWx0ZXIiLCJOdW1iZXIiLCJpc0Zpbml0ZSIsInNvcnQiLCJmbG9vciIsImNlaWwiLCJkYXRhIiwic2FtcGxlU2l6ZSIsInNhbXBsZVN0ZXAiLCJvdXRwdXQiLCJpIiwiaXNUaW1lIiwiZmllbGRJZHgiLCJmb3JtYXQiLCJtb21lbnQiLCJ1dGMiLCJ2YWx1ZU9mIiwib2JqIiwiT2JqZWN0IiwiYSIsImZpZWxkVHlwZSIsIkFMTF9GSUVMRF9UWVBFUyIsInJlYWwiLCJpbnRlZ2VyIiwidGltZXN0YW1wIiwibnVtIiwiZGVjaW1hbHMiLCJ0IiwicG93Iiwicm91bmQiLCJzaWduIiwidG9GaXhlZCIsInN0ZXAiLCJpc05hTiIsInNwbGl0WmVybyIsInRvU3RyaW5nIiwic3BsaXQiLCJtaW5WYWx1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LEdBQXFCSyxRQUEvQjtBQUNEOztBQUVEO0FBQ0EsTUFBTU0sVUFBVTlFLGFBQWE2RSxPQUFiLEVBQXNCSCxPQUF0QixDQUFoQjs7QUFFQSxTQUFPdEMsT0FBTzBDLE9BQVAsQ0FBUDtBQUNEIiwiZmlsZSI6ImRhdGEtdXRpbHMuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgKGMpIDIwMTggVWJlciBUZWNobm9sb2dpZXMsIEluYy5cbi8vXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5XG4vLyBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0byBkZWFsXG4vLyBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXG4vLyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsXG4vLyBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuLy9cbi8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1Jcbi8vIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSXG4vLyBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gVEhFIFNPRlRXQVJFLlxuXG5pbXBvcnQgbW9tZW50IGZyb20gJ21vbWVudCc7XG5pbXBvcnQgYXNzZXJ0IGZyb20gJ2Fzc2VydCc7XG5pbXBvcnQge0FMTF9GSUVMRF9UWVBFU30gZnJvbSAnY29uc3RhbnRzL2RlZmF1bHQtc2V0dGluZ3MnO1xuXG5jb25zdCBNQVhfTEFUSVRVREUgPSA5MDtcbmNvbnN0IE1JTl9MQVRJVFVERSA9IC05MDtcbmNvbnN0IE1BWF9MT05HSVRVREUgPSAxODA7XG5jb25zdCBNSU5fTE9OR0lUVURFID0gLTE4MDtcblxuLyoqXG4gKiBzaW1wbGUgZ2V0dGluZyB1bmlxdWUgdmFsdWVzIG9mIGFuIGFycmF5XG4gKlxuICogQHBhcmFtIHthcnJheX0gdmFsdWVzXG4gKiBAcmV0dXJucyB7YXJyYXl9IHVuaXF1ZSB2YWx1ZXNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVuaXF1ZSh2YWx1ZXMpIHtcbiAgY29uc3QgcmVzdWx0cyA9IFtdO1xuICB2YWx1ZXMuZm9yRWFjaCh2ID0+IHtcbiAgICBpZiAoIXJlc3VsdHMuaW5jbHVkZXModikgJiYgdiAhPT0gbnVsbCAmJiB2ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIHJlc3VsdHMucHVzaCh2KTtcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiByZXN1bHRzO1xufVxuXG4vKiBlc2xpbnQtZGlzYWJsZSBtYXgtc3RhdGVtZW50cyAqL1xuLyoqXG4gKiByZXR1cm4gY2VudGVyIG9mIG1hcCBmcm9tIGdpdmVuIHBvaW50c1xuICogQHBhcmFtIHthcnJheX0gbGF5ZXJzXG4gKiBAcGFyYW0ge3N0cmluZ30gZGF0YUlkXG4gKiBAcmV0dXJucyB7b2JqZWN0fSBjb29yZGluYXRlcyBvZiBtYXAgY2VudGVyLCBlbXB0eSBpZiBub3QgZm91bmRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZpbmRNYXBCb3VuZHMobGF5ZXJzKSB7XG4gIC8vIGZpbmQgYm91bmRzIGluIGZvcm1hdHRlZCBsYXllckRhdGFcbiAgLy8gdGFrZSBBTEwgbGF5ZXJzIGludG8gYWNjb3VudCB3aGVuIGZpbmRpbmcgbWFwIGJvdW5kc1xuICBjb25zdCBhdmFpbGFibGVMYXllckJvdW5kcyA9IGxheWVycy5yZWR1Y2UoKHJlcywgbCkgPT4ge1xuICAgIGlmIChsLm1ldGEgJiYgbC5tZXRhLmJvdW5kcykge1xuICAgICAgcmVzLnB1c2gobC5tZXRhLmJvdW5kcyk7XG4gICAgfVxuICAgIHJldHVybiByZXM7XG4gIH0sIFtdKVxuICAvLyByZXR1cm4gbnVsbCBpZiBubyBsYXllciBpcyBhdmFpbGFibGVcbiAgaWYgKGF2YWlsYWJsZUxheWVyQm91bmRzLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG4gIC8vIG1lcmdlIGJvdW5kcyBpbiBlYWNoIGxheWVyXG4gIGNvbnN0IG5ld0JvdW5kcyA9IGF2YWlsYWJsZUxheWVyQm91bmRzLnJlZHVjZSgocmVzLCBiKSA9PiB7XG4gICAgcmV0dXJuIFtcbiAgICAgIE1hdGgubWluKHJlc1swXSwgYlswXSksXG4gICAgICBNYXRoLm1pbihyZXNbMV0sIGJbMV0pLFxuICAgICAgTWF0aC5tYXgocmVzWzJdLCBiWzJdKSxcbiAgICAgIE1hdGgubWF4KHJlc1szXSwgYlszXSlcbiAgICBdO1xuICB9LCBbTUFYX0xPTkdJVFVERSwgTUFYX0xBVElUVURFLCBNSU5fTE9OR0lUVURFLCBNSU5fTEFUSVRVREVdKTtcbiAgcmV0dXJuIG5ld0JvdW5kcztcbn1cbi8qIGVzbGludC1lbmFibGUgbWF4LXN0YXRlbWVudHMgKi9cblxuZXhwb3J0IGZ1bmN0aW9uIGdldExhdExuZ0JvdW5kcyhwb2ludHMsIGlkeCwgbGltaXQpIHtcbiAgY29uc3QgbGF0cyA9IHBvaW50c1xuICAgIC5tYXAoZCA9PiBBcnJheS5pc0FycmF5KGQpICYmIGRbaWR4XSlcbiAgICAuZmlsdGVyKE51bWJlci5pc0Zpbml0ZSlcbiAgICAuc29ydChudW1iZXJTb3J0KTtcblxuICBpZiAoIWxhdHMubGVuZ3RoKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cbiAgLy8gdXNlIDk5IHBlcmNlbnRpbGUgdG8gZmlsdGVyIG91dCBvdXRsaWVyc1xuICAvLyBjbGFtcCB0byBsaW1pdFxuICByZXR1cm4gW1xuICAgIE1hdGgubWF4KGxhdHNbTWF0aC5mbG9vcigwLjAxICogKGxhdHMubGVuZ3RoIC0gMSkpXSwgbGltaXRbMF0pLFxuICAgIE1hdGgubWluKGxhdHNbTWF0aC5jZWlsKDAuOTkgKiAobGF0cy5sZW5ndGggLSAxKSldLCBsaW1pdFsxXSlcbiAgXTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFNhbXBsZURhdGEoZGF0YSwgc2FtcGxlU2l6ZSA9IDUwMCkge1xuICBjb25zdCBzYW1wbGVTdGVwID0gTWF0aC5tYXgoTWF0aC5mbG9vcihkYXRhLmxlbmd0aCAvIHNhbXBsZVNpemUpLCAxKTtcbiAgY29uc3Qgb3V0cHV0ID0gW107XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgZGF0YS5sZW5ndGg7IGkgKz0gc2FtcGxlU3RlcCkge1xuICAgIG91dHB1dC5wdXNoKGRhdGFbaV0pO1xuICB9XG5cbiAgcmV0dXJuIG91dHB1dDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG1heWJlVG9EYXRlKGlzVGltZSwgZmllbGRJZHgsIGZvcm1hdCwgZCkge1xuICBpZiAoaXNUaW1lKSB7XG4gICAgaWYgKG5vdE51bGxvclVuZGVmaW5lZChkW2ZpZWxkSWR4XSkpIHtcbiAgICAgIHJldHVybiB0eXBlb2YgZFtmaWVsZElkeF0gPT09ICdzdHJpbmcnXG4gICAgICAgID8gbW9tZW50LnV0YyhkW2ZpZWxkSWR4XSwgZm9ybWF0KS52YWx1ZU9mKClcbiAgICAgICAgOiBmb3JtYXQgPT09ICd4JyA/IGRbZmllbGRJZHhdICogMTAwMCA6IGRbZmllbGRJZHhdO1xuICAgIH1cblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgcmV0dXJuIGRbZmllbGRJZHhdO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbm90TnVsbG9yVW5kZWZpbmVkKGQpIHtcbiAgcmV0dXJuIGQgIT09IHVuZGVmaW5lZCAmJiBkICE9PSBudWxsO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaXNQbGFpbk9iamVjdChvYmopIHtcbiAgcmV0dXJuIChcbiAgICBvYmogPT09IE9iamVjdChvYmopICYmIHR5cGVvZiBvYmogIT09ICdmdW5jdGlvbicgJiYgIUFycmF5LmlzQXJyYXkob2JqKVxuICApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gbnVtYmVyU29ydChhLCBiKSB7XG4gIHJldHVybiBhIC0gYjtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFNvcnRpbmdGdW5jdGlvbihmaWVsZFR5cGUpIHtcbiAgc3dpdGNoIChmaWVsZFR5cGUpIHtcbiAgICBjYXNlIEFMTF9GSUVMRF9UWVBFUy5yZWFsOlxuICAgIGNhc2UgQUxMX0ZJRUxEX1RZUEVTLmludGVnZXI6XG4gICAgY2FzZSBBTExfRklFTERfVFlQRVMudGltZXN0YW1wOlxuICAgICAgcmV0dXJuIG51bWJlclNvcnQ7XG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbn1cblxuLyoqXG4gKiByb3VuZCBudW1iZXIgd2l0aCBleGFjdCBudW1iZXIgb2YgZGVjaW1hbHNcbiAqIHJldHVybiBhcyBhIHN0cmluZ1xuICogQHBhcmFtIHtudW1iZXJ9IG51bVxuICogQHBhcmFtIHtudW1iZXJ9IGRlY2ltYWxzXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIGEgcm91bmRlZCBudW1iZXIgaW4gc3RyaW5nIGZvcm1hdFxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJlY2lzZVJvdW5kKG51bSwgZGVjaW1hbHMpIHtcbiAgY29uc3QgdCA9IE1hdGgucG93KDEwLCBkZWNpbWFscyk7XG4gIHJldHVybiAoXG4gICAgTWF0aC5yb3VuZChcbiAgICAgIG51bSAqIHQgK1xuICAgICAgICAoZGVjaW1hbHMgPiAwID8gMSA6IDApICpcbiAgICAgICAgICAoTWF0aC5zaWduKG51bSkgKiAoMTAgLyBNYXRoLnBvdygxMDAsIGRlY2ltYWxzKSkpXG4gICAgKSAvIHRcbiAgKS50b0ZpeGVkKGRlY2ltYWxzKTtcbn1cblxuLyoqXG4gKiBnZXQgbnVtYmVyIG9mIGRlY2ltYWxzIHRvIHJvdW5kIHRvIGZvciBzbGlkZXIgZnJvbSBzdGVwXG4gKiBAcGFyYW0ge251bWJlcn0gc3RlcFxuICogQHJldHVybnMge251bWJlcn0gLSBudW1iZXIgb2YgZGVjaW1hbFxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0Um91bmRpbmdEZWNpbWFsRnJvbVN0ZXAoc3RlcCkge1xuICBpZiAoaXNOYU4oc3RlcCkpIHtcbiAgICBhc3NlcnQoJ3N0ZXAgaXMgbm90IGEgbnVtYmVyJyk7XG4gICAgYXNzZXJ0KHN0ZXApO1xuICB9XG5cbiAgY29uc3Qgc3BsaXRaZXJvID0gc3RlcC50b1N0cmluZygpLnNwbGl0KCcuJyk7XG4gIGlmIChzcGxpdFplcm8ubGVuZ3RoID09PSAxKSB7XG4gICAgcmV0dXJuIDA7XG4gIH1cbiAgcmV0dXJuIHNwbGl0WmVyb1sxXS5sZW5ndGg7XG59XG5cbi8qKlxuICogcm91bmQgdGhlIHZhbHVlIHRvIHN0ZXAgZm9yIHRoZSBzbGlkZXJcbiAqIEBwYXJhbSB7bnVtYmVyfSBtaW5WYWx1ZVxuICogQHBhcmFtIHtudW1iZXJ9IHN0ZXBcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWxcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gcm91bmRlZCBudW1iZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJvdW5kVmFsVG9TdGVwKG1pblZhbHVlLCBzdGVwLCB2YWwpIHtcbiAgaWYgKGlzTmFOKHN0ZXApKSB7XG4gICAgcmV0dXJuIHZhbDtcbiAgfVxuXG4gIGNvbnN0IGRlY2ltYWwgPSBnZXRSb3VuZGluZ0RlY2ltYWxGcm9tU3RlcChzdGVwKTtcbiAgY29uc3Qgc3RlcHMgPSBNYXRoLmZsb29yKCh2YWwgLSBtaW5WYWx1ZSkgLyBzdGVwKTtcbiAgbGV0IHJlbWFpbiA9IHZhbCAtIChzdGVwcyAqIHN0ZXAgKyBtaW5WYWx1ZSk7XG5cbiAgLy8gaGFzIHRvIHJvdW5kIGJlY2F1c2UgamF2YXNjcmlwdCB0dXJucyAwLjEgaW50byAwLjk5OTk5OTk5OTk5OTk5ODdcbiAgcmVtYWluID0gTnVtYmVyKHByZWNpc2VSb3VuZChyZW1haW4sIDgpKTtcblxuICBsZXQgY2xvc2VzdDtcbiAgaWYgKHJlbWFpbiA9PT0gMCkge1xuICAgIGNsb3Nlc3QgPSB2YWw7XG4gIH0gZWxzZSBpZiAocmVtYWluIDwgc3RlcCAvIDIpIHtcbiAgICBjbG9zZXN0ID0gc3RlcHMgKiBzdGVwICsgbWluVmFsdWU7XG4gIH0gZWxzZSB7XG4gICAgY2xvc2VzdCA9IChzdGVwcyArIDEpICogc3RlcCArIG1pblZhbHVlO1xuICB9XG5cbiAgLy8gcHJlY2lzZSByb3VuZCByZXR1cm4gYSBzdHJpbmcgcm91bmRlZCB0byB0aGUgZGVmaW5lZCBkZWNpbWFsXG4gIGNvbnN0IHJvdW5kZWQgPSBwcmVjaXNlUm91bmQoY2xvc2VzdCwgZGVjaW1hbCk7XG5cbiAgcmV0dXJuIE51bWJlcihyb3VuZGVkKTtcbn1cbiJdfQ==
;