UNPKG

kepler.gl

Version:

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

449 lines (366 loc) 42.4 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties'); var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2); var _defineProperty2 = require('babel-runtime/helpers/defineProperty'); var _defineProperty3 = _interopRequireDefault(_defineProperty2); var _extends3 = require('babel-runtime/helpers/extends'); var _extends4 = _interopRequireDefault(_extends3); var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray'); var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2); exports.mergeFilters = mergeFilters; exports.mergeLayers = mergeLayers; exports.mergeInteractions = mergeInteractions; exports.mergeInteractionTooltipConfig = mergeInteractionTooltipConfig; exports.mergeLayerBlending = mergeLayerBlending; exports.validateSavedLayerColumns = validateSavedLayerColumns; exports.validateSavedVisualChannels = validateSavedVisualChannels; exports.validateLayerWithData = validateLayerWithData; exports.validateFilterWithData = validateFilterWithData; var _lodash = require('lodash.uniq'); var _lodash2 = _interopRequireDefault(_lodash); var _lodash3 = require('lodash.pick'); var _lodash4 = _interopRequireDefault(_lodash3); var _filterUtils = require('../utils/filter-utils'); var _defaultSettings = require('../constants/default-settings'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Merge loaded filters with current state, if no fields or data are loaded * save it for later * * @param {Object} state * @param {Object[]} filtersToMerge * @return {Object} updatedState */ // Copyright (c) 2018 Uber Technologies, Inc. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to deal // in the Software without restriction, including without limitation the rights // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell // copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. function mergeFilters(state, filtersToMerge) { var merged = []; var unmerged = []; var datasets = state.datasets; if (!Array.isArray(filtersToMerge) || !filtersToMerge.length) { return state; } // merge filters filtersToMerge.forEach(function (filter) { // match filter.dataId with current datesets id // uploaded data need to have the same dataId with the filter if (datasets[filter.dataId]) { // datasets is already loaded var validateFilter = validateFilterWithData(datasets[filter.dataId], filter); if (validateFilter) { merged.push(validateFilter); } } else { // datasets not yet loaded unmerged.push(filter); } }); // filter data var updatedFilters = [].concat((0, _toConsumableArray3.default)(state.filters || []), merged); var datasetToFilter = (0, _lodash2.default)(merged.map(function (d) { return d.dataId; })); var updatedDataset = datasetToFilter.reduce(function (accu, dataId) { return (0, _extends4.default)({}, accu, (0, _defineProperty3.default)({}, dataId, (0, _extends4.default)({}, datasets[dataId], (0, _filterUtils.filterData)(datasets[dataId].allData, dataId, updatedFilters)))); }, datasets); return (0, _extends4.default)({}, state, { filters: updatedFilters, datasets: updatedDataset, filterToBeMerged: unmerged }); } /** * Merge layers from de-serialized state, if no fields or data are loaded * save it for later * * @param {object} state * @param {Object[]} layersToMerge * @return {Object} state */ function mergeLayers(state, layersToMerge) { var mergedLayer = []; var unmerged = []; var datasets = state.datasets; if (!Array.isArray(layersToMerge) || !layersToMerge.length) { return state; } layersToMerge.forEach(function (layer) { if (datasets[layer.config.dataId]) { // datasets are already loaded var validateLayer = validateLayerWithData(datasets[layer.config.dataId], layer, state.layerClasses); if (validateLayer) { mergedLayer.push(validateLayer); } } else { // datasets not yet loaded unmerged.push(layer); } }); var layers = [].concat((0, _toConsumableArray3.default)(state.layers), mergedLayer); var newLayerOrder = mergedLayer.map(function (_, i) { return state.layers.length + i; }); // put new layers in front of current layers var layerOrder = [].concat((0, _toConsumableArray3.default)(newLayerOrder), (0, _toConsumableArray3.default)(state.layerOrder)); return (0, _extends4.default)({}, state, { layers: layers, layerOrder: layerOrder, layerToBeMerged: unmerged }); } /** * Merge interactions with saved config * * @param {object} state * @param {Object} interactionToBeMerged * @return {Object} mergedState */ function mergeInteractions(state, interactionToBeMerged) { var merged = {}; var unmerged = {}; if (interactionToBeMerged) { Object.keys(interactionToBeMerged).forEach(function (key) { if (!state.interactionConfig[key]) { return; } var _ref = interactionToBeMerged[key] || {}, enabled = _ref.enabled, configSaved = (0, _objectWithoutProperties3.default)(_ref, ['enabled']); var configToMerge = configSaved; if (key === 'tooltip') { var _mergeInteractionTool = mergeInteractionTooltipConfig(state, configSaved), mergedTooltip = _mergeInteractionTool.mergedTooltip, unmergedTooltip = _mergeInteractionTool.unmergedTooltip; // merge new dataset tooltips with original dataset tooltips configToMerge = { fieldsToShow: (0, _extends4.default)({}, state.interactionConfig[key].config.fieldsToShow, mergedTooltip) }; if (Object.keys(unmergedTooltip).length) { unmerged.tooltip = { fieldsToShow: unmergedTooltip, enabled: enabled }; } } merged[key] = (0, _extends4.default)({}, state.interactionConfig[key], { enabled: enabled, config: (0, _lodash4.default)((0, _extends4.default)({}, state.interactionConfig[key].config, configToMerge), Object.keys(state.interactionConfig[key].config)) }); }); } return (0, _extends4.default)({}, state, { interactionConfig: (0, _extends4.default)({}, state.interactionConfig, merged), interactionToBeMerged: unmerged }); } /** * Merge interactionConfig.tooltip with saved config, * validate fieldsToShow * * @param {string} state * @param {Object} tooltipConfig * @return {Object} - {mergedTooltip: {}, unmergedTooltip: {}} */ function mergeInteractionTooltipConfig(state) { var tooltipConfig = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var unmergedTooltip = {}; var mergedTooltip = {}; if (!tooltipConfig.fieldsToShow || !Object.keys(tooltipConfig.fieldsToShow).length) { return { mergedTooltip: mergedTooltip, unmergedTooltip: unmergedTooltip }; } for (var dataId in tooltipConfig.fieldsToShow) { if (!state.datasets[dataId]) { // is not yet loaded unmergedTooltip[dataId] = tooltipConfig.fieldsToShow[dataId]; } else { (function () { // if dataset is loaded var allFields = state.datasets[dataId].fields.map(function (d) { return d.name; }); var foundFieldsToShow = tooltipConfig.fieldsToShow[dataId].filter(function (name) { return allFields.includes(name); }); mergedTooltip[dataId] = foundFieldsToShow; })(); } } return { mergedTooltip: mergedTooltip, unmergedTooltip: unmergedTooltip }; } /** * Merge layerBlending with saved * * @param {object} state * @param {string} layerBlending * @return {object} merged state */ function mergeLayerBlending(state, layerBlending) { if (layerBlending && _defaultSettings.LAYER_BLENDINGS[layerBlending]) { return (0, _extends4.default)({}, state, { layerBlending: layerBlending }); } return state; } /** * Validate saved layer columns with new data, * update fieldIdx based on new fields * * @param {Object[]} fields * @param {Object} savedCols * @param {Object} emptyCols * @return {null | Object} - validated columns or null */ function validateSavedLayerColumns(fields, savedCols, emptyCols) { var colFound = {}; // find actual column fieldIdx, in case it has changed var allColFound = Object.keys(emptyCols).every(function (key) { var saved = savedCols[key]; colFound[key] = (0, _extends4.default)({}, emptyCols[key]); var fieldIdx = fields.findIndex(function (_ref2) { var name = _ref2.name; return name === saved; }); if (fieldIdx > -1) { // update found columns colFound[key].fieldIdx = fieldIdx; colFound[key].value = saved; return true; } // if col is optional, allow null value return emptyCols[key].optional || false; }); return allColFound && colFound; } /** * Validate saved visual channels config with new data, * refer to vis-state-schema.js VisualChannelSchemaV1 * * @param {Object[]} fields * @param {Object} visualChannels * @param {Object} savedLayer * @return {Object} - validated visual channel in config or {} */ function validateSavedVisualChannels(fields, visualChannels, savedLayer) { return Object.values(visualChannels).reduce(function (found, _ref3) { var field = _ref3.field, scale = _ref3.scale; var foundField = void 0; if (savedLayer.config[field]) { foundField = fields.find(function (fd) { return Object.keys(savedLayer.config[field]).every(function (key) { return savedLayer.config[field][key] === fd[key]; }); }); } return (0, _extends4.default)({}, found, foundField ? (0, _defineProperty3.default)({}, field, foundField) : {}, savedLayer.config[scale] ? (0, _defineProperty3.default)({}, scale, savedLayer.config[scale]) : {}); }, {}); } /** * Validate saved layer config with new data, * update fieldIdx based on new fields * * @param {Object[]} fields * @param {String} dataId * @param {Object} savedLayer * @param {Object} layerClasses * @return {null | Object} - validated layer or null */ function validateLayerWithData(_ref6, savedLayer, layerClasses) { var fields = _ref6.fields, dataId = _ref6.id; var type = savedLayer.type; // layer doesnt have a valid type if (!layerClasses.hasOwnProperty(type) || !savedLayer.config || !savedLayer.config.columns) { return null; } var newLayer = new layerClasses[type]({ id: savedLayer.id, dataId: dataId, label: savedLayer.config.label, color: savedLayer.config.color, isVisible: savedLayer.config.isVisible }); // find column fieldIdx var columns = validateSavedLayerColumns(fields, savedLayer.config.columns, newLayer.getLayerColumns()); if (!columns) { return null; } // visual channel field is saved to be {name, type} // find visual channel field by matching both name and type // refer to vis-state-schema.js VisualChannelSchemaV1 var foundVisualChannelConfigs = validateSavedVisualChannels(fields, newLayer.visualChannels, savedLayer); // copy visConfig over to emptyLayer to make sure it has all the props var visConfig = newLayer.copyLayerConfig(newLayer.config.visConfig, savedLayer.config.visConfig || {}, { notToDeepMerge: 'colorRange' }); newLayer.updateLayerConfig((0, _extends4.default)({ columns: columns, visConfig: visConfig }, foundVisualChannelConfigs)); return newLayer; } /** * Validate saved filter config with new data, * calculate domain and fieldIdx based new fields and data * * @param {Object[]} dataset.fields * @param {Object[]} dataset.allData * @param {Object} filter - filter to be validate * @return {Object | null} - validated filter */ function validateFilterWithData(_ref7, filter) { var fields = _ref7.fields, allData = _ref7.allData; // match filter.name to field.name var fieldIdx = fields.findIndex(function (_ref8) { var name = _ref8.name; return name === filter.name; }); if (fieldIdx < 0) { // if can't find field with same name, discharge filter return null; } var field = fields[fieldIdx]; var value = filter.value; // return filter type, default value, fieldType and fieldDomain from field var filterPropsFromField = (0, _filterUtils.getFilterProps)(allData, field); var matchedFilter = (0, _extends4.default)({}, (0, _filterUtils.getDefaultFilter)(filter.dataId), filter, filterPropsFromField, { freeze: true, fieldIdx: fieldIdx }); var _matchedFilter = matchedFilter, yAxis = _matchedFilter.yAxis; if (yAxis) { var matcheAxis = fields.find(function (_ref9) { var name = _ref9.name, type = _ref9.type; return name === yAxis.name && type === yAxis.type; }); matchedFilter = matcheAxis ? (0, _extends4.default)({}, matchedFilter, { yAxis: matcheAxis }, (0, _filterUtils.getFilterPlot)((0, _extends4.default)({}, matchedFilter, { yAxis: matcheAxis }), allData)) : matchedFilter; } matchedFilter.value = (0, _filterUtils.adjustValueToFilterDomain)(value, matchedFilter); if (matchedFilter.value === null) { // cannt adjust saved value to filter return null; } return matchedFilter; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9yZWR1Y2Vycy92aXMtc3RhdGUtbWVyZ2VyLmpzIl0sIm5hbWVzIjpbIm1lcmdlRmlsdGVycyIsIm1lcmdlTGF5ZXJzIiwibWVyZ2VJbnRlcmFjdGlvbnMiLCJtZXJnZUludGVyYWN0aW9uVG9vbHRpcENvbmZpZyIsIm1lcmdlTGF5ZXJCbGVuZGluZyIsInZhbGlkYXRlU2F2ZWRMYXllckNvbHVtbnMiLCJ2YWxpZGF0ZVNhdmVkVmlzdWFsQ2hhbm5lbHMiLCJ2YWxpZGF0ZUxheWVyV2l0aERhdGEiLCJ2YWxpZGF0ZUZpbHRlcldpdGhEYXRhIiwic3RhdGUiLCJmaWx0ZXJzVG9NZXJnZSIsIm1lcmdlZCIsInVubWVyZ2VkIiwiZGF0YXNldHMiLCJBcnJheSIsImlzQXJyYXkiLCJsZW5ndGgiLCJmb3JFYWNoIiwiZmlsdGVyIiwiZGF0YUlkIiwidmFsaWRhdGVGaWx0ZXIiLCJwdXNoIiwidXBkYXRlZEZpbHRlcnMiLCJmaWx0ZXJzIiwiZGF0YXNldFRvRmlsdGVyIiwibWFwIiwiZCIsInVwZGF0ZWREYXRhc2V0IiwicmVkdWNlIiwiYWNjdSIsImFsbERhdGEiLCJmaWx0ZXJUb0JlTWVyZ2VkIiwibGF5ZXJzVG9NZXJnZSIsIm1lcmdlZExheWVyIiwibGF5ZXIiLCJjb25maWciLCJ2YWxpZGF0ZUxheWVyIiwibGF5ZXJDbGFzc2VzIiwibGF5ZXJzIiwibmV3TGF5ZXJPcmRlciIsIl8iLCJpIiwibGF5ZXJPcmRlciIsImxheWVyVG9CZU1lcmdlZCIsImludGVyYWN0aW9uVG9CZU1lcmdlZCIsIk9iamVjdCIsImtleXMiLCJpbnRlcmFjdGlvbkNvbmZpZyIsImtleSIsImVuYWJsZWQiLCJjb25maWdTYXZlZCIsImNvbmZpZ1RvTWVyZ2UiLCJtZXJnZWRUb29sdGlwIiwidW5tZXJnZWRUb29sdGlwIiwiZmllbGRzVG9TaG93IiwidG9vbHRpcCIsInRvb2x0aXBDb25maWciLCJhbGxGaWVsZHMiLCJmaWVsZHMiLCJuYW1lIiwiZm91bmRGaWVsZHNUb1Nob3ciLCJpbmNsdWRlcyIsImxheWVyQmxlbmRpbmciLCJMQVlFUl9CTEVORElOR1MiLCJzYXZlZENvbHMiLCJlbXB0eUNvbHMiLCJjb2xGb3VuZCIsImFsbENvbEZvdW5kIiwiZXZlcnkiLCJzYXZlZCIsImZpZWxkSWR4IiwiZmluZEluZGV4IiwidmFsdWUiLCJvcHRpb25hbCIsInZpc3VhbENoYW5uZWxzIiwic2F2ZWRMYXllciIsInZhbHVlcyIsImZvdW5kIiwiZmllbGQiLCJzY2FsZSIsImZvdW5kRmllbGQiLCJmaW5kIiwiZmQiLCJpZCIsInR5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNvbHVtbnMiLCJuZXdMYXllciIsImxhYmVsIiwiY29sb3IiLCJpc1Zpc2libGUiLCJnZXRMYXllckNvbHVtbnMiLCJmb3VuZFZpc3VhbENoYW5uZWxDb25maWdzIiwidmlzQ29uZmlnIiwiY29weUxheWVyQ29uZmlnIiwibm90VG9EZWVwTWVyZ2UiLCJ1cGRhdGVMYXllckNvbmZpZyIsImZpbHRlclByb3BzRnJvbUZpZWxkIiwibWF0Y2hlZEZpbHRlciIsImZyZWV6ZSIsInlBeGlzIiwibWF0Y2hlQXhpcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztRQXlDZ0JBLFksR0FBQUEsWTtRQTREQUMsVyxHQUFBQSxXO1FBaURBQyxpQixHQUFBQSxpQjtRQWdFQUMsNkIsR0FBQUEsNkI7UUFtQ0FDLGtCLEdBQUFBLGtCO1FBcUJBQyx5QixHQUFBQSx5QjtRQWdDQUMsMkIsR0FBQUEsMkI7UUFpQ0FDLHFCLEdBQUFBLHFCO1FBZ0VBQyxzQixHQUFBQSxzQjs7QUEzWGhCOzs7O0FBQ0E7Ozs7QUFFQTs7QUFRQTs7OztBQUVBOzs7Ozs7OztBQWpDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUF1Qk8sU0FBU1IsWUFBVCxDQUFzQlMsS0FBdEIsRUFBNkJDLGNBQTdCLEVBQTZD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NUI7QUFBQSxHQUFqQixDQUFqQjs7QUFFQSxNQUFJVyxXQUFXLENBQWYsRUFBa0I7QUFDaEI7QUFDQSxXQUFPLElBQVA7QUFDRDs7QUFFRCxNQUFNUSxRQUFRcEIsT0FBT1ksUUFBUCxDQUFkO0FBQ0EsTUFBTUUsUUFBUXRELE9BQU9zRCxLQUFyQjs7QUFFQTtBQUNBLE1BQU15Qix1QkFBdUIsaUNBQWVuRSxPQUFmLEVBQXdCZ0QsS0FBeEIsQ0FBN0I7O0FBRUEsTUFBSW9CLDJDQUNDLG1DQUFpQmhGLE9BQU9DLE1BQXhCLENBREQsRUFFQ0QsTUFGRCxFQUdDK0Usb0JBSEQ7QUFJRkUsWUFBUSxJQUpOO0FBS0Y3QjtBQUxFLElBQUo7O0FBZmdFLHVCQXVCaEQ0QixhQXZCZ0Q7QUFBQSxNQXVCekRFLEtBdkJ5RCxrQkF1QnpEQSxLQXZCeUQ7O0FBd0JoRSxNQUFJQSxLQUFKLEVBQVc7QUFDVCxRQUFNQyxhQUFhM0MsT0FBT3VCLElBQVAsQ0FDakI7QUFBQSxVQUFFdEIsSUFBRixTQUFFQSxJQUFGO0FBQUEsVUFBUXlCLElBQVIsU0FBUUEsSUFBUjtBQUFBLGFBQWtCekIsU0FBU3lDLE1BQU16QyxJQUFmLElBQXVCeUIsU0FBU2dCLE1BQU1oQixJQUF4RDtBQUFBLEtBRGlCLENBQW5COztBQUlBYyxvQkFBZ0JHLHdDQUVQSCxhQUZPO0FBR1ZFLGFBQU9DO0FBSEcsT0FJUCwyREFBa0JILGFBQWxCLElBQWlDRSxPQUFPQyxVQUF4QyxLQUFxRHZFLE9BQXJELENBSk8sSUFNWm9FLGFBTko7QUFPRDs7QUFFREEsZ0JBQWMxQixLQUFkLEdBQXNCLDRDQUEwQkEsS0FBMUIsRUFBaUMwQixhQUFqQyxDQUF0Qjs7QUFFQSxNQUFJQSxjQUFjMUIsS0FBZCxLQUF3QixJQUE1QixFQUFrQztBQUNoQztBQUNBLFdBQU8sSUFBUDtBQUNEOztBQUVELFNBQU8wQixhQUFQO0FBQ0QiLCJmaWxlIjoidmlzLXN0YXRlLW1lcmdlci5qcyIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAoYykgMjAxOCBVYmVyIFRlY2hub2xvZ2llcywgSW5jLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbi8vIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbi8vIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbi8vIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxuLy8gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB1bmlxIGZyb20gJ2xvZGFzaC51bmlxJztcbmltcG9ydCBwaWNrIGZyb20gJ2xvZGFzaC5waWNrJztcblxuaW1wb3J0IHtcbiAgZ2V0RGVmYXVsdEZpbHRlcixcbiAgZ2V0RmlsdGVyUHJvcHMsXG4gIGdldEZpbHRlclBsb3QsXG4gIGZpbHRlckRhdGEsXG4gIGFkanVzdFZhbHVlVG9GaWx0ZXJEb21haW5cbn0gZnJvbSAndXRpbHMvZmlsdGVyLXV0aWxzJztcblxuaW1wb3J0IHtMQVlFUl9CTEVORElOR1N9IGZyb20gJ2NvbnN0YW50cy9kZWZhdWx0LXNldHRpbmdzJztcblxuLyoqXG4gKiBNZXJnZSBsb2FkZWQgZmlsdGVycyB3aXRoIGN1cnJlbnQgc3RhdGUsIGlmIG5vIGZpZWxkcyBvciBkYXRhIGFyZSBsb2FkZWRcbiAqIHNhdmUgaXQgZm9yIGxhdGVyXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHN0YXRlXG4gKiBAcGFyYW0ge09iamVjdFtdfSBmaWx0ZXJzVG9NZXJnZVxuICogQHJldHVybiB7T2JqZWN0fSB1cGRhdGVkU3RhdGVcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlRmlsdGVycyhzdGF0ZSwgZmlsdGVyc1RvTWVyZ2UpIHtcbiAgY29uc3QgbWVyZ2VkID0gW107XG4gIGNvbnN0IHVubWVyZ2VkID0gW107XG4gIGNvbnN0IHtkYXRhc2V0c30gPSBzdGF0ZTtcblxuICBpZiAoIUFycmF5LmlzQXJyYXkoZmlsdGVyc1RvTWVyZ2UpIHx8ICFmaWx0ZXJzVG9NZXJnZS5sZW5ndGgpIHtcbiAgICByZXR1cm4gc3RhdGU7XG4gIH1cblxuICAvLyBtZXJnZSBmaWx0ZXJzXG4gIGZpbHRlcnNUb01lcmdlLmZvckVhY2goZmlsdGVyID0+IHtcbiAgICAvLyBtYXRjaCBmaWx0ZXIuZGF0YUlkIHdpdGggY3VycmVudCBkYXRlc2V0cyBpZFxuICAgIC8vIHVwbG9hZGVkIGRhdGEgbmVlZCB0byBoYXZlIHRoZSBzYW1lIGRhdGFJZCB3aXRoIHRoZSBmaWx0ZXJcbiAgICBpZiAoZGF0YXNldHNbZmlsdGVyLmRhdGFJZF0pIHtcbiAgICAgIC8vIGRhdGFzZXRzIGlzIGFscmVhZHkgbG9hZGVkXG4gICAgICBjb25zdCB2YWxpZGF0ZUZpbHRlciA9IHZhbGlkYXRlRmlsdGVyV2l0aERhdGEoXG4gICAgICAgIGRhdGFzZXRzW2ZpbHRlci5kYXRhSWRdLFxuICAgICAgICBmaWx0ZXJcbiAgICAgICk7XG5cbiAgICAgIGlmICh2YWxpZGF0ZUZpbHRlcikge1xuICAgICAgICBtZXJnZWQucHVzaCh2YWxpZGF0ZUZpbHRlcik7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGRhdGFzZXRzIG5vdCB5ZXQgbG9hZGVkXG4gICAgICB1bm1lcmdlZC5wdXNoKGZpbHRlcik7XG4gICAgfVxuICB9KTtcblxuICAvLyBmaWx0ZXIgZGF0YVxuICBjb25zdCB1cGRhdGVkRmlsdGVycyA9IFsuLi4oc3RhdGUuZmlsdGVycyB8fCBbXSksIC4uLm1lcmdlZF07XG4gIGNvbnN0IGRhdGFzZXRUb0ZpbHRlciA9IHVuaXEobWVyZ2VkLm1hcChkID0+IGQuZGF0YUlkKSk7XG5cbiAgY29uc3QgdXBkYXRlZERhdGFzZXQgPSBkYXRhc2V0VG9GaWx0ZXIucmVkdWNlKFxuICAgIChhY2N1LCBkYXRhSWQpID0+ICh7XG4gICAgICAuLi5hY2N1LFxuICAgICAgW2RhdGFJZF06IHtcbiAgICAgICAgLi4uZGF0YXNldHNbZGF0YUlkXSxcbiAgICAgICAgLi4uZmlsdGVyRGF0YShkYXRhc2V0c1tkYXRhSWRdLmFsbERhdGEsIGRhdGFJZCwgdXBkYXRlZEZpbHRlcnMpXG4gICAgICB9XG4gICAgfSksXG4gICAgZGF0YXNldHNcbiAgKTtcblxuICByZXR1cm4ge1xuICAgIC4uLnN0YXRlLFxuICAgIGZpbHRlcnM6IHVwZGF0ZWRGaWx0ZXJzLFxuICAgIGRhdGFzZXRzOiB1cGRhdGVkRGF0YXNldCxcbiAgICBmaWx0ZXJUb0JlTWVyZ2VkOiB1bm1lcmdlZFxuICB9O1xufVxuXG4vKipcbiAqIE1lcmdlIGxheWVycyBmcm9tIGRlLXNlcmlhbGl6ZWQgc3RhdGUsIGlmIG5vIGZpZWxkcyBvciBkYXRhIGFyZSBsb2FkZWRcbiAqIHNhdmUgaXQgZm9yIGxhdGVyXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IHN0YXRlXG4gKiBAcGFyYW0ge09iamVjdFtdfSBsYXllcnNUb01lcmdlXG4gKiBAcmV0dXJuIHtPYmplY3R9IHN0YXRlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZUxheWVycyhzdGF0ZSwgbGF5ZXJzVG9NZXJnZSkge1xuICBjb25zdCBtZXJnZWRMYXllciA9IFtdO1xuICBjb25zdCB1bm1lcmdlZCA9IFtdO1xuXG4gIGNvbnN0IHtkYXRhc2V0c30gPSBzdGF0ZTtcblxuICBpZiAoIUFycmF5LmlzQXJyYXkobGF5ZXJzVG9NZXJnZSkgfHwgIWxheWVyc1RvTWVyZ2UubGVuZ3RoKSB7XG4gICAgcmV0dXJuIHN0YXRlO1xuICB9XG5cbiAgbGF5ZXJzVG9NZXJnZS5mb3JFYWNoKGxheWVyID0+IHtcbiAgICBpZiAoZGF0YXNldHNbbGF5ZXIuY29uZmlnLmRhdGFJZF0pIHtcbiAgICAgIC8vIGRhdGFzZXRzIGFyZSBhbHJlYWR5IGxvYWRlZFxuICAgICAgY29uc3QgdmFsaWRhdGVMYXllciA9IHZhbGlkYXRlTGF5ZXJXaXRoRGF0YShcbiAgICAgICAgZGF0YXNldHNbbGF5ZXIuY29uZmlnLmRhdGFJZF0sXG4gICAgICAgIGxheWVyLFxuICAgICAgICBzdGF0ZS5sYXllckNsYXNzZXNcbiAgICAgICk7XG5cbiAgICAgIGlmICh2YWxpZGF0ZUxheWVyKSB7XG4gICAgICAgIG1lcmdlZExheWVyLnB1c2godmFsaWRhdGVMYXllcik7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIGRhdGFzZXRzIG5vdCB5ZXQgbG9hZGVkXG4gICAgICB1bm1lcmdlZC5wdXNoKGxheWVyKTtcbiAgICB9XG4gIH0pO1xuXG4gIGNvbnN0IGxheWVycyA9IFsuLi5zdGF0ZS5sYXllcnMsIC4uLm1lcmdlZExheWVyXTtcbiAgY29uc3QgbmV3TGF5ZXJPcmRlciA9IG1lcmdlZExheWVyLm1hcCgoXywgaSkgPT4gc3RhdGUubGF5ZXJzLmxlbmd0aCArIGkpO1xuXG4gIC8vIHB1dCBuZXcgbGF5ZXJzIGluIGZyb250IG9mIGN1cnJlbnQgbGF5ZXJzXG4gIGNvbnN0IGxheWVyT3JkZXIgPSBbLi4ubmV3TGF5ZXJPcmRlciwgLi4uc3RhdGUubGF5ZXJPcmRlcl07XG5cbiAgcmV0dXJuIHtcbiAgICAuLi5zdGF0ZSxcbiAgICBsYXllcnMsXG4gICAgbGF5ZXJPcmRlcixcbiAgICBsYXllclRvQmVNZXJnZWQ6IHVubWVyZ2VkXG4gIH07XG59XG5cbi8qKlxuICogTWVyZ2UgaW50ZXJhY3Rpb25zIHdpdGggc2F2ZWQgY29uZmlnXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IHN0YXRlXG4gKiBAcGFyYW0ge09iamVjdH0gaW50ZXJhY3Rpb25Ub0JlTWVyZ2VkXG4gKiBAcmV0dXJuIHtPYmplY3R9IG1lcmdlZFN0YXRlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZUludGVyYWN0aW9ucyhzdGF0ZSwgaW50ZXJhY3Rpb25Ub0JlTWVyZ2VkKSB7XG4gIGNvbnN0IG1lcmdlZCA9IHt9O1xuICBjb25zdCB1bm1lcmdlZCA9IHt9O1xuXG4gIGlmIChpbnRlcmFjdGlvblRvQmVNZXJnZWQpIHtcbiAgICBPYmplY3Qua2V5cyhpbnRlcmFjdGlvblRvQmVNZXJnZWQpLmZvckVhY2goa2V5ID0+IHtcbiAgICAgIGlmICghc3RhdGUuaW50ZXJhY3Rpb25Db25maWdba2V5XSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IHtlbmFibGVkLCAuLi5jb25maWdTYXZlZH0gPSBpbnRlcmFjdGlvblRvQmVNZXJnZWRba2V5XSB8fCB7fTtcbiAgICAgIGxldCBjb25maWdUb01lcmdlID0gY29uZmlnU2F2ZWQ7XG5cbiAgICAgIGlmIChrZXkgPT09ICd0b29sdGlwJykge1xuICAgICAgICBjb25zdCB7bWVyZ2VkVG9vbHRpcCwgdW5tZXJnZWRUb29sdGlwfSA9IG1lcmdlSW50ZXJhY3Rpb25Ub29sdGlwQ29uZmlnKFxuICAgICAgICAgIHN0YXRlLFxuICAgICAgICAgIGNvbmZpZ1NhdmVkXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gbWVyZ2UgbmV3IGRhdGFzZXQgdG9vbHRpcHMgd2l0aCBvcmlnaW5hbCBkYXRhc2V0IHRvb2x0aXBzXG4gICAgICAgIGNvbmZpZ1RvTWVyZ2UgPSB7XG4gICAgICAgICAgZmllbGRzVG9TaG93OiB7XG4gICAgICAgICAgICAuLi5zdGF0ZS5pbnRlcmFjdGlvbkNvbmZpZ1trZXldLmNvbmZpZy5maWVsZHNUb1Nob3csXG4gICAgICAgICAgICAuLi5tZXJnZWRUb29sdGlwXG4gICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIGlmIChPYmplY3Qua2V5cyh1bm1lcmdlZFRvb2x0aXApLmxlbmd0aCkge1xuICAgICAgICAgIHVubWVyZ2VkLnRvb2x0aXAgPSB7ZmllbGRzVG9TaG93OiB1bm1lcmdlZFRvb2x0aXAsIGVuYWJsZWR9O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIG1lcmdlZFtrZXldID0ge1xuICAgICAgICAuLi5zdGF0ZS5pbnRlcmFjdGlvbkNvbmZpZ1trZXldLFxuICAgICAgICBlbmFibGVkLFxuICAgICAgICBjb25maWc6IHBpY2soXG4gICAgICAgICAge1xuICAgICAgICAgICAgLi4uc3RhdGUuaW50ZXJhY3Rpb25Db25maWdba2V5XS5jb25maWcsXG4gICAgICAgICAgICAuLi5jb25maWdUb01lcmdlXG4gICAgICAgICAgfSxcbiAgICAgICAgICBPYmplY3Qua2V5cyhzdGF0ZS5pbnRlcmFjdGlvbkNvbmZpZ1trZXldLmNvbmZpZylcbiAgICAgICAgKVxuICAgICAgfTtcbiAgICB9KTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgLi4uc3RhdGUsXG4gICAgaW50ZXJhY3Rpb25Db25maWc6IHtcbiAgICAgIC4uLnN0YXRlLmludGVyYWN0aW9uQ29uZmlnLFxuICAgICAgLi4ubWVyZ2VkXG4gICAgfSxcbiAgICBpbnRlcmFjdGlvblRvQmVNZXJnZWQ6IHVubWVyZ2VkXG4gIH07XG59XG5cbi8qKlxuICogTWVyZ2UgaW50ZXJhY3Rpb25Db25maWcudG9vbHRpcCB3aXRoIHNhdmVkIGNvbmZpZyxcbiAqIHZhbGlkYXRlIGZpZWxkc1RvU2hvd1xuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdGF0ZVxuICogQHBhcmFtIHtPYmplY3R9IHRvb2x0aXBDb25maWdcbiAqIEByZXR1cm4ge09iamVjdH0gLSB7bWVyZ2VkVG9vbHRpcDoge30sIHVubWVyZ2VkVG9vbHRpcDoge319XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZUludGVyYWN0aW9uVG9vbHRpcENvbmZpZyhzdGF0ZSwgdG9vbHRpcENvbmZpZyA9IHt9KSB7XG4gIGNvbnN0IHVubWVyZ2VkVG9vbHRpcCA9IHt9O1xuICBjb25zdCBtZXJnZWRUb29sdGlwID0ge307XG5cbiAgaWYgKFxuICAgICF0b29sdGlwQ29uZmlnLmZpZWxkc1RvU2hvdyB8fFxuICAgICFPYmplY3Qua2V5cyh0b29sdGlwQ29uZmlnLmZpZWxkc1RvU2hvdykubGVuZ3RoXG4gICkge1xuICAgIHJldHVybiB7bWVyZ2VkVG9vbHRpcCwgdW5tZXJnZWRUb29sdGlwfTtcbiAgfVxuXG4gIGZvciAoY29uc3QgZGF0YUlkIGluIHRvb2x0aXBDb25maWcuZmllbGRzVG9TaG93KSB7XG4gICAgaWYgKCFzdGF0ZS5kYXRhc2V0c1tkYXRhSWRdKSB7XG4gICAgICAvLyBpcyBub3QgeWV0IGxvYWRlZFxuICAgICAgdW5tZXJnZWRUb29sdGlwW2RhdGFJZF0gPSB0b29sdGlwQ29uZmlnLmZpZWxkc1RvU2hvd1tkYXRhSWRdO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBpZiBkYXRhc2V0IGlzIGxvYWRlZFxuICAgICAgY29uc3QgYWxsRmllbGRzID0gc3RhdGUuZGF0YXNldHNbZGF0YUlkXS5maWVsZHMubWFwKGQgPT4gZC5uYW1lKTtcbiAgICAgIGNvbnN0IGZvdW5kRmllbGRzVG9TaG93ID0gdG9vbHRpcENvbmZpZy5maWVsZHNUb1Nob3dbZGF0YUlkXS5maWx0ZXIoXG4gICAgICAgIG5hbWUgPT4gYWxsRmllbGRzLmluY2x1ZGVzKG5hbWUpXG4gICAgICApO1xuXG4gICAgICBtZXJnZWRUb29sdGlwW2RhdGFJZF0gPSBmb3VuZEZpZWxkc1RvU2hvdztcbiAgICB9XG4gIH1cblxuICByZXR1cm4ge21lcmdlZFRvb2x0aXAsIHVubWVyZ2VkVG9vbHRpcH07XG59XG4vKipcbiAqIE1lcmdlIGxheWVyQmxlbmRpbmcgd2l0aCBzYXZlZFxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBzdGF0ZVxuICogQHBhcmFtIHtzdHJpbmd9IGxheWVyQmxlbmRpbmdcbiAqIEByZXR1cm4ge29iamVjdH0gbWVyZ2VkIHN0YXRlXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBtZXJnZUxheWVyQmxlbmRpbmcoc3RhdGUsIGxheWVyQmxlbmRpbmcpIHtcbiAgaWYgKGxheWVyQmxlbmRpbmcgJiYgTEFZRVJfQkxFTkRJTkdTW2xheWVyQmxlbmRpbmddKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLnN0YXRlLFxuICAgICAgbGF5ZXJCbGVuZGluZ1xuICAgIH07XG4gIH1cblxuICByZXR1cm4gc3RhdGU7XG59XG5cbi8qKlxuICogVmFsaWRhdGUgc2F2ZWQgbGF5ZXIgY29sdW1ucyB3aXRoIG5ldyBkYXRhLFxuICogdXBkYXRlIGZpZWxkSWR4IGJhc2VkIG9uIG5ldyBmaWVsZHNcbiAqXG4gKiBAcGFyYW0ge09iamVjdFtdfSBmaWVsZHNcbiAqIEBwYXJhbSB7T2JqZWN0fSBzYXZlZENvbHNcbiAqIEBwYXJhbSB7T2JqZWN0fSBlbXB0eUNvbHNcbiAqIEByZXR1cm4ge251bGwgfCBPYmplY3R9IC0gdmFsaWRhdGVkIGNvbHVtbnMgb3IgbnVsbFxuICovXG5cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZVNhdmVkTGF5ZXJDb2x1bW5zKGZpZWxkcywgc2F2ZWRDb2xzLCBlbXB0eUNvbHMpIHtcbiAgY29uc3QgY29sRm91bmQgPSB7fTtcbiAgLy8gZmluZCBhY3R1YWwgY29sdW1uIGZpZWxkSWR4LCBpbiBjYXNlIGl0IGhhcyBjaGFuZ2VkXG4gIGNvbnN0IGFsbENvbEZvdW5kID0gT2JqZWN0LmtleXMoZW1wdHlDb2xzKS5ldmVyeShrZXkgPT4ge1xuICAgIGNvbnN0IHNhdmVkID0gc2F2ZWRDb2xzW2tleV07XG4gICAgY29sRm91bmRba2V5XSA9IHsuLi5lbXB0eUNvbHNba2V5XX07XG5cbiAgICBjb25zdCBmaWVsZElkeCA9IGZpZWxkcy5maW5kSW5kZXgoKHtuYW1lfSkgPT4gbmFtZSA9PT0gc2F2ZWQpO1xuXG4gICAgaWYgKGZpZWxkSWR4ID4gLTEpIHtcbiAgICAgIC8vIHVwZGF0ZSBmb3VuZCBjb2x1bW5zXG4gICAgICBjb2xGb3VuZFtrZXldLmZpZWxkSWR4ID0gZmllbGRJZHg7XG4gICAgICBjb2xGb3VuZFtrZXldLnZhbHVlID0gc2F2ZWQ7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICAvLyBpZiBjb2wgaXMgb3B0aW9uYWwsIGFsbG93IG51bGwgdmFsdWVcbiAgICByZXR1cm4gZW1wdHlDb2xzW2tleV0ub3B0aW9uYWwgfHwgZmFsc2U7XG4gIH0pO1xuXG4gIHJldHVybiBhbGxDb2xGb3VuZCAmJiBjb2xGb3VuZDtcbn1cblxuLyoqXG4gKiBWYWxpZGF0ZSBzYXZlZCB2aXN1YWwgY2hhbm5lbHMgY29uZmlnIHdpdGggbmV3IGRhdGEsXG4gKiByZWZlciB0byB2aXMtc3RhdGUtc2NoZW1hLmpzIFZpc3VhbENoYW5uZWxTY2hlbWFWMVxuICpcbiAqIEBwYXJhbSB7T2JqZWN0W119IGZpZWxkc1xuICogQHBhcmFtIHtPYmplY3R9IHZpc3VhbENoYW5uZWxzXG4gKiBAcGFyYW0ge09iamVjdH0gc2F2ZWRMYXllclxuICogQHJldHVybiB7T2JqZWN0fSAtIHZhbGlkYXRlZCB2aXN1YWwgY2hhbm5lbCBpbiBjb25maWcgb3Ige31cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlU2F2ZWRWaXN1YWxDaGFubmVscyhcbiAgZmllbGRzLFxuICB2aXN1YWxDaGFubmVscyxcbiAgc2F2ZWRMYXllclxuKSB7XG4gIHJldHVybiBPYmplY3QudmFsdWVzKHZpc3VhbENoYW5uZWxzKS5yZWR1Y2UoKGZvdW5kLCB7ZmllbGQsIHNjYWxlfSkgPT4ge1xuICAgIGxldCBmb3VuZEZpZWxkO1xuICAgIGlmIChzYXZlZExheWVyLmNvbmZpZ1tmaWVsZF0pIHtcbiAgICAgIGZvdW5kRmllbGQgPSBmaWVsZHMuZmluZChmZCA9PlxuICAgICAgICBPYmplY3Qua2V5cyhzYXZlZExheWVyLmNvbmZpZ1tmaWVsZF0pLmV2ZXJ5KFxuICAgICAgICAgIGtleSA9PiBzYXZlZExheWVyLmNvbmZpZ1tmaWVsZF1ba2V5XSA9PT0gZmRba2V5XVxuICAgICAgICApXG4gICAgICApO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICAuLi5mb3VuZCxcbiAgICAgIC4uLihmb3VuZEZpZWxkID8ge1tmaWVsZF06IGZvdW5kRmllbGR9IDoge30pLFxuICAgICAgLi4uKHNhdmVkTGF5ZXIuY29uZmlnW3NjYWxlXSA/IHtbc2NhbGVdOiBzYXZlZExheWVyLmNvbmZpZ1tzY2FsZV19IDoge30pXG4gICAgfTtcbiAgfSwge30pO1xufVxuXG4vKipcbiAqIFZhbGlkYXRlIHNhdmVkIGxheWVyIGNvbmZpZyB3aXRoIG5ldyBkYXRhLFxuICogdXBkYXRlIGZpZWxkSWR4IGJhc2VkIG9uIG5ldyBmaWVsZHNcbiAqXG4gKiBAcGFyYW0ge09iamVjdFtdfSBmaWVsZHNcbiAqIEBwYXJhbSB7U3RyaW5nfSBkYXRhSWRcbiAqIEBwYXJhbSB7T2JqZWN0fSBzYXZlZExheWVyXG4gKiBAcGFyYW0ge09iamVjdH0gbGF5ZXJDbGFzc2VzXG4gKiBAcmV0dXJuIHtudWxsIHwgT2JqZWN0fSAtIHZhbGlkYXRlZCBsYXllciBvciBudWxsXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2YWxpZGF0ZUxheWVyV2l0aERhdGEoe2ZpZWxkcywgaWQ6IGRhdGFJZH0sIHNhdmVkTGF5ZXIsIGxheWVyQ2xhc3Nlcykge1xuICBjb25zdCB7dHlwZX0gPSBzYXZlZExheWVyO1xuICAvLyBsYXllciBkb2VzbnQgaGF2ZSBhIHZhbGlkIHR5cGVcbiAgaWYgKFxuICAgICFsYXllckNsYXNzZXMuaGFzT3duUHJvcGVydHkodHlwZSkgfHxcbiAgICAhc2F2ZWRMYXllci5jb25maWcgfHxcbiAgICAhc2F2ZWRMYXllci5jb25maWcuY29sdW1uc1xuICApIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IG5ld0xheWVyID0gbmV3IGxheWVyQ2xhc3Nlc1t0eXBlXSh7XG4gICAgaWQ6IHNhdmVkTGF5ZXIuaWQsXG4gICAgZGF0YUlkLFxuICAgIGxhYmVsOiBzYXZlZExheWVyLmNvbmZpZy5sYWJlbCxcbiAgICBjb2xvcjogc2F2ZWRMYXllci5jb25maWcuY29sb3IsXG4gICAgaXNWaXNpYmxlOiBzYXZlZExheWVyLmNvbmZpZy5pc1Zpc2libGVcbiAgfSk7XG5cbiAgLy8gZmluZCBjb2x1bW4gZmllbGRJZHhcbiAgY29uc3QgY29sdW1ucyA9IHZhbGlkYXRlU2F2ZWRMYXllckNvbHVtbnMoXG4gICAgZmllbGRzLFxuICAgIHNhdmVkTGF5ZXIuY29uZmlnLmNvbHVtbnMsXG4gICAgbmV3TGF5ZXIuZ2V0TGF5ZXJDb2x1bW5zKClcbiAgKTtcblxuICBpZiAoIWNvbHVtbnMpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8vIHZpc3VhbCBjaGFubmVsIGZpZWxkIGlzIHNhdmVkIHRvIGJlIHtuYW1lLCB0eXBlfVxuICAvLyBmaW5kIHZpc3VhbCBjaGFubmVsIGZpZWxkIGJ5IG1hdGNoaW5nIGJvdGggbmFtZSBhbmQgdHlwZVxuICAvLyByZWZlciB0byB2aXMtc3RhdGUtc2NoZW1hLmpzIFZpc3VhbENoYW5uZWxTY2hlbWFWMVxuICBjb25zdCBmb3VuZFZpc3VhbENoYW5uZWxDb25maWdzID0gdmFsaWRhdGVTYXZlZFZpc3VhbENoYW5uZWxzKFxuICAgIGZpZWxkcyxcbiAgICBuZXdMYXllci52aXN1YWxDaGFubmVscyxcbiAgICBzYXZlZExheWVyXG4gICk7XG5cbiAgLy8gY29weSB2aXNDb25maWcgb3ZlciB0byBlbXB0eUxheWVyIHRvIG1ha2Ugc3VyZSBpdCBoYXMgYWxsIHRoZSBwcm9wc1xuICBjb25zdCB2aXNDb25maWcgPSBuZXdMYXllci5jb3B5TGF5ZXJDb25maWcoXG4gICAgbmV3TGF5ZXIuY29uZmlnLnZpc0NvbmZpZyxcbiAgICBzYXZlZExheWVyLmNvbmZpZy52aXNDb25maWcgfHwge30sXG4gICAge25vdFRvRGVlcE1lcmdlOiAnY29sb3JSYW5nZSd9XG4gICk7XG5cbiAgbmV3TGF5ZXIudXBkYXRlTGF5ZXJDb25maWcoe1xuICAgIGNvbHVtbnMsXG4gICAgdmlzQ29uZmlnLFxuICAgIC4uLmZvdW5kVmlzdWFsQ2hhbm5lbENvbmZpZ3NcbiAgfSk7XG5cbiAgcmV0dXJuIG5ld0xheWVyO1xufVxuXG4vKipcbiAqIFZhbGlkYXRlIHNhdmVkIGZpbHRlciBjb25maWcgd2l0aCBuZXcgZGF0YSxcbiAqIGNhbGN1bGF0ZSBkb21haW4gYW5kIGZpZWxkSWR4IGJhc2VkIG5ldyBmaWVsZHMgYW5kIGRhdGFcbiAqXG4gKiBAcGFyYW0ge09iamVjdFtdfSBkYXRhc2V0LmZpZWxkc1xuICogQHBhcmFtIHtPYmplY3RbXX0gZGF0YXNldC5hbGxEYXRhXG4gKiBAcGFyYW0ge09iamVjdH0gZmlsdGVyIC0gZmlsdGVyIHRvIGJlIHZhbGlkYXRlXG4gKiBAcmV0dXJuIHtPYmplY3QgfCBudWxsfSAtIHZhbGlkYXRlZCBmaWx0ZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlRmlsdGVyV2l0aERhdGEoe2ZpZWxkcywgYWxsRGF0YX0sIGZpbHRlcikge1xuICAvLyBtYXRjaCBmaWx0ZXIubmFtZSB0byBmaWVsZC5uYW1lXG4gIGNvbnN0IGZpZWxkSWR4ID0gZmllbGRzLmZpbmRJbmRleCgoe25hbWV9KSA9PiBuYW1lID09PSBmaWx0ZXIubmFtZSk7XG5cbiAgaWYgKGZpZWxkSWR4IDwgMCkge1xuICAgIC8vIGlmIGNhbid0IGZpbmQgZmllbGQgd2l0aCBzYW1lIG5hbWUsIGRpc2NoYXJnZSBmaWx0ZXJcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IGZpZWxkID0gZmllbGRzW2ZpZWxkSWR4XTtcbiAgY29uc3QgdmFsdWUgPSBmaWx0ZXIudmFsdWU7XG5cbiAgLy8gcmV0dXJuIGZpbHRlciB0eXBlLCBkZWZhdWx0IHZhbHVlLCBmaWVsZFR5cGUgYW5kIGZpZWxkRG9tYWluIGZyb20gZmllbGRcbiAgY29uc3QgZmlsdGVyUHJvcHNGcm9tRmllbGQgPSBnZXRGaWx0ZXJQcm9wcyhhbGxEYXRhLCBmaWVsZCk7XG5cbiAgbGV0IG1hdGNoZWRGaWx0ZXIgPSB7XG4gICAgLi4uZ2V0RGVmYXVsdEZpbHRlcihmaWx0ZXIuZGF0YUlkKSxcbiAgICAuLi5maWx0ZXIsXG4gICAgLi4uZmlsdGVyUHJvcHNGcm9tRmllbGQsXG4gICAgZnJlZXplOiB0cnVlLFxuICAgIGZpZWxkSWR4XG4gIH07XG5cbiAgY29uc3Qge3lBeGlzfSA9IG1hdGNoZWRGaWx0ZXI7XG4gIGlmICh5QXhpcykge1xuICAgIGNvbnN0IG1hdGNoZUF4aXMgPSBmaWVsZHMuZmluZChcbiAgICAgICh7bmFtZSwgdHlwZX0pID0+IG5hbWUgPT09IHlBeGlzLm5hbWUgJiYgdHlwZSA9PT0geUF4aXMudHlwZVxuICAgICk7XG5cbiAgICBtYXRjaGVkRmlsdGVyID0gbWF0Y2hlQXhpc1xuICAgICAgPyB7XG4gICAgICAgICAgLi4ubWF0Y2hlZEZpbHRlcixcbiAgICAgICAgICB5QXhpczogbWF0Y2hlQXhpcyxcbiAgICAgICAgICAuLi5nZXRGaWx0ZXJQbG90KHsuLi5tYXRjaGVkRmlsdGVyLCB5QXhpczogbWF0Y2hlQXhpc30sIGFsbERhdGEpXG4gICAgICAgIH1cbiAgICAgIDogbWF0Y2hlZEZpbHRlcjtcbiAgfVxuXG4gIG1hdGNoZWRGaWx0ZXIudmFsdWUgPSBhZGp1c3RWYWx1ZVRvRmlsdGVyRG9tYWluKHZhbHVlLCBtYXRjaGVkRmlsdGVyKTtcblxuICBpZiAobWF0Y2hlZEZpbHRlci52YWx1ZSA9PT0gbnVsbCkge1xuICAgIC8vIGNhbm50IGFkanVzdCBzYXZlZCB2YWx1ZSB0byBmaWx0ZXJcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIHJldHVybiBtYXRjaGVkRmlsdGVyO1xufVxuIl19