kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
235 lines (194 loc) • 26.4 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.addDataToMapComposed = exports.loadFileSuccessUpdater = exports.addDataToMapUpdater = exports.defaultAddDataToMapOptions = exports.isValidConfig = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _uiStateUpdaters = require("./ui-state-updaters");
var _visStateUpdaters = require("./vis-state-updaters");
var _mapStateUpdaters = require("./map-state-updaters");
var _mapStyleUpdaters = require("./map-style-updaters");
var _dataUtils = require("../utils/data-utils");
var _schemas = _interopRequireDefault(require("../schemas"));
var _utils = require("../utils/utils");
var _fileHandler = require("../processors/file-handler");
var _console = _interopRequireDefault(require("global/console"));
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
// compose action to apply result multiple reducers, with the output of one
/**
* Some actions will affect the entire kepler.lg instance state.
* The updaters for these actions is exported as `combinedUpdaters`. These updater take the entire instance state
* as the first argument. Read more about [Using updaters](../advanced-usage/using-updaters.md)
* @public
* @example
*
* import keplerGlReducer, {combinedUpdaters} from 'kepler.gl/reducers';
* // Root Reducer
* const reducers = combineReducers({
* keplerGl: keplerGlReducer,
* app: appReducer
* });
*
* const composedReducer = (state, action) => {
* switch (action.type) {
* // add data to map after receiving data from remote sources
* case 'LOAD_REMOTE_RESOURCE_SUCCESS':
* return {
* ...state,
* keplerGl: {
* ...state.keplerGl,
* // pass in kepler.gl instance state to combinedUpdaters
* map: combinedUpdaters.addDataToMapUpdater(
* state.keplerGl.map,
* {
* payload: {
* datasets: action.datasets,
* options: {readOnly: true},
* config: action.config
* }
* }
* )
* }
* };
* }
* return reducers(state, action);
* };
*
* export default composedReducer;
*/
/* eslint-disable no-unused-vars */
var combinedUpdaters = null;
/* eslint-enable no-unused-vars */
var isValidConfig = function isValidConfig(config) {
return (0, _utils.isPlainObject)(config) && (0, _utils.isPlainObject)(config.config) && config.version;
};
exports.isValidConfig = isValidConfig;
var defaultAddDataToMapOptions = {
centerMap: true,
keepExistingConfig: false
};
exports.defaultAddDataToMapOptions = defaultAddDataToMapOptions;
var identity = function identity(state) {
return state;
};
/* eslint-disable-next-line no-unused-vars */
function log(text) {
return function (value) {
return _console["default"].log(text, value);
};
}
function payload_(p) {
return {
payload: p
};
}
function apply_(updater, payload) {
return function (state) {
return updater(state, payload);
};
}
function with_(fn) {
return function (state) {
return fn(state)(state);
};
}
function if_(pred, fn) {
return pred ? fn : identity;
}
function compose_(fns) {
return function (state) {
return fns.reduce(function (state2, fn) {
return fn(state2);
}, state);
};
}
function merge_(obj) {
return function (state) {
return _objectSpread({}, state, {}, obj);
};
}
function pick_(prop) {
return function (fn) {
return function (state) {
return _objectSpread({}, state, (0, _defineProperty2["default"])({}, prop, fn(state[prop])));
};
};
}
/**
* Combine data and full configuration update in a single action
*
* @memberof combinedUpdaters
* @param {Object} state kepler.gl instance state, containing all subreducer state
* @param {Object} action
* @param {Object} action.payload `{datasets, options, config}`
* @param {Array<Object>|Object} action.payload.datasets - ***required** datasets can be a dataset or an array of datasets
* Each dataset object needs to have `info` and `data` property.
* @param {Object} action.payload.datasets.info -info of a dataset
* @param {string} action.payload.datasets.info.id - id of this dataset. If config is defined, `id` should matches the `dataId` in config.
* @param {string} action.payload.datasets.info.label - A display name of this dataset
* @param {Object} action.payload.datasets.data - ***required** The data object, in a tabular format with 2 properties `fields` and `rows`
* @param {Array<Object>} action.payload.datasets.data.fields - ***required** Array of fields,
* @param {string} action.payload.datasets.data.fields.name - ***required** Name of the field,
* @param {Array<Array>} action.payload.datasets.data.rows - ***required** Array of rows, in a tabular format with `fields` and `rows`
* @param {Object} action.payload.options option object `{centerMap: true}`
* @param {Object} action.payload.config map config
* @returns {Object} nextState
* @public
*/
var addDataToMapUpdater = function addDataToMapUpdater(state, _ref) {
var payload = _ref.payload;
var datasets = payload.datasets,
config = payload.config,
info = payload.info;
var options = _objectSpread({}, defaultAddDataToMapOptions, {}, payload.options);
var parsedConfig = config;
if (isValidConfig(config)) {
// if passed in saved config
parsedConfig = _schemas["default"].parseSavedConfig(config);
}
var oldLayers = state.visState.layers;
var filterNewlyAddedLayers = function filterNewlyAddedLayers(layers) {
return layers.filter(function (nl) {
return !oldLayers.find(function (ol) {
return ol === nl;
});
});
};
return compose_([pick_('visState')(apply_(_visStateUpdaters.updateVisDataUpdater, {
datasets: datasets,
options: options,
config: parsedConfig
})), if_(info, pick_('visState')(apply_(_visStateUpdaters.setMapInfoUpdater, {
info: info
}))), with_(function (_ref2) {
var visState = _ref2.visState;
return pick_('mapState')(apply_(_mapStateUpdaters.receiveMapConfigUpdater, payload_({
config: parsedConfig,
options: options,
bounds: options.centerMap ? (0, _dataUtils.findMapBounds)(filterNewlyAddedLayers(visState.layers)) : null
})));
}), pick_('mapStyle')(apply_(_mapStyleUpdaters.receiveMapConfigUpdater, payload_({
config: parsedConfig,
options: options
}))), pick_('uiState')(apply_(_uiStateUpdaters.loadFilesSuccessUpdater)), pick_('uiState')(apply_(_uiStateUpdaters.toggleModalUpdater, payload_(null))), pick_('uiState')(merge_(options.hasOwnProperty('readOnly') ? {
readOnly: options.readOnly
} : {}))])(state);
};
exports.addDataToMapUpdater = addDataToMapUpdater;
var loadFileSuccessUpdater = function loadFileSuccessUpdater(state, action) {
// still more to load
var payloads = (0, _fileHandler.filesToDataPayload)(action.result);
var nextState = compose_([pick_('visState')(merge_({
fileLoading: false,
fileLoadingProgress: 100
}))])(state); // make multiple add data to map calls
return compose_(payloads.map(function (p) {
return apply_(addDataToMapUpdater, payload_(p));
}))(nextState);
};
exports.loadFileSuccessUpdater = loadFileSuccessUpdater;
var addDataToMapComposed = addDataToMapUpdater;
exports.addDataToMapComposed = addDataToMapComposed;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9yZWR1Y2Vycy9jb21iaW5lZC11cGRhdGVycy5qcyJdLCJuYW1lcyI6WyJjb21iaW5lZFVwZGF0ZXJzIiwiaXNWYWxpZENvbmZpZyIsImNvbmZpZyIsInZlcnNpb24iLCJkZWZhdWx0QWRkRGF0YVRvTWFwT3B0aW9ucyIsImNlbnRlck1hcCIsImtlZXBFeGlzdGluZ0NvbmZpZyIsImlkZW50aXR5Iiwic3RhdGUiLCJsb2ciLCJ0ZXh0IiwidmFsdWUiLCJDb25zb2xlIiwicGF5bG9hZF8iLCJwIiwicGF5bG9hZCIsImFwcGx5XyIsInVwZGF0ZXIiLCJ3aXRoXyIsImZuIiwiaWZfIiwicHJlZCIsImNvbXBvc2VfIiwiZm5zIiwicmVkdWNlIiwic3RhdGUyIiwibWVyZ2VfIiwib2JqIiwicGlja18iLCJwcm9wIiwiYWRkRGF0YVRvTWFwVXBkYXRlciIsImRhdGFzZXRzIiwiaW5mbyIsIm9wdGlvbnMiLCJwYXJzZWRDb25maWciLCJLZXBsZXJHbFNjaGVtYSIsInBhcnNlU2F2ZWRDb25maWciLCJvbGRMYXllcnMiLCJ2aXNTdGF0ZSIsImxheWVycyIsImZpbHRlck5ld2x5QWRkZWRMYXllcnMiLCJmaWx0ZXIiLCJubCIsImZpbmQiLCJvbCIsInZpc1N0YXRlVXBkYXRlVmlzRGF0YVVwZGF0ZXIiLCJzZXRNYXBJbmZvVXBkYXRlciIsInN0YXRlTWFwQ29uZmlnVXBkYXRlciIsImJvdW5kcyIsInN0eWxlTWFwQ29uZmlnVXBkYXRlciIsImxvYWRGaWxlc1N1Y2Nlc3NVcGRhdGVyIiwidG9nZ2xlTW9kYWxVcGRhdGVyIiwiaGFzT3duUHJvcGVydHkiLCJyZWFkT25seSIsImxvYWRGaWxlU3VjY2Vzc1VwZGF0ZXIiLCJhY3Rpb24iLCJwYXlsb2FkcyIsInJlc3VsdCIsIm5leHRTdGF0ZSIsImZpbGVMb2FkaW5nIiwiZmlsZUxvYWRpbmdQcm9ncmVzcyIsIm1hcCIsImFkZERhdGFUb01hcENvbXBvc2VkIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQXlDQTs7QUFDQTs7QUFJQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7Ozs7O0FBRUE7O0FBRUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQXlDQTtBQUNBLElBQU1BLGdCQUFnQixHQUFHLElBQXpCO0FBQ0E7O0FBRU8sSUFBTUMsYUFBYSxHQUFHLFNBQWhCQSxhQUFnQixDQUFBQyxNQUFNO0FBQUEsU0FDakMsMEJBQWNBLE1BQWQsS0FBeUIsMEJBQWNBLE1BQU0sQ0FBQ0EsTUFBckIsQ0FBekIsSUFBeURBLE1BQU0sQ0FBQ0MsT0FEL0I7QUFBQSxDQUE1Qjs7O0FBR0EsSUFBTUMsMEJBQTBCLEdBQUc7QUFDeENDLEVBQUFBLFNBQVMsRUFBRSxJQUQ2QjtBQUV4Q0MsRUFBQUEsa0JBQWtCLEVBQUU7QUFGb0IsQ0FBbkM7OztBQUtQLElBQU1DLFFBQVEsR0FBRyxTQUFYQSxRQUFXLENBQUFDLEtBQUs7QUFBQSxTQUFJQSxLQUFKO0FBQUEsQ0FBdEI7QUFFQTs7O0FBQ0EsU0FBU0MsR0FBVCxDQUFhQyxJQUFiLEVBQW1CO0FBQ2pCLFNBQU8sVUFBQUMsS0FBSztBQUFBLFdBQUlDLG9CQUFRSCxHQUFSLENBQVlDLElBQVosRUFBa0JDLEtBQWxCLENBQUo7QUFBQSxHQUFaO0FBQ0Q7O0FBRUQsU0FBU0UsUUFBVCxDQUFrQkMsQ0FBbEIsRUFBcUI7QUFDbkIsU0FBTztBQUFDQyxJQUFBQSxPQUFPLEVBQUVEO0FBQVYsR0FBUDtBQUNEOztBQUVELFNBQVNFLE1BQVQsQ0FBZ0JDLE9BQWhCLEVBQXlCRixPQUF6QixFQUFrQztBQUNoQyxTQUFPLFVBQUFQLEtBQUs7QUFBQSxXQUFJUyxPQUFPLENBQUNULEtBQUQsRUFBUU8sT0FBUixDQUFYO0FBQUEsR0FBWjtBQUNEOztBQUVELFNBQVNHLEtBQVQsQ0FBZUMsRUFBZixFQUFtQjtBQUNqQixTQUFPLFVBQUFYLEtBQUs7QUFBQSxXQUFJVyxFQUFFLENBQUNYLEtBQUQsQ0FBRixDQUFVQSxLQUFWLENBQUo7QUFBQSxHQUFaO0FBQ0Q7O0FBRUQsU0FBU1ksR0FBVCxDQUFhQyxJQUFiLEVBQW1CRixFQUFuQixFQUF1QjtBQUNyQixTQUFPRSxJQUFJLEdBQUdGLEVBQUgsR0FBUVosUUFBbkI7QUFDRDs7QUFFRCxTQUFTZSxRQUFULENBQWtCQyxHQUFsQixFQUF1QjtBQUNyQixTQUFPLFVBQUFmLEtBQUs7QUFBQSxXQUFJZSxHQUFHLENBQUNDLE1BQUosQ0FBVyxVQUFDQyxNQUFELEVBQVNOLEVBQVQ7QUFBQSxhQUFnQkEsRUFBRSxDQUFDTSxNQUFELENBQWxCO0FBQUEsS0FBWCxFQUF1Q2pCLEtBQXZDLENBQUo7QUFBQSxHQUFaO0FBQ0Q7O0FBRUQsU0FBU2tCLE1BQVQsQ0FBZ0JDLEdBQWhCLEVBQXFCO0FBQ25CLFNBQU8sVUFBQW5CLEtBQUs7QUFBQSw2QkFBU0EsS0FBVCxNQUFtQm1CLEdBQW5CO0FBQUEsR0FBWjtBQUNEOztBQUVELFNBQVNDLEtBQVQsQ0FBZUMsSUFBZixFQUFxQjtBQUNuQixTQUFPLFVBQUFWLEVBQUU7QUFBQSxXQUFJLFVBQUFYLEtBQUs7QUFBQSwrQkFBU0EsS0FBVCx1Q0FBaUJxQixJQUFqQixFQUF3QlYsRUFBRSxDQUFDWCxLQUFLLENBQUNxQixJQUFELENBQU4sQ0FBMUI7QUFBQSxLQUFUO0FBQUEsR0FBVDtBQUNEO0FBRUQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBcUJPLElBQU1DLG1CQUFtQixHQUFHLFNBQXRCQSxtQkFBc0IsQ0FBQ3RCLEtBQUQsUUFBc0I7QUFBQSxNQUFiTyxPQUFhLFFBQWJBLE9BQWE7QUFBQSxNQUNoRGdCLFFBRGdELEdBQ3RCaEIsT0FEc0IsQ0FDaERnQixRQURnRDtBQUFBLE1BQ3RDN0IsTUFEc0MsR0FDdEJhLE9BRHNCLENBQ3RDYixNQURzQztBQUFBLE1BQzlCOEIsSUFEOEIsR0FDdEJqQixPQURzQixDQUM5QmlCLElBRDhCOztBQUd2RCxNQUFNQyxPQUFPLHFCQUNSN0IsMEJBRFEsTUFFUlcsT0FBTyxDQUFDa0IsT0FGQSxDQUFiOztBQUtBLE1BQUlDLFlBQVksR0FBR2hDLE1BQW5COztBQUVBLE1BQUlELGFBQWEsQ0FBQ0MsTUFBRCxDQUFqQixFQUEyQjtBQUN6QjtBQUNBZ0MsSUFBQUEsWUFBWSxHQUFHQyxvQkFBZUMsZ0JBQWYsQ0FBZ0NsQyxNQUFoQyxDQUFmO0FBQ0Q7O0FBQ0QsTUFBTW1DLFNBQVMsR0FBRzdCLEtBQUssQ0FBQzhCLFFBQU4sQ0FBZUMsTUFBakM7O0FBQ0EsTUFBTUMsc0JBQXNCLEdBQUcsU0FBekJBLHNCQUF5QixDQUFBRCxNQUFNO0FBQUEsV0FBSUEsTUFBTSxDQUFDRSxNQUFQLENBQWMsVUFBQUMsRUFBRTtBQUFBLGFBQUksQ0FBQ0wsU0FBUyxDQUFDTSxJQUFWLENBQWUsVUFBQUMsRUFBRTtBQUFBLGVBQUlBLEVBQUUsS0FBS0YsRUFBWDtBQUFBLE9BQWpCLENBQUw7QUFBQSxLQUFoQixDQUFKO0FBQUEsR0FBckM7O0FBRUEsU0FBT3BCLFFBQVEsQ0FBQyxDQUNkTSxLQUFLLENBQUMsVUFBRCxDQUFMLENBQ0VaLE1BQU0sQ0FBQzZCLHNDQUFELEVBQStCO0FBQ25DZCxJQUFBQSxRQUFRLEVBQVJBLFFBRG1DO0FBRW5DRSxJQUFBQSxPQUFPLEVBQVBBLE9BRm1DO0FBR25DL0IsSUFBQUEsTUFBTSxFQUFFZ0M7QUFIMkIsR0FBL0IsQ0FEUixDQURjLEVBU2RkLEdBQUcsQ0FBQ1ksSUFBRCxFQUFPSixLQUFLLENBQUMsVUFBRCxDQUFMLENBQWtCWixNQUFNLENBQUM4QixtQ0FBRCxFQUFvQjtBQUFDZCxJQUFBQSxJQUFJLEVBQUpBO0FBQUQsR0FBcEIsQ0FBeEIsQ0FBUCxDQVRXLEVBV2RkLEtBQUssQ0FBQztBQUFBLFFBQUVvQixRQUFGLFNBQUVBLFFBQUY7QUFBQSxXQUNKVixLQUFLLENBQUMsVUFBRCxDQUFMLENBQ0VaLE1BQU0sQ0FDSitCLHlDQURJLEVBRUpsQyxRQUFRLENBQUM7QUFDUFgsTUFBQUEsTUFBTSxFQUFFZ0MsWUFERDtBQUVQRCxNQUFBQSxPQUFPLEVBQVBBLE9BRk87QUFHUGUsTUFBQUEsTUFBTSxFQUFFZixPQUFPLENBQUM1QixTQUFSLEdBQ0osOEJBQWNtQyxzQkFBc0IsQ0FBQ0YsUUFBUSxDQUFDQyxNQUFWLENBQXBDLENBREksR0FFSjtBQUxHLEtBQUQsQ0FGSixDQURSLENBREk7QUFBQSxHQUFELENBWFMsRUEwQmRYLEtBQUssQ0FBQyxVQUFELENBQUwsQ0FBa0JaLE1BQU0sQ0FBQ2lDLHlDQUFELEVBQXdCcEMsUUFBUSxDQUFDO0FBQUNYLElBQUFBLE1BQU0sRUFBRWdDLFlBQVQ7QUFBdUJELElBQUFBLE9BQU8sRUFBUEE7QUFBdkIsR0FBRCxDQUFoQyxDQUF4QixDQTFCYyxFQTRCZEwsS0FBSyxDQUFDLFNBQUQsQ0FBTCxDQUFpQlosTUFBTSxDQUFDa0Msd0NBQUQsQ0FBdkIsQ0E1QmMsRUE4QmR0QixLQUFLLENBQUMsU0FBRCxDQUFMLENBQWlCWixNQUFNLENBQUNtQyxtQ0FBRCxFQUFxQnRDLFFBQVEsQ0FBQyxJQUFELENBQTdCLENBQXZCLENBOUJjLEVBZ0NkZSxLQUFLLENBQUMsU0FBRCxDQUFMLENBQWlCRixNQUFNLENBQUNPLE9BQU8sQ0FBQ21CLGNBQVIsQ0FBdUIsVUFBdkIsSUFBcUM7QUFBQ0MsSUFBQUEsUUFBUSxFQUFFcEIsT0FBTyxDQUFDb0I7QUFBbkIsR0FBckMsR0FBb0UsRUFBckUsQ0FBdkIsQ0FoQ2MsQ0FBRCxDQUFSLENBaUNKN0MsS0FqQ0ksQ0FBUDtBQWtDRCxDQW5ETTs7OztBQXFEQSxJQUFNOEMsc0JBQXNCLEdBQUcsU0FBekJBLHNCQUF5QixDQUFDOUMsS0FBRCxFQUFRK0MsTUFBUixFQUFtQjtBQUN2RDtBQUNBLE1BQU1DLFFBQVEsR0FBRyxxQ0FBbUJELE1BQU0sQ0FBQ0UsTUFBMUIsQ0FBakI7QUFDQSxNQUFNQyxTQUFTLEdBQUdwQyxRQUFRLENBQUMsQ0FDekJNLEtBQUssQ0FBQyxVQUFELENBQUwsQ0FDRUYsTUFBTSxDQUFDO0FBQ0xpQyxJQUFBQSxXQUFXLEVBQUUsS0FEUjtBQUVMQyxJQUFBQSxtQkFBbUIsRUFBRTtBQUZoQixHQUFELENBRFIsQ0FEeUIsQ0FBRCxDQUFSLENBT2ZwRCxLQVBlLENBQWxCLENBSHVELENBWXZEOztBQUNBLFNBQU9jLFFBQVEsQ0FBQ2tDLFFBQVEsQ0FBQ0ssR0FBVCxDQUFhLFVBQUEvQyxDQUFDO0FBQUEsV0FBSUUsTUFBTSxDQUFDYyxtQkFBRCxFQUFzQmpCLFFBQVEsQ0FBQ0MsQ0FBRCxDQUE5QixDQUFWO0FBQUEsR0FBZCxDQUFELENBQVIsQ0FBc0U0QyxTQUF0RSxDQUFQO0FBQ0QsQ0FkTTs7O0FBZ0JBLElBQU1JLG9CQUFvQixHQUFHaEMsbUJBQTdCIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IChjKSAyMDIwIFViZXIgVGVjaG5vbG9naWVzLCBJbmMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuLy8gaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0c1xuLy8gdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuLy8gY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4vLyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbi8vIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbi8vIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vIFRIRSBTT0ZUV0FSRS5cblxuLy8gQ29weXJpZ2h0IChjKSAyMDIwIFViZXIgVGVjaG5vbG9naWVzLCBJbmMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuLy8gaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0c1xuLy8gdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuLy8gdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlXywgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbi8vIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxuLy8gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7dG9nZ2xlTW9kYWxVcGRhdGVyLCBsb2FkRmlsZXNTdWNjZXNzVXBkYXRlcn0gZnJvbSAnLi91aS1zdGF0ZS11cGRhdGVycyc7XG5pbXBvcnQge1xuICB1cGRhdGVWaXNEYXRhVXBkYXRlciBhcyB2aXNTdGF0ZVVwZGF0ZVZpc0RhdGFVcGRhdGVyLFxuICBzZXRNYXBJbmZvVXBkYXRlclxufSBmcm9tICcuL3Zpcy1zdGF0ZS11cGRhdGVycyc7XG5pbXBvcnQge3JlY2VpdmVNYXBDb25maWdVcGRhdGVyIGFzIHN0YXRlTWFwQ29uZmlnVXBkYXRlcn0gZnJvbSAnLi9tYXAtc3RhdGUtdXBkYXRlcnMnO1xuaW1wb3J0IHtyZWNlaXZlTWFwQ29uZmlnVXBkYXRlciBhcyBzdHlsZU1hcENvbmZpZ1VwZGF0ZXJ9IGZyb20gJy4vbWFwLXN0eWxlLXVwZGF0ZXJzJztcbmltcG9ydCB7ZmluZE1hcEJvdW5kc30gZnJvbSAndXRpbHMvZGF0YS11dGlscyc7XG5pbXBvcnQgS2VwbGVyR2xTY2hlbWEgZnJvbSAnc2NoZW1hcyc7XG5pbXBvcnQge2lzUGxhaW5PYmplY3R9IGZyb20gJ3V0aWxzL3V0aWxzJztcbmltcG9ydCB7ZmlsZXNUb0RhdGFQYXlsb2FkfSBmcm9tICdwcm9jZXNzb3JzL2ZpbGUtaGFuZGxlcic7XG5pbXBvcnQgQ29uc29sZSBmcm9tICdnbG9iYWwvY29uc29sZSc7XG5cbi8vIGNvbXBvc2UgYWN0aW9uIHRvIGFwcGx5IHJlc3VsdCBtdWx0aXBsZSByZWR1Y2Vycywgd2l0aCB0aGUgb3V0cHV0IG9mIG9uZVxuXG4vKipcbiAqIFNvbWUgYWN0aW9ucyB3aWxsIGFmZmVjdCB0aGUgZW50aXJlIGtlcGxlci5sZyBpbnN0YW5jZSBzdGF0ZS5cbiAqIFRoZSB1cGRhdGVycyBmb3IgdGhlc2UgYWN0aW9ucyBpcyBleHBvcnRlZCBhcyBgY29tYmluZWRVcGRhdGVyc2AuIFRoZXNlIHVwZGF0ZXIgdGFrZSB0aGUgZW50aXJlIGluc3RhbmNlIHN0YXRlXG4gKiBhcyB0aGUgZmlyc3QgYXJndW1lbnQuIFJlYWQgbW9yZSBhYm91dCBbVXNpbmcgdXBkYXRlcnNdKC4uL2FkdmFuY2VkLXVzYWdlL3VzaW5nLXVwZGF0ZXJzLm1kKVxuICogQHB1YmxpY1xuICogQGV4YW1wbGVcbiAqXG4gKiBpbXBvcnQga2VwbGVyR2xSZWR1Y2VyLCB7Y29tYmluZWRVcGRhdGVyc30gZnJvbSAna2VwbGVyLmdsL3JlZHVjZXJzJztcbiAqIC8vIFJvb3QgUmVkdWNlclxuICogY29uc3QgcmVkdWNlcnMgPSBjb21iaW5lUmVkdWNlcnMoe1xuICogIGtlcGxlckdsOiBrZXBsZXJHbFJlZHVjZXIsXG4gKiAgYXBwOiBhcHBSZWR1Y2VyXG4gKiB9KTtcbiAqXG4gKiBjb25zdCBjb21wb3NlZFJlZHVjZXIgPSAoc3RhdGUsIGFjdGlvbikgPT4ge1xuICogIHN3aXRjaCAoYWN0aW9uLnR5cGUpIHtcbiAqICAgIC8vIGFkZCBkYXRhIHRvIG1hcCBhZnRlciByZWNlaXZpbmcgZGF0YSBmcm9tIHJlbW90ZSBzb3VyY2VzXG4gKiAgICBjYXNlICdMT0FEX1JFTU9URV9SRVNPVVJDRV9TVUNDRVNTJzpcbiAqICAgICAgcmV0dXJuIHtcbiAqICAgICAgICAuLi5zdGF0ZSxcbiAqICAgICAgICBrZXBsZXJHbDoge1xuICogICAgICAgICAgLi4uc3RhdGUua2VwbGVyR2wsXG4gKiAgICAgICAgICAvLyBwYXNzIGluIGtlcGxlci5nbCBpbnN0YW5jZSBzdGF0ZSB0byBjb21iaW5lZFVwZGF0ZXJzXG4gKiAgICAgICAgICBtYXA6ICBjb21iaW5lZFVwZGF0ZXJzLmFkZERhdGFUb01hcFVwZGF0ZXIoXG4gKiAgICAgICAgICAgc3RhdGUua2VwbGVyR2wubWFwLFxuICogICAgICAgICAgIHtcbiAqICAgICAgICAgICAgIHBheWxvYWQ6IHtcbiAqICAgICAgICAgICAgICAgZGF0YXNldHM6IGFjdGlvbi5kYXRhc2V0cyxcbiAqICAgICAgICAgICAgICAgb3B0aW9uczoge3JlYWRPbmx5OiB0cnVlfSxcbiAqICAgICAgICAgICAgICAgY29uZmlnOiBhY3Rpb24uY29uZmlnXG4gKiAgICAgICAgICAgICAgfVxuICogICAgICAgICAgICB9XG4gKiAgICAgICAgICApXG4gKiAgICAgICAgfVxuICogICAgICB9O1xuICogIH1cbiAqICByZXR1cm4gcmVkdWNlcnMoc3RhdGUsIGFjdGlvbik7XG4gKiB9O1xuICpcbiAqIGV4cG9ydCBkZWZhdWx0IGNvbXBvc2VkUmVkdWNlcjtcbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tdW51c2VkLXZhcnMgKi9cbmNvbnN0IGNvbWJpbmVkVXBkYXRlcnMgPSBudWxsO1xuLyogZXNsaW50LWVuYWJsZSBuby11bnVzZWQtdmFycyAqL1xuXG5leHBvcnQgY29uc3QgaXNWYWxpZENvbmZpZyA9IGNvbmZpZyA9PlxuICBpc1BsYWluT2JqZWN0KGNvbmZpZykgJiYgaXNQbGFpbk9iamVjdChjb25maWcuY29uZmlnKSAmJiBjb25maWcudmVyc2lvbjtcblxuZXhwb3J0IGNvbnN0IGRlZmF1bHRBZGREYXRhVG9NYXBPcHRpb25zID0ge1xuICBjZW50ZXJNYXA6IHRydWUsXG4gIGtlZXBFeGlzdGluZ0NvbmZpZzogZmFsc2Vcbn07XG5cbmNvbnN0IGlkZW50aXR5ID0gc3RhdGUgPT4gc3RhdGU7XG5cbi8qIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bnVzZWQtdmFycyAqL1xuZnVuY3Rpb24gbG9nKHRleHQpIHtcbiAgcmV0dXJuIHZhbHVlID0+IENvbnNvbGUubG9nKHRleHQsIHZhbHVlKTtcbn1cblxuZnVuY3Rpb24gcGF5bG9hZF8ocCkge1xuICByZXR1cm4ge3BheWxvYWQ6IHB9O1xufVxuXG5mdW5jdGlvbiBhcHBseV8odXBkYXRlciwgcGF5bG9hZCkge1xuICByZXR1cm4gc3RhdGUgPT4gdXBkYXRlcihzdGF0ZSwgcGF5bG9hZCk7XG59XG5cbmZ1bmN0aW9uIHdpdGhfKGZuKSB7XG4gIHJldHVybiBzdGF0ZSA9PiBmbihzdGF0ZSkoc3RhdGUpO1xufVxuXG5mdW5jdGlvbiBpZl8ocHJlZCwgZm4pIHtcbiAgcmV0dXJuIHByZWQgPyBmbiA6IGlkZW50aXR5O1xufVxuXG5mdW5jdGlvbiBjb21wb3NlXyhmbnMpIHtcbiAgcmV0dXJuIHN0YXRlID0+IGZucy5yZWR1Y2UoKHN0YXRlMiwgZm4pID0+IGZuKHN0YXRlMiksIHN0YXRlKTtcbn1cblxuZnVuY3Rpb24gbWVyZ2VfKG9iaikge1xuICByZXR1cm4gc3RhdGUgPT4gKHsuLi5zdGF0ZSwgLi4ub2JqfSk7XG59XG5cbmZ1bmN0aW9uIHBpY2tfKHByb3ApIHtcbiAgcmV0dXJuIGZuID0+IHN0YXRlID0+ICh7Li4uc3RhdGUsIFtwcm9wXTogZm4oc3RhdGVbcHJvcF0pfSk7XG59XG5cbi8qKlxuICogQ29tYmluZSBkYXRhIGFuZCBmdWxsIGNvbmZpZ3VyYXRpb24gdXBkYXRlIGluIGEgc2luZ2xlIGFjdGlvblxuICpcbiAqIEBtZW1iZXJvZiBjb21iaW5lZFVwZGF0ZXJzXG4gKiBAcGFyYW0ge09iamVjdH0gc3RhdGUga2VwbGVyLmdsIGluc3RhbmNlIHN0YXRlLCBjb250YWluaW5nIGFsbCBzdWJyZWR1Y2VyIHN0YXRlXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uLnBheWxvYWQgYHtkYXRhc2V0cywgb3B0aW9ucywgY29uZmlnfWBcbiAqIEBwYXJhbSB7QXJyYXk8T2JqZWN0PnxPYmplY3R9IGFjdGlvbi5wYXlsb2FkLmRhdGFzZXRzIC0gKioqcmVxdWlyZWQqKiBkYXRhc2V0cyBjYW4gYmUgYSBkYXRhc2V0IG9yIGFuIGFycmF5IG9mIGRhdGFzZXRzXG4gKiBFYWNoIGRhdGFzZXQgb2JqZWN0IG5lZWRzIHRvIGhhdmUgYGluZm9gIGFuZCBgZGF0YWAgcHJvcGVydHkuXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uLnBheWxvYWQuZGF0YXNldHMuaW5mbyAtaW5mbyBvZiBhIGRhdGFzZXRcbiAqIEBwYXJhbSB7c3RyaW5nfSBhY3Rpb24ucGF5bG9hZC5kYXRhc2V0cy5pbmZvLmlkIC0gaWQgb2YgdGhpcyBkYXRhc2V0LiBJZiBjb25maWcgaXMgZGVmaW5lZCwgYGlkYCBzaG91bGQgbWF0Y2hlcyB0aGUgYGRhdGFJZGAgaW4gY29uZmlnLlxuICogQHBhcmFtIHtzdHJpbmd9IGFjdGlvbi5wYXlsb2FkLmRhdGFzZXRzLmluZm8ubGFiZWwgLSBBIGRpc3BsYXkgbmFtZSBvZiB0aGlzIGRhdGFzZXRcbiAqIEBwYXJhbSB7T2JqZWN0fSBhY3Rpb24ucGF5bG9hZC5kYXRhc2V0cy5kYXRhIC0gKioqcmVxdWlyZWQqKiBUaGUgZGF0YSBvYmplY3QsIGluIGEgdGFidWxhciBmb3JtYXQgd2l0aCAyIHByb3BlcnRpZXMgYGZpZWxkc2AgYW5kIGByb3dzYFxuICogQHBhcmFtIHtBcnJheTxPYmplY3Q+fSBhY3Rpb24ucGF5bG9hZC5kYXRhc2V0cy5kYXRhLmZpZWxkcyAtICoqKnJlcXVpcmVkKiogQXJyYXkgb2YgZmllbGRzLFxuICogQHBhcmFtIHtzdHJpbmd9IGFjdGlvbi5wYXlsb2FkLmRhdGFzZXRzLmRhdGEuZmllbGRzLm5hbWUgLSAqKipyZXF1aXJlZCoqIE5hbWUgb2YgdGhlIGZpZWxkLFxuICogQHBhcmFtIHtBcnJheTxBcnJheT59IGFjdGlvbi5wYXlsb2FkLmRhdGFzZXRzLmRhdGEucm93cyAtICoqKnJlcXVpcmVkKiogQXJyYXkgb2Ygcm93cywgaW4gYSB0YWJ1bGFyIGZvcm1hdCB3aXRoIGBmaWVsZHNgIGFuZCBgcm93c2BcbiAqIEBwYXJhbSB7T2JqZWN0fSBhY3Rpb24ucGF5bG9hZC5vcHRpb25zIG9wdGlvbiBvYmplY3QgYHtjZW50ZXJNYXA6IHRydWV9YFxuICogQHBhcmFtIHtPYmplY3R9IGFjdGlvbi5wYXlsb2FkLmNvbmZpZyBtYXAgY29uZmlnXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBuZXh0U3RhdGVcbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGNvbnN0IGFkZERhdGFUb01hcFVwZGF0ZXIgPSAoc3RhdGUsIHtwYXlsb2FkfSkgPT4ge1xuICBjb25zdCB7ZGF0YXNldHMsIGNvbmZpZywgaW5mb30gPSBwYXlsb2FkO1xuXG4gIGNvbnN0IG9wdGlvbnMgPSB7XG4gICAgLi4uZGVmYXVsdEFkZERhdGFUb01hcE9wdGlvbnMsXG4gICAgLi4ucGF5bG9hZC5vcHRpb25zXG4gIH07XG5cbiAgbGV0IHBhcnNlZENvbmZpZyA9IGNvbmZpZztcblxuICBpZiAoaXNWYWxpZENvbmZpZyhjb25maWcpKSB7XG4gICAgLy8gaWYgcGFzc2VkIGluIHNhdmVkIGNvbmZpZ1xuICAgIHBhcnNlZENvbmZpZyA9IEtlcGxlckdsU2NoZW1hLnBhcnNlU2F2ZWRDb25maWcoY29uZmlnKTtcbiAgfVxuICBjb25zdCBvbGRMYXllcnMgPSBzdGF0ZS52aXNTdGF0ZS5sYXllcnM7XG4gIGNvbnN0IGZpbHRlck5ld2x5QWRkZWRMYXllcnMgPSBsYXllcnMgPT4gbGF5ZXJzLmZpbHRlcihubCA9PiAhb2xkTGF5ZXJzLmZpbmQob2wgPT4gb2wgPT09IG5sKSk7XG5cbiAgcmV0dXJuIGNvbXBvc2VfKFtcbiAgICBwaWNrXygndmlzU3RhdGUnKShcbiAgICAgIGFwcGx5Xyh2aXNTdGF0ZVVwZGF0ZVZpc0RhdGFVcGRhdGVyLCB7XG4gICAgICAgIGRhdGFzZXRzLFxuICAgICAgICBvcHRpb25zLFxuICAgICAgICBjb25maWc6IHBhcnNlZENvbmZpZ1xuICAgICAgfSlcbiAgICApLFxuXG4gICAgaWZfKGluZm8sIHBpY2tfKCd2aXNTdGF0ZScpKGFwcGx5XyhzZXRNYXBJbmZvVXBkYXRlciwge2luZm99KSkpLFxuXG4gICAgd2l0aF8oKHt2aXNTdGF0ZX0pID0+XG4gICAgICBwaWNrXygnbWFwU3RhdGUnKShcbiAgICAgICAgYXBwbHlfKFxuICAgICAgICAgIHN0YXRlTWFwQ29uZmlnVXBkYXRlcixcbiAgICAgICAgICBwYXlsb2FkXyh7XG4gICAgICAgICAgICBjb25maWc6IHBhcnNlZENvbmZpZyxcbiAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICBib3VuZHM6IG9wdGlvbnMuY2VudGVyTWFwXG4gICAgICAgICAgICAgID8gZmluZE1hcEJvdW5kcyhmaWx0ZXJOZXdseUFkZGVkTGF5ZXJzKHZpc1N0YXRlLmxheWVycykpXG4gICAgICAgICAgICAgIDogbnVsbFxuICAgICAgICAgIH0pXG4gICAgICAgIClcbiAgICAgIClcbiAgICApLFxuXG4gICAgcGlja18oJ21hcFN0eWxlJykoYXBwbHlfKHN0eWxlTWFwQ29uZmlnVXBkYXRlciwgcGF5bG9hZF8oe2NvbmZpZzogcGFyc2VkQ29uZmlnLCBvcHRpb25zfSkpKSxcblxuICAgIHBpY2tfKCd1aVN0YXRlJykoYXBwbHlfKGxvYWRGaWxlc1N1Y2Nlc3NVcGRhdGVyKSksXG5cbiAgICBwaWNrXygndWlTdGF0ZScpKGFwcGx5Xyh0b2dnbGVNb2RhbFVwZGF0ZXIsIHBheWxvYWRfKG51bGwpKSksXG5cbiAgICBwaWNrXygndWlTdGF0ZScpKG1lcmdlXyhvcHRpb25zLmhhc093blByb3BlcnR5KCdyZWFkT25seScpID8ge3JlYWRPbmx5OiBvcHRpb25zLnJlYWRPbmx5fSA6IHt9KSlcbiAgXSkoc3RhdGUpO1xufTtcblxuZXhwb3J0IGNvbnN0IGxvYWRGaWxlU3VjY2Vzc1VwZGF0ZXIgPSAoc3RhdGUsIGFjdGlvbikgPT4ge1xuICAvLyBzdGlsbCBtb3JlIHRvIGxvYWRcbiAgY29uc3QgcGF5bG9hZHMgPSBmaWxlc1RvRGF0YVBheWxvYWQoYWN0aW9uLnJlc3VsdCk7XG4gIGNvbnN0IG5leHRTdGF0ZSA9IGNvbXBvc2VfKFtcbiAgICBwaWNrXygndmlzU3RhdGUnKShcbiAgICAgIG1lcmdlXyh7XG4gICAgICAgIGZpbGVMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgZmlsZUxvYWRpbmdQcm9ncmVzczogMTAwXG4gICAgICB9KVxuICAgIClcbiAgXSkoc3RhdGUpO1xuXG4gIC8vIG1ha2UgbXVsdGlwbGUgYWRkIGRhdGEgdG8gbWFwIGNhbGxzXG4gIHJldHVybiBjb21wb3NlXyhwYXlsb2Fkcy5tYXAocCA9PiBhcHBseV8oYWRkRGF0YVRvTWFwVXBkYXRlciwgcGF5bG9hZF8ocCkpKSkobmV4dFN0YXRlKTtcbn07XG5cbmV4cG9ydCBjb25zdCBhZGREYXRhVG9NYXBDb21wb3NlZCA9IGFkZERhdGFUb01hcFVwZGF0ZXI7XG4iXX0=
;