UNPKG

kepler.gl.geoiq

Version:

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

508 lines (415 loc) 46.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.processCsvData = processCsvData; exports.getSampleForTypeAnalyze = getSampleForTypeAnalyze; exports.parseCsvDataByFieldType = parseCsvDataByFieldType; exports.getFieldsFromData = getFieldsFromData; exports.renameDuplicateFields = renameDuplicateFields; exports.analyzerTypeToFieldType = analyzerTypeToFieldType; exports.processRowObject = processRowObject; exports.processGeojson = processGeojson; exports.formatCsv = formatCsv; exports.validateInputData = validateInputData; exports.processKeplerglJSON = processKeplerglJSON; exports["default"] = void 0; var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _toArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toArray")); var _d3Dsv = require("d3-dsv"); var _d3Array = require("d3-array"); var _window = require("global/window"); var _assert = _interopRequireDefault(require("assert")); var _typeAnalyzerGeoiq = require("type-analyzer-geoiq"); var _geojsonNormalize = _interopRequireDefault(require("@mapbox/geojson-normalize")); var _defaultSettings = require("../constants/default-settings"); var _dataUtils = require("../utils/data-utils"); var _schemas = _interopRequireDefault(require("../schemas")); function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } // if any of these value occurs in csv, parse it to null; var CSV_NULLS = ['', 'null', 'NULL', 'Null', 'NaN']; function processCsvData(rawData) { // here we assume the csv file that people uploaded will have first row // as name of the column // TODO: add a alert at upload csv to remind define first row var _csvParseRows = (0, _d3Dsv.csvParseRows)(rawData), _csvParseRows2 = (0, _toArray2["default"])(_csvParseRows), headerRow = _csvParseRows2[0], rows = _csvParseRows2.slice(1); if (!rows.length || !headerRow) { // looks like an empty file // resolve null, and catch them later in one place return null; } cleanUpFalsyCsvValue(rows); // No need to run type detection on every data point // here we get a list of none null values to run analyze on var sample = getSampleForTypeAnalyze({ fields: headerRow, allData: rows }); var fields = getFieldsFromData(sample, headerRow); fields.forEach(parseCsvDataByFieldType.bind(null, rows)); return { fields: fields, rows: rows }; } /** * get fields from csv data * * @param {array} fields - an array of fields name * @param {array} allData * @param {array} sampleCount * @returns {array} formatted fields */ function getSampleForTypeAnalyze(_ref) { var fields = _ref.fields, allData = _ref.allData, _ref$sampleCount = _ref.sampleCount, sampleCount = _ref$sampleCount === void 0 ? 50 : _ref$sampleCount; var total = Math.min(sampleCount, allData.length); // const fieldOrder = fields.map(f => f.name); var sample = (0, _d3Array.range)(0, total, 1).map(function (d) { return {}; }); // collect sample data for each field fields.forEach(function (field, fieldIdx) { // data counter var i = 0; // sample counter var j = 0; while (j < total) { if (i >= allData.length) { // if depleted data pool sample[j][field] = null; j++; } else if ((0, _dataUtils.notNullorUndefined)(allData[i][fieldIdx])) { sample[j][field] = allData[i][fieldIdx]; j++; i++; } else { i++; } } }); return sample; } function cleanUpFalsyCsvValue(rows) { for (var i = 0; i < rows.length; i++) { for (var j = 0; j < rows[i].length; j++) { // analyzer will set any fields to 'string' if there are empty values // which will be parsed as '' by d3.csv // here we parse empty data as null // TODO: create warning when deltect `CSV_NULLS` in the data if (!rows[i][j] || CSV_NULLS.includes(rows[i][j])) { rows[i][j] = null; } } } } /** * Process uploaded csv file to parse value by field type * * @param {array} rows * @param {object} field * @param {number} i * @returns {void} */ function parseCsvDataByFieldType(rows, field, i) { var unixFormat = ['x', 'X']; rows.forEach(function (row) { if (row[i] !== null) { switch (field.type) { case _defaultSettings.ALL_FIELD_TYPES.real: row[i] = parseFloat(row[i]); break; // TODO: timestamp can be either '1495827326' or '2016-03-10 11:20' // if it's '1495827326' we pass it to int case _defaultSettings.ALL_FIELD_TYPES.timestamp: row[i] = unixFormat.includes(field.format) ? Number(row[i]) : row[i]; break; case _defaultSettings.ALL_FIELD_TYPES.integer: row[i] = parseInt(row[i], 10); break; case _defaultSettings.ALL_FIELD_TYPES["boolean"]: // 0 and 1 only field can also be boolean row[i] = row[i] === 'true' || row[i] === 'True' || row[i] === '1'; break; default: break; } } }); } /** * get fields from csv data * * @param {array} data * @param {array} fieldOrder * @returns {array} formatted fields */ function getFieldsFromData(data, fieldOrder) { // add a check for epoch timestamp var metadata = _typeAnalyzerGeoiq.Analyzer.computeColMeta(data, [{ regex: /.*geojson|all_points/g, dataType: 'GEOMETRY' }]); var _renameDuplicateField = renameDuplicateFields(fieldOrder), fieldByIndex = _renameDuplicateField.fieldByIndex; return fieldOrder.reduce(function (orderedArray, field, index) { var name = fieldByIndex[index]; var fieldMeta = metadata.find(function (m) { return m.key === field; }); var _ref2 = fieldMeta || {}, type = _ref2.type, format = _ref2.format; orderedArray[index] = { name: name, format: format, // need this for mapbuilder conversion: filter type detection // category, tableFieldIndex: index + 1, type: analyzerTypeToFieldType(type) }; // console.log(orderedArray); return orderedArray; }, []); } /** * pass in an array of field names, rename duplicated one * and return a map from old field index to new name * * @param {array} fieldOrder * @returns {Object} 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: {} }); } /** * Map Analyzer types to local field types * * @param {string} aType * @returns {string} corresponding type in ALL_FIELD_TYPES */ /* eslint-disable complexity */ function analyzerTypeToFieldType(aType) { var DATE = _typeAnalyzerGeoiq.DATA_TYPES.DATE, TIME = _typeAnalyzerGeoiq.DATA_TYPES.TIME, DATETIME = _typeAnalyzerGeoiq.DATA_TYPES.DATETIME, NUMBER = _typeAnalyzerGeoiq.DATA_TYPES.NUMBER, INT = _typeAnalyzerGeoiq.DATA_TYPES.INT, FLOAT = _typeAnalyzerGeoiq.DATA_TYPES.FLOAT, BOOLEAN = _typeAnalyzerGeoiq.DATA_TYPES.BOOLEAN, STRING = _typeAnalyzerGeoiq.DATA_TYPES.STRING, CITY = _typeAnalyzerGeoiq.DATA_TYPES.CITY, GEOMETRY = _typeAnalyzerGeoiq.DATA_TYPES.GEOMETRY, GEOMETRY_FROM_STRING = _typeAnalyzerGeoiq.DATA_TYPES.GEOMETRY_FROM_STRING, ZIPCODE = _typeAnalyzerGeoiq.DATA_TYPES.ZIPCODE, PAIR_GEOMETRY_FROM_STRING = _typeAnalyzerGeoiq.DATA_TYPES.PAIR_GEOMETRY_FROM_STRING; // TODO: un recognized types // CURRENCY PERCENT NONE switch (aType) { case DATE: return _defaultSettings.ALL_FIELD_TYPES.date; case TIME: return _defaultSettings.ALL_FIELD_TYPES.string; case DATETIME: return _defaultSettings.ALL_FIELD_TYPES.timestamp; case NUMBER: case FLOAT: return _defaultSettings.ALL_FIELD_TYPES.real; case INT: return _defaultSettings.ALL_FIELD_TYPES.integer; case BOOLEAN: return _defaultSettings.ALL_FIELD_TYPES["boolean"]; case GEOMETRY: case GEOMETRY_FROM_STRING: case PAIR_GEOMETRY_FROM_STRING: return _defaultSettings.ALL_FIELD_TYPES.geojson; case STRING: case CITY: case ZIPCODE: return _defaultSettings.ALL_FIELD_TYPES.string; default: _window.console.warn("Unsupported analyzer type: ".concat(aType)); return _defaultSettings.ALL_FIELD_TYPES.string; } } /* eslint-enable complexity */ /* * Process rawData where each row is an object */ function processRowObject(rawData) { if (!rawData.length) { return null; } var keys = Object.keys(rawData[0]); var rows = rawData.map(function (d) { return keys.map(function (key) { return d[key]; }); }); var fields = getFieldsFromData(rawData, keys); return { fields: fields, rows: rows }; } /** * * @param {Object} rawData - raw geojson feature collection */ function processGeojson(rawData) { var normalizedGeojson = (0, _geojsonNormalize["default"])(rawData); if (!normalizedGeojson || !Array.isArray(normalizedGeojson.features)) { // fail to normalize geojson return null; } // getting all feature fields var allData = normalizedGeojson.features.reduce(function (accu, f, i) { if (f.geometry) { accu.push(_objectSpread({ // add feature to _geojson field _geojson: f }, f.properties || {})); } return accu; }, []); // get all the field var fields = allData.reduce(function (prev, curr) { Object.keys(curr).forEach(function (key) { if (!prev.includes(key)) { prev.push(key); } }); return prev; }, []); // make sure each feature has exact same fields allData.forEach(function (d) { fields.forEach(function (f) { if (!(f in d)) { d[f] = null; } }); }); // console.log(processRowObject(allData)) return processRowObject(allData); } /** * On export data to csv * @param data * @param fields */ function formatCsv(data, fields) { var columns = fields.map(function (f) { return f.name; }); var formattedData = [columns]; // parse geojson object as string data.forEach(function (row) { formattedData.push(row.map(function (d, i) { return d && _defaultSettings.GEOJSON_FIELDS.geojson.includes(fields[i].name) ? JSON.stringify(d) : d; })); }); return (0, _d3Dsv.csvFormatRows)(formattedData); } /** * @param data * @returns {{allData: Array, fields: Array}} */ function validateInputData(data) { // TODO: add test /* * expected input data format * { * fields: [], * rows: [] * } */ var proceed = true; if (!data) { (0, _assert["default"])('receiveVisData: data cannot be null'); proceed = false; } else if (!Array.isArray(data.fields)) { (0, _assert["default"])('receiveVisData: expect data.fields to be an array'); proceed = false; } else if (!Array.isArray(data.rows)) { (0, _assert["default"])('receiveVisData: expect data.rows to be an array'); proceed = false; } if (!proceed) { return null; } var fields = data.fields, rows = data.rows; // check if all fields has name, format and type var allValid = fields.every(function (f, i) { if ((0, _typeof2["default"])(f) !== 'object') { (0, _assert["default"])("fields needs to be an array of object, but find ".concat(f)); return false; } if (!f.name) { (0, _assert["default"])("field.name is required but missing in field ".concat(JSON.stringify(f))); // assign a name f.name = "column_".concat(i); } if (!_defaultSettings.ALL_FIELD_TYPES[f.type]) { (0, _assert["default"])("unknown field type ".concat(f.type)); return false; } return f.type !== _defaultSettings.ALL_FIELD_TYPES.timestamp || typeof f.format === 'string'; }); if (allValid) { return { rows: rows, fields: fields }; } // if any field has missing type, recalculate it for everyone // because we simply lost faith in humanity var sampleData = getSampleForTypeAnalyze({ fields: fields.map(function (f) { return f.name; }), allData: rows }); var fieldOrder = fields.map(function (f) { return f.name; }); var meta = getFieldsFromData(sampleData, fieldOrder); var updatedFields = fields.map(function (f, i) { return _objectSpread({}, f, { type: meta[i].type, format: meta[i].format }); }); return { fields: updatedFields, rows: rows }; } /** * Process kepler.gl json to be load by addDataToMap * @param {Object} rawData */ function processKeplerglJSON(rawData) { return rawData ? _schemas["default"].load(rawData.datasets, rawData.config) : null; } var _default = { processGeojson: processGeojson, processCsvData: processCsvData, processRowObject: processRowObject, processKeplerglJSON: processKeplerglJSON, analyzerTypeToFieldType: analyzerTypeToFieldType, getFieldsFromData: getFieldsFromData, parseCsvDataByFieldType: parseCsvDataByFieldType }; exports["default"] = _default; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcm9jZXNzb3JzL2RhdGEtcHJvY2Vzc29yLmpzIl0sIm5hbWVzIjpbIkNTVl9OVUxMUyIsInByb2Nlc3NDc3ZEYXRhIiwicmF3RGF0YSIsImhlYWRlclJvdyIsInJvd3MiLCJsZW5ndGgiLCJjbGVhblVwRmFsc3lDc3ZWYWx1ZSIsInNhbXBsZSIsImdldFNhbXBsZUZvclR5cGVBbmFseXplIiwiZmllbGRzIiwiYWxsRGF0YSIsImdldEZpZWxkc0Zyb21EYXRhIiwiZm9yRWFjaCIsInBhcnNlQ3N2RGF0YUJ5RmllbGRUeXBlIiwiYmluZCIsInNhbXBsZUNvdW50IiwidG90YWwiLCJNYXRoIiwibWluIiwibWFwIiwiZCIsImZpZWxkIiwiZmllbGRJZHgiLCJpIiwiaiIsImluY2x1ZGVzIiwidW5peEZvcm1hdCIsInJvdyIsInR5cGUiLCJBTExfRklFTERfVFlQRVMiLCJyZWFsIiwicGFyc2VGbG9hdCIsInRpbWVzdGFtcCIsImZvcm1hdCIsIk51bWJlciIsImludGVnZXIiLCJwYXJzZUludCIsImRhdGEiLCJmaWVsZE9yZGVyIiwibWV0YWRhdGEiLCJBbmFseXplciIsImNvbXB1dGVDb2xNZXRhIiwicmVnZXgiLCJkYXRhVHlwZSIsInJlbmFtZUR1cGxpY2F0ZUZpZWxkcyIsImZpZWxkQnlJbmRleCIsInJlZHVjZSIsIm9yZGVyZWRBcnJheSIsImluZGV4IiwibmFtZSIsImZpZWxkTWV0YSIsImZpbmQiLCJtIiwia2V5IiwidGFibGVGaWVsZEluZGV4IiwiYW5hbHl6ZXJUeXBlVG9GaWVsZFR5cGUiLCJhY2N1IiwiYWxsTmFtZXMiLCJmaWVsZE5hbWUiLCJjb3VudGVyIiwicHVzaCIsImFUeXBlIiwiREFURSIsIkFuYWx5emVyREFUQV9UWVBFUyIsIlRJTUUiLCJEQVRFVElNRSIsIk5VTUJFUiIsIklOVCIsIkZMT0FUIiwiQk9PTEVBTiIsIlNUUklORyIsIkNJVFkiLCJHRU9NRVRSWSIsIkdFT01FVFJZX0ZST01fU1RSSU5HIiwiWklQQ09ERSIsIlBBSVJfR0VPTUVUUllfRlJPTV9TVFJJTkciLCJkYXRlIiwic3RyaW5nIiwiZ2VvanNvbiIsImdsb2JhbENvbnNvbGUiLCJ3YXJuIiwicHJvY2Vzc1Jvd09iamVjdCIsImtleXMiLCJPYmplY3QiLCJwcm9jZXNzR2VvanNvbiIsIm5vcm1hbGl6ZWRHZW9qc29uIiwiQXJyYXkiLCJpc0FycmF5IiwiZmVhdHVyZXMiLCJmIiwiZ2VvbWV0cnkiLCJfZ2VvanNvbiIsInByb3BlcnRpZXMiLCJwcmV2IiwiY3VyciIsImZvcm1hdENzdiIsImNvbHVtbnMiLCJmb3JtYXR0ZWREYXRhIiwiR0VPSlNPTl9GSUVMRFMiLCJKU09OIiwic3RyaW5naWZ5IiwidmFsaWRhdGVJbnB1dERhdGEiLCJwcm9jZWVkIiwiYWxsVmFsaWQiLCJldmVyeSIsInNhbXBsZURhdGEiLCJtZXRhIiwidXBkYXRlZEZpZWxkcyIsInByb2Nlc3NLZXBsZXJnbEpTT04iLCJLZXBsZXJHbFNjaGVtYSIsImxvYWQiLCJkYXRhc2V0cyIsImNvbmZpZyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFvQkE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7Ozs7OztBQUVBO0FBQ0EsSUFBTUEsU0FBUyxHQUFHLENBQUMsRUFBRCxFQUFLLE1BQUwsRUFBYSxNQUFiLEVBQXFCLE1BQXJCLEVBQTZCLEtBQTdCLENBQWxCOztBQUVPLFNBQVNDLGNBQVQsQ0FBd0JDLE9BQXhCLEVBQWlDO0FBQ3RDO0FBQ0E7QUFDQTtBQUhzQyxzQkFJVCx5QkFBYUEsT0FBYixDQUpTO0FBQUE7QUFBQSxNQUkvQkMsU0FKK0I7QUFBQSxNQUlqQkMsSUFKaUI7O0FBTXRDLE1BQUksQ0FBQ0EsSUFBSSxDQUFDQyxNQUFOLElBQWdCLENBQUNGLFNBQXJCLEVBQWdDO0FBQzlCO0FBQ0E7QUFDQSxXQUFPLElBQVA7QUFDRDs7QUFFREcsRUFBQUEsb0JBQW9CLENBQUNGLElBQUQsQ0FBcEIsQ0Fac0MsQ0Fh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QWlCLENBQUM4RixVQUFELEVBQWFuRSxVQUFiLENBQTlCO0FBQ0EsTUFBTXFFLGFBQWEsR0FBR2xHLE1BQU0sQ0FBQ1UsR0FBUCxDQUFXLFVBQUNzRSxDQUFELEVBQUlsRSxDQUFKO0FBQUEsNkJBQzVCa0UsQ0FENEI7QUFFL0I3RCxNQUFBQSxJQUFJLEVBQUU4RSxJQUFJLENBQUNuRixDQUFELENBQUosQ0FBUUssSUFGaUI7QUFHL0JLLE1BQUFBLE1BQU0sRUFBRXlFLElBQUksQ0FBQ25GLENBQUQsQ0FBSixDQUFRVTtBQUhlO0FBQUEsR0FBWCxDQUF0QjtBQU1BLFNBQU87QUFBQ3hCLElBQUFBLE1BQU0sRUFBRWtHLGFBQVQ7QUFBd0J2RyxJQUFBQSxJQUFJLEVBQUpBO0FBQXhCLEdBQVA7QUFDRDtBQUVEOzs7Ozs7QUFJTyxTQUFTd0csbUJBQVQsQ0FBNkIxRyxPQUE3QixFQUFzQztBQUMzQyxTQUFPQSxPQUFPLEdBQUcyRyxvQkFBZUMsSUFBZixDQUFvQjVHLE9BQU8sQ0FBQzZHLFFBQTVCLEVBQXNDN0csT0FBTyxDQUFDOEcsTUFBOUMsQ0FBSCxHQUEyRCxJQUF6RTtBQUNEOztlQUVjO0FBQ2I1QixFQUFBQSxjQUFjLEVBQWRBLGNBRGE7QUFFYm5GLEVBQUFBLGNBQWMsRUFBZEEsY0FGYTtBQUdiZ0YsRUFBQUEsZ0JBQWdCLEVBQWhCQSxnQkFIYTtBQUliMkIsRUFBQUEsbUJBQW1CLEVBQW5CQSxtQkFKYTtBQUtickQsRUFBQUEsdUJBQXVCLEVBQXZCQSx1QkFMYTtBQU1iNUMsRUFBQUEsaUJBQWlCLEVBQWpCQSxpQkFOYTtBQU9iRSxFQUFBQSx1QkFBdUIsRUFBdkJBO0FBUGEsQyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAoYykgMjAxOSBVYmVyIFRlY2hub2xvZ2llcywgSW5jLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbi8vIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbi8vIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbi8vIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxuLy8gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7Y3N2UGFyc2VSb3dzLCBjc3ZGb3JtYXRSb3dzfSBmcm9tICdkMy1kc3YnO1xuaW1wb3J0IHtyYW5nZX0gZnJvbSAnZDMtYXJyYXknO1xuaW1wb3J0IHtjb25zb2xlIGFzIGdsb2JhbENvbnNvbGV9IGZyb20gJ2dsb2JhbC93aW5kb3cnO1xuaW1wb3J0IGFzc2VydCBmcm9tICdhc3NlcnQnO1xuaW1wb3J0IHtBbmFseXplciwgREFUQV9UWVBFUyBhcyBBbmFseXplckRBVEFfVFlQRVN9IGZyb20gJ3R5cGUtYW5hbHl6ZXItZ2VvaXEnO1xuaW1wb3J0IG5vcm1hbGl6ZSBmcm9tICdAbWFwYm94L2dlb2pzb24tbm9ybWFsaXplJztcbmltcG9ydCB7QUxMX0ZJRUxEX1RZUEVTLCBHRU9KU09OX0ZJRUxEU30gZnJvbSAnY29uc3RhbnRzL2RlZmF1bHQtc2V0dGluZ3MnO1xuaW1wb3J0IHtub3ROdWxsb3JVbmRlZmluZWR9IGZyb20gJ3V0aWxzL2RhdGEtdXRpbHMnO1xuaW1wb3J0IEtlcGxlckdsU2NoZW1hIGZyb20gJ3NjaGVtYXMnO1xuXG4vLyBpZiBhbnkgb2YgdGhlc2UgdmFsdWUgb2NjdXJzIGluIGNzdiwgcGFyc2UgaXQgdG8gbnVsbDtcbmNvbnN0IENTVl9OVUxMUyA9IFsnJywgJ251bGwnLCAnTlVMTCcsICdOdWxsJywgJ05hTiddO1xuXG5leHBvcnQgZnVuY3Rpb24gcHJvY2Vzc0NzdkRhdGEocmF3RGF0YSkge1xuICAvLyBoZXJlIHdlIGFzc3VtZSB0aGUgY3N2IGZpbGUgdGhhdCBwZW9wbGUgdXBsb2FkZWQgd2lsbCBoYXZlIGZpcnN0IHJvd1xuICAvLyBhcyBuYW1lIG9mIHRoZSBjb2x1bW5cbiAgLy8gVE9ETzogYWRkIGEgYWxlcnQgYXQgdXBsb2FkIGNzdiB0byByZW1pbmQgZGVmaW5lIGZpcnN0IHJvd1xuICBjb25zdCBbaGVhZGVyUm93LCAuLi5yb3dzXSA9IGNzdlBhcnNlUm93cyhyYXdEYXRhKTtcblxuICBpZiAoIXJvd3MubGVuZ3RoIHx8ICFoZWFkZXJSb3cpIHtcbiAgICAvLyBsb29rcyBsaWtlIGFuIGVtcHR5IGZpbGVcbiAgICAvLyByZXNvbHZlIG51bGwsIGFuZCBjYXRjaCB0aGVtIGxhdGVyIGluIG9uZSBwbGFjZVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY2xlYW5VcEZhbHN5Q3N2VmFsdWUocm93cyk7XG4gIC8vIE5vIG5lZWQgdG8gcnVuIHR5cGUgZGV0ZWN0aW9uIG9uIGV2ZXJ5IGRhdGEgcG9pbnRcbiAgLy8gaGVyZSB3ZSBnZXQgYSBsaXN0IG9mIG5vbmUgbnVsbCB2YWx1ZXMgdG8gcnVuIGFuYWx5emUgb25cbiAgY29uc3Qgc2FtcGxlID0gZ2V0U2FtcGxlRm9yVHlwZUFuYWx5emUoe2ZpZWxkczogaGVhZGVyUm93LCBhbGxEYXRhOiByb3dzfSk7XG5cbiAgY29uc3QgZmllbGRzID0gZ2V0RmllbGRzRnJvbURhdGEoc2FtcGxlLCBoZWFkZXJSb3cpO1xuXG4gIGZpZWxkcy5mb3JFYWNoKHBhcnNlQ3N2RGF0YUJ5RmllbGRUeXBlLmJpbmQobnVsbCwgcm93cykpO1xuXG4gIHJldHVybiB7ZmllbGRzLCByb3dzfTtcbn1cblxuLyoqXG4gKiBnZXQgZmllbGRzIGZyb20gY3N2IGRhdGFcbiAqXG4gKiBAcGFyYW0ge2FycmF5fSBmaWVsZHMgLSBhbiBhcnJheSBvZiBmaWVsZHMgbmFtZVxuICogQHBhcmFtIHthcnJheX0gYWxsRGF0YVxuICogQHBhcmFtIHthcnJheX0gc2FtcGxlQ291bnRcbiAqIEByZXR1cm5zIHthcnJheX0gZm9ybWF0dGVkIGZpZWxkc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2FtcGxlRm9yVHlwZUFuYWx5emUoe2ZpZWxkcywgYWxsRGF0YSwgc2FtcGxlQ291bnQgPSA1MH0pIHtcbiAgY29uc3QgdG90YWwgPSBNYXRoLm1pbihzYW1wbGVDb3VudCwgYWxsRGF0YS5sZW5ndGgpO1xuICAvLyBjb25zdCBmaWVsZE9yZGVyID0gZmllbGRzLm1hcChmID0+IGYubmFtZSk7XG4gIGNvbnN0IHNhbXBsZSA9IHJhbmdlKDAsIHRvdGFsLCAxKS5tYXAoZCA9PiAoe30pKTtcblxuICAvLyBjb2xsZWN0IHNhbXBsZSBkYXRhIGZvciBlYWNoIGZpZWxkXG4gIGZpZWxkcy5mb3JFYWNoKChmaWVsZCwgZmllbGRJZHgpID0+IHtcbiAgICAvLyBkYXRhIGNvdW50ZXJcbiAgICBsZXQgaSA9IDA7XG4gICAgLy8gc2FtcGxlIGNvdW50ZXJcbiAgICBsZXQgaiA9IDA7XG5cbiAgICB3aGlsZSAoaiA8IHRvdGFsKSB7XG4gICAgICBpZiAoaSA+PSBhbGxEYXRhLmxlbmd0aCkge1xuICAgICAgICAvLyBpZiBkZXBsZXRlZCBkYXRhIHBvb2xcbiAgICAgICAgc2FtcGxlW2pdW2ZpZWxkXSA9IG51bGw7XG4gICAgICAgIGorKztcbiAgICAgIH0gZWxzZSBpZiAobm90TnVsbG9yVW5kZWZpbmVkKGFsbERhdGFbaV1bZmllbGRJZHhdKSkge1xuICAgICAgICBzYW1wbGVbal1bZmllbGRdID0gYWxsRGF0YVtpXVtmaWVsZElkeF07XG4gICAgICAgIGorKztcbiAgICAgICAgaSsrO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaSsrO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIHNhbXBsZTtcbn1cblxuZnVuY3Rpb24gY2xlYW5VcEZhbHN5Q3N2VmFsdWUocm93cykge1xuICBmb3IgKGxldCBpID0gMDsgaSA8IHJvd3MubGVuZ3RoOyBpKyspIHtcbiAgICBmb3IgKGxldCBqID0gMDsgaiA8IHJvd3NbaV0ubGVuZ3RoOyBqKyspIHtcbiAgICAgIC8vIGFuYWx5emVyIHdpbGwgc2V0IGFueSBmaWVsZHMgdG8gJ3N0cmluZycgaWYgdGhlcmUgYXJlIGVtcHR5IHZhbHVlc1xuICAgICAgLy8gd2hpY2ggd2lsbCBiZSBwYXJzZWQgYXMgJycgYnkgZDMuY3N2XG4gICAgICAvLyBoZXJlIHdlIHBhcnNlIGVtcHR5IGRhdGEgYXMgbnVsbFxuICAgICAgLy8gVE9ETzogY3JlYXRlIHdhcm5pbmcgd2hlbiBkZWx0ZWN0IGBDU1ZfTlVMTFNgIGluIHRoZSBkYXRhXG4gICAgICBpZiAoIXJvd3NbaV1bal0gfHwgQ1NWX05VTExTLmluY2x1ZGVzKHJvd3NbaV1bal0pKSB7XG4gICAgICAgIHJvd3NbaV1bal0gPSBudWxsO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuLyoqXG4gKiBQcm9jZXNzIHVwbG9hZGVkIGNzdiBmaWxlIHRvIHBhcnNlIHZhbHVlIGJ5IGZpZWxkIHR5cGVcbiAqXG4gKiBAcGFyYW0ge2FycmF5fSByb3dzXG4gKiBAcGFyYW0ge29iamVjdH0gZmllbGRcbiAqIEBwYXJhbSB7bnVtYmVyfSBpXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQ3N2RGF0YUJ5RmllbGRUeXBlKHJvd3MsIGZpZWxkLCBpKSB7XG4gIGNvbnN0IHVuaXhGb3JtYXQgPSBbJ3gnLCAnWCddO1xuXG4gIHJvd3MuZm9yRWFjaChyb3cgPT4ge1xuICAgIGlmIChyb3dbaV0gIT09IG51bGwpIHtcbiAgICAgIHN3aXRjaCAoZmllbGQudHlwZSkge1xuICAgICAgICBjYXNlIEFMTF9GSUVMRF9UWVBFUy5yZWFsOlxuICAgICAgICAgIHJvd1tpXSA9IHBhcnNlRmxvYXQocm93W2ldKTtcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICAvLyBUT0RPOiB0aW1lc3RhbXAgY2FuIGJlIGVpdGhlciAnMTQ5NTgyNzMyNicgb3IgJzIwMTYtMDMtMTAgMTE6MjAnXG4gICAgICAgIC8vIGlmIGl0J3MgJzE0OTU4MjczMjYnIHdlIHBhc3MgaXQgdG8gaW50XG4gICAgICAgIGNhc2UgQUxMX0ZJRUxEX1RZUEVTLnRpbWVzdGFtcDpcbiAgICAgICAgICByb3dbaV0gPSB1bml4Rm9ybWF0LmluY2x1ZGVzKGZpZWxkLmZvcm1hdCkgPyBOdW1iZXIocm93W2ldKSA6IHJvd1tpXTtcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICBjYXNlIEFMTF9GSUVMRF9UWVBFUy5pbnRlZ2VyOlxuICAgICAgICAgIHJvd1tpXSA9IHBhcnNlSW50KHJvd1tpXSwgMTApO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGNhc2UgQUxMX0ZJRUxEX1RZUEVTLmJvb2xlYW46XG4gICAgICAgICAgLy8gMCBhbmQgMSBvbmx5IGZpZWxkIGNhbiBhbHNvIGJlIGJvb2xlYW5cbiAgICAgICAgICByb3dbaV0gPSByb3dbaV0gPT09ICd0cnVlJyB8fCByb3dbaV0gPT09ICdUcnVlJyB8fCByb3dbaV0gPT09ICcxJztcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogZ2V0IGZpZWxkcyBmcm9tIGNzdiBkYXRhXG4gKlxuICogQHBhcmFtIHthcnJheX0gZGF0YVxuICogQHBhcmFtIHthcnJheX0gZmllbGRPcmRlclxuICogQHJldHVybnMge2FycmF5fSBmb3JtYXR0ZWQgZmllbGRzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRGaWVsZHNGcm9tRGF0YShkYXRhLCBmaWVsZE9yZGVyKSB7XG4gIC8vIGFkZCBhIGNoZWNrIGZvciBlcG9jaCB0aW1lc3RhbXBcbiAgY29uc3QgbWV0YWRhdGEgPSBBbmFseXplci5jb21wdXRlQ29sTWV0YShkYXRhLCBbXG4gICAge3JlZ2V4OiAvLipnZW9qc29ufGFsbF9wb2ludHMvZywgZGF0YVR5cGU6ICdHRU9NRVRSWSd9XG4gIF0pO1xuXG4gIGNvbnN0IHtmaWVsZEJ5SW5kZXh9ID0gcmVuYW1lRHVwbGljYXRlRmllbGRzKGZpZWxkT3JkZXIpO1xuXG4gIHJldHVybiBmaWVsZE9yZGVyLnJlZHVjZSgob3JkZXJlZEFycmF5LCBmaWVsZCwgaW5kZXgpID0+IHtcbiAgICBjb25zdCBuYW1lID0gZmllbGRCeUluZGV4W2luZGV4XTtcbiAgICBjb25zdCBmaWVsZE1ldGEgPSBtZXRhZGF0YS5maW5kKG0gPT4gbS5rZXkgPT09IGZpZWxkKTtcbiAgICBjb25zdCB7dHlwZSwgZm9ybWF0fSA9IGZpZWxkTWV0YSB8fCB7fTtcblxuICAgIG9yZGVyZWRBcnJheVtpbmRleF0gPSB7XG4gICAgICBuYW1lLFxuICAgICAgZm9ybWF0LFxuXG4gICAgICAvLyBuZWVkIHRoaXMgZm9yIG1hcGJ1aWxkZXIgY29udmVyc2lvbjogZmlsdGVyIHR5cGUgZGV0ZWN0aW9uXG4gICAgICAvLyBjYXRlZ29yeSxcbiAgICAgIHRhYmxlRmllbGRJbmRleDogaW5kZXggKyAxLFxuICAgICAgdHlwZTogYW5hbHl6ZXJUeXBlVG9GaWVsZFR5cGUodHlwZSlcbiAgICB9O1xuICAgIC8vIGNvbnNvbGUubG9nKG9yZGVyZWRBcnJheSk7XG4gICAgcmV0dXJuIG9yZGVyZWRBcnJheTtcbiAgfSwgW10pO1xufVxuXG4vKipcbiAqIHBhc3MgaW4gYW4gYXJyYXkgb2YgZmllbGQgbmFtZXMsIHJlbmFtZSBkdXBsaWNhdGVkIG9uZVxuICogYW5kIHJldHVybiBhIG1hcCBmcm9tIG9sZCBmaWVsZCBpbmRleCB0byBuZXcgbmFtZVxuICpcbiAqIEBwYXJhbSB7YXJyYXl9IGZpZWxkT3JkZXJcbiAqIEByZXR1cm5zIHtPYmplY3R9IG5ldyBmaWVsZCBuYW1lIGJ5IGluZGV4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZW5hbWVEdXBsaWNhdGVGaWVsZHMoZmllbGRPcmRlcikge1xuICByZXR1cm4gZmllbGRPcmRlci5yZWR1Y2UoXG4gICAgKGFjY3UsIGZpZWxkLCBpKSA9PiB7XG4gICAgICBjb25zdCB7YWxsTmFtZXN9ID0gYWNjdTtcbiAgICAgIGxldCBmaWVsZE5hbWUgPSBmaWVsZDtcblxuICAgICAgLy8gYWRkIGEgY291bnRlciB0byBkdXBsaWNhdGVkIG5hbWVzXG4gICAgICBpZiAoYWxsTmFtZXMuaW5jbHVkZXMoZmllbGQpKSB7XG4gICAgICAgIGxldCBjb3VudGVyID0gMDtcbiAgICAgICAgd2hpbGUgKGFsbE5hbWVzLmluY2x1ZGVzKGAke2ZpZWxkfS0ke2NvdW50ZXJ9YCkpIHtcbiAgICAgICAgICBjb3VudGVyKys7XG4gICAgICAgIH1cbiAgICAgICAgZmllbGROYW1lID0gYCR7ZmllbGR9LSR7Y291bnRlcn1gO1xuICAgICAgfVxuXG4gICAgICBhY2N1LmZpZWxkQnlJbmRleFtpXSA9IGZpZWxkTmFtZTtcbiAgICAgIGFjY3UuYWxsTmFtZXMucHVzaChmaWVsZE5hbWUpO1xuXG4gICAgICByZXR1cm4gYWNjdTtcbiAgICB9LFxuICAgIHthbGxOYW1lczogW10sIGZpZWxkQnlJbmRleDoge319XG4gICk7XG59XG5cbi8qKlxuICogTWFwIEFuYWx5emVyIHR5cGVzIHRvIGxvY2FsIGZpZWxkIHR5cGVzXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGFUeXBlXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBjb3JyZXNwb25kaW5nIHR5cGUgaW4gQUxMX0ZJRUxEX1RZUEVTXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIGNvbXBsZXhpdHkgKi9cbmV4cG9ydCBmdW5jdGlvbiBhbmFseXplclR5cGVUb0ZpZWxkVHlwZShhVHlwZSkge1xuICBjb25zdCB7XG4gICAgREFURSxcbiAgICBUSU1FLFxuICAgIERBVEVUSU1FLFxuICAgIE5VTUJFUixcbiAgICBJTlQsXG4gICAgRkxPQVQsXG4gICAgQk9PTEVBTixcbiAgICBTVFJJTkcsXG4gICAgQ0lUWSxcbiAgICBHRU9NRVRSWSxcbiAgICBHRU9NRVRSWV9GUk9NX1NUUklORyxcbiAgICBaSVBDT0RFLFxuICAgIFBBSVJfR0VPTUVUUllfRlJPTV9TVFJJTkdcbiAgfSA9IEFuYWx5emVyREFUQV9UWVBFUztcblxuICAvLyBUT0RPOiB1biByZWNvZ25pemVkIHR5cGVzXG4gIC8vIENVUlJFTkNZIFBFUkNFTlQgTk9ORVxuICBzd2l0Y2ggKGFUeXBlKSB7XG4gICAgY2FzZSBEQVRFOlxuICAgICAgcmV0dXJuIEFMTF9GSUVMRF9UWVBFUy5kYXRlO1xuICAgIGNhc2UgVElNRTpcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMuc3RyaW5nO1xuICAgIGNhc2UgREFURVRJTUU6XG4gICAgICByZXR1cm4gQUxMX0ZJRUxEX1RZUEVTLnRpbWVzdGFtcDtcbiAgICBjYXNlIE5VTUJFUjpcbiAgICBjYXNlIEZMT0FUOlxuICAgICAgcmV0dXJuIEFMTF9GSUVMRF9UWVBFUy5yZWFsO1xuICAgIGNhc2UgSU5UOlxuICAgICAgcmV0dXJuIEFMTF9GSUVMRF9UWVBFUy5pbnRlZ2VyO1xuICAgIGNhc2UgQk9PTEVBTjpcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMuYm9vbGVhbjtcbiAgICBjYXNlIEdFT01FVFJZOlxuICAgIGNhc2UgR0VPTUVUUllfRlJPTV9TVFJJTkc6XG4gICAgY2FzZSBQQUlSX0dFT01FVFJZX0ZST01fU1RSSU5HOlxuICAgICAgcmV0dXJuIEFMTF9GSUVMRF9UWVBFUy5nZW9qc29uO1xuICAgIGNhc2UgU1RSSU5HOlxuICAgIGNhc2UgQ0lUWTpcbiAgICBjYXNlIFpJUENPREU6XG4gICAgICByZXR1cm4gQUxMX0ZJRUxEX1RZUEVTLnN0cmluZztcbiAgICBkZWZhdWx0OlxuICAgICAgZ2xvYmFsQ29uc29sZS53YXJuKGBVbnN1cHBvcnRlZCBhbmFseXplciB0eXBlOiAke2FUeXBlfWApO1xuICAgICAgcmV0dXJuIEFMTF9GSUVMRF9UWVBFUy5zdHJpbmc7XG4gIH1cbn1cbi8qIGVzbGludC1lbmFibGUgY29tcGxleGl0eSAqL1xuXG4vKlxuICogUHJvY2VzcyByYXdEYXRhIHdoZXJlIGVhY2ggcm93IGlzIGFuIG9iamVjdFxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJvY2Vzc1Jvd09iamVjdChyYXdEYXRhKSB7XG4gIGlmICghcmF3RGF0YS5sZW5ndGgpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyhyYXdEYXRhWzBdKTtcbiAgY29uc3Qgcm93cyA9IHJhd0RhdGEubWFwKGQgPT4ga2V5cy5tYXAoa2V5ID0+IGRba2V5XSkpO1xuICBjb25zdCBmaWVsZHMgPSBnZXRGaWVsZHNGcm9tRGF0YShyYXdEYXRhLCBrZXlzKTtcblxuICByZXR1cm4ge1xuICAgIGZpZWxkcyxcbiAgICByb3dzXG4gIH07XG59XG5cbi8qKlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSByYXdEYXRhIC0gcmF3IGdlb2pzb24gZmVhdHVyZSBjb2xsZWN0aW9uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcm9jZXNzR2VvanNvbihyYXdEYXRhKSB7XG4gIGNvbnN0IG5vcm1hbGl6ZWRHZW9qc29uID0gbm9ybWFsaXplKHJhd0RhdGEpO1xuXG4gIGlmICghbm9ybWFsaXplZEdlb2pzb24gfHwgIUFycmF5LmlzQXJyYXkobm9ybWFsaXplZEdlb2pzb24uZmVhdHVyZXMpKSB7XG4gICAgLy8gZmFpbCB0byBub3JtYWxpemUgZ2VvanNvblxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLy8gZ2V0dGluZyBhbGwgZmVhdHVyZSBmaWVsZHNcbiAgY29uc3QgYWxsRGF0YSA9IG5vcm1hbGl6ZWRHZW9qc29uLmZlYXR1cmVzLnJlZHVjZSgoYWNjdSwgZiwgaSkgPT4ge1xuICAgIGlmIChmLmdlb21ldHJ5KSB7XG4gICAgICBhY2N1LnB1c2goe1xuICAgICAgICAvLyBhZGQgZmVhdHVyZSB0byBfZ2VvanNvbiBmaWVsZFxuICAgICAgICBfZ2VvanNvbjogZixcbiAgICAgICAgLi4uKGYucHJvcGVydGllcyB8fCB7fSlcbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gYWNjdTtcbiAgfSwgW10pO1xuXG4gIC8vIGdldCBhbGwgdGhlIGZpZWxkXG4gIGNvbnN0IGZpZWxkcyA9IGFsbERhdGEucmVkdWNlKChwcmV2LCBjdXJyKSA9PiB7XG4gICAgT2JqZWN0LmtleXMoY3VycikuZm9yRWFjaChrZXkgPT4ge1xuICAgICAgaWYgKCFwcmV2LmluY2x1ZGVzKGtleSkpIHtcbiAgICAgICAgcHJldi5wdXNoKGtleSk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIHByZXY7XG4gIH0sIFtdKTtcblxuICAvLyBtYWtlIHN1cmUgZWFjaCBmZWF0dXJlIGhhcyBleGFjdCBzYW1lIGZpZWxkc1xuICBhbGxEYXRhLmZvckVhY2goZCA9PiB7XG4gICAgZmllbGRzLmZvckVhY2goZiA9PiB7XG4gICAgICBpZiAoIShmIGluIGQpKSB7XG4gICAgICAgIGRbZl0gPSBudWxsO1xuICAgICAgfVxuICAgIH0pO1xuICB9KTtcblxuICAvLyBjb25zb2xlLmxvZyhwcm9jZXNzUm93T2JqZWN0KGFsbERhdGEpKVxuICByZXR1cm4gcHJvY2Vzc1Jvd09iamVjdChhbGxEYXRhKTtcblxufVxuXG4vKipcbiAqIE9uIGV4cG9ydCBkYXRhIHRvIGNzdlxuICogQHBhcmFtIGRhdGFcbiAqIEBwYXJhbSBmaWVsZHNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdENzdihkYXRhLCBmaWVsZHMpIHtcbiAgY29uc3QgY29sdW1ucyA9IGZpZWxkcy5tYXAoZiA9PiBmLm5hbWUpO1xuICBjb25zdCBmb3JtYXR0ZWREYXRhID0gW2NvbHVtbnNdO1xuXG4gIC8vIHBhcnNlIGdlb2pzb24gb2JqZWN0IGFzIHN0cmluZ1xuICBkYXRhLmZvckVhY2gocm93ID0+IHtcbiAgICBmb3JtYXR0ZWREYXRhLnB1c2goXG4gICAgICByb3cubWFwKChkLCBpKSA9PlxuICAgICAgICBkICYmIEdFT0pTT05fRklFTERTLmdlb2pzb24uaW5jbHVkZXMoZmllbGRzW2ldLm5hbWUpXG4gICAgICAgICAgPyBKU09OLnN0cmluZ2lmeShkKVxuICAgICAgICAgIDogZFxuICAgICAgKVxuICAgICk7XG4gIH0pO1xuXG4gIHJldHVybiBjc3ZGb3JtYXRSb3dzKGZvcm1hdHRlZERhdGEpO1xufVxuXG4vKipcbiAqIEBwYXJhbSBkYXRhXG4gKiBAcmV0dXJucyB7e2FsbERhdGE6IEFycmF5LCBmaWVsZHM6IEFycmF5fX1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlSW5wdXREYXRhKGRhdGEpIHtcbiAgLy8gVE9ETzogYWRkIHRlc3RcbiAgLypcbiAgICogZXhwZWN0ZWQgaW5wdXQgZGF0YSBmb3JtYXRcbiAgICoge1xuICAgKiAgIGZpZWxkczogW10sXG4gICAqICAgcm93czogW11cbiAgICogfVxuICAgKi9cbiAgbGV0IHByb2NlZWQgPSB0cnVlO1xuICBpZiAoIWRhdGEpIHtcbiAgICBhc3NlcnQoJ3JlY2VpdmVWaXNEYXRhOiBkYXRhIGNhbm5vdCBiZSBudWxsJyk7XG4gICAgcHJvY2VlZCA9IGZhbHNlO1xuICB9IGVsc2UgaWYgKCFBcnJheS5pc0FycmF5KGRhdGEuZmllbGRzKSkge1xuICAgIGFzc2VydCgncmVjZWl2ZVZpc0RhdGE6IGV4cGVjdCBkYXRhLmZpZWxkcyB0byBiZSBhbiBhcnJheScpO1xuICAgIHByb2NlZWQgPSBmYWxzZTtcbiAgfSBlbHNlIGlmICghQXJyYXkuaXNBcnJheShkYXRhLnJvd3MpKSB7XG4gICAgYXNzZXJ0KCdyZWNlaXZlVmlzRGF0YTogZXhwZWN0IGRhdGEucm93cyB0byBiZSBhbiBhcnJheScpO1xuICAgIHByb2NlZWQgPSBmYWxzZTtcbiAgfVxuXG4gIGlmICghcHJvY2VlZCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3Qge2ZpZWxkcywgcm93c30gPSBkYXRhO1xuXG4gIC8vIGNoZWNrIGlmIGFsbCBmaWVsZHMgaGFzIG5hbWUsIGZvcm1hdCBhbmQgdHlwZVxuICBjb25zdCBhbGxWYWxpZCA9IGZpZWxkcy5ldmVyeSgoZiwgaSkgPT4ge1xuICAgIGlmICh0eXBlb2YgZiAhPT0gJ29iamVjdCcpIHtcbiAgICAgIGFzc2VydChgZmllbGRzIG5lZWRzIHRvIGJlIGFuIGFycmF5IG9mIG9iamVjdCwgYnV0IGZpbmQgJHtmfWApO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmICghZi5uYW1lKSB7XG4gICAgICBhc3NlcnQoXG4gICAgICAgIGBmaWVsZC5uYW1lIGlzIHJlcXVpcmVkIGJ1dCBtaXNzaW5nIGluIGZpZWxkICR7SlNPTi5zdHJpbmdpZnkoZil9YFxuICAgICAgKTtcbiAgICAgIC8vIGFzc2lnbiBhIG5hbWVcbiAgICAgIGYubmFtZSA9IGBjb2x1bW5fJHtpfWA7XG4gICAgfVxuXG4gICAgaWYgKCFBTExfRklFTERfVFlQRVNbZi50eXBlXSkge1xuICAgICAgYXNzZXJ0KGB1bmtub3duIGZpZWxkIHR5cGUgJHtmLnR5cGV9YCk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIGYudHlwZSAhPT0gQUxMX0ZJRUxEX1RZUEVTLnRpbWVzdGFtcCB8fCB0eXBlb2YgZi5mb3JtYXQgPT09ICdzdHJpbmcnO1xuICB9KTtcblxuICBpZiAoYWxsVmFsaWQpIHtcbiAgICByZXR1cm4ge3Jvd3MsIGZpZWxkc307XG4gIH1cblxuICAvLyBpZiBhbnkgZmllbGQgaGFzIG1pc3NpbmcgdHlwZSwgcmVjYWxjdWxhdGUgaXQgZm9yIGV2ZXJ5b25lXG4gIC8vIGJlY2F1c2Ugd2Ugc2ltcGx5IGxvc3QgZmFpdGggaW4gaHVtYW5pdHlcbiAgY29uc3Qgc2FtcGxlRGF0YSA9IGdldFNhbXBsZUZvclR5cGVBbmFseXplKHtcbiAgICBmaWVsZHM6IGZpZWxkcy5tYXAoZiA9PiBmLm5hbWUpLFxuICAgIGFsbERhdGE6IHJvd3NcbiAgfSk7XG4gIGNvbnN0IGZpZWxkT3JkZXIgPSBmaWVsZHMubWFwKGYgPT4gZi5uYW1lKTtcbiAgY29uc3QgbWV0YSA9IGdldEZpZWxkc0Zyb21EYXRhKHNhbXBsZURhdGEsIGZpZWxkT3JkZXIpO1xuICBjb25zdCB1cGRhdGVkRmllbGRzID0gZmllbGRzLm1hcCgoZiwgaSkgPT4gKHtcbiAgICAuLi5mLFxuICAgIHR5cGU6IG1ldGFbaV0udHlwZSxcbiAgICBmb3JtYXQ6IG1ldGFbaV0uZm9ybWF0XG4gIH0pKTtcblxuICByZXR1cm4ge2ZpZWxkczogdXBkYXRlZEZpZWxkcywgcm93c307XG59XG5cbi8qKlxuICogUHJvY2VzcyBrZXBsZXIuZ2wganNvbiB0byBiZSBsb2FkIGJ5IGFkZERhdGFUb01hcFxuICogQHBhcmFtIHtPYmplY3R9IHJhd0RhdGFcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByb2Nlc3NLZXBsZXJnbEpTT04ocmF3RGF0YSkge1xuICByZXR1cm4gcmF3RGF0YSA/IEtlcGxlckdsU2NoZW1hLmxvYWQocmF3RGF0YS5kYXRhc2V0cywgcmF3RGF0YS5jb25maWcpIDogbnVsbDtcbn1cblxuZXhwb3J0IGRlZmF1bHQge1xuICBwcm9jZXNzR2VvanNvbixcbiAgcHJvY2Vzc0NzdkRhdGEsXG4gIHByb2Nlc3NSb3dPYmplY3QsXG4gIHByb2Nlc3NLZXBsZXJnbEpTT04sXG4gIGFuYWx5emVyVHlwZVRvRmllbGRUeXBlLFxuICBnZXRGaWVsZHNGcm9tRGF0YSxcbiAgcGFyc2VDc3ZEYXRhQnlGaWVsZFR5cGVcbn07XG4iXX0=