UNPKG

kepler.gl

Version:

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

302 lines (288 loc) 33.9 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ACCEPTED_ANALYZER_TYPES = void 0; exports.analyzerTypeToFieldType = analyzerTypeToFieldType; exports.getFieldsFromData = getFieldsFromData; exports.getSampleForTypeAnalyze = getSampleForTypeAnalyze; exports.getSampleForTypeAnalyzeArrow = getSampleForTypeAnalyzeArrow; exports.renameDuplicateFields = renameDuplicateFields; var _typeAnalyzer = require("type-analyzer"); var _constants = require("@kepler.gl/constants"); var _window = require("global/window"); var _d3Array = require("d3-array"); var _data = require("./data"); var _h3Utils = require("./h3-utils"); // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project var H3_ANALYZER_TYPE = 'H3'; var ACCEPTED_ANALYZER_TYPES = exports.ACCEPTED_ANALYZER_TYPES = [_typeAnalyzer.DATA_TYPES.DATE, _typeAnalyzer.DATA_TYPES.TIME, _typeAnalyzer.DATA_TYPES.DATETIME, _typeAnalyzer.DATA_TYPES.NUMBER, _typeAnalyzer.DATA_TYPES.INT, _typeAnalyzer.DATA_TYPES.FLOAT, _typeAnalyzer.DATA_TYPES.BOOLEAN, _typeAnalyzer.DATA_TYPES.STRING, _typeAnalyzer.DATA_TYPES.GEOMETRY, _typeAnalyzer.DATA_TYPES.GEOMETRY_FROM_STRING, _typeAnalyzer.DATA_TYPES.PAIR_GEOMETRY_FROM_STRING, _typeAnalyzer.DATA_TYPES.ZIPCODE, _typeAnalyzer.DATA_TYPES.ARRAY, _typeAnalyzer.DATA_TYPES.OBJECT, H3_ANALYZER_TYPE]; var IGNORE_DATA_TYPES = Object.keys(_typeAnalyzer.DATA_TYPES).filter(function (type) { return !ACCEPTED_ANALYZER_TYPES.includes(type); }); /** * Getting sample data for analyzing field type. */ function getSampleForTypeAnalyze(_ref) { var fields = _ref.fields, rows = _ref.rows, _ref$sampleCount = _ref.sampleCount, sampleCount = _ref$sampleCount === void 0 ? 50 : _ref$sampleCount; var total = Math.min(sampleCount, rows.length); // const fieldOrder = fields.map(f => f.name); var sample = (0, _d3Array.range)(0, total, 1).map(function () { return {}; }); if (rows.length < 1) { return []; } var isRowObject = !Array.isArray(rows[0]); // collect sample data for each field fields.forEach(function (field, fieldIdx) { // row counter var i = 0; // sample counter var j = 0; while (j < total) { if (i >= rows.length) { // if depleted data pool sample[j][field] = null; j++; } else if ((0, _data.notNullorUndefined)(rows[i][isRowObject ? field : fieldIdx])) { var value = rows[i][isRowObject ? field : fieldIdx]; sample[j][field] = typeof value === 'string' ? value.trim() : value; j++; i++; } else { i++; } } }); return sample; } /** * Getting sample data for analyzing field type for Arrow tables. * @param table Arrow table or an array of vectors. * @param fields Field names. * @param sampleCount Number of sample rows to get. * @returns Sample rows. */ function getSampleForTypeAnalyzeArrow(table, fields) { var sampleCount = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 50; var isTable = !Array.isArray(table); var numRows = isTable ? table.numRows : table[0].length; var getVector = isTable ? function (index) { return table.getChildAt(index); } : function (index) { return table[index]; }; var total = Math.min(sampleCount, numRows); var sample = (0, _d3Array.range)(0, total, 1).map(function () { return {}; }); if (numRows < 1) { return []; } // collect sample data for each field fields.forEach(function (field, fieldIdx) { var rowIndex = 0; var sampleIndex = 0; while (sampleIndex < total) { var _getVector; if (rowIndex >= numRows) { // if depleted data pool sample[sampleIndex][field] = null; sampleIndex++; } else if ((0, _data.notNullorUndefined)((_getVector = getVector(fieldIdx)) === null || _getVector === void 0 ? void 0 : _getVector.get(rowIndex))) { var _getVector2; var value = (_getVector2 = getVector(fieldIdx)) === null || _getVector2 === void 0 ? void 0 : _getVector2.get(rowIndex); sample[sampleIndex][field] = typeof value === 'string' ? value.trim() : value; sampleIndex++; rowIndex++; } else { rowIndex++; } } }); return sample; } /** * Convert type-analyzer output to kepler.gl field types * * @param aType * @returns corresponding type in `ALL_FIELD_TYPES` */ /* eslint-disable complexity */ function analyzerTypeToFieldType(aType) { var DATE = _typeAnalyzer.DATA_TYPES.DATE, TIME = _typeAnalyzer.DATA_TYPES.TIME, DATETIME = _typeAnalyzer.DATA_TYPES.DATETIME, NUMBER = _typeAnalyzer.DATA_TYPES.NUMBER, INT = _typeAnalyzer.DATA_TYPES.INT, FLOAT = _typeAnalyzer.DATA_TYPES.FLOAT, BOOLEAN = _typeAnalyzer.DATA_TYPES.BOOLEAN, STRING = _typeAnalyzer.DATA_TYPES.STRING, GEOMETRY = _typeAnalyzer.DATA_TYPES.GEOMETRY, GEOMETRY_FROM_STRING = _typeAnalyzer.DATA_TYPES.GEOMETRY_FROM_STRING, PAIR_GEOMETRY_FROM_STRING = _typeAnalyzer.DATA_TYPES.PAIR_GEOMETRY_FROM_STRING, ZIPCODE = _typeAnalyzer.DATA_TYPES.ZIPCODE, ARRAY = _typeAnalyzer.DATA_TYPES.ARRAY, OBJECT = _typeAnalyzer.DATA_TYPES.OBJECT; // TODO: un recognized types // CURRENCY PERCENT NONE switch (aType) { case DATE: return _constants.ALL_FIELD_TYPES.date; case TIME: case DATETIME: return _constants.ALL_FIELD_TYPES.timestamp; case FLOAT: return _constants.ALL_FIELD_TYPES.real; case INT: return _constants.ALL_FIELD_TYPES.integer; case BOOLEAN: return _constants.ALL_FIELD_TYPES["boolean"]; case GEOMETRY: case GEOMETRY_FROM_STRING: case PAIR_GEOMETRY_FROM_STRING: return _constants.ALL_FIELD_TYPES.geojson; case ARRAY: return _constants.ALL_FIELD_TYPES.array; case OBJECT: return _constants.ALL_FIELD_TYPES.object; case NUMBER: case STRING: case ZIPCODE: return _constants.ALL_FIELD_TYPES.string; case H3_ANALYZER_TYPE: return _constants.ALL_FIELD_TYPES.h3; default: _window.console.warn("Unsupported analyzer type: ".concat(aType)); return _constants.ALL_FIELD_TYPES.string; } } /** * Analyze field types from data in `string` format, e.g. uploaded csv. * Assign `type`, `fieldIdx` and `format` (timestamp only) to each field * * @param data array of row object * @param fieldOrder array of field names as string * @returns formatted fields * @public * @example * * import {getFieldsFromData} from 'kepler.gl/common-utils'; * const data = [{ * time: '2016-09-17 00:09:55', * value: '4', * surge: '1.2', * isTrip: 'true', * zeroOnes: '0' * }, { * time: '2016-09-17 00:30:08', * value: '3', * surge: null, * isTrip: 'false', * zeroOnes: '1' * }, { * time: null, * value: '2', * surge: '1.3', * isTrip: null, * zeroOnes: '1' * }]; * * const fieldOrder = ['time', 'value', 'surge', 'isTrip', 'zeroOnes']; * const fields = getFieldsFromData(data, fieldOrder); * // fields = [ * // {name: 'time', format: 'YYYY-M-D H:m:s', fieldIdx: 1, type: 'timestamp'}, * // {name: 'value', format: '', fieldIdx: 4, type: 'integer'}, * // {name: 'surge', format: '', fieldIdx: 5, type: 'real'}, * // {name: 'isTrip', format: '', fieldIdx: 6, type: 'boolean'}, * // {name: 'zeroOnes', format: '', fieldIdx: 7, type: 'integer'}]; * */ function getFieldsFromData(data, fieldOrder) { // add a check for epoch timestamp var metadata = _typeAnalyzer.Analyzer.computeColMeta(data, [{ regex: /.*geojson|all_points/g, dataType: 'GEOMETRY' }, { regex: /.*census/g, dataType: 'STRING' }], { ignoredDataTypes: IGNORE_DATA_TYPES }); var _renameDuplicateField = renameDuplicateFields(fieldOrder), fieldByIndex = _renameDuplicateField.fieldByIndex; var result = fieldOrder.map(function (field, index) { var name = fieldByIndex[index]; var fieldMeta = metadata.find(function (m) { return m.key === field; }); // fieldMeta could be undefined if the field has no data and Analyzer.computeColMeta // will ignore the field. In this case, we will simply assign the field type to STRING // since dropping the column in the RowData could be expensive var type = (fieldMeta === null || fieldMeta === void 0 ? void 0 : fieldMeta.type) || 'STRING'; var format = (fieldMeta === null || fieldMeta === void 0 ? void 0 : fieldMeta.format) || ''; // quick check if first valid string in column is H3 if (type === _typeAnalyzer.DATA_TYPES.STRING) { for (var i = 0, n = data.length; i < n; ++i) { if ((0, _data.notNullorUndefined)(data[i][name])) { type = (0, _h3Utils.h3IsValid)(data[i][name] || '') ? H3_ANALYZER_TYPE : type; break; } } } // quick check if string is hex wkb if (type === _typeAnalyzer.DATA_TYPES.STRING) { type = data.some(function (d) { return (0, _data.isHexWkb)(d[name]); }) ? _typeAnalyzer.DATA_TYPES.GEOMETRY : type; } return { name: name, id: name, displayName: name, format: format, fieldIdx: index, type: analyzerTypeToFieldType(type), analyzerType: type, valueAccessor: function valueAccessor(dc) { return function (d) { return dc.valueAt(d.index, index); }; } }; }); return result; } /** * pass in an array of field names, rename duplicated one * and return a map from old field index to new name * * @param fieldOrder * @returns new field name by index */ function renameDuplicateFields(fieldOrder) { return fieldOrder.reduce(function (accu, field, i) { var allNames = accu.allNames; var fieldName = field; // add a counter to duplicated names if (allNames.includes(field)) { var counter = 0; while (allNames.includes("".concat(field, "-").concat(counter))) { counter++; } fieldName = "".concat(field, "-").concat(counter); } accu.fieldByIndex[i] = fieldName; accu.allNames.push(fieldName); return accu; }, { allNames: [], fieldByIndex: [] }); } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfdHlwZUFuYWx5emVyIiwicmVxdWlyZSIsIl9jb25zdGFudHMiLCJfd2luZG93IiwiX2QzQXJyYXkiLCJfZGF0YSIsIl9oM1V0aWxzIiwiSDNfQU5BTFlaRVJfVFlQRSIsIkFDQ0VQVEVEX0FOQUxZWkVSX1RZUEVTIiwiZXhwb3J0cyIsIkFuYWx5emVyREFUQV9UWVBFUyIsIkRBVEUiLCJUSU1FIiwiREFURVRJTUUiLCJOVU1CRVIiLCJJTlQiLCJGTE9BVCIsIkJPT0xFQU4iLCJTVFJJTkciLCJHRU9NRVRSWSIsIkdFT01FVFJZX0ZST01fU1RSSU5HIiwiUEFJUl9HRU9NRVRSWV9GUk9NX1NUUklORyIsIlpJUENPREUiLCJBUlJBWSIsIk9CSkVDVCIsIklHTk9SRV9EQVRBX1RZUEVTIiwiT2JqZWN0Iiwia2V5cyIsImZpbHRlciIsInR5cGUiLCJpbmNsdWRlcyIsImdldFNhbXBsZUZvclR5cGVBbmFseXplIiwiX3JlZiIsImZpZWxkcyIsInJvd3MiLCJfcmVmJHNhbXBsZUNvdW50Iiwic2FtcGxlQ291bnQiLCJ0b3RhbCIsIk1hdGgiLCJtaW4iLCJsZW5ndGgiLCJzYW1wbGUiLCJyYW5nZSIsIm1hcCIsImlzUm93T2JqZWN0IiwiQXJyYXkiLCJpc0FycmF5IiwiZm9yRWFjaCIsImZpZWxkIiwiZmllbGRJZHgiLCJpIiwiaiIsIm5vdE51bGxvclVuZGVmaW5lZCIsInZhbHVlIiwidHJpbSIsImdldFNhbXBsZUZvclR5cGVBbmFseXplQXJyb3ciLCJ0YWJsZSIsImFyZ3VtZW50cyIsInVuZGVmaW5lZCIsImlzVGFibGUiLCJudW1Sb3dzIiwiZ2V0VmVjdG9yIiwiaW5kZXgiLCJnZXRDaGlsZEF0Iiwicm93SW5kZXgiLCJzYW1wbGVJbmRleCIsIl9nZXRWZWN0b3IiLCJnZXQiLCJfZ2V0VmVjdG9yMiIsImFuYWx5emVyVHlwZVRvRmllbGRUeXBlIiwiYVR5cGUiLCJBTExfRklFTERfVFlQRVMiLCJkYXRlIiwidGltZXN0YW1wIiwicmVhbCIsImludGVnZXIiLCJnZW9qc29uIiwiYXJyYXkiLCJvYmplY3QiLCJzdHJpbmciLCJoMyIsImdsb2JhbENvbnNvbGUiLCJ3YXJuIiwiY29uY2F0IiwiZ2V0RmllbGRzRnJvbURhdGEiLCJkYXRhIiwiZmllbGRPcmRlciIsIm1ldGFkYXRhIiwiQW5hbHl6ZXIiLCJjb21wdXRlQ29sTWV0YSIsInJlZ2V4IiwiZGF0YVR5cGUiLCJpZ25vcmVkRGF0YVR5cGVzIiwiX3JlbmFtZUR1cGxpY2F0ZUZpZWxkIiwicmVuYW1lRHVwbGljYXRlRmllbGRzIiwiZmllbGRCeUluZGV4IiwicmVzdWx0IiwibmFtZSIsImZpZWxkTWV0YSIsImZpbmQiLCJtIiwia2V5IiwiZm9ybWF0IiwibiIsImgzSXNWYWxpZCIsInNvbWUiLCJkIiwiaXNIZXhXa2IiLCJpZCIsImRpc3BsYXlOYW1lIiwiYW5hbHl6ZXJUeXBlIiwidmFsdWVBY2Nlc3NvciIsImRjIiwidmFsdWVBdCIsInJlZHVjZSIsImFjY3UiLCJhbGxOYW1lcyIsImZpZWxkTmFtZSIsImNvdW50ZXIiLCJwdXNoIl0sInNvdXJjZXMiOlsiLi4vc3JjL2RhdGEtdHlwZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4vLyBDb3B5cmlnaHQgY29udHJpYnV0b3JzIHRvIHRoZSBrZXBsZXIuZ2wgcHJvamVjdFxuXG5pbXBvcnQge0FuYWx5emVyLCBEQVRBX1RZUEVTIGFzIEFuYWx5emVyREFUQV9UWVBFU30gZnJvbSAndHlwZS1hbmFseXplcic7XG5pbXBvcnQge0Fycm93VGFibGVJbnRlcmZhY2UsIEFwYWNoZVZlY3RvckludGVyZmFjZSwgUm93RGF0YSwgRmllbGR9IGZyb20gJ0BrZXBsZXIuZ2wvdHlwZXMnO1xuaW1wb3J0IHtBTExfRklFTERfVFlQRVN9IGZyb20gJ0BrZXBsZXIuZ2wvY29uc3RhbnRzJztcbmltcG9ydCB7Y29uc29sZSBhcyBnbG9iYWxDb25zb2xlfSBmcm9tICdnbG9iYWwvd2luZG93JztcbmltcG9ydCB7cmFuZ2V9IGZyb20gJ2QzLWFycmF5JztcbmltcG9ydCB7aXNIZXhXa2IsIG5vdE51bGxvclVuZGVmaW5lZH0gZnJvbSAnLi9kYXRhJztcbmltcG9ydCB7aDNJc1ZhbGlkfSBmcm9tICcuL2gzLXV0aWxzJztcblxuY29uc3QgSDNfQU5BTFlaRVJfVFlQRSA9ICdIMyc7XG5cbmV4cG9ydCBjb25zdCBBQ0NFUFRFRF9BTkFMWVpFUl9UWVBFUyA9IFtcbiAgQW5hbHl6ZXJEQVRBX1RZUEVTLkRBVEUsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5USU1FLFxuICBBbmFseXplckRBVEFfVFlQRVMuREFURVRJTUUsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5OVU1CRVIsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5JTlQsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5GTE9BVCxcbiAgQW5hbHl6ZXJEQVRBX1RZUEVTLkJPT0xFQU4sXG4gIEFuYWx5emVyREFUQV9UWVBFUy5TVFJJTkcsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5HRU9NRVRSWSxcbiAgQW5hbHl6ZXJEQVRBX1RZUEVTLkdFT01FVFJZX0ZST01fU1RSSU5HLFxuICBBbmFseXplckRBVEFfVFlQRVMuUEFJUl9HRU9NRVRSWV9GUk9NX1NUUklORyxcbiAgQW5hbHl6ZXJEQVRBX1RZUEVTLlpJUENPREUsXG4gIEFuYWx5emVyREFUQV9UWVBFUy5BUlJBWSxcbiAgQW5hbHl6ZXJEQVRBX1RZUEVTLk9CSkVDVCxcbiAgSDNfQU5BTFlaRVJfVFlQRVxuXTtcblxuY29uc3QgSUdOT1JFX0RBVEFfVFlQRVMgPSBPYmplY3Qua2V5cyhBbmFseXplckRBVEFfVFlQRVMpLmZpbHRlcihcbiAgdHlwZSA9PiAhQUNDRVBURURfQU5BTFlaRVJfVFlQRVMuaW5jbHVkZXModHlwZSlcbik7XG5cbi8qKlxuICogR2V0dGluZyBzYW1wbGUgZGF0YSBmb3IgYW5hbHl6aW5nIGZpZWxkIHR5cGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRTYW1wbGVGb3JUeXBlQW5hbHl6ZSh7XG4gIGZpZWxkcyxcbiAgcm93cyxcbiAgc2FtcGxlQ291bnQgPSA1MFxufToge1xuICBmaWVsZHM6IHN0cmluZ1tdO1xuICByb3dzOiB1bmtub3duW11bXSB8IFJvd0RhdGE7XG4gIHNhbXBsZUNvdW50PzogbnVtYmVyO1xufSk6IFJvd0RhdGEge1xuICBjb25zdCB0b3RhbCA9IE1hdGgubWluKHNhbXBsZUNvdW50LCByb3dzLmxlbmd0aCk7XG4gIC8vIGNvbnN0IGZpZWxkT3JkZXIgPSBmaWVsZHMubWFwKGYgPT4gZi5uYW1lKTtcbiAgY29uc3Qgc2FtcGxlID0gcmFuZ2UoMCwgdG90YWwsIDEpLm1hcCgoKSA9PiAoe30pKTtcblxuICBpZiAocm93cy5sZW5ndGggPCAxKSB7XG4gICAgcmV0dXJuIFtdO1xuICB9XG4gIGNvbnN0IGlzUm93T2JqZWN0ID0gIUFycmF5LmlzQXJyYXkocm93c1swXSk7XG5cbiAgLy8gY29sbGVjdCBzYW1wbGUgZGF0YSBmb3IgZWFjaCBmaWVsZFxuICBmaWVsZHMuZm9yRWFjaCgoZmllbGQsIGZpZWxkSWR4KSA9PiB7XG4gICAgLy8gcm93IGNvdW50ZXJcbiAgICBsZXQgaSA9IDA7XG4gICAgLy8gc2FtcGxlIGNvdW50ZXJcbiAgICBsZXQgaiA9IDA7XG5cbiAgICB3aGlsZSAoaiA8IHRvdGFsKSB7XG4gICAgICBpZiAoaSA+PSByb3dzLmxlbmd0aCkge1xuICAgICAgICAvLyBpZiBkZXBsZXRlZCBkYXRhIHBvb2xcbiAgICAgICAgc2FtcGxlW2pdW2ZpZWxkXSA9IG51bGw7XG4gICAgICAgIGorKztcbiAgICAgIH0gZWxzZSBpZiAobm90TnVsbG9yVW5kZWZpbmVkKHJvd3NbaV1baXNSb3dPYmplY3QgPyBmaWVsZCA6IGZpZWxkSWR4XSkpIHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSByb3dzW2ldW2lzUm93T2JqZWN0ID8gZmllbGQgOiBmaWVsZElkeF07XG4gICAgICAgIHNhbXBsZVtqXVtmaWVsZF0gPSB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gdmFsdWUudHJpbSgpIDogdmFsdWU7XG4gICAgICAgIGorKztcbiAgICAgICAgaSsrO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaSsrO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIHNhbXBsZTtcbn1cblxuLyoqXG4gKiBHZXR0aW5nIHNhbXBsZSBkYXRhIGZvciBhbmFseXppbmcgZmllbGQgdHlwZSBmb3IgQXJyb3cgdGFibGVzLlxuICogQHBhcmFtIHRhYmxlIEFycm93IHRhYmxlIG9yIGFuIGFycmF5IG9mIHZlY3RvcnMuXG4gKiBAcGFyYW0gZmllbGRzIEZpZWxkIG5hbWVzLlxuICogQHBhcmFtIHNhbXBsZUNvdW50IE51bWJlciBvZiBzYW1wbGUgcm93cyB0byBnZXQuXG4gKiBAcmV0dXJucyBTYW1wbGUgcm93cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFNhbXBsZUZvclR5cGVBbmFseXplQXJyb3coXG4gIHRhYmxlOiBBcnJvd1RhYmxlSW50ZXJmYWNlIHwgQXBhY2hlVmVjdG9ySW50ZXJmYWNlW10sXG4gIGZpZWxkczogc3RyaW5nW10sXG4gIHNhbXBsZUNvdW50ID0gNTBcbik6IGFueVtdIHtcbiAgY29uc3QgaXNUYWJsZSA9ICFBcnJheS5pc0FycmF5KHRhYmxlKTtcblxuICBjb25zdCBudW1Sb3dzID0gaXNUYWJsZSA/IHRhYmxlLm51bVJvd3MgOiB0YWJsZVswXS5sZW5ndGg7XG4gIGNvbnN0IGdldFZlY3RvciA9IGlzVGFibGUgPyBpbmRleCA9PiB0YWJsZS5nZXRDaGlsZEF0KGluZGV4KSA6IGluZGV4ID0+IHRhYmxlW2luZGV4XTtcblxuICBjb25zdCB0b3RhbCA9IE1hdGgubWluKHNhbXBsZUNvdW50LCBudW1Sb3dzKTtcbiAgY29uc3Qgc2FtcGxlID0gcmFuZ2UoMCwgdG90YWwsIDEpLm1hcCgoKSA9PiAoe30pKTtcblxuICBpZiAobnVtUm93cyA8IDEpIHtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICAvLyBjb2xsZWN0IHNhbXBsZSBkYXRhIGZvciBlYWNoIGZpZWxkXG4gIGZpZWxkcy5mb3JFYWNoKChmaWVsZCwgZmllbGRJZHgpID0+IHtcbiAgICBsZXQgcm93SW5kZXggPSAwO1xuICAgIGxldCBzYW1wbGVJbmRleCA9IDA7XG5cbiAgICB3aGlsZSAoc2FtcGxlSW5kZXggPCB0b3RhbCkge1xuICAgICAgaWYgKHJvd0luZGV4ID49IG51bVJvd3MpIHtcbiAgICAgICAgLy8gaWYgZGVwbGV0ZWQgZGF0YSBwb29sXG4gICAgICAgIHNhbXBsZVtzYW1wbGVJbmRleF1bZmllbGRdID0gbnVsbDtcbiAgICAgICAgc2FtcGxlSW5kZXgrKztcbiAgICAgIH0gZWxzZSBpZiAobm90TnVsbG9yVW5kZWZpbmVkKGdldFZlY3RvcihmaWVsZElkeCk/LmdldChyb3dJbmRleCkpKSB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gZ2V0VmVjdG9yKGZpZWxkSWR4KT8uZ2V0KHJvd0luZGV4KTtcbiAgICAgICAgc2FtcGxlW3NhbXBsZUluZGV4XVtmaWVsZF0gPSB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gdmFsdWUudHJpbSgpIDogdmFsdWU7XG4gICAgICAgIHNhbXBsZUluZGV4Kys7XG4gICAgICAgIHJvd0luZGV4Kys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByb3dJbmRleCsrO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIHNhbXBsZTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IHR5cGUtYW5hbHl6ZXIgb3V0cHV0IHRvIGtlcGxlci5nbCBmaWVsZCB0eXBlc1xuICpcbiAqIEBwYXJhbSBhVHlwZVxuICogQHJldHVybnMgY29ycmVzcG9uZGluZyB0eXBlIGluIGBBTExfRklFTERfVFlQRVNgXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIGNvbXBsZXhpdHkgKi9cbmV4cG9ydCBmdW5jdGlvbiBhbmFseXplclR5cGVUb0ZpZWxkVHlwZShhVHlwZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3Qge1xuICAgIERBVEUsXG4gICAgVElNRSxcbiAgICBEQVRFVElNRSxcbiAgICBOVU1CRVIsXG4gICAgSU5ULFxuICAgIEZMT0FULFxuICAgIEJPT0xFQU4sXG4gICAgU1RSSU5HLFxuICAgIEdFT01FVFJZLFxuICAgIEdFT01FVFJZX0ZST01fU1RSSU5HLFxuICAgIFBBSVJfR0VPTUVUUllfRlJPTV9TVFJJTkcsXG4gICAgWklQQ09ERSxcbiAgICBBUlJBWSxcbiAgICBPQkpFQ1RcbiAgfSA9IEFuYWx5emVyREFUQV9UWVBFUztcblxuICAvLyBUT0RPOiB1biByZWNvZ25pemVkIHR5cGVzXG4gIC8vIENVUlJFTkNZIFBFUkNFTlQgTk9ORVxuICBzd2l0Y2ggKGFUeXBlKSB7XG4gICAgY2FzZSBEQVRFOlxuICAgICAgcmV0dXJuIEFMTF9GSUVMRF9UWVBFUy5kYXRlO1xuICAgIGNhc2UgVElNRTpcbiAgICBjYXNlIERBVEVUSU1FOlxuICAgICAgcmV0dXJuIEFMTF9GSUVMRF9UWVBFUy50aW1lc3RhbXA7XG4gICAgY2FzZSBGTE9BVDpcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMucmVhbDtcbiAgICBjYXNlIElOVDpcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMuaW50ZWdlcjtcbiAgICBjYXNlIEJPT0xFQU46XG4gICAgICByZXR1cm4gQUxMX0ZJRUxEX1RZUEVTLmJvb2xlYW47XG4gICAgY2FzZSBHRU9NRVRSWTpcbiAgICBjYXNlIEdFT01FVFJZX0ZST01fU1RSSU5HOlxuICAgIGNhc2UgUEFJUl9HRU9NRVRSWV9GUk9NX1NUUklORzpcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMuZ2VvanNvbjtcbiAgICBjYXNlIEFSUkFZOlxuICAgICAgcmV0dXJuIEFMTF9GSUVMRF9UWVBFUy5hcnJheTtcbiAgICBjYXNlIE9CSkVDVDpcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMub2JqZWN0O1xuICAgIGNhc2UgTlVNQkVSOlxuICAgIGNhc2UgU1RSSU5HOlxuICAgIGNhc2UgWklQQ09ERTpcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMuc3RyaW5nO1xuICAgIGNhc2UgSDNfQU5BTFlaRVJfVFlQRTpcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMuaDM7XG4gICAgZGVmYXVsdDpcbiAgICAgIGdsb2JhbENvbnNvbGUud2FybihgVW5zdXBwb3J0ZWQgYW5hbHl6ZXIgdHlwZTogJHthVHlwZX1gKTtcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMuc3RyaW5nO1xuICB9XG59XG5cbi8qKlxuICogQW5hbHl6ZSBmaWVsZCB0eXBlcyBmcm9tIGRhdGEgaW4gYHN0cmluZ2AgZm9ybWF0LCBlLmcuIHVwbG9hZGVkIGNzdi5cbiAqIEFzc2lnbiBgdHlwZWAsIGBmaWVsZElkeGAgYW5kIGBmb3JtYXRgICh0aW1lc3RhbXAgb25seSkgdG8gZWFjaCBmaWVsZFxuICpcbiAqIEBwYXJhbSBkYXRhIGFycmF5IG9mIHJvdyBvYmplY3RcbiAqIEBwYXJhbSBmaWVsZE9yZGVyIGFycmF5IG9mIGZpZWxkIG5hbWVzIGFzIHN0cmluZ1xuICogQHJldHVybnMgZm9ybWF0dGVkIGZpZWxkc1xuICogQHB1YmxpY1xuICogQGV4YW1wbGVcbiAqXG4gKiBpbXBvcnQge2dldEZpZWxkc0Zyb21EYXRhfSBmcm9tICdrZXBsZXIuZ2wvY29tbW9uLXV0aWxzJztcbiAqIGNvbnN0IGRhdGEgPSBbe1xuICogICB0aW1lOiAnMjAxNi0wOS0xNyAwMDowOTo1NScsXG4gKiAgIHZhbHVlOiAnNCcsXG4gKiAgIHN1cmdlOiAnMS4yJyxcbiAqICAgaXNUcmlwOiAndHJ1ZScsXG4gKiAgIHplcm9PbmVzOiAnMCdcbiAqIH0sIHtcbiAqICAgdGltZTogJzIwMTYtMDktMTcgMDA6MzA6MDgnLFxuICogICB2YWx1ZTogJzMnLFxuICogICBzdXJnZTogbnVsbCxcbiAqICAgaXNUcmlwOiAnZmFsc2UnLFxuICogICB6ZXJvT25lczogJzEnXG4gKiB9LCB7XG4gKiAgIHRpbWU6IG51bGwsXG4gKiAgIHZhbHVlOiAnMicsXG4gKiAgIHN1cmdlOiAnMS4zJyxcbiAqICAgaXNUcmlwOiBudWxsLFxuICogICB6ZXJvT25lczogJzEnXG4gKiB9XTtcbiAqXG4gKiBjb25zdCBmaWVsZE9yZGVyID0gWyd0aW1lJywgJ3ZhbHVlJywgJ3N1cmdlJywgJ2lzVHJpcCcsICd6ZXJvT25lcyddO1xuICogY29uc3QgZmllbGRzID0gZ2V0RmllbGRzRnJvbURhdGEoZGF0YSwgZmllbGRPcmRlcik7XG4gKiAvLyBmaWVsZHMgPSBbXG4gKiAvLyB7bmFtZTogJ3RpbWUnLCBmb3JtYXQ6ICdZWVlZLU0tRCBIOm06cycsIGZpZWxkSWR4OiAxLCB0eXBlOiAndGltZXN0YW1wJ30sXG4gKiAvLyB7bmFtZTogJ3ZhbHVlJywgZm9ybWF0OiAnJywgZmllbGRJZHg6IDQsIHR5cGU6ICdpbnRlZ2VyJ30sXG4gKiAvLyB7bmFtZTogJ3N1cmdlJywgZm9ybWF0OiAnJywgZmllbGRJZHg6IDUsIHR5cGU6ICdyZWFsJ30sXG4gKiAvLyB7bmFtZTogJ2lzVHJpcCcsIGZvcm1hdDogJycsIGZpZWxkSWR4OiA2LCB0eXBlOiAnYm9vbGVhbid9LFxuICogLy8ge25hbWU6ICd6ZXJvT25lcycsIGZvcm1hdDogJycsIGZpZWxkSWR4OiA3LCB0eXBlOiAnaW50ZWdlcid9XTtcbiAqXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRGaWVsZHNGcm9tRGF0YShkYXRhOiBSb3dEYXRhLCBmaWVsZE9yZGVyOiBzdHJpbmdbXSk6IEZpZWxkW10ge1xuICAvLyBhZGQgYSBjaGVjayBmb3IgZXBvY2ggdGltZXN0YW1wXG4gIGNvbnN0IG1ldGFkYXRhID0gQW5hbHl6ZXIuY29tcHV0ZUNvbE1ldGEoXG4gICAgZGF0YSxcbiAgICBbXG4gICAgICB7cmVnZXg6IC8uKmdlb2pzb258YWxsX3BvaW50cy9nLCBkYXRhVHlwZTogJ0dFT01FVFJZJ30sXG4gICAgICB7cmVnZXg6IC8uKmNlbnN1cy9nLCBkYXRhVHlwZTogJ1NUUklORyd9XG4gICAgXSxcbiAgICB7aWdub3JlZERhdGFUeXBlczogSUdOT1JFX0RBVEFfVFlQRVN9XG4gICk7XG5cbiAgY29uc3Qge2ZpZWxkQnlJbmRleH0gPSByZW5hbWVEdXBsaWNhdGVGaWVsZHMoZmllbGRPcmRlcik7XG5cbiAgY29uc3QgcmVzdWx0ID0gZmllbGRPcmRlci5tYXAoKGZpZWxkLCBpbmRleCkgPT4ge1xuICAgIGNvbnN0IG5hbWUgPSBmaWVsZEJ5SW5kZXhbaW5kZXhdO1xuXG4gICAgY29uc3QgZmllbGRNZXRhID0gbWV0YWRhdGEuZmluZChtID0+IG0ua2V5ID09PSBmaWVsZCk7XG5cbiAgICAvLyBmaWVsZE1ldGEgY291bGQgYmUgdW5kZWZpbmVkIGlmIHRoZSBmaWVsZCBoYXMgbm8gZGF0YSBhbmQgQW5hbHl6ZXIuY29tcHV0ZUNvbE1ldGFcbiAgICAvLyB3aWxsIGlnbm9yZSB0aGUgZmllbGQuIEluIHRoaXMgY2FzZSwgd2Ugd2lsbCBzaW1wbHkgYXNzaWduIHRoZSBmaWVsZCB0eXBlIHRvIFNUUklOR1xuICAgIC8vIHNpbmNlIGRyb3BwaW5nIHRoZSBjb2x1bW4gaW4gdGhlIFJvd0RhdGEgY291bGQgYmUgZXhwZW5zaXZlXG4gICAgbGV0IHR5cGUgPSBmaWVsZE1ldGE/LnR5cGUgfHwgJ1NUUklORyc7XG4gICAgY29uc3QgZm9ybWF0ID0gZmllbGRNZXRhPy5mb3JtYXQgfHwgJyc7XG5cbiAgICAvLyBxdWljayBjaGVjayBpZiBmaXJzdCB2YWxpZCBzdHJpbmcgaW4gY29sdW1uIGlzIEgzXG4gICAgaWYgKHR5cGUgPT09IEFuYWx5emVyREFUQV9UWVBFUy5TVFJJTkcpIHtcbiAgICAgIGZvciAobGV0IGkgPSAwLCBuID0gZGF0YS5sZW5ndGg7IGkgPCBuOyArK2kpIHtcbiAgICAgICAgaWYgKG5vdE51bGxvclVuZGVmaW5lZChkYXRhW2ldW25hbWVdKSkge1xuICAgICAgICAgIHR5cGUgPSBoM0lzVmFsaWQoZGF0YVtpXVtuYW1lXSB8fCAnJykgPyBIM19BTkFMWVpFUl9UWVBFIDogdHlwZTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIHF1aWNrIGNoZWNrIGlmIHN0cmluZyBpcyBoZXggd2tiXG4gICAgaWYgKHR5cGUgPT09IEFuYWx5emVyREFUQV9UWVBFUy5TVFJJTkcpIHtcbiAgICAgIHR5cGUgPSBkYXRhLnNvbWUoZCA9PiBpc0hleFdrYihkW25hbWVdKSkgPyBBbmFseXplckRBVEFfVFlQRVMuR0VPTUVUUlkgOiB0eXBlO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBuYW1lLFxuICAgICAgaWQ6IG5hbWUsXG4gICAgICBkaXNwbGF5TmFtZTogbmFtZSxcbiAgICAgIGZvcm1hdCxcbiAgICAgIGZpZWxkSWR4OiBpbmRleCxcbiAgICAgIHR5cGU6IGFuYWx5emVyVHlwZVRvRmllbGRUeXBlKHR5cGUpLFxuICAgICAgYW5hbHl6ZXJUeXBlOiB0eXBlLFxuICAgICAgdmFsdWVBY2Nlc3NvcjogZGMgPT4gZCA9PiB7XG4gICAgICAgIHJldHVybiBkYy52YWx1ZUF0KGQuaW5kZXgsIGluZGV4KTtcbiAgICAgIH1cbiAgICB9O1xuICB9KTtcblxuICByZXR1cm4gcmVzdWx0O1xufVxuXG4vKipcbiAqIHBhc3MgaW4gYW4gYXJyYXkgb2YgZmllbGQgbmFtZXMsIHJlbmFtZSBkdXBsaWNhdGVkIG9uZVxuICogYW5kIHJldHVybiBhIG1hcCBmcm9tIG9sZCBmaWVsZCBpbmRleCB0byBuZXcgbmFtZVxuICpcbiAqIEBwYXJhbSBmaWVsZE9yZGVyXG4gKiBAcmV0dXJucyBuZXcgZmllbGQgbmFtZSBieSBpbmRleFxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVuYW1lRHVwbGljYXRlRmllbGRzKGZpZWxkT3JkZXI6IHN0cmluZ1tdKToge1xuICBhbGxOYW1lczogc3RyaW5nW107XG4gIGZpZWxkQnlJbmRleDogc3RyaW5nW107XG59IHtcbiAgcmV0dXJuIGZpZWxkT3JkZXIucmVkdWNlPHthbGxOYW1lczogc3RyaW5nW107IGZpZWxkQnlJbmRleDogc3RyaW5nW119PihcbiAgICAoYWNjdSwgZmllbGQsIGkpID0+IHtcbiAgICAgIGNvbnN0IHthbGxOYW1lc30gPSBhY2N1O1xuICAgICAgbGV0IGZpZWxkTmFtZSA9IGZpZWxkO1xuXG4gICAgICAvLyBhZGQgYSBjb3VudGVyIHRvIGR1cGxpY2F0ZWQgbmFtZXNcbiAgICAgIGlmIChhbGxOYW1lcy5pbmNsdWRlcyhmaWVsZCkpIHtcbiAgICAgICAgbGV0IGNvdW50ZXIgPSAwO1xuICAgICAgICB3aGlsZSAoYWxsTmFtZXMuaW5jbHVkZXMoYCR7ZmllbGR9LSR7Y291bnRlcn1gKSkge1xuICAgICAgICAgIGNvdW50ZXIrKztcbiAgICAgICAgfVxuICAgICAgICBmaWVsZE5hbWUgPSBgJHtmaWVsZH0tJHtjb3VudGVyfWA7XG4gICAgICB9XG5cbiAgICAgIGFjY3UuZmllbGRCeUluZGV4W2ldID0gZmllbGROYW1lO1xuICAgICAgYWNjdS5hbGxOYW1lcy5wdXNoKGZpZWxkTmFtZSk7XG5cbiAgICAgIHJldHVybiBhY2N1O1xuICAgIH0sXG4gICAge2FsbE5hbWVzOiBbXSwgZmllbGRCeUluZGV4OiBbXX1cbiAgKTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7QUFHQSxJQUFBQSxhQUFBLEdBQUFDLE9BQUE7QUFFQSxJQUFBQyxVQUFBLEdBQUFELE9BQUE7QUFDQSxJQUFBRSxPQUFBLEdBQUFGLE9BQUE7QUFDQSxJQUFBRyxRQUFBLEdBQUFILE9BQUE7QUFDQSxJQUFBSSxLQUFBLEdBQUFKLE9BQUE7QUFDQSxJQUFBSyxRQUFBLEdBQUFMLE9BQUE7QUFUQTtBQUNBOztBQVVBLElBQU1NLGdCQUFnQixHQUFHLElBQUk7QUFFdEIsSUFBTUMsdUJBQXVCLEdBQUFDLE9BQUEsQ0FBQUQsdUJBQUEsR0FBRyxDQUNyQ0Usd0JBQWtCLENBQUNDLElBQUksRUFDdkJELHdCQUFrQixDQUFDRSxJQUFJLEVBQ3ZCRix3QkFBa0IsQ0FBQ0csUUFBUSxFQUMzQkgsd0JBQWtCLENBQUNJLE1BQU0sRUFDekJKLHdCQUFrQixDQUFDSyxHQUFHLEVBQ3RCTCx3QkFBa0IsQ0FBQ00sS0FBSyxFQUN4Qk4s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