UNPKG

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
"use strict"; 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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9yZWR1Y2Vycy9jb21iaW5lZC11cGRhdGVycy5qcyJdLCJuYW1lcyI6WyJjb21iaW5lZFVwZGF0ZXJzIiwiaXNWYWxpZENvbmZpZyIsImNvbmZpZyIsInZlcnNpb24iLCJkZWZhdWx0QWRkRGF0YVRvTWFwT3B0aW9ucyIsImNlbnRlck1hcCIsImtlZXBFeGlzdGluZ0NvbmZpZyIsImlkZW50aXR5Iiwic3RhdGUiLCJsb2ciLCJ0ZXh0IiwidmFsdWUiLCJDb25zb2xlIiwicGF5bG9hZF8iLCJwIiwicGF5bG9hZCIsImFwcGx5XyIsInVwZGF0ZXIiLCJ3aXRoXyIsImZuIiwiaWZfIiwicHJlZCIsImNvbXBvc2VfIiwiZm5zIiwicmVkdWNlIiwic3RhdGUyIiwibWVyZ2VfIiwib2JqIiwicGlja18iLCJwcm9wIiwiYWRkRGF0YVRvTWFwVXBkYXRlciIsImRhdGFzZXRzIiwiaW5mbyIsIm9wdGlvbnMiLCJwYXJzZWRDb25maWciLCJLZXBsZXJHbFNjaGVtYSIsInBhcnNlU2F2ZWRDb25maWciLCJvbGRMYXllcnMiLCJ2aXNTdGF0ZSIsImxheWVycyIsImZpbHRlck5ld2x5QWRkZWRMYXllcnMiLCJmaWx0ZXIiLCJubCIsImZpbmQiLCJvbCIsInZpc1N0YXRlVXBkYXRlVmlzRGF0YVVwZGF0ZXIiLCJzZXRNYXBJbmZvVXBkYXRlciIsInN0YXRlTWFwQ29uZmlnVXBkYXRlciIsImJvdW5kcyIsInN0eWxlTWFwQ29uZmlnVXBkYXRlciIsImxvYWRGaWxlc1N1Y2Nlc3NVcGRhdGVyIiwidG9nZ2xlTW9kYWxVcGRhdGVyIiwiaGFzT3duUHJvcGVydHkiLCJyZWFkT25seSIsImxvYWRGaWxlU3VjY2Vzc1VwZGF0ZXIiLCJhY3Rpb24iLCJwYXlsb2FkcyIsInJlc3VsdCIsIm5leHRTdGF0ZSIsImZpbGVMb2FkaW5nIiwiZmlsZUxvYWRpbmdQcm9ncmVzcyIsIm1hcCIsImFkZERhdGFUb01hcENvbXBvc2VkIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztB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eUIsQ0FBRCxDQUFSLENBT2ZwRCxLQVBlLENBQWxCLENBSHVELENBWXZEOztBQUNBLFNBQU9jLFFBQVEsQ0FBQ2tDLFFBQVEsQ0FBQ0ssR0FBVCxDQUFhLFVBQUEvQyxDQUFDO0FBQUEsV0FBSUUsTUFBTSxDQUFDYyxtQkFBRCxFQUFzQmpCLFFBQVEsQ0FBQ0MsQ0FBRCxDQUE5QixDQUFWO0FBQUEsR0FBZCxDQUFELENBQVIsQ0FBc0U0QyxTQUF0RSxDQUFQO0FBQ0QsQ0FkTTs7O0FBZ0JBLElBQU1JLG9CQUFvQixHQUFHaEMsbUJBQTdCIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQ29weXJpZ2h0IChjKSAyMDIwIFViZXIgVGVjaG5vbG9naWVzLCBJbmMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuLy8gaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0c1xuLy8gdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuLy8gY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4vLyBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4vLyBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4vLyBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbi8vIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuLy8gQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuLy8gTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbi8vIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbi8vIFRIRSBTT0ZUV0FSRS5cblxuLy8gQ29weXJpZ2h0IChjKSAyMDIwIFViZXIgVGVjaG5vbG9naWVzLCBJbmMuXG4vL1xuLy8gUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuLy8gb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuLy8gaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0c1xuLy8gdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuLy8gdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlXywgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbi8vIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxuLy8gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCB7dG9nZ2xlTW9kYWxVcGRhdGVyLCBsb2FkRmlsZXNTdWNjZXNzVXBkYXRlcn0gZnJvbSAnLi91aS1zdGF0ZS11cGRhdGVycyc7XG5pbXBvcnQge1xuICB1cGRhdGVWaXNEYXRhVXBkYXRlciBhcyB2aXNTdGF0ZVVwZGF0ZVZpc0RhdGFVcGRhdGVyLFxuICBzZXRNYXBJbmZvVXBkYXRlclxufSBmcm9tICcuL3Zpcy1zdGF0ZS11cGRhdGVycyc7XG5pbXBvcnQge3JlY2VpdmVNYXBDb25maWdVcGRhdGVyIGFzIHN0YXRlTWFwQ29uZmlnVXBkYXRlcn0gZnJvbSAnLi9tYXAtc3RhdGUtdXBkYXRlcnMnO1xuaW1wb3J0IHtyZWNlaXZlTWFwQ29uZmlnVXBkYXRlciBhcyBzdHlsZU1hcENvbmZpZ1VwZGF0ZXJ9IGZyb20gJy4vbWFwLXN0eWxlLXVwZGF0ZXJzJztcbmltcG9ydCB7ZmluZE1hcEJvdW5kc30gZnJvbSAndXRpbHMvZGF0YS11dGlscyc7XG5pbXBvcnQgS2VwbGVyR2xTY2hlbWEgZnJvbSAnc2NoZW1hcyc7XG5pbXBvcnQge2lzUGxhaW5PYmplY3R9IGZyb20gJ3V0aWxzL3V0aWxzJztcbmltcG9ydCB7ZmlsZXNUb0RhdGFQYXlsb2FkfSBmcm9tICdwcm9jZXNzb3JzL2ZpbGUtaGFuZGxlcic7XG5pbXBvcnQgQ29uc29sZSBmcm9tICdnbG9iYWwvY29uc29sZSc7XG5cbi8vIGNvbXBvc2UgYWN0aW9uIHRvIGFwcGx5IHJlc3VsdCBtdWx0aXBsZSByZWR1Y2Vycywgd2l0aCB0aGUgb3V0cHV0IG9mIG9uZVxuXG4vKipcbiAqIFNvbWUgYWN0aW9ucyB3aWxsIGFmZmVjdCB0aGUgZW50aXJlIGtlcGxlci5sZyBpbnN0YW5jZSBzdGF0ZS5cbiAqIFRoZSB1cGRhdGVycyBmb3IgdGhlc2UgYWN0aW9ucyBpcyBleHBvcnRlZCBhcyBgY29tYmluZWRVcGRhdGVyc2AuIFRoZXNlIHVwZGF0ZXIgdGFrZSB0aGUgZW50aXJlIGluc3RhbmNlIHN0YXRlXG4gKiBhcyB0aGUgZmlyc3QgYXJndW1lbnQuIFJlYWQgbW9yZSBhYm91dCBbVXNpbmcgdXBkYXRlcnNdKC4uL2FkdmFuY2VkLXVzYWdlL3VzaW5nLXVwZGF0ZXJzLm1kKVxuICogQHB1YmxpY1xuICogQGV4YW1wbGVcbiAqXG4gKiBpbXBvcnQga2VwbGVyR2xSZWR1Y2VyLCB7Y29tYmluZWRVcGRhdGVyc30gZnJvbSAna2VwbGVyLmdsL3JlZHVjZXJzJztcbiAqIC8vIFJvb3QgUmVkdWNlclxuICogY29uc3QgcmVkdWNlcnMgPSBjb21iaW5lUmVkdWNlcnMoe1xuICogIGtlcGxlckdsOiBrZXBsZXJHbFJlZHVjZXIsXG4gKiAgYXBwOiBhcHBSZWR1Y2VyXG4gKiB9KTtcbiAqXG4gKiBjb25zdCBjb21wb3NlZFJlZHVjZXIgPSAoc3RhdGUsIGFjdGlvbikgPT4ge1xuICogIHN3aXRjaCAoYWN0aW9uLnR5cGUpIHtcbiAqICAgIC8vIGFkZCBkYXRhIHRvIG1hcCBhZnRlciByZWNlaXZpbmcgZGF0YSBmcm9tIHJlbW90ZSBzb3VyY2VzXG4gKiAgICBjYXNlICdMT0FEX1JFTU9URV9SRVNPVVJDRV9TVUNDRVNTJzpcbiAqICAgICAgcmV0dXJuIHtcbiAqICAgICAgICAuLi5zdGF0ZSxcbiAqICAgICAgICBrZXBsZXJHbDoge1xuICogICAgICAgICAgLi4uc3RhdGUua2VwbGVyR2wsXG4gKiAgICAgICAgICAvLyBwYXNzIGluIGtlcGxlci5nbCBpbnN0YW5jZSBzdGF0ZSB0byBjb21iaW5lZFVwZGF0ZXJzXG4gKiAgICAgICAgICBtYXA6ICBjb21iaW5lZFVwZGF0ZXJzLmFkZERhdGFUb01hcFVwZGF0ZXIoXG4gKiAgICAgICAgICAgc3RhdGUua2VwbGVyR2wubWFwLFxuICogICAgICAgICAgIHtcbiAqICAgICAgICAgICAgIHBheWxvYWQ6IHtcbiAqICAgICAgICAgICAgICAgZGF0YXNldHM6IGFjdGlvbi5kYXRhc2V0cyxcbiAqICAgICAgICAgICAgICAgb3B0aW9uczoge3JlYWRPbmx5OiB0cnVlfSxcbiAqICAgICAgICAgICAgICAgY29uZmlnOiBhY3Rpb24uY29uZmlnXG4gKiAgICAgICAgICAgICAgfVxuICogICAgICAgICAgICB9XG4gKiAgICAgICAgICApXG4gKiAgICAgICAgfVxuICogICAgICB9O1xuICogIH1cbiAqICByZXR1cm4gcmVkdWNlcnMoc3RhdGUsIGFjdGlvbik7XG4gKiB9O1xuICpcbiAqIGV4cG9ydCBkZWZhdWx0IGNvbXBvc2VkUmVkdWNlcjtcbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tdW51c2VkLXZhcnMgKi9cbmNvbnN0IGNvbWJpbmVkVXBkYXRlcnMgPSBudWxsO1xuLyogZXNsaW50LWVuYWJsZSBuby11bnVzZWQtdmFycyAqL1xuXG5leHBvcnQgY29uc3QgaXNWYWxpZENvbmZpZyA9IGNvbmZpZyA9PlxuICBpc1BsYWluT2JqZWN0KGNvbmZpZykgJiYgaXNQbGFpbk9iamVjdChjb25maWcuY29uZmlnKSAmJiBjb25maWcudmVyc2lvbjtcblxuZXhwb3J0IGNvbnN0IGRlZmF1bHRBZGREYXRhVG9NYXBPcHRpb25zID0ge1xuICBjZW50ZXJNYXA6IHRydWUsXG4gIGtlZXBFeGlzdGluZ0NvbmZpZzogZmFsc2Vcbn07XG5cbmNvbnN0IGlkZW50aXR5ID0gc3RhdGUgPT4gc3RhdGU7XG5cbi8qIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bnVzZWQtdmFycyAqL1xuZnVuY3Rpb24gbG9nKHRleHQpIHtcbiAgcmV0dXJuIHZhbHVlID0+IENvbnNvbGUubG9nKHRleHQsIHZhbHVlKTtcbn1cblxuZnVuY3Rpb24gcGF5bG9hZF8ocCkge1xuICByZXR1cm4ge3BheWxvYWQ6IHB9O1xufVxuXG5mdW5jdGlvbiBhcHBseV8odXBkYXRlciwgcGF5bG9hZCkge1xuICByZXR1cm4gc3RhdGUgPT4gdXBkYXRlcihzdGF0ZSwgcGF5bG9hZCk7XG59XG5cbmZ1bmN0aW9uIHdpdGhfKGZuKSB7XG4gIHJldHVybiBzdGF0ZSA9PiBmbihzdGF0ZSkoc3RhdGUpO1xufVxuXG5mdW5jdGlvbiBpZl8ocHJlZCwgZm4pIHtcbiAgcmV0dXJuIHByZWQgPyBmbiA6IGlkZW50aXR5O1xufVxuXG5mdW5jdGlvbiBjb21wb3NlXyhmbnMpIHtcbiAgcmV0dXJuIHN0YXRlID0+IGZucy5yZWR1Y2UoKHN0YXRlMiwgZm4pID0+IGZuKHN0YXRlMiksIHN0YXRlKTtcbn1cblxuZnVuY3Rpb24gbWVyZ2VfKG9iaikge1xuICByZXR1cm4gc3RhdGUgPT4gKHsuLi5zdGF0ZSwgLi4ub2JqfSk7XG59XG5cbmZ1bmN0aW9uIHBpY2tfKHByb3ApIHtcbiAgcmV0dXJuIGZuID0+IHN0YXRlID0+ICh7Li4uc3RhdGUsIFtwcm9wXTogZm4oc3RhdGVbcHJvcF0pfSk7XG59XG5cbi8qKlxuICogQ29tYmluZSBkYXRhIGFuZCBmdWxsIGNvbmZpZ3VyYXRpb24gdXBkYXRlIGluIGEgc2luZ2xlIGFjdGlvblxuICpcbiAqIEBtZW1iZXJvZiBjb21iaW5lZFVwZGF0ZXJzXG4gKiBAcGFyYW0ge09iamVjdH0gc3RhdGUga2VwbGVyLmdsIGluc3RhbmNlIHN0YXRlLCBjb250YWluaW5nIGFsbCBzdWJyZWR1Y2VyIHN0YXRlXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uLnBheWxvYWQgYHtkYXRhc2V0cywgb3B0aW9ucywgY29uZmlnfWBcbiAqIEBwYXJhbSB7QXJyYXk8T2JqZWN0PnxPYmplY3R9IGFjdGlvbi5wYXlsb2FkLmRhdGFzZXRzIC0gKioqcmVxdWlyZWQqKiBkYXRhc2V0cyBjYW4gYmUgYSBkYXRhc2V0IG9yIGFuIGFycmF5IG9mIGRhdGFzZXRzXG4gKiBFYWNoIGRhdGFzZXQgb2JqZWN0IG5lZWRzIHRvIGhhdmUgYGluZm9gIGFuZCBgZGF0YWAgcHJvcGVydHkuXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uLnBheWxvYWQuZGF0YXNldHMuaW5mbyAtaW5mbyBvZiBhIGRhdGFzZXRcbiAqIEBwYXJhbSB7c3RyaW5nfSBhY3Rpb24ucGF5bG9hZC5kYXRhc2V0cy5pbmZvLmlkIC0gaWQgb2YgdGhpcyBkYXRhc2V0LiBJZiBjb25maWcgaXMgZGVmaW5lZCwgYGlkYCBzaG91bGQgbWF0Y2hlcyB0aGUgYGRhdGFJZGAgaW4gY29uZmlnLlxuICogQHBhcmFtIHtzdHJpbmd9IGFjdGlvbi5wYXlsb2FkLmRhdGFzZXRzLmluZm8ubGFiZWwgLSBBIGRpc3BsYXkgbmFtZSBvZiB0aGlzIGRhdGFzZXRcbiAqIEBwYXJhbSB7T2JqZWN0fSBhY3Rpb24ucGF5bG9hZC5kYXRhc2V0cy5kYXRhIC0gKioqcmVxdWlyZWQqKiBUaGUgZGF0YSBvYmplY3QsIGluIGEgdGFidWxhciBmb3JtYXQgd2l0aCAyIHByb3BlcnRpZXMgYGZpZWxkc2AgYW5kIGByb3dzYFxuICogQHBhcmFtIHtBcnJheTxPYmplY3Q+fSBhY3Rpb24ucGF5bG9hZC5kYXRhc2V0cy5kYXRhLmZpZWxkcyAtICoqKnJlcXVpcmVkKiogQXJyYXkgb2YgZmllbGRzLFxuICogQHBhcmFtIHtzdHJpbmd9IGFjdGlvbi5wYXlsb2FkLmRhdGFzZXRzLmRhdGEuZmllbGRzLm5hbWUgLSAqKipyZXF1aXJlZCoqIE5hbWUgb2YgdGhlIGZpZWxkLFxuICogQHBhcmFtIHtBcnJheTxBcnJheT59IGFjdGlvbi5wYXlsb2FkLmRhdGFzZXRzLmRhdGEucm93cyAtICoqKnJlcXVpcmVkKiogQXJyYXkgb2Ygcm93cywgaW4gYSB0YWJ1bGFyIGZvcm1hdCB3aXRoIGBmaWVsZHNgIGFuZCBgcm93c2BcbiAqIEBwYXJhbSB7T2JqZWN0fSBhY3Rpb24ucGF5bG9hZC5vcHRpb25zIG9wdGlvbiBvYmplY3QgYHtjZW50ZXJNYXA6IHRydWV9YFxuICogQHBhcmFtIHtPYmplY3R9IGFjdGlvbi5wYXlsb2FkLmNvbmZpZyBtYXAgY29uZmlnXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBuZXh0U3RhdGVcbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGNvbnN0IGFkZERhdGFUb01hcFVwZGF0ZXIgPSAoc3RhdGUsIHtwYXlsb2FkfSkgPT4ge1xuICBjb25zdCB7ZGF0YXNldHMsIGNvbmZpZywgaW5mb30gPSBwYXlsb2FkO1xuXG4gIGNvbnN0IG9wdGlvbnMgPSB7XG4gICAgLi4uZGVmYXVsdEFkZERhdGFUb01hcE9wdGlvbnMsXG4gICAgLi4ucGF5bG9hZC5vcHRpb25zXG4gIH07XG5cbiAgbGV0IHBhcnNlZENvbmZpZyA9IGNvbmZpZztcblxuICBpZiAoaXNWYWxpZENvbmZpZyhjb25maWcpKSB7XG4gICAgLy8gaWYgcGFzc2VkIGluIHNhdmVkIGNvbmZpZ1xuICAgIHBhcnNlZENvbmZpZyA9IEtlcGxlckdsU2NoZW1hLnBhcnNlU2F2ZWRDb25maWcoY29uZmlnKTtcbiAgfVxuICBjb25zdCBvbGRMYXllcnMgPSBzdGF0ZS52aXNTdGF0ZS5sYXllcnM7XG4gIGNvbnN0IGZpbHRlck5ld2x5QWRkZWRMYXllcnMgPSBsYXllcnMgPT4gbGF5ZXJzLmZpbHRlcihubCA9PiAhb2xkTGF5ZXJzLmZpbmQob2wgPT4gb2wgPT09IG5sKSk7XG5cbiAgcmV0dXJuIGNvbXBvc2VfKFtcbiAgICBwaWNrXygndmlzU3RhdGUnKShcbiAgICAgIGFwcGx5Xyh2aXNTdGF0ZVVwZGF0ZVZpc0RhdGFVcGRhdGVyLCB7XG4gICAgICAgIGRhdGFzZXRzLFxuICAgICAgICBvcHRpb25zLFxuICAgICAgICBjb25maWc6IHBhcnNlZENvbmZpZ1xuICAgICAgfSlcbiAgICApLFxuXG4gICAgaWZfKGluZm8sIHBpY2tfKCd2aXNTdGF0ZScpKGFwcGx5XyhzZXRNYXBJbmZvVXBkYXRlciwge2luZm99KSkpLFxuXG4gICAgd2l0aF8oKHt2aXNTdGF0ZX0pID0+XG4gICAgICBwaWNrXygnbWFwU3RhdGUnKShcbiAgICAgICAgYXBwbHlfKFxuICAgICAgICAgIHN0YXRlTWFwQ29uZmlnVXBkYXRlcixcbiAgICAgICAgICBwYXlsb2FkXyh7XG4gICAgICAgICAgICBjb25maWc6IHBhcnNlZENvbmZpZyxcbiAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICBib3VuZHM6IG9wdGlvbnMuY2VudGVyTWFwXG4gICAgICAgICAgICAgID8gZmluZE1hcEJvdW5kcyhmaWx0ZXJOZXdseUFkZGVkTGF5ZXJzKHZpc1N0YXRlLmxheWVycykpXG4gICAgICAgICAgICAgIDogbnVsbFxuICAgICAgICAgIH0pXG4gICAgICAgIClcbiAgICAgIClcbiAgICApLFxuXG4gICAgcGlja18oJ21hcFN0eWxlJykoYXBwbHlfKHN0eWxlTWFwQ29uZmlnVXBkYXRlciwgcGF5bG9hZF8oe2NvbmZpZzogcGFyc2VkQ29uZmlnLCBvcHRpb25zfSkpKSxcblxuICAgIHBpY2tfKCd1aVN0YXRlJykoYXBwbHlfKGxvYWRGaWxlc1N1Y2Nlc3NVcGRhdGVyKSksXG5cbiAgICBwaWNrXygndWlTdGF0ZScpKGFwcGx5Xyh0b2dnbGVNb2RhbFVwZGF0ZXIsIHBheWxvYWRfKG51bGwpKSksXG5cbiAgICBwaWNrXygndWlTdGF0ZScpKG1lcmdlXyhvcHRpb25zLmhhc093blByb3BlcnR5KCdyZWFkT25seScpID8ge3JlYWRPbmx5OiBvcHRpb25zLnJlYWRPbmx5fSA6IHt9KSlcbiAgXSkoc3RhdGUpO1xufTtcblxuZXhwb3J0IGNvbnN0IGxvYWRGaWxlU3VjY2Vzc1VwZGF0ZXIgPSAoc3RhdGUsIGFjdGlvbikgPT4ge1xuICAvLyBzdGlsbCBtb3JlIHRvIGxvYWRcbiAgY29uc3QgcGF5bG9hZHMgPSBmaWxlc1RvRGF0YVBheWxvYWQoYWN0aW9uLnJlc3VsdCk7XG4gIGNvbnN0IG5leHRTdGF0ZSA9IGNvbXBvc2VfKFtcbiAgICBwaWNrXygndmlzU3RhdGUnKShcbiAgICAgIG1lcmdlXyh7XG4gICAgICAgIGZpbGVMb2FkaW5nOiBmYWxzZSxcbiAgICAgICAgZmlsZUxvYWRpbmdQcm9ncmVzczogMTAwXG4gICAgICB9KVxuICAgIClcbiAgXSkoc3RhdGUpO1xuXG4gIC8vIG1ha2UgbXVsdGlwbGUgYWRkIGRhdGEgdG8gbWFwIGNhbGxzXG4gIHJldHVybiBjb21wb3NlXyhwYXlsb2Fkcy5tYXAocCA9PiBhcHBseV8oYWRkRGF0YVRvTWFwVXBkYXRlciwgcGF5bG9hZF8ocCkpKSkobmV4dFN0YXRlKTtcbn07XG5cbmV4cG9ydCBjb25zdCBhZGREYXRhVG9NYXBDb21wb3NlZCA9IGFkZERhdGFUb01hcFVwZGF0ZXI7XG4iXX0=