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 _src = require("/Users/ihordykhta/Desktop/unfolded/kepler.gl/src/constants/src"); var _src2 = require("/Users/ihordykhta/Desktop/unfolded/kepler.gl/src/processors/src"); 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 === _src.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 === _src.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 === _src.LAYER_TYPES.geojson; }); var pointLayer = selectedLayers.find(function (layer) { return layer.type === _src.LAYER_TYPES.point; }); var otherLayers = selectedLayers.filter(function (layer) { return layer.type !== _src.LAYER_TYPES.geojson && layer.type !== _src.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) ? _src.ALL_FIELD_TYPES.integer : _src.ALL_FIELD_TYPES.real : _src.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, _src2.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,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfY29sb3JJbnRlcnBvbGF0ZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX3NyYyIsIl9zcmMyIiwiX2NyZWF0ZUZvck9mSXRlcmF0b3JIZWxwZXIiLCJyIiwiZSIsInQiLCJTeW1ib2wiLCJpdGVyYXRvciIsIkFycmF5IiwiaXNBcnJheSIsIl91bnN1cHBvcnRlZEl0ZXJhYmxlVG9BcnJheSIsImxlbmd0aCIsIl9uIiwiRiIsInMiLCJuIiwiZG9uZSIsInZhbHVlIiwiZiIsIlR5cGVFcnJvciIsIm8iLCJhIiwidSIsImNhbGwiLCJuZXh0IiwiX2FycmF5TGlrZVRvQXJyYXkiLCJ0b1N0cmluZyIsInNsaWNlIiwiY29uc3RydWN0b3IiLCJuYW1lIiwiZnJvbSIsInRlc3QiLCJpbnRlcnBvbGF0ZUNvbG9yIiwib3JpZ2luYWxDb2xvcnMiLCJudW1iZXJPZkNvbG9ycyIsImludGVycCIsImludGVycG9sYXRlIiwiY29sb3JzIiwiXyIsImoiLCJoZXhDb2xvcnMiLCJtYXAiLCJjb2xvciIsInJnYiIsIm1hdGNoIiwiY29uY2F0IiwiYyIsInBhcnNlSW50IiwicGFkU3RhcnQiLCJqb2luIiwiZ2V0VmFsdWVzRnJvbURhdGFzZXQiLCJkYXRhc2V0cyIsImxheWVycyIsImRhdGFzZXROYW1lIiwidmFyaWFibGVOYW1lIiwiZGF0YXNldElkIiwiT2JqZWN0Iiwia2V5cyIsImZpbmQiLCJkYXRhSWQiLCJsYWJlbCIsIkVycm9yIiwiZGF0YXNldCIsImZpZWxkIiwiZmllbGRzIiwidHlwZSIsImdldFZhbHVlc0Zyb21WZWN0b3JUaWxlTGF5ZXIiLCJpIiwiZ2V0VmFsdWUiLCJpc1ZlY3RvclRpbGVMYXllciIsImxheWVyIiwiTEFZRVJfVFlQRVMiLCJ2ZWN0b3JUaWxlIiwibGF5ZXJJbmRleCIsImZpbmRJbmRleCIsImNvbmZpZyIsImFjY2Vzc29yIiwiYWNjZXNzUm93VmFsdWUiLCJ2YWx1ZXMiLCJfaXRlcmF0b3IiLCJ0aWxlRGF0YXNldCIsInRpbGVTZXQiLCJfc3RlcCIsInJvdyIsInB1c2giLCJlcnIiLCJoaWdobGlnaHRSb3dzIiwic2VsZWN0ZWRSb3dJbmRpY2VzIiwibGF5ZXJTZXRJc1ZhbGlkIiwiZmlsdGVyZWRJbmRleCIsImFsbEluZGV4ZXMiLCJzZWxlY3RMYXllcnMiLCJmaWx0ZXIiLCJpZCIsImZvckVhY2giLCJmb3JtYXRMYXllckRhdGEiLCJnZXREYXRhc2V0Q29udGV4dCIsImNvbnRleHQiLCJkYXRhTWV0YSIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJnZW9tZXRyeU1vZGUiLCJjb2x1bW5Nb2RlIiwiZ2VvbWV0cnlDb2x1bW5zIiwiZnJvbUVudHJpZXMiLCJlbnRyaWVzIiwiY29sdW1ucyIsIl9yZWYyIiwiX3JlZjMiLCJfc2xpY2VkVG9BcnJheTIiLCJfcmVmNCIsIl9yZWY1Iiwia2V5IiwiX3R5cGVvZjIiLCJfcmVmNiIsIl9yZWY3IiwidiIsIkpTT04iLCJzdHJpbmdpZnkiLCJnZXRHZW9tZXRyaWVzRnJvbURhdGFzZXQiLCJsYXllckRhdGEiLCJzZWxlY3RlZCIsImdlb21ldHJpZXMiLCJfaXRlcmF0b3IyIiwiX3N0ZXAyIiwic2VsZWN0ZWRMYXllcnMiLCJnZW9qc29uTGF5ZXIiLCJnZW9qc29uIiwicG9pbnRMYXllciIsInBvaW50Iiwib3RoZXJMYXllcnMiLCJ2YWxpZExheWVyIiwiZGF0YSIsInNhdmVBc0RhdGFzZXQiLCJuZXdEYXRhc2V0TmFtZSIsImluY2x1ZGVzIiwibGVmdERhdGFzZXQiLCJudW1Sb3dzIiwiZ2V0RmVhdHVyZXNGcm9tVmVjdG9yVGlsZSIsIl90b0NvbnN1bWFibGVBcnJheTIiLCJmaWVsZE5hbWUiLCJpbmRleCIsImRpc3BsYXlOYW1lIiwiZGV0ZXJtaW5lRmllbGRUeXBlIiwiZGF0YVZhbHVlcyIsInJvd3MiLCJmaWxsIiwicm93SWR4IiwiY29sIiwiX2dlb21ldHJpZXMkcm93SWR4JHByIiwicHJvcGVydGllcyIsIm5ld0RhdGFzZXQiLCJpbmZvIiwiTnVtYmVyIiwiaXNJbnRlZ2VyIiwiQUxMX0ZJRUxEX1RZUEVTIiwiaW50ZWdlciIsInJlYWwiLCJzdHJpbmciLCJoaWdobGlnaHRSb3dzQnlDb2x1bW5WYWx1ZXMiLCJjb2x1bW5OYW1lIiwic2VsZWN0ZWRWYWx1ZXMiLCJ2YWx1ZURpY3QiLCJyZWR1Y2UiLCJhY2MiLCJzZWxlY3RlZEluZGljZXMiLCJmZWF0dXJlcyIsIl9pdGVyYXRvcjMiLCJfc3RlcDMiLCJhcHBlbmRDb2x1bW5zVG9EYXRhc2V0IiwiX3giLCJfeDIiLCJfeDMiLCJfeDQiLCJfeDUiLCJfYXBwZW5kQ29sdW1uc1RvRGF0YXNldCIsImFwcGx5IiwiYXJndW1lbnRzIiwiX2FzeW5jVG9HZW5lcmF0b3IyIiwiX3JlZ2VuZXJhdG9yIiwibWFyayIsIl9jYWxsZWUiLCJyZXN1bHQiLCJvcmlnaW5hbERhdGFzZXQiLCJyb3dPYmplY3RzIiwiY29sdW1uRGF0YSIsIl9pdGVyYXRvcjQiLCJfc3RlcDQiLCJfZmllbGQyIiwicm93T2JqZWN0IiwiX2l0ZXJhdG9yNSIsIl9zdGVwNSIsIl9pIiwiX3Jvd09iamVjdCIsIl9pdGVyYXRvcjYiLCJfc3RlcDYiLCJfZmllbGQzIiwiX2xvb3AiLCJfaTIiLCJwcm9jZXNzZWREYXRhIiwid3JhcCIsIl9jYWxsZWUkIiwiX2NvbnRleHQyIiwicHJldiIsInF1ZXJ5Um93IiwiX2xvb3AkIiwiX2NvbnRleHQiLCJzdG9wIiwiZGVsZWdhdGVZaWVsZCIsInByb2Nlc3NGaWxlRGF0YSIsImNvbnRlbnQiLCJmaWxlTmFtZSIsImZpbGVDYWNoZSIsInNlbnQiLCJhYnJ1cHQiXSwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYWktYXNzaXN0YW50L3NyYy90b29scy91dGlscy50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4vLyBDb3B5cmlnaHQgY29udHJpYnV0b3JzIHRvIHRoZSBrZXBsZXIuZ2wgcHJvamVjdFxuXG5pbXBvcnQgaW50ZXJwb2xhdGUgZnJvbSAnY29sb3ItaW50ZXJwb2xhdGUnO1xuaW1wb3J0IHtGZWF0dXJlfSBmcm9tICdnZW9qc29uJztcbmltcG9ydCB7TGF5ZXIsIFZlY3RvclRpbGVMYXllcn0gZnJvbSAnQGtlcGxlci5nbC9sYXllcnMnO1xuaW1wb3J0IHtEYXRhc2V0cywgS2VwbGVyVGFibGV9IGZyb20gJ0BrZXBsZXIuZ2wvdGFibGUnO1xuaW1wb3J0IHtTcGF0aWFsSm9pbkdlb21ldHJpZXN9IGZyb20gJ0BvcGVuYXNzaXN0YW50L2dlb2RhJztcbmltcG9ydCB7QUxMX0ZJRUxEX1RZUEVTLCBMQVlFUl9UWVBFU30gZnJvbSAnQGtlcGxlci5nbC9jb25zdGFudHMnO1xuaW1wb3J0IHtGaWVsZCwgUHJvdG9EYXRhc2V0LCBQcm90b0RhdGFzZXRGaWVsZH0gZnJvbSAnQGtlcGxlci5nbC90eXBlcyc7XG5pbXBvcnQge3Byb2Nlc3NGaWxlRGF0YX0gZnJvbSAnQGtlcGxlci5nbC9wcm9jZXNzb3JzJztcblxuLyoqXG4gKiBJbnRlcnBvbGF0ZSB0aGUgY29sb3JzIGZyb20gdGhlIG9yaWdpbmFsIGNvbG9ycyB3aXRoIHRoZSBnaXZlbiBudW1iZXIgb2YgY29sb3JzXG4gKiBAcGFyYW0gb3JpZ2luYWxDb2xvcnMgVGhlIG9yaWdpbmFsIGNvbG9yc1xuICogQHBhcmFtIG51bWJlck9mQ29sb3JzIFRoZSBudW1iZXIgb2YgY29sb3JzXG4gKiBAcmV0dXJucyBUaGUgaW50ZXJwb2xhdGVkIGNvbG9yc1xuICovXG5leHBvcnQgZnVuY3Rpb24gaW50ZXJwb2xhdGVDb2xvcihvcmlnaW5hbENvbG9yczogc3RyaW5nW10sIG51bWJlck9mQ29sb3JzOiBudW1iZXIpIHtcbiAgaWYgKG9yaWdpbmFsQ29sb3JzLmxlbmd0aCA9PT0gbnVtYmVyT2ZDb2xvcnMpIHtcbiAgICByZXR1cm4gb3JpZ2luYWxDb2xvcnM7XG4gIH1cbiAgY29uc3QgaW50ZXJwID0gaW50ZXJwb2xhdGUob3JpZ2luYWxDb2xvcnMpO1xuICBjb25zdCBjb2xvcnMgPSBBcnJheS5mcm9tKHtsZW5ndGg6IG51bWJlck9mQ29sb3JzfSwgKF8sIGopID0+IGludGVycChqIC8gKG51bWJlck9mQ29sb3JzIC0gMSkpKTtcbiAgLy8gY29udmVydCBjb2xvcnMgZnJvbSAncmdiKDI1NSwgMjU1LCAyNTUpJyB0byAnI2ZmZmZmZidcbiAgY29uc3QgaGV4Q29sb3JzID0gY29sb3JzLm1hcChjb2xvciA9PiB7XG4gICAgY29uc3QgcmdiID0gY29sb3IubWF0Y2goL1xcZCsvZyk7XG4gICAgcmV0dXJuIGAjJHtyZ2I/Lm1hcChjID0+IHBhcnNlSW50KGMpLnRvU3RyaW5nKDE2KS5wYWRTdGFydCgyLCAnMCcpKS5qb2luKCcnKX1gO1xuICB9KTtcbiAgcmV0dXJuIGhleENvbG9ycztcbn1cblxuLyoqXG4gKiBHZXQgdGhlIHZhbHVlcyBmcm9tIGEgZGF0YXNldCBmb3IgYSB2YXJpYWJsZVxuICogQHBhcmFtIGRhdGFzZXRzXG4gKiBAcGFyYW0gZGF0YXNldE5hbWVcbiAqIEBwYXJhbSB2YXJpYWJsZU5hbWVcbiAqIEByZXR1cm5zIHtudW1iZXJbXX1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFZhbHVlc0Zyb21EYXRhc2V0KFxuICBkYXRhc2V0czogRGF0YXNldHMsXG4gIGxheWVyczogTGF5ZXJbXSxcbiAgZGF0YXNldE5hbWU6IHN0cmluZyxcbiAgdmFyaWFibGVOYW1lOiBzdHJpbmdcbik6IHVua25vd25bXSB7XG4gIC8vIGZpbmQgd2hpY2ggZGF0YXNldCBoYXMgdGhlIHZhcmlhYmxlTmFtZVxuICBjb25zdCBkYXRhc2V0SWQgPSBPYmplY3Qua2V5cyhkYXRhc2V0cykuZmluZChkYXRhSWQgPT4gZGF0YXNldHNbZGF0YUlkXS5sYWJlbCA9PT0gZGF0YXNldE5hbWUpO1xuICBpZiAoIWRhdGFzZXRJZCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgRGF0YXNldCAke2RhdGFzZXROYW1lfSBub3QgZm91bmRgKTtcbiAgfVxuICBjb25zdCBkYXRhc2V0ID0gZGF0YXNldHNbZGF0YXNldElkXTtcbiAgaWYgKGRhdGFzZXQpIHtcbiAgICAvLyBjaGVjayBpZiBmaWVsZCBleGlzdHNcbiAgICBjb25zdCBmaWVsZCA9IGRhdGFzZXQuZmllbGRzLmZpbmQoZmllbGQgPT4gZmllbGQubmFtZSA9PT0gdmFyaWFibGVOYW1lKTtcbiAgICBpZiAoIWZpZWxkKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEZpZWxkICR7dmFyaWFibGVOYW1lfSBub3QgZm91bmQgaW4gZGF0YXNldCAke2RhdGFzZXROYW1lfWApO1xuICAgIH1cbiAgICAvLyBmb3IgdmVjdG9yLXRpbGUsIGdldHRpbmcgdmFsdWVzIGZyb20gbGF5ZXJEYXRhXG4gICAgaWYgKGRhdGFzZXQudHlwZSA9PT0gJ3ZlY3Rvci10aWxlJykge1xuICAgICAgLy8gZ2V0IGZpZWxkIGZyb20gZGF0YXNldFxuICAgICAgY29uc3QgZmllbGQgPSBkYXRhc2V0LmZpZWxkcy5maW5kKGZpZWxkID0+IGZpZWxkLm5hbWUgPT09IHZhcmlhYmxlTmFtZSk7XG4gICAgICBpZiAoZmllbGQpIHtcbiAgICAgICAgcmV0dXJuIGdldFZhbHVlc0Zyb21WZWN0b3JUaWxlTGF5ZXIoZGF0YXNldElkLCBsYXllcnMsIGZpZWxkKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIEFycmF5LmZyb20oe2xlbmd0aDogZGF0YXNldC5sZW5ndGh9LCAoXywgaSkgPT4gZGF0YXNldC5nZXRWYWx1ZSh2YXJpYWJsZU5hbWUsIGkpKTtcbiAgfVxuICByZXR1cm4gW107XG59XG5cbmZ1bmN0aW9uIGlzVmVjdG9yVGlsZUxheWVyKGxheWVyOiBMYXllcik6IGxheWVyIGlzIFZlY3RvclRpbGVMYXllciB7XG4gIHJldHVybiBsYXllci50eXBlID09PSBMQVlFUl9UWVBFUy52ZWN0b3JUaWxlO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZ2V0VmFsdWVzRnJvbVZlY3RvclRpbGVMYXllcihkYXRhc2V0SWQ6IHN0cmluZywgbGF5ZXJzOiBMYXllcltdLCBmaWVsZDogRmllbGQpIHtcbiAgLy8gZ2V0IHRoZSBpbmRleCBvZiB0aGUgbGF5ZXJcbiAgY29uc3QgbGF5ZXJJbmRleCA9IGxheWVycy5maW5kSW5kZXgobGF5ZXIgPT4gbGF5ZXIuY29uZmlnLmRhdGFJZCA9PT0gZGF0YXNldElkKTtcbiAgaWYgKGxheWVySW5kZXggPT09IC0xKSByZXR1cm4gW107XG4gIGNvbnN0IGxheWVyID0gbGF5ZXJzW2xheWVySW5kZXhdO1xuICBpZiAoIWlzVmVjdG9yVGlsZUxheWVyKGxheWVyKSkgcmV0dXJuIFtdO1xuICBjb25zdCBhY2Nlc3NvciA9IGxheWVyLmFjY2Vzc1Jvd1ZhbHVlKGZpZWxkKTtcbiAgY29uc3QgdmFsdWVzOiB1bmtub3duW10gPSBbXTtcbiAgLy8gQHRzLWV4cGVjdC1lcnJvciBUT0RPIGZpeCB0aGlzIGxhdGVyIGluIHRoZSB2ZWN0b3ItdGlsZSBsYXllclxuICBmb3IgKGNvbnN0IHJvdyBvZiBsYXllci50aWxlRGF0YXNldC50aWxlU2V0KSB7XG4gICAgY29uc3QgdmFsdWUgPSBhY2Nlc3NvcihmaWVsZCwgcm93KTtcbiAgICBpZiAodmFsdWUgPT09IG51bGwpIGJyZWFrO1xuICAgIHZhbHVlcy5wdXNoKHZhbHVlKTtcbiAgfVxuICByZXR1cm4gdmFsdWVzO1xufVxuXG4vKipcbiAqIEhpZ2hsaWdodCB0aGUgcm93cyBpbiBhIGRhdGFzZXRcbiAqIEBwYXJhbSBkYXRhc2V0cyBUaGUga2VwbGVyLmdsIGRhdGFzZXRzXG4gKiBAcGFyYW0gbGF5ZXJzIFRoZSBrZXBsZXIuZ2wgbGF5ZXJzXG4gKiBAcGFyYW0gZGF0YXNldE5hbWUgVGhlIG5hbWUgb2YgdGhlIGRhdGFzZXRcbiAqIEBwYXJhbSBzZWxlY3RlZFJvd0luZGljZXMgVGhlIGluZGljZXMgb2YgdGhlIHJvd3MgdG8gaGlnaGxpZ2h0XG4gKiBAcGFyYW0gbGF5ZXJTZXRJc1ZhbGlkIFRoZSBmdW5jdGlvbiB0byBzZXQgdGhlIGxheWVyIHZhbGlkaXR5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoaWdobGlnaHRSb3dzKFxuICBkYXRhc2V0czogRGF0YXNldHMsXG4gIGxheWVyczogTGF5ZXJbXSxcbiAgZGF0YXNldE5hbWU6IHN0cmluZyxcbiAgc2VsZWN0ZWRSb3dJbmRpY2VzOiBudW1iZXJbXSxcbiAgbGF5ZXJTZXRJc1ZhbGlkOiAobGF5ZXI6IExheWVyLCBpc1ZhbGlkOiBib29sZWFuKSA9PiB2b2lkXG4pIHtcbiAgLy8gdXBkYXRlIHRoZSBmaWx0ZXJlZEluZGV4IGluIHRoZSBkYXRhc2V0XG4gIGNvbnN0IGRhdGFzZXRJZCA9IE9iamVjdC5rZXlzKGRhdGFzZXRzKS5maW5kKGRhdGFJZCA9PiBkYXRhc2V0c1tkYXRhSWRdLmxhYmVsID09PSBkYXRhc2V0TmFtZSk7XG4gIGlmICghZGF0YXNldElkKSByZXR1cm47XG4gIGNvbnN0IGRhdGFzZXQgPSBkYXRhc2V0c1tkYXRhc2V0SWRdO1xuICBpZiAoZGF0YXNldCkge1xuICAgIGRhdGFzZXQuZmlsdGVyZWRJbmRleCA9XG4gICAgICBzZWxlY3RlZFJvd0luZGljZXMubGVuZ3RoID09PSAwID8gZGF0YXNldC5hbGxJbmRleGVzIDogc2VsZWN0ZWRSb3dJbmRpY2VzO1xuICAgIC8vIGdldCBhbGwgbGF5ZXJzIHRoYXQgdXNlIHRoaXMgZGF0YXNldFxuICAgIGNvbnN0IHNlbGVjdExheWVycyA9IGxheWVycy5maWx0ZXIobGF5ZXIgPT4gbGF5ZXIuY29uZmlnLmRhdGFJZCA9PT0gZGF0YXNldC5pZCk7XG4gICAgc2VsZWN0TGF5ZXJzLmZvckVhY2gobGF5ZXIgPT4ge1xuICAgICAgbGF5ZXIuZm9ybWF0TGF5ZXJEYXRhKGRhdGFzZXRzKTtcbiAgICAgIC8vIHRyaWdnZXIgYSByZS1yZW5kZXIgdXNpbmcgbGF5ZXJTZXRJc1ZhbGlkKCkgdG8gdXBkYXRlIHRoZSB0b3AgbGF5ZXJcbiAgICAgIGxheWVyU2V0SXNWYWxpZChsYXllciwgdHJ1ZSk7XG4gICAgfSk7XG4gIH1cbn1cblxuLyoqXG4gKiBHZXQgdGhlIGRhdGFzZXQgY29udGV4dCwgd2hpY2ggaXMgdXNlZCB0byBwcm92aWRlIHRoZSBkYXRhc2V0IGluZm9ybWF0aW9uIHRvIHRoZSBBSSBhc3Npc3RhbnRcbiAqIEBwYXJhbSBkYXRhc2V0cyBUaGUga2VwbGVyLmdsIGRhdGFzZXRzXG4gKiBAcGFyYW0gbGF5ZXJzIFRoZSBrZXBsZXIuZ2wgbGF5ZXJzXG4gKiBAcmV0dXJucyBUaGUgZGF0YXNldCBjb250ZXh0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXREYXRhc2V0Q29udGV4dChkYXRhc2V0cz86IERhdGFzZXRzLCBsYXllcnM/OiBMYXllcltdKSB7XG4gIGlmICghZGF0YXNldHMgfHwgIWxheWVycykgcmV0dXJuICcnO1xuICBjb25zdCBjb250ZXh0ID1cbiAgICAnUGxlYXNlIHJlbWVtYmVyIHRoZSBmb2xsb3dpbmcgZGF0YXNldHMgYW5kIGxheWVycyBmb3IgYW5zd2VyaW5nIHRoZSB1c2VyIHF1ZXN0aW9uOic7XG4gIGNvbnN0IGRhdGFNZXRhID0gT2JqZWN0LnZhbHVlcyhkYXRhc2V0cykubWFwKChkYXRhc2V0OiBLZXBsZXJUYWJsZSkgPT4gKHtcbiAgICBkYXRhc2V0TmFtZTogZGF0YXNldC5sYWJlbCxcbiAgICBkYXRhc2V0SWQ6IGRhdGFzZXQuaWQsXG4gICAgZmllbGRzOiBkYXRhc2V0LmZpZWxkcy5tYXAoZmllbGQgPT4gKHtbZmllbGQubmFtZV06IGZpZWxkLnR5cGV9KSksXG4gICAgbGF5ZXJzOiBsYXllcnNcbiAgICAgIC5maWx0ZXIobGF5ZXIgPT4gbGF5ZXIuY29uZmlnLmRhdGFJZCA9PT0gZGF0YXNldC5pZClcbiAgICAgIC5tYXAobGF5ZXIgPT4gKHtcbiAgICAgICAgaWQ6IGxheWVyLmlkLFxuICAgICAgICBsYWJlbDogbGF5ZXIuY29uZmlnLmxhYmVsLFxuICAgICAgICB0eXBlOiBsYXllci50eXBlLFxuICAgICAgICBnZW9tZXRyeU1vZGU6IGxheWVyLmNvbmZpZy5jb2x1bW5Nb2RlLFxuICAgICAgICAvLyBnZXQgdGhlIHZhbGlkIGdlb21ldHJ5IGNvbHVtbnMgYXMgc3RyaW5nXG4gICAgICAgIGdlb21ldHJ5Q29sdW1uczogT2JqZWN0LmZyb21FbnRyaWVzKFxuICAgICAgICAgIE9iamVjdC5lbnRyaWVzKGxheWVyLmNvbmZpZy5jb2x1bW5zKVxuICAgICAgICAgICAgLmZpbHRlcigoWywgdmFsdWVdKSA9PiB2YWx1ZSAhPT0gbnVsbClcbiAgICAgICAgICAgIC5tYXAoKFtrZXksIHZhbHVlXSkgPT4gW1xuICAgICAgICAgICAgICBrZXksXG4gICAgICAgICAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgdmFsdWUgIT09IG51bGxcbiAgICAgICAgICAgICAgICA/IE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyh2YWx1ZSkuZmlsdGVyKChbLCB2XSkgPT4gdiAhPT0gbnVsbCkpXG4gICAgICAgICAgICAgICAgOiB2YWx1ZVxuICAgICAgICAgICAgXSlcbiAgICAgICAgKVxuICAgICAgfSkpXG4gIH0pKTtcbiAgcmV0dXJuIGAke2NvbnRleHR9XFxuJHtKU09OLnN0cmluZ2lmeShkYXRhTWV0YSl9YDtcbn1cblxuLyoqXG4gKiBHZXQgdGhlIGdlb21ldHJpZXMgZnJvbSBhIGRhdGFzZXRcbiAqIEBwYXJhbSBkYXRhc2V0cyBUaGUga2VwbGVyLmdsIGRhdGFzZXRzXG4gKiBAcGFyYW0gbGF5ZXJzIFRoZSBrZXBsZXIuZ2wgbGF5ZXJzXG4gKiBAcGFyYW0gbGF5ZXJEYXRhIFRoZSBsYXllciBkYXRhXG4gKiBAcGFyYW0gZGF0YXNldE5hbWUgVGhlIG5hbWUgb2YgdGhlIGRhdGFzZXRcbiAqIEByZXR1cm5zIFRoZSBnZW9tZXRyaWVzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRHZW9tZXRyaWVzRnJvbURhdGFzZXQoXG4gIGRhdGFzZXRzOiBEYXRhc2V0cyxcbiAgbGF5ZXJzOiBMYXllcltdLFxuICBsYXllckRhdGE6IGFueVtdLFxuICBkYXRhc2V0TmFtZTogc3RyaW5nXG4pOiBTcGF0aWFsSm9pbkdlb21ldHJpZXMge1xuICBjb25zdCBkYXRhc2V0SWQgPSBPYmplY3Qua2V5cyhkYXRhc2V0cykuZmluZChkYXRhSWQgPT4gZGF0YXNldHNbZGF0YUlkXS5sYWJlbCA9PT0gZGF0YXNldE5hbWUpO1xuICBpZiAoIWRhdGFzZXRJZCkge1xuICAgIHJldHVybiBbXTtcbiAgfVxuICBjb25zdCBkYXRhc2V0ID0gZGF0YXNldHNbZGF0YXNldElkXTtcblxuICAvLyBpZiBsYXllciBpcyB2ZWN0b3ItdGlsZSwgZ2V0IHRoZSBnZW9tZXRyaWVzIGZyb20gdGhlIGxheWVyXG4gIGlmIChkYXRhc2V0LnR5cGUgPT09ICd2ZWN0b3ItdGlsZScpIHtcbiAgICAvLyBmaW5kIHRoZSB2ZWN0b3ItdGlsZSBsYXllclxuICAgIGNvbnN0IHNlbGVjdGVkID0gbGF5ZXJzLmZpbHRlcihsYXllciA9PiBsYXllci5jb25maWcuZGF0YUlkID09PSBkYXRhc2V0LmlkKTtcbiAgICBjb25zdCBsYXllciA9IHNlbGVjdGVkLmZpbmQobGF5ZXIgPT4gbGF5ZXIudHlwZSA9PT0gTEFZRVJfVFlQRVMudmVjdG9yVGlsZSk7XG4gICAgaWYgKCFsYXllcikgcmV0dXJuIFtdO1xuXG4gICAgY29uc3QgZ2VvbWV0cmllczogRmVhdHVyZVtdID0gW107XG4gICAgLy8gQHRzLWV4cGVjdC1lcnJvciBUT0RPIGZpeCB0aGlzIGxhdGVyIGluIHRoZSB2ZWN0b3ItdGlsZSBsYXllclxuICAgIGZvciAoY29uc3Qgcm93IG9mIGxheWVyLnRpbGVEYXRhc2V0LnRpbGVTZXQpIHtcbiAgICAgIGdlb21ldHJpZXMucHVzaChyb3cpO1xuICAgIH1cbiAgICByZXR1cm4gZ2VvbWV0cmllcztcbiAgfVxuXG4gIC8vIGZvciBub24tdmVjdG9yLXRpbGUgZGF0YXNldCwgZ2V0IHRoZSBnZW9tZXRyaWVzIGZyb20gdGhlIHBvc3NpYmxlIGxheWVyXG4gIGNvbnN0IHNlbGVjdGVkTGF5ZXJzID0gbGF5ZXJzLmZpbHRlcihsYXllciA9PiBsYXllci5jb25maWcuZGF0YUlkID09PSBkYXRhc2V0LmlkKTtcbiAgaWYgKHNlbGVjdGVkTGF5ZXJzLmxlbmd0aCA9PT0gMCkgcmV0dXJuIFtdO1xuXG4gIC8vIGZpbmQgZ2VvanNvbiBsYXllciwgdGhlbiBwb2ludCBsYXllciwgdGhlbiBvdGhlciBsYXllcnNcbiAgY29uc3QgZ2VvanNvbkxheWVyID0gc2VsZWN0ZWRMYXllcnMuZmluZChsYXllciA9PiBsYXllci50eXBlID09PSBMQVlFUl9UWVBFUy5nZW9qc29uKTtcbiAgY29uc3QgcG9pbnRMYXllciA9IHNlbGVjdGVkTGF5ZXJzLmZpbmQobGF5ZXIgPT4gbGF5ZXIudHlwZSA9PT0gTEFZRVJfVFlQRVMucG9pbnQpO1xuICBjb25zdCBvdGhlckxheWVycyA9IHNlbGVjdGVkTGF5ZXJzLmZpbHRlcihcbiAgICBsYXllciA9PiBsYXllci50eXBlICE9PSBMQVlFUl9UWVBFUy5nZW9qc29uICYmIGxheWVyLnR5cGUgIT09IExBWUVSX1RZUEVTLnBvaW50XG4gICk7XG5cbiAgY29uc3QgdmFsaWRMYXllciA9IGdlb2pzb25MYXllciB8fCBwb2ludExheWVyIHx8IG90aGVyTGF5ZXJzWzBdO1xuICBpZiAodmFsaWRMYXllcikge1xuICAgIGNvbnN0IGxheWVySW5kZXggPSBsYXllcnMuZmluZEluZGV4KGxheWVyID0+IGxheWVyLmlkID09PSB2YWxpZExheWVyLmlkKTtcbiAgICBjb25zdCBnZW9tZXRyaWVzID0gbGF5ZXJEYXRhW2xheWVySW5kZXhdO1xuICAgIHJldHVybiBnZW9tZXRyaWVzLmRhdGE7XG4gIH1cblxuICByZXR1cm4gW107XG59XG5cbi8qKlxuICogU2F2ZSB0aGUgZGF0YSBhcyBhIG5ldyBkYXRhc2V0IGJ5IGpvaW5pbmcgaXQgd2l0aCB0aGUgbGVmdCBkYXRhc2V0XG4gKiBAcGFyYW0gZGF0YXNldHMgVGhlIGtlcGxlci5nbCBkYXRhc2V0c1xuICogQHBhcmFtIGRhdGFzZXROYW1lIFRoZSBuYW1lIG9mIHRoZSBsZWZ0IGRhdGFzZXRcbiAqIEBwYXJhbSBkYXRhIFRoZSBkYXRhIHRvIHNhdmVcbiAqIEBwYXJhbSBhZGREYXRhVG9NYXAgVGhlIGZ1bmN0aW9uIHRvIGFkZCB0aGUgZGF0YSB0byB0aGUgbWFwXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzYXZlQXNEYXRhc2V0KFxuICBkYXRhc2V0czogRGF0YXNldHMsXG4gIGxheWVyczogTGF5ZXJbXSxcbiAgZGF0YXNldE5hbWU6IHN0cmluZyxcbiAgbmV3RGF0YXNldE5hbWU6IHN0cmluZyxcbiAgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bltdPlxuKSB7XG4gIC8vIGZpbmQgZGF0YXNldElkIGZyb20gZGF0YXNldHNcbiAgY29uc3QgZGF0YXNldElkID0gT2JqZWN0LmtleXMoZGF0YXNldHMpLmZpbmQoZGF0YUlkID0+IGRhdGFzZXRzW2RhdGFJZF0ubGFiZWwgPT09IGRhdGFzZXROYW1lKTtcbiAgaWYgKCFkYXRhc2V0SWQpIHJldHVybjtcblxuICAvLyBjaGVjayBpZiBuZXdEYXRhc2V0TmFtZSBhbHJlYWR5IGV4aXN0c1xuICBpZiAoT2JqZWN0LmtleXMoZGF0YXNldHMpLmluY2x1ZGVzKG5ld0RhdGFzZXROYW1lKSkgcmV0dXJuO1xuXG4gIC8vIFNhdmUgdGhlIGRhdGEgYXMgYSBuZXcgZGF0YXNldCBieSBqb2luaW5nIGl0IHdpdGggdGhlIGxlZnQgZGF0YXNldFxuICBjb25zdCBsZWZ0RGF0YXNldCA9IGRhdGFzZXRzW2RhdGFzZXRJZF07XG4gIGxldCBudW1Sb3dzID0gbGVmdERhdGFzZXQubGVuZ3RoO1xuICBsZXQgZ2VvbWV0cmllczogRmVhdHVyZVtdO1xuXG4gIGlmIChsZWZ0RGF0YXNldC50eXBlID09PSAndmVjdG9yLXRpbGUnKSB7XG4gICAgLy8gd2UgbmVlZCB0byBnZXQgZ2VvbWV0cmllcyBmcm9tIHRoZSB2ZWN0b3ItdGlsZSBsYXllclxuICAgIGdlb21ldHJpZXMgPSBnZXRGZWF0dXJlc0Zyb21WZWN0b3JUaWxlKGxlZnREYXRhc2V0LCBsYXllcnMpIHx8IFtdO1xuICAgIG51bVJvd3MgPSBnZW9tZXRyaWVzLmxlbmd0aDtcbiAgfVxuXG4gIGNvbnN0IGZpZWxkczogUHJvdG9EYXRhc2V0RmllbGRbXSA9IFtcbiAgICAvLyBOZXcgZmllbGRzIGZyb20gZGF0YVxuICAgIC4uLk9iamVjdC5rZXlzKGRhdGEpLm1hcCgoZmllbGROYW1lLCBpbmRleCkgPT4gKHtcbiAgICAgIG5hbWU6IGZpZWxkTmFtZSxcbiAgICAgIGlkOiBgJHtmaWVsZE5hbWV9XyR7aW5kZXh9YCxcbiAgICAgIGRpc3BsYXlOYW1lOiBmaWVsZE5hbWUsXG4gICAgICB0eXBlOiBkZXRlcm1pbmVGaWVsZFR5cGUoZGF0YVtmaWVsZE5hbWVdWzBdKVxuICAgIH0pKSxcbiAgICAvLyBFeGlzdGluZyBmaWVsZHMgZnJvbSBsZWZ0RGF0YXNldFxuICAgIC4uLmxlZnREYXRhc2V0LmZpZWxkcy5tYXAoKGZpZWxkLCBpbmRleCkgPT4gKHtcbiAgICAgIG5hbWU6IGZpZWxkLm5hbWUsXG4gICAgICBpZDogZmllbGQuaWQgfHwgYCR7ZmllbGQubmFtZX1fJHtpbmRleH1gLFxuICAgICAgZGlzcGxheU5hbWU6IGZpZWxkLmRpc3BsYXlOYW1lLFxuICAgICAgdHlwZTogZmllbGQudHlwZVxuICAgIH0pKSxcbiAgICAvLyBhZGQgZ2VvbWV0cnkgY29sdW1uIGZvciB2ZWN0b3ItdGlsZVxuICAgIC4uLihsZWZ0RGF0YXNldC50eXBlID09PSAndmVjdG9yLXRpbGUnXG4gICAgICA/IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBuYW1lOiAnX2dlb2pzb24nLFxuICAgICAgICAgICAgaWQ6ICdfZ2VvanNvbicsXG4gICAgICAgICAgICBkaXNwbGF5TmFtZTogJ19nZW9qc29uJyxcbiAgICAgICAgICAgIHR5cGU6ICdnZW9qc29uJ1xuICAgICAgICAgIH1cbiAgICAgICAgXVxuICAgICAgOiBbXSlcbiAgXTtcblxuICAvLyBQcmUtY2FsY3VsYXRlIGRhdGEgdmFsdWVzIGFycmF5XG4gIGNvbnN0IGRhdGFWYWx1ZXMgPSBPYmplY3QudmFsdWVzKGRhdGEpO1xuXG4gIGNvbnN0IHJvd3MgPSBBcnJheShudW1Sb3dzKVxuICAgIC5maWxsKG51bGwpXG4gICAgLm1hcCgoXywgcm93SWR4KSA9PiBbXG4gICAgICAvLyBOZXcgZGF0YSB2YWx1ZXNcbiAgICAgIC4uLmRhdGFWYWx1ZXMubWFwKGNvbCA9PiBjb2xbcm93SWR4XSksXG4gICAgICAvLyBFeGlzdGluZyBkYXRhc2V0IHZhbHVlc1xuICAgICAgLi4ubGVmdERhdGFzZXQuZmllbGRzLm1hcChmaWVsZCA9PlxuICAgICAgICBsZWZ0RGF0YXNldC50eXBlID09PSAndmVjdG9yLXRpbGUnXG4gICAgICAgICAgPyBnZW9tZXRyaWVzW3Jvd0lkeF0ucHJvcGVydGllcz8uW2ZpZWxkLm5hbWVdXG4gICAgICAgICAgOiBsZWZ0RGF0YXNldC5nZXRWYWx1ZShmaWVsZC5uYW1lLCByb3dJZHgpXG4gICAgICApLFxuICAgICAgLy8gZ2VvbWV0cnkgY29sdW1uIGZvciB2ZWN0b3ItdGlsZVxuICAgICAgLi4uKGxlZnREYXRhc2V0LnR5cGUgPT09ICd2ZWN0b3ItdGlsZScgPyBbZ2VvbWV0cmllc1tyb3dJZHhdXSA6IFtdKVxuICAgIF0pO1xuXG4gIC8vIGNyZWF0ZSBuZXcgZGF0YXNldFxuICBjb25zdCBuZXdEYXRhc2V0OiBQcm90b0RhdGFzZXQgPSB7XG4gICAgaW5mbzoge1xuICAgICAgaWQ6IG5ld0RhdGFzZXROYW1lLFxuICAgICAgbGFiZWw6IG5ld0RhdGFzZXROYW1lXG4gICAgfSxcbiAgICBkYXRhOiB7XG4gICAgICBmaWVsZHMsXG4gICAgICByb3dzXG4gICAgfVxuICB9O1xuXG4gIHJldHVybiBuZXdEYXRhc2V0O1xufVxuXG4vKipcbiAqIEhlbHBlciBmdW5jdGlvbiB0byBkZXRlcm1pbmUgZmllbGQgdHlwZVxuICogQHBhcmFtIHZhbHVlIFRoZSB2YWx1ZSB0byBkZXRlcm1pbmUgdGhlIGZpZWxkIHR5cGVcbiAqIEByZXR1cm5zIFRoZSBmaWVsZCB0eXBlXG4gKi9cbmZ1bmN0aW9uIGRldGVybWluZUZpZWxkVHlwZSh2YWx1ZTogdW5rbm93bik6IGtleW9mIHR5cGVvZiBBTExfRklFTERfVFlQRVMge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJ1xuICAgID8gTnVtYmVyLmlzSW50ZWdlcih2YWx1ZSlcbiAgICAgID8gQUxMX0ZJRUxEX1RZUEVTLmludGVnZXJcbiAgICAgIDogQUxMX0ZJRUxEX1RZUEVTLnJlYWxcbiAgICA6IEFMTF9GSUVMRF9UWVBFUy5zdHJpbmc7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBoaWdobGlnaHRSb3dzQnlDb2x1bW5WYWx1ZXMoXG4gIGRhdGFzZXRzOiBEYXRhc2V0cyxcbiAgbGF5ZXJzOiBMYXllcltdLFxuICBkYXRhc2V0TmFtZTogc3RyaW5nLFxuICBjb2x1bW5OYW1lOiBzdHJpbmcsXG4gIHNlbGVjdGVkVmFsdWVzOiB1bmtub3duW10sXG4gIGxheWVyU2V0SXNWYWxpZDogKGxheWVyOiBMYXllciwgaXNWYWxpZDogYm9vbGVhbikgPT4gdm9pZFxuKSB7XG4gIGNvbnN0IGRhdGFzZXRJZCA9IE9iamVjdC5rZXlzKGRhdGFzZXRzKS5maW5kKGRhdGFJZCA9PiBkYXRhc2V0c1tkYXRhSWRdLmxhYmVsID09PSBkYXRhc2V0TmFtZSk7XG4gIGlmICghZGF0YXNldElkKSByZXR1cm47XG4gIGNvbnN0IGRhdGFzZXQgPSBkYXRhc2V0c1tkYXRhc2V0SWRdO1xuICBpZiAoZGF0YXNldCkge1xuICAgIC8vIGdldCB0aGUgdmFsdWVzIG9mIHRoZSBjb2x1bW5cbiAgICBjb25zdCB2YWx1ZXMgPSBBcnJheS5mcm9tKHtsZW5ndGg6IGRhdGFzZXQubGVuZ3RofSwgKF8sIGkpID0+IGRhdGFzZXQuZ2V0VmFsdWUoY29sdW1uTmFtZSwgaSkpO1xuICAgIC8vIGNyZWF0ZSBhIGRpY3QgdXNpbmcgdGhlIHZhbHVlc1xuICAgIGNvbnN0IHZhbHVlRGljdCA9IHZhbHVlcy5yZWR1Y2UoKGFjYywgdmFsdWUsIGluZGV4KSA9PiB7XG4gICAgICBhY2NbdmFsdWVdID0gaW5kZXg7XG4gICAgICByZXR1cm4gYWNjO1xuICAgIH0sIHt9KTtcbiAgICAvLyBuZWVkIHRvIGZpeCB0aGUgdHlwZSBlcnJvciBvZiB2YWx1ZSBoZXJlXG4gICAgY29uc3Qgc2VsZWN0ZWRJbmRpY2VzID0gc2VsZWN0ZWRWYWx1ZXMubWFwKHZhbHVlID0+IHZhbHVlRGljdFt2YWx1ZSBhcyBhbnldKTtcbiAgICAvLyBoaWdobGlnaHQgdGhlIHJvd3NcbiAgICBoaWdobGlnaHRSb3dzKGRhdGFzZXRzLCBsYXllcnMsIGRhdGFzZXROYW1lLCBzZWxlY3RlZEluZGljZXMsIGxheWVyU2V0SXNWYWxpZCk7XG4gIH1cbn1cblxuZnVuY3Rpb24gZ2V0RmVhdHVyZXNGcm9tVmVjdG9yVGlsZShsZWZ0RGF0YXNldDogS2VwbGVyVGFibGUsIGxheWVyczogTGF5ZXJbXSkge1xuICBjb25zdCBsYXllckluZGV4ID0gbGF5ZXJzLmZpbmRJbmRleChsYXllciA9PiBsYXllci5jb25maWcuZGF0YUlkID09PSBsZWZ0RGF0YXNldC5pZCk7XG4gIGlmIChsYXllckluZGV4ID09PSAtMSkgcmV0dXJuO1xuXG4gIGNvbnN0IGxheWVyID0gbGF5ZXJzW2xheWVySW5kZXhdO1xuICBpZiAoIWlzVmVjdG9yVGlsZUxheWVyKGxheWVyKSkgcmV0dXJuO1xuXG4gIGNvbnN0IGZlYXR1cmVzOiBGZWF0dXJlW10gPSBbXTtcbiAgLy8gQHRzLWV4cGVjdC1lcnJvciBUT0RPIGZpeCB0aGlzIGxhdGVyIGluIHRoZSB2ZWN0b3ItdGlsZSBsYXllclxuICBmb3IgKGNvbnN0IHJvdyBvZiBsYXllci50aWxlRGF0YXNldC50aWxlU2V0KSB7XG4gICAgZmVhdHVyZXMucHVzaChyb3cpO1xuICB9XG5cbiAgcmV0dXJuIGZlYXR1cmVzO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYXBwZW5kQ29sdW1uc1RvRGF0YXNldChcbiAgZGF0YXNldHM6IERhdGFzZXRzLFxuICBsYXllcnM6IExheWVyW10sXG4gIGRhdGFzZXROYW1lOiBzdHJpbmcsXG4gIHJlc3VsdDogUmVjb3JkPHN0cmluZywgbnVtYmVyPltdLFxuICBuZXdEYXRhc2V0TmFtZTogc3RyaW5nXG4pIHtcbiAgLy8gZmluZCBkYXRhc2V0SWQgZnJvbSBkYXRhc2V0c1xuICBjb25zdCBkYXRhc2V0SWQgPSBPYmplY3Qua2V5cyhkYXRhc2V0cykuZmluZChkYXRhSWQgPT4gZGF0YXNldHNbZGF0YUlkXS5sYWJlbCA9PT0gZGF0YXNldE5hbWUpO1xuICBpZiAoIWRhdGFzZXRJZCkge1xuICAgIHRocm93IG5ldyBFcnJvcihgRGF0YXNldCAke2RhdGFzZXROYW1lfSBub3QgZm91bmRgKTtcbiAgfVxuXG4gIGNvbnN0IG9yaWdpbmFsRGF0YXNldCA9IGRhdGFzZXRzW2RhdGFzZXRJZF07XG5cbiAgY29uc3QgZmllbGRzID0gb3JpZ2luYWxEYXRhc2V0LmZpZWxkcztcblxuICBjb25zdCBudW1Sb3dzID0gb3JpZ2luYWxEYXRhc2V0Lmxlbmd0aCB8fCByZXN1bHQubGVuZ3RoO1xuXG4gIC8vIGNyZWF0ZSBhIHJvd09iamVjdHMgYXJyYXkgdG8gc3RvcmUgdGhlIG9yaWdpbmFsIGRhdGFzZXQgdmFsdWVzICsgcXVlcnkgcmVzdWx0IHZhbHVlc1xuICBjb25zdCByb3dPYmplY3RzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPltdID0gW107XG5cbiAgaWYgKG9yaWdpbmFsRGF0YXNldC50eXBlID09PSAndmVjdG9yLXRpbGUnKSB7XG4gICAgY29uc3QgY29sdW1uRGF0YSA9IHt9O1xuICAgIGZvciAoY29uc3QgZmllbGQgb2YgZmllbGRzKSB7XG4gICAgICAvLyBnZXQgdGhlIHZhbHVlcyBmcm9tIHRoZSB2ZWN0b3IgdGlsZSBsYXllclxuICAgICAgY29sdW1uRGF0YVtmaWVsZC5uYW1lXSA9IGdldFZhbHVlc0Zyb21WZWN0b3JUaWxlTGF5ZXIoZGF0YXNldElkLCBsYXllcnMsIGZpZWxkKTtcbiAgICB9XG4gICAgLy8gY29udmVydCBjb2x1bW5EYXRhIHRvIHJvd09iamVjdHNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bVJvd3M7IGkrKykge1xuICAgICAgY29uc3Qgcm93T2JqZWN0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICAgICAgZm9yIChjb25zdCBmaWVsZCBvZiBmaWVsZHMpIHtcbiAgICAgICAgcm93T2JqZWN0W2ZpZWxkLm5hbWVdID0gY29sdW1uRGF0YVtmaWVsZC5uYW1lXVtpXTtcbiAgICAgIH1cbiAgICAgIHJvd09iamVjdHMucHVzaChyb3dPYmplY3QpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bVJvd3M7IGkrKykge1xuICAgICAgY29uc3Qgcm93T2JqZWN0OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiA9IHt9O1xuICAgICAgZm9yIChjb25zdCBmaWVsZCBvZiBmaWVsZHMpIHtcbiAgICAgICAgY29uc3QgdmFsdWUgPSBvcmlnaW5hbERhdGFzZXQuZ2V0VmFsdWUoZmllbGQubmFtZSwgaSk7XG4gICAgICAgIHJvd09iamVjdFtmaWVsZC5uYW1lXSA9IHZhbHVlO1xuICAgICAgfVxuICAgICAgcm93T2JqZWN0cy5wdXNoKHJvd09iamVjdCk7XG4gICAgfVxuICB9XG5cbiAgLy8gYWRkIHRoZSBxdWVyeSByZXN1bHQgdG8gdGhlIG9yaWdpbmFsIGRhdGFzZXQgb3IgdXBkYXRlIHRoZSBmaWVsZCB2YWx1ZXMgZnJvbSBxdWVyeSByZXN1bHRcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBudW1Sb3dzOyBpKyspIHtcbiAgICBjb25zdCBxdWVyeVJvdyA9IHJlc3VsdFtpXTtcbiAgICBjb25zdCByb3dPYmplY3QgPSByb3dPYmplY3RzW2ldO1xuICAgIC8vIGl0ZXJhdGUgb3ZlciB0aGUga2V5cyBvZiBxdWVyeVJvd1xuICAgIE9iamVjdC5rZXlzKHF1ZXJ5Um93KS5mb3JFYWNoKGtleSA9PiB7XG4gICAgICBjb25zdCB2YWx1ZSA9IHF1ZXJ5Um93W2tleV07XG4gICAgICByb3dPYmplY3Rba2V5XSA9IHZhbHVlO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gdXNlIHByb2Nlc3NGaWxlRGF0YSB0byBwcm9jZXNzIHRoZSByb3dPYmplY3RcbiAgY29uc3QgcHJvY2Vzc2VkRGF0YSA9IGF3YWl0IHByb2Nlc3NGaWxlRGF0YSh7XG4gICAgY29udGVudDoge2ZpbGVOYW1lOiBuZXdEYXRhc2V0TmFtZSwgZGF0YTogcm93T2JqZWN0c30sXG4gICAgZmlsZUNhY2hlOiBbXVxuICB9KTtcblxuICByZXR1cm4gcHJvY2Vzc2VkRGF0YTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBR0EsSUFBQUEsaUJBQUEsR0FBQUMsc0JBQUEsQ0FBQUMsT0FBQTtBQUtBLElBQUFDLElBQUEsR0FBQUQsT0FBQTtBQUVBLElBQUFFLEtBQUEsR0FBQUYsT0FBQTtBQUFzRCxTQUFBRywyQkFBQUMsQ0FBQSxFQUFBQyxDQUFBLFFBQUFDLENBQUEseUJBQUFDLE1BQUEsSUFBQUgsQ0FBQSxDQUFBRyxNQUFBLENBQUFDLFFBQUEsS0FBQUosQ0FBQSxxQkFBQUUsQ0FBQSxRQUFBRyxLQUFBLENBQUFDLE9BQUEsQ0FBQU4sQ0FBQSxNQUFBRSxDQUFBLEdBQUFLLDJCQUFBLENBQUFQLENBQUEsTUFBQUMsQ0FBQSxJQUFBRCxDQUFBLHVCQUFBQSxDQUFBLENBQUFRLE1BQUEsSUFBQU4sQ0FBQSxLQUFBRixDQUFBLEdBQUFFLENBQUEsT0FBQU8sRUFBQSxNQUFBQyxDQUFBLFlBQUFBLEVBQUEsZUFBQUMsQ0FBQSxFQUFBRCxDQUFBLEVBQUFFLENBQUEsV0FBQUEsRUFBQSxXQUFBSCxFQUFBLElBQUFULENBQUEsQ0FBQVEsTUFBQSxLQUFBSyxJQUFBLFdBQUFBLElBQUEsTUFBQUMsS0FBQSxFQUFBZCxDQUFBLENBQUFTLEVBQUEsVUFBQVIsQ0FBQSxXQUFBQSxFQUFBRCxDQUFBLFVBQUFBLENBQUEsS0FBQWUsQ0FBQSxFQUFBTCxDQUFBLGdCQUFBTSxTQUFBLGlKQUFBQyxDQUFBLEVBQUFDLENBQUEsT0FBQUMsQ0FBQSxnQkFBQVIsQ0FBQSxXQUFBQSxFQUFBLElBQUFULENBQUEsR0FBQUEsQ0FBQSxD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