UNPKG

kepler.gl

Version:

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

336 lines (322 loc) 39.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.checkDatasetNotExists = checkDatasetNotExists; exports.checkFieldNotExists = checkFieldNotExists; exports.getDatasetContext = getDatasetContext; exports.getGeometriesFromDataset = getGeometriesFromDataset; exports.getScatterplotValuesFromDataset = getScatterplotValuesFromDataset; exports.getValuesFromDataset = getValuesFromDataset; exports.highlightRows = highlightRows; exports.highlightRowsByColumnValues = highlightRowsByColumnValues; exports.interpolateColor = interpolateColor; exports.saveAsDataset = saveAsDataset; 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"); // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project /** * Check if the dataset exists * @param datasets The kepler.gl datasets * @param datasetName The name of the dataset * @param functionName The name of the function * @returns The result of the check */ function checkDatasetNotExists(datasets, datasetName, functionName) { var datasetId = Object.keys(datasets).find(function (dataId) { return datasets[dataId].label === datasetName; }); if (!datasetId) { return { name: functionName, result: { success: false, details: "Dataset not found. Please specify one from the following datasets: ".concat(Object.keys(datasets).join(', ')) } }; } return null; } /** * Check if the field exists * @param dataset The kepler.gl dataset * @param fieldName The name of the field * @param functionName The name of the function * @returns The result of the check */ function checkFieldNotExists(dataset, fieldName, functionName) { var field = dataset.fields.find(function (f) { return f.name === fieldName; }); if (!field) { return { type: 'layer', name: functionName, result: { success: false, details: "Field not found. Please specify one from the following fields: ".concat(dataset.fields.map(function (f) { return f.name; }).join(', ')) } }; } return null; } /** * 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, datasetName, variableName) { // find which dataset has the variableName var datasetId = Object.keys(datasets).find(function (dataId) { return datasets[dataId].label === datasetName; }); if (!datasetId) return []; var dataset = datasets[datasetId]; if (dataset) { return Array.from({ length: dataset.length }, function (_, i) { return dataset.getValue(variableName, i); }); } return []; } /** * Get the x and y values from a dataset for a scatterplot * @param datasets * @param datasetName * @param xVariableName * @param yVariableName * @returns {x: number[], y: number[]} */ function getScatterplotValuesFromDataset(datasets, datasetName, xVariableName, yVariableName) { var xValues = getValuesFromDataset(datasets, datasetName, xVariableName); var yValues = getValuesFromDataset(datasets, datasetName, yVariableName); return { x: xValues, y: yValues }; } /** * 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) { var context = 'Please remember the following dataset context:'; 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]; // get the index of the layer var layerIndex = layers.findIndex(function (layer) { return layer.config.dataId === dataset.id; }); if (layerIndex === -1) return []; var geometries = layerData[layerIndex]; return geometries === null || geometries === void 0 ? void 0 : geometries.data; } /** * 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, datasetName, data, addDataToMap) { // find datasetId from datasets var datasetId = Object.keys(datasets).find(function (dataId) { return datasets[dataId].label === datasetName; }); if (!datasetId) return; var leftDataset = datasets[datasetId]; var numRows = leftDataset.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 }; }))); // 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) { return leftDataset.getValue(field.name, rowIdx); }))); }); // create new dataset var newDatasetName = "".concat(datasetName, "_joined"); var newDataset = { info: { id: newDatasetName, label: newDatasetName }, data: { fields: fields, rows: rows } }; addDataToMap({ datasets: [newDataset], options: { autoCreateLayers: true, centerMap: true } }); } /** * 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); } } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfY29sb3JJbnRlcnBvbGF0ZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJyZXF1aXJlIiwiX2NvbnN0YW50cyIsImNoZWNrRGF0YXNldE5vdEV4aXN0cyIsImRhdGFzZXRzIiwiZGF0YXNldE5hbWUiLCJmdW5jdGlvbk5hbWUiLCJkYXRhc2V0SWQiLCJPYmplY3QiLCJrZXlzIiwiZmluZCIsImRhdGFJZCIsImxhYmVsIiwibmFtZSIsInJlc3VsdCIsInN1Y2Nlc3MiLCJkZXRhaWxzIiwiY29uY2F0Iiwiam9pbiIsImNoZWNrRmllbGROb3RFeGlzdHMiLCJkYXRhc2V0IiwiZmllbGROYW1lIiwiZmllbGQiLCJmaWVsZHMiLCJmIiwidHlwZSIsIm1hcCIsImludGVycG9sYXRlQ29sb3IiLCJvcmlnaW5hbENvbG9ycyIsIm51bWJlck9mQ29sb3JzIiwibGVuZ3RoIiwiaW50ZXJwIiwiaW50ZXJwb2xhdGUiLCJjb2xvcnMiLCJBcnJheSIsImZyb20iLCJfIiwiaiIsImhleENvbG9ycyIsImNvbG9yIiwicmdiIiwibWF0Y2giLCJjIiwicGFyc2VJbnQiLCJ0b1N0cmluZyIsInBhZFN0YXJ0IiwiZ2V0VmFsdWVzRnJvbURhdGFzZXQiLCJ2YXJpYWJsZU5hbWUiLCJpIiwiZ2V0VmFsdWUiLCJnZXRTY2F0dGVycGxvdFZhbHVlc0Zyb21EYXRhc2V0IiwieFZhcmlhYmxlTmFtZSIsInlWYXJpYWJsZU5hbWUiLCJ4VmFsdWVzIiwieVZhbHVlcyIsIngiLCJ5IiwiaGlnaGxpZ2h0Um93cyIsImxheWVycyIsInNlbGVjdGVkUm93SW5kaWNlcyIsImxheWVyU2V0SXNWYWxpZCIsImZpbHRlcmVkSW5kZXgiLCJhbGxJbmRleGVzIiwic2VsZWN0TGF5ZXJzIiwiZmlsdGVyIiwibGF5ZXIiLCJjb25maWciLCJpZCIsImZvckVhY2giLCJmb3JtYXRMYXllckRhdGEiLCJnZXREYXRhc2V0Q29udGV4dCIsImNvbnRleHQiLCJkYXRhTWV0YSIsInZhbHVlcyIsIl9kZWZpbmVQcm9wZXJ0eTIiLCJnZW9tZXRyeU1vZGUiLCJjb2x1bW5Nb2RlIiwiZ2VvbWV0cnlDb2x1bW5zIiwiZnJvbUVudHJpZXMiLCJlbnRyaWVzIiwiY29sdW1ucyIsIl9yZWYyIiwiX3JlZjMiLCJfc2xpY2VkVG9BcnJheTIiLCJ2YWx1ZSIsIl9yZWY0IiwiX3JlZjUiLCJrZXkiLCJfdHlwZW9mMiIsIl9yZWY2IiwiX3JlZjciLCJ2IiwiSlNPTiIsInN0cmluZ2lmeSIsImdldEdlb21ldHJpZXNGcm9tRGF0YXNldCIsImxheWVyRGF0YSIsImxheWVySW5kZXgiLCJmaW5kSW5kZXgiLCJnZW9tZXRyaWVzIiwiZGF0YSIsInNhdmVBc0RhdGFzZXQiLCJhZGREYXRhVG9NYXAiLCJsZWZ0RGF0YXNldCIsIm51bVJvd3MiLCJfdG9Db25zdW1hYmxlQXJyYXkyIiwiaW5kZXgiLCJkaXNwbGF5TmFtZSIsImRldGVybWluZUZpZWxkVHlwZSIsImRhdGFWYWx1ZXMiLCJyb3dzIiwiZmlsbCIsInJvd0lkeCIsImNvbCIsIm5ld0RhdGFzZXROYW1lIiwibmV3RGF0YXNldCIsImluZm8iLCJvcHRpb25zIiwiYXV0b0NyZWF0ZUxheWVycyIsImNlbnRlck1hcCIsIk51bWJlciIsImlzSW50ZWdlciIsIkFMTF9GSUVMRF9UWVBFUyIsImludGVnZXIiLCJyZWFsIiwic3RyaW5nIiwiaGlnaGxpZ2h0Um93c0J5Q29sdW1uVmFsdWVzIiwiY29sdW1uTmFtZSIsInNlbGVjdGVkVmFsdWVzIiwidmFsdWVEaWN0IiwicmVkdWNlIiwiYWNjIiwic2VsZWN0ZWRJbmRpY2VzIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3Rvb2xzL3V0aWxzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVRcbi8vIENvcHlyaWdodCBjb250cmlidXRvcnMgdG8gdGhlIGtlcGxlci5nbCBwcm9qZWN0XG5cbmltcG9ydCBpbnRlcnBvbGF0ZSBmcm9tICdjb2xvci1pbnRlcnBvbGF0ZSc7XG5cbmltcG9ydCB7TGF5ZXJ9IGZyb20gJ0BrZXBsZXIuZ2wvbGF5ZXJzJztcbmltcG9ydCB7RGF0YXNldHMsIEtlcGxlclRhYmxlfSBmcm9tICdAa2VwbGVyLmdsL3RhYmxlJztcbmltcG9ydCB7U3BhdGlhbEpvaW5HZW9tZXRyaWVzfSBmcm9tICdAb3BlbmFzc2lzdGFudC9nZW9kYSc7XG5pbXBvcnQge0FMTF9GSUVMRF9UWVBFU30gZnJvbSAnQGtlcGxlci5nbC9jb25zdGFudHMnO1xuaW1wb3J0IHtBZGREYXRhVG9NYXBQYXlsb2FkLCBQcm90b0RhdGFzZXQsIFByb3RvRGF0YXNldEZpZWxkfSBmcm9tICdAa2VwbGVyLmdsL3R5cGVzJztcblxuLyoqXG4gKiBDaGVjayBpZiB0aGUgZGF0YXNldCBleGlzdHNcbiAqIEBwYXJhbSBkYXRhc2V0cyBUaGUga2VwbGVyLmdsIGRhdGFzZXRzXG4gKiBAcGFyYW0gZGF0YXNldE5hbWUgVGhlIG5hbWUgb2YgdGhlIGRhdGFzZXRcbiAqIEBwYXJhbSBmdW5jdGlvbk5hbWUgVGhlIG5hbWUgb2YgdGhlIGZ1bmN0aW9uXG4gKiBAcmV0dXJucyBUaGUgcmVzdWx0IG9mIHRoZSBjaGVja1xuICovXG5leHBvcnQgZnVuY3Rpb24gY2hlY2tEYXRhc2V0Tm90RXhpc3RzKFxuICBkYXRhc2V0czogRGF0YXNldHMsXG4gIGRhdGFzZXROYW1lOiBzdHJpbmcsXG4gIGZ1bmN0aW9uTmFtZTogc3RyaW5nXG4pIHtcbiAgY29uc3QgZGF0YXNldElkID0gT2JqZWN0LmtleXMoZGF0YXNldHMpLmZpbmQoZGF0YUlkID0+IGRhdGFzZXRzW2RhdGFJZF0ubGFiZWwgPT09IGRhdGFzZXROYW1lKTtcbiAgaWYgKCFkYXRhc2V0SWQpIHtcbiAgICByZXR1cm4ge1xuICAgICAgbmFtZTogZnVuY3Rpb25OYW1lLFxuICAgICAgcmVzdWx0OiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBkZXRhaWxzOiBgRGF0YXNldCBub3QgZm91bmQuIFBsZWFzZSBzcGVjaWZ5IG9uZSBmcm9tIHRoZSBmb2xsb3dpbmcgZGF0YXNldHM6ICR7T2JqZWN0LmtleXMoXG4gICAgICAgICAgZGF0YXNldHNcbiAgICAgICAgKS5qb2luKCcsICcpfWBcbiAgICAgIH1cbiAgICB9O1xuICB9XG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIENoZWNrIGlmIHRoZSBmaWVsZCBleGlzdHNcbiAqIEBwYXJhbSBkYXRhc2V0IFRoZSBrZXBsZXIuZ2wgZGF0YXNldFxuICogQHBhcmFtIGZpZWxkTmFtZSBUaGUgbmFtZSBvZiB0aGUgZmllbGRcbiAqIEBwYXJhbSBmdW5jdGlvbk5hbWUgVGhlIG5hbWUgb2YgdGhlIGZ1bmN0aW9uXG4gKiBAcmV0dXJucyBUaGUgcmVzdWx0IG9mIHRoZSBjaGVja1xuICovXG5leHBvcnQgZnVuY3Rpb24gY2hlY2tGaWVsZE5vdEV4aXN0cyhkYXRhc2V0OiBLZXBsZXJUYWJsZSwgZmllbGROYW1lOiBzdHJpbmcsIGZ1bmN0aW9uTmFtZTogc3RyaW5nKSB7XG4gIGNvbnN0IGZpZWxkID0gZGF0YXNldC5maWVsZHMuZmluZChmID0+IGYubmFtZSA9PT0gZmllbGROYW1lKTtcbiAgaWYgKCFmaWVsZCkge1xuICAgIHJldHVybiB7XG4gICAgICB0eXBlOiAnbGF5ZXInLFxuICAgICAgbmFtZTogZnVuY3Rpb25OYW1lLFxuICAgICAgcmVzdWx0OiB7XG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBkZXRhaWxzOiBgRmllbGQgbm90IGZvdW5kLiBQbGVhc2Ugc3BlY2lmeSBvbmUgZnJvbSB0aGUgZm9sbG93aW5nIGZpZWxkczogJHtkYXRhc2V0LmZpZWxkc1xuICAgICAgICAgIC5tYXAoZiA9PiBmLm5hbWUpXG4gICAgICAgICAgLmpvaW4oJywgJyl9YFxuICAgICAgfVxuICAgIH07XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogSW50ZXJwb2xhdGUgdGhlIGNvbG9ycyBmcm9tIHRoZSBvcmlnaW5hbCBjb2xvcnMgd2l0aCB0aGUgZ2l2ZW4gbnVtYmVyIG9mIGNvbG9yc1xuICogQHBhcmFtIG9yaWdpbmFsQ29sb3JzIFRoZSBvcmlnaW5hbCBjb2xvcnNcbiAqIEBwYXJhbSBudW1iZXJPZkNvbG9ycyBUaGUgbnVtYmVyIG9mIGNvbG9yc1xuICogQHJldHVybnMgVGhlIGludGVycG9sYXRlZCBjb2xvcnNcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGludGVycG9sYXRlQ29sb3Iob3JpZ2luYWxDb2xvcnM6IHN0cmluZ1tdLCBudW1iZXJPZkNvbG9yczogbnVtYmVyKSB7XG4gIGlmIChvcmlnaW5hbENvbG9ycy5sZW5ndGggPT09IG51bWJlck9mQ29sb3JzKSB7XG4gICAgcmV0dXJuIG9yaWdpbmFsQ29sb3JzO1xuICB9XG4gIGNvbnN0IGludGVycCA9IGludGVycG9sYXRlKG9yaWdpbmFsQ29sb3JzKTtcbiAgY29uc3QgY29sb3JzID0gQXJyYXkuZnJvbSh7bGVuZ3RoOiBudW1iZXJPZkNvbG9yc30sIChfLCBqKSA9PiBpbnRlcnAoaiAvIChudW1iZXJPZkNvbG9ycyAtIDEpKSk7XG4gIC8vIGNvbnZlcnQgY29sb3JzIGZyb20gJ3JnYigyNTUsIDI1NSwgMjU1KScgdG8gJyNmZmZmZmYnXG4gIGNvbnN0IGhleENvbG9ycyA9IGNvbG9ycy5tYXAoY29sb3IgPT4ge1xuICAgIGNvbnN0IHJnYiA9IGNvbG9yLm1hdGNoKC9cXGQrL2cpO1xuICAgIHJldHVybiBgIyR7cmdiPy5tYXAoYyA9PiBwYXJzZUludChjKS50b1N0cmluZygxNikucGFkU3RhcnQoMiwgJzAnKSkuam9pbignJyl9YDtcbiAgfSk7XG4gIHJldHVybiBoZXhDb2xvcnM7XG59XG5cbi8qKlxuICogR2V0IHRoZSB2YWx1ZXMgZnJvbSBhIGRhdGFzZXQgZm9yIGEgdmFyaWFibGVcbiAqIEBwYXJhbSBkYXRhc2V0c1xuICogQHBhcmFtIGRhdGFzZXROYW1lXG4gKiBAcGFyYW0gdmFyaWFibGVOYW1lXG4gKiBAcmV0dXJucyB7bnVtYmVyW119XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRWYWx1ZXNGcm9tRGF0YXNldChcbiAgZGF0YXNldHM6IERhdGFzZXRzLFxuICBkYXRhc2V0TmFtZTogc3RyaW5nLFxuICB2YXJpYWJsZU5hbWU6IHN0cmluZ1xuKTogbnVtYmVyW10ge1xuICAvLyBmaW5kIHdoaWNoIGRhdGFzZXQgaGFzIHRoZSB2YXJpYWJsZU5hbWVcbiAgY29uc3QgZGF0YXNldElkID0gT2JqZWN0LmtleXMoZGF0YXNldHMpLmZpbmQoZGF0YUlkID0+IGRhdGFzZXRzW2RhdGFJZF0ubGFiZWwgPT09IGRhdGFzZXROYW1lKTtcbiAgaWYgKCFkYXRhc2V0SWQpIHJldHVybiBbXTtcbiAgY29uc3QgZGF0YXNldCA9IGRhdGFzZXRzW2RhdGFzZXRJZF07XG4gIGlmIChkYXRhc2V0KSB7XG4gICAgcmV0dXJuIEFycmF5LmZyb20oe2xlbmd0aDogZGF0YXNldC5sZW5ndGh9LCAoXywgaSkgPT4gZGF0YXNldC5nZXRWYWx1ZSh2YXJpYWJsZU5hbWUsIGkpKTtcbiAgfVxuICByZXR1cm4gW107XG59XG5cbi8qKlxuICogR2V0IHRoZSB4IGFuZCB5IHZhbHVlcyBmcm9tIGEgZGF0YXNldCBmb3IgYSBzY2F0dGVycGxvdFxuICogQHBhcmFtIGRhdGFzZXRzXG4gKiBAcGFyYW0gZGF0YXNldE5hbWVcbiAqIEBwYXJhbSB4VmFyaWFibGVOYW1lXG4gKiBAcGFyYW0geVZhcmlhYmxlTmFtZVxuICogQHJldHVybnMge3g6IG51bWJlcltdLCB5OiBudW1iZXJbXX1cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFNjYXR0ZXJwbG90VmFsdWVzRnJvbURhdGFzZXQoXG4gIGRhdGFzZXRzOiBEYXRhc2V0cyxcbiAgZGF0YXNldE5hbWU6IHN0cmluZyxcbiAgeFZhcmlhYmxlTmFtZTogc3RyaW5nLFxuICB5VmFyaWFibGVOYW1lOiBzdHJpbmdcbik6IHt4OiBudW1iZXJbXTsgeTogbnVtYmVyW119IHtcbiAgY29uc3QgeFZhbHVlcyA9IGdldFZhbHVlc0Zyb21EYXRhc2V0KGRhdGFzZXRzLCBkYXRhc2V0TmFtZSwgeFZhcmlhYmxlTmFtZSk7XG4gIGNvbnN0IHlWYWx1ZXMgPSBnZXRWYWx1ZXNGcm9tRGF0YXNldChkYXRhc2V0cywgZGF0YXNldE5hbWUsIHlWYXJpYWJsZU5hbWUpO1xuICByZXR1cm4ge3g6IHhWYWx1ZXMsIHk6IHlWYWx1ZXN9O1xufVxuXG4vKipcbiAqIEhpZ2hsaWdodCB0aGUgcm93cyBpbiBhIGRhdGFzZXRcbiAqIEBwYXJhbSBkYXRhc2V0cyBUaGUga2VwbGVyLmdsIGRhdGFzZXRzXG4gKiBAcGFyYW0gbGF5ZXJzIFRoZSBrZXBsZXIuZ2wgbGF5ZXJzXG4gKiBAcGFyYW0gZGF0YXNldE5hbWUgVGhlIG5hbWUgb2YgdGhlIGRhdGFzZXRcbiAqIEBwYXJhbSBzZWxlY3RlZFJvd0luZGljZXMgVGhlIGluZGljZXMgb2YgdGhlIHJvd3MgdG8gaGlnaGxpZ2h0XG4gKiBAcGFyYW0gbGF5ZXJTZXRJc1ZhbGlkIFRoZSBmdW5jdGlvbiB0byBzZXQgdGhlIGxheWVyIHZhbGlkaXR5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBoaWdobGlnaHRSb3dzKFxuICBkYXRhc2V0czogRGF0YXNldHMsXG4gIGxheWVyczogTGF5ZXJbXSxcbiAgZGF0YXNldE5hbWU6IHN0cmluZyxcbiAgc2VsZWN0ZWRSb3dJbmRpY2VzOiBudW1iZXJbXSxcbiAgbGF5ZXJTZXRJc1ZhbGlkOiAobGF5ZXI6IExheWVyLCBpc1ZhbGlkOiBib29sZWFuKSA9PiB2b2lkXG4pIHtcbiAgLy8gdXBkYXRlIHRoZSBmaWx0ZXJlZEluZGV4IGluIHRoZSBkYXRhc2V0XG4gIGNvbnN0IGRhdGFzZXRJZCA9IE9iamVjdC5rZXlzKGRhdGFzZXRzKS5maW5kKGRhdGFJZCA9PiBkYXRhc2V0c1tkYXRhSWRdLmxhYmVsID09PSBkYXRhc2V0TmFtZSk7XG4gIGlmICghZGF0YXNldElkKSByZXR1cm47XG4gIGNvbnN0IGRhdGFzZXQgPSBkYXRhc2V0c1tkYXRhc2V0SWRdO1xuICBpZiAoZGF0YXNldCkge1xuICAgIGRhdGFzZXQuZmlsdGVyZWRJbmRleCA9XG4gICAgICBzZWxlY3RlZFJvd0luZGljZXMubGVuZ3RoID09PSAwID8gZGF0YXNldC5hbGxJbmRleGVzIDogc2VsZWN0ZWRSb3dJbmRpY2VzO1xuICAgIC8vIGdldCBhbGwgbGF5ZXJzIHRoYXQgdXNlIHRoaXMgZGF0YXNldFxuICAgIGNvbnN0IHNlbGVjdExheWVycyA9IGxheWVycy5maWx0ZXIobGF5ZXIgPT4gbGF5ZXIuY29uZmlnLmRhdGFJZCA9PT0gZGF0YXNldC5pZCk7XG4gICAgc2VsZWN0TGF5ZXJzLmZvckVhY2gobGF5ZXIgPT4ge1xuICAgICAgbGF5ZXIuZm9ybWF0TGF5ZXJEYXRhKGRhdGFzZXRzKTtcbiAgICAgIC8vIHRyaWdnZXIgYSByZS1yZW5kZXIgdXNpbmcgbGF5ZXJTZXRJc1ZhbGlkKCkgdG8gdXBkYXRlIHRoZSB0b3AgbGF5ZXJcbiAgICAgIGxheWVyU2V0SXNWYWxpZChsYXllciwgdHJ1ZSk7XG4gICAgfSk7XG4gIH1cbn1cblxuLyoqXG4gKiBHZXQgdGhlIGRhdGFzZXQgY29udGV4dCwgd2hpY2ggaXMgdXNlZCB0byBwcm92aWRlIHRoZSBkYXRhc2V0IGluZm9ybWF0aW9uIHRvIHRoZSBBSSBhc3Npc3RhbnRcbiAqIEBwYXJhbSBkYXRhc2V0cyBUaGUga2VwbGVyLmdsIGRhdGFzZXRzXG4gKiBAcGFyYW0gbGF5ZXJzIFRoZSBrZXBsZXIuZ2wgbGF5ZXJzXG4gKiBAcmV0dXJucyBUaGUgZGF0YXNldCBjb250ZXh0XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXREYXRhc2V0Q29udGV4dChkYXRhc2V0czogRGF0YXNldHMsIGxheWVyczogTGF5ZXJbXSkge1xuICBjb25zdCBjb250ZXh0ID0gJ1BsZWFzZSByZW1lbWJlciB0aGUgZm9sbG93aW5nIGRhdGFzZXQgY29udGV4dDonO1xuICBjb25zdCBkYXRhTWV0YSA9IE9iamVjdC52YWx1ZXMoZGF0YXNldHMpLm1hcCgoZGF0YXNldDogS2VwbGVyVGFibGUpID0+ICh7XG4gICAgZGF0YXNldE5hbWU6IGRhdGFzZXQubGFiZWwsXG4gICAgZGF0YXNldElkOiBkYXRhc2V0LmlkLFxuICAgIGZpZWxkczogZGF0YXNldC5maWVsZHMubWFwKGZpZWxkID0+ICh7W2ZpZWxkLm5hbWVdOiBmaWVsZC50eXBlfSkpLFxuICAgIGxheWVyczogbGF5ZXJzXG4gICAgICAuZmlsdGVyKGxheWVyID0+IGxheWVyLmNvbmZpZy5kYXRhSWQgPT09IGRhdGFzZXQuaWQpXG4gICAgICAubWFwKGxheWVyID0+ICh7XG4gICAgICAgIGlkOiBsYXllci5pZCxcbiAgICAgICAgbGFiZWw6IGxheWVyLmNvbmZpZy5sYWJlbCxcbiAgICAgICAgdHlwZTogbGF5ZXIudHlwZSxcbiAgICAgICAgZ2VvbWV0cnlNb2RlOiBsYXllci5jb25maWcuY29sdW1uTW9kZSxcbiAgICAgICAgLy8gZ2V0IHRoZSB2YWxpZCBnZW9tZXRyeSBjb2x1bW5zIGFzIHN0cmluZ1xuICAgICAgICBnZW9tZXRyeUNvbHVtbnM6IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgICAgICBPYmplY3QuZW50cmllcyhsYXllci5jb25maWcuY29sdW1ucylcbiAgICAgICAgICAgIC5maWx0ZXIoKFssIHZhbHVlXSkgPT4gdmFsdWUgIT09IG51bGwpXG4gICAgICAgICAgICAubWFwKChba2V5LCB2YWx1ZV0pID0+IFtcbiAgICAgICAgICAgICAga2V5LFxuICAgICAgICAgICAgICB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlICE9PSBudWxsXG4gICAgICAgICAgICAgICAgPyBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXModmFsdWUpLmZpbHRlcigoWywgdl0pID0+IHYgIT09IG51bGwpKVxuICAgICAgICAgICAgICAgIDogdmFsdWVcbiAgICAgICAgICAgIF0pXG4gICAgICAgIClcbiAgICAgIH0pKVxuICB9KSk7XG4gIHJldHVybiBgJHtjb250ZXh0fVxcbiR7SlNPTi5zdHJpbmdpZnkoZGF0YU1ldGEpfWA7XG59XG5cbi8qKlxuICogR2V0IHRoZSBnZW9tZXRyaWVzIGZyb20gYSBkYXRhc2V0XG4gKiBAcGFyYW0gZGF0YXNldHMgVGhlIGtlcGxlci5nbCBkYXRhc2V0c1xuICogQHBhcmFtIGxheWVycyBUaGUga2VwbGVyLmdsIGxheWVyc1xuICogQHBhcmFtIGxheWVyRGF0YSBUaGUgbGF5ZXIgZGF0YVxuICogQHBhcmFtIGRhdGFzZXROYW1lIFRoZSBuYW1lIG9mIHRoZSBkYXRhc2V0XG4gKiBAcmV0dXJucyBUaGUgZ2VvbWV0cmllc1xuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0R2VvbWV0cmllc0Zyb21EYXRhc2V0KFxuICBkYXRhc2V0czogRGF0YXNldHMsXG4gIGxheWVyczogTGF5ZXJbXSxcbiAgbGF5ZXJEYXRhOiBhbnlbXSxcbiAgZGF0YXNldE5hbWU6IHN0cmluZ1xuKTogU3BhdGlhbEpvaW5HZW9tZXRyaWVzIHtcbiAgY29uc3QgZGF0YXNldElkID0gT2JqZWN0LmtleXMoZGF0YXNldHMpLmZpbmQoZGF0YUlkID0+IGRhdGFzZXRzW2RhdGFJZF0ubGFiZWwgPT09IGRhdGFzZXROYW1lKTtcbiAgaWYgKCFkYXRhc2V0SWQpIHJldHVybiBbXTtcbiAgY29uc3QgZGF0YXNldCA9IGRhdGFzZXRzW2RhdGFzZXRJZF07XG5cbiAgLy8gZ2V0IHRoZSBpbmRleCBvZiB0aGUgbGF5ZXJcbiAgY29uc3QgbGF5ZXJJbmRleCA9IGxheWVycy5maW5kSW5kZXgobGF5ZXIgPT4gbGF5ZXIuY29uZmlnLmRhdGFJZCA9PT0gZGF0YXNldC5pZCk7XG4gIGlmIChsYXllckluZGV4ID09PSAtMSkgcmV0dXJuIFtdO1xuXG4gIGNvbnN0IGdlb21ldHJpZXMgPSBsYXllckRhdGFbbGF5ZXJJbmRleF07XG5cbiAgcmV0dXJuIGdlb21ldHJpZXM/LmRhdGE7XG59XG5cbi8qKlxuICogU2F2ZSB0aGUgZGF0YSBhcyBhIG5ldyBkYXRhc2V0IGJ5IGpvaW5pbmcgaXQgd2l0aCB0aGUgbGVmdCBkYXRhc2V0XG4gKiBAcGFyYW0gZGF0YXNldHMgVGhlIGtlcGxlci5nbCBkYXRhc2V0c1xuICogQHBhcmFtIGRhdGFzZXROYW1lIFRoZSBuYW1lIG9mIHRoZSBsZWZ0IGRhdGFzZXRcbiAqIEBwYXJhbSBkYXRhIFRoZSBkYXRhIHRvIHNhdmVcbiAqIEBwYXJhbSBhZGREYXRhVG9NYXAgVGhlIGZ1bmN0aW9uIHRvIGFkZCB0aGUgZGF0YSB0byB0aGUgbWFwXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzYXZlQXNEYXRhc2V0KFxuICBkYXRhc2V0czogRGF0YXNldHMsXG4gIGRhdGFzZXROYW1lOiBzdHJpbmcsXG4gIGRhdGE6IFJlY29yZDxzdHJpbmcsIG51bWJlcltdPixcbiAgYWRkRGF0YVRvTWFwOiAoZGF0YTogQWRkRGF0YVRvTWFwUGF5bG9hZCkgPT4gdm9pZFxuKSB7XG4gIC8vIGZpbmQgZGF0YXNldElkIGZyb20gZGF0YXNldHNcbiAgY29uc3QgZGF0YXNldElkID0gT2JqZWN0LmtleXMoZGF0YXNldHMpLmZpbmQoZGF0YUlkID0+IGRhdGFzZXRzW2RhdGFJZF0ubGFiZWwgPT09IGRhdGFzZXROYW1lKTtcbiAgaWYgKCFkYXRhc2V0SWQpIHJldHVybjtcblxuICBjb25zdCBsZWZ0RGF0YXNldCA9IGRhdGFzZXRzW2RhdGFzZXRJZF07XG4gIGNvbnN0IG51bVJvd3MgPSBsZWZ0RGF0YXNldC5sZW5ndGg7XG5cbiAgY29uc3QgZmllbGRzOiBQcm90b0RhdGFzZXRGaWVsZFtdID0gW1xuICAgIC8vIE5ldyBmaWVsZHMgZnJvbSBkYXRhXG4gICAgLi4uT2JqZWN0LmtleXMoZGF0YSkubWFwKChmaWVsZE5hbWUsIGluZGV4KSA9PiAoe1xuICAgICAgbmFtZTogZmllbGROYW1lLFxuICAgICAgaWQ6IGAke2ZpZWxkTmFtZX1fJHtpbmRleH1gLFxuICAgICAgZGlzcGxheU5hbWU6IGZpZWxkTmFtZSxcbiAgICAgIHR5cGU6IGRldGVybWluZUZpZWxkVHlwZShkYXRhW2ZpZWxkTmFtZV1bMF0pXG4gICAgfSkpLFxuICAgIC8vIEV4aXN0aW5nIGZpZWxkcyBmcm9tIGxlZnREYXRhc2V0XG4gICAgLi4ubGVmdERhdGFzZXQuZmllbGRzLm1hcCgoZmllbGQsIGluZGV4KSA9PiAoe1xuICAgICAgbmFtZTogZmllbGQubmFtZSxcbiAgICAgIGlkOiBmaWVsZC5pZCB8fCBgJHtmaWVsZC5uYW1lfV8ke2luZGV4fWAsXG4gICAgICBkaXNwbGF5TmFtZTogZmllbGQuZGlzcGxheU5hbWUsXG4gICAgICB0eXBlOiBmaWVsZC50eXBlXG4gICAgfSkpXG4gIF07XG5cbiAgLy8gUHJlLWNhbGN1bGF0ZSBkYXRhIHZhbHVlcyBhcnJheVxuICBjb25zdCBkYXRhVmFsdWVzID0gT2JqZWN0LnZhbHVlcyhkYXRhKTtcblxuICBjb25zdCByb3dzID0gQXJyYXkobnVtUm93cylcbiAgICAuZmlsbChudWxsKVxuICAgIC5tYXAoKF8sIHJvd0lkeCkgPT4gW1xuICAgICAgLy8gTmV3IGRhdGEgdmFsdWVzXG4gICAgICAuLi5kYXRhVmFsdWVzLm1hcChjb2wgPT4gY29sW3Jvd0lkeF0pLFxuICAgICAgLy8gRXhpc3RpbmcgZGF0YXNldCB2YWx1ZXNcbiAgICAgIC4uLmxlZnREYXRhc2V0LmZpZWxkcy5tYXAoZmllbGQgPT4gbGVmdERhdGFzZXQuZ2V0VmFsdWUoZmllbGQubmFtZSwgcm93SWR4KSlcbiAgICBdKTtcblxuICAvLyBjcmVhdGUgbmV3IGRhdGFzZXRcbiAgY29uc3QgbmV3RGF0YXNldE5hbWUgPSBgJHtkYXRhc2V0TmFtZX1fam9pbmVkYDtcbiAgY29uc3QgbmV3RGF0YXNldDogUHJvdG9EYXRhc2V0ID0ge1xuICAgIGluZm86IHtcbiAgICAgIGlkOiBuZXdEYXRhc2V0TmFtZSxcbiAgICAgIGxhYmVsOiBuZXdEYXRhc2V0TmFtZVxuICAgIH0sXG4gICAgZGF0YToge1xuICAgICAgZmllbGRzLFxuICAgICAgcm93c1xuICAgIH1cbiAgfTtcblxuICBhZGREYXRhVG9NYXAoe2RhdGFzZXRzOiBbbmV3RGF0YXNldF0sIG9wdGlvbnM6IHthdXRvQ3JlYXRlTGF5ZXJzOiB0cnVlLCBjZW50ZXJNYXA6IHRydWV9fSk7XG59XG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRvIGRldGVybWluZSBmaWVsZCB0eXBlXG4gKiBAcGFyYW0gdmFsdWUgVGhlIHZhbHVlIHRvIGRldGVybWluZSB0aGUgZmllbGQgdHlwZVxuICogQHJldHVybnMgVGhlIGZpZWxkIHR5cGVcbiAqL1xuZnVuY3Rpb24gZGV0ZXJtaW5lRmllbGRUeXBlKHZhbHVlOiB1bmtub3duKToga2V5b2YgdHlwZW9mIEFMTF9GSUVMRF9UWVBFUyB7XG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInXG4gICAgPyBOdW1iZXIuaXNJbnRlZ2VyKHZhbHVlKVxuICAgICAgPyBBTExfRklFTERfVFlQRVMuaW50ZWdlclxuICAgICAgOiBBTExfRklFTERfVFlQRVMucmVhbFxuICAgIDogQUxMX0ZJRUxEX1RZUEVTLnN0cmluZztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGhpZ2hsaWdodFJvd3NCeUNvbHVtblZhbHVlcyhcbiAgZGF0YXNldHM6IERhdGFzZXRzLFxuICBsYXllcnM6IExheWVyW10sXG4gIGRhdGFzZXROYW1lOiBzdHJpbmcsXG4gIGNvbHVtbk5hbWU6IHN0cmluZyxcbiAgc2VsZWN0ZWRWYWx1ZXM6IHVua25vd25bXSxcbiAgbGF5ZXJTZXRJc1ZhbGlkOiAobGF5ZXI6IExheWVyLCBpc1ZhbGlkOiBib29sZWFuKSA9PiB2b2lkXG4pIHtcbiAgY29uc3QgZGF0YXNldElkID0gT2JqZWN0LmtleXMoZGF0YXNldHMpLmZpbmQoZGF0YUlkID0+IGRhdGFzZXRzW2RhdGFJZF0ubGFiZWwgPT09IGRhdGFzZXROYW1lKTtcbiAgaWYgKCFkYXRhc2V0SWQpIHJldHVybjtcbiAgY29uc3QgZGF0YXNldCA9IGRhdGFzZXRzW2RhdGFzZXRJZF07XG4gIGlmIChkYXRhc2V0KSB7XG4gICAgLy8gZ2V0IHRoZSB2YWx1ZXMgb2YgdGhlIGNvbHVtblxuICAgIGNvbnN0IHZhbHVlcyA9IEFycmF5LmZyb20oe2xlbmd0aDogZGF0YXNldC5sZW5ndGh9LCAoXywgaSkgPT4gZGF0YXNldC5nZXRWYWx1ZShjb2x1bW5OYW1lLCBpKSk7XG4gICAgLy8gY3JlYXRlIGEgZGljdCB1c2luZyB0aGUgdmFsdWVzXG4gICAgY29uc3QgdmFsdWVEaWN0ID0gdmFsdWVzLnJlZHVjZSgoYWNjLCB2YWx1ZSwgaW5kZXgpID0+IHtcbiAgICAgIGFjY1t2YWx1ZV0gPSBpbmRleDtcbiAgICAgIHJldHVybiBhY2M7XG4gICAgfSwge30pO1xuICAgIC8vIG5lZWQgdG8gZml4IHRoZSB0eXBlIGVycm9yIG9mIHZhbHVlIGhlcmVcbiAgICBjb25zdCBzZWxlY3RlZEluZGljZXMgPSBzZWxlY3RlZFZhbHVlcy5tYXAodmFsdWUgPT4gdmFsdWVEaWN0W3ZhbHVlIGFzIGFueV0pO1xuICAgIC8vIGhpZ2hsaWdodCB0aGUgcm93c1xuICAgIGhpZ2hsaWdodFJvd3MoZGF0YXNldHMsIGxheWVycywgZGF0YXNldE5hbWUsIHNlbGVjdGVkSW5kaWNlcywgbGF5ZXJTZXRJc1ZhbGlkKTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUdBLElBQUFBLGlCQUFBLEdBQUFDLHNCQUFBLENBQUFDLE9BQUE7QUFLQSxJQUFBQyxVQUFBLEdBQUFELE9BQUE7QUFSQTtBQUNBOztBQVVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ08sU0FBU0UscUJBQXFCQSxDQUNuQ0MsUUFBa0IsRUFDbEJDLFdBQW1CLEVBQ25CQyxZQUFvQixFQUNwQjtFQUNBLElBQU1DLFNBQVMsR0FBR0MsTUFBTSxDQUFDQyxJQUFJLENBQUNMLFFBQVEsQ0FBQyxDQUFDTSxJQUFJLENBQUMsVUFBQUMsTUFBTTtJQUFBLE9BQUlQLFFBQVEsQ0FBQ08sTUFBTSxDQUFDLENBQUNDLEtBQUssS0FBS1AsV0FBVztFQUFBLEVBQUM7RUFDOUYsSUFBSSxDQUFDRSxTQUFTLEVBQUU7SUFDZCxPQUFPO01BQ0xNLElBQUksRUFBRVAsWUFBWTtNQUNsQlEsTUFBTSxFQUFFO1FBQ05DLE9BQU8sRUFBRSxLQUFLO1FBQ2RD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