kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
200 lines (162 loc) • 20.8 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.coordHasLength4 = coordHasLength4;
exports.containValidTime = containValidTime;
exports.isTripGeoJsonField = isTripGeoJsonField;
exports.parseTripGeoJsonTimestamp = parseTripGeoJsonTimestamp;
exports.getAnimationDomainFromTimestamps = getAnimationDomainFromTimestamps;
var _typeAnalyzer = require("type-analyzer");
var _dataUtils = require("../../utils/data-utils");
var _geojsonUtils = require("../geojson-layer/geojson-utils");
// Copyright (c) 2020 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.
/**
* Parse geojson from string
* @param {array} geojson feature object values
* @returns {boolean} whether the geometry coordinates has length of 4
*/
function coordHasLength4(samples) {
var hasLength4 = true;
for (var i = 0; i < samples.length; i += 1) {
hasLength4 = !samples[i].geometry.coordinates.find(function (c) {
return c.length < 4;
});
if (!hasLength4) {
break;
}
}
return hasLength4;
}
/**
* Check whether geojson linestring's 4th coordinate is 1) not timestamp 2) unix time stamp 3) real date time
* @param {array} data array to be tested if its elements are timestamp
* @returns {string} the type of timestamp: unix/datetime/invalid(not timestamp)
*/
function containValidTime(timestamps) {
var formattedTimeStamps = timestamps.map(function (ts) {
return {
ts: ts
};
});
var ignoredDataTypes = Object.keys(_typeAnalyzer.DATA_TYPES).filter(function (type) {
return ![_typeAnalyzer.DATA_TYPES.TIME, _typeAnalyzer.DATA_TYPES.DATETIME].includes(type);
}); // ignore all types but TIME to improve performance
var analyzedType = _typeAnalyzer.Analyzer.computeColMeta(formattedTimeStamps, [], {
ignoredDataTypes: ignoredDataTypes
})[0];
if (!analyzedType || analyzedType.category !== 'TIME') {
return false;
}
return analyzedType;
}
/**
* Check if geojson features are trip layer animatable by meeting 3 conditions
* @param {array} features array of geojson feature objects
* @returns {boolean} whether it is trip layer animatable
*/
function isTripGeoJsonField() {
var allData = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var field = arguments.length > 1 ? arguments[1] : undefined;
if (!allData.length) {
return false;
}
var getValue = function getValue(d) {
return d[field.tableFieldIndex - 1];
};
var maxCount = 10000;
var sampleRawFeatures = allData.length > maxCount ? (0, _dataUtils.getSampleData)(allData, maxCount, getValue) : allData.map(getValue);
var features = sampleRawFeatures.map(_geojsonUtils.parseGeoJsonRawFeature).filter(function (f) {
return f;
});
var featureTypes = (0, _geojsonUtils.getGeojsonFeatureTypes)(features); // condition 1: contain line string
if (!featureTypes.line) {
return false;
} // condition 2:sample line strings contain 4 coordinates
if (!coordHasLength4(features)) {
return false;
} // condition 3:the 4th coordinate of the first feature line strings is valid time
var tsHolder = features[0].geometry.coordinates.map(function (coord) {
return coord[3];
});
return Boolean(containValidTime(tsHolder));
}
/**
* Get unix timestamp from animatable geojson for deck.gl trip layer
* @param {Array<Object>} dataToFeature array of geojson feature objects, can be null
* @returns {Array<Number>} unix timestamp in milliseconds
*/
function parseTripGeoJsonTimestamp(dataToFeature) {
// Analyze type based on coordinates of the 1st lineString
// select a sample trip to analyze time format
var empty = {
dataToTimeStamp: [],
animationDomain: null
};
var sampleTrip = dataToFeature.find(function (f) {
return f && f.geometry && f.geometry.coordinates && f.geometry.coordinates.length >= 3;
}); // if no valid geometry
if (!sampleTrip) {
return empty;
}
var analyzedType = containValidTime(sampleTrip.geometry.coordinates.map(function (coord) {
return coord[3];
}));
if (!analyzedType) {
return empty;
}
var format = analyzedType.format;
var getTimeValue = function getTimeValue(coord) {
return coord && (0, _dataUtils.notNullorUndefined)(coord[3]) ? (0, _dataUtils.timeToUnixMilli)(coord[3], format) : null;
};
var dataToTimeStamp = dataToFeature.map(function (f) {
return f && f.geometry && Array.isArray(f.geometry.coordinates) ? f.geometry.coordinates.map(getTimeValue) : null;
});
var animationDomain = getAnimationDomainFromTimestamps(dataToTimeStamp);
return {
dataToTimeStamp: dataToTimeStamp,
animationDomain: animationDomain
};
}
function findMinFromSorted() {
var list = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
return list.find(_dataUtils.notNullorUndefined) || null;
}
function findMaxFromSorted() {
var list = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var i = list.length - 1;
while (i > 0) {
if ((0, _dataUtils.notNullorUndefined)(list[i])) {
return list[i];
}
i--;
}
return null;
}
function getAnimationDomainFromTimestamps() {
var dataToTimeStamp = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
return dataToTimeStamp.reduce(function (accu, tss) {
accu[0] = Math.min(accu[0], findMinFromSorted(tss));
accu[1] = Math.max(accu[1], findMaxFromSorted(tss));
return accu;
}, [Infinity, -Infinity]);
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9sYXllcnMvdHJpcC1sYXllci90cmlwLXV0aWxzLmpzIl0sIm5hbWVzIjpbImNvb3JkSGFzTGVuZ3RoNCIsInNhbXBsZXMiLCJoYXNMZW5ndGg0IiwiaSIsImxlbmd0aCIsImdlb21ldHJ5IiwiY29vcmRpbmF0ZXMiLCJmaW5kIiwiYyIsImNvbnRhaW5WYWxpZFRpbWUiLCJ0aW1lc3RhbXBzIiwiZm9ybWF0dGVkVGltZVN0YW1wcyIsIm1hcCIsInRzIiwiaWdub3JlZERhdGFUeXBlcyIsIk9iamVjdCIsImtleXMiLCJEQVRBX1RZUEVTIiwiZmlsdGVyIiwidHlwZSIsIlRJTUUiLCJEQVRFVElNRSIsImluY2x1ZGVzIiwiYW5hbHl6ZWRUeXBlIiwiQW5hbHl6ZXIiLCJjb21wdXRlQ29sTWV0YSIsImNhdGVnb3J5IiwiaXNUcmlwR2VvSnNvbkZpZWxkIiwiYWxsRGF0YSIsImZpZWxkIiwiZ2V0VmFsdWUiLCJkIiwidGFibGVGaWVsZEluZGV4IiwibWF4Q291bnQiLCJzYW1wbGVSYXdGZWF0dXJlcyIsImZlYXR1cmVzIiwicGFyc2VHZW9Kc29uUmF3RmVhdHVyZSIsImYiLCJmZWF0dXJlVHlwZXMiLCJsaW5lIiwidHNIb2xkZXIiLCJjb29yZCIsIkJvb2xlYW4iLCJwYXJzZVRyaXBHZW9Kc29uVGltZXN0YW1wIiwiZGF0YVRvRmVhdHVyZSIsImVtcHR5IiwiZGF0YVRvVGltZVN0YW1wIiwiYW5pbWF0aW9uRG9tYWluIiwic2FtcGxlVHJpcCIsImZvcm1hdCIsImdldFRpbWVWYWx1ZSIsIkFycmF5IiwiaXNBcnJheSIsImdldEFuaW1hdGlvbkRvbWFpbkZyb21UaW1lc3RhbXBzIiwiZmluZE1pbkZyb21Tb3J0ZWQiLCJsaXN0Iiwibm90TnVsbG9yVW5kZWZpbmVkIiwiZmluZE1heEZyb21Tb3J0ZWQiLCJyZWR1Y2UiLCJhY2N1IiwidHNzIiwiTWF0aCIsIm1pbiIsIm1heCIsIkluZmluaXR5Il0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQW9CQTs7QUFFQTs7QUFFQTs7QUF4QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBUUE7Ozs7O0FBS08sU0FBU0EsZUFBVCxDQUF5QkMsT0FBekIsRUFBa0M7QUFDdkMsTUFBSUMsVUFBVSxHQUFHLElBQWpCOztBQUNBLE9BQUssSUFBSUMsQ0FBQyxHQUFHLENBQWIsRUFBZ0JBLENBQUMsR0FBR0YsT0FBTyxDQUFDRyxNQUE1QixFQUFvQ0QsQ0FBQyxJQUFJLENBQXpDLEVBQTRDO0FBQzFDRCxJQUFBQSxVQUFVLEdBQUcsQ0FBQ0QsT0FBTyxDQUFDRSxDQUFELENBQVAsQ0FBV0UsUUFBWCxDQUFvQkMsV0FBcEIsQ0FBZ0NDLElBQWhDLENBQXFDLFVBQUFDLENBQUM7QUFBQSxhQUFJQSxDQUFDLENBQUNKLE1BQUYsR0FBVyxDQUFmO0FBQUEsS0FBdEMsQ0FBZDs7QUFDQSxRQUFJLENBQUNGLFVBQUwsRUFBaUI7QUFDZjtBQUNEO0FBQ0Y7O0FBQ0QsU0FBT0EsVUFBUDtBQUNEO0FBRUQ7Ozs7Ozs7QUFNTyxTQUFTTyxnQkFBVCxDQUEwQkMsVUFBMUIsRUFBc0M7QUFDM0MsTUFBTUMsbUJBQW1CLEdBQUdELFVBQVUsQ0FBQ0UsR0FBWCxDQUFlLFVBQUFDLEVBQUU7QUFBQSxXQUFLO0FBQUNBLE1BQUFBLEVBQUUsRUFBRkE7QUFBRCxLQUFMO0FBQUEsR0FBakIsQ0FBNUI7QUFDQSxNQUFNQyxnQkFBZ0IsR0FBR0MsTUFBTSxDQUFDQyxJQUFQLENBQVlDLHdCQUFaLEVBQXdCQyxNQUF4QixDQUN2QixVQUFBQyxJQUFJO0FBQUEsV0FBSSxDQUFDLENBQUNGLHlCQUFXRyxJQUFaLEVBQWtCSCx5QkFBV0ksUUFBN0IsRUFBdUNDLFFBQXZDLENBQWdESCxJQUFoRCxDQUFMO0FBQUEsR0FEbUIsQ0FBekIsQ0FGMkMsQ0FNM0M7O0FBQ0EsTUFBTUksWUFBWSxHQUFHQyx1QkFBU0MsY0FBVCxDQUF3QmQsbUJBQXhCLEVBQTZDLEVBQTdDLEVBQWlEO0FBQUNHLElBQUFBLGdCQUFnQixFQUFoQkE7QUFBRCxHQUFqRCxFQUFxRSxDQUFyRSxDQUFyQjs7QUFFQSxNQUFJLENBQUNTLFlBQUQsSUFBaUJBLFlBQVksQ0FBQ0csUUFBYixLQUEwQixNQUEvQyxFQUF1RDtBQUNyRCxXQUFPLEtBQVA7QUFDRDs7QUFDRCxTQUFPSCxZQUFQO0FBQ0Q7QUFFRDs7Ozs7OztBQUtPLFNBQVNJLGtCQUFULEdBQWlEO0FBQUEsTUFBckJDLE9BQXFCLHVFQUFYLEVBQVc7QUFBQSxNQUFQQyxLQUFPOztBQUN0RCxNQUFJLENBQUNELE9BQU8sQ0FBQ3hCLE1BQWIsRUFBcUI7QUFDbkIsV0FBTyxLQUFQO0FBQ0Q7O0FBQ0QsTUFBTTBCLFFBQVEsR0FBRyxTQUFYQSxRQUFXLENBQUFDLENBQUM7QUFBQSxXQUFJQSxDQUFDLENBQUNGLEtBQUssQ0FBQ0csZUFBTixHQUF3QixDQUF6QixDQUFMO0FBQUEsR0FBbEI7O0FBQ0EsTUFBTUMsUUFBUSxHQUFHLEtBQWpCO0FBQ0EsTUFBTUMsaUJBQWlCLEdBQ3JCTixPQUFPLENBQUN4QixNQUFSLEdBQWlCNkIsUUFBakIsR0FBNEIsOEJBQWNMLE9BQWQsRUFBdUJLLFFBQXZCLEVBQWlDSCxRQUFqQyxDQUE1QixHQUF5RUYsT0FBTyxDQUFDaEIsR0FBUixDQUFZa0IsUUFBWixDQUQzRTtBQUdBLE1BQU1LLFFBQVEsR0FBR0QsaUJBQWlCLENBQUN0QixHQUFsQixDQUFzQndCLG9DQUF0QixFQUE4Q2xCLE1BQTlDLENBQXFELFVBQUFtQixDQUFDO0FBQUEsV0FBSUEsQ0FBSjtBQUFBLEdBQXRELENBQWpCO0FBQ0EsTUFBTUMsWUFBWSxHQUFHLDBDQUF1QkgsUUFBdkIsQ0FBckIsQ0FWc0QsQ0FZdEQ7O0FBQ0EsTUFBSSxDQUFDRyxZQUFZLENBQUNDLElBQWxCLEVBQXdCO0FBQ3RCLFdBQU8sS0FBUDtBQUNELEdBZnFELENBaUJ0RDs7O0FBQ0EsTUFBSSxDQUFDdkMsZUFBZSxDQUFDbUMsUUFBRCxDQUFwQixFQUFnQztBQUM5QixXQUFPLEtBQVA7QUFDRCxHQXBCcUQsQ0FzQnREOzs7QUFDQSxNQUFNSyxRQUFRLEdBQUdMLFFBQVEsQ0FBQyxDQUFELENBQVIsQ0FBWTlCLFFBQVosQ0FBcUJDLFdBQXJCLENBQWlDTSxHQUFqQyxDQUFxQyxVQUFBNkIsS0FBSztBQUFBLFdBQUlBLEtBQUssQ0FBQyxDQUFELENBQVQ7QUFBQSxHQUExQyxDQUFqQjtBQUVBLFNBQU9DLE9BQU8sQ0FBQ2pDLGdCQUFnQixDQUFDK0IsUUFBRCxDQUFqQixDQUFkO0FBQ0Q7QUFFRDs7Ozs7OztBQUtPLFNBQVNHLHlCQUFULENBQW1DQyxhQUFuQyxFQUFrRDtBQUN2RDtBQUNBO0FBQ0EsTUFBTUMsS0FBSyxHQUFHO0FBQUNDLElBQUFBLGVBQWUsRUFBRSxFQUFsQjtBQUFzQkMsSUFBQUEsZUFBZSxFQUFFO0FBQXZDLEdBQWQ7QUFDQSxNQUFNQyxVQUFVLEdBQUdKLGFBQWEsQ0FBQ3JDLElBQWQsQ0FDakIsVUFBQThCLENBQUM7QUFBQSxXQUFJQSxDQUFDLElBQUlBLENBQUMsQ0FBQ2hDLFFBQVAsSUFBbUJnQyxDQUFDLENBQUNoQyxRQUFGLENBQVdDLFdBQTlCLElBQTZDK0IsQ0FBQyxDQUFDaEMsUUFBRixDQUFXQyxXQUFYLENBQXVCRixNQUF2QixJQUFpQyxDQUFsRjtBQUFBLEdBRGdCLENBQW5CLENBSnVELENBUXZEOztBQUNBLE1BQUksQ0FBQzRDLFVBQUwsRUFBaUI7QUFDZixXQUFPSCxLQUFQO0FBQ0Q7O0FBRUQsTUFBTXRCLFlBQVksR0FBR2QsZ0JBQWdCLENBQUN1QyxVQUFVLENBQUMzQyxRQUFYLENBQW9CQyxXQUFwQixDQUFnQ00sR0FBaEMsQ0FBb0MsVUFBQTZCLEtBQUs7QUFBQSxXQUFJQSxLQUFLLENBQUMsQ0FBRCxDQUFUO0FBQUEsR0FBekMsQ0FBRCxDQUFyQzs7QUFFQSxNQUFJLENBQUNsQixZQUFMLEVBQW1CO0FBQ2pCLFdBQU9zQixLQUFQO0FBQ0Q7O0FBakJzRCxNQW1CaERJLE1BbkJnRCxHQW1CdEMxQixZQW5Cc0MsQ0FtQmhEMEIsTUFuQmdEOztBQW9CdkQsTUFBTUMsWUFBWSxHQUFHLFNBQWZBLFlBQWUsQ0FBQVQsS0FBSztBQUFBLFdBQ3hCQSxLQUFLLElBQUksbUNBQW1CQSxLQUFLLENBQUMsQ0FBRCxDQUF4QixDQUFULEdBQXdDLGdDQUFnQkEsS0FBSyxDQUFDLENBQUQsQ0FBckIsRUFBMEJRLE1BQTFCLENBQXhDLEdBQTRFLElBRHBEO0FBQUEsR0FBMUI7O0FBR0EsTUFBTUgsZUFBZSxHQUFHRixhQUFhLENBQUNoQyxHQUFkLENBQWtCLFVBQUF5QixDQUFDO0FBQUEsV0FDekNBLENBQUMsSUFBSUEsQ0FBQyxDQUFDaEMsUUFBUCxJQUFtQjhDLEtBQUssQ0FBQ0MsT0FBTixDQUFjZixDQUFDLENBQUNoQyxRQUFGLENBQVdDLFdBQXpCLENBQW5CLEdBQ0krQixDQUFDLENBQUNoQyxRQUFGLENBQVdDLFdBQVgsQ0FBdUJNLEdBQXZCLENBQTJCc0MsWUFBM0IsQ0FESixHQUVJLElBSHFDO0FBQUEsR0FBbkIsQ0FBeEI7QUFNQSxNQUFNSCxlQUFlLEdBQUdNLGdDQUFnQyxDQUFDUCxlQUFELENBQXhEO0FBRUEsU0FBTztBQUFDQSxJQUFBQSxlQUFlLEVBQWZBLGVBQUQ7QUFBa0JDLElBQUFBLGVBQWUsRUFBZkE7QUFBbEIsR0FBUDtBQUNEOztBQUVELFNBQVNPLGlCQUFULEdBQXNDO0FBQUEsTUFBWEMsSUFBVyx1RUFBSixFQUFJO0FBQ3BDLFNBQU9BLElBQUksQ0FBQ2hELElBQUwsQ0FBVWlELDZCQUFWLEtBQWlDLElBQXhDO0FBQ0Q7O0FBRUQsU0FBU0MsaUJBQVQsR0FBc0M7QUFBQSxNQUFYRixJQUFXLHVFQUFKLEVBQUk7QUFDcEMsTUFBSXBELENBQUMsR0FBR29ELElBQUksQ0FBQ25ELE1BQUwsR0FBYyxDQUF0Qjs7QUFDQSxTQUFPRCxDQUFDLEdBQUcsQ0FBWCxFQUFjO0FBQ1osUUFBSSxtQ0FBbUJvRCxJQUFJLENBQUNwRCxDQUFELENBQXZCLENBQUosRUFBaUM7QUFDL0IsYUFBT29ELElBQUksQ0FBQ3BELENBQUQsQ0FBWDtBQUNEOztBQUNEQSxJQUFBQSxDQUFDO0FBQ0Y7O0FBQ0QsU0FBTyxJQUFQO0FBQ0Q7O0FBRU0sU0FBU2tELGdDQUFULEdBQWdFO0FBQUEsTUFBdEJQLGVBQXNCLHVFQUFKLEVBQUk7QUFDckUsU0FBT0EsZUFBZSxDQUFDWSxNQUFoQixDQUNMLFVBQUNDLElBQUQsRUFBT0MsR0FBUCxFQUFlO0FBQ2JELElBQUFBLElBQUksQ0FBQyxDQUFELENBQUosR0FBVUUsSUFBSSxDQUFDQyxHQUFMLENBQVNILElBQUksQ0FBQyxDQUFELENBQWIsRUFBa0JMLGlCQUFpQixDQUFDTSxHQUFELENBQW5DLENBQVY7QUFDQUQsSUFBQUEsSUFBSSxDQUFDLENBQUQsQ0FBSixHQUFVRSxJQUFJLENBQUNFLEdBQUwsQ0FBU0osSUFBSSxDQUFDLENBQUQsQ0FBYixFQUFrQkYsaUJBQWlCLENBQUNHLEdBQUQsQ0FBbkMsQ0FBVjtBQUNBLFdBQU9ELElBQVA7QUFDRCxHQUxJLEVBTUwsQ0FBQ0ssUUFBRCxFQUFXLENBQUNBLFFBQVosQ0FOSyxDQUFQO0FBUUQiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgKGMpIDIwMjAgVWJlciBUZWNobm9sb2dpZXMsIEluYy5cbi8vXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5XG4vLyBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0byBkZWFsXG4vLyBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXG4vLyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsXG4vLyBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuLy9cbi8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1Jcbi8vIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSXG4vLyBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gVEhFIFNPRlRXQVJFLlxuXG5pbXBvcnQge0FuYWx5emVyLCBEQVRBX1RZUEVTfSBmcm9tICd0eXBlLWFuYWx5emVyJztcblxuaW1wb3J0IHtnZXRTYW1wbGVEYXRhLCB0aW1lVG9Vbml4TWlsbGksIG5vdE51bGxvclVuZGVmaW5lZH0gZnJvbSAndXRpbHMvZGF0YS11dGlscyc7XG5cbmltcG9ydCB7cGFyc2VHZW9Kc29uUmF3RmVhdHVyZSwgZ2V0R2VvanNvbkZlYXR1cmVUeXBlc30gZnJvbSAnbGF5ZXJzL2dlb2pzb24tbGF5ZXIvZ2VvanNvbi11dGlscyc7XG5cbi8qKlxuICogUGFyc2UgZ2VvanNvbiBmcm9tIHN0cmluZ1xuICogQHBhcmFtIHthcnJheX0gZ2VvanNvbiBmZWF0dXJlIG9iamVjdCB2YWx1ZXNcbiAqIEByZXR1cm5zIHtib29sZWFufSB3aGV0aGVyIHRoZSBnZW9tZXRyeSBjb29yZGluYXRlcyBoYXMgbGVuZ3RoIG9mIDRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvb3JkSGFzTGVuZ3RoNChzYW1wbGVzKSB7XG4gIGxldCBoYXNMZW5ndGg0ID0gdHJ1ZTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBzYW1wbGVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgaGFzTGVuZ3RoNCA9ICFzYW1wbGVzW2ldLmdlb21ldHJ5LmNvb3JkaW5hdGVzLmZpbmQoYyA9PiBjLmxlbmd0aCA8IDQpO1xuICAgIGlmICghaGFzTGVuZ3RoNCkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG4gIHJldHVybiBoYXNMZW5ndGg0O1xufVxuXG4vKipcbiAqIENoZWNrIHdoZXRoZXIgZ2VvanNvbiBsaW5lc3RyaW5nJ3MgNHRoIGNvb3JkaW5hdGUgaXMgMSkgbm90IHRpbWVzdGFtcCAyKSB1bml4IHRpbWUgc3RhbXAgMykgcmVhbCBkYXRlIHRpbWVcbiAqIEBwYXJhbSB7YXJyYXl9IGRhdGEgYXJyYXkgdG8gYmUgdGVzdGVkIGlmIGl0cyBlbGVtZW50cyBhcmUgdGltZXN0YW1wXG4gKiBAcmV0dXJucyB7c3RyaW5nfSB0aGUgdHlwZSBvZiB0aW1lc3RhbXA6IHVuaXgvZGF0ZXRpbWUvaW52YWxpZChub3QgdGltZXN0YW1wKVxuICovXG5cbmV4cG9ydCBmdW5jdGlvbiBjb250YWluVmFsaWRUaW1lKHRpbWVzdGFtcHMpIHtcbiAgY29uc3QgZm9ybWF0dGVkVGltZVN0YW1wcyA9IHRpbWVzdGFtcHMubWFwKHRzID0+ICh7dHN9KSk7XG4gIGNvbnN0IGlnbm9yZWREYXRhVHlwZXMgPSBPYmplY3Qua2V5cyhEQVRBX1RZUEVTKS5maWx0ZXIoXG4gICAgdHlwZSA9PiAhW0RBVEFfVFlQRVMuVElNRSwgREFUQV9UWVBFUy5EQVRFVElNRV0uaW5jbHVkZXModHlwZSlcbiAgKTtcblxuICAvLyBpZ25vcmUgYWxsIHR5cGVzIGJ1dCBUSU1FIHRvIGltcHJvdmUgcGVyZm9ybWFuY2VcbiAgY29uc3QgYW5hbHl6ZWRUeXBlID0gQW5hbHl6ZXIuY29tcHV0ZUNvbE1ldGEoZm9ybWF0dGVkVGltZVN0YW1wcywgW10sIHtpZ25vcmVkRGF0YVR5cGVzfSlbMF07XG5cbiAgaWYgKCFhbmFseXplZFR5cGUgfHwgYW5hbHl6ZWRUeXBlLmNhdGVnb3J5ICE9PSAnVElNRScpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgcmV0dXJuIGFuYWx5emVkVHlwZTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBnZW9qc29uIGZlYXR1cmVzIGFyZSB0cmlwIGxheWVyIGFuaW1hdGFibGUgYnkgbWVldGluZyAzIGNvbmRpdGlvbnNcbiAqIEBwYXJhbSB7YXJyYXl9IGZlYXR1cmVzIGFycmF5IG9mIGdlb2pzb24gZmVhdHVyZSBvYmplY3RzXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gd2hldGhlciBpdCBpcyB0cmlwIGxheWVyIGFuaW1hdGFibGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzVHJpcEdlb0pzb25GaWVsZChhbGxEYXRhID0gW10sIGZpZWxkKSB7XG4gIGlmICghYWxsRGF0YS5sZW5ndGgpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY29uc3QgZ2V0VmFsdWUgPSBkID0+IGRbZmllbGQudGFibGVGaWVsZEluZGV4IC0gMV07XG4gIGNvbnN0IG1heENvdW50ID0gMTAwMDA7XG4gIGNvbnN0IHNhbXBsZVJhd0ZlYXR1cmVzID1cbiAgICBhbGxEYXRhLmxlbmd0aCA+IG1heENvdW50ID8gZ2V0U2FtcGxlRGF0YShhbGxEYXRhLCBtYXhDb3VudCwgZ2V0VmFsdWUpIDogYWxsRGF0YS5tYXAoZ2V0VmFsdWUpO1xuXG4gIGNvbnN0IGZlYXR1cmVzID0gc2FtcGxlUmF3RmVhdHVyZXMubWFwKHBhcnNlR2VvSnNvblJhd0ZlYXR1cmUpLmZpbHRlcihmID0+IGYpO1xuICBjb25zdCBmZWF0dXJlVHlwZXMgPSBnZXRHZW9qc29uRmVhdHVyZVR5cGVzKGZlYXR1cmVzKTtcblxuICAvLyBjb25kaXRpb24gMTogY29udGFpbiBsaW5lIHN0cmluZ1xuICBpZiAoIWZlYXR1cmVUeXBlcy5saW5lKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gY29uZGl0aW9uIDI6c2FtcGxlIGxpbmUgc3RyaW5ncyBjb250YWluIDQgY29vcmRpbmF0ZXNcbiAgaWYgKCFjb29yZEhhc0xlbmd0aDQoZmVhdHVyZXMpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gY29uZGl0aW9uIDM6dGhlIDR0aCBjb29yZGluYXRlIG9mIHRoZSBmaXJzdCBmZWF0dXJlIGxpbmUgc3RyaW5ncyBpcyB2YWxpZCB0aW1lXG4gIGNvbnN0IHRzSG9sZGVyID0gZmVhdHVyZXNbMF0uZ2VvbWV0cnkuY29vcmRpbmF0ZXMubWFwKGNvb3JkID0+IGNvb3JkWzNdKTtcblxuICByZXR1cm4gQm9vbGVhbihjb250YWluVmFsaWRUaW1lKHRzSG9sZGVyKSk7XG59XG5cbi8qKlxuICogR2V0IHVuaXggdGltZXN0YW1wIGZyb20gYW5pbWF0YWJsZSBnZW9qc29uIGZvciBkZWNrLmdsIHRyaXAgbGF5ZXJcbiAqIEBwYXJhbSB7QXJyYXk8T2JqZWN0Pn0gZGF0YVRvRmVhdHVyZSBhcnJheSBvZiBnZW9qc29uIGZlYXR1cmUgb2JqZWN0cywgY2FuIGJlIG51bGxcbiAqIEByZXR1cm5zIHtBcnJheTxOdW1iZXI+fSB1bml4IHRpbWVzdGFtcCBpbiBtaWxsaXNlY29uZHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlVHJpcEdlb0pzb25UaW1lc3RhbXAoZGF0YVRvRmVhdHVyZSkge1xuICAvLyBBbmFseXplIHR5cGUgYmFzZWQgb24gY29vcmRpbmF0ZXMgb2YgdGhlIDFzdCBsaW5lU3RyaW5nXG4gIC8vIHNlbGVjdCBhIHNhbXBsZSB0cmlwIHRvIGFuYWx5emUgdGltZSBmb3JtYXRcbiAgY29uc3QgZW1wdHkgPSB7ZGF0YVRvVGltZVN0YW1wOiBbXSwgYW5pbWF0aW9uRG9tYWluOiBudWxsfTtcbiAgY29uc3Qgc2FtcGxlVHJpcCA9IGRhdGFUb0ZlYXR1cmUuZmluZChcbiAgICBmID0+IGYgJiYgZi5nZW9tZXRyeSAmJiBmLmdlb21ldHJ5LmNvb3JkaW5hdGVzICYmIGYuZ2VvbWV0cnkuY29vcmRpbmF0ZXMubGVuZ3RoID49IDNcbiAgKTtcblxuICAvLyBpZiBubyB2YWxpZCBnZW9tZXRyeVxuICBpZiAoIXNhbXBsZVRyaXApIHtcbiAgICByZXR1cm4gZW1wdHk7XG4gIH1cblxuICBjb25zdCBhbmFseXplZFR5cGUgPSBjb250YWluVmFsaWRUaW1lKHNhbXBsZVRyaXAuZ2VvbWV0cnkuY29vcmRpbmF0ZXMubWFwKGNvb3JkID0+IGNvb3JkWzNdKSk7XG5cbiAgaWYgKCFhbmFseXplZFR5cGUpIHtcbiAgICByZXR1cm4gZW1wdHk7XG4gIH1cblxuICBjb25zdCB7Zm9ybWF0fSA9IGFuYWx5emVkVHlwZTtcbiAgY29uc3QgZ2V0VGltZVZhbHVlID0gY29vcmQgPT5cbiAgICBjb29yZCAmJiBub3ROdWxsb3JVbmRlZmluZWQoY29vcmRbM10pID8gdGltZVRvVW5peE1pbGxpKGNvb3JkWzNdLCBmb3JtYXQpIDogbnVsbDtcblxuICBjb25zdCBkYXRhVG9UaW1lU3RhbXAgPSBkYXRhVG9GZWF0dXJlLm1hcChmID0+XG4gICAgZiAmJiBmLmdlb21ldHJ5ICYmIEFycmF5LmlzQXJyYXkoZi5nZW9tZXRyeS5jb29yZGluYXRlcylcbiAgICAgID8gZi5nZW9tZXRyeS5jb29yZGluYXRlcy5tYXAoZ2V0VGltZVZhbHVlKVxuICAgICAgOiBudWxsXG4gICk7XG5cbiAgY29uc3QgYW5pbWF0aW9uRG9tYWluID0gZ2V0QW5pbWF0aW9uRG9tYWluRnJvbVRpbWVzdGFtcHMoZGF0YVRvVGltZVN0YW1wKTtcblxuICByZXR1cm4ge2RhdGFUb1RpbWVTdGFtcCwgYW5pbWF0aW9uRG9tYWlufTtcbn1cblxuZnVuY3Rpb24gZmluZE1pbkZyb21Tb3J0ZWQobGlzdCA9IFtdKSB7XG4gIHJldHVybiBsaXN0LmZpbmQobm90TnVsbG9yVW5kZWZpbmVkKSB8fCBudWxsO1xufVxuXG5mdW5jdGlvbiBmaW5kTWF4RnJvbVNvcnRlZChsaXN0ID0gW10pIHtcbiAgbGV0IGkgPSBsaXN0Lmxlbmd0aCAtIDE7XG4gIHdoaWxlIChpID4gMCkge1xuICAgIGlmIChub3ROdWxsb3JVbmRlZmluZWQobGlzdFtpXSkpIHtcbiAgICAgIHJldHVybiBsaXN0W2ldO1xuICAgIH1cbiAgICBpLS07XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRBbmltYXRpb25Eb21haW5Gcm9tVGltZXN0YW1wcyhkYXRhVG9UaW1lU3RhbXAgPSBbXSkge1xuICByZXR1cm4gZGF0YVRvVGltZVN0YW1wLnJlZHVjZShcbiAgICAoYWNjdSwgdHNzKSA9PiB7XG4gICAgICBhY2N1WzBdID0gTWF0aC5taW4oYWNjdVswXSwgZmluZE1pbkZyb21Tb3J0ZWQodHNzKSk7XG4gICAgICBhY2N1WzFdID0gTWF0aC5tYXgoYWNjdVsxXSwgZmluZE1heEZyb21Tb3J0ZWQodHNzKSk7XG4gICAgICByZXR1cm4gYWNjdTtcbiAgICB9LFxuICAgIFtJbmZpbml0eSwgLUluZmluaXR5XVxuICApO1xufVxuIl19
;