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
JavaScript
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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
;