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
JavaScript
;
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=