UNPKG

kepler.gl

Version:

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

724 lines (705 loc) 98.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getFieldsFromTile = void 0; exports.getFilterProps = getFilterProps; 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 _uniq = _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 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; // PMTiles can potentially be in RasterTile format var mimeType = metadata.tileMIMEType; if (mimeType) { parsed.pmtilesType = mimeType === 'application/vnd.mapbox-vector-tile' ? _constants.PMTilesType.MVT : _constants.PMTilesType.RASTER; } // 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, _uniq["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 && (!metadata.pmtilesType || metadata.pmtilesType === _constants.PMTilesType.MVT))) { _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,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfdHlwZUFuYWx5emVyIiwicmVxdWlyZSIsIl9kM0FycmF5IiwiX2NvbnNvbGUiLCJfaW50ZXJvcFJlcXVpcmVEZWZhdWx0IiwiX3VuaXEiLCJfbXZ0IiwiX3BtdGlsZXMiLCJfY29tbW9uVXRpbHMiLCJfY29uc3RhbnRzIiwiX3V0aWxzIiwiX2NyZWF0ZUZvck9mSXRlcmF0b3JIZWxwZXIiLCJyIiwiZSIsInQiLCJTeW1ib2wiLCJpdGVyYXRvciIsIkFycmF5IiwiaXNBcnJheSIsIl91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheSIsImxlbmd0aCIsIl9uIiwiRiIsInMiLCJuIiwiZG9uZSIsInZhbHVlIiwiZiIsIlR5cGVFcnJvciIsIm8iLCJhIiwidSIsImNhbGwiLCJuZXh0IiwiX2FycmF5TGlrZVRvQXJyYXkiLCJ0b1N0cmluZyIsInNsaWNlIiwiY29uc3RydWN0b3IiLCJuYW1lIiwiZnJvbSIsInRlc3QiLCJvd25LZXlzIiwiT2JqZWN0Iiwia2V5cyIsImdldE93blByb3BlcnR5U3ltYm9scyIsImZpbHRlciIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsImVudW1lcmFibGUiLCJwdXNoIiwiYXBwbHkiLCJfb2JqZWN0U3ByZWFkIiwiYXJndW1lbnRzIiwiZm9yRWFjaCIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzIiwiZGVmaW5lUHJvcGVydGllcyIsImRlZmluZVByb3BlcnR5IiwiaXNUaWxlRGF0YXNldCIsImRhdGFzZXQiLCJCb29sZWFuIiwidHlwZSIsIkRhdGFzZXRUeXBlIiwiVkVDVE9SX1RJTEUiLCJpc0xhdCIsIm51bSIsIk51bWJlciIsImlzRmluaXRlIiwiaXNMbmciLCJpc1pvb20iLCJmcm9tQXJyYXlPclN0cmluZyIsImRhdGEiLCJzcGxpdCIsIm1hcCIsInBhcnNlRmxvYXQiLCJwYXJzZUNlbnRlciIsImNlbnRlciIsInJlc3VsdCIsInBhcnNlQm91bmRzIiwiYm91bmRzIiwiZXZlcnkiLCJYX1BBVFQiLCJZX1BBVFQiLCJaX1BBVFQiLCJpc0Z1bGx5UXVhbGlmaWVkVGlsZVVybCIsInRpbGVVcmwiLCJnZXRUaWxlVXJsIiwidmFsaWRhdGVVcmwiLCJ1bmRlZmluZWQiLCJ1cmlQYXJ0cyIsInBhcnNlVXJpIiwicHJvdG9jb2wiLCJob3N0IiwiY29uY2F0IiwicmVwbGFjZSIsIlRJTEVTRVRfRlVOQ1RJT05TIiwiZ2V0TWV0YVVybCIsImdldE1ldGFVcmxNYXBib3giLCJwYXJzZU1ldGFkYXRhIiwicGFyc2VNZXRhZGF0YVRpbGVKU09OIiwiZ2V0TWV0YVVybFRpcHBlY2Fub2UiLCJnZXRUaWxlc2V0RnVuY3Rpb25zIiwiVVJMIiwiaG9zdG5hbWUiLCJlcnJvciIsInBhcnNlVmVjdG9yTWV0YWRhdGEiLCJtZXRhZGF0YSIsIm9wdGlvbiIsIl9yZWYiLCJfcmVmJHRpbGVVcmwiLCJNQVBCT1hfVVJMX1BBVFQiLCJfcGFyc2VkJGZpZWxkcyIsInBhcnNlZCIsInBhcnNlTWV0YWRhdGFUaXBwZWNhbm9lRnJvbURhdGFTb3VyY2UiLCJtaW1lVHlwZSIsInRpbGVNSU1FVHlwZSIsInBtdGlsZXNUeXBlIiwiUE1UaWxlc1R5cGUiLCJNVlQiLCJSQVNURVIiLCJmaWVsZHMiLCJ1cmwiLCJiYXNlVXJsIiwiX3BtVGlsZU1ldGFkYXRhJHRpbGVqIiwiX3BtVGlsZU1ldGFkYXRhJHRpbGVqMiIsIl90eXBlb2YyIiwiYXR0cmlidXRpb25zIiwibWV0YUpzb24iLCJtYXhab29tIiwibWluWm9vbSIsIm12dE1ldGFkYXRhIiwicG1UaWxlTWV0YWRhdGEiLCJKU09OIiwicGFyc2UiLCJlcnIiLCJib3VuZGluZ0JveCIsImZsYXQiLCJjZW50ZXJab29tIiwiX3RvQ29uc3VtYWJsZUFycmF5MiIsInNhZmVQYXJzZUZsb2F0IiwiZGVzY3JpcHRpb24iLCJ0aWxlanNvbiIsImxheWVycyIsIl9wbVRpbGVNZXRhZGF0YSR0aWxlajMiLCJwbVRpbGVzTGF5ZXJUb1RpcHBlY2Fub2VMYXllciIsImNvbGxlY3RBdHRyaWJ1dGVzIiwiaHRtbEF0dHJpYnV0aW9uIiwicGFyc2VNZXRhSnNvbiIsImlucHV0IiwiaXNOYU4iLCJ0aWxlc3RhdHMiLCJnZXRUaW1lQW5pbWF0aW9uRG9tYWluIiwibWFwcGVkVmFsdWUiLCJ0aW1lU3RlcHMiLCJ1bmlxIiwic29ydCIsImFzY2VuZGluZyIsIm5vdE51bGxPclVuZGVmaW5lZCIsImRvbWFpbiIsImR1cmF0aW9uIiwiY2xhbXBlZCIsImNsYW1wIiwicG1UaWxlVHlwZVRvQXR0ck1hcCIsImZsb2F0MzIiLCJzdHJpbmciLCJ1dGY4Iiwib3V0TGF5ZXJzIiwiX2l0ZXJhdG9yIiwiX3N0ZXAiLCJsYXllciIsIl9yZWYyIiwiX3JlZjIkZmllbGRzIiwiX2l0ZXJhdG9yMiIsIl9zdGVwMiIsIl9wbUZpZWxkJHZhbHVlcyIsInBtRmllbGQiLCJhdHRyaWJ1dGUiLCJjb3VudCIsInVuaXF1ZVZhbHVlQ291bnQiLCJ2YWx1ZXMiLCJtaW4iLCJtYXgiLCJhdHRyaWJ1dGVzIiwiaW5kZXhlZEF0dHJpYnV0ZXMiLCJfaXRlcmF0b3IzIiwiX3N0ZXAzIiwiX3JlZjMiLCJfcmVmMyRhdHRyaWJ1dGVzIiwiX2l0ZXJhdG9yNSIsIl9zdGVwNSIsImF0dHIiLCJmbmFtZSIsImF0dHJpYnV0ZVRvRmllbGQiLCJtZXJnZUF0dHJpYnV0ZURvbWFpbiIsIl9pIiwiX09iamVjdCRlbnRyaWVzIiwiZW50cmllcyIsIl9PYmplY3QkZW50cmllcyRfaSIsIl9zbGljZWRUb0FycmF5MiIsImF0dHJzIiwiX3BhcnNlSW5kZXhlZEZpZWxkIiwicGFyc2VJbmRleGVkRmllbGQiLCJpbmRleGVkRmllbGQiLCJ1bmlkZW50aWZpZWQiLCJfaXRlcmF0b3I0IiwiX3N0ZXA0IiwidW5pZGVudGlmaWVkQXR0ciIsImdldEluZGV4S2V5RnJvbUZpZWxkTmFtZSIsImZpZWxkIiwiX2l0ZXJhdG9yNiIsIl9zdGVwNiIsImZpZWxkTmFtZSIsImluZGV4S2V5IiwiYW5hbHl6ZWRUeXBlIiwiY29udGFpblZhbGlkVGltZSIsImlkIiwiaW5kZXhCeSIsImZvcm1hdCIsImFuYWx5emVyVHlwZVRvRmllbGRUeXBlIiwiZmllbGRUcyIsImVwb2NoIiwidGltZVRvVW5peE1pbGxpIiwiQUxMX0ZJRUxEX1RZUEVTIiwidGltZXN0YW1wIiwidGltZURvbWFpbiIsImNvbXBhcmUiLCJudW0xIiwibnVtMiIsIm9wZXJhdG9yIiwiTWF0aCIsIk5hTiIsImdldEZpbHRlclByb3BzIiwiZmllbGRUeXBlIiwicmVhbCIsImludGVnZXIiLCJfZ2V0QXR0cmlidXRlRG9tYWluIiwiZ2V0QXR0cmlidXRlRG9tYWluIiwiX2dldEF0dHJpYnV0ZURvbWFpbjIiLCJkaWZmIiwic3RlcCIsImdldE51bWVyaWNTdGVwU2l6ZSIsImZvcm1hdE51bWJlckJ5U3RlcCIsImZpbHRlclByb3BzIiwiRklMVEVSX1RZUEVTIiwicmFuZ2UiLCJ0eXBlT3B0aW9ucyIsImdwdSIsInNlbGVjdCIsIm11bHRpU2VsZWN0IiwiZmllbGRUeXBlcyIsImF0dHJpYnV0ZVR5cGVUb0ZpZWxkVHlwZSIsIl9maWVsZCRtZXRhZGF0YSIsIl9maWVsZCRmaWx0ZXJQcm9wcyIsImF0dHJUeXBlTWFwIiwibnVtYmVyIiwiYW5hbHl6ZXJUeXBlIiwiREFUQV9UWVBFUyIsIkZMT0FUIiwibnVtZXJpYyIsIlNUUklORyIsInZhY2hhciIsIklOVCIsImludDQiLCJCT09MRUFOIiwiYm9vbCIsImFUeXBlIiwidG9Mb3dlckNhc2UiLCJDb25zb2xlIiwid2FybiIsIm1hdGNoRGF0YXNldFR5cGUiLCJjb25maWciLCJkYXRhSWQiLCJzdXBwb3J0ZWREYXRhc2V0VHlwZXMiLCJpbmNsdWRlcyIsImdldEZpZWxkc0Zyb21UaWxlIiwiZXhwb3J0cyIsIl9yZWY1IiwiX2FzeW5jVG9HZW5lcmF0b3IyIiwiX3JlZ2VuZXJhdG9yIiwibWFyayIsIl9jYWxsZWUiLCJfcmVmNCIsInJlbW90ZVRpbGVGb3JtYXQiLCJ0aWxlc2V0VXJsIiwibWV0YWRhdGFVcmwiLCJfbWV0YWRhdGEkZmllbGRzIiwiX21ldGFkYXRhJGJvdW5kcyIsImxvbiIsImxhdCIsInRpbGVJbmRpY2VzIiwidGlsZVNvdXJjZSIsInRpbGUiLCJ1cGRhdGVkRmllbGRzIiwid3JhcCIsIl9jYWxsZWUkIiwiX2NvbnRleHQiLCJwcmV2IiwibG9uTGF0VG9UaWxlSW5kZXgiLCJSZW1vdGVUaWxlRm9ybWF0IiwiTVZUU291cmNlIiwiY3JlYXRlRGF0YVNvdXJjZSIsImRlY29kZVVSSUNvbXBvbmVudCIsIm12dCIsIlBNVGlsZXNTb3VyY2UiLCJnZXRUaWxlRGF0YSIsImluZGV4Iiwic2VudCIsInRpbGVUb0ZpZWxkcyIsInQwIiwic3RvcCIsIl94IiwiX3RpbGUkZmVhdHVyZXMiLCJmZWF0dXJlcyIsImhlYWRlciIsInByb3BlcnRpZXMiLCJvdXRwdXQiLCJvYmoiLCJjb2x1bW5OYW1lIiwiZ2V0RmllbGRzRnJvbURhdGEiLCJmb3JjZVN0cmluZyIsIkFOQUxZWkVSX0RBVEFfVFlQRVMiLCJ6b29tIiwiRXJyb3IiLCJzY2FsZSIsIngiLCJmbG9vciIsImxhdFJhZCIsIlBJIiwieSIsImxvZyIsInRhbiIsImNvcyIsInoiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvdGlsZXNldC92ZWN0b3ItdGlsZS11dGlscy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4vLyBDb3B5cmlnaHQgY29udHJpYnV0b3JzIHRvIHRoZSBrZXBsZXIuZ2wgcHJvamVjdFxuXG5pbXBvcnQge0RBVEFfVFlQRVMgYXMgQU5BTFlaRVJfREFUQV9UWVBFU30gZnJvbSAndHlwZS1hbmFseXplcic7XG5pbXBvcnQge2FzY2VuZGluZ30gZnJvbSAnZDMtYXJyYXknO1xuaW1wb3J0IENvbnNvbGUgZnJvbSAnZ2xvYmFsL2NvbnNvbGUnO1xuaW1wb3J0IHVuaXEgZnJvbSAnbG9kYXNoL3VuaXEnO1xuaW1wb3J0IHtEQVRBX1RZUEVTfSBmcm9tICd0eXBlLWFuYWx5emVyJztcblxuaW1wb3J0IHtNVlRTb3VyY2UsIFRpbGVKU09OfSBmcm9tICdAbG9hZGVycy5nbC9tdnQnO1xuaW1wb3J0IHtQTVRpbGVzU291cmNlLCBQTVRpbGVzTWV0YWRhdGF9IGZyb20gJ0Bsb2FkZXJzLmdsL3BtdGlsZXMnO1xuXG5pbXBvcnQge1xuICBhbmFseXplclR5cGVUb0ZpZWxkVHlwZSxcbiAgY29udGFpblZhbGlkVGltZSxcbiAgbm90TnVsbG9yVW5kZWZpbmVkIGFzIG5vdE51bGxPclVuZGVmaW5lZCxcbiAgcGFyc2VVcmksXG4gIGdldEZpZWxkc0Zyb21EYXRhXG59IGZyb20gJ0BrZXBsZXIuZ2wvY29tbW9uLXV0aWxzJztcbmltcG9ydCB7XG4gIERhdGFzZXRUeXBlLFxuICBBTExfRklFTERfVFlQRVMsXG4gIEZJTFRFUl9UWVBFUyxcbiAgUE1UaWxlc1R5cGUsXG4gIFJlbW90ZVRpbGVGb3JtYXRcbn0gZnJvbSAnQGtlcGxlci5nbC9jb25zdGFudHMnO1xuXG5pbXBvcnQge0ZlYXR1cmUsIEZpZWxkIGFzIEtlcGxlckZpZWxkLCBLZXBsZXJMYXllcn0gZnJvbSAnQGtlcGxlci5nbC90eXBlcyc7XG5pbXBvcnQge2NsYW1wLCBmb3JtYXROdW1iZXJCeVN0ZXAsIGdldE51bWVyaWNTdGVwU2l6ZSwgdGltZVRvVW5peE1pbGxpfSBmcm9tICdAa2VwbGVyLmdsL3V0aWxzJztcblxuaW1wb3J0IHtcbiAgRmlsdGVyUHJvcHMsXG4gIE51bWVyaWNGaWVsZEZpbHRlclByb3BzLFxuICBCb29sZWFuRmllbGRGaWx0ZXJQcm9wcyxcbiAgU3RyaW5nRmllbGRGaWx0ZXJQcm9wcyxcbiAgZGVmYXVsdCBhcyBLZXBsZXJEYXRhc2V0XG59IGZyb20gJy4uL2tlcGxlci10YWJsZSc7XG5cbmV4cG9ydCBmdW5jdGlvbiBpc1RpbGVEYXRhc2V0KGRhdGFzZXQ6IEtlcGxlckRhdGFzZXQgfCB7dHlwZTogc3RyaW5nfSk6IGJvb2xlYW4ge1xuICByZXR1cm4gQm9vbGVhbihkYXRhc2V0Py50eXBlID09PSBEYXRhc2V0VHlwZS5WRUNUT1JfVElMRSk7XG59XG5cbnR5cGUgVmVjdG9yVGlsZUZpZWxkID0ge1xuICBhbmFseXplclR5cGU6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xuICBpZDogc3RyaW5nO1xuICBmb3JtYXQ6IHN0cmluZztcbiAgdHlwZTogc3RyaW5nO1xuICBmaWx0ZXJQcm9wcz86IEZpbHRlclByb3BzO1xufTtcblxuZXhwb3J0IHR5cGUgVmVjdG9yVGlsZU1ldGFkYXRhID0ge1xuICBhdHRyaWJ1dGlvbnM/OiB1bmtub3duW107XG4gIG1ldGFKc29uOiBhbnkgfCBudWxsO1xuICBib3VuZHM6IG51bWJlcltdIHwgbnVsbDtcbiAgY2VudGVyOiBudW1iZXJbXSB8IG51bGw7XG4gIG1heFpvb206IG51bWJlciB8IG51bGw7XG4gIG1pblpvb206IG51bWJlciB8IG51bGw7XG4gIG5hbWU/OiBzdHJpbmc7XG4gIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICBmaWVsZHM6IFZlY3RvclRpbGVGaWVsZFtdO1xuXG4gIC8vIGlmIHRoZSB0aWxlc2V0IGlzIG9mIHBtdGlsZXMgZm9ybWF0IHRoZW4gaW5jbHVkZSBpbmZvIGFib3V0IHR5cGUgb2YgcG10aWxlc1xuICBwbXRpbGVzVHlwZT86IFBNVGlsZXNUeXBlO1xufTtcblxudHlwZSBUaWxlc2V0TWV0YWRhdGEgPSBWZWN0b3JUaWxlTWV0YWRhdGE7XG5cbmV4cG9ydCB0eXBlIFRpcHBlY2Fub2VMYXllckF0dHJpYnV0ZSA9IHtcbiAgYXR0cmlidXRlPzogc3RyaW5nO1xuICB0eXBlPzogc3RyaW5nO1xuICBtaW4/OiBudW1iZXI7XG4gIG1heD86IG51bWJlcjtcbiAgdmFsdWVzOiBzdHJpbmdbXSB8IG51bWJlcltdO1xufTtcblxudHlwZSBUaXBwZWNhbm9lTGF5ZXIgPSB7XG4gIGF0dHJpYnV0ZXM/OiBUaXBwZWNhbm9lTGF5ZXJBdHRyaWJ1dGVbXTtcbn07XG50eXBlIFRpbGVzZXRGdW5jdGlvbiA9IHtcbiAgZ2V0TWV0YVVybDogKHM6IHN0cmluZykgPT4gc3RyaW5nIHwgbnVsbDtcbiAgcGFyc2VNZXRhZGF0YTogKGQ6IGFueSwgb3B0aW9ucz86IGFueSkgPT4gVGlsZXNldE1ldGFkYXRhIHwgbnVsbDtcbn07XG4vLyBodHRwczovL2dpdGh1Yi5jb20vbWFwYm94L3RpbGVqc29uLXNwZWMvdHJlZS9tYXN0ZXIvMi4yLjBcbmZ1bmN0aW9uIGlzTGF0KG51bTogYW55KTogYm9vbGVhbiB7XG4gIHJldHVybiBOdW1iZXIuaXNGaW5pdGUobnVtKSAmJiBudW0gPD0gOTAgJiYgbnVtID49IC05MDtcbn1cbmZ1bmN0aW9uIGlzTG5nKG51bTogYW55KTogYm9vbGVhbiB7XG4gIHJldHVybiBOdW1iZXIuaXNGaW5pdGUobnVtKSAmJiBudW0gPD0gMTgwICYmIG51bSA+PSAtMTgwO1xufVxuZnVuY3Rpb24gaXNab29tKG51bTogYW55KTogYm9vbGVhbiB7XG4gIHJldHVybiBOdW1iZXIuaXNGaW5pdGUobnVtKSAmJiBudW0gPj0gMCAmJiBudW0gPD0gMjI7XG59XG5mdW5jdGlvbiBmcm9tQXJyYXlPclN0cmluZyhkYXRhOiBzdHJpbmcgfCBudW1iZXJbXSk6IG51bWJlcltdIHwgbnVsbCB7XG4gIGlmICh0eXBlb2YgZGF0YSA9PT0gJ3N0cmluZycpIHtcbiAgICByZXR1cm4gZGF0YS5zcGxpdCgnLCcpLm1hcChwYXJzZUZsb2F0KTtcbiAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KGRhdGEpKSB7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbmZ1bmN0aW9uIHBhcnNlQ2VudGVyKGNlbnRlcjogc3RyaW5nIHwgbnVtYmVyW10pOiBudW1iZXJbXSB8IG51bGwge1xuICAvLyBzdXBwb3J0ZWQgZm9ybWF0c1xuICAvLyBzdHJpbmc6IFwiLTk2LjY1NzcxNSw0MC4xMjYxMjcsLTkwLjE0MDA2MSw0My41MTY2ODlcIixcbiAgLy8gYXJyYXk6IFstOTEuNTA1MTI3LDQxLjYxNTQ0MiwxNF1cbiAgY29uc3QgcmVzdWx0ID0gZnJvbUFycmF5T3JTdHJpbmcoY2VudGVyKTtcbiAgaWYgKFxuICAgIEFycmF5LmlzQXJyYXkocmVzdWx0KSAmJlxuICAgIHJlc3VsdC5sZW5ndGggPT09IDMgJiZcbiAgICBpc0xuZyhyZXN1bHRbMF0pICYmXG4gICAgaXNMYXQocmVzdWx0WzFdKSAmJlxuICAgIGlzWm9vbShyZXN1bHRbMl0pXG4gICkge1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogYm91bmRzIHNob3VsZCBiZSBbbWluTG5nLCBtaW5MYXQsIG1heExuZywgbWF4TGF0XVxuICogQHBhcmFtIHsqfSBib3VuZHNcbiAqL1xuZnVuY3Rpb24gcGFyc2VCb3VuZHMoYm91bmRzOiBzdHJpbmcgfCBudW1iZXJbXSk6IG51bWJlcltdIHwgbnVsbCB7XG4gIC8vIHN1cHBvcnRlZCBmb3JtYXRzXG4gIC8vIHN0cmluZzogXCItOTYuNjU3NzE1LDQwLjEyNjEyNywtOTAuMTQwMDYxLDQzLjUxNjY4OVwiLFxuICAvLyBhcnJheTogWyAtMTgwLCAtODUuMDUxMTI4Nzc5ODA2NTksIDE4MCwgODUuMDUxMTI4Nzc5ODA2NiBdXG4gIGNvbnN0IHJlc3VsdCA9IGZyb21BcnJheU9yU3RyaW5nKGJvdW5kcyk7XG4gIC8vIHZhbGlkYXRlIGJvdW5kc1xuICBpZiAoXG4gICAgQXJyYXkuaXNBcnJheShyZXN1bHQpICYmXG4gICAgcmVzdWx0Lmxlbmd0aCA9PT0gNCAmJlxuICAgIFtyZXN1bHRbMF0sIHJlc3VsdFsyXV0uZXZlcnkoaXNMbmcpICYmXG4gICAgW3Jlc3VsdFsxXSwgcmVzdWx0WzNdXS5ldmVyeShpc0xhdClcbiAgKSB7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cblxuY29uc3QgWF9QQVRUID0gL1xce3hcXH0vO1xuY29uc3QgWV9QQVRUID0gL1xce3lcXH0vO1xuY29uc3QgWl9QQVRUID0gL1xce3pcXH0vO1xuXG5mdW5jdGlvbiBpc0Z1bGx5UXVhbGlmaWVkVGlsZVVybCh0aWxlVXJsOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIFhfUEFUVC50ZXN0KHRpbGVVcmwpICYmIFlfUEFUVC50ZXN0KHRpbGVVcmwpICYmIFpfUEFUVC50ZXN0KHRpbGVVcmwpO1xufVxuXG4vKipcbiAqIE5vcm1hbGl6ZSB0aWxlIFVSTFxuICogQHBhcmFtICB7c3RyaW5nfSB0aWxlVXJsIEluaXRpYWwgdGlsZSBVUkwsIHdoaWNoIG1heSBiZSBlaXRoZXIgdGhlIHJvb3QgVVJMIGZvciB0aGVcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICB0aWxlc2V0IG9yIGEgZnVsbHkgcXVhbGlmaWVkIHRlbXBsYXRlXG4gKiBAcGFyYW0gIHtmdW5jdGlvbn0gdmFsaWRhdGVVcmwgZnVuY3Rpb24gdG8gdmFsaWRhdGUgdGlsZSBVUkxcbiAqIEByZXR1cm4ge3N0cmluZ3xudWxsfSAgICBGdWxseSBxdWFsaWZpZWQgdGlsZSBVUkwgdGVtcGxhdGUsIG9yIG51bGwgaWYgaW5wdXQgZG9lcyBub3RcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICBhcHBlYXIgdG8gYmUgYSB2YWxpZCBVUkxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFRpbGVVcmwoXG4gIHRpbGVVcmw6IHN0cmluZyxcbiAgdmFsaWRhdGVVcmw6IChzOiBzdHJpbmcpID0+IGJvb2xlYW4gPSBpc0Z1bGx5UXVhbGlmaWVkVGlsZVVybFxuKTogc3RyaW5nIHwgbnVsbCB7XG4gIC8vIENoZWNrIGZvciBhIHZhbGlkIFVSTC4gSWRlYWxseSB3ZSdkIGhhdmUgYSBzaW1wbGUgbWV0aG9kIGhlcmUuXG4gIGNvbnN0IHVyaVBhcnRzID0gcGFyc2VVcmkodGlsZVVybCk7XG4gIGlmICghdXJpUGFydHMucHJvdG9jb2wgfHwgIXVyaVBhcnRzLmhvc3QpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuICBpZiAodmFsaWRhdGVVcmwodGlsZVVybCkpIHtcbiAgICByZXR1cm4gdGlsZVVybDtcbiAgfVxuICByZXR1cm4gYCR7dGlsZVVybC5yZXBsYWNlKC9cXC8kLywgJycpfS97en0ve3h9L3t5fS5wYmZgO1xufVxuXG4vKipcbiAqIE1hcCBvZiB1dGlsIGZ1bmN0aW9ucyBmb3IgZGlmZmVyZW50IHRpbGVzZXQgdHlwZXMsIGtleWVkIGJ5IGhvc3RcbiAqL1xuY29uc3QgVElMRVNFVF9GVU5DVElPTlM6IHtba2V5OiBzdHJpbmddOiBUaWxlc2V0RnVuY3Rpb259ID0ge1xuICAnYXBpLm1hcGJveC5jb20nOiB7XG4gICAgZ2V0TWV0YVVybDogZ2V0TWV0YVVybE1hcGJveCxcbiAgICBwYXJzZU1ldGFkYXRhOiBwYXJzZU1ldGFkYXRhVGlsZUpTT05cbiAgfSxcbiAgZGVmYXVsdDoge1xuICAgIGdldE1ldGFVcmw6IGdldE1ldGFVcmxUaXBwZWNhbm9lLFxuICAgIHBhcnNlTWV0YWRhdGE6IHBhcnNlTWV0YWRhdGFUaWxlSlNPTlxuICB9XG59O1xuXG5mdW5jdGlvbiBnZXRUaWxlc2V0RnVuY3Rpb25zKHRpbGVVcmw6IHN0cmluZyB8IG51bGwpOiBUaWxlc2V0RnVuY3Rpb24ge1xuICBsZXQgaG9zdCA9ICcnO1xuICB0cnkge1xuICAgIGhvc3QgPSBuZXcgVVJMKHRpbGVVcmwgfHwgJycpLmhvc3RuYW1lO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIC8vIGRvIG5vdGhpbmdcbiAgfVxuXG4gIHJldHVybiBUSUxFU0VUX0ZVTkNUSU9OU1tob3N0XSB8fCBUSUxFU0VUX0ZVTkNUSU9OUy5kZWZhdWx0O1xufVxuXG4vKipcbiAqIEdldCB0aGUgbWV0YWRhdGEgVVJMIGZvciBhIGdpdmVuIHRpbGVzZXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE1ldGFVcmwodGlsZVVybDogc3RyaW5nKTogc3RyaW5nIHwgbnVsbCB7XG4gIHJldHVybiBnZXRUaWxlc2V0RnVuY3Rpb25zKHRpbGVVcmwpLmdldE1ldGFVcmwodGlsZVVybCk7XG59XG50eXBlIFBhcnNlTWV0YWRhdGFPcHRpb24gPSB7XG4gIHRpbGVVcmw/OiBzdHJpbmcgfCBudWxsO1xufTtcbi8qKlxuICogUGFyc2UgdGhlIG1ldGFkYXRhIGZvciBhIGdpdmVuIHRpbGVzZXRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlVmVjdG9yTWV0YWRhdGEoXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvZXhwbGljaXQtbW9kdWxlLWJvdW5kYXJ5LXR5cGVzXG4gIG1ldGFkYXRhOiBQTVRpbGVzTWV0YWRhdGEgfCBUaWxlSlNPTixcbiAgb3B0aW9uPzogUGFyc2VNZXRhZGF0YU9wdGlvblxuKTogVGlsZXNldE1ldGFkYXRhIHwgbnVsbCB7XG4gIGNvbnN0IHt0aWxlVXJsID0gJyd9ID0gb3B0aW9uIHx8IHt9O1xuICByZXR1cm4gZ2V0VGlsZXNldEZ1bmN0aW9ucyh0aWxlVXJsKS5wYXJzZU1ldGFkYXRhKG1ldGFkYXRhKTtcbn1cblxuY29uc3QgTUFQQk9YX1VSTF9QQVRUID0gL1xcL1xce3pcXH1cXC9cXHt4XFx9XFwvXFx7eVxcfVxcLm12dC87XG5cbmZ1bmN0aW9uIGdldE1ldGFVcmxNYXBib3godGlsZVVybCA9ICcnKTogc3RyaW5nIHtcbiAgcmV0dXJuIHRpbGVVcmwucmVwbGFjZShNQVBCT1hfVVJMX1BBVFQsICcuanNvbicpO1xufVxuXG5mdW5jdGlvbiBwYXJzZU1ldGFkYXRhVGlsZUpTT04obWV0YWRhdGE6IFBNVGlsZXNNZXRhZGF0YSB8IFRpbGVKU09OKTogVGlsZXNldE1ldGFkYXRhIHwgbnVsbCB7XG4gIGNvbnN0IHBhcnNlZCA9IHBhcnNlTWV0YWRhdGFUaXBwZWNhbm9lRnJvbURhdGFTb3VyY2UobWV0YWRhdGEpO1xuICBpZiAoIXBhcnNlZCkgcmV0dXJuIG51bGw7XG5cbiAgLy8gUE1UaWxlcyBjYW4gcG90ZW50aWFsbHkgYmUgaW4gUmFzdGVyVGlsZSBmb3JtYXRcbiAgY29uc3QgbWltZVR5cGUgPSAobWV0YWRhdGEgYXMgUE1UaWxlc01ldGFkYXRhKS50aWxlTUlNRVR5cGU7XG4gIGlmIChtaW1lVHlwZSkge1xuICAgIHBhcnNlZC5wbXRpbGVzVHlwZSA9XG4gICAgICBtaW1lVHlwZSA9PT0gJ2FwcGxpY2F0aW9uL3ZuZC5tYXBib3gtdmVjdG9yLXRpbGUnID8gUE1UaWxlc1R5cGUuTVZUIDogUE1UaWxlc1R5cGUuUkFTVEVSO1xuICB9XG5cbiAgLy8gRmllbGRzIGFscmVhZHkgcGFyc2VkIGZyb20gYGpzb25gIHByb3BlcnR5XG4gIGlmIChwYXJzZWQuZmllbGRzPy5sZW5ndGgpIHtcbiAgICByZXR1cm4gcGFyc2VkO1xuICB9XG5cbiAgcmV0dXJuIHBhcnNlZDtcbn1cblxuZnVuY3Rpb24gZ2V0TWV0YVVybFRpcHBlY2Fub2UodGlsZVVybCkge1xuICBjb25zdCB1cmwgPSBnZXRUaWxlVXJsKHRpbGVVcmwpO1xuICBpZiAoIXVybCkgcmV0dXJuIG51bGw7XG4gIC8vIGFzc3VtZXMgdGhlIHN0cnVjdHVyZSA8dXJsX2Jhc2U+L3t6fS4uLlxuICBjb25zdCBiYXNlVXJsID0gdXJsLnNwbGl0KFpfUEFUVClbMF0ucmVwbGFjZSgvXFwvJC8sICcnKTtcbiAgcmV0dXJuIGAke2Jhc2VVcmx9L21ldGFkYXRhLmpzb25gO1xufVxuXG4vKipcbiAqIFNwZWNpYWwgcGFyc2luZyBmb3IgbWV0YWRhdGEgcmV0dXJuZWQgYnkgTVZUU291cmNlIGFuZCBQTVRpbGVzU291cmNlLlxuICogQHBhcmFtIG1ldGFkYXRhIFRpbGVzZXQgbWV0YWRhdGEgcGFyc2VkIGJ5IGEgRGF0YVNvdWNlXG4gKiBAcmV0dXJucyBNZXRhZGF0YSBpbiBLZXBsZXItZnJpZW5kbHkgZm9ybWF0LlxuICovXG5mdW5jdGlvbiBwYXJzZU1ldGFkYXRhVGlwcGVjYW5vZUZyb21EYXRhU291cmNlKFxuICBtZXRhZGF0YTogUE1UaWxlc01ldGFkYXRhIHwgVGlsZUpTT04gfCBudWxsXG4pOiBUaWxlc2V0TWV0YWRhdGEgfCBudWxsIHtcbiAgaWYgKCFtZXRhZGF0YSB8fCB0eXBlb2YgbWV0YWRhdGEgIT09ICdvYmplY3QnKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBsZXQgcmVzdWx0OiBUaWxlc2V0TWV0YWRhdGEgPSB7XG4gICAgYXR0cmlidXRpb25zOiBbXSxcbiAgICBtZXRhSnNvbjogbnVsbCxcbiAgICBib3VuZHM6IG51bGwsXG4gICAgY2VudGVyOiBudWxsLFxuICAgIG1heFpvb206IG51bGwsXG4gICAgbWluWm9vbTogbnVsbCxcbiAgICBmaWVsZHM6IFtdXG4gIH07XG5cbiAgY29uc3QgbXZ0TWV0YWRhdGEgPSBtZXRhZGF0YSBhcyBUaWxlSlNPTjtcbiAgY29uc3QgcG1UaWxlTWV0YWRhdGEgPSBtZXRhZGF0YSBhcyBQTVRpbGVzTWV0YWRhdGE7XG5cbiAgLy8gdHJ5IHRvIHBhcnNlIG1ldGFKc29uXG4gIGlmICh0eXBlb2YgbXZ0TWV0YWRhdGEubWV0YUpzb24gPT09ICdzdHJpbmcnKSB7XG4gICAgdHJ5IHtcbiAgICAgIHJlc3VsdC5tZXRhSnNvbiA9IEpTT04ucGFyc2UobXZ0TWV0YWRhdGEubWV0YUpzb24pO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gZG8gbm90aGluZ1xuICAgIH1cbiAgfSBlbHNlIGlmICh0eXBlb2YgbXZ0TWV0YWRhdGEubWV0YUpzb24gPT09ICdvYmplY3QnKSB7XG4gICAgcmVzdWx0Lm1ldGFKc29uID0gbXZ0TWV0YWRhdGEubWV0YUpzb247XG4gIH1cblxuICByZXN1bHQuYm91bmRzID0gcGFyc2VCb3VuZHMoXG4gICAgQXJyYXkuaXNBcnJheShtZXRhZGF0YS5ib3VuZGluZ0JveCkgPyBtZXRhZGF0YS5ib3VuZGluZ0JveC5mbGF0KCkgOiAnJ1xuICApO1xuXG4gIC8vIFBNVGlsZVNvdXJjZSBoYXMgY2VudGVyWm9vbSBhbmQgY2VudGVyIFtsb24sIGxhdF0sIE1WVFNvdXJjZSAtIFtsb24sIGxhdCwgem9vbV1cbiAgY29uc3QgY2VudGVyID1cbiAgICBwbVRpbGVNZXRhZGF0YS5jZW50ZXJab29tICE9PSB1bmRlZmluZWQgJiYgQXJyYXkuaXNBcnJheShtZXRhZGF0YS5jZW50ZXIpXG4gICAgICA/IFsuLi5tZXRhZGF0YS5jZW50ZXIsIHBtVGlsZU1ldGFkYXRhLmNlbnRlclpvb21dXG4gICAgICA6IG1ldGFkYXRhLmNlbnRlcjtcbiAgcmVzdWx0LmNlbnRlciA9IHBhcnNlQ2VudGVyKGNlbnRlciB8fCAnJyk7XG5cbiAgcmVzdWx0Lm1heFpvb20gPSBzYWZlUGFyc2VGbG9hdChtZXRhZGF0YS5tYXhab29tKTtcbiAgcmVzdWx0Lm1pblpvb20gPSBzYWZlUGFyc2VGbG9hdChtZXRhZGF0YS5taW5ab29tKTtcbiAgcmVzdWx0Lm5hbWUgPSBtZXRhZGF0YS5uYW1lIHx8ICcnO1xuICByZXN1bHQuZGVzY3JpcHRpb24gPSBtdnRNZXRhZGF0YS5kZXNjcmlwdGlvbiB8fCBwbVRpbGVNZXRhZGF0YS50aWxlanNvbj8uZGVzY3JpcHRpb24gfHwgJyc7XG5cbiAgaWYgKEFycmF5LmlzQXJyYXkocG1UaWxlTWV0YWRhdGEudGlsZWpzb24/LmxheWVycykpIHtcbiAgICBjb25zdCBsYXllcnMgPSBwbVRpbGVzTGF5ZXJUb1RpcHBlY2Fub2VMYXllcihwbVRpbGVNZXRhZGF0YS50aWxlanNvbj8ubGF5ZXJzKTtcbiAgICByZXN1bHQuZmllbGRzID0gY29sbGVjdEF0dHJpYnV0ZXMobGF5ZXJzKTtcbiAgfSBlbHNlIGlmIChBcnJheS5pc0FycmF5KG12dE1ldGFkYXRhLmxheWVycykpIHtcbiAgICBjb25zdCBsYXllcnMgPSBwbVRpbGVzTGF5ZXJUb1RpcHBlY2Fub2VMYXllcihtdnRNZXRhZGF0YS5sYXllcnMpO1xuICAgIHJlc3VsdC5maWVsZHMgPSBjb2xsZWN0QXR0cmlidXRlcyhsYXllcnMpO1xuICB9XG5cbiAgcmVzdWx0ID0ge1xuICAgIC4uLnJlc3VsdCxcbiAgICBhdHRyaWJ1dGlvbnM6XG4gICAgICBwbVRpbGVNZXRhZGF0YS5hdHRyaWJ1dGlvbnMgfHxcbiAgICAgIChtdnRNZXRhZGF0YS5odG1sQXR0cmlidXRpb24gPyBbbXZ0TWV0YWRhdGEuaHRtbEF0dHJpYnV0aW9uXSA6IHVuZGVmaW5lZCkgfHxcbiAgICAgIFtdLFxuICAgIC4uLnBhcnNlTWV0YUpzb24ocmVzdWx0Lm1ldGFKc29uKVxuICB9O1xuXG4gIHJldHVybiByZXN1bHQ7XG59XG5cbmZ1bmN0aW9uIHNhZmVQYXJzZUZsb2F0KGlucHV0OiB1bmtub3duKTogbnVtYmVyIHwgbnVsbCB7XG4gIGNvbnN0IHJlc3VsdCA9XG4gICAgdHlwZW9mIGlucHV0ID09PSAnc3RyaW5nJyA/IHBhcnNlRmxvYXQoaW5wdXQpIDogdHlwZW9mIGlucHV0ID09PSAnbnVtYmVyJyA/IGlucHV0IDogbnVsbDtcbiAgcmV0dXJuIHJlc3VsdCA9PT0gbnVsbCB8fCBpc05hTihyZXN1bHQpID8gbnVsbCA6IHJlc3VsdDtcbn1cblxuZnVuY3Rpb24gcGFyc2VNZXRhSnNvbihtZXRhSnNvbjogYW55KToge2ZpZWxkczogVmVjdG9yVGlsZUZpZWxkW119IHwgbnVsbCB7XG4gIGlmICghbWV0YUpzb24gfHwgdHlwZW9mIG1ldGFKc29uICE9PSAnb2JqZWN0Jykge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgaWYgKG1ldGFKc29uLnRpbGVzdGF0cyAmJiBBcnJheS5pc0FycmF5KG1ldGFKc29uLnRpbGVzdGF0cy5sYXllcnMpKSB7XG4gICAgLy8gd2UgYXJlIGluIGx1Y2shXG4gICAgcmV0dXJuIHtmaWVsZHM6IGNvbGxlY3RBdHRyaWJ1dGVzKG1ldGFKc29uLnRpbGVzdGF0cy5sYXllcnMpfTtcbiAgfVxuICByZXR1cm4gbnVsbDtcbn1cblxuZnVuY3Rpb24gZ2V0VGltZUFuaW1hdGlvbkRvbWFpbihtYXBwZWRWYWx1ZTogbnVtYmVyW10pOiB7XG4gIGRvbWFpbjogbnVtYmVyW107XG4gIHRpbWVTdGVwczogbnVtYmVyW107XG4gIG1hcHBlZFZhbHVlOiBudW1iZXJbXTtcbiAgZHVyYXRpb246IG51bWJlcjtcbn0ge1xuICBjb25zdCB0aW1lU3RlcHMgPSB1bmlxKG1hcHBlZFZhbHVlKS5zb3J0KGFzY2VuZGluZykuZmlsdGVyKG5vdE51bGxPclVuZGVmaW5lZCk7XG5cbiAgY29uc3QgZG9tYWluID0gW3RpbWVTdGVwc1swXSwgdGltZVN0ZXBzW3RpbWVTdGVwcy5sZW5ndGggLSAxXV07XG5cbiAgLy8gaWYgdGFrcyAxMCAqIDEwMDAgbXMgdG8gZmluaXNoIHRoZSBlbnRpcmUgYW5pbWF0aW9uXG4gIGNvbnN0IGR1cmF0aW9uID0gMTAwMDAgLyB0aW1lU3RlcHMubGVuZ3RoO1xuICBjb25zdCBjbGFtcGVkID0gY2xhbXAoWzEwMCwgMjAwMF0sIGR1cmF0aW9uKTtcblxuICByZXR1cm4ge2RvbWFpbiwgdGltZVN0ZXBzLCBkdXJhdGlvbjogY2xhbXBlZCwgbWFwcGVkVmFsdWV9O1xufVxuXG5jb25zdCBwbVRpbGVUeXBlVG9BdHRyTWFwID0ge1xuICBmbG9hdDMyOiAnbnVtYmVyJyxcbiAgc3RyaW5nOiAnc3RyaW5nJyxcbiAgdXRmODogJ3N0cmluZycsXG4gIGludDogJ2ludCcsXG4gIGJvb2xlYW46ICdib29sZWFuJ1xufTtcblxuLyoqXG4gKiBUcmFuc2Zvcm0gVGlsZUpTT05bJ2xheWVycyddIGJhY2sgdG8gVGlwcGVjYW5vZUxheWVyXG4gKi9cbmZ1bmN0aW9uIHBtVGlsZXNMYXllclRvVGlwcGVjYW5vZUxheWVyKGxheWVyczogVGlsZUpTT05bJ2xheWVycyddKTogVGlwcGVjYW5vZUxheWVyW10ge1xuICBpZiAoIWxheWVycykgcmV0dXJuIFtdO1xuXG4gIGNvbnN0IG91dExheWVyczogVGlwcGVjYW5vZUxheWVyW10gPSBbXTtcbiAgZm9yIChjb25zdCBsYXllciBvZiBsYXllcnMpIHtcbiAgICBjb25zdCB7ZmllbGRzID0gW119ID0gbGF5ZXIgfHwge307XG4gICAgZm9yIChjb25zdCBwbUZpZWxkIG9mIGZpZWxkcykge1xuICAgICAgY29uc3QgYXR0cmlidXRlID0ge1xuICAgICAgICBhdHRyaWJ1dGU6IHBtRmllbGQubmFtZSxcbiAgICAgICAgdHlwZTogcG1UaWxlVHlwZVRvQXR0ck1hcFtwbUZpZWxkLnR5cGVdLFxuICAgICAgICBjb3VudDogcG1GaWVsZC51bmlxdWVWYWx1ZUNvdW50LFxuICAgICAgICB2YWx1ZXM6IChwbUZpZWxkLnZhbHVlcyA/PyBbXSkgYXMgbnVtYmVyW10gfCBzdHJpbmdbXSxcbiAgICAgICAgbWluOiBwbUZpZWxkLm1pbixcbiAgICAgICAgbWF4OiBwbUZpZWxkLm1heFxuICAgICAgfTtcblxuICAgICAgb3V0TGF5ZXJzLnB1c2goe1xuICAgICAgICBhdHRyaWJ1dGVzOiBbYXR0cmlidXRlXVxuICAgICAgfSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBvdXRMYXllcnM7XG59XG5cbmZ1bmN0aW9uIGNvbGxlY3RBdHRyaWJ1dGVzKGxheWVyczogVGlwcGVjYW5vZUxheWVyW10gPSBbXSk6IFZlY3RvclRpbGVGaWVsZFtdIHtcbiAgY29uc3QgZmllbGRzID0ge307XG4gIGNvbnN0IGluZGV4ZWRBdHRyaWJ1dGVzOiB7W2tleTogc3RyaW5nXTogVGlwcGVjYW5vZUxheWVyQXR0cmlidXRlW119ID0ge307XG5cbiAgZm9yIChjb25zdCBsYXllciBvZiBsYXllcnMpIHtcbiAgICBjb25zdCB7YXR0cmlidXRlcyA9IFtdfSA9IGxheWVyIHx8IHt9O1xuICAgIGZvciAoY29uc3QgYXR0ciBvZiBhdHRyaWJ1dGVzKSB7XG4gICAgICBjb25zdCBuYW1lID0gYXR0ci5hdHRyaWJ1dGU7XG4gICAgICBpZiAodHlwZW9mIG5hbWUgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtZGVwdGhcbiAgICAgICAgaWYgKG5hbWUuc3BsaXQoJ3wnKS5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgLy8gaW5kZXhlZCBmaWVsZFxuICAgICAgICAgIGNvbnN0IGZuYW1lID0gbmFtZS5zcGxpdCgnfCcpWzBdO1xuICAgICAgICAgIGluZGV4ZWRBdHRyaWJ1dGVzW2ZuYW1lXSA9IGluZGV4ZWRBdHRyaWJ1dGVzW2ZuYW1lXSB8fCBbXTtcbiAgICAgICAgICBpbmRleG