UNPKG

kepler.gl

Version:

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

524 lines (509 loc) 65.9 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.appendColumnsToDataset = appendColumnsToDataset; exports.getDatasetContext = getDatasetContext; exports.getGeometriesFromDataset = getGeometriesFromDataset; exports.getValuesFromDataset = getValuesFromDataset; exports.getValuesFromVectorTileLayer = getValuesFromVectorTileLayer; exports.highlightRows = highlightRows; exports.highlightRowsByColumnValues = highlightRowsByColumnValues; exports.interpolateColor = interpolateColor; exports.saveAsDataset = saveAsDataset; var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _colorInterpolate = _interopRequireDefault(require("color-interpolate")); var _constants = require("@kepler.gl/constants"); var _processors = require("@kepler.gl/processors"); 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; } // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project /** * Interpolate the colors from the original colors with the given number of colors * @param originalColors The original colors * @param numberOfColors The number of colors * @returns The interpolated colors */ function interpolateColor(originalColors, numberOfColors) { if (originalColors.length === numberOfColors) { return originalColors; } var interp = (0, _colorInterpolate["default"])(originalColors); var colors = Array.from({ length: numberOfColors }, function (_, j) { return interp(j / (numberOfColors - 1)); }); // convert colors from 'rgb(255, 255, 255)' to '#ffffff' var hexColors = colors.map(function (color) { var rgb = color.match(/\d+/g); return "#".concat(rgb === null || rgb === void 0 ? void 0 : rgb.map(function (c) { return parseInt(c).toString(16).padStart(2, '0'); }).join('')); }); return hexColors; } /** * Get the values from a dataset for a variable * @param datasets * @param datasetName * @param variableName * @returns {number[]} */ function getValuesFromDataset(datasets, layers, datasetName, variableName) { // find which dataset has the variableName var datasetId = Object.keys(datasets).find(function (dataId) { return datasets[dataId].label === datasetName; }); if (!datasetId) { throw new Error("Dataset ".concat(datasetName, " not found")); } var dataset = datasets[datasetId]; if (dataset) { // check if field exists var field = dataset.fields.find(function (field) { return field.name === variableName; }); if (!field) { throw new Error("Field ".concat(variableName, " not found in dataset ").concat(datasetName)); } // for vector-tile, getting values from layerData if (dataset.type === 'vector-tile') { // get field from dataset var _field = dataset.fields.find(function (field) { return field.name === variableName; }); if (_field) { return getValuesFromVectorTileLayer(datasetId, layers, _field); } } return Array.from({ length: dataset.length }, function (_, i) { return dataset.getValue(variableName, i); }); } return []; } function isVectorTileLayer(layer) { return layer.type === _constants.LAYER_TYPES.vectorTile; } function getValuesFromVectorTileLayer(datasetId, layers, field) { // get the index of the layer var layerIndex = layers.findIndex(function (layer) { return layer.config.dataId === datasetId; }); if (layerIndex === -1) return []; var layer = layers[layerIndex]; if (!isVectorTileLayer(layer)) return []; var accessor = layer.accessRowValue(field); var values = []; // @ts-expect-error TODO fix this later in the vector-tile layer var _iterator = _createForOfIteratorHelper(layer.tileDataset.tileSet), _step; try { for (_iterator.s(); !(_step = _iterator.n()).done;) { var row = _step.value; var value = accessor(field, row); if (value === null) break; values.push(value); } } catch (err) { _iterator.e(err); } finally { _iterator.f(); } return values; } /** * Highlight the rows in a dataset * @param datasets The kepler.gl datasets * @param layers The kepler.gl layers * @param datasetName The name of the dataset * @param selectedRowIndices The indices of the rows to highlight * @param layerSetIsValid The function to set the layer validity */ function highlightRows(datasets, layers, datasetName, selectedRowIndices, layerSetIsValid) { // update the filteredIndex in the dataset var datasetId = Object.keys(datasets).find(function (dataId) { return datasets[dataId].label === datasetName; }); if (!datasetId) return; var dataset = datasets[datasetId]; if (dataset) { dataset.filteredIndex = selectedRowIndices.length === 0 ? dataset.allIndexes : selectedRowIndices; // get all layers that use this dataset var selectLayers = layers.filter(function (layer) { return layer.config.dataId === dataset.id; }); selectLayers.forEach(function (layer) { layer.formatLayerData(datasets); // trigger a re-render using layerSetIsValid() to update the top layer layerSetIsValid(layer, true); }); } } /** * Get the dataset context, which is used to provide the dataset information to the AI assistant * @param datasets The kepler.gl datasets * @param layers The kepler.gl layers * @returns The dataset context */ function getDatasetContext(datasets, layers) { if (!datasets || !layers) return ''; var context = 'Please remember the following datasets and layers for answering the user question:'; var dataMeta = Object.values(datasets).map(function (dataset) { return { datasetName: dataset.label, datasetId: dataset.id, fields: dataset.fields.map(function (field) { return (0, _defineProperty2["default"])({}, field.name, field.type); }), layers: layers.filter(function (layer) { return layer.config.dataId === dataset.id; }).map(function (layer) { return { id: layer.id, label: layer.config.label, type: layer.type, geometryMode: layer.config.columnMode, // get the valid geometry columns as string geometryColumns: Object.fromEntries(Object.entries(layer.config.columns).filter(function (_ref2) { var _ref3 = (0, _slicedToArray2["default"])(_ref2, 2), value = _ref3[1]; return value !== null; }).map(function (_ref4) { var _ref5 = (0, _slicedToArray2["default"])(_ref4, 2), key = _ref5[0], value = _ref5[1]; return [key, (0, _typeof2["default"])(value) === 'object' && value !== null ? Object.fromEntries(Object.entries(value).filter(function (_ref6) { var _ref7 = (0, _slicedToArray2["default"])(_ref6, 2), v = _ref7[1]; return v !== null; })) : value]; })) }; }) }; }); return "".concat(context, "\n").concat(JSON.stringify(dataMeta)); } /** * Get the geometries from a dataset * @param datasets The kepler.gl datasets * @param layers The kepler.gl layers * @param layerData The layer data * @param datasetName The name of the dataset * @returns The geometries */ function getGeometriesFromDataset(datasets, layers, layerData, datasetName) { var datasetId = Object.keys(datasets).find(function (dataId) { return datasets[dataId].label === datasetName; }); if (!datasetId) { return []; } var dataset = datasets[datasetId]; // if layer is vector-tile, get the geometries from the layer if (dataset.type === 'vector-tile') { // find the vector-tile layer var selected = layers.filter(function (layer) { return layer.config.dataId === dataset.id; }); var layer = selected.find(function (layer) { return layer.type === _constants.LAYER_TYPES.vectorTile; }); if (!layer) return []; var geometries = []; // @ts-expect-error TODO fix this later in the vector-tile layer var _iterator2 = _createForOfIteratorHelper(layer.tileDataset.tileSet), _step2; try { for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) { var row = _step2.value; geometries.push(row); } } catch (err) { _iterator2.e(err); } finally { _iterator2.f(); } return geometries; } // for non-vector-tile dataset, get the geometries from the possible layer var selectedLayers = layers.filter(function (layer) { return layer.config.dataId === dataset.id; }); if (selectedLayers.length === 0) return []; // find geojson layer, then point layer, then other layers var geojsonLayer = selectedLayers.find(function (layer) { return layer.type === _constants.LAYER_TYPES.geojson; }); var pointLayer = selectedLayers.find(function (layer) { return layer.type === _constants.LAYER_TYPES.point; }); var otherLayers = selectedLayers.filter(function (layer) { return layer.type !== _constants.LAYER_TYPES.geojson && layer.type !== _constants.LAYER_TYPES.point; }); var validLayer = geojsonLayer || pointLayer || otherLayers[0]; if (validLayer) { var layerIndex = layers.findIndex(function (layer) { return layer.id === validLayer.id; }); var _geometries = layerData[layerIndex]; return _geometries.data; } return []; } /** * Save the data as a new dataset by joining it with the left dataset * @param datasets The kepler.gl datasets * @param datasetName The name of the left dataset * @param data The data to save * @param addDataToMap The function to add the data to the map */ function saveAsDataset(datasets, layers, datasetName, newDatasetName, data) { // find datasetId from datasets var datasetId = Object.keys(datasets).find(function (dataId) { return datasets[dataId].label === datasetName; }); if (!datasetId) return; // check if newDatasetName already exists if (Object.keys(datasets).includes(newDatasetName)) return; // Save the data as a new dataset by joining it with the left dataset var leftDataset = datasets[datasetId]; var numRows = leftDataset.length; var geometries; if (leftDataset.type === 'vector-tile') { // we need to get geometries from the vector-tile layer geometries = getFeaturesFromVectorTile(leftDataset, layers) || []; numRows = geometries.length; } var fields = [].concat((0, _toConsumableArray2["default"])(Object.keys(data).map(function (fieldName, index) { return { name: fieldName, id: "".concat(fieldName, "_").concat(index), displayName: fieldName, type: determineFieldType(data[fieldName][0]) }; })), (0, _toConsumableArray2["default"])(leftDataset.fields.map(function (field, index) { return { name: field.name, id: field.id || "".concat(field.name, "_").concat(index), displayName: field.displayName, type: field.type }; })), (0, _toConsumableArray2["default"])(leftDataset.type === 'vector-tile' ? [{ name: '_geojson', id: '_geojson', displayName: '_geojson', type: 'geojson' }] : [])); // Pre-calculate data values array var dataValues = Object.values(data); var rows = Array(numRows).fill(null).map(function (_, rowIdx) { return [].concat((0, _toConsumableArray2["default"])(dataValues.map(function (col) { return col[rowIdx]; })), (0, _toConsumableArray2["default"])(leftDataset.fields.map(function (field) { var _geometries$rowIdx$pr; return leftDataset.type === 'vector-tile' ? (_geometries$rowIdx$pr = geometries[rowIdx].properties) === null || _geometries$rowIdx$pr === void 0 ? void 0 : _geometries$rowIdx$pr[field.name] : leftDataset.getValue(field.name, rowIdx); })), (0, _toConsumableArray2["default"])(leftDataset.type === 'vector-tile' ? [geometries[rowIdx]] : [])); }); // create new dataset var newDataset = { info: { id: newDatasetName, label: newDatasetName }, data: { fields: fields, rows: rows } }; return newDataset; } /** * Helper function to determine field type * @param value The value to determine the field type * @returns The field type */ function determineFieldType(value) { return typeof value === 'number' ? Number.isInteger(value) ? _constants.ALL_FIELD_TYPES.integer : _constants.ALL_FIELD_TYPES.real : _constants.ALL_FIELD_TYPES.string; } function highlightRowsByColumnValues(datasets, layers, datasetName, columnName, selectedValues, layerSetIsValid) { var datasetId = Object.keys(datasets).find(function (dataId) { return datasets[dataId].label === datasetName; }); if (!datasetId) return; var dataset = datasets[datasetId]; if (dataset) { // get the values of the column var values = Array.from({ length: dataset.length }, function (_, i) { return dataset.getValue(columnName, i); }); // create a dict using the values var valueDict = values.reduce(function (acc, value, index) { acc[value] = index; return acc; }, {}); // need to fix the type error of value here var selectedIndices = selectedValues.map(function (value) { return valueDict[value]; }); // highlight the rows highlightRows(datasets, layers, datasetName, selectedIndices, layerSetIsValid); } } function getFeaturesFromVectorTile(leftDataset, layers) { var layerIndex = layers.findIndex(function (layer) { return layer.config.dataId === leftDataset.id; }); if (layerIndex === -1) return; var layer = layers[layerIndex]; if (!isVectorTileLayer(layer)) return; var features = []; // @ts-expect-error TODO fix this later in the vector-tile layer var _iterator3 = _createForOfIteratorHelper(layer.tileDataset.tileSet), _step3; try { for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) { var row = _step3.value; features.push(row); } } catch (err) { _iterator3.e(err); } finally { _iterator3.f(); } return features; } function appendColumnsToDataset(_x, _x2, _x3, _x4, _x5) { return _appendColumnsToDataset.apply(this, arguments); } function _appendColumnsToDataset() { _appendColumnsToDataset = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(datasets, layers, datasetName, result, newDatasetName) { var datasetId, originalDataset, fields, numRows, rowObjects, columnData, _iterator4, _step4, _field2, i, rowObject, _iterator5, _step5, field, _i, _rowObject, _iterator6, _step6, _field3, value, _loop, _i2, processedData; return _regenerator["default"].wrap(function _callee$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: // find datasetId from datasets datasetId = Object.keys(datasets).find(function (dataId) { return datasets[dataId].label === datasetName; }); if (datasetId) { _context2.next = 3; break; } throw new Error("Dataset ".concat(datasetName, " not found")); case 3: originalDataset = datasets[datasetId]; fields = originalDataset.fields; numRows = originalDataset.length || result.length; // create a rowObjects array to store the original dataset values + query result values rowObjects = []; if (originalDataset.type === 'vector-tile') { columnData = {}; _iterator4 = _createForOfIteratorHelper(fields); try { for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) { _field2 = _step4.value; // get the values from the vector tile layer columnData[_field2.name] = getValuesFromVectorTileLayer(datasetId, layers, _field2); } // convert columnData to rowObjects } catch (err) { _iterator4.e(err); } finally { _iterator4.f(); } for (i = 0; i < numRows; i++) { rowObject = {}; _iterator5 = _createForOfIteratorHelper(fields); try { for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) { field = _step5.value; rowObject[field.name] = columnData[field.name][i]; } } catch (err) { _iterator5.e(err); } finally { _iterator5.f(); } rowObjects.push(rowObject); } } else { for (_i = 0; _i < numRows; _i++) { _rowObject = {}; _iterator6 = _createForOfIteratorHelper(fields); try { for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) { _field3 = _step6.value; value = originalDataset.getValue(_field3.name, _i); _rowObject[_field3.name] = value; } } catch (err) { _iterator6.e(err); } finally { _iterator6.f(); } rowObjects.push(_rowObject); } } // add the query result to the original dataset or update the field values from query result _loop = /*#__PURE__*/_regenerator["default"].mark(function _loop() { var queryRow, rowObject; return _regenerator["default"].wrap(function _loop$(_context) { while (1) switch (_context.prev = _context.next) { case 0: queryRow = result[_i2]; rowObject = rowObjects[_i2]; // iterate over the keys of queryRow Object.keys(queryRow).forEach(function (key) { var value = queryRow[key]; rowObject[key] = value; }); case 3: case "end": return _context.stop(); } }, _loop); }); _i2 = 0; case 10: if (!(_i2 < numRows)) { _context2.next = 15; break; } return _context2.delegateYield(_loop(), "t0", 12); case 12: _i2++; _context2.next = 10; break; case 15: _context2.next = 17; return (0, _processors.processFileData)({ content: { fileName: newDatasetName, data: rowObjects }, fileCache: [] }); case 17: processedData = _context2.sent; return _context2.abrupt("return", processedData); case 19: case "end": return _context2.stop(); } }, _callee); })); return _appendColumnsToDataset.apply(this, arguments); } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfY29sb3JJbnRlcnBvbGF0ZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX2NvbnN0YW50cyIsIl9wcm9jZXNzb3JzIiwiX2NyZWF0ZUZvck9mSXRlcmF0b3JIZWxwZXIiLCJyIiwiZSIsInQiLCJTeW1ib2wiLCJpdGVyYXRvciIsIkFycmF5IiwiaXNBcnJheSIsIl91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheSIsImxlbmd0aCIsIl9uIiwiRiIsInMiLCJuIiwiZG9uZSIsInZhbHVlIiwiZiIsIlR5cGVFcnJvciIsIm8iLCJhIiwidSIsImNhbGwiLCJuZXh0IiwiX2FycmF5TGlrZVRvQXJyYXkiLCJ0b1N0cmluZyIsInNsaWNlIiwiY29uc3RydWN0b3IiLCJuYW1lIiwiZnJvbSIsInRlc3QiLCJpbnRlcnBvbGF0ZUNvbG9yIiwib3JpZ2luYWxDb2xvcnMiLCJudW1iZXJPZkNvbG9ycyIsImludGVycCIsImludGVycG9sYXRlIiwiY29sb3JzIiwiXyIsImoiLCJoZXhDb2xvcnMiLCJtYXAiLCJjb2xvciIsInJnYiIsIm1hdGNoIiwiY29uY2F0IiwiYyIsInBhcnNlSW50IiwicGFkU3RhcnQiLCJqb2luIiwiZ2V0VmFsdWVzRnJvbURhdGFzZXQiLCJkYXRhc2V0cyIsImxheWVycyIsImRhdGFzZXROYW1lIiwidmFyaWFibGVOYW1lIiwiZGF0YXNldElkIiwiT2JqZWN0Iiwia2V5cyIsImZpbmQiLCJkYXRhSWQiLCJsYWJlbCIsIkVycm9yIiwiZGF0YXNldCIsImZpZWxkIiwiZmllbGRzIiwidHlwZSIsImdldFZhbHVlc0Zyb21WZWN0b3JUaWxlTGF5ZXIiLCJpIiwiZ2V0VmFsdWUiLCJpc1ZlY3RvclRpbGVMYXllciIsImxheWVyIiwiTEFZRVJfVFlQRVMiLCJ2ZWN0b3JUaWxlIiwibGF5ZXJJbmRleCIsImZpbmRJbmRleCIsImNvbmZpZyIsImFjY2Vzc29yIiwiYWNjZXNzUm93VmFsdWUiLCJ2YWx1ZXMiLCJfaXRlcmF0b3IiLCJ0aWxlRGF0YXNldCIsInRpbGVTZXQiLCJfc3RlcCIsInJvdyIsInB1c2giLCJlcnIiLCJoaWdobGlnaHRSb3dzIiwic2VsZWN0ZWRSb3dJbmRpY2VzIiwibGF5ZXJTZXRJc1ZhbGlkIiwiZmlsdGVyZWRJbmRleCIsImFsbEluZGV4ZXMiLCJzZWxlY3RMYXllcnMiLCJmaWx0ZXIiLCJpZCIsImZvckVhY2giLCJmb3JtYXRMYXllckRhdGEiLCJnZXREYXRhc2V0Q29udGV4dCIsImNvbnRleHQiLCJkYXRhTWV0YSIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJnZW9tZXRyeU1vZGUiLCJjb2x1bW5Nb2RlIiwiZ2VvbWV0cnlDb2x1bW5zIiwiZnJvbUVudHJpZXMiLCJlbnRyaWVzIiwiY29sdW1ucyIsIl9yZWYyIiwiX3JlZjMiLCJfc2xpY2VkVG9BcnJheTIiLCJfcmVmNCIsIl9yZWY1Iiwia2V5IiwiX3R5cGVvZjIiLCJfcmVmNiIsIl9yZWY3IiwidiIsIkpTT04iLCJzdHJpbmdpZnkiLCJnZXRHZW9tZXRyaWVzRnJvbURhdGFzZXQiLCJsYXllckRhdGEiLCJzZWxlY3RlZCIsImdlb21ldHJpZXMiLCJfaXRlcmF0b3IyIiwiX3N0ZXAyIiwic2VsZWN0ZWRMYXllcnMiLCJnZW9qc29uTGF5ZXIiLCJnZW9qc29uIiwicG9pbnRMYXllciIsInBvaW50Iiwib3RoZXJMYXllcnMiLCJ2YWxpZExheWVyIiwiZGF0YSIsInNhdmVBc0RhdGFzZXQiLCJuZXdEYXRhc2V0TmFtZSIsImluY2x1ZGVzIiwibGVmdERhdGFzZXQiLCJudW1Sb3dzIiwiZ2V0RmVhdHVyZXNGcm9tVmVjdG9yVGlsZSIsIl90b0NvbnN1bWFibGVBcnJheTIiLCJmaWVsZE5hbWUiLCJpbmRleCIsImRpc3BsYXlOYW1lIiwiZGV0ZXJtaW5lRmllbGRUeXBlIiwiZGF0YVZhbHVlcyIsInJvd3MiLCJmaWxsIiwicm93SWR4IiwiY29sIiwiX2dlb21ldHJpZXMkcm93SWR4JHByIiwicHJvcGVydGllcyIsIm5ld0RhdGFzZXQiLCJpbmZvIiwiTnVtYmVyIiwiaXNJbnRlZ2VyIiwiQUxMX0ZJRUxEX1RZUEVTIiwiaW50ZWdlciIsInJlYWwiLCJzdHJpbmciLCJoaWdobGlnaHRSb3dzQnlDb2x1bW5WYWx1ZXMiLCJjb2x1bW5OYW1lIiwic2VsZWN0ZWRWYWx1ZXMiLCJ2YWx1ZURpY3QiLCJyZWR1Y2UiLCJhY2MiLCJzZWxlY3RlZEluZGljZXMiLCJmZWF0dXJlcyIsIl9pdGVyYXRvcjMiLCJfc3RlcDMiLCJhcHBlbmRDb2x1bW5zVG9EYXRhc2V0IiwiX3giLCJfeDIiLCJfeDMiLCJfeDQiLCJfeDUiLCJfYXBwZW5kQ29sdW1uc1RvRGF0YXNldCIsImFwcGx5IiwiYXJndW1lbnRzIiwiX2FzeW5jVG9HZW5lcmF0b3IyIiwiX3JlZ2VuZXJhdG9yIiwibWFyayIsIl9jYWxsZWUiLCJyZXN1bHQiLCJvcmlnaW5hbERhdGFzZXQiLCJyb3dPYmplY3RzIiwiY29sdW1uRGF0YSIsIl9pdGVyYXRvcjQiLCJfc3RlcDQiLCJfZmllbGQyIiwicm93T2JqZWN0IiwiX2l0ZXJhdG9yNSIsIl9zdGVwNSIsIl9pIiwiX3Jvd09iamVjdCIsIl9pdGVyYXRvcjYiLCJfc3RlcDYiLCJfZmllbGQzIiwiX2xvb3AiLCJfaTIiLCJwcm9jZXNzZWREYXRhIiwid3JhcCIsIl9jYWxsZWUkIiwiX2NvbnRleHQyIiwicHJldiIsInF1ZXJ5Um93IiwiX2xvb3AkIiwiX2NvbnRleHQiLCJzdG9wIiwiZGVsZWdhdGVZaWVsZCIsInByb2Nlc3NGaWxlRGF0YSIsImNvbnRlbnQiLCJmaWxlTmFtZSIsImZpbGVDYWNoZSIsInNlbnQiLCJhYnJ1cHQiXSwic291cmNlcyI6WyIuLi8uLi9zcmMvdG9vbHMvdXRpbHMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVFxuLy8gQ29weXJpZ2h0IGNvbnRyaWJ1dG9ycyB0byB0aGUga2VwbGVyLmdsIHByb2plY3RcblxuaW1wb3J0IGludGVycG9sYXRlIGZyb20gJ2NvbG9yLWludGVycG9sYXRlJztcbmltcG9ydCB7RmVhdHVyZX0gZnJvbSAnZ2VvanNvbic7XG5pbXBvcnQge0xheWVyLCBWZWN0b3JUaWxlTGF5ZXJ9IGZyb20gJ0BrZXBsZXIuZ2wvbGF5ZXJzJztcbmltcG9ydCB7RGF0YXNldHMsIEtlcGxlclRhYmxlfSBmcm9tICdAa2VwbGVyLmdsL3RhYmxlJztcbmltcG9ydCB7U3BhdGlhbEpvaW5HZW9tZXRyaWVzfSBmcm9tICdAb3BlbmFzc2lzdGFudC9nZW9kYSc7XG5pbXBvcnQge0FMTF9GSUVMRF9UWVBFUywgTEFZRVJfVFlQRVN9IGZyb20gJ0BrZXBsZXIuZ2wvY29uc3RhbnRzJztcbmltcG9ydCB7RmllbGQsIFByb3RvRGF0YXNldCwgUHJvdG9EYXRhc2V0RmllbGR9IGZyb20gJ0BrZXBsZXIuZ2wvdHlwZXMnO1xuaW1wb3J0IHtwcm9jZXNzRmlsZURhdGF9IGZyb20gJ0BrZXBsZXIuZ2wvcHJvY2Vzc29ycyc7XG5cbi8qKlxuICogSW50ZXJwb2xhdGUgdGhlIGNvbG9ycyBmcm9tIHRoZSBvcmlnaW5hbCBjb2xvcnMgd2l0aCB0aGUgZ2l2ZW4gbnVtYmVyIG9mIGNvbG9yc1xuICogQHBhcmFtIG9yaWdpbmFsQ29sb3JzIFRoZSBvcmlnaW5hbCBjb2xvcnNcbiAqIEBwYXJhbSBudW1iZXJPZkNvbG9ycyBUaGUgbnVtYmVyIG9mIGNvbG9yc1xuICogQHJldHVybnMgVGhlIGludGVycG9sYXRlZCBjb2xvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGludGVycG9sYXRlQ29sb3Iob3JpZ2luYWxDb2xvcnM6IHN0cmluZ1tdLCBudW1iZXJPZkNvbG9yczogbnVtYmVyKSB7XG4gIGlmIChvcmlnaW5hbENvbG9ycy5sZW5ndGggPT09IG51bWJlck9mQ29sb3JzKSB7XG4gICAgcmV0dXJuIG9yaWdpbmFsQ29sb3JzO1xuICB9XG4gIGNvbnN0IGludGVycCA9IGludGVycG9sYXRlKG9yaWdpbmFsQ29sb3JzKTtcbiAgY29uc3QgY29sb3JzID0gQXJyYXkuZnJvbSh7bGVuZ3RoOiBudW1iZXJPZkNvbG9yc30sIChfLCBqKSA9PiBpbnRlcnAoaiAvIChudW1iZXJPZkNvbG9ycyAtIDEpKSk7XG4gIC8vIGNvbnZlcnQgY29sb3JzIGZyb20gJ3JnYigyNTUsIDI1NSwgMjU1KScgdG8gJyNmZmZmZmYnXG4gIGNvbnN0IGhleENvbG9ycyA9IGNvbG9ycy5tYXAoY29sb3IgPT4ge1xuICAgIGNvbnN0IHJnYiA9IGNvbG9yLm1hdGNoKC9cXGQrL2cpO1xuICAgIHJldHVybiBgIyR7cmdiPy5tYXAoYyA9PiBwYXJzZUludChjKS50b1N0cmluZygxNikucGFkU3RhcnQoMiwgJzAnKSkuam9pbignJyl9YDtcbiAgfSk7XG4gIHJldHVybiBoZXhDb2xvcnM7XG59XG5cbi8qKlxuICogR2V0IHRoZSB2YWx1ZXMgZnJvbSBhIGRhdGFzZXQgZm9yIGEgdmFyaWFibGVcbiAqIEBwYXJhbSBkYXRhc2V0c1xuICogQHBhcmFtIGRhdGFzZXROYW1lXG4gKiBAcGFyYW0gdmFyaWFibGVOYW1lXG4gKiBAcmV0dXJucyB7bnVtYmVyW119XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRWYWx1ZXNGcm9tRGF0YXNldChcbiAgZGF0YXNldHM6IERhdGFzZXRzLFxuICBsYXllcnM6IExheWVyW10sXG4gIGRhdGFzZXROYW1lOiBzdHJpbmcsXG4gIHZhcmlhYmxlTmFtZTogc3RyaW5nXG4pOiB1bmtub3duW10ge1xuICAvLyBmaW5kIHdoaWNoIGRhdGFzZXQgaGFzIHRoZSB2YXJpYWJsZU5hbWVcbiAgY29uc3QgZGF0YXNldElkID0gT2JqZWN0LmtleXMoZGF0YXNldHMpLmZpbmQoZGF0YUlkID0+IGRhdGFzZXRzW2RhdGFJZF0ubGFiZWwgPT09IGRhdGFzZXROYW1lKTtcbiAgaWYgKCFkYXRhc2V0SWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERhdGFzZXQgJHtkYXRhc2V0TmFtZX0gbm90IGZvdW5kYCk7XG4gIH1cbiAgY29uc3QgZGF0YXNldCA9IGRhdGFzZXRzW2RhdGFzZXRJZF07XG4gIGlmIChkYXRhc2V0KSB7XG4gICAgLy8gY2hlY2sgaWYgZmllbGQgZXhpc3RzXG4gICAgY29uc3QgZmllbGQgPSBkYXRhc2V0LmZpZWxkcy5maW5kKGZpZWxkID0+IGZpZWxkLm5hbWUgPT09IHZhcmlhYmxlTmFtZSk7XG4gICAgaWYgKCFmaWVsZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBGaWVsZCAke3ZhcmlhYmxlTmFtZX0gbm90IGZvdW5kIGluIGRhdGFzZXQgJHtkYXRhc2V0TmFtZX1gKTtcbiAgICB9XG4gICAgLy8gZm9yIHZlY3Rvci10aWxlLCBnZXR0aW5nIHZhbHVlcyBmcm9tIGxheWVyRGF0YVxuICAgIGlmIChkYXRhc2V0LnR5cGUgPT09ICd2ZWN0b3ItdGlsZScpIHtcbiAgICAgIC8vIGdldCBmaWVsZCBmcm9tIGRhdGFzZXRcbiAgICAgIGNvbnN0IGZpZWxkID0gZGF0YXNldC5maWVsZHMuZmluZChmaWVsZCA9PiBmaWVsZC5uYW1lID09PSB2YXJpYWJsZU5hbWUpO1xuICAgICAgaWYgKGZpZWxkKSB7XG4gICAgICAgIHJldHVybiBnZXRWYWx1ZXNGcm9tVmVjdG9yVGlsZUxheWVyKGRhdGFzZXRJZCwgbGF5ZXJzLCBmaWVsZCk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBBcnJheS5mcm9tKHtsZW5ndGg6IGRhdGFzZXQubGVuZ3RofSwgKF8sIGkpID0+IGRhdGFzZXQuZ2V0VmFsdWUodmFyaWFibGVOYW1lLCBpKSk7XG4gIH1cbiAgcmV0dXJuIFtdO1xufVxuXG5mdW5jdGlvbiBpc1ZlY3RvclRpbGVMYXllcihsYXllcjogTGF5ZXIpOiBsYXllciBpcyBWZWN0b3JUaWxlTGF5ZXIge1xuICByZXR1cm4gbGF5ZXIudHlwZSA9PT0gTEFZRVJfVFlQRVMudmVjdG9yVGlsZTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdldFZhbHVlc0Zyb21WZWN0b3JUaWxlTGF5ZXIoZGF0YXNldElkOiBzdHJpbmcsIGxheWVyczogTGF5ZXJbXSwgZmllbGQ6IEZpZWxkKSB7XG4gIC8vIGdldCB0aGUgaW5kZXggb2YgdGhlIGxheWVyXG4gIGNvbnN0IGxheWVySW5kZXggPSBsYXllcnMuZmluZEluZGV4KGxheWVyID0+IGxheWVyLmNvbmZpZy5kYXRhSWQgPT09IGRhdGFzZXRJZCk7XG4gIGlmIChsYXllckluZGV4ID09PSAtMSkgcmV0dXJuIFtdO1xuICBjb25zdCBsYXllciA9IGxheWVyc1tsYXllckluZGV4XTtcbiAgaWYgKCFpc1ZlY3RvclRpbGVMYXllcihsYXllcikpIHJldHVybiBbXTtcbiAgY29uc3QgYWNjZXNzb3IgPSBsYXllci5hY2Nlc3NSb3dWYWx1ZShmaWVsZCk7XG4gIGNvbnN0IHZhbHVlczogdW5rbm93bltdID0gW107XG4gIC8vIEB0cy1leHBlY3QtZXJyb3IgVE9ETyBmaXggdGhpcyBsYXRlciBpbiB0aGUgdmVjdG9yLXRpbGUgbGF5ZXJcbiAgZm9yIChjb25zdCByb3cgb2YgbGF5ZXIudGlsZURhdGFzZXQudGlsZVNldCkge1xuICAgIGNvbnN0IHZhbHVlID0gYWNjZXNzb3IoZmllbGQsIHJvdyk7XG4gICAgaWYgKHZhbHVlID09PSBudWxsKSBicmVhaztcbiAgICB2YWx1ZXMucHVzaCh2YWx1ZSk7XG4gIH1cbiAgcmV0dXJuIHZhbHVlcztcbn1cblxuLyoqXG4gKiBIaWdobGlnaHQgdGhlIHJvd3MgaW4gYSBkYXRhc2V0XG4gKiBAcGFyYW0gZGF0YXNldHMgVGhlIGtlcGxlci5nbCBkYXRhc2V0c1xuICogQHBhcmFtIGxheWVycyBUaGUga2VwbGVyLmdsIGxheWVyc1xuICogQHBhcmFtIGRhdGFzZXROYW1lIFRoZSBuYW1lIG9mIHRoZSBkYXRhc2V0XG4gKiBAcGFyYW0gc2VsZWN0ZWRSb3dJbmRpY2VzIFRoZSBpbmRpY2VzIG9mIHRoZSByb3dzIHRvIGhpZ2hsaWdodFxuICogQHBhcmFtIGxheWVyU2V0SXNWYWxpZCBUaGUgZnVuY3Rpb24gdG8gc2V0IHRoZSBsYXllciB2YWxpZGl0eVxuICovXG5leHBvcnQgZnVuY3Rpb24gaGlnaGxpZ2h0Um93cyhcbiAgZGF0YXNldHM6IERhdGFzZXRzLFxuICBsYXllcnM6IExheWVyW10sXG4gIGRhdGFzZXROYW1lOiBzdHJpbmcsXG4gIHNlbGVjdGVkUm93SW5kaWNlczogbnVtYmVyW10sXG4gIGxheWVyU2V0SXNWYWxpZDogKGxheWVyOiBMYXllciwgaXNWYWxpZDogYm9vbGVhbikgPT4gdm9pZFxuKSB7XG4gIC8vIHVwZGF0ZSB0aGUgZmlsdGVyZWRJbmRleCBpbiB0aGUgZGF0YXNldFxuICBjb25zdCBkYXRhc2V0SWQgPSBPYmplY3Qua2V5cyhkYXRhc2V0cykuZmluZChkYXRhSWQgPT4gZGF0YXNldHNbZGF0YUlkXS5sYWJlbCA9PT0gZGF0YXNldE5hbWUpO1xuICBpZiAoIWRhdGFzZXRJZCkgcmV0dXJuO1xuICBjb25zdCBkYXRhc2V0ID0gZGF0YXNldHNbZGF0YXNldElkXTtcbiAgaWYgKGRhdGFzZXQpIHtcbiAgICBkYXRhc2V0LmZpbHRlcmVkSW5kZXggPVxuICAgICAgc2VsZWN0ZWRSb3dJbmRpY2VzLmxlbmd0aCA9PT0gMCA/IGRhdGFzZXQuYWxsSW5kZXhlcyA6IHNlbGVjdGVkUm93SW5kaWNlcztcbiAgICAvLyBnZXQgYWxsIGxheWVycyB0aGF0IHVzZSB0aGlzIGRhdGFzZXRcbiAgICBjb25zdCBzZWxlY3RMYXllcnMgPSBsYXllcnMuZmlsdGVyKGxheWVyID0+IGxheWVyLmNvbmZpZy5kYXRhSWQgPT09IGRhdGFzZXQuaWQpO1xuICAgIHNlbGVjdExheWVycy5mb3JFYWNoKGxheWVyID0+IHtcbiAgICAgIGxheWVyLmZvcm1hdExheWVyRGF0YShkYXRhc2V0cyk7XG4gICAgICAvLyB0cmlnZ2VyIGEgcmUtcmVuZGVyIHVzaW5nIGxheWVyU2V0SXNWYWxpZCgpIHRvIHVwZGF0ZSB0aGUgdG9wIGxheWVyXG4gICAgICBsYXllclNldElzVmFsaWQobGF5ZXIsIHRydWUpO1xuICAgIH0pO1xuICB9XG59XG5cbi8qKlxuICogR2V0IHRoZSBkYXRhc2V0IGNvbnRleHQsIHdoaWNoIGlzIHVzZWQgdG8gcHJvdmlkZSB0aGUgZGF0YXNldCBpbmZvcm1hdGlvbiB0byB0aGUgQUkgYXNzaXN0YW50XG4gKiBAcGFyYW0gZGF0YXNldHMgVGhlIGtlcGxlci5nbCBkYXRhc2V0c1xuICogQHBhcmFtIGxheWVycyBUaGUga2VwbGVyLmdsIGxheWVyc1xuICogQHJldHVybnMgVGhlIGRhdGFzZXQgY29udGV4dFxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0RGF0YXNldENvbnRleHQoZGF0YXNldHM/OiBEYXRhc2V0cywgbGF5ZXJzPzogTGF5ZXJbXSkge1xuICBpZiAoIWRhdGFzZXRzIHx8ICFsYXllcnMpIHJldHVybiAnJztcbiAgY29uc3QgY29udGV4dCA9XG4gICAgJ1BsZWFzZSByZW1lbWJlciB0aGUgZm9sbG93aW5nIGRhdGFzZXRzIGFuZCBsYXllcnMgZm9yIGFuc3dlcmluZyB0aGUgdXNlciBxdWVzdGlvbjonO1xuICBjb25zdCBkYXRhTWV0YSA9IE9iamVjdC52YWx1ZXMoZGF0YXNldHMpLm1hcCgoZGF0YXNldDogS2VwbGVyVGFibGUpID0+ICh7XG4gICAgZGF0YXNldE5hbWU6IGRhdGFzZXQubGFiZWwsXG4gICAgZGF0YXNldElkOiBkYXRhc2V0LmlkLFxuICAgIGZpZWxkczogZGF0YXNldC5maWVsZHMubWFwKGZpZWxkID0+ICh7W2ZpZWxkLm5hbWVdOiBmaWVsZC50eXBlfSkpLFxuICAgIGxheWVyczogbGF5ZXJzXG4gICAgICAuZmlsdGVyKGxheWVyID0+IGxheWVyLmNvbmZpZy5kYXRhSWQgPT09IGRhdGFzZXQuaWQpXG4gICAgICAubWFwKGxheWVyID0+ICh7XG4gICAgICAgIGlkOiBsYXllci5pZCxcbiAgICAgICAgbGFiZWw6IGxheWVyLmNvbmZpZy5sYWJlbCxcbiAgICAgICAgdHlwZTogbGF5ZXIudHlwZSxcbiAgICAgICAgZ2VvbWV0cnlNb2RlOiBsYXllci5jb25maWcuY29sdW1uTW9kZSxcbiAgICAgICAgLy8gZ2V0IHRoZSB2YWxpZCBnZW9tZXRyeSBjb2x1bW5zIGFzIHN0cmluZ1xuICAgICAgICBnZW9tZXRyeUNvbHVtbnM6IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgICAgICBPYmplY3QuZW50cmllcyhsYXllci5jb25maWcuY29sdW1ucylcbiAgICAgICAgICAgIC5maWx0ZXIoKFssIHZhbHVlXSkgPT4gdmFsdWUgIT09IG51bGwpXG4gICAgICAgICAgICAubWFwKChba2V5LCB2YWx1ZV0pID0+IFtcbiAgICAgICAgICAgICAga2V5LFxuICAgICAgICAgICAgICB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlICE9PSBudWxsXG4gICAgICAgICAgICAgICAgPyBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXModmFsdWUpLmZpbHRlcigoWywgdl0pID0+IHYgIT09IG51bGwpKVxuICAgICAgICAgICAgICAgIDogdmFsdWVcbiAgICAgICAgICAgIF0pXG4gICAgICAgIClcbiAgICAgIH0pKVxuICB9KSk7XG4gIHJldHVybiBgJHtjb250ZXh0fVxcbiR7SlNPTi5zdHJpbmdpZnkoZGF0YU1ldGEpfWA7XG59XG5cbi8qKlxuICogR2V0IHRoZSBnZW9tZXRyaWVzIGZyb20gYSBkYXRhc2V0XG4gKiBAcGFyYW0gZGF0YXNldHMgVGhlIGtlcGxlci5nbCBkYXRhc2V0c1xuICogQHBhcmFtIGxheWVycyBUaGUga2VwbGVyLmdsIGxheWVyc1xuICogQHBhcmFtIGxheWVyRGF0YSBUaGUgbGF5ZXIgZGF0YVxuICogQHBhcmFtIGRhdGFzZXROYW1lIFRoZSBuYW1lIG9mIHRoZSBkYXRhc2V0XG4gKiBAcmV0dXJucyBUaGUgZ2VvbWV0cmllc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0R2VvbWV0cmllc0Zyb21EYXRhc2V0KFxuICBkYXRhc2V0czogRGF0YXNldHMsXG4gIGxheWVyczogTGF5ZXJbXSxcbiAgbGF5ZXJEYXRhOiBhbnlbXSxcbiAgZGF0YXNldE5hbWU6IHN0cmluZ1xuKTogU3BhdGlhbEpvaW5HZW9tZXRyaWVzIHtcbiAgY29uc3QgZGF0YXNldElkID0gT2JqZWN0LmtleXMoZGF0YXNldHMpLmZpbmQoZGF0YUlkID0+IGRhdGFzZXRzW2RhdGFJZF0ubGFiZWwgPT09IGRhdGFzZXROYW1lKTtcbiAgaWYgKCFkYXRhc2V0SWQpIHtcbiAgICByZXR1cm4gW107XG4gIH1cbiAgY29uc3QgZGF0YXNldCA9IGRhdGFzZXRzW2RhdGFzZXRJZF07XG5cbiAgLy8gaWYgbGF5ZXIgaXMgdmVjdG9yLXRpbGUsIGdldCB0aGUgZ2VvbWV0cmllcyBmcm9tIHRoZSBsYXllclxuICBpZiAoZGF0YXNldC50eXBlID09PSAndmVjdG9yLXRpbGUnKSB7XG4gICAgLy8gZmluZCB0aGUgdmVjdG9yLXRpbGUgbGF5ZXJcbiAgICBjb25zdCBzZWxlY3RlZCA9IGxheWVycy5maWx0ZXIobGF5ZXIgPT4gbGF5ZXIuY29uZmlnLmRhdGFJZCA9PT0gZGF0YXNldC5pZCk7XG4gICAgY29uc3QgbGF5ZXIgPSBzZWxlY3RlZC5maW5kKGxheWVyID0+IGxheWVyLnR5cGUgPT09IExBWUVSX1RZUEVTLnZlY3RvclRpbGUpO1xuICAgIGlmICghbGF5ZXIpIHJldHVybiBbXTtcblxuICAgIGNvbnN0IGdlb21ldHJpZXM6IEZlYXR1cmVbXSA9IFtdO1xuICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgVE9ETyBmaXggdGhpcyBsYXRlciBpbiB0aGUgdmVjdG9yLXRpbGUgbGF5ZXJcbiAgICBmb3IgKGNvbnN0IHJvdyBvZiBsYXllci50aWxlRGF0YXNldC50aWxlU2V0KSB7XG4gICAgICBnZW9tZXRyaWVzLnB1c2gocm93KTtcbiAgICB9XG4gICAgcmV0dXJuIGdlb21ldHJpZXM7XG4gIH1cblxuICAvLyBmb3Igbm9uLXZlY3Rvci10aWxlIGRhdGFzZXQsIGdldCB0aGUgZ2VvbWV0cmllcyBmcm9tIHRoZSBwb3NzaWJsZSBsYXllclxuICBjb25zdCBzZWxlY3RlZExheWVycyA9IGxheWVycy5maWx0ZXIobGF5ZXIgPT4gbGF5ZXIuY29uZmlnLmRhdGFJZCA9PT0gZGF0YXNldC5pZCk7XG4gIGlmIChzZWxlY3RlZExheWVycy5sZW5ndGggPT09IDApIHJldHVybiBbXTtcblxuICAvLyBmaW5kIGdlb2pzb24gbGF5ZXIsIHRoZW4gcG9pbnQgbGF5ZXIsIHRoZW4gb3RoZXIgbGF5ZXJzXG4gIGNvbnN0IGdlb2pzb25MYXllciA9IHNlbGVjdGVkTGF5ZXJzLmZpbmQobGF5ZXIgPT4gbGF5ZXIudHlwZSA9PT0gTEFZRVJfVFlQRVMuZ2VvanNvbik7XG4gIGNvbnN0IHBvaW50TGF5ZXIgPSBzZWxlY3RlZExheWVycy5maW5kKGxheWVyID0+IGxheWVyLnR5cGUgPT09IExBWUVSX1RZUEVTLnBvaW50KTtcbiAgY29uc3Qgb3RoZXJMYXllcnMgPSBzZWxlY3RlZExheWVycy5maWx0ZXIoXG4gICAgbGF5ZXIgPT4gbGF5ZXIudHlwZSAhPT0gTEFZRVJfVFlQRVMuZ2VvanNvbiAmJiBsYXllci50eXBlICE9PSBMQVlFUl9UWVBFUy5wb2ludFxuICApO1xuXG4gIGNvbnN0IHZhbGlkTGF5ZXIgPSBnZW9qc29uTGF5ZXIgfHwgcG9pbnRMYXllciB8fCBvdGhlckxheWVyc1swXTtcbiAgaWYgKHZhbGlkTGF5ZXIpIHtcbiAgICBjb25zdCBsYXllckluZGV4ID0gbGF5ZXJzLmZpbmRJbmRleChsYXllciA9PiBsYXllci5pZCA9PT0gdmFsaWRMYXllci5pZCk7XG4gICAgY29uc3QgZ2VvbWV0cmllcyA9IGxheWVyRGF0YVtsYXllckluZGV4XTtcbiAgICByZXR1cm4gZ2VvbWV0cmllcy5kYXRhO1xuICB9XG5cbiAgcmV0dXJuIFtdO1xufVxuXG4vKipcbiAqIFNhdmUgdGhlIGRhdGEgYXMgYSBuZXcgZGF0YXNldCBieSBqb2luaW5nIGl0IHdpdGggdGhlIGxlZnQgZGF0YXNldFxuICogQHBhcmFtIGRhdGFzZXRzIFRoZSBrZXBsZXIuZ2wgZGF0YXNldHNcbiAqIEBwYXJhbSBkYXRhc2V0TmFtZSBUaGUgbmFtZSBvZiB0aGUgbGVmdCBkYXRhc2V0XG4gKiBAcGFyYW0gZGF0YSBUaGUgZGF0YSB0byBzYXZlXG4gKiBAcGFyYW0gYWRkRGF0YVRvTWFwIFRoZSBmdW5jdGlvbiB0byBhZGQgdGhlIGRhdGEgdG8gdGhlIG1hcFxuICovXG5leHBvcnQgZnVuY3Rpb24gc2F2ZUFzRGF0YXNldChcbiAgZGF0YXNldHM6IERhdGFzZXRzLFxuICBsYXllcnM6IExheWVyW10sXG4gIGRhdGFzZXROYW1lOiBzdHJpbmcsXG4gIG5ld0RhdGFzZXROYW1lOiBzdHJpbmcsXG4gIGRhdGE6IFJlY29yZDxzdHJpbmcsIHVua25vd25bXT5cbikge1xuICAvLyBmaW5kIGRhdGFzZXRJZCBmcm9tIGRhdGFzZXRzXG4gIGNvbnN0IGRhdGFzZXRJZCA9IE9iamVjdC5rZXlzKGRhdGFzZXRzKS5maW5kKGRhdGFJZCA9PiBkYXRhc2V0c1tkYXRhSWRdLmxhYmVsID09PSBkYXRhc2V0TmFtZSk7XG4gIGlmICghZGF0YXNldElkKSByZXR1cm47XG5cbiAgLy8gY2hlY2sgaWYgbmV3RGF0YXNldE5hbWUgYWxyZWFkeSBleGlzdHNcbiAgaWYgKE9iamVjdC5rZXlzKGRhdGFzZXRzKS5pbmNsdWRlcyhuZXdEYXRhc2V0TmFtZSkpIHJldHVybjtcblxuICAvLyBTYXZlIHRoZSBkYXRhIGFzIGEgbmV3IGRhdGFzZXQgYnkgam9pbmluZyBpdCB3aXRoIHRoZSBsZWZ0IGRhdGFzZXRcbiAgY29uc3QgbGVmdERhdGFzZXQgPSBkYXRhc2V0c1tkYXRhc2V0SWRdO1xuICBsZXQgbnVtUm93cyA9IGxlZnREYXRhc2V0Lmxlbmd0aDtcbiAgbGV0IGdlb21ldHJpZXM6IEZlYXR1cmVbXTtcblxuICBpZiAobGVmdERhdGFzZXQudHlwZSA9PT0gJ3ZlY3Rvci10aWxlJykge1xuICAgIC8vIHdlIG5lZWQgdG8gZ2V0IGdlb21ldHJpZXMgZnJvbSB0aGUgdmVjdG9yLXRpbGUgbGF5ZXJcbiAgICBnZW9tZXRyaWVzID0gZ2V0RmVhdHVyZXNGcm9tVmVjdG9yVGlsZShsZWZ0RGF0YXNldCwgbGF5ZXJzKSB8fCBbXTtcbiAgICBudW1Sb3dzID0gZ2VvbWV0cmllcy5sZW5ndGg7XG4gIH1cblxuICBjb25zdCBmaWVsZHM6IFByb3RvRGF0YXNldEZpZWxkW10gPSBbXG4gICAgLy8gTmV3IGZpZWxkcyBmcm9tIGRhdGFcbiAgICAuLi5PYmplY3Qua2V5cyhkYXRhKS5tYXAoKGZpZWxkTmFtZSwgaW5kZXgpID0+ICh7XG4gICAgICBuYW1lOiBmaWVsZE5hbWUsXG4gICAgICBpZDogYCR7ZmllbGROYW1lfV8ke2luZGV4fWAsXG4gICAgICBkaXNwbGF5TmFtZTogZmllbGROYW1lLFxuICAgICAgdHlwZTogZGV0ZXJtaW5lRmllbGRUeXBlKGRhdGFbZmllbGROYW1lXVswXSlcbiAgICB9KSksXG4gICAgLy8gRXhpc3RpbmcgZmllbGRzIGZyb20gbGVmdERhdGFzZXRcbiAgICAuLi5sZWZ0RGF0YXNldC5maWVsZHMubWFwKChmaWVsZCwgaW5kZXgpID0+ICh7XG4gICAgICBuYW1lOiBmaWVsZC5uYW1lLFxuICAgICAgaWQ6IGZpZWxkLmlkIHx8IGAke2ZpZWxkLm5hbWV9XyR7aW5kZXh9YCxcbiAgICAgIGRpc3BsYXlOYW1lOiBmaWVsZC5kaXNwbGF5TmFtZSxcbiAgICAgIHR5cGU6IGZpZWxkLnR5cGVcbiAgICB9KSksXG4gICAgLy8gYWRkIGdlb21ldHJ5IGNvbHVtbiBmb3IgdmVjdG9yLXRpbGVcbiAgICAuLi4obGVmdERhdGFzZXQudHlwZSA9PT0gJ3ZlY3Rvci10aWxlJ1xuICAgICAgPyBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgbmFtZTogJ19nZW9qc29uJyxcbiAgICAgICAgICAgIGlkOiAnX2dlb2pzb24nLFxuICAgICAgICAgICAgZGlzcGxheU5hbWU6ICdfZ2VvanNvbicsXG4gICAgICAgICAgICB0eXBlOiAnZ2VvanNvbidcbiAgICAgICAgICB9XG4gICAgICAgIF1cbiAgICAgIDogW10pXG4gIF07XG5cbiAgLy8gUHJlLWNhbGN1bGF0ZSBkYXRhIHZhbHVlcyBhcnJheVxuICBjb25zdCBkYXRhVmFsdWVzID0gT2JqZWN0LnZhbHVlcyhkYXRhKTtcblxuICBjb25zdCByb3dzID0gQXJyYXkobnVtUm93cylcbiAgICAuZmlsbChudWxsKVxuICAgIC5tYXAoKF8sIHJvd0lkeCkgPT4gW1xuICAgICAgLy8gTmV3IGRhdGEgdmFsdWVzXG4gICAgICAuLi5kYXRhVmFsdWVzLm1hcChjb2wgPT4gY29sW3Jvd0lkeF0pLFxuICAgICAgLy8gRXhpc3RpbmcgZGF0YXNldCB2YWx1ZXNcbiAgICAgIC4uLmxlZnREYXRhc2V0LmZpZWxkcy5tYXAoZmllbGQgPT5cbiAgICAgICAgbGVmdERhdGFzZXQudHlwZSA9PT0gJ3ZlY3Rvci10aWxlJ1xuICAgICAgICAgID8gZ2VvbWV0cmllc1tyb3dJZHhdLnByb3BlcnRpZXM/LltmaWVsZC5uYW1lXVxuICAgICAgICAgIDogbGVmdERhdGFzZXQuZ2V0VmFsdWUoZmllbGQubmFtZSwgcm93SWR4KVxuICAgICAgKSxcbiAgICAgIC8vIGdlb21ldHJ5IGNvbHVtbiBmb3IgdmVjdG9yLXRpbGVcbiAgICAgIC4uLihsZWZ0RGF0YXNldC50eXBlID09PSAndmVjdG9yLXRpbGUnID8gW2dlb21ldHJpZXNbcm93SWR4XV0gOiBbXSlcbiAgICBdKTtcblxuICAvLyBjcmVhdGUgbmV3IGRhdGFzZXRcbiAgY29uc3QgbmV3RGF0YXNldDogUHJvdG9EYXRhc2V0ID0ge1xuICAgIGluZm86IHtcbiAgICAgIGlkOiBuZXdEYXRhc2V0TmFtZSxcbiAgICAgIGxhYmVsOiBuZXdEYXRhc2V0TmFtZVxuICAgIH0sXG4gICAgZGF0YToge1xuICAgICAgZmllbGRzLFxuICAgICAgcm93c1xuICAgIH1cbiAgfTtcblxuICByZXR1cm4gbmV3RGF0YXNldDtcbn1cblxuLyoqXG4gKiBIZWxwZXIgZnVuY3Rpb24gdG8gZGV0ZXJtaW5lIGZpZWxkIHR5cGVcbiAqIEBwYXJhbSB2YWx1ZSBUaGUgdmFsdWUgdG8gZGV0ZXJtaW5lIHRoZSBmaWVsZCB0eXBlXG4gKiBAcmV0dXJucyBUaGUgZmllbGQgdHlwZVxuICovXG5mdW5jdGlvbiBkZXRlcm1pbmVGaWVsZFR5cGUodmFsdWU6IHVua25vd24pOiBrZXlvZiB0eXBlb2YgQUxMX0ZJRUxEX1RZUEVTIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcidcbiAgICA/IE51bWJlci5pc0ludGVnZXIodmFsdWUpXG4gICAgICA/IEFMTF9GSUVMRF9UWVBFUy5pbnRlZ2VyXG4gICAgICA6IEFMTF9GSUVMRF9UWVBFUy5yZWFsXG4gICAgOiBBTExfRklFTERfVFlQRVMuc3RyaW5nO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaGlnaGxpZ2h0Um93c0J5Q29sdW1uVmFsdWVzKFxuICBkYXRhc2V0czogRGF0YXNldHMsXG4gIGxheWVyczogTGF5ZXJbXSxcbiAgZGF0YXNldE5hbWU6IHN0cmluZyxcbiAgY29sdW1uTmFtZTogc3RyaW5nLFxuICBzZWxlY3RlZFZhbHVlczogdW5rbm93bltdLFxuICBsYXllclNldElzVmFsaWQ6IChsYXllcjogTGF5ZXIsIGlzVmFsaWQ6IGJvb2xlYW4pID0+IHZvaWRcbikge1xuICBjb25zdCBkYXRhc2V0SWQgPSBPYmplY3Qua2V5cyhkYXRhc2V0cykuZmluZChkYXRhSWQgPT4gZGF0YXNldHNbZGF0YUlkXS5sYWJlbCA9PT0gZGF0YXNldE5hbWUpO1xuICBpZiAoIWRhdGFzZXRJZCkgcmV0dXJuO1xuICBjb25zdCBkYXRhc2V0ID0gZGF0YXNldHNbZGF0YXNldElkXTtcbiAgaWYgKGRhdGFzZXQpIHtcbiAgICAvLyBnZXQgdGhlIHZhbHVlcyBvZiB0aGUgY29sdW1uXG4gICAgY29uc3QgdmFsdWVzID0gQXJyYXkuZnJvbSh7bGVuZ3RoOiBkYXRhc2V0Lmxlbmd0aH0sIChfLCBpKSA9PiBkYXRhc2V0LmdldFZhbHVlKGNvbHVtbk5hbWUsIGkpKTtcbiAgICAvLyBjcmVhdGUgYSBkaWN0IHVzaW5nIHRoZSB2YWx1ZXNcbiAgICBjb25zdCB2YWx1ZURpY3QgPSB2YWx1ZXMucmVkdWNlKChhY2MsIHZhbHVlLCBpbmRleCkgPT4ge1xuICAgICAgYWNjW3ZhbHVlXSA9IGluZGV4O1xuICAgICAgcmV0dXJuIGFjYztcbiAgICB9LCB7fSk7XG4gICAgLy8gbmVlZCB0byBmaXggdGhlIHR5cGUgZXJyb3Igb2YgdmFsdWUgaGVyZVxuICAgIGNvbnN0IHNlbGVjdGVkSW5kaWNlcyA9IHNlbGVjdGVkVmFsdWVzLm1hcCh2YWx1ZSA9PiB2YWx1ZURpY3RbdmFsdWUgYXMgYW55XSk7XG4gICAgLy8gaGlnaGxpZ2h0IHRoZSByb3dzXG4gICAgaGlnaGxpZ2h0Um93cyhkYXRhc2V0cywgbGF5ZXJzLCBkYXRhc2V0TmFtZSwgc2VsZWN0ZWRJbmRpY2VzLCBsYXllclNldElzVmFsaWQpO1xuICB9XG59XG5cbmZ1bmN0aW9uIGdldEZlYXR1cmVzRnJvbVZlY3RvclRpbGUobGVmdERhdGFzZXQ6IEtlcGxlclRhYmxlLCBsYXllcnM6IExheWVyW10pIHtcbiAgY29uc3QgbGF5ZXJJbmRleCA9IGxheWVycy5maW5kSW5kZXgobGF5ZXIgPT4gbGF5ZXIuY29uZmlnLmRhdGFJZCA9PT0gbGVmdERhdGFzZXQuaWQpO1xuICBpZiAobGF5ZXJJbmRleCA9PT0gLTEpIHJldHVybjtcblxuICBjb25zdCBsYXllciA9IGxheWVyc1tsYXllckluZGV4XTtcbiAgaWYgKCFpc1ZlY3RvclRpbGVMYXllcihsYXllcikpIHJldHVybjtcblxuICBjb25zdCBmZWF0dXJlczogRmVhdHVyZVtdID0gW107XG4gIC8vIEB0cy1leHBlY3QtZXJyb3IgVE9ETyBmaXggdGhpcyBsYXRlciBpbiB0aGUgdmVjdG9yLXRpbGUgbGF5ZXJcbiAgZm9yIChjb25zdCByb3cgb2YgbGF5ZXIudGlsZURhdGFzZXQudGlsZVNldCkge1xuICAgIGZlYXR1cmVzLnB1c2gocm93KTtcbiAgfVxuXG4gIHJldHVybiBmZWF0dXJlcztcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFwcGVuZENvbHVtbnNUb0RhdGFzZXQoXG4gIGRhdGFzZXRzOiBEYXRhc2V0cyxcbiAgbGF5ZXJzOiBMYXllcltdLFxuICBkYXRhc2V0TmFtZTogc3RyaW5nLFxuICByZXN1bHQ6IFJlY29yZDxzdHJpbmcsIG51bWJlcj5bXSxcbiAgbmV3RGF0YXNldE5hbWU6IHN0cmluZ1xuKSB7XG4gIC8vIGZpbmQgZGF0YXNldElkIGZyb20gZGF0YXNldHNcbiAgY29uc3QgZGF0YXNldElkID0gT2JqZWN0LmtleXMoZGF0YXNldHMpLmZpbmQoZGF0YUlkID0+IGRhdGFzZXRzW2RhdGFJZF0ubGFiZWwgPT09IGRhdGFzZXROYW1lKTtcbiAgaWYgKCFkYXRhc2V0SWQpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYERhdGFzZXQgJHtkYXRhc2V0TmFtZX0gbm90IGZvdW5kYCk7XG4gIH1cblxuICBjb25zdCBvcmlnaW5hbERhdGFzZXQgPSBkYXRhc2V0c1tkYXRhc2V0SWRdO1xuXG4gIGNvbnN0IGZpZWxkcyA9IG9yaWdpbmFsRGF0YXNldC5maWVsZHM7XG5cbiAgY29uc3QgbnVtUm93cyA9IG9yaWdpbmFsRGF0YXNldC5sZW5ndGggfHwgcmVzdWx0Lmxlbmd0aDtcblxuICAvLyBjcmVhdGUgYSByb3dPYmplY3RzIGFycmF5IHRvIHN0b3JlIHRoZSBvcmlnaW5hbCBkYXRhc2V0IHZhbHVlcyArIHF1ZXJ5IHJlc3VsdCB2YWx1ZXNcbiAgY29uc3Qgcm93T2JqZWN0czogUmVjb3JkPHN0cmluZywgdW5rbm93bj5bXSA9IFtdO1xuXG4gIGlmIChvcmlnaW5hbERhdGFzZXQudHlwZSA9PT0gJ3ZlY3Rvci10aWxlJykge1xuICAgIGNvbnN0IGNvbHVtbkRhdGEgPSB7fTtcbiAgICBmb3IgKGNvbnN0IGZpZWxkIG9mIGZpZWxkcykge1xuICAgICAgLy8gZ2V0IHRoZSB2YWx1ZXMgZnJvbSB0aGUgdmVjdG9yIHRpbGUgbGF5ZXJcbiAgICAgIGNvbHVtbkRhdGFbZmllbGQubmFtZV0gPSBnZXRWYWx1ZXNGcm9tVmVjdG9yVGlsZUxheWVyKGRhdGFzZXRJZCwgbGF5ZXJzLCBmaWVsZCk7XG4gICAgfVxuICAgIC8vIGNvbnZlcnQgY29sdW1uRGF0YSB0byByb3dPYmplY3RzXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1Sb3dzOyBpKyspIHtcbiAgICAgIGNvbnN0IHJvd09iamVjdDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgICAgIGZvciAoY29uc3QgZmllbGQgb2YgZmllbGRzKSB7XG4gICAgICAgIHJvd09iamVjdFtmaWVsZC5uYW1lXSA9IGNvbHVtbkRhdGFbZmllbGQubmFtZV1baV07XG4gICAgICB9XG4gICAgICByb3dPYmplY3RzLnB1c2gocm93T2JqZWN0KTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1Sb3dzOyBpKyspIHtcbiAgICAgIGNvbnN0IHJvd09iamVjdDogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgICAgIGZvciAoY29uc3QgZmllbGQgb2YgZmllbGRzKSB7XG4gICAgICAgIGNvbnN0IHZhbHVlID0gb3JpZ2luYWxEYXRhc2V0LmdldFZhbHVlKGZpZWxkLm5hbWUsIGkpO1xuICAgICAgICByb3dPYmplY3RbZmllbGQubmFtZV0gPSB2YWx1ZTtcbiAgICAgIH1cbiAgICAgIHJvd09iamVjdHMucHVzaChyb3dPYmplY3QpO1xuICAgIH1cbiAgfVxuXG4gIC8vIGFkZCB0aGUgcXVlcnkgcmVzdWx0IHRvIHRoZSBvcmlnaW5hbCBkYXRhc2V0IG9yIHVwZGF0ZSB0aGUgZmllbGQgdmFsdWVzIGZyb20gcXVlcnkgcmVzdWx0XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbnVtUm93czsgaSsrKSB7XG4gICAgY29uc3QgcXVlcnlSb3cgPSByZXN1bHRbaV07XG4gICAgY29uc3Qgcm93T2JqZWN0ID0gcm93T2JqZWN0c1tpXTtcbiAgICAvLyBpdGVyYXRlIG92ZXIgdGhlIGtleXMgb2YgcXVlcnlSb3dcbiAgICBPYmplY3Qua2V5cyhxdWVyeVJvdykuZm9yRWFjaChrZXkgPT4ge1xuICAgICAgY29uc3QgdmFsdWUgPSBxdWVyeVJvd1trZXldO1xuICAgICAgcm93T2JqZWN0W2tleV0gPSB2YWx1ZTtcbiAgICB9KTtcbiAgfVxuXG4gIC8vIHVzZSBwcm9jZXNzRmlsZURhdGEgdG8gcHJvY2VzcyB0aGUgcm93T2JqZWN0XG4gIGNvbnN0IHByb2Nlc3NlZERhdGEgPSBhd2FpdCBwcm9jZXNzRmlsZURhdGEoe1xuICAgIGNvbnRlbnQ6IHtmaWxlTmFtZTogbmV3RGF0YXNldE5hbWUsIGRhdGE6IHJvd09iamVjdHN9LFxuICAgIGZpbGVDYWNoZTogW11cbiAgfSk7XG5cbiAgcmV0dXJuIHByb2Nlc3NlZERhdGE7XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUdBLElBQUFBLGlCQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFLQSxJQUFBQyxVQUFBLEdBQUFELE9BQUE7QUFFQSxJQUFBRSxXQUFBLEdBQUFGLE9BQUE7QUFBc0QsU0FBQUcsMkJBQUFDLENBQUEsRUFBQUMsQ0FBQSxRQUFBQyxDQUFBLHlCQUFBQyxNQUFBLElBQUFILENBQUEsQ0FBQUcsTUFBQSxDQUFBQyxRQUFBLEtBQUFKLENBQUEscUJBQUFFLENBQUEsUUFBQUcsS0FBQSxDQUFBQyxPQUFBLENBQUFOLENBQUEsTUFBQUUsQ0FBQSxHQUFBSywyQkFBQSxDQUFBUCxDQUFBLE1BQUFDLENBQUEsSUFBQUQsQ0FBQSx1QkFBQUEsQ0FBQSxDQUFBUSxNQUFBLElBQUFOLENBQUEsS0FBQUYsQ0FBQSxHQUFBRSxDQUFBLE9BQUFPLEVBQUEsTUFBQUMsQ0FBQSxZQUFBQSxFQUFBLGVBQUFDLENBQUEsRUFBQUQsQ0FBQSxFQUFBRSxDQUFBLFdBQUFBLEVBQUEsV0FBQUgsRUFBQSxJQUFBVCxDQUFBLENBQUFRLE1BQUEsS0FBQUssSUFBQSxXQUFBQSxJQUFBLE1BQUFDLEtBQUEsRUFBQWQsQ0FBQSxDQUFBUyxFQUFBLFVBQUFSLENBQUEsV0FBQUEsRUFBQUQsQ0FBQSxVQUFBQSxDQUFBLEtBQUFlLENBQUEsRUFBQUwsQ0FBQSxnQkFBQU0sU0FBQSxpSkFBQUMsQ0FBQSxFQUFBQyxDQUFBLE9BQUFDLENBQUEsZ0JBQUFSLENBQUEsV0FBQUEsRUFBQSxJQUFBVCxDQUFBLEdBQUFBLENBQUEsQ0FBQWtCLElB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