kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
489 lines (411 loc) • 42.7 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof2 = require('babel-runtime/helpers/typeof');
var _typeof3 = _interopRequireDefault(_typeof2);
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _toArray2 = require('babel-runtime/helpers/toArray');
var _toArray3 = _interopRequireDefault(_toArray2);
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;
var _d3Dsv = require('d3-dsv');
var _d3Array = require('d3-array');
var _window = require('global/window');
var _assert = require('assert');
var _assert2 = _interopRequireDefault(_assert);
var _typeAnalyzer = require('type-analyzer');
var _geojsonNormalize = require('@mapbox/geojson-normalize');
var _geojsonNormalize2 = _interopRequireDefault(_geojsonNormalize);
var _defaultSettings = require('../constants/default-settings');
var _dataUtils = require('../utils/data-utils');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// if any of these value occurs in csv, parse it to null;
// Copyright (c) 2018 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.
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
var _csvParseRows = (0, _d3Dsv.csvParseRows)(rawData),
_csvParseRows2 = (0, _toArray3.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 === undefined ? 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 = _typeAnalyzer.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)
};
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(field + '-' + counter)) {
counter++;
}
fieldName = field + '-' + 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 = _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,
CITY = _typeAnalyzer.DATA_TYPES.CITY,
GEOMETRY = _typeAnalyzer.DATA_TYPES.GEOMETRY,
GEOMETRY_FROM_STRING = _typeAnalyzer.DATA_TYPES.GEOMETRY_FROM_STRING,
ZIPCODE = _typeAnalyzer.DATA_TYPES.ZIPCODE,
PAIR_GEOMETRY_FROM_STRING = _typeAnalyzer.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:
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: ' + 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
};
}
function processGeojson(rawData) {
var normalizedGeojson = (0, _geojsonNormalize2.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((0, _extends3.default)({
// 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;
}
});
});
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, _assert2.default)('receiveVisData: data cannot be null');
proceed = false;
} else if (!Array.isArray(data.fields)) {
(0, _assert2.default)('receiveVisData: expect data.fields to be an array');
proceed = false;
} else if (!Array.isArray(data.rows)) {
(0, _assert2.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 ((typeof f === 'undefined' ? 'undefined' : (0, _typeof3.default)(f)) !== 'object') {
(0, _assert2.default)('fields needs to be an array of object, but find ' + f);
return false;
}
if (!f.name) {
(0, _assert2.default)('field.name is required but missing in field ' + JSON.stringify(f));
// assign a name
f.name = 'column_' + i;
}
if (!_defaultSettings.ALL_FIELD_TYPES[f.type]) {
(0, _assert2.default)('unknown field type ' + f.type);
return false;
}
return f.type && f.format && f.name;
});
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 (0, _extends3.default)({}, f, {
type: meta[i].type,
format: meta[i].format
});
});
return { fields: updatedFields, rows: rows };
}
exports.default = {
processGeojson: processGeojson,
processCsvData: processCsvData,
processRowObject: processRowObject,
analyzerTypeToFieldType: analyzerTypeToFieldType,
getFieldsFromData: getFieldsFromData,
parseCsvDataByFieldType: parseCsvDataByFieldType
};
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9wcm9jZXNzb3JzL2RhdGEtcHJvY2Vzc29yLmpzIl0sIm5hbWVzIjpbInByb2Nlc3NDc3ZEYXRhIiwiZ2V0U2FtcGxlRm9yVHlwZUFuYWx5emUiLCJwYXJzZUNzdkRhdGFCeUZpZWxkVHlwZSIsImdldEZpZWxkc0Zyb21EYXRhIiwicmVuYW1lRHVwbGljYXRlRmllbGRzIiwiYW5hbHl6ZXJUeXBlVG9GaWVsZFR5cGUiLCJwcm9jZXNzUm93T2JqZWN0IiwicHJvY2Vzc0dlb2pzb24iLCJmb3JtYXRDc3YiLCJ2YWxpZGF0ZUlucHV0RGF0YSIsIkNTVl9OVUxMUyIsInJhd0RhdGEiLCJoZWFkZXJSb3ciLCJyb3dzIiwibGVuZ3RoIiwiY2xlYW5VcEZhbHN5Q3N2VmFsdWUiLCJzYW1wbGUiLCJmaWVsZHMiLCJhbGxEYXRhIiwiZm9yRWFjaCIsImJpbmQiLCJzYW1wbGVDb3VudCIsInRvdGFsIiwiTWF0aCIsIm1pbiIsIm1hcCIsImZpZWxkIiwiZmllbGRJZHgiLCJpIiwiaiIsImluY2x1ZGVzIiwidW5peEZvcm1hdCIsInJvdyIsInR5cGUiLCJBTExfRklFTERfVFlQRVMiLCJyZWFsIiwicGFyc2VGbG9hdCIsInRpbWVzdGFtcCIsImZvcm1hdCIsIk51bWJlciIsImludGVnZXIiLCJwYXJzZUludCIsImJvb2xlYW4iLCJkYXRhIiwiZmllbGRPcmRlciIsIm1ldGFkYXRhIiwiQW5hbHl6ZXIiLCJjb21wdXRlQ29sTWV0YSIsInJlZ2V4IiwiZGF0YVR5cGUiLCJmaWVsZEJ5SW5kZXgiLCJyZWR1Y2UiLCJvcmRlcmVkQXJyYXkiLCJpbmRleCIsIm5hbWUiLCJmaWVsZE1ldGEiLCJmaW5kIiwibSIsImtleSIsInRhYmxlRmllbGRJbmRleCIsImFjY3UiLCJhbGxOYW1lcyIsImZpZWxkTmFtZSIsImNvdW50ZXIiLCJwdXNoIiwiYVR5cGUiLCJEQVRFIiwiQW5hbHl6ZXJEQVRBX1RZUEVTIiwiVElNRSIsIkRBVEVUSU1FIiwiTlVNQkVSIiwiSU5UIiwiRkxPQVQiLCJCT09MRUFOIiwiU1RSSU5HIiwiQ0lUWSIsIkdFT01FVFJZIiwiR0VPTUVUUllfRlJPTV9TVFJJTkciLCJaSVBDT0RFIiwiUEFJUl9HRU9NRVRSWV9GUk9NX1NUUklORyIsImRhdGUiLCJnZW9qc29uIiwic3RyaW5nIiwiZ2xvYmFsQ29uc29sZSIsIndhcm4iLCJrZXlzIiwiT2JqZWN0IiwiZCIsIm5vcm1hbGl6ZWRHZW9qc29uIiwiQXJyYXkiLCJpc0FycmF5IiwiZmVhdHVyZXMiLCJmIiwiZ2VvbWV0cnkiLCJfZ2VvanNvbiIsInByb3BlcnRpZXMiLCJwcmV2IiwiY3VyciIsImNvbHVtbnMiLCJmb3JtYXR0ZWREYXRhIiwiR0VPSlNPTl9GSUVMRFMiLCJKU09OIiwic3RyaW5naWZ5IiwicHJvY2VlZCIsImFsbFZhbGlkIiwiZXZlcnkiLCJzYW1wbGVEYXRhIiwibWV0YSIsInVwZGF0ZWRGaWVsZHMiXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7OztRQWdDZ0JBLGMsR0FBQUEsYztRQWlDQUMsdUIsR0FBQUEsdUI7UUFtREFDLHVCLEdBQUFBLHVCO1FBdUNBQyxpQixHQUFBQSxpQjtRQWtDQUMscUIsR0FBQUEscUI7UUErQkFDLHVCLEdBQUFBLHVCO1FBa0RBQyxnQixHQUFBQSxnQjtRQWVBQyxjLEdBQUFBLGM7UUErQ0FDLFMsR0FBQUEsUztRQXFCQUMsaUIsR0FBQUEsaUI7O0FBN1VoQjs7QUFDQTs7QUFDQTs7QUFDQTs7OztBQUNBOztBQUNBOzs7O0FBQ0E7O0FBQ0E7Ozs7QUFFQTtBQTdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFZQSxJQUFNQyxZQUFZLENBQUMsRUFBRCxFQUFLLE1BQUwsRUFBYSxNQUFiLEVBQXFCLE1BQXJCLEVBQTZCLEtBQTdCLENBQWxCOztBQUVPLFNBQVNWLGNBQVQsQ0FBd0JXLE9BQXhCLEVBQWlDOztBQUV0QztBQUNBO0FBSHNDLHNCQUtULHlCQUFhQSxPQUFiLENBTFM7QUFBQTtBQUFBLE1BSy9CQyxTQUwrQjtBQUFBLE1BS2pCQyxJQUxpQjs7QUFPdEMsTUFBSSxDQUFDQSxLQUFLQyxNQUFOLElBQWdCLENBQUNGLFNBQXJCLEVBQWdDO0FBQzlCO0FBQ0E7QUFDQSxXQUFPLElBQVA7QUFDRDs7QUFFREcsdUJBQXFCRixJQUFyQjtBQUNBO0FBQ0E7QUFDQSxNQUFNRyxTQUFTZix3QkFBd0IsRUFBQ2dCLFFBQVFMLFNBQVQsRUFBb0JNLFNBQVNMLElBQTdCLEVBQXhCLENBQWY7O0FBRUEsTUFBTUksU0FBU2Qsa0JBQWtCYSxNQUFsQixFQUEwQkosU0FBMUIsQ0FBZjs7QUFFQUssU0FBT0UsT0FBUCxDQUFlakIsd0JBQXdCa0IsSUFBeEIsQ0FBNkIsSUFBN0IsRUFBbUNQLElBQW5DLENBQWY7O0FBRUEsU0FBTyxFQUFDSSxjQUFELEVBQVNKLFVBQVQsRUFBUDtBQUNEOztBQUVEOzs7Ozs7OztBQVFPLFNBQVNaLHVCQUFULE9BQXNFO0FBQUEsTUFBcENnQixNQUFvQyxRQUFwQ0EsTUFBb0M7QUFBQSxNQUE1QkMsT0FBNEIsUUFBNUJBLE9BQTRCO0FBQUEsOEJBQW5CRyxXQUFtQjtBQUFBLE1BQW5CQSxXQUFtQixvQ0FBTCxFQUFLOztBQUMzRSxNQUFNQyxRQUFRQyxLQUFLQyxHQUFMLENBQVNILFdBQVQsRUFBc0JILFFBQVFKLE1BQTlCLENBQWQ7QUFDQTtBQUNBLE1BQU1FLFNBQVMsb0JBQU0sQ0FBTixFQUFTTSxLQUFULEVBQWdCLENBQWhCLEVBQW1CRyxHQUFuQixDQUF1QjtBQUFBLFdBQU0sRUFBTjtBQUFBLEdBQXZCLENBQWY7O0FBRUE7QUFDQVIsU0FBT0UsT0FBUCxDQUFlLFVBQUNPLEtBQUQsRUFBUUMsUUFBUixFQUFxQjtBQUNsQztBQUNBLFFBQUlDLElBQUksQ0FBUjtBQUNBO0FBQ0EsUUFBSUMsSUFBSSxDQUFSOztBQUVBLFdBQU9BLElBQUlQLEtBQVgsRUFBa0I7QUFDaEIsVUFBSU0sS0FBS1YsUUFBUUosTUFBakIsRUFBeUI7QUFDdkI7QUFDQUUsZUFBT2EsQ0FBUCxFQUFVSCxLQUFWLElBQW1CLElBQW5CO0FBQ0FHO0FBQ0QsT0FKRCxNQUlPLElBQUksbUNBQW1CWCxRQUFRVSxDQUFSLEVBQVdELFFBQVgsQ0FBbkIsQ0FBSixFQUE4QztBQUNuRFgsZUFBT2EsQ0FBUCxFQUFVSCxLQUFWLElBQW1CUixRQUFRVSxDQUFSLEVBQVdELFFBQVgsQ0FBbkI7QUFDQUU7QUFDQUQ7QUFDRCxPQUpNLE1BSUE7QUFDTEE7QUFDRDtBQUNGO0FBQ0YsR0FuQkQ7O0FBcUJBLFNBQU9aLE1BQVA7QUFDRDs7QUFFRCxTQUFTRCxvQkFBVCxDQUE4QkYsSUFBOUIsRUFBb0M7QUFDbEMsT0FBSyxJQUFJZSxJQUFJLENBQWIsRUFBZ0JBLElBQUlmLEtBQUtDLE1BQXpCLEVBQWlDYyxHQUFqQyxFQUFzQztBQUNwQyxTQUFLLElBQUlDLElBQUksQ0FBYixFQUFnQkEsSUFBSWhCLEtBQUtlLENBQUwsRUFBUWQsTUFBNUIsRUFBb0NlLEdBQXBDLEVBQXlDO0FBQ3ZDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBSSxDQUFDaEIsS0FBS2UsQ0FBTCxFQUFRQyxDQUFSLENBQUQsSUFBZW5CLFVBQVVvQixRQUFWLENBQW1CakIsS0FBS2UsQ0FBTCxFQUFRQyxDQUFSLENBQW5CLENBQW5CLEVBQW1EO0FBQ2pEaEIsYUFBS2UsQ0FBTCxFQUFRQyxDQUFSLElBQWEsSUFBYjtBQUNEO0FBQ0Y7QUFDRjtBQUNGO0FBQ0Q7Ozs7Ozs7O0FBUU8sU0FBUzNCLHVCQUFULENBQWlDVyxJQUFqQyxFQUF1Q2EsS0FBdkMsRUFBOENFLENBQTlDLEVBQWlEO0FBQ3RELE1BQU1HLGFBQWEsQ0FBQyxHQUFELEVBQU0sR0FBTixDQUFuQjs7QUFFQWxCLE9BQUtNLE9BQUwsQ0FBYSxlQUFPO0FBQ2xCLFFBQUlhLElBQUlKLENBQUosTUFBVyxJQUFmLEVBQXFCO0FBQ25CLGNBQVFGLE1BQU1PLElBQWQ7QUFDRSxhQUFLQyxpQ0FBZ0JDLElBQXJCO0FBQ0VILGNBQUlKLENBQUosSUFBU1EsV0FBV0osSUFBSUosQ0FBSixDQUFYLENBQVQ7QUFDQTs7QUFFRjtBQUNBO0FBQ0EsYUFBS00saUNBQWdCRyxTQUFyQjtBQUNFTCxjQUFJSixDQUFKLElBQVNHLFdBQVdELFFBQVgsQ0FBb0JKLE1BQU1ZLE1BQTFCLElBQW9DQyxPQUFPUCxJQUFJSixDQUFKLENBQVAsQ0FBcEMsR0FBcURJLElBQUlKLENBQUosQ0FBOUQ7QUFDQTs7QUFFRixhQUFLTSxpQ0FBZ0JNLE9BQXJCO0FBQ0VSLGNBQUlKLENBQUosSUFBU2EsU0FBU1QsSUFBSUosQ0FBSixDQUFULEVBQWlCLEVBQWpCLENBQVQ7QUFDQTs7QUFFRixhQUFLTSxpQ0FBZ0JRLE9BQXJCO0FBQ0U7QUFDQVYsY0FBSUosQ0FBSixJQUFTSSxJQUFJSixDQUFKLE1BQVcsTUFBWCxJQUFxQkksSUFBSUosQ0FBSixNQUFXLE1BQWhDLElBQTBDSSxJQUFJSixDQUFKLE1BQVcsR0FBOUQ7QUFDQTs7QUFFRjtBQUNFO0FBckJKO0FBdUJEO0FBQ0YsR0ExQkQ7QUEyQkQ7O0FBRUQ7Ozs7Ozs7QUFPTyxTQUFTekIsaUJBQVQsQ0FBMkJ3QyxJQUEzQixFQUFpQ0MsVUFBakMsRUFBNkM7QUFDbEQ7QUFDQSxNQUFNQyxXQUFXQyx1QkFBU0MsY0FBVCxDQUF3QkosSUFBeEIsRUFBOEIsQ0FDN0MsRUFBQ0ssT0FBTyx1QkFBUixFQUFpQ0MsVUFBVSxVQUEzQyxFQUQ2QyxDQUE5QixDQUFqQjs7QUFGa0QsOEJBTTNCN0Msc0JBQXNCd0MsVUFBdEIsQ0FOMkI7QUFBQSxNQU0zQ00sWUFOMkMseUJBTTNDQSxZQU4yQzs7QUFRbEQsU0FBT04sV0FBV08sTUFBWCxDQUFrQixVQUFDQyxZQUFELEVBQWUxQixLQUFmLEVBQXNCMkIsS0FBdEIsRUFBZ0M7QUFDdkQsUUFBTUMsT0FBT0osYUFBYUcsS0FBYixDQUFiO0FBQ0EsUUFBTUUsWUFBWVYsU0FBU1csSUFBVCxDQUFjO0FBQUEsYUFBS0MsRUFBRUMsR0FBRixLQUFVaEMsS0FBZjtBQUFBLEtBQWQsQ0FBbEI7O0FBRnVELGdCQUdoQzZCLGFBQWEsRUFIbUI7QUFBQSxRQUdoRHRCLElBSGdELFNBR2hEQSxJQUhnRDtBQUFBLFFBRzFDSyxNQUgwQyxTQUcxQ0EsTUFIMEM7O0FBS3ZEYyxpQkFBYUMsS0FBYixJQUFzQjtBQUNwQkMsZ0JBRG9CO0FBRXBCaEIsb0JBRm9COztBQUlwQjtBQUNBO0FBQ0FxQix1QkFBaUJOLFFBQVEsQ0FOTDtBQU9wQnBCLFlBQU01Qix3QkFBd0I0QixJQUF4QjtBQVBjLEtBQXRCOztBQVVBLFdBQU9tQixZQUFQO0FBQ0QsR0FoQk0sRUFnQkosRUFoQkksQ0FBUDtBQWlCRDs7QUFFRDs7Ozs7OztBQU9PLFNBQVNoRCxxQkFBVCxDQUErQndDLFVBQS9CLEVBQTJDO0FBQ2hELFNBQU9BLFdBQVdPLE1BQVgsQ0FDTCxVQUFDUyxJQUFELEVBQU9sQyxLQUFQLEVBQWNFLENBQWQsRUFBb0I7QUFBQSxRQUNYaUMsUUFEVyxHQUNDRCxJQURELENBQ1hDLFFBRFc7O0FBRWxCLFFBQUlDLFlBQVlwQyxLQUFoQjs7QUFFQTtBQUNBLFFBQUltQyxTQUFTL0IsUUFBVCxDQUFrQkosS0FBbEIsQ0FBSixFQUE4QjtBQUM1QixVQUFJcUMsVUFBVSxDQUFkO0FBQ0EsYUFBT0YsU0FBUy9CLFFBQVQsQ0FBcUJKLEtBQXJCLFNBQThCcUMsT0FBOUIsQ0FBUCxFQUFpRDtBQUMvQ0E7QUFDRDtBQUNERCxrQkFBZXBDLEtBQWYsU0FBd0JxQyxPQUF4QjtBQUNEOztBQUVESCxTQUFLVixZQUFMLENBQWtCdEIsQ0FBbEIsSUFBdUJrQyxTQUF2QjtBQUNBRixTQUFLQyxRQUFMLENBQWNHLElBQWQsQ0FBbUJGLFNBQW5COztBQUVBLFdBQU9GLElBQVA7QUFDRCxHQWxCSSxFQW1CTCxFQUFDQyxVQUFVLEVBQVgsRUFBZVgsY0FBYyxFQUE3QixFQW5CSyxDQUFQO0FBcUJEOztBQUVEOzs7Ozs7QUFNQTtBQUNPLFNBQVM3Qyx1QkFBVCxDQUFpQzRELEtBQWpDLEVBQXdDO0FBQUEsTUFFM0NDLElBRjJDLEdBZXpDQyx3QkFmeUMsQ0FFM0NELElBRjJDO0FBQUEsTUFHM0NFLElBSDJDLEdBZXpDRCx3QkFmeUMsQ0FHM0NDLElBSDJDO0FBQUEsTUFJM0NDLFFBSjJDLEdBZXpDRix3QkFmeUMsQ0FJM0NFLFFBSjJDO0FBQUEsTUFLM0NDLE1BTDJDLEdBZXpDSCx3QkFmeUMsQ0FLM0NHLE1BTDJDO0FBQUEsTUFNM0NDLEdBTjJDLEdBZXpDSix3QkFmeUMsQ0FNM0NJLEdBTjJDO0FBQUEsTUFPM0NDLEtBUDJDLEdBZXpDTCx3QkFmeUMsQ0FPM0NLLEtBUDJDO0FBQUEsTUFRM0NDLE9BUjJDLEdBZXpDTix3QkFmeUMsQ0FRM0NNLE9BUjJDO0FBQUEsTUFTM0NDLE1BVDJDLEdBZXpDUCx3QkFmeUMsQ0FTM0NPLE1BVDJDO0FBQUEsTUFVM0NDLElBVjJDLEdBZXpDUix3QkFmeUMsQ0FVM0NRLElBVjJDO0FBQUEsTUFXM0NDLFFBWDJDLEdBZXpDVCx3QkFmeUMsQ0FXM0NTLFFBWDJDO0FBQUEsTUFZM0NDLG9CQVoyQyxHQWV6Q1Ysd0JBZnlDLENBWTNDVSxvQkFaMkM7QUFBQSxNQWEzQ0MsT0FiMkMsR0FlekNYLHdCQWZ5QyxDQWEzQ1csT0FiMkM7QUFBQSxNQWMzQ0MseUJBZDJDLEdBZXpDWix3QkFmeUMsQ0FjM0NZLHlCQWQyQzs7QUFpQjdDO0FBQ0E7O0FBQ0EsVUFBUWQsS0FBUjtBQUNFLFNBQUtDLElBQUw7QUFDRSxhQUFPaEMsaUNBQWdCOEMsSUFBdkI7QUFDRixTQUFLWixJQUFMO0FBQ0EsU0FBS0MsUUFBTDtBQUNFLGFBQU9uQyxpQ0FBZ0JHLFNBQXZCO0FBQ0YsU0FBS2lDLE1BQUw7QUFDQSxTQUFLRSxLQUFMO0FBQ0UsYUFBT3RDLGlDQUFnQkMsSUFBdkI7QUFDRixTQUFLb0MsR0FBTDtBQUNFLGFBQU9yQyxpQ0FBZ0JNLE9BQXZCO0FBQ0YsU0FBS2lDLE9BQUw7QUFDRSxhQUFPdkMsaUNBQWdCUSxPQUF2QjtBQUNGLFNBQUtrQyxRQUFMO0FBQ0EsU0FBS0Msb0JBQUw7QUFDQSxTQUFLRSx5QkFBTDtBQUNFLGFBQU83QyxpQ0FBZ0IrQyxPQUF2QjtBQUNGLFNBQUtQLE1BQUw7QUFDQSxTQUFLQyxJQUFMO0FBQ0EsU0FBS0csT0FBTDtBQUNFLGFBQU81QyxpQ0FBZ0JnRCxNQUF2QjtBQUNGO0FBQ0VDLHNCQUFjQyxJQUFkLGlDQUFpRG5CLEtBQWpEO0FBQ0EsYUFBTy9CLGlDQUFnQmdELE1BQXZCO0FBdkJKO0FBeUJEO0FBQ0Q7O0FBRUE7OztBQUdPLFNBQVM1RSxnQkFBVCxDQUEwQkssT0FBMUIsRUFBbUM7QUFDeEMsTUFBSSxDQUFDQSxRQUFRRyxNQUFiLEVBQXFCO0FBQ25CLFdBQU8sSUFBUDtBQUNEOztBQUVELE1BQU11RSxPQUFPQyxPQUFPRCxJQUFQLENBQVkxRSxRQUFRLENBQVIsQ0FBWixDQUFiO0FBQ0EsTUFBTUUsT0FBT0YsUUFBUWMsR0FBUixDQUFZO0FBQUEsV0FBSzRELEtBQUs1RCxHQUFMLENBQVM7QUFBQSxhQUFPOEQsRUFBRTdCLEdBQUYsQ0FBUDtBQUFBLEtBQVQsQ0FBTDtBQUFBLEdBQVosQ0FBYjtBQUNBLE1BQU16QyxTQUFTZCxrQkFBa0JRLE9BQWxCLEVBQTJCMEUsSUFBM0IsQ0FBZjs7QUFFQSxTQUFPO0FBQ0xwRSxrQkFESztBQUVMSjtBQUZLLEdBQVA7QUFJRDs7QUFFTSxTQUFTTixjQUFULENBQXdCSSxPQUF4QixFQUFpQztBQUN0QyxNQUFNNkUsb0JBQW9CLGdDQUFVN0UsT0FBVixDQUExQjs7QUFFQSxNQUFJLENBQUM2RSxpQkFBRCxJQUFzQixDQUFDQyxNQUFNQyxPQUFOLENBQWNGLGtCQUFrQkcsUUFBaEMsQ0FBM0IsRUFBc0U7QUFDcEU7QUFDQSxXQUFPLElBQVA7QUFDRDs7QUFFRDtBQUNBLE1BQU16RSxVQUFVc0Usa0JBQWtCRyxRQUFsQixDQUEyQnhDLE1BQTNCLENBQWtDLFVBQUNTLElBQUQsRUFBT2dDLENBQVAsRUFBVWhFLENBQVYsRUFBZ0I7QUFDaEUsUUFBSWdFLEVBQUVDLFFBQU4sRUFBZ0I7QUFDZGpDLFdBQUtJLElBQUw7QUFDRTtBQUNBOEIsa0JBQVVGO0FBRlosU0FHTUEsRUFBRUcsVUFBRixJQUFnQixFQUh0QjtBQUtEO0FBQ0QsV0FBT25DLElBQVA7QUFDRCxHQVRlLEVBU2IsRUFUYSxDQUFoQjs7QUFXQTtBQUNBLE1BQU0zQyxTQUFTQyxRQUFRaUMsTUFBUixDQUFlLFVBQUM2QyxJQUFELEVBQU9DLElBQVAsRUFBZ0I7QUFDNUNYLFdBQU9ELElBQVAsQ0FBWVksSUFBWixFQUFrQjlFLE9BQWxCLENBQTBCLGVBQU87QUFDL0IsVUFBSSxDQUFDNkUsS0FBS2xFLFFBQUwsQ0FBYzRCLEdBQWQsQ0FBTCxFQUF5QjtBQUN2QnNDLGFBQUtoQyxJQUFMLENBQVVOLEdBQVY7QUFDRDtBQUNGLEtBSkQ7QUFLQSxXQUFPc0MsSUFBUDtBQUNELEdBUGMsRUFPWixFQVBZLENBQWY7O0FBU0E7QUFDQTlFLFVBQVFDLE9BQVIsQ0FBZ0IsYUFBSztBQUNuQkYsV0FBT0UsT0FBUCxDQUFlLGFBQUs7QUFDbEIsVUFBSSxFQUFFeUUsS0FBS0wsQ0FBUCxDQUFKLEVBQWU7QUFDYkEsVUFBRUssQ0FBRixJQUFPLElBQVA7QUFDRDtBQUNGLEtBSkQ7QUFLRCxHQU5EOztBQVFBLFNBQU90RixpQkFBaUJZLE9BQWpCLENBQVA7QUFDRDs7QUFFRDs7Ozs7QUFLTyxTQUFTVixTQUFULENBQW1CbUMsSUFBbkIsRUFBeUIxQixNQUF6QixFQUFpQztBQUN0QyxNQUFNaUYsVUFBVWpGLE9BQU9RLEdBQVAsQ0FBVztBQUFBLFdBQUttRSxFQUFFdEMsSUFBUDtBQUFBLEdBQVgsQ0FBaEI7QUFDQSxNQUFNNkMsZ0JBQWdCLENBQUNELE9BQUQsQ0FBdEI7O0FBRUE7QUFDQXZELE9BQUt4QixPQUFMLENBQWEsZUFBTztBQUNsQmdGLGtCQUFjbkMsSUFBZCxDQUNFaEMsSUFBSVAsR0FBSixDQUNFLFVBQUM4RCxDQUFELEVBQUkzRCxDQUFKO0FBQUEsYUFBVTJELEtBQUthLGdDQUFlbkIsT0FBZixDQUF1Qm5ELFFBQXZCLENBQWdDYixPQUFPVyxDQUFQLEVBQVUwQixJQUExQyxDQUFMLEdBQ1IrQyxLQUFLQyxTQUFMLENBQWVmLENBQWYsQ0FEUSxHQUNZQSxDQUR0QjtBQUFBLEtBREYsQ0FERjtBQU1ELEdBUEQ7O0FBU0EsU0FBTywwQkFBY1ksYUFBZCxDQUFQO0FBQ0Q7O0FBRUQ7Ozs7QUFJTyxTQUFTMUYsaUJBQVQsQ0FBMkJrQyxJQUEzQixFQUFpQztBQUN0QztBQUNBOzs7Ozs7O0FBT0EsTUFBSTRELFVBQVUsSUFBZDtBQUNBLE1BQUksQ0FBQzVELElBQUwsRUFBVztBQUNULDBCQUFPLHFDQUFQO0FBQ0E0RCxjQUFVLEtBQVY7QUFDRCxHQUhELE1BR08sSUFBSSxDQUFDZCxNQUFNQyxPQUFOLENBQWMvQyxLQUFLMUIsTUFBbkIsQ0FBTCxFQUFpQztBQUN0QywwQkFBTyxtREFBUDtBQUNBc0YsY0FBVSxLQUFWO0FBQ0QsR0FITSxNQUdBLElBQUksQ0FBQ2QsTUFBTUMsT0FBTixDQUFjL0MsS0FBSzlCLElBQW5CLENBQUwsRUFBK0I7QUFDcEMsMEJBQU8saURBQVA7QUFDQTBGLGNBQVUsS0FBVjtBQUNEOztBQUVELE1BQUksQ0FBQ0EsT0FBTCxFQUFjO0FBQ1osV0FBTyxJQUFQO0FBQ0Q7O0FBdkJxQyxNQXlCL0J0RixNQXpCK0IsR0F5QmYwQixJQXpCZSxDQXlCL0IxQixNQXpCK0I7QUFBQSxNQXlCdkJKLElBekJ1QixHQXlCZjhCLElBekJlLENBeUJ2QjlCLElBekJ1Qjs7QUEyQnRDOztBQUNBLE1BQU0yRixXQUFXdkYsT0FBT3dGLEtBQVAsQ0FBYSxVQUFDYixDQUFELEVBQUloRSxDQUFKLEVBQVU7QUFDdEMsUUFBSSxRQUFPZ0UsQ0FBUCx1REFBT0EsQ0FBUCxPQUFhLFFBQWpCLEVBQTJCO0FBQ3pCLGlGQUEwREEsQ0FBMUQ7QUFDQSxhQUFPLEtBQVA7QUFDRDs7QUFFRCxRQUFJLENBQUNBLEVBQUV0QyxJQUFQLEVBQWE7QUFDWCw2RUFDaUQrQyxLQUFLQyxTQUFMLENBQWVWLENBQWYsQ0FEakQ7QUFHQTtBQUNBQSxRQUFFdEMsSUFBRixlQUFtQjFCLENBQW5CO0FBQ0Q7O0FBRUQsUUFBSSxDQUFDTSxpQ0FBZ0IwRCxFQUFFM0QsSUFBbEIsQ0FBTCxFQUE4QjtBQUM1QixvREFBNkIyRCxFQUFFM0QsSUFBL0I7QUFDQSxhQUFPLEtBQVA7QUFDRDs7QUFFRCxXQUFPMkQsRUFBRTNELElBQUYsSUFBVTJELEVBQUV0RCxNQUFaLElBQXNCc0QsRUFBRXRDLElBQS9CO0FBQ0QsR0FwQmdCLENBQWpCOztBQXNCQSxNQUFJa0QsUUFBSixFQUFjO0FBQ1osV0FBTyxFQUFDM0YsVUFBRCxFQUFPSSxjQUFQLEVBQVA7QUFDRDs7QUFFRDtBQUNBO0FBQ0EsTUFBTXlGLGFBQWF6Ryx3QkFBd0IsRUFBQ2dCLFFBQVFBLE9BQU9RLEdBQVAsQ0FBVztBQUFBLGFBQUttRSxFQUFFdEMsSUFBUDtBQUFBLEtBQVgsQ0FBVCxFQUFrQ3BDLFNBQVNMLElBQTNDLEVBQXhCLENBQW5CO0FBQ0EsTUFBTStCLGFBQWEzQixPQUFPUSxHQUFQLENBQVc7QUFBQSxXQUFLbUUsRUFBRXRDLElBQVA7QUFBQSxHQUFYLENBQW5CO0FBQ0EsTUFBTXFELE9BQU94RyxrQkFBa0J1RyxVQUFsQixFQUE4QjlELFVBQTlCLENBQWI7QUFDQSxNQUFNZ0UsZ0JBQWdCM0YsT0FBT1EsR0FBUCxDQUFXLFVBQUNtRSxDQUFELEVBQUloRSxDQUFKO0FBQUEsc0NBQzVCZ0UsQ0FENEI7QUFFL0IzRCxZQUFNMEUsS0FBSy9FLENBQUwsRUFBUUssSUFGaUI7QUFHL0JLLGNBQVFxRSxLQUFLL0UsQ0FBTCxFQUFRVTtBQUhlO0FBQUEsR0FBWCxDQUF0Qjs7QUFNQSxTQUFPLEVBQUNyQixRQUFRMkYsYUFBVCxFQUF3Qi9GLFVBQXhCLEVBQVA7QUFDRDs7a0JBRWM7QUFDYk4sZ0NBRGE7QUFFYlAsZ0NBRmE7QUFHYk0sb0NBSGE7QUFJYkQsa0RBSmE7QUFLYkYsc0NBTGE7QUFNYkQ7QUFOYSxDIiwiZmlsZSI6ImRhdGEtcHJvY2Vzc29yLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IChjKSAyMDE4IFViZXIgVGVjaG5vbG9naWVzLCBJbmMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuLy8gaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0c1xuLy8gdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuLy8gY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4vLyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbi8vIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbi8vIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vIFRIRSBTT0ZUV0FSRS5cblxuaW1wb3J0IHtjc3ZQYXJzZVJvd3MsIGNzdkZvcm1hdFJvd3N9IGZyb20gJ2QzLWRzdic7XG5pbXBvcnQge3JhbmdlfSBmcm9tICdkMy1hcnJheSc7XG5pbXBvcnQge2NvbnNvbGUgYXMgZ2xvYmFsQ29uc29sZX0gZnJvbSAnZ2xvYmFsL3dpbmRvdyc7XG5pbXBvcnQgYXNzZXJ0IGZyb20gJ2Fzc2VydCc7XG5pbXBvcnQge0FuYWx5emVyLCBEQVRBX1RZUEVTIGFzIEFuYWx5emVyREFUQV9UWVBFU30gZnJvbSAndHlwZS1hbmFseXplcic7XG5pbXBvcnQgbm9ybWFsaXplIGZyb20gJ0BtYXBib3gvZ2VvanNvbi1ub3JtYWxpemUnO1xuaW1wb3J0IHtBTExfRklFTERfVFlQRVMsIEdFT0pTT05fRklFTERTfSBmcm9tICdjb25zdGFudHMvZGVmYXVsdC1zZXR0aW5ncyc7XG5pbXBvcnQge25vdE51bGxvclVuZGVmaW5lZH0gZnJvbSAndXRpbHMvZGF0YS11dGlscyc7XG5cbi8vIGlmIGFueSBvZiB0aGVzZSB2YWx1ZSBvY2N1cnMgaW4gY3N2LCBwYXJzZSBpdCB0byBudWxsO1xuY29uc3QgQ1NWX05VTExTID0gWycnLCAnbnVsbCcsICdOVUxMJywgJ051bGwnLCAnTmFOJ107XG5cbmV4cG9ydCBmdW5jdGlvbiBwcm9jZXNzQ3N2RGF0YShyYXdEYXRhKSB7XG5cbiAgLy8gaGVyZSB3ZSBhc3N1bWUgdGhlIGNzdiBmaWxlIHRoYXQgcGVvcGxlIHVwbG9hZGVkIHdpbGwgaGF2ZSBmaXJzdCByb3dcbiAgLy8gYXMgbmFtZSBvZiB0aGUgY29sdW1uXG4gIC8vVE9ETzogYWRkIGEgYWxlcnQgYXQgdXBsb2FkIGNzdiB0byByZW1pbmQgZGVmaW5lIGZpcnN0IHJvd1xuICBjb25zdCBbaGVhZGVyUm93LCAuLi5yb3dzXSA9IGNzdlBhcnNlUm93cyhyYXdEYXRhKTtcblxuICBpZiAoIXJvd3MubGVuZ3RoIHx8ICFoZWFkZXJSb3cpIHtcbiAgICAvLyBsb29rcyBsaWtlIGFuIGVtcHR5IGZpbGVcbiAgICAvLyByZXNvbHZlIG51bGwsIGFuZCBjYXRjaCB0aGVtIGxhdGVyIGluIG9uZSBwbGFjZVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY2xlYW5VcEZhbHN5Q3N2VmFsdWUocm93cyk7XG4gIC8vIE5vIG5lZWQgdG8gcnVuIHR5cGUgZGV0ZWN0aW9uIG9uIGV2ZXJ5IGRhdGEgcG9pbnRcbiAgLy8gaGVyZSB3ZSBnZXQgYSBsaXN0IG9mIG5vbmUgbnVsbCB2YWx1ZXMgdG8gcnVuIGFuYWx5emUgb25cbiAgY29uc3Qgc2FtcGxlID0gZ2V0U2FtcGxlRm9yVHlwZUFuYWx5emUoe2ZpZWxkczogaGVhZGVyUm93LCBhbGxEYXRhOiByb3dzfSk7XG5cbiAgY29uc3QgZmllbGRzID0gZ2V0RmllbGRzRnJvbURhdGEoc2FtcGxlLCBoZWFkZXJSb3cpO1xuXG4gIGZpZWxkcy5mb3JFYWNoKHBhcnNlQ3N2RGF0YUJ5RmllbGRUeXBlLmJpbmQobnVsbCwgcm93cykpO1xuXG4gIHJldHVybiB7ZmllbGRzLCByb3dzfTtcbn1cblxuLyoqXG4gKiBnZXQgZmllbGRzIGZyb20gY3N2IGRhdGFcbiAqXG4gKiBAcGFyYW0ge2FycmF5fSBmaWVsZHMgLSBhbiBhcnJheSBvZiBmaWVsZHMgbmFtZVxuICogQHBhcmFtIHthcnJheX0gYWxsRGF0YVxuICogQHBhcmFtIHthcnJheX0gc2FtcGxlQ291bnRcbiAqIEByZXR1cm5zIHthcnJheX0gZm9ybWF0dGVkIGZpZWxkc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2FtcGxlRm9yVHlwZUFuYWx5emUoe2ZpZWxkcywgYWxsRGF0YSwgc2FtcGxlQ291bnQgPSA1MH0pIHtcbiAgY29uc3QgdG90YWwgPSBNYXRoLm1pbihzYW1wbGVDb3VudCwgYWxsRGF0YS5sZW5ndGgpO1xuICAvLyBjb25zdCBmaWVsZE9yZGVyID0gZmllbGRzLm1hcChmID0+IGYubmFtZSk7XG4gIGNvbnN0IHNhbXBsZSA9IHJhbmdlKDAsIHRvdGFsLCAxKS5tYXAoZCA9PiAoe30pKTtcblxuICAvLyBjb2xsZWN0IHNhbXBsZSBkYXRhIGZvciBlYWNoIGZpZWxkXG4gIGZpZWxkcy5mb3JFYWNoKChmaWVsZCwgZmllbGRJZHgpID0+IHtcbiAgICAvLyBkYXRhIGNvdW50ZXJcbiAgICBsZXQgaSA9IDA7XG4gICAgLy8gc2FtcGxlIGNvdW50ZXJcbiAgICBsZXQgaiA9IDA7XG5cbiAgICB3aGlsZSAoaiA8IHRvdGFsKSB7XG4gICAgICBpZiAoaSA+PSBhbGxEYXRhLmxlbmd0aCkge1xuICAgICAgICAvLyBpZiBkZXBsZXRlZCBkYXRhIHBvb2xcbiAgICAgICAgc2FtcGxlW2pdW2ZpZWxkXSA9IG51bGw7XG4gICAgICAgIGorKztcbiAgICAgIH0gZWxzZSBpZiAobm90TnVsbG9yVW5kZWZpbmVkKGFsbERhdGFbaV1bZmllbGRJZHhdKSkge1xuICAgICAgICBzYW1wbGVbal1bZmllbGRdID0gYWxsRGF0YVtpXVtmaWVsZElkeF07XG4gICAgICAgIGorKztcbiAgICAgICAgaSsrO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaSsrO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIHNhbXBsZTtcbn1cblxuZnVuY3Rpb24gY2xlYW5VcEZhbHN5Q3N2VmFsdWUocm93cykge1xuICBmb3IgKGxldCBpID0gMDsgaSA8IHJvd3MubGVuZ3RoOyBpKyspIHtcbiAgICBmb3IgKGxldCBqID0gMDsgaiA8IHJvd3NbaV0ubGVuZ3RoOyBqKyspIHtcbiAgICAgIC8vIGFuYWx5emVyIHdpbGwgc2V0IGFueSBmaWVsZHMgdG8gJ3N0cmluZycgaWYgdGhlcmUgYXJlIGVtcHR5IHZhbHVlc1xuICAgICAgLy8gd2hpY2ggd2lsbCBiZSBwYXJzZWQgYXMgJycgYnkgZDMuY3N2XG4gICAgICAvLyBoZXJlIHdlIHBhcnNlIGVtcHR5IGRhdGEgYXMgbnVsbFxuICAgICAgLy8gVE9ETzogY3JlYXRlIHdhcm5pbmcgd2hlbiBkZWx0ZWN0IGBDU1ZfTlVMTFNgIGluIHRoZSBkYXRhXG4gICAgICBpZiAoIXJvd3NbaV1bal0gfHwgQ1NWX05VTExTLmluY2x1ZGVzKHJvd3NbaV1bal0pKSB7XG4gICAgICAgIHJvd3NbaV1bal0gPSBudWxsO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuLyoqXG4gKiBQcm9jZXNzIHVwbG9hZGVkIGNzdiBmaWxlIHRvIHBhcnNlIHZhbHVlIGJ5IGZpZWxkIHR5cGVcbiAqXG4gKiBAcGFyYW0ge2FycmF5fSByb3dzXG4gKiBAcGFyYW0ge29iamVjdH0gZmllbGRcbiAqIEBwYXJhbSB7bnVtYmVyfSBpXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlQ3N2RGF0YUJ5RmllbGRUeXBlKHJvd3MsIGZpZWxkLCBpKSB7XG4gIGNvbnN0IHVuaXhGb3JtYXQgPSBbJ3gnLCAnWCddO1xuXG4gIHJvd3MuZm9yRWFjaChyb3cgPT4ge1xuICAgIGlmIChyb3dbaV0gIT09IG51bGwpIHtcbiAgICAgIHN3aXRjaCAoZmllbGQudHlwZSkge1xuICAgICAgICBjYXNlIEFMTF9GSUVMRF9UWVBFUy5yZWFsOlxuICAgICAgICAgIHJvd1tpXSA9IHBhcnNlRmxvYXQocm93W2ldKTtcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICAvLyBUT0RPOiB0aW1lc3RhbXAgY2FuIGJlIGVpdGhlciAnMTQ5NTgyNzMyNicgb3IgJzIwMTYtMDMtMTAgMTE6MjAnXG4gICAgICAgIC8vIGlmIGl0J3MgJzE0OTU4MjczMjYnIHdlIHBhc3MgaXQgdG8gaW50XG4gICAgICAgIGNhc2UgQUxMX0ZJRUxEX1RZUEVTLnRpbWVzdGFtcDpcbiAgICAgICAgICByb3dbaV0gPSB1bml4Rm9ybWF0LmluY2x1ZGVzKGZpZWxkLmZvcm1hdCkgPyBOdW1iZXIocm93W2ldKSA6IHJvd1tpXTtcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICBjYXNlIEFMTF9GSUVMRF9UWVBFUy5pbnRlZ2VyOlxuICAgICAgICAgIHJvd1tpXSA9IHBhcnNlSW50KHJvd1tpXSwgMTApO1xuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGNhc2UgQUxMX0ZJRUxEX1RZUEVTLmJvb2xlYW46XG4gICAgICAgICAgLy8gMCBhbmQgMSBvbmx5IGZpZWxkIGNhbiBhbHNvIGJlIGJvb2xlYW5cbiAgICAgICAgICByb3dbaV0gPSByb3dbaV0gPT09ICd0cnVlJyB8fCByb3dbaV0gPT09ICdUcnVlJyB8fCByb3dbaV0gPT09ICcxJztcbiAgICAgICAgICBicmVhaztcblxuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogZ2V0IGZpZWxkcyBmcm9tIGNzdiBkYXRhXG4gKlxuICogQHBhcmFtIHthcnJheX0gZGF0YVxuICogQHBhcmFtIHthcnJheX0gZmllbGRPcmRlclxuICogQHJldHVybnMge2FycmF5fSBmb3JtYXR0ZWQgZmllbGRzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRGaWVsZHNGcm9tRGF0YShkYXRhLCBmaWVsZE9yZGVyKSB7XG4gIC8vIGFkZCBhIGNoZWNrIGZvciBlcG9jaCB0aW1lc3RhbXBcbiAgY29uc3QgbWV0YWRhdGEgPSBBbmFseXplci5jb21wdXRlQ29sTWV0YShkYXRhLCBbXG4gICAge3JlZ2V4OiAvLipnZW9qc29ufGFsbF9wb2ludHMvZywgZGF0YVR5cGU6ICdHRU9NRVRSWSd9XG4gIF0pO1xuXG4gIGNvbnN0IHtmaWVsZEJ5SW5kZXh9ID0gcmVuYW1lRHVwbGljYXRlRmllbGRzKGZpZWxkT3JkZXIpO1xuXG4gIHJldHVybiBmaWVsZE9yZGVyLnJlZHVjZSgob3JkZXJlZEFycmF5LCBmaWVsZCwgaW5kZXgpID0+IHtcbiAgICBjb25zdCBuYW1lID0gZmllbGRCeUluZGV4W2luZGV4XTtcbiAgICBjb25zdCBmaWVsZE1ldGEgPSBtZXRhZGF0YS5maW5kKG0gPT4gbS5rZXkgPT09IGZpZWxkKTtcbiAgICBjb25zdCB7dHlwZSwgZm9ybWF0fSA9IGZpZWxkTWV0YSB8fCB7fTtcblxuICAgIG9yZGVyZWRBcnJheVtpbmRleF0gPSB7XG4gICAgICBuYW1lLFxuICAgICAgZm9ybWF0LFxuXG4gICAgICAvLyBuZWVkIHRoaXMgZm9yIG1hcGJ1aWxkZXIgY29udmVyc2lvbjogZmlsdGVyIHR5cGUgZGV0ZWN0aW9uXG4gICAgICAvLyBjYXRlZ29yeSxcbiAgICAgIHRhYmxlRmllbGRJbmRleDogaW5kZXggKyAxLFxuICAgICAgdHlwZTogYW5hbHl6ZXJUeXBlVG9GaWVsZFR5cGUodHlwZSlcbiAgICB9O1xuXG4gICAgcmV0dXJuIG9yZGVyZWRBcnJheTtcbiAgfSwgW10pO1xufVxuXG4vKipcbiAqIHBhc3MgaW4gYW4gYXJyYXkgb2YgZmllbGQgbmFtZXMsIHJlbmFtZSBkdXBsaWNhdGVkIG9uZVxuICogYW5kIHJldHVybiBhIG1hcCBmcm9tIG9sZCBmaWVsZCBpbmRleCB0byBuZXcgbmFtZVxuICpcbiAqIEBwYXJhbSB7YXJyYXl9IGZpZWxkT3JkZXJcbiAqIEByZXR1cm5zIHtPYmplY3R9IG5ldyBmaWVsZCBuYW1lIGJ5IGluZGV4XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZW5hbWVEdXBsaWNhdGVGaWVsZHMoZmllbGRPcmRlcikge1xuICByZXR1cm4gZmllbGRPcmRlci5yZWR1Y2UoXG4gICAgKGFjY3UsIGZpZWxkLCBpKSA9PiB7XG4gICAgICBjb25zdCB7YWxsTmFtZXN9ID0gYWNjdTtcbiAgICAgIGxldCBmaWVsZE5hbWUgPSBmaWVsZDtcblxuICAgICAgLy8gYWRkIGEgY291bnRlciB0byBkdXBsaWNhdGVkIG5hbWVzXG4gICAgICBpZiAoYWxsTmFtZXMuaW5jbHVkZXMoZmllbGQpKSB7XG4gICAgICAgIGxldCBjb3VudGVyID0gMDtcbiAgICAgICAgd2hpbGUgKGFsbE5hbWVzLmluY2x1ZGVzKGAke2ZpZWxkfS0ke2NvdW50ZXJ9YCkpIHtcbiAgICAgICAgICBjb3VudGVyKys7XG4gICAgICAgIH1cbiAgICAgICAgZmllbGROYW1lID0gYCR7ZmllbGR9LSR7Y291bnRlcn1gO1xuICAgICAgfVxuXG4gICAgICBhY2N1LmZpZWxkQnlJbmRleFtpXSA9IGZpZWxkTmFtZTtcbiAgICAgIGFjY3UuYWxsTmFtZXMucHVzaChmaWVsZE5hbWUpO1xuXG4gICAgICByZXR1cm4gYWNjdTtcbiAgICB9LFxuICAgIHthbGxOYW1lczogW10sIGZpZWxkQnlJbmRleDoge319XG4gICk7XG59XG5cbi8qKlxuICogTWFwIEFuYWx5emVyIHR5cGVzIHRvIGxvY2FsIGZpZWxkIHR5cGVzXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGFUeXBlXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBjb3JyZXNwb25kaW5nIHR5cGUgaW4gQUxMX0ZJRUxEX1RZUEVTXG4gKi9cbi8qIGVzbGludC1kaXNhYmxlIGNvbXBsZXhpdHkgKi9cbmV4cG9ydCBmdW5jdGlvbiBhbmFseXplclR5cGVUb0ZpZWxkVHlwZShhVHlwZSkge1xuICBjb25zdCB7XG4gICAgREFURSxcbiAgICBUSU1FLFxuICAgIERBVEVUSU1FLFxuICAgIE5VTUJFUixcbiAgICBJTlQsXG4gICAgRkxPQVQsXG4gICAgQk9PTEVBTixcbiAgICBTVFJJTkcsXG4gICAgQ0lUWSxcbiAgICBHRU9NRVRSWSxcbiAgICBHRU9NRVRSWV9GUk9NX1NUUklORyxcbiAgICBaSVBDT0RFLFxuICAgIFBBSVJfR0VPTUVUUllfRlJPTV9TVFJJTkdcbiAgfSA9IEFuYWx5emVyREFUQV9UWVBFUztcblxuICAvLyBUT0RPOiB1biByZWNvZ25pemVkIHR5cGVzXG4gIC8vIENVUlJFTkNZIFBFUkNFTlQgTk9ORVxuICBzd2l0Y2ggKGFUeXBlKSB7XG4gICAgY2FzZSBEQVRFOlxuICAgICAgcmV0dXJuIEFMTF9GSUVMRF9UWVBFUy5kYXRlO1xuICAgIGNhc2UgVElNRTpcbiAgICBjYXNlIERBVEVUSU1FOlxuICAgICAgcmV0dXJuIEFMTF9GSUVMRF9UWVBFUy50aW1lc3RhbXA7XG4gICAgY2FzZSBOVU1CRVI6XG4gICAgY2FzZSBGTE9BVDpcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMucmVhbDtcbiAgICBjYXNlIElOVDpcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMuaW50ZWdlcjtcbiAgICBjYXNlIEJPT0xFQU46XG4gICAgICByZXR1cm4gQUxMX0ZJRUxEX1RZUEVTLmJvb2xlYW47XG4gICAgY2FzZSBHRU9NRVRSWTpcbiAgICBjYXNlIEdFT01FVFJZX0ZST01fU1RSSU5HOlxuICAgIGNhc2UgUEFJUl9HRU9NRVRSWV9GUk9NX1NUUklORzpcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMuZ2VvanNvbjtcbiAgICBjYXNlIFNUUklORzpcbiAgICBjYXNlIENJVFk6XG4gICAgY2FzZSBaSVBDT0RFOlxuICAgICAgcmV0dXJuIEFMTF9GSUVMRF9UWVBFUy5zdHJpbmc7XG4gICAgZGVmYXVsdDpcbiAgICAgIGdsb2JhbENvbnNvbGUud2FybihgVW5zdXBwb3J0ZWQgYW5hbHl6ZXIgdHlwZTogJHthVHlwZX1gKTtcbiAgICAgIHJldHVybiBBTExfRklFTERfVFlQRVMuc3RyaW5nO1xuICB9XG59XG4vKiBlc2xpbnQtZW5hYmxlIGNvbXBsZXhpdHkgKi9cblxuLypcbiAqIFByb2Nlc3MgcmF3RGF0YSB3aGVyZSBlYWNoIHJvdyBpcyBhbiBvYmplY3RcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByb2Nlc3NSb3dPYmplY3QocmF3RGF0YSkge1xuICBpZiAoIXJhd0RhdGEubGVuZ3RoKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBjb25zdCBrZXlzID0gT2JqZWN0LmtleXMocmF3RGF0YVswXSk7XG4gIGNvbnN0IHJvd3MgPSByYXdEYXRhLm1hcChkID0+IGtleXMubWFwKGtleSA9PiBkW2tleV0pKTtcbiAgY29uc3QgZmllbGRzID0gZ2V0RmllbGRzRnJvbURhdGEocmF3RGF0YSwga2V5cyk7XG5cbiAgcmV0dXJuIHtcbiAgICBmaWVsZHMsXG4gICAgcm93c1xuICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gcHJvY2Vzc0dlb2pzb24ocmF3RGF0YSkge1xuICBjb25zdCBub3JtYWxpemVkR2VvanNvbiA9IG5vcm1hbGl6ZShyYXdEYXRhKTtcblxuICBpZiAoIW5vcm1hbGl6ZWRHZW9qc29uIHx8ICFBcnJheS5pc0FycmF5KG5vcm1hbGl6ZWRHZW9qc29uLmZlYXR1cmVzKSkge1xuICAgIC8vIGZhaWwgdG8gbm9ybWFsaXplIGdlb2pzb25cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8vIGdldHRpbmcgYWxsIGZlYXR1cmUgZmllbGRzXG4gIGNvbnN0IGFsbERhdGEgPSBub3JtYWxpemVkR2VvanNvbi5mZWF0dXJlcy5yZWR1Y2UoKGFjY3UsIGYsIGkpID0+IHtcbiAgICBpZiAoZi5nZW9tZXRyeSkge1xuICAgICAgYWNjdS5wdXNoKHtcbiAgICAgICAgLy8gYWRkIGZlYXR1cmUgdG8gX2dlb2pzb24gZmllbGRcbiAgICAgICAgX2dlb2pzb246IGYsXG4gICAgICAgIC4uLihmLnByb3BlcnRpZXMgfHwge30pXG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIGFjY3U7XG4gIH0sIFtdKTtcblxuICAvLyBnZXQgYWxsIHRoZSBmaWVsZFxuICBjb25zdCBmaWVsZHMgPSBhbGxEYXRhLnJlZHVjZSgocHJldiwgY3VycikgPT4ge1xuICAgIE9iamVjdC5rZXlzKGN1cnIpLmZvckVhY2goa2V5ID0+IHtcbiAgICAgIGlmICghcHJldi5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICAgIHByZXYucHVzaChrZXkpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBwcmV2O1xuICB9LCBbXSk7XG5cbiAgLy8gbWFrZSBzdXJlIGVhY2ggZmVhdHVyZSBoYXMgZXhhY3Qgc2FtZSBmaWVsZHNcbiAgYWxsRGF0YS5mb3JFYWNoKGQgPT4ge1xuICAgIGZpZWxkcy5mb3JFYWNoKGYgPT4ge1xuICAgICAgaWYgKCEoZiBpbiBkKSkge1xuICAgICAgICBkW2ZdID0gbnVsbDtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSk7XG5cbiAgcmV0dXJuIHByb2Nlc3NSb3dPYmplY3QoYWxsRGF0YSk7XG59XG5cbi8qKlxuICogT24gZXhwb3J0IGRhdGEgdG8gY3N2XG4gKiBAcGFyYW0gZGF0YVxuICogQHBhcmFtIGZpZWxkc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZm9ybWF0Q3N2KGRhdGEsIGZpZWxkcykge1xuICBjb25zdCBjb2x1bW5zID0gZmllbGRzLm1hcChmID0+IGYubmFtZSk7XG4gIGNvbnN0IGZvcm1hdHRlZERhdGEgPSBbY29sdW1uc107XG5cbiAgLy8gcGFyc2UgZ2VvanNvbiBvYmplY3QgYXMgc3RyaW5nXG4gIGRhdGEuZm9yRWFjaChyb3cgPT4ge1xuICAgIGZvcm1hdHRlZERhdGEucHVzaChcbiAgICAgIHJvdy5tYXAoXG4gICAgICAgIChkLCBpKSA9PiBkICYmIEdFT0pTT05fRklFTERTLmdlb2pzb24uaW5jbHVkZXMoZmllbGRzW2ldLm5hbWUpID9cbiAgICAgICAgICBKU09OLnN0cmluZ2lmeShkKSA6IGRcbiAgICAgIClcbiAgICApXG4gIH0pO1xuXG4gIHJldHVybiBjc3ZGb3JtYXRSb3dzKGZvcm1hdHRlZERhdGEpO1xufVxuXG4vKipcbiAqIEBwYXJhbSBkYXRhXG4gKiBAcmV0dXJucyB7e2FsbERhdGE6IEFycmF5LCBmaWVsZHM6IEFycmF5fX1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlSW5wdXREYXRhKGRhdGEpIHtcbiAgLy8gVE9ETzogYWRkIHRlc3RcbiAgLypcbiAgICogZXhwZWN0ZWQgaW5wdXQgZGF0YSBmb3JtYXRcbiAgICoge1xuICAgKiAgIGZpZWxkczogW10sXG4gICAqICAgcm93czogW11cbiAgICogfVxuICAgKi9cbiAgbGV0IHByb2NlZWQgPSB0cnVlO1xuICBpZiAoIWRhdGEpIHtcbiAgICBhc3NlcnQoJ3JlY2VpdmVWaXNEYXRhOiBkYXRhIGNhbm5vdCBiZSBudWxsJyk7XG4gICAgcHJvY2VlZCA9IGZhbHNlO1xuICB9IGVsc2UgaWYgKCFBcnJheS5pc0FycmF5KGRhdGEuZmllbGRzKSkge1xuICAgIGFzc2VydCgncmVjZWl2ZVZpc0RhdGE6IGV4cGVjdCBkYXRhLmZpZWxkcyB0byBiZSBhbiBhcnJheScpO1xuICAgIHByb2NlZWQgPSBmYWxzZTtcbiAgfSBlbHNlIGlmICghQXJyYXkuaXNBcnJheShkYXRhLnJvd3MpKSB7XG4gICAgYXNzZXJ0KCdyZWNlaXZlVmlzRGF0YTogZXhwZWN0IGRhdGEucm93cyB0byBiZSBhbiBhcnJheScpO1xuICAgIHByb2NlZWQgPSBmYWxzZTtcbiAgfVxuXG4gIGlmICghcHJvY2VlZCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3Qge2ZpZWxkcywgcm93c30gPSBkYXRhO1xuXG4gIC8vIGNoZWNrIGlmIGFsbCBmaWVsZHMgaGFzIG5hbWUsIGZvcm1hdCBhbmQgdHlwZVxuICBjb25zdCBhbGxWYWxpZCA9IGZpZWxkcy5ldmVyeSgoZiwgaSkgPT4ge1xuICAgIGlmICh0eXBlb2YgZiAhPT0gJ29iamVjdCcpIHtcbiAgICAgIGFzc2VydChgZmllbGRzIG5lZWRzIHRvIGJlIGFuIGFycmF5IG9mIG9iamVjdCwgYnV0IGZpbmQgJHtmfWApO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmICghZi5uYW1lKSB7XG4gICAgICBhc3NlcnQoXG4gICAgICAgIGBmaWVsZC5uYW1lIGlzIHJlcXVpcmVkIGJ1dCBtaXNzaW5nIGluIGZpZWxkICR7SlNPTi5zdHJpbmdpZnkoZil9YFxuICAgICAgKTtcbiAgICAgIC8vIGFzc2lnbiBhIG5hbWVcbiAgICAgIGYubmFtZSA9IGBjb2x1bW5fJHtpfWA7XG4gICAgfVxuXG4gICAgaWYgKCFBTExfRklFTERfVFlQRVNbZi50eXBlXSkge1xuICAgICAgYXNzZXJ0KGB1bmtub3duIGZpZWxkIHR5cGUgJHtmLnR5cGV9YCk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIGYudHlwZSAmJiBmLmZvcm1hdCAmJiBmLm5hbWU7XG4gIH0pO1xuXG4gIGlmIChhbGxWYWxpZCkge1xuICAgIHJldHVybiB7cm93cywgZmllbGRzfTtcbiAgfVxuXG4gIC8vIGlmIGFueSBmaWVsZCBoYXMgbWlzc2luZyB0eXBlLCByZWNhbGN1bGF0ZSBpdCBmb3IgZXZlcnlvbmVcbiAgLy8gYmVjYXVzZSB3ZSBzaW1wbHkgbG9zdCBmYWl0aCBpbiBodW1hbml0eVxuICBjb25zdCBzYW1wbGVEYXRhID0gZ2V0U2FtcGxlRm9yVHlwZUFuYWx5emUoe2ZpZWxkczogZmllbGRzLm1hcChmID0+IGYubmFtZSksIGFsbERhdGE6IHJvd3N9KTtcbiAgY29uc3QgZmllbGRPcmRlciA9IGZpZWxkcy5tYXAoZiA9PiBmLm5hbWUpO1xuICBjb25zdCBtZXRhID0gZ2V0RmllbGRzRnJvbURhdGEoc2FtcGxlRGF0YSwgZmllbGRPcmRlcik7XG4gIGNvbnN0IHVwZGF0ZWRGaWVsZHMgPSBmaWVsZHMubWFwKChmLCBpKSA9PiAoe1xuICAgIC4uLmYsXG4gICAgdHlwZTogbWV0YVtpXS50eXBlLFxuICAgIGZvcm1hdDogbWV0YVtpXS5mb3JtYXRcbiAgfSkpO1xuXG4gIHJldHVybiB7ZmllbGRzOiB1cGRhdGVkRmllbGRzLCByb3dzfTtcbn1cblxuZXhwb3J0IGRlZmF1bHQge1xuICBwcm9jZXNzR2VvanNvbixcbiAgcHJvY2Vzc0NzdkRhdGEsXG4gIHByb2Nlc3NSb3dPYmplY3QsXG4gIGFuYWx5emVyVHlwZVRvRmllbGRUeXBlLFxuICBnZXRGaWVsZHNGcm9tRGF0YSxcbiAgcGFyc2VDc3ZEYXRhQnlGaWVsZFR5cGVcbn07XG4iXX0=
;