kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
725 lines (708 loc) • 97.3 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getFieldsFromTile = void 0;
exports.getFilterProps = getFilterProps;
exports.getLoaderOptions = void 0;
exports.getMetaUrl = getMetaUrl;
exports.getTileUrl = getTileUrl;
exports.isTileDataset = isTileDataset;
exports.matchDatasetType = matchDatasetType;
exports.parseVectorMetadata = parseVectorMetadata;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
var _typeAnalyzer = require("type-analyzer");
var _d3Array = require("d3-array");
var _console = _interopRequireDefault(require("global/console"));
var _lodash = _interopRequireDefault(require("lodash.uniq"));
var _mvt = require("@loaders.gl/mvt");
var _pmtiles = require("@loaders.gl/pmtiles");
var _commonUtils = require("@kepler.gl/common-utils");
var _constants = require("@kepler.gl/constants");
var _utils = require("@kepler.gl/utils");
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } // SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
var getLoaderOptions = exports.getLoaderOptions = function getLoaderOptions() {
return {
mvt: {
workerUrl: "https://unpkg.com/@loaders.gl/mvt/dist/mvt-worker.js"
}
};
};
function isTileDataset(dataset) {
return Boolean((dataset === null || dataset === void 0 ? void 0 : dataset.type) === _constants.DatasetType.VECTOR_TILE);
}
// https://github.com/mapbox/tilejson-spec/tree/master/2.2.0
function isLat(num) {
return Number.isFinite(num) && num <= 90 && num >= -90;
}
function isLng(num) {
return Number.isFinite(num) && num <= 180 && num >= -180;
}
function isZoom(num) {
return Number.isFinite(num) && num >= 0 && num <= 22;
}
function fromArrayOrString(data) {
if (typeof data === 'string') {
return data.split(',').map(parseFloat);
} else if (Array.isArray(data)) {
return data;
}
return null;
}
function parseCenter(center) {
// supported formats
// string: "-96.657715,40.126127,-90.140061,43.516689",
// array: [-91.505127,41.615442,14]
var result = fromArrayOrString(center);
if (Array.isArray(result) && result.length === 3 && isLng(result[0]) && isLat(result[1]) && isZoom(result[2])) {
return result;
}
return null;
}
/**
* bounds should be [minLng, minLat, maxLng, maxLat]
* @param {*} bounds
*/
function parseBounds(bounds) {
// supported formats
// string: "-96.657715,40.126127,-90.140061,43.516689",
// array: [ -180, -85.05112877980659, 180, 85.0511287798066 ]
var result = fromArrayOrString(bounds);
// validate bounds
if (Array.isArray(result) && result.length === 4 && [result[0], result[2]].every(isLng) && [result[1], result[3]].every(isLat)) {
return result;
}
return null;
}
var X_PATT = /\{x\}/;
var Y_PATT = /\{y\}/;
var Z_PATT = /\{z\}/;
function isFullyQualifiedTileUrl(tileUrl) {
return X_PATT.test(tileUrl) && Y_PATT.test(tileUrl) && Z_PATT.test(tileUrl);
}
/**
* Normalize tile URL
* @param {string} tileUrl Initial tile URL, which may be either the root URL for the
* tileset or a fully qualified template
* @param {function} validateUrl function to validate tile URL
* @return {string|null} Fully qualified tile URL template, or null if input does not
* appear to be a valid URL
*/
function getTileUrl(tileUrl) {
var validateUrl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : isFullyQualifiedTileUrl;
// Check for a valid URL. Ideally we'd have a simple method here.
var uriParts = (0, _commonUtils.parseUri)(tileUrl);
if (!uriParts.protocol || !uriParts.host) {
return null;
}
if (validateUrl(tileUrl)) {
return tileUrl;
}
return "".concat(tileUrl.replace(/\/$/, ''), "/{z}/{x}/{y}.pbf");
}
/**
* Map of util functions for different tileset types, keyed by host
*/
var TILESET_FUNCTIONS = {
'api.mapbox.com': {
getMetaUrl: getMetaUrlMapbox,
parseMetadata: parseMetadataTileJSON
},
"default": {
getMetaUrl: getMetaUrlTippecanoe,
parseMetadata: parseMetadataTileJSON
}
};
function getTilesetFunctions(tileUrl) {
var host = '';
try {
host = new URL(tileUrl || '').hostname;
} catch (error) {
// do nothing
}
return TILESET_FUNCTIONS[host] || TILESET_FUNCTIONS["default"];
}
/**
* Get the metadata URL for a given tileset
*/
function getMetaUrl(tileUrl) {
return getTilesetFunctions(tileUrl).getMetaUrl(tileUrl);
}
/**
* Parse the metadata for a given tileset
*/
function parseVectorMetadata(
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
metadata, option) {
var _ref = option || {},
_ref$tileUrl = _ref.tileUrl,
tileUrl = _ref$tileUrl === void 0 ? '' : _ref$tileUrl;
return getTilesetFunctions(tileUrl).parseMetadata(metadata);
}
var MAPBOX_URL_PATT = /\/\{z\}\/\{x\}\/\{y\}\.mvt/;
function getMetaUrlMapbox() {
var tileUrl = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
return tileUrl.replace(MAPBOX_URL_PATT, '.json');
}
function parseMetadataTileJSON(metadata) {
var _parsed$fields;
var parsed = parseMetadataTippecanoeFromDataSource(metadata);
if (!parsed) return null;
// Fields already parsed from `json` property
if ((_parsed$fields = parsed.fields) !== null && _parsed$fields !== void 0 && _parsed$fields.length) {
return parsed;
}
return parsed;
}
function getMetaUrlTippecanoe(tileUrl) {
var url = getTileUrl(tileUrl);
if (!url) return null;
// assumes the structure <url_base>/{z}...
var baseUrl = url.split(Z_PATT)[0].replace(/\/$/, '');
return "".concat(baseUrl, "/metadata.json");
}
/**
* Special parsing for metadata returned by MVTSource and PMTilesSource.
* @param metadata Tileset metadata parsed by a DataSouce
* @returns Metadata in Kepler-friendly format.
*/
function parseMetadataTippecanoeFromDataSource(metadata) {
var _pmTileMetadata$tilej, _pmTileMetadata$tilej2;
if (!metadata || (0, _typeof2["default"])(metadata) !== 'object') {
return null;
}
var result = {
attributions: [],
metaJson: null,
bounds: null,
center: null,
maxZoom: null,
minZoom: null,
fields: []
};
var mvtMetadata = metadata;
var pmTileMetadata = metadata;
// try to parse metaJson
if (typeof mvtMetadata.metaJson === 'string') {
try {
result.metaJson = JSON.parse(mvtMetadata.metaJson);
} catch (err) {
// do nothing
}
} else if ((0, _typeof2["default"])(mvtMetadata.metaJson) === 'object') {
result.metaJson = mvtMetadata.metaJson;
}
result.bounds = parseBounds(Array.isArray(metadata.boundingBox) ? metadata.boundingBox.flat() : '');
// PMTileSource has centerZoom and center [lon, lat], MVTSource - [lon, lat, zoom]
var center = pmTileMetadata.centerZoom !== undefined && Array.isArray(metadata.center) ? [].concat((0, _toConsumableArray2["default"])(metadata.center), [pmTileMetadata.centerZoom]) : metadata.center;
result.center = parseCenter(center || '');
result.maxZoom = safeParseFloat(metadata.maxZoom);
result.minZoom = safeParseFloat(metadata.minZoom);
result.name = metadata.name || '';
result.description = mvtMetadata.description || ((_pmTileMetadata$tilej = pmTileMetadata.tilejson) === null || _pmTileMetadata$tilej === void 0 ? void 0 : _pmTileMetadata$tilej.description) || '';
if (Array.isArray((_pmTileMetadata$tilej2 = pmTileMetadata.tilejson) === null || _pmTileMetadata$tilej2 === void 0 ? void 0 : _pmTileMetadata$tilej2.layers)) {
var _pmTileMetadata$tilej3;
var layers = pmTilesLayerToTippecanoeLayer((_pmTileMetadata$tilej3 = pmTileMetadata.tilejson) === null || _pmTileMetadata$tilej3 === void 0 ? void 0 : _pmTileMetadata$tilej3.layers);
result.fields = collectAttributes(layers);
} else if (Array.isArray(mvtMetadata.layers)) {
var _layers = pmTilesLayerToTippecanoeLayer(mvtMetadata.layers);
result.fields = collectAttributes(_layers);
}
result = _objectSpread(_objectSpread({}, result), {}, {
attributions: pmTileMetadata.attributions || (mvtMetadata.htmlAttribution ? [mvtMetadata.htmlAttribution] : undefined) || []
}, parseMetaJson(result.metaJson));
return result;
}
function safeParseFloat(input) {
var result = typeof input === 'string' ? parseFloat(input) : typeof input === 'number' ? input : null;
return result === null || isNaN(result) ? null : result;
}
function parseMetaJson(metaJson) {
if (!metaJson || (0, _typeof2["default"])(metaJson) !== 'object') {
return null;
}
if (metaJson.tilestats && Array.isArray(metaJson.tilestats.layers)) {
// we are in luck!
return {
fields: collectAttributes(metaJson.tilestats.layers)
};
}
return null;
}
function getTimeAnimationDomain(mappedValue) {
var timeSteps = (0, _lodash["default"])(mappedValue).sort(_d3Array.ascending).filter(_commonUtils.notNullorUndefined);
var domain = [timeSteps[0], timeSteps[timeSteps.length - 1]];
// if taks 10 * 1000 ms to finish the entire animation
var duration = 10000 / timeSteps.length;
var clamped = (0, _utils.clamp)([100, 2000], duration);
return {
domain: domain,
timeSteps: timeSteps,
duration: clamped,
mappedValue: mappedValue
};
}
var pmTileTypeToAttrMap = {
float32: 'number',
string: 'string',
utf8: 'string',
"int": 'int',
"boolean": 'boolean'
};
/**
* Transform TileJSON['layers'] back to TippecanoeLayer
*/
function pmTilesLayerToTippecanoeLayer(layers) {
if (!layers) return [];
var outLayers = [];
var _iterator = _createForOfIteratorHelper(layers),
_step;
try {
for (_iterator.s(); !(_step = _iterator.n()).done;) {
var layer = _step.value;
var _ref2 = layer || {},
_ref2$fields = _ref2.fields,
fields = _ref2$fields === void 0 ? [] : _ref2$fields;
var _iterator2 = _createForOfIteratorHelper(fields),
_step2;
try {
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
var _pmField$values;
var pmField = _step2.value;
var attribute = {
attribute: pmField.name,
type: pmTileTypeToAttrMap[pmField.type],
count: pmField.uniqueValueCount,
values: (_pmField$values = pmField.values) !== null && _pmField$values !== void 0 ? _pmField$values : [],
min: pmField.min,
max: pmField.max
};
outLayers.push({
attributes: [attribute]
});
}
} catch (err) {
_iterator2.e(err);
} finally {
_iterator2.f();
}
}
} catch (err) {
_iterator.e(err);
} finally {
_iterator.f();
}
return outLayers;
}
function collectAttributes() {
var layers = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
var fields = {};
var indexedAttributes = {};
var _iterator3 = _createForOfIteratorHelper(layers),
_step3;
try {
for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
var layer = _step3.value;
var _ref3 = layer || {},
_ref3$attributes = _ref3.attributes,
attributes = _ref3$attributes === void 0 ? [] : _ref3$attributes;
var _iterator5 = _createForOfIteratorHelper(attributes),
_step5;
try {
for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
var attr = _step5.value;
var _name = attr.attribute;
if (typeof _name === 'string') {
// eslint-disable-next-line max-depth
if (_name.split('|').length > 1) {
// indexed field
var fname = _name.split('|')[0];
indexedAttributes[fname] = indexedAttributes[fname] || [];
indexedAttributes[fname].push(attr);
} else if (!fields[_name]) {
fields[_name] = attributeToField(attr);
} else {
mergeAttributeDomain(fields[_name], attr);
}
}
}
} catch (err) {
_iterator5.e(err);
} finally {
_iterator5.f();
}
}
// parse indexed attribute, and put index key unidentified back as normal field
} catch (err) {
_iterator3.e(err);
} finally {
_iterator3.f();
}
for (var _i = 0, _Object$entries = Object.entries(indexedAttributes); _i < _Object$entries.length; _i++) {
var _Object$entries$_i = (0, _slicedToArray2["default"])(_Object$entries[_i], 2),
name = _Object$entries$_i[0],
attrs = _Object$entries$_i[1];
var _parseIndexedField = parseIndexedField(name, attrs),
indexedField = _parseIndexedField.indexedField,
unidentified = _parseIndexedField.unidentified;
fields[indexedField.name] = indexedField;
var _iterator4 = _createForOfIteratorHelper(unidentified),
_step4;
try {
for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
var unidentifiedAttr = _step4.value;
if (unidentifiedAttr.attribute) {
fields[unidentifiedAttr.attribute] = fields[unidentifiedAttr.attribute] || attributeToField(unidentifiedAttr);
mergeAttributeDomain(fields[unidentifiedAttr.attribute], unidentifiedAttr);
}
}
} catch (err) {
_iterator4.e(err);
} finally {
_iterator4.f();
}
}
return Object.values(fields);
}
function getIndexKeyFromFieldName(name) {
return name && name.split('|').length > 1 ? name.split('|')[1] : null;
}
function parseIndexedField(name, attrs) {
var unidentified = [];
// analyze time format
var field;
var _iterator6 = _createForOfIteratorHelper(attrs),
_step6;
try {
for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
var attr = _step6.value;
var fieldName = attr.attribute;
var indexKey = getIndexKeyFromFieldName(fieldName || '');
var analyzedType = indexKey && (0, _commonUtils.containValidTime)([indexKey]);
if (analyzedType) {
field = field || _objectSpread(_objectSpread({}, attributeToField(attr)), {}, {
// overide name and id to truncated name
name: name,
id: name,
indexBy: {
format: analyzedType.format,
type: (0, _commonUtils.analyzerTypeToFieldType)(analyzedType.type),
mappedValue: {}
}
});
mergeAttributeDomain(field, attr);
// save epoch time in mappedValue
var fieldTs = indexKey;
if (analyzedType.format === 'x' || analyzedType.format === 'X') {
fieldTs = Number(indexKey);
}
var epoch = (0, _utils.timeToUnixMilli)(fieldTs, analyzedType.format);
if (epoch) {
field.indexBy.mappedValue[epoch] = fieldName;
}
} else {
// key is not valid timestamp
unidentified.push(attr);
}
}
} catch (err) {
_iterator6.e(err);
} finally {
_iterator6.f();
}
if (field.indexBy && field.indexBy.type === _constants.ALL_FIELD_TYPES.timestamp) {
field.indexBy.timeDomain = getTimeAnimationDomain(Object.keys(field.indexBy.mappedValue).map(Number));
}
return {
unidentified: unidentified,
indexedField: field
};
}
function compare(num1, num2, operator) {
return Number.isFinite(num1) && Number.isFinite(num2) ? Math[operator](num1, num2) : Number.isFinite(num1) ? num1 : Number.isFinite(num2) ? num2 : NaN;
}
function getFilterProps(fieldType, attribute) {
switch (fieldType) {
case _constants.ALL_FIELD_TYPES.real:
case _constants.ALL_FIELD_TYPES.integer:
{
var _getAttributeDomain = getAttributeDomain(fieldType, attribute),
_getAttributeDomain2 = (0, _slicedToArray2["default"])(_getAttributeDomain, 2),
min = _getAttributeDomain2[0],
max = _getAttributeDomain2[1];
var diff = max - min;
var step = (0, _utils.getNumericStepSize)(diff) || 0.1;
var domain = [(0, _utils.formatNumberByStep)(min, step, 'floor'), (0, _utils.formatNumberByStep)(max, step, 'ceil')];
var filterProps = {
domain: domain,
value: domain,
type: _constants.FILTER_TYPES.range,
typeOptions: [_constants.FILTER_TYPES.range],
gpu: true,
step: step
};
return filterProps;
}
case _constants.ALL_FIELD_TYPES["boolean"]:
{
var _filterProps = {
domain: [true, false],
value: true,
type: _constants.FILTER_TYPES.select,
gpu: true
};
return _filterProps;
}
default:
{
// Assume string for all other fields
var _filterProps2 = {
domain: attribute.values,
value: attribute.values,
type: _constants.FILTER_TYPES.multiSelect,
gpu: false
};
return _filterProps2;
}
}
}
function attributeToField() {
var attribute = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
values: []
};
// attribute: "_season_peaks_color"
// count: 1000
// max: 0.95
// min: 0.24375
// type: "number"
var fieldTypes = attributeTypeToFieldType(attribute.type);
return _objectSpread({
name: attribute.attribute,
id: attribute.attribute,
format: '',
filterProps: getFilterProps(fieldTypes.type, attribute)
}, fieldTypes);
}
function getAttributeDomain(type, attribute) {
switch (type) {
case _constants.ALL_FIELD_TYPES.real:
case _constants.ALL_FIELD_TYPES.integer:
return [Number.isFinite(attribute.min) ? attribute.min : NaN, Number.isFinite(attribute.max) ? attribute.max : NaN];
case _constants.ALL_FIELD_TYPES["boolean"]:
return [0, 1];
default:
return [0, 1];
}
}
/**
* @param field This function mutates the field parameter
*/
function mergeAttributeDomain(field, attribute) {
switch (field.type) {
case _constants.ALL_FIELD_TYPES.real:
case _constants.ALL_FIELD_TYPES.integer:
{
var _field$metadata, _field$filterProps;
var domain = ((_field$metadata = field.metadata) === null || _field$metadata === void 0 ? void 0 : _field$metadata.domain) || ((_field$filterProps = field.filterProps) === null || _field$filterProps === void 0 ? void 0 : _field$filterProps.domain);
if (domain) {
domain.min = compare(attribute.min, domain[0], 'min');
domain.max = compare(attribute.max, domain[1], 'max');
}
return;
}
default:
return;
}
}
// possible types https://github.com/mapbox/tippecanoe#modifying-feature-attributes
var attrTypeMap = {
number: {
type: _constants.ALL_FIELD_TYPES.real,
analyzerType: _typeAnalyzer.DATA_TYPES.FLOAT
},
numeric: {
type: _constants.ALL_FIELD_TYPES.real,
analyzerType: _typeAnalyzer.DATA_TYPES.FLOAT
},
string: {
type: _constants.ALL_FIELD_TYPES.string,
analyzerType: _typeAnalyzer.DATA_TYPES.STRING
},
vachar: {
type: _constants.ALL_FIELD_TYPES.string,
analyzerType: _typeAnalyzer.DATA_TYPES.STRING
},
"float": {
type: _constants.ALL_FIELD_TYPES.real,
analyzerType: _typeAnalyzer.DATA_TYPES.FLOAT
},
"int": {
type: _constants.ALL_FIELD_TYPES.integer,
analyzerType: _typeAnalyzer.DATA_TYPES.INT
},
int4: {
type: _constants.ALL_FIELD_TYPES.integer,
analyzerType: _typeAnalyzer.DATA_TYPES.INT
},
"boolean": {
type: _constants.ALL_FIELD_TYPES["boolean"],
analyzerType: _typeAnalyzer.DATA_TYPES.BOOLEAN
},
bool: {
type: _constants.ALL_FIELD_TYPES["boolean"],
analyzerType: _typeAnalyzer.DATA_TYPES.BOOLEAN
}
};
function attributeTypeToFieldType(aType) {
var type = aType === null || aType === void 0 ? void 0 : aType.toLowerCase();
if (!type || !attrTypeMap[type]) {
_console["default"].warn("cannot convert attribute type ".concat(type, " to kepler.gl data type, use string by default"));
return attrTypeMap.string;
}
return attrTypeMap[type];
}
/**
* Returns true if a dataset can be used as source data for a layer.
* @param dataset A dataset.
* @param layer A layer.
* @returns Returns true if a dataset can be used as source data for a layer.
*/
function matchDatasetType(dataset, layer) {
// allow selection if type is not assigned yet
if (!layer.type) {
return true;
}
// allow selection if is current selected dataset
if (layer.config.dataId === dataset.id) {
return true;
}
// allow selection if layer doesn't have supportedDatasetTypes
if (!layer.supportedDatasetTypes) {
return true;
}
return Array.isArray(layer.supportedDatasetTypes) && layer.supportedDatasetTypes.includes(dataset.type || '');
}
/**
* Extracts fields from a tile and updates the metadata object with found fields.
* Note: this function is for tilesets that don't include fields in metadata (most likely saved with older spec.).
* @param params.remoteTileFormat The format of the remote tile (MVT or PMTiles).
* @param params.tilesetUrl The URL of the tileset.
* @param params.metadataUrl The URL of the metadata.
* @param params.metadata The metadata object containing fields and tile properties.
*/
var getFieldsFromTile = exports.getFieldsFromTile = /*#__PURE__*/function () {
var _ref5 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(_ref4) {
var remoteTileFormat, tilesetUrl, metadataUrl, metadata, _metadata$fields, _metadata$bounds, lon, lat, tileIndices, tileSource, tile, updatedFields;
return _regenerator["default"].wrap(function _callee$(_context) {
while (1) switch (_context.prev = _context.next) {
case 0:
remoteTileFormat = _ref4.remoteTileFormat, tilesetUrl = _ref4.tilesetUrl, metadataUrl = _ref4.metadataUrl, metadata = _ref4.metadata;
_context.prev = 1;
if (!(tilesetUrl && metadataUrl && metadata && ((_metadata$fields = metadata.fields) === null || _metadata$fields === void 0 ? void 0 : _metadata$fields.length) === 0 && metadata.minZoom && ((_metadata$bounds = metadata.bounds) === null || _metadata$bounds === void 0 ? void 0 : _metadata$bounds.length) === 4)) {
_context.next = 12;
break;
}
lon = (metadata.bounds[0] + metadata.bounds[2]) / 2;
lat = (metadata.bounds[1] + metadata.bounds[3]) / 2;
tileIndices = lonLatToTileIndex(lon, lat, metadata.minZoom);
tileSource = remoteTileFormat === _constants.RemoteTileFormat.MVT ? _mvt.MVTSource.createDataSource(decodeURIComponent(tilesetUrl), {
mvt: {
metadataUrl: decodeURIComponent(metadataUrl)
}
}) : _pmtiles.PMTilesSource.createDataSource(tilesetUrl, {});
_context.next = 9;
return tileSource.getTileData({
index: tileIndices
});
case 9:
tile = _context.sent;
updatedFields = tileToFields(tile).map(function (f) {
return _objectSpread(_objectSpread({}, f), {}, {
analyzerType: f.analyzerType || _constants.ALL_FIELD_TYPES.string,
id: f.id || f.name
});
});
metadata.fields = updatedFields;
case 12:
_context.next = 16;
break;
case 14:
_context.prev = 14;
_context.t0 = _context["catch"](1);
case 16:
case "end":
return _context.stop();
}
}, _callee, null, [[1, 14]]);
}));
return function getFieldsFromTile(_x) {
return _ref5.apply(this, arguments);
};
}();
/**
* Converts tile features into Kepler fields.
* @param tile The tile object containing features.
* @returns An array of Kepler fields derived from the tile's features.
*/
var tileToFields = function tileToFields(tile) {
var _tile$features;
if ((tile === null || tile === void 0 || (_tile$features = tile.features) === null || _tile$features === void 0 ? void 0 : _tile$features.length) > 0) {
var header = Object.keys(tile.features[0].properties);
var output = tile.features.map(function (f) {
var obj = {};
header.forEach(function (columnName) {
obj[columnName] = f.properties[columnName];
});
return obj;
});
var fields = (0, _commonUtils.getFieldsFromData)(output, header);
// extra transformation of strings to numbers for tiles isn't implemented, so use string, not computed types
return fields.map(function (f) {
var forceString = (f.type === 'integer' || f.type === 'float') && typeof tile.features[0].properties[f.name] === 'string';
return _objectSpread(_objectSpread({}, f), {}, {
analyzerType: forceString ? _typeAnalyzer.DATA_TYPES.STRING : f.analyzerType,
type: forceString ? 'string' : f.type
});
});
}
return [];
};
/**
* Converts longitude, latitude, and zoom level into vector tile indices (x, y, z).
* @param lon Longitude in degrees, ranging from -180 to 180.
* @param lat Latitude in degrees, ranging from -90 to 90.
* @param zoom Zoom level (integer), where higher values provide more detail.
* @returns Tile indices with x and y coordinates and zoom level z.
*/
function lonLatToTileIndex(lon, lat, zoom) {
if (lat < -85.0511 || lat > 85.0511) {
throw new Error('Latitude out of range. Must be between -85.0511 and 85.0511.');
}
if (zoom < 0) {
throw new Error('Zoom level must be a non-negative integer.');
}
// 2^zoom (number of tiles per axis at given zoom level)
var scale = 1 << zoom;
// Convert longitude to tile X
var x = Math.floor((lon + 180) / 360 * scale);
// Convert latitude to tile Y
var latRad = lat * Math.PI / 180;
var y = Math.floor((1 - Math.log(Math.tan(latRad) + 1 / Math.cos(latRad)) / Math.PI) / 2 * scale);
return {
x: x,
y: y,
z: zoom
};
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfdHlwZUFuYWx5emVyIiwicmVxdWlyZSIsIl9kM0FycmF5IiwiX2NvbnNvbGUiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwiX2xvZGFzaCIsIl9tdnQiLCJfcG10aWxlcyIsIl9jb21tb25VdGlscyIsIl9jb25zdGFudHMiLCJfdXRpbHMiLCJfY3JlYXRlRm9yT2ZJdGVyYXRvckhlbHBlciIsInIiLCJlIiwidCIsIlN5bWJvbCIsIml0ZXJhdG9yIiwiQXJyYXkiLCJpc0FycmF5IiwiX3Vuc3VwcG9ydGVkSXRlcmFibGVUb0FycmF5IiwibGVuZ3RoIiwiX24iLCJGIiwicyIsIm4iLCJkb25lIiwidmFsdWUiLCJmIiwiVHlwZUVycm9yIiwibyIsImEiLCJ1IiwiY2FsbCIsIm5leHQiLCJfYXJyYXlMaWtlVG9BcnJheSIsInRvU3RyaW5nIiwic2xpY2UiLCJjb25zdHJ1Y3RvciIsIm5hbWUiLCJmcm9tIiwidGVzdCIsIm93bktleXMiLCJPYmplY3QiLCJrZXlzIiwiZ2V0T3duUHJvcGVydHlTeW1ib2xzIiwiZmlsdGVyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwiZW51bWVyYWJsZSIsInB1c2giLCJhcHBseSIsIl9vYmplY3RTcHJlYWQiLCJhcmd1bWVudHMiLCJmb3JFYWNoIiwiX2RlZmluZVByb3BlcnR5MiIsImdldE93blByb3BlcnR5RGVzY3JpcHRvcnMiLCJkZWZpbmVQcm9wZXJ0aWVzIiwiZGVmaW5lUHJvcGVydHkiLCJnZXRMb2FkZXJPcHRpb25zIiwiZXhwb3J0cyIsIm12dCIsIndvcmtlclVybCIsImlzVGlsZURhdGFzZXQiLCJkYXRhc2V0IiwiQm9vbGVhbiIsInR5cGUiLCJEYXRhc2V0VHlwZSIsIlZFQ1RPUl9USUxFIiwiaXNMYXQiLCJudW0iLCJOdW1iZXIiLCJpc0Zpbml0ZSIsImlzTG5nIiwiaXNab29tIiwiZnJvbUFycmF5T3JTdHJpbmciLCJkYXRhIiwic3BsaXQiLCJtYXAiLCJwYXJzZUZsb2F0IiwicGFyc2VDZW50ZXIiLCJjZW50ZXIiLCJyZXN1bHQiLCJwYXJzZUJvdW5kcyIsImJvdW5kcyIsImV2ZXJ5IiwiWF9QQVRUIiwiWV9QQVRUIiwiWl9QQVRUIiwiaXNGdWxseVF1YWxpZmllZFRpbGVVcmwiLCJ0aWxlVXJsIiwiZ2V0VGlsZVVybCIsInZhbGlkYXRlVXJsIiwidW5kZWZpbmVkIiwidXJpUGFydHMiLCJwYXJzZVVyaSIsInByb3RvY29sIiwiaG9zdCIsImNvbmNhdCIsInJlcGxhY2UiLCJUSUxFU0VUX0ZVTkNUSU9OUyIsImdldE1ldGFVcmwiLCJnZXRNZXRhVXJsTWFwYm94IiwicGFyc2VNZXRhZGF0YSIsInBhcnNlTWV0YWRhdGFUaWxlSlNPTiIsImdldE1ldGFVcmxUaXBwZWNhbm9lIiwiZ2V0VGlsZXNldEZ1bmN0aW9ucyIsIlVSTCIsImhvc3RuYW1lIiwiZXJyb3IiLCJwYXJzZVZlY3Rvck1ldGFkYXRhIiwibWV0YWRhdGEiLCJvcHRpb24iLCJfcmVmIiwiX3JlZiR0aWxlVXJsIiwiTUFQQk9YX1VSTF9QQVRUIiwiX3BhcnNlZCRmaWVsZHMiLCJwYXJzZWQiLCJwYXJzZU1ldGFkYXRhVGlwcGVjYW5vZUZyb21EYXRhU291cmNlIiwiZmllbGRzIiwidXJsIiwiYmFzZVVybCIsIl9wbVRpbGVNZXRhZGF0YSR0aWxlaiIsIl9wbVRpbGVNZXRhZGF0YSR0aWxlajIiLCJfdHlwZW9mMiIsImF0dHJpYnV0aW9ucyIsIm1ldGFKc29uIiwibWF4Wm9vbSIsIm1pblpvb20iLCJtdnRNZXRhZGF0YSIsInBtVGlsZU1ldGFkYXRhIiwiSlNPTiIsInBhcnNlIiwiZXJyIiwiYm91bmRpbmdCb3giLCJmbGF0IiwiY2VudGVyWm9vbSIsIl90b0NvbnN1bWFibGVBcnJheTIiLCJzYWZlUGFyc2VGbG9hdCIsImRlc2NyaXB0aW9uIiwidGlsZWpzb24iLCJsYXllcnMiLCJfcG1UaWxlTWV0YWRhdGEkdGlsZWozIiwicG1UaWxlc0xheWVyVG9UaXBwZWNhbm9lTGF5ZXIiLCJjb2xsZWN0QXR0cmlidXRlcyIsImh0bWxBdHRyaWJ1dGlvbiIsInBhcnNlTWV0YUpzb24iLCJpbnB1dCIsImlzTmFOIiwidGlsZXN0YXRzIiwiZ2V0VGltZUFuaW1hdGlvbkRvbWFpbiIsIm1hcHBlZFZhbHVlIiwidGltZVN0ZXBzIiwidW5pcSIsInNvcnQiLCJhc2NlbmRpbmciLCJub3ROdWxsT3JVbmRlZmluZWQiLCJkb21haW4iLCJkdXJhdGlvbiIsImNsYW1wZWQiLCJjbGFtcCIsInBtVGlsZVR5cGVUb0F0dHJNYXAiLCJmbG9hdDMyIiwic3RyaW5nIiwidXRmOCIsIm91dExheWVycyIsIl9pdGVyYXRvciIsIl9zdGVwIiwibGF5ZXIiLCJfcmVmMiIsIl9yZWYyJGZpZWxkcyIsIl9pdGVyYXRvcjIiLCJfc3RlcDIiLCJfcG1GaWVsZCR2YWx1ZXMiLCJwbUZpZWxkIiwiYXR0cmlidXRlIiwiY291bnQiLCJ1bmlxdWVWYWx1ZUNvdW50IiwidmFsdWVzIiwibWluIiwibWF4IiwiYXR0cmlidXRlcyIsImluZGV4ZWRBdHRyaWJ1dGVzIiwiX2l0ZXJhdG9yMyIsIl9zdGVwMyIsIl9yZWYzIiwiX3JlZjMkYXR0cmlidXRlcyIsIl9pdGVyYXRvcjUiLCJfc3RlcDUiLCJhdHRyIiwiZm5hbWUiLCJhdHRyaWJ1dGVUb0ZpZWxkIiwibWVyZ2VBdHRyaWJ1dGVEb21haW4iLCJfaSIsIl9PYmplY3QkZW50cmllcyIsImVudHJpZXMiLCJfT2JqZWN0JGVudHJpZXMkX2kiLCJfc2xpY2VkVG9BcnJheTIiLCJhdHRycyIsIl9wYXJzZUluZGV4ZWRGaWVsZCIsInBhcnNlSW5kZXhlZEZpZWxkIiwiaW5kZXhlZEZpZWxkIiwidW5pZGVudGlmaWVkIiwiX2l0ZXJhdG9yNCIsIl9zdGVwNCIsInVuaWRlbnRpZmllZEF0dHIiLCJnZXRJbmRleEtleUZyb21GaWVsZE5hbWUiLCJmaWVsZCIsIl9pdGVyYXRvcjYiLCJfc3RlcDYiLCJmaWVsZE5hbWUiLCJpbmRleEtleSIsImFuYWx5emVkVHlwZSIsImNvbnRhaW5WYWxpZFRpbWUiLCJpZCIsImluZGV4QnkiLCJmb3JtYXQiLCJhbmFseXplclR5cGVUb0ZpZWxkVHlwZSIsImZpZWxkVHMiLCJlcG9jaCIsInRpbWVUb1VuaXhNaWxsaSIsIkFMTF9GSUVMRF9UWVBFUyIsInRpbWVzdGFtcCIsInRpbWVEb21haW4iLCJjb21wYXJlIiwibnVtMSIsIm51bTIiLCJvcGVyYXRvciIsIk1hdGgiLCJOYU4iLCJnZXRGaWx0ZXJQcm9wcyIsImZpZWxkVHlwZSIsInJlYWwiLCJpbnRlZ2VyIiwiX2dldEF0dHJpYnV0ZURvbWFpbiIsImdldEF0dHJpYnV0ZURvbWFpbiIsIl9nZXRBdHRyaWJ1dGVEb21haW4yIiwiZGlmZiIsInN0ZXAiLCJnZXROdW1lcmljU3RlcFNpemUiLCJmb3JtYXROdW1iZXJCeVN0ZXAiLCJmaWx0ZXJQcm9wcyIsIkZJTFRFUl9UWVBFUyIsInJhbmdlIiwidHlwZU9wdGlvbnMiLCJncHUiLCJzZWxlY3QiLCJtdWx0aVNlbGVjdCIsImZpZWxkVHlwZXMiLCJhdHRyaWJ1dGVUeXBlVG9GaWVsZFR5cGUiLCJfZmllbGQkbWV0YWRhdGEiLCJfZmllbGQkZmlsdGVyUHJvcHMiLCJhdHRyVHlwZU1hcCIsIm51bWJlciIsImFuYWx5emVyVHlwZSIsIkRBVEFfVFlQRVMiLCJGTE9BVCIsIm51bWVyaWMiLCJTVFJJTkciLCJ2YWNoYXIiLCJJTlQiLCJpbnQ0IiwiQk9PTEVBTiIsImJvb2wiLCJhVHlwZSIsInRvTG93ZXJDYXNlIiwiQ29uc29sZSIsIndhcm4iLCJtYXRjaERhdGFzZXRUeXBlIiwiY29uZmlnIiwiZGF0YUlkIiwic3VwcG9ydGVkRGF0YXNldFR5cGVzIiwiaW5jbHVkZXMiLCJnZXRGaWVsZHNGcm9tVGlsZSIsIl9yZWY1IiwiX2FzeW5jVG9HZW5lcmF0b3IyIiwiX3JlZ2VuZXJhdG9yIiwibWFyayIsIl9jYWxsZWUiLCJfcmVmNCIsInJlbW90ZVRpbGVGb3JtYXQiLCJ0aWxlc2V0VXJsIiwibWV0YWRhdGFVcmwiLCJfbWV0YWRhdGEkZmllbGRzIiwiX21ldGFkYXRhJGJvdW5kcyIsImxvbiIsImxhdCIsInRpbGVJbmRpY2VzIiwidGlsZVNvdXJjZSIsInRpbGUiLCJ1cGRhdGVkRmllbGRzIiwid3JhcCIsIl9jYWxsZWUkIiwiX2NvbnRleHQiLCJwcmV2IiwibG9uTGF0VG9UaWxlSW5kZXgiLCJSZW1vdGVUaWxlRm9ybWF0IiwiTVZUIiwiTVZUU291cmNlIiwiY3JlYXRlRGF0YVNvdXJjZSIsImRlY29kZVVSSUNvbXBvbmVudCIsIlBNVGlsZXNTb3VyY2UiLCJnZXRUaWxlRGF0YSIsImluZGV4Iiwic2VudCIsInRpbGVUb0ZpZWxkcyIsInQwIiwic3RvcCIsIl94IiwiX3RpbGUkZmVhdHVyZXMiLCJmZWF0dXJlcyIsImhlYWRlciIsInByb3BlcnRpZXMiLCJvdXRwdXQiLCJvYmoiLCJjb2x1bW5OYW1lIiwiZ2V0RmllbGRzRnJvbURhdGEiLCJmb3JjZVN0cmluZyIsIkFOQUxZWkVSX0RBVEFfVFlQRVMiLCJ6b29tIiwiRXJyb3IiLCJzY2FsZSIsIngiLCJmbG9vciIsImxhdFJhZCIsIlBJIiwieSIsImxvZyIsInRhbiIsImNvcyIsInoiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvdGlsZXNldC92ZWN0b3ItdGlsZS11dGlscy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4vLyBDb3B5cmlnaHQgY29udHJpYnV0b3JzIHRvIHRoZSBrZXBsZXIuZ2wgcHJvamVjdFxuXG5pbXBvcnQge0RBVEFfVFlQRVMgYXMgQU5BTFlaRVJfREFUQV9UWVBFU30gZnJvbSAndHlwZS1hbmFseXplcic7XG5pbXBvcnQge2FzY2VuZGluZ30gZnJvbSAnZDMtYXJyYXknO1xuaW1wb3J0IENvbnNvbGUgZnJvbSAnZ2xvYmFsL2NvbnNvbGUnO1xuaW1wb3J0IHVuaXEgZnJvbSAnbG9kYXNoLnVuaXEnO1xuaW1wb3J0IHtEQVRBX1RZUEVTfSBmcm9tICd0eXBlLWFuYWx5emVyJztcblxuaW1wb3J0IHtNVlRTb3VyY2UsIFRpbGVKU09OfSBmcm9tICdAbG9hZGVycy5nbC9tdnQnO1xuaW1wb3J0IHtQTVRpbGVzU291cmNlLCBQTVRpbGVzTWV0YWRhdGF9IGZyb20gJ0Bsb2FkZXJzLmdsL3BtdGlsZXMnO1xuXG5pbXBvcnQge1xuICBhbmFseXplclR5cGVUb0ZpZWxkVHlwZSxcbiAgY29udGFpblZhbGlkVGltZSxcbiAgbm90TnVsbG9yVW5kZWZpbmVkIGFzIG5vdE51bGxPclVuZGVmaW5lZCxcbiAgcGFyc2VVcmksXG4gIGdldEZpZWxkc0Zyb21EYXRhXG59IGZyb20gJ0BrZXBsZXIuZ2wvY29tbW9uLXV0aWxzJztcbmltcG9ydCB7RGF0YXNldFR5cGUsIEFMTF9GSUVMRF9UWVBFUywgRklMVEVSX1RZUEVTLCBSZW1vdGVUaWxlRm9ybWF0fSBmcm9tICdAa2VwbGVyLmdsL2NvbnN0YW50cyc7XG5cbmltcG9ydCB7RmVhdHVyZSwgRmllbGQgYXMgS2VwbGVyRmllbGQsIEtlcGxlckxheWVyfSBmcm9tICdAa2VwbGVyLmdsL3R5cGVzJztcbmltcG9ydCB7Y2xhbXAsIGZvcm1hdE51bWJlckJ5U3RlcCwgZ2V0TnVtZXJpY1N0ZXBTaXplLCB0aW1lVG9Vbml4TWlsbGl9IGZyb20gJ0BrZXBsZXIuZ2wvdXRpbHMnO1xuXG5pbXBvcnQge1xuICBGaWx0ZXJQcm9wcyxcbiAgTnVtZXJpY0ZpZWxkRmlsdGVyUHJvcHMsXG4gIEJvb2xlYW5GaWVsZEZpbHRlclByb3BzLFxuICBTdHJpbmdGaWVsZEZpbHRlclByb3BzLFxuICBkZWZhdWx0IGFzIEtlcGxlckRhdGFzZXRcbn0gZnJvbSAnLi4va2VwbGVyLXRhYmxlJztcblxuZXhwb3J0IGNvbnN0IGdldExvYWRlck9wdGlvbnMgPSAoKSA9PiB7XG4gIHJldHVybiB7XG4gICAgbXZ0OiB7XG4gICAgICB3b3JrZXJVcmw6IGBodHRwczovL3VucGtnLmNvbS9AbG9hZGVycy5nbC9tdnQvZGlzdC9tdnQtd29ya2VyLmpzYFxuICAgIH1cbiAgfTtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1RpbGVEYXRhc2V0KGRhdGFzZXQ6IEtlcGxlckRhdGFzZXQgfCB7dHlwZTogc3RyaW5nfSk6IGJvb2xlYW4ge1xuICByZXR1cm4gQm9vbGVhbihkYXRhc2V0Py50eXBlID09PSBEYXRhc2V0VHlwZS5WRUNUT1JfVElMRSk7XG59XG5cbnR5cGUgVmVjdG9yVGlsZUZpZWxkID0ge1xuICBhbmFseXplclR5cGU6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xuICBpZDogc3RyaW5nO1xuICBmb3JtYXQ6IHN0cmluZztcbiAgdHlwZTogc3RyaW5nO1xuICBmaWx0ZXJQcm9wcz86IEZpbHRlclByb3BzO1xufTtcblxuZXhwb3J0IHR5cGUgVmVjdG9yVGlsZU1ldGFkYXRhID0ge1xuICBhdHRyaWJ1dGlvbnM/OiB1bmtub3duW107XG4gIG1ldGFKc29uOiBhbnkgfCBudWxsO1xuICBib3VuZHM6IG51bWJlcltdIHwgbnVsbDtcbiAgY2VudGVyOiBudW1iZXJbXSB8IG51bGw7XG4gIG1heFpvb206IG51bWJlciB8IG51bGw7XG4gIG1pblpvb206IG51bWJlciB8IG51bGw7XG4gIG5hbWU/OiBzdHJpbmc7XG4gIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICBmaWVsZHM6IFZlY3RvclRpbGVGaWVsZFtdO1xufTtcblxudHlwZSBUaWxlc2V0TWV0YWRhdGEgPSBWZWN0b3JUaWxlTWV0YWRhdGE7XG5cbmV4cG9ydCB0eXBlIFRpcHBlY2Fub2VMYXllckF0dHJpYnV0ZSA9IHtcbiAgYXR0cmlidXRlPzogc3RyaW5nO1xuICB0eXBlPzogc3RyaW5nO1xuICBtaW4/OiBudW1iZXI7XG4gIG1heD86IG51bWJlcjtcbiAgdmFsdWVzOiBzdHJpbmdbXSB8IG51bWJlcltdO1xufTtcblxudHlwZSBUaXBwZWNhbm9lTGF5ZXIgPSB7XG4gIGF0dHJpYnV0ZXM/OiBUaXBwZWNhbm9lTGF5ZXJBdHRyaWJ1dGVbXTtcbn07XG50eXBlIFRpbGVzZXRGdW5jdGlvbiA9IHtcbiAgZ2V0TWV0YVVybDogKHM6IHN0cmluZykgPT4gc3RyaW5nIHwgbnVsbDtcbiAgcGFyc2VNZXRhZGF0YTogKGQ6IGFueSwgb3B0aW9ucz86IGFueSkgPT4gVGlsZXNldE1ldGFkYXRhIHwgbnVsbDtcbn07XG4vLyBodHRwczovL2dpdGh1Yi5jb20vbWFwYm94L3RpbGVqc29uLXNwZWMvdHJlZS9tYXN0ZXIvMi4yLjBcbmZ1bmN0aW9uIGlzTGF0KG51bTogYW55KTogYm9vbGVhbiB7XG4gIHJldHVybiBOdW1iZXIuaXNGaW5pdGUobnVtKSAmJiBudW0gPD0gOTAgJiYgbnVtID49IC05MDtcbn1cbmZ1bmN0aW9uIGlzTG5nKG51bTogYW55KTogYm9vbGVhbiB7XG4gIHJldHVybiBOdW1iZXIuaXNGaW5pdGUobnVtKSAmJiBudW0gPD0gMTgwICYmIG51bSA+PSAtMTgwO1xufVxuZnVuY3Rpb24gaXNab29tKG51bTogYW55KTogYm9vbGVhbiB7XG4gIHJldHVybiBOdW1iZXIuaXNGaW5pdGUobnVtKSAmJiBudW0gPj0gMCAmJiBudW0gPD0gMjI7XG59XG5mdW5jdGlvbiBmcm9tQXJyYXlPclN0cmluZyhkYXRhOiBzdHJpbmcgfCBudW1iZXJbXSk6IG51bWJlcltdIHwgbnVsbCB7XG4gIGlmICh0eXBlb2YgZGF0YSA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gZGF0YS5zcGxpdCgnLCcpLm1hcChwYXJzZUZsb2F0KTtcbiAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KGRhdGEpKSB7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbmZ1bmN0aW9uIHBhcnNlQ2VudGVyKGNlbnRlcjogc3RyaW5nIHwgbnVtYmVyW10pOiBudW1iZXJbXSB8IG51bGwge1xuICAvLyBzdXBwb3J0ZWQgZm9ybWF0c1xuICAvLyBzdHJpbmc6IFwiLTk2LjY1NzcxNSw0MC4xMjYxMjcsLTkwLjE0MDA2MSw0My41MTY2ODlcIixcbiAgLy8gYXJyYXk6IFstOTEuNTA1MTI3LDQxLjYxNTQ0MiwxNF1cbiAgY29uc3QgcmVzdWx0ID0gZnJvbUFycmF5T3JTdHJpbmcoY2VudGVyKTtcbiAgaWYgKFxuICAgIEFycmF5LmlzQXJyYXkocmVzdWx0KSAmJlxuICAgIHJlc3VsdC5sZW5ndGggPT09IDMgJiZcbiAgICBpc0xuZyhyZXN1bHRbMF0pICYmXG4gICAgaXNMYXQocmVzdWx0WzFdKSAmJlxuICAgIGlzWm9vbShyZXN1bHRbMl0pXG4gICkge1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogYm91bmRzIHNob3VsZCBiZSBbbWluTG5nLCBtaW5MYXQsIG1heExuZywgbWF4TGF0XVxuICogQHBhcmFtIHsqfSBib3VuZHNcbiAqL1xuZnVuY3Rpb24gcGFyc2VCb3VuZHMoYm91bmRzOiBzdHJpbmcgfCBudW1iZXJbXSk6IG51bWJlcltdIHwgbnVsbCB7XG4gIC8vIHN1cHBvcnRlZCBmb3JtYXRzXG4gIC8vIHN0cmluZzogXCItOTYuNjU3NzE1LDQwLjEyNjEyNywtOTAuMTQwMDYxLDQzLjUxNjY4OVwiLFxuICAvLyBhcnJheTogWyAtMTgwLCAtODUuMDUxMTI4Nzc5ODA2NTksIDE4MCwgODUuMDUxMTI4Nzc5ODA2NiBdXG4gIGNvbnN0IHJlc3VsdCA9IGZyb21BcnJheU9yU3RyaW5nKGJvdW5kcyk7XG4gIC8vIHZhbGlkYXRlIGJvdW5kc1xuICBpZiAoXG4gICAgQXJyYXkuaXNBcnJheShyZXN1bHQpICYmXG4gICAgcmVzdWx0Lmxlbmd0aCA9PT0gNCAmJlxuICAgIFtyZXN1bHRbMF0sIHJlc3VsdFsyXV0uZXZlcnkoaXNMbmcpICYmXG4gICAgW3Jlc3VsdFsxXSwgcmVzdWx0WzNdXS5ldmVyeShpc0xhdClcbiAgKSB7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cblxuY29uc3QgWF9QQVRUID0gL1xce3hcXH0vO1xuY29uc3QgWV9QQVRUID0gL1xce3lcXH0vO1xuY29uc3QgWl9QQVRUID0gL1xce3pcXH0vO1xuXG5mdW5jdGlvbiBpc0Z1bGx5UXVhbGlmaWVkVGlsZVVybCh0aWxlVXJsOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIFhfUEFUVC50ZXN0KHRpbGVVcmwpICYmIFlfUEFUVC50ZXN0KHRpbGVVcmwpICYmIFpfUEFUVC50ZXN0KHRpbGVVcmwpO1xufVxuXG4vKipcbiAqIE5vcm1hbGl6ZSB0aWxlIFVSTFxuICogQHBhcmFtICB7c3RyaW5nfSB0aWxlVXJsIEluaXRpYWwgdGlsZSBVUkwsIHdoaWNoIG1heSBiZSBlaXRoZXIgdGhlIHJvb3QgVVJMIGZvciB0aGVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICB0aWxlc2V0IG9yIGEgZnVsbHkgcXVhbGlmaWVkIHRlbXBsYXRlXG4gKiBAcGFyYW0gIHtmdW5jdGlvbn0gdmFsaWRhdGVVcmwgZnVuY3Rpb24gdG8gdmFsaWRhdGUgdGlsZSBVUkxcbiAqIEByZXR1cm4ge3N0cmluZ3xudWxsfSAgICBGdWxseSBxdWFsaWZpZWQgdGlsZSBVUkwgdGVtcGxhdGUsIG9yIG51bGwgaWYgaW5wdXQgZG9lcyBub3RcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICBhcHBlYXIgdG8gYmUgYSB2YWxpZCBVUkxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFRpbGVVcmwoXG4gIHRpbGVVcmw6IHN0cmluZyxcbiAgdmFsaWRhdGVVcmw6IChzOiBzdHJpbmcpID0+IGJvb2xlYW4gPSBpc0Z1bGx5UXVhbGlmaWVkVGlsZVVybFxuKTogc3RyaW5nIHwgbnVsbCB7XG4gIC8vIENoZWNrIGZvciBhIHZhbGlkIFVSTC4gSWRlYWxseSB3ZSdkIGhhdmUgYSBzaW1wbGUgbWV0aG9kIGhlcmUuXG4gIGNvbnN0IHVyaVBhcnRzID0gcGFyc2VVcmkodGlsZVVybCk7XG4gIGlmICghdXJpUGFydHMucHJvdG9jb2wgfHwgIXVyaVBhcnRzLmhvc3QpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBpZiAodmFsaWRhdGVVcmwodGlsZVVybCkpIHtcbiAgICByZXR1cm4gdGlsZVVybDtcbiAgfVxuICByZXR1cm4gYCR7dGlsZVVybC5yZXBsYWNlKC9cXC8kLywgJycpfS97en0ve3h9L3t5fS5wYmZgO1xufVxuXG4vKipcbiAqIE1hcCBvZiB1dGlsIGZ1bmN0aW9ucyBmb3IgZGlmZmVyZW50IHRpbGVzZXQgdHlwZXMsIGtleWVkIGJ5IGhvc3RcbiAqL1xuY29uc3QgVElMRVNFVF9GVU5DVElPTlM6IHtba2V5OiBzdHJpbmddOiBUaWxlc2V0RnVuY3Rpb259ID0ge1xuICAnYXBpLm1hcGJveC5jb20nOiB7XG4gICAgZ2V0TWV0YVVybDogZ2V0TWV0YVVybE1hcGJveCxcbiAgICBwYXJzZU1ldGFkYXRhOiBwYXJzZU1ldGFkYXRhVGlsZUpTT05cbiAgfSxcbiAgZGVmYXVsdDoge1xuICAgIGdldE1ldGFVcmw6IGdldE1ldGFVcmxUaXBwZWNhbm9lLFxuICAgIHBhcnNlTWV0YWRhdGE6IHBhcnNlTWV0YWRhdGFUaWxlSlNPTlxuICB9XG59O1xuXG5mdW5jdGlvbiBnZXRUaWxlc2V0RnVuY3Rpb25zKHRpbGVVcmw6IHN0cmluZyB8IG51bGwpOiBUaWxlc2V0RnVuY3Rpb24ge1xuICBsZXQgaG9zdCA9ICcnO1xuICB0cnkge1xuICAgIGhvc3QgPSBuZXcgVVJMKHRpbGVVcmwgfHwgJycpLmhvc3RuYW1lO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIC8vIGRvIG5vdGhpbmdcbiAgfVxuXG4gIHJldHVybiBUSUxFU0VUX0ZVTkNUSU9OU1tob3N0XSB8fCBUSUxFU0VUX0ZVTkNUSU9OUy5kZWZhdWx0O1xufVxuXG4vKipcbiAqIEdldCB0aGUgbWV0YWRhdGEgVVJMIGZvciBhIGdpdmVuIHRpbGVzZXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE1ldGFVcmwodGlsZVVybDogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gIHJldHVybiBnZXRUaWxlc2V0RnVuY3Rpb25zKHRpbGVVcmwpLmdldE1ldGFVcmwodGlsZVVybCk7XG59XG50eXBlIFBhcnNlTWV0YWRhdGFPcHRpb24gPSB7XG4gIHRpbGVVcmw/OiBzdHJpbmcgfCBudWxsO1xufTtcbi8qKlxuICogUGFyc2UgdGhlIG1ldGFkYXRhIGZvciBhIGdpdmVuIHRpbGVzZXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlVmVjdG9yTWV0YWRhdGEoXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvZXhwbGljaXQtbW9kdWxlLWJvdW5kYXJ5LXR5cGVzXG4gIG1ldGFkYXRhOiBQTVRpbGVzTWV0YWRhdGEgfCBUaWxlSlNPTixcbiAgb3B0aW9uPzogUGFyc2VNZXRhZGF0YU9wdGlvblxuKTogVGlsZXNldE1ldGFkYXRhIHwgbnVsbCB7XG4gIGNvbnN0IHt0aWxlVXJsID0gJyd9ID0gb3B0aW9uIHx8IHt9O1xuICByZXR1cm4gZ2V0VGlsZXNldEZ1bmN0aW9ucyh0aWxlVXJsKS5wYXJzZU1ldGFkYXRhKG1ldGFkYXRhKTtcbn1cblxuY29uc3QgTUFQQk9YX1VSTF9QQVRUID0gL1xcL1xce3pcXH1cXC9cXHt4XFx9XFwvXFx7eVxcfVxcLm12dC87XG5cbmZ1bmN0aW9uIGdldE1ldGFVcmxNYXBib3godGlsZVVybCA9ICcnKTogc3RyaW5nIHtcbiAgcmV0dXJuIHRpbGVVcmwucmVwbGFjZShNQVBCT1hfVVJMX1BBVFQsICcuanNvbicpO1xufVxuXG5mdW5jdGlvbiBwYXJzZU1ldGFkYXRhVGlsZUpTT04obWV0YWRhdGE6IFBNVGlsZXNNZXRhZGF0YSB8IFRpbGVKU09OKTogVGlsZXNldE1ldGFkYXRhIHwgbnVsbCB7XG4gIGNvbnN0IHBhcnNlZCA9IHBhcnNlTWV0YWRhdGFUaXBwZWNhbm9lRnJvbURhdGFTb3VyY2UobWV0YWRhdGEpO1xuICBpZiAoIXBhcnNlZCkgcmV0dXJuIG51bGw7XG4gIC8vIEZpZWxkcyBhbHJlYWR5IHBhcnNlZCBmcm9tIGBqc29uYCBwcm9wZXJ0eVxuICBpZiAocGFyc2VkLmZpZWxkcz8ubGVuZ3RoKSB7XG4gICAgcmV0dXJuIHBhcnNlZDtcbiAgfVxuXG4gIHJldHVybiBwYXJzZWQ7XG59XG5cbmZ1bmN0aW9uIGdldE1ldGFVcmxUaXBwZWNhbm9lKHRpbGVVcmwpIHtcbiAgY29uc3QgdXJsID0gZ2V0VGlsZVVybCh0aWxlVXJsKTtcbiAgaWYgKCF1cmwpIHJldHVybiBudWxsO1xuICAvLyBhc3N1bWVzIHRoZSBzdHJ1Y3R1cmUgPHVybF9iYXNlPi97en0uLi5cbiAgY29uc3QgYmFzZVVybCA9IHVybC5zcGxpdChaX1BBVFQpWzBdLnJlcGxhY2UoL1xcLyQvLCAnJyk7XG4gIHJldHVybiBgJHtiYXNlVXJsfS9tZXRhZGF0YS5qc29uYDtcbn1cblxuLyoqXG4gKiBTcGVjaWFsIHBhcnNpbmcgZm9yIG1ldGFkYXRhIHJldHVybmVkIGJ5IE1WVFNvdXJjZSBhbmQgUE1UaWxlc1NvdXJjZS5cbiAqIEBwYXJhbSBtZXRhZGF0YSBUaWxlc2V0IG1ldGFkYXRhIHBhcnNlZCBieSBhIERhdGFTb3VjZVxuICogQHJldHVybnMgTWV0YWRhdGEgaW4gS2VwbGVyLWZyaWVuZGx5IGZvcm1hdC5cbiAqL1xuZnVuY3Rpb24gcGFyc2VNZXRhZGF0YVRpcHBlY2Fub2VGcm9tRGF0YVNvdXJjZShcbiAgbWV0YWRhdGE6IFBNVGlsZXNNZXRhZGF0YSB8IFRpbGVKU09OIHwgbnVsbFxuKTogVGlsZXNldE1ldGFkYXRhIHwgbnVsbCB7XG4gIGlmICghbWV0YWRhdGEgfHwgdHlwZW9mIG1ldGFkYXRhICE9PSAnb2JqZWN0Jykge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgbGV0IHJlc3VsdDogVGlsZXNldE1ldGFkYXRhID0ge1xuICAgIGF0dHJpYnV0aW9uczogW10sXG4gICAgbWV0YUpzb246IG51bGwsXG4gICAgYm91bmRzOiBudWxsLFxuICAgIGNlbnRlcjogbnVsbCxcbiAgICBtYXhab29tOiBudWxsLFxuICAgIG1pblpvb206IG51bGwsXG4gICAgZmllbGRzOiBbXVxuICB9O1xuXG4gIGNvbnN0IG12dE1ldGFkYXRhID0gbWV0YWRhdGEgYXMgVGlsZUpTT047XG4gIGNvbnN0IHBtVGlsZU1ldGFkYXRhID0gbWV0YWRhdGEgYXMgUE1UaWxlc01ldGFkYXRhO1xuXG4gIC8vIHRyeSB0byBwYXJzZSBtZXRhSnNvblxuICBpZiAodHlwZW9mIG12dE1ldGFkYXRhLm1ldGFKc29uID09PSAnc3RyaW5nJykge1xuICAgIHRyeSB7XG4gICAgICByZXN1bHQubWV0YUpzb24gPSBKU09OLnBhcnNlKG12dE1ldGFkYXRhLm1ldGFKc29uKTtcbiAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgIC8vIGRvIG5vdGhpbmdcbiAgICB9XG4gIH0gZWxzZSBpZiAodHlwZW9mIG12dE1ldGFkYXRhLm1ldGFKc29uID09PSAnb2JqZWN0Jykge1xuICAgIHJlc3VsdC5tZXRhSnNvbiA9IG12dE1ldGFkYXRhLm1ldGFKc29uO1xuICB9XG5cbiAgcmVzdWx0LmJvdW5kcyA9IHBhcnNlQm91bmRzKFxuICAgIEFycmF5LmlzQXJyYXkobWV0YWRhdGEuYm91bmRpbmdCb3gpID8gbWV0YWRhdGEuYm91bmRpbmdCb3guZmxhdCgpIDogJydcbiAgKTtcblxuICAvLyBQTVRpbGVTb3VyY2UgaGFzIGNlbnRlclpvb20gYW5kIGNlbnRlciBbbG9uLCBsYXRdLCBNVlRTb3VyY2UgLSBbbG9uLCBsYXQsIHpvb21dXG4gIGNvbnN0IGNlbnRlciA9XG4gICAgcG1UaWxlTWV0YWRhdGEuY2VudGVyWm9vbSAhPT0gdW5kZWZpbmVkICYmIEFycmF5LmlzQXJyYXkobWV0YWRhdGEuY2VudGVyKVxuICAgICAgPyBbLi4ubWV0YWRhdGEuY2VudGVyLCBwbVRpbGVNZXRhZGF0YS5jZW50ZXJab29tXVxuICAgICAgOiBtZXRhZGF0YS5jZW50ZXI7XG4gIHJlc3VsdC5jZW50ZXIgPSBwYXJzZUNlbnRlcihjZW50ZXIgfHwgJycpO1xuXG4gIHJlc3VsdC5tYXhab29tID0gc2FmZVBhcnNlRmxvYXQobWV0YWRhdGEubWF4Wm9vbSk7XG4gIHJlc3VsdC5taW5ab29tID0gc2FmZVBhcnNlRmxvYXQobWV0YWRhdGEubWluWm9vbSk7XG4gIHJlc3VsdC5uYW1lID0gbWV0YWRhdGEubmFtZSB8fCAnJztcbiAgcmVzdWx0LmRlc2NyaXB0aW9uID0gbXZ0TWV0YWRhdGEuZGVzY3JpcHRpb24gfHwgcG1UaWxlTWV0YWRhdGEudGlsZWpzb24/LmRlc2NyaXB0aW9uIHx8ICcnO1xuXG4gIGlmIChBcnJheS5pc0FycmF5KHBtVGlsZU1ldGFkYXRhLnRpbGVqc29uPy5sYXllcnMpKSB7XG4gICAgY29uc3QgbGF5ZXJzID0gcG1UaWxlc0xheWVyVG9UaXBwZWNhbm9lTGF5ZXIocG1UaWxlTWV0YWRhdGEudGlsZWpzb24/LmxheWVycyk7XG4gICAgcmVzdWx0LmZpZWxkcyA9IGNvbGxlY3RBdHRyaWJ1dGVzKGxheWVycyk7XG4gIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShtdnRNZXRhZGF0YS5sYXllcnMpKSB7XG4gICAgY29uc3QgbGF5ZXJzID0gcG1UaWxlc0xheWVyVG9UaXBwZWNhbm9lTGF5ZXIobXZ0TWV0YWRhdGEubGF5ZXJzKTtcbiAgICByZXN1bHQuZmllbGRzID0gY29sbGVjdEF0dHJpYnV0ZXMobGF5ZXJzKTtcbiAgfVxuXG4gIHJlc3VsdCA9IHtcbiAgICAuLi5yZXN1bHQsXG4gICAgYXR0cmlidXRpb25zOlxuICAgICAgcG1UaWxlTWV0YWRhdGEuYXR0cmlidXRpb25zIHx8XG4gICAgICAobXZ0TWV0YWRhdGEuaHRtbEF0dHJpYnV0aW9uID8gW212dE1ldGFkYXRhLmh0bWxBdHRyaWJ1dGlvbl0gOiB1bmRlZmluZWQpIHx8XG4gICAgICBbXSxcbiAgICAuLi5wYXJzZU1ldGFKc29uKHJlc3VsdC5tZXRhSnNvbilcbiAgfTtcblxuICByZXR1cm4gcmVzdWx0O1xufVxuXG5mdW5jdGlvbiBzYWZlUGFyc2VGbG9hdChpbnB1dDogdW5rbm93bik6IG51bWJlciB8IG51bGwge1xuICBjb25zdCByZXN1bHQgPVxuICAgIHR5cGVvZiBpbnB1dCA9PT0gJ3N0cmluZycgPyBwYXJzZUZsb2F0KGlucHV0KSA6IHR5cGVvZiBpbnB1dCA9PT0gJ251bWJlcicgPyBpbnB1dCA6IG51bGw7XG4gIHJldHVybiByZXN1bHQgPT09IG51bGwgfHwgaXNOYU4ocmVzdWx0KSA/IG51bGwgOiByZXN1bHQ7XG59XG5cbmZ1bmN0aW9uIHBhcnNlTWV0YUpzb24obWV0YUpzb246IGFueSk6IHtmaWVsZHM6IFZlY3RvclRpbGVGaWVsZFtdfSB8IG51bGwge1xuICBpZiAoIW1ldGFKc29uIHx8IHR5cGVvZiBtZXRhSnNvbiAhPT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGlmIChtZXRhSnNvbi50aWxlc3RhdHMgJiYgQXJyYXkuaXNBcnJheShtZXRhSnNvbi50aWxlc3RhdHMubGF5ZXJzKSkge1xuICAgIC8vIHdlIGFyZSBpbiBsdWNrIVxuICAgIHJldHVybiB7ZmllbGRzOiBjb2xsZWN0QXR0cmlidXRlcyhtZXRhSnNvbi50aWxlc3RhdHMubGF5ZXJzKX07XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbmZ1bmN0aW9uIGdldFRpbWVBbmltYXRpb25Eb21haW4obWFwcGVkVmFsdWU6IG51bWJlcltdKToge1xuICBkb21haW46IG51bWJlcltdO1xuICB0aW1lU3RlcHM6IG51bWJlcltdO1xuICBtYXBwZWRWYWx1ZTogbnVtYmVyW107XG4gIGR1cmF0aW9uOiBudW1iZXI7XG59IHtcbiAgY29uc3QgdGltZVN0ZXBzID0gdW5pcShtYXBwZWRWYWx1ZSkuc29ydChhc2NlbmRpbmcpLmZpbHRlcihub3ROdWxsT3JVbmRlZmluZWQpO1xuXG4gIGNvbnN0IGRvbWFpbiA9IFt0aW1lU3RlcHNbMF0sIHRpbWVTdGVwc1t0aW1lU3RlcHMubGVuZ3RoIC0gMV1dO1xuXG4gIC8vIGlmIHRha3MgMTAgKiAxMDAwIG1zIHRvIGZpbmlzaCB0aGUgZW50aXJlIGFuaW1hdGlvblxuICBjb25zdCBkdXJhdGlvbiA9IDEwMDAwIC8gdGltZVN0ZXBzLmxlbmd0aDtcbiAgY29uc3QgY2xhbXBlZCA9IGNsYW1wKFsxMDAsIDIwMDBdLCBkdXJhdGlvbik7XG5cbiAgcmV0dXJuIHtkb21haW4sIHRpbWVTdGVwcywgZHVyYXRpb246IGNsYW1wZWQsIG1hcHBlZFZhbHVlfTtcbn1cblxuY29uc3QgcG1UaWxlVHlwZVRvQXR0ck1hcCA9IHtcbiAgZmxvYXQzMjogJ251bWJlcicsXG4gIHN0cmluZzogJ3N0cmluZycsXG4gIHV0Zjg6ICdzdHJpbmcnLFxuICBpbnQ6ICdpbnQnLFxuICBib29sZWFuOiAnYm9vbGVhbidcbn07XG5cbi8qKlxuICogVHJhbnNmb3JtIFRpbGVKU09OWydsYXllcnMnXSBiYWNrIHRvIFRpcHBlY2Fub2VMYXllclxuICovXG5mdW5jdGlvbiBwbVRpbGVzTGF5ZXJUb1RpcHBlY2Fub2VMYXllcihsYXllcnM6IFRpbGVKU09OWydsYXllcnMnXSk6IFRpcHBlY2Fub2VMYXllcltdIHtcbiAgaWYgKCFsYXllcnMpIHJldHVybiBbXTtcblxuICBjb25zdCBvdXRMYXllcnM6IFRpcHBlY2Fub2VMYXllcltdID0gW107XG4gIGZvciAoY29uc3QgbGF5ZXIgb2YgbGF5ZXJzKSB7XG4gICAgY29uc3Qge2ZpZWxkcyA9IFtdfSA9IGxheWVyIHx8IHt9O1xuICAgIGZvciAoY29uc3QgcG1GaWVsZCBvZiBmaWVsZHMpIHtcbiAgICAgIGNvbnN0IGF0dHJpYnV0ZSA9IHtcbiAgICAgICAgYXR0cmlidXRlOiBwbUZpZWxkLm5hbWUsXG4gICAgICAgIHR5cGU6IHBtVGlsZVR5cGVUb0F0dHJNYXBbcG1GaWVsZC50eXBlXSxcbiAgICAgICAgY291bnQ6IHBtRmllbGQudW5pcXVlVmFsdWVDb3VudCxcbiAgICAgICAgdmFsdWVzOiAocG1GaWVsZC52YWx1ZXMgPz8gW10pIGFzIG51bWJlcltdIHwgc3RyaW5nW10sXG4gICAgICAgIG1pbjogcG1GaWVsZC5taW4sXG4gICAgICAgIG1heDogcG1GaWVsZC5tYXhcbiAgICAgIH07XG5cbiAgICAgIG91dExheWVycy5wdXNoKHtcbiAgICAgICAgYXR0cmlidXRlczogW2F0dHJpYnV0ZV1cbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuICByZXR1cm4gb3V0TGF5ZXJzO1xufVxuXG5mdW5jdGlvbiBjb2xsZWN0QXR0cmlidXRlcyhsYXllcnM6IFRpcHBlY2Fub2VMYXllcltdID0gW10pOiBWZWN0b3JUaWxlRmllbGRbXSB7XG4gIGNvbnN0IGZpZWxkcyA9IHt9O1xuICBjb25zdCBpbmRleGVkQXR0cmlidXRlczoge1trZXk6IHN0cmluZ106IFRpcHBlY2Fub2VMYXllckF0dHJpYnV0ZVtdfSA9IHt9O1xuXG4gIGZvciAoY29uc3QgbGF5ZXIgb2YgbGF5ZXJzKSB7XG4gICAgY29uc3Qge2F0dHJpYnV0ZXMgPSBbXX0gPSBsYXllciB8fCB7fTtcbiAgICBmb3IgKGNvbnN0IGF0dHIgb2YgYXR0cmlidXRlcykge1xuICAgICAgY29uc3QgbmFtZSA9IGF0dHIuYXR0cmlidXRlO1xuICAgICAgaWYgKHR5cGVvZiBuYW1lID09PSAnc3RyaW5nJykge1xuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbWF4LWRlcHRoXG4gICAgICAgIGlmIChuYW1lLnNwbGl0KCd8JykubGVuZ3RoID4gMSkge1xuICAgICAgICAgIC8vIGluZGV4ZWQgZmllbGRcbiAgICAgICAgICBjb25zdCBmbmFtZSA9IG5hbWUuc3BsaXQoJ3wnKVswXTtcbiAgICAgICAgICBpbmRleGVkQXR0cmlidXRlc1tmbmFtZV0gPSBpbmRleGVkQXR0cmlidXRlc1tmbmFtZV0gfHwgW107XG4gICAgICAgICAgaW5kZXhlZEF0dHJpYnV0ZXNbZm5hbWVdLnB1c2goYXR0cik7XG4gICAgICAgIH0gZWxzZSBpZiAoIWZpZWxkc1tuYW1lXSkge1xuICAgICAgICAgIGZpZWxkc1tuYW1lXSA9IGF0dHJpYnV0ZVRvRmllbGQoYXR0cik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbWVyZ2VBdHRyaWJ1dGVEb21haW4oZmllbGRzW25hbWVdLCBhdHRyKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIHBhcnNlIGluZGV4ZWQgYXR0cmlidXRlLCBhbmQgcHV0IGluZGV4IGtleSB1bmlkZW50aWZpZWQgYmFjayBhcyBub3JtYWwgZmllbGRcbiAgZm9yIChjb25zdCBbbmFtZSwgYXR0cnNdIG9mIE9iamVjdC5lbnRyaWVzKGluZGV4ZWRBdHRyaWJ1dGV