UNPKG

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
"use strict"; 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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9sYXllcnMvdHJpcC1sYXllci90cmlwLXV0aWxzLmpzIl0sIm5hbWVzIjpbImNvb3JkSGFzTGVuZ3RoNCIsInNhbXBsZXMiLCJoYXNMZW5ndGg0IiwiaSIsImxlbmd0aCIsImdlb21ldHJ5IiwiY29vcmRpbmF0ZXMiLCJmaW5kIiwiYyIsImNvbnRhaW5WYWxpZFRpbWUiLCJ0aW1lc3RhbXBzIiwiZm9ybWF0dGVkVGltZVN0YW1wcyIsIm1hcCIsInRzIiwiaWdub3JlZERhdGFUeXBlcyIsIk9iamVjdCIsImtleXMiLCJEQVRBX1RZUEVTIiwiZmlsdGVyIiwidHlwZSIsIlRJTUUiLCJEQVRFVElNRSIsImluY2x1ZGVzIiwiYW5hbHl6ZWRUeXBlIiwiQW5hbHl6ZXIiLCJjb21wdXRlQ29sTWV0YSIsImNhdGVnb3J5IiwiaXNUcmlwR2VvSnNvbkZpZWxkIiwiYWxsRGF0YSIsImZpZWxkIiwiZ2V0VmFsdWUiLCJkIiwidGFibGVGaWVsZEluZGV4IiwibWF4Q291bnQiLCJzYW1wbGVSYXdGZWF0dXJlcyIsImZlYXR1cmVzIiwicGFyc2VHZW9Kc29uUmF3RmVhdHVyZSIsImYiLCJmZWF0dXJlVHlwZXMiLCJsaW5lIiwidHNIb2xkZXIiLCJjb29yZCIsIkJvb2xlYW4iLCJwYXJzZVRyaXBHZW9Kc29uVGltZXN0YW1wIiwiZGF0YVRvRmVhdHVyZSIsImVtcHR5IiwiZGF0YVRvVGltZVN0YW1wIiwiYW5pbWF0aW9uRG9tYWluIiwic2FtcGxlVHJpcCIsImZvcm1hdCIsImdldFRpbWVWYWx1ZSIsIkFycmF5IiwiaXNBcnJheSIsImdldEFuaW1hdGlvbkRvbWFpbkZyb21UaW1lc3RhbXBzIiwiZmluZE1pbkZyb21Tb3J0ZWQiLCJsaXN0Iiwibm90TnVsbG9yVW5kZWZpbmVkIiwiZmluZE1heEZyb21Tb3J0ZWQiLCJyZWR1Y2UiLCJhY2N1IiwidHNzIiwiTWF0aCIsIm1pbiIsIm1heCIsIkluZmluaXR5Il0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztB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T29ELElBQUksQ0FBQ3BELENBQUQsQ0FBWDtBQUNEOztBQUNEQSxJQUFBQSxDQUFDO0FBQ0Y7O0FBQ0QsU0FBTyxJQUFQO0FBQ0Q7O0FBRU0sU0FBU2tELGdDQUFULEdBQWdFO0FBQUEsTUFBdEJQLGVBQXNCLHVFQUFKLEVBQUk7QUFDckUsU0FBT0EsZUFBZSxDQUFDWSxNQUFoQixDQUNMLFVBQUNDLElBQUQsRUFBT0MsR0FBUCxFQUFlO0FBQ2JELElBQUFBLElBQUksQ0FBQyxDQUFELENBQUosR0FBVUUsSUFBSSxDQUFDQyxHQUFMLENBQVNILElBQUksQ0FBQyxDQUFELENBQWIsRUFBa0JMLGlCQUFpQixDQUFDTSxHQUFELENBQW5DLENBQVY7QUFDQUQsSUFBQUEsSUFBSSxDQUFDLENBQUQsQ0FBSixHQUFVRSxJQUFJLENBQUNFLEdBQUwsQ0FBU0osSUFBSSxDQUFDLENBQUQsQ0FBYixFQUFrQkYsaUJBQWlCLENBQUNHLEdBQUQsQ0FBbkMsQ0FBVjtBQUNBLFdBQU9ELElBQVA7QUFDRCxHQUxJLEVBTUwsQ0FBQ0ssUUFBRCxFQUFXLENBQUNBLFFBQVosQ0FOSyxDQUFQO0FBUUQiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgKGMpIDIwMjAgVWJlciBUZWNobm9sb2dpZXMsIEluYy5cbi8vXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5XG4vLyBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0byBkZWFsXG4vLyBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXG4vLyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsXG4vLyBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuLy9cbi8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1Jcbi8vIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSXG4vLyBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gVEhFIFNPRlRXQVJFLlxuXG5pbXBvcnQge0FuYWx5emVyLCBEQVRBX1RZUEVTfSBmcm9tICd0eXBlLWFuYWx5emVyJztcblxuaW1wb3J0IHtnZXRTYW1wbGVEYXRhLCB0aW1lVG9Vbml4TWlsbGksIG5vdE51bGxvclVuZGVmaW5lZH0gZnJvbSAndXRpbHMvZGF0YS11dGlscyc7XG5cbmltcG9ydCB7cGFyc2VHZW9Kc29uUmF3RmVhdHVyZSwgZ2V0R2VvanNvbkZlYXR1cmVUeXBlc30gZnJvbSAnbGF5ZXJzL2dlb2pzb24tbGF5ZXIvZ2VvanNvbi11dGlscyc7XG5cbi8qKlxuICogUGFyc2UgZ2VvanNvbiBmcm9tIHN0cmluZ1xuICogQHBhcmFtIHthcnJheX0gZ2VvanNvbiBmZWF0dXJlIG9iamVjdCB2YWx1ZXNcbiAqIEByZXR1cm5zIHtib29sZWFufSB3aGV0aGVyIHRoZSBnZW9tZXRyeSBjb29yZGluYXRlcyBoYXMgbGVuZ3RoIG9mIDRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvb3JkSGFzTGVuZ3RoNChzYW1wbGVzKSB7XG4gIGxldCBoYXNMZW5ndGg0ID0gdHJ1ZTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBzYW1wbGVzLmxlbmd0aDsgaSArPSAxKSB7XG4gICAgaGFzTGVuZ3RoNCA9ICFzYW1wbGVzW2ldLmdlb21ldHJ5LmNvb3JkaW5hdGVzLmZpbmQoYyA9PiBjLmxlbmd0aCA8IDQpO1xuICAgIGlmICghaGFzTGVuZ3RoNCkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG4gIHJldHVybiBoYXNMZW5ndGg0O1xufVxuXG4vKipcbiAqIENoZWNrIHdoZXRoZXIgZ2VvanNvbiBsaW5lc3RyaW5nJ3MgNHRoIGNvb3JkaW5hdGUgaXMgMSkgbm90IHRpbWVzdGFtcCAyKSB1bml4IHRpbWUgc3RhbXAgMykgcmVhbCBkYXRlIHRpbWVcbiAqIEBwYXJhbSB7YXJyYXl9IGRhdGEgYXJyYXkgdG8gYmUgdGVzdGVkIGlmIGl0cyBlbGVtZW50cyBhcmUgdGltZXN0YW1wXG4gKiBAcmV0dXJucyB7c3RyaW5nfSB0aGUgdHlwZSBvZiB0aW1lc3RhbXA6IHVuaXgvZGF0ZXRpbWUvaW52YWxpZChub3QgdGltZXN0YW1wKVxuICovXG5cbmV4cG9ydCBmdW5jdGlvbiBjb250YWluVmFsaWRUaW1lKHRpbWVzdGFtcHMpIHtcbiAgY29uc3QgZm9ybWF0dGVkVGltZVN0YW1wcyA9IHRpbWVzdGFtcHMubWFwKHRzID0+ICh7dHN9KSk7XG4gIGNvbnN0IGlnbm9yZWREYXRhVHlwZXMgPSBPYmplY3Qua2V5cyhEQVRBX1RZUEVTKS5maWx0ZXIoXG4gICAgdHlwZSA9PiAhW0RBVEFfVFlQRVMuVElNRSwgREFUQV9UWVBFUy5EQVRFVElNRV0uaW5jbHVkZXModHlwZSlcbiAgKTtcblxuICAvLyBpZ25vcmUgYWxsIHR5cGVzIGJ1dCBUSU1FIHRvIGltcHJvdmUgcGVyZm9ybWFuY2VcbiAgY29uc3QgYW5hbHl6ZWRUeXBlID0gQW5hbHl6ZXIuY29tcHV0ZUNvbE1ldGEoZm9ybWF0dGVkVGltZVN0YW1wcywgW10sIHtpZ25vcmVkRGF0YVR5cGVzfSlbMF07XG5cbiAgaWYgKCFhbmFseXplZFR5cGUgfHwgYW5hbHl6ZWRUeXBlLmNhdGVnb3J5ICE9PSAnVElNRScpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgcmV0dXJuIGFuYWx5emVkVHlwZTtcbn1cblxuLyoqXG4gKiBDaGVjayBpZiBnZW9qc29uIGZlYXR1cmVzIGFyZSB0cmlwIGxheWVyIGFuaW1hdGFibGUgYnkgbWVldGluZyAzIGNvbmRpdGlvbnNcbiAqIEBwYXJhbSB7YXJyYXl9IGZlYXR1cmVzIGFycmF5IG9mIGdlb2pzb24gZmVhdHVyZSBvYmplY3RzXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gd2hldGhlciBpdCBpcyB0cmlwIGxheWVyIGFuaW1hdGFibGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzVHJpcEdlb0pzb25GaWVsZChhbGxEYXRhID0gW10sIGZpZWxkKSB7XG4gIGlmICghYWxsRGF0YS5sZW5ndGgpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbiAgY29uc3QgZ2V0VmFsdWUgPSBkID0+IGRbZmllbGQudGFibGVGaWVsZEluZGV4IC0gMV07XG4gIGNvbnN0IG1heENvdW50ID0gMTAwMDA7XG4gIGNvbnN0IHNhbXBsZVJhd0ZlYXR1cmVzID1cbiAgICBhbGxEYXRhLmxlbmd0aCA+IG1heENvdW50ID8gZ2V0U2FtcGxlRGF0YShhbGxEYXRhLCBtYXhDb3VudCwgZ2V0VmFsdWUpIDogYWxsRGF0YS5tYXAoZ2V0VmFsdWUpO1xuXG4gIGNvbnN0IGZlYXR1cmVzID0gc2FtcGxlUmF3RmVhdHVyZXMubWFwKHBhcnNlR2VvSnNvblJhd0ZlYXR1cmUpLmZpbHRlcihmID0+IGYpO1xuICBjb25zdCBmZWF0dXJlVHlwZXMgPSBnZXRHZW9qc29uRmVhdHVyZVR5cGVzKGZlYXR1cmVzKTtcblxuICAvLyBjb25kaXRpb24gMTogY29udGFpbiBsaW5lIHN0cmluZ1xuICBpZiAoIWZlYXR1cmVUeXBlcy5saW5lKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gY29uZGl0aW9uIDI6c2FtcGxlIGxpbmUgc3RyaW5ncyBjb250YWluIDQgY29vcmRpbmF0ZXNcbiAgaWYgKCFjb29yZEhhc0xlbmd0aDQoZmVhdHVyZXMpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gY29uZGl0aW9uIDM6dGhlIDR0aCBjb29yZGluYXRlIG9mIHRoZSBmaXJzdCBmZWF0dXJlIGxpbmUgc3RyaW5ncyBpcyB2YWxpZCB0aW1lXG4gIGNvbnN0IHRzSG9sZGVyID0gZmVhdHVyZXNbMF0uZ2VvbWV0cnkuY29vcmRpbmF0ZXMubWFwKGNvb3JkID0+IGNvb3JkWzNdKTtcblxuICByZXR1cm4gQm9vbGVhbihjb250YWluVmFsaWRUaW1lKHRzSG9sZGVyKSk7XG59XG5cbi8qKlxuICogR2V0IHVuaXggdGltZXN0YW1wIGZyb20gYW5pbWF0YWJsZSBnZW9qc29uIGZvciBkZWNrLmdsIHRyaXAgbGF5ZXJcbiAqIEBwYXJhbSB7QXJyYXk8T2JqZWN0Pn0gZGF0YVRvRmVhdHVyZSBhcnJheSBvZiBnZW9qc29uIGZlYXR1cmUgb2JqZWN0cywgY2FuIGJlIG51bGxcbiAqIEByZXR1cm5zIHtBcnJheTxOdW1iZXI+fSB1bml4IHRpbWVzdGFtcCBpbiBtaWxsaXNlY29uZHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlVHJpcEdlb0pzb25UaW1lc3RhbXAoZGF0YVRvRmVhdHVyZSkge1xuICAvLyBBbmFseXplIHR5cGUgYmFzZWQgb24gY29vcmRpbmF0ZXMgb2YgdGhlIDFzdCBsaW5lU3RyaW5nXG4gIC8vIHNlbGVjdCBhIHNhbXBsZSB0cmlwIHRvIGFuYWx5emUgdGltZSBmb3JtYXRcbiAgY29uc3QgZW1wdHkgPSB7ZGF0YVRvVGltZVN0YW1wOiBbXSwgYW5pbWF0aW9uRG9tYWluOiBudWxsfTtcbiAgY29uc3Qgc2FtcGxlVHJpcCA9IGRhdGFUb0ZlYXR1cmUuZmluZChcbiAgICBmID0+IGYgJiYgZi5nZW9tZXRyeSAmJiBmLmdlb21ldHJ5LmNvb3JkaW5hdGVzICYmIGYuZ2VvbWV0cnkuY29vcmRpbmF0ZXMubGVuZ3RoID49IDNcbiAgKTtcblxuICAvLyBpZiBubyB2YWxpZCBnZW9tZXRyeVxuICBpZiAoIXNhbXBsZVRyaXApIHtcbiAgICByZXR1cm4gZW1wdHk7XG4gIH1cblxuICBjb25zdCBhbmFseXplZFR5cGUgPSBjb250YWluVmFsaWRUaW1lKHNhbXBsZVRyaXAuZ2VvbWV0cnkuY29vcmRpbmF0ZXMubWFwKGNvb3JkID0+IGNvb3JkWzNdKSk7XG5cbiAgaWYgKCFhbmFseXplZFR5cGUpIHtcbiAgICByZXR1cm4gZW1wdHk7XG4gIH1cblxuICBjb25zdCB7Zm9ybWF0fSA9IGFuYWx5emVkVHlwZTtcbiAgY29uc3QgZ2V0VGltZVZhbHVlID0gY29vcmQgPT5cbiAgICBjb29yZCAmJiBub3ROdWxsb3JVbmRlZmluZWQoY29vcmRbM10pID8gdGltZVRvVW5peE1pbGxpKGNvb3JkWzNdLCBmb3JtYXQpIDogbnVsbDtcblxuICBjb25zdCBkYXRhVG9UaW1lU3RhbXAgPSBkYXRhVG9GZWF0dXJlLm1hcChmID0+XG4gICAgZiAmJiBmLmdlb21ldHJ5ICYmIEFycmF5LmlzQXJyYXkoZi5nZW9tZXRyeS5jb29yZGluYXRlcylcbiAgICAgID8gZi5nZW9tZXRyeS5jb29yZGluYXRlcy5tYXAoZ2V0VGltZVZhbHVlKVxuICAgICAgOiBudWxsXG4gICk7XG5cbiAgY29uc3QgYW5pbWF0aW9uRG9tYWluID0gZ2V0QW5pbWF0aW9uRG9tYWluRnJvbVRpbWVzdGFtcHMoZGF0YVRvVGltZVN0YW1wKTtcblxuICByZXR1cm4ge2RhdGFUb1RpbWVTdGFtcCwgYW5pbWF0aW9uRG9tYWlufTtcbn1cblxuZnVuY3Rpb24gZmluZE1pbkZyb21Tb3J0ZWQobGlzdCA9IFtdKSB7XG4gIHJldHVybiBsaXN0LmZpbmQobm90TnVsbG9yVW5kZWZpbmVkKSB8fCBudWxsO1xufVxuXG5mdW5jdGlvbiBmaW5kTWF4RnJvbVNvcnRlZChsaXN0ID0gW10pIHtcbiAgbGV0IGkgPSBsaXN0Lmxlbmd0aCAtIDE7XG4gIHdoaWxlIChpID4gMCkge1xuICAgIGlmIChub3ROdWxsb3JVbmRlZmluZWQobGlzdFtpXSkpIHtcbiAgICAgIHJldHVybiBsaXN0W2ldO1xuICAgIH1cbiAgICBpLS07XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRBbmltYXRpb25Eb21haW5Gcm9tVGltZXN0YW1wcyhkYXRhVG9UaW1lU3RhbXAgPSBbXSkge1xuICByZXR1cm4gZGF0YVRvVGltZVN0YW1wLnJlZHVjZShcbiAgICAoYWNjdSwgdHNzKSA9PiB7XG4gICAgICBhY2N1WzBdID0gTWF0aC5taW4oYWNjdVswXSwgZmluZE1pbkZyb21Tb3J0ZWQodHNzKSk7XG4gICAgICBhY2N1WzFdID0gTWF0aC5tYXgoYWNjdVsxXSwgZmluZE1heEZyb21Tb3J0ZWQodHNzKSk7XG4gICAgICByZXR1cm4gYWNjdTtcbiAgICB9LFxuICAgIFtJbmZpbml0eSwgLUluZmluaXR5XVxuICApO1xufVxuIl19