kepler.gl.geoiq
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
528 lines (452 loc) • 58.6 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
var _typeof = require("@babel/runtime/helpers/typeof");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.addCustomMapStyleUpdater = exports.INITIAL_MAP_STYLE = void 0;
exports.getInitialInputStyle = getInitialInputStyle;
exports.getMapStyles = getMapStyles;
exports.set3dBuildingColorUpdater = exports.resetMapConfigMapStyleUpdater = exports.requestMapStylesUpdater = exports.receiveMapConfigUpdater = exports.mapStyleChangeUpdater = exports.mapConfigChangeUpdater = exports.loadMapStylesUpdater = exports.loadMapStyleErrUpdater = exports.loadCustomMapStyleUpdater = exports.inputMapStyleUpdater = exports.initMapStyleUpdater = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _tasks = _interopRequireWildcard(require("react-palm/tasks"));
var _lodash = _interopRequireDefault(require("lodash.clonedeep"));
var _mapboxGlStyleEditor = require("../utils/map-style-utils/mapbox-gl-style-editor");
var _defaultSettings = require("../constants/default-settings");
var _utils = require("../utils/utils");
var _tasks2 = require("../tasks/tasks");
var _mapStyleActions = require("../actions/map-style-actions");
var _d3Color = require("d3-color");
var _colorUtils = require("../utils/color-utils");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { (0, _defineProperty2["default"])(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var DEFAULT_BLDG_COLOR = '#D1CEC7';
var getDefaultState = function getDefaultState() {
var visibleLayerGroups = {};
var styleType = 'auto';
var topLayerGroups = {};
return {
styleType: styleType,
visibleLayerGroups: visibleLayerGroups,
topLayerGroups: topLayerGroups,
mapStyles: _defaultSettings.DEFAULT_MAP_STYLES.reduce(function (accu, curr) {
return _objectSpread(_objectSpread({}, accu), {}, (0, _defineProperty2["default"])({}, curr.id, curr));
}, {}),
// save mapbox access token
mapboxApiAccessToken: null,
mapboxApiUrl: _defaultSettings.DEFAULT_MAPBOX_API_URL,
mapStylesReplaceDefault: false,
inputStyle: getInitialInputStyle(),
threeDBuildingColor: (0, _colorUtils.hexToRgb)(DEFAULT_BLDG_COLOR),
custom3DBuildingColor: false
};
};
/**
* Updaters for `mapStyle`. Can be used in your root reducer to directly modify kepler.gl's state.
* Read more about [Using updaters](../advanced-usage/using-updaters.md)
* @public
* @example
*
* import keplerGlReducer, {mapStyleUpdaters} from 'kepler.gl/reducers';
* // Root Reducer
* const reducers = combineReducers({
* keplerGl: keplerGlReducer,
* app: appReducer
* });
*
* const composedReducer = (state, action) => {
* switch (action.type) {
* // click button to hide label from background map
* case 'CLICK_BUTTON':
* return {
* ...state,
* keplerGl: {
* ...state.keplerGl,
* foo: {
* ...state.keplerGl.foo,
* mapStyle: mapStyleUpdaters.mapConfigChangeUpdater(
* mapStyle,
* {payload: {visibleLayerGroups: {label: false, road: true, background: true}}}
* )
* }
* }
* };
* }
* return reducers(state, action);
* };
*
* export default composedReducer;
*/
/* eslint-disable no-unused-vars */
var mapStyleUpdaters = null;
/* eslint-enable no-unused-vars */
/**
* Default initial `mapStyle`
* @memberof mapStyleUpdaters
* @constant
* @property {string} styleType - Default: `'dark'`
* @property {Object} visibleLayerGroups - Default: `{}`
* @property {Object} topLayerGroups - Default: `{}`
* @property {Object} mapStyles - mapping from style key to style object
* @property {string} mapboxApiAccessToken - Default: `null`
* @Property {string} mapboxApiUrl - Default null
* @Property {Boolean} mapStylesReplaceDefault - Default: `false`
* @property {Object} inputStyle - Default: `{}`
* @property {Array} threeDBuildingColor - Default: `[r, g, b]`
* @public
*/
var INITIAL_MAP_STYLE = exports.INITIAL_MAP_STYLE = getDefaultState();
/**
* Create two map styles from preset map style, one for top map one for bottom
*
* @param {string} styleType - current map style
* @param {Object} visibleLayerGroups - visible layers of bottom map
* @param {Object} topLayerGroups - visible layers of top map
* @param {Object} mapStyles - a dictionary of all map styles
* @returns {Object} bottomMapStyle | topMapStyle | isRaster
*/
function getMapStyles(_ref) {
var styleType = _ref.styleType,
visibleLayerGroups = _ref.visibleLayerGroups,
topLayerGroups = _ref.topLayerGroups,
mapStyles = _ref.mapStyles;
var mapStyle = mapStyles[styleType]; // style might not be loaded yet
if (!mapStyle || !mapStyle.style) {
return {};
}
var editable = Object.keys(visibleLayerGroups).length;
var bottomMapStyle = !editable ? mapStyle.style : (0, _mapboxGlStyleEditor.editBottomMapStyle)({
id: styleType,
mapStyle: mapStyle,
visibleLayerGroups: visibleLayerGroups
});
var hasTopLayer = editable && Object.values(topLayerGroups).some(function (v) {
return v;
}); // mute top layer if not visible in bottom layer
var topLayers = hasTopLayer && Object.keys(topLayerGroups).reduce(function (accu, key) {
return _objectSpread(_objectSpread({}, accu), {}, (0, _defineProperty2["default"])({}, key, topLayerGroups[key] && visibleLayerGroups[key]));
}, {});
var topMapStyle = hasTopLayer ? (0, _mapboxGlStyleEditor.editTopMapStyle)({
id: styleType,
mapStyle: mapStyle,
visibleLayerGroups: topLayers
}) : null;
return {
bottomMapStyle: bottomMapStyle,
topMapStyle: topMapStyle,
editable: editable
};
}
function findLayerFillColor(layer) {
return layer && layer.paint && layer.paint['background-color'];
}
function get3DBuildingColor(style) {
// set building color to be the same as the background color.
if (!style.style) {
return DEFAULT_BLDG_COLOR;
}
var backgroundLayer = (style.style.layers || []).find(function (_ref2) {
var id = _ref2.id;
return id === 'background';
});
var buildingLayer = (style.style.layers || []).find(function (_ref3) {
var id = _ref3.id;
return id.match(/building/);
});
var buildingColor = findLayerFillColor(buildingLayer) || findLayerFillColor(backgroundLayer) || DEFAULT_BLDG_COLOR; // brighten or darken building based on style
var operation = style.id.match(/(?=(dark|night))/) ? 'brighter' : 'darker';
var alpha = 0.2;
var rgbObj = (0, _d3Color.rgb)(buildingColor)[operation]([alpha]);
return [rgbObj.r, rgbObj.g, rgbObj.b];
}
function getLayerGroupsFromStyle(style) {
return Array.isArray(style.layers) ? _defaultSettings.DEFAULT_LAYER_GROUPS.filter(function (lg) {
return style.layers.filter(lg.filter).length;
}) : [];
} // Updaters
/**
* Propagate `mapStyle` reducer with `mapboxApiAccessToken` and `mapStylesReplaceDefault`.
* if mapStylesReplaceDefault is true mapStyles is emptied; loadMapStylesUpdater() will
* populate mapStyles.
*
* @memberof mapStyleUpdaters
* @param {Object} state
* @param {Object} action
* @param {Object} action.payload
* @param {string} action.payload.mapboxApiAccessToken
* @returns {Object} nextState
* @public
*/
var initMapStyleUpdater = exports.initMapStyleUpdater = function initMapStyleUpdater(state, action) {
return _objectSpread(_objectSpread({}, state), {}, {
// save mapbox access token to map style state
mapboxApiAccessToken: (action.payload || {}).mapboxApiAccessToken,
mapboxApiUrl: (action.payload || {}).mapboxApiUrl || state.mapboxApiUrl,
mapStyles: action.payload && !action.payload.mapStylesReplaceDefault ? state.mapStyles : {},
mapStylesReplaceDefault: action.payload.mapStylesReplaceDefault || false
});
}; // });
/**
* Update `visibleLayerGroups`to change layer group visibility
* @memberof mapStyleUpdaters
* @param {Object} state `mapStyle`
* @param {Object} action
* @param {Object} action.payload new config `{visibleLayerGroups: {label: false, road: true, background: true}}`
* @returns {Object} nextState
* @public
*/
var mapConfigChangeUpdater = exports.mapConfigChangeUpdater = function mapConfigChangeUpdater(state, action) {
return _objectSpread(_objectSpread(_objectSpread({}, state), action.payload), getMapStyles(_objectSpread(_objectSpread({}, state), action.payload)));
};
/**
* Change to another map style. The selected style should already been loaded into `mapStyle.mapStyles`
* @memberof mapStyleUpdaters
* @param {Object} state `mapStyle`
* @param {Object} action
* @param {string} action.payload
* @returns {Object} nextState
* @public
*/
var mapStyleChangeUpdater = exports.mapStyleChangeUpdater = function mapStyleChangeUpdater(state, _ref4) {
var styleType = _ref4.payload;
if (!state.mapStyles[styleType]) {
// we might not have received the style yet
return state;
}
var defaultLGVisibility = (0, _mapboxGlStyleEditor.getDefaultLayerGroupVisibility)(state.mapStyles[styleType]);
var visibleLayerGroups = (0, _mapboxGlStyleEditor.mergeLayerGroupVisibility)(defaultLGVisibility, state.visibleLayerGroups);
var threeDBuildingColor = state.custom3DBuildingColor ? state.threeDBuildingColor : get3DBuildingColor(state.mapStyles[styleType]);
return _objectSpread(_objectSpread({}, state), {}, {
styleType: styleType,
visibleLayerGroups: visibleLayerGroups,
threeDBuildingColor: threeDBuildingColor
}, getMapStyles(_objectSpread(_objectSpread({}, state), {}, {
visibleLayerGroups: visibleLayerGroups,
styleType: styleType
})));
};
/**
* Callback when load map style success
* @memberof mapStyleUpdaters
* @param {Object} state `mapStyle`
* @param {Object} action
* @param {Object} action.payload a `{[id]: style}` mapping
* @return {Object} nextState
* @public
*/
var loadMapStylesUpdater = exports.loadMapStylesUpdater = function loadMapStylesUpdater(state, action) {
var newStyles = action.payload || {};
var addLayerGroups = Object.keys(newStyles).reduce(function (accu, id) {
return _objectSpread(_objectSpread({}, accu), {}, (0, _defineProperty2["default"])({}, id, _objectSpread(_objectSpread({}, newStyles[id]), {}, {
layerGroups: newStyles[id].layerGroups || getLayerGroupsFromStyle(newStyles[id].style)
})));
}, {}); // add new styles to state
var newState = _objectSpread(_objectSpread({}, state), {}, {
mapStyles: _objectSpread(_objectSpread({}, state.mapStyles), addLayerGroups)
});
return newStyles[state.styleType] ? mapStyleChangeUpdater(newState, {
payload: state.styleType
}) : newState;
};
/**
* Callback when load map style error
* @memberof mapStyleUpdaters
* @param {Object} state `mapStyle`
* @param {Object} action
* @param {*} action.payload error
* @returns {Object} nextState
* @public
*/
// do nothing for now, if didn't load, skip it
var loadMapStyleErrUpdater = exports.loadMapStyleErrUpdater = function loadMapStyleErrUpdater(state) {
return state;
};
var requestMapStylesUpdater = exports.requestMapStylesUpdater = function requestMapStylesUpdater(state, _ref5) {
var mapStyles = _ref5.payload;
var loadMapStyleTasks = getLoadMapStyleTasks(mapStyles, state.mapboxApiAccessToken, state.mapboxApiUrl);
return (0, _tasks.withTask)(state, loadMapStyleTasks);
};
/**
* Load map style object when pass in saved map config
* @memberof mapStyleUpdaters
* @param {Object} state `mapStyle`
* @param {Object} action
* @param {Object} action.payload saved map config `{mapStyle, visState, mapState}`
* @returns {Object} nextState or `react-pam` tasks to load map style object
*/
var receiveMapConfigUpdater = exports.receiveMapConfigUpdater = function receiveMapConfigUpdater(state, _ref6) {
var _ref6$payload$config = _ref6.payload.config,
config = _ref6$payload$config === void 0 ? {} : _ref6$payload$config;
var mapStyle = config.mapStyle;
if (!mapStyle) {
return state;
} // if saved custom mapStyles load the style object
var loadMapStyleTasks = mapStyle.mapStyles ? getLoadMapStyleTasks(mapStyle.mapStyles, state.mapboxApiAccessToken, state.mapboxApiUrl) : null; // merge default mapStyles
var merged = mapStyle.mapStyles ? _objectSpread(_objectSpread({}, mapStyle), {}, {
mapStyles: _objectSpread(_objectSpread({}, mapStyle.mapStyles), state.mapStyles)
}) : mapStyle; // set custom3DBuildingColor: true if mapStyle contains threeDBuildingColor
merged.custom3DBuildingColor = Boolean(mapStyle.threeDBuildingColor) || merged.custom3DBuildingColor;
var newState = mapConfigChangeUpdater(state, {
payload: merged
});
return loadMapStyleTasks ? (0, _tasks.withTask)(newState, loadMapStyleTasks) : newState;
};
function getLoadMapStyleTasks(mapStyles, mapboxApiAccessToken, mapboxApiUrl) {
return [_tasks["default"].all(Object.values(mapStyles).map(function (_ref7) {
var id = _ref7.id,
url = _ref7.url,
accessToken = _ref7.accessToken;
return {
id: id,
url: (0, _mapboxGlStyleEditor.isValidStyleUrl)(url) ? (0, _mapboxGlStyleEditor.getStyleDownloadUrl)(url, accessToken || mapboxApiAccessToken, mapboxApiUrl) : url
};
}).map(_tasks2.LOAD_MAP_STYLE_TASK)).bimap( // success
function (results) {
return (0, _mapStyleActions.loadMapStyles)(results.reduce(function (accu, _ref8) {
var id = _ref8.id,
style = _ref8.style;
return _objectSpread(_objectSpread({}, accu), {}, (0, _defineProperty2["default"])({}, id, _objectSpread(_objectSpread({}, mapStyles[id]), {}, {
style: style
})));
}, {}));
}, // error
_mapStyleActions.loadMapStyleErr)];
}
/**
* Reset map style config to initial state
* @memberof mapStyleUpdaters
* @param {Object} state `mapStyle`
* @returns {Object} nextState
* @public
*/
var resetMapConfigMapStyleUpdater = exports.resetMapConfigMapStyleUpdater = function resetMapConfigMapStyleUpdater(state) {
var emptyConfig = _objectSpread(_objectSpread(_objectSpread({}, INITIAL_MAP_STYLE), {}, {
mapboxApiAccessToken: state.mapboxApiAccessToken,
mapboxApiUrl: state.mapboxApiUrl,
mapStylesReplaceDefault: state.mapStylesReplaceDefault
}, state.initialState), {}, {
mapStyles: state.mapStyles,
initialState: state.initialState
});
return mapStyleChangeUpdater(emptyConfig, {
payload: emptyConfig.styleType
});
};
/**
* Callback when a custom map style object is received
* @memberof mapStyleUpdaters
* @param {Object} state `mapStyle`
* @param {Object} action
* @param {Object} action.payload
* @param {string} action.payload.icon
* @param {Object} action.payload.style
* @param {*} action.payload.error
* @returns {Object} nextState
* @public
*/
var loadCustomMapStyleUpdater = exports.loadCustomMapStyleUpdater = function loadCustomMapStyleUpdater(state, _ref9) {
var _ref9$payload = _ref9.payload,
icon = _ref9$payload.icon,
style = _ref9$payload.style,
error = _ref9$payload.error;
return _objectSpread(_objectSpread({}, state), {}, {
inputStyle: _objectSpread(_objectSpread(_objectSpread(_objectSpread({}, state.inputStyle), style ? {
id: style.id || (0, _utils.generateHashId)(),
// make a copy of the style object
style: (0, _lodash["default"])(style),
label: style.name,
// gathering layer group info from style json
layerGroups: getLayerGroupsFromStyle(style)
} : {}), icon ? {
icon: icon
} : {}), error !== undefined ? {
error: error
} : {})
});
};
/**
* Input a custom map style object
* @memberof mapStyleUpdaters
* @param {Object} state `mapStyle`
* @param {Object} action action object
* @param {Object} action.payload inputStyle
* @param {string} action.payload.url style url e.g. `'mapbox://styles/heshan/xxxxxyyyyzzz'`
* @param {string} action.payload.id style url e.g. `'custom_style_1'`
* @param {Object} action.payload.style actual mapbox style json
* @param {string} action.payload.name style name
* @param {Object} action.payload.layerGroups layer groups that can be used to set map layer visibility
* @param {Object} action.payload.icon icon image data url
* @returns {Object} nextState
* @public
*/
var inputMapStyleUpdater = exports.inputMapStyleUpdater = function inputMapStyleUpdater(state, _ref10) {
var _ref10$payload = _ref10.payload,
inputStyle = _ref10$payload.inputStyle,
mapState = _ref10$payload.mapState;
var updated = _objectSpread(_objectSpread({}, state.inputStyle), inputStyle);
var isValid = (0, _mapboxGlStyleEditor.isValidStyleUrl)(updated.url);
var icon = isValid ? (0, _mapboxGlStyleEditor.getStyleImageIcon)({
mapState: mapState,
styleUrl: updated.url,
mapboxApiAccessToken: updated.accessToken || state.mapboxApiAccessToken,
mapboxApiUrl: state.mapboxApiUrl || _defaultSettings.DEFAULT_MAPBOX_API_URL
}) : state.inputStyle.icon;
return _objectSpread(_objectSpread({}, state), {}, {
inputStyle: _objectSpread(_objectSpread({}, updated), {}, {
isValid: isValid,
icon: icon
})
});
};
/**
* Add map style from user input to reducer and set it to current style
* This action is called when user click confirm after putting in a valid style url in the custom map style dialog.
* It should not be called from outside kepler.gl without a valid `inputStyle` in the `mapStyle` reducer.
* @memberof mapStyleUpdaters
* @param {Object} state `mapStyle`
* @returns {Object} nextState
*/
var addCustomMapStyleUpdater = exports.addCustomMapStyleUpdater = function addCustomMapStyleUpdater(state) {
var styleId = state.inputStyle.id;
var newState = _objectSpread(_objectSpread({}, state), {}, {
mapStyles: _objectSpread(_objectSpread({}, state.mapStyles), {}, (0, _defineProperty2["default"])({}, styleId, state.inputStyle)),
// set to default
inputStyle: getInitialInputStyle()
}); // set new style
return mapStyleChangeUpdater(newState, {
payload: styleId
});
};
/**
* Updates 3d building color
* @memberof mapStyleUpdaters
* @param state
* @param color
* @return {Object} nextState
*/
var set3dBuildingColorUpdater = exports.set3dBuildingColorUpdater = function set3dBuildingColorUpdater(state, _ref11) {
var color = _ref11.payload;
return _objectSpread(_objectSpread({}, state), {}, {
threeDBuildingColor: color,
custom3DBuildingColor: true
});
};
/**
* Return the initial input style
* @return Object
*/
function getInitialInputStyle() {
return {
accessToken: null,
error: false,
isValid: false,
label: null,
style: null,
url: null,
icon: null,
custom: true
};
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9yZWR1Y2Vycy9tYXAtc3R5bGUtdXBkYXRlcnMuanMiXSwibmFtZXMiOlsiREVGQVVMVF9CTERHX0NPTE9SIiwiZ2V0RGVmYXVsdFN0YXRlIiwidmlzaWJsZUxheWVyR3JvdXBzIiwic3R5bGVUeXBlIiwidG9wTGF5ZXJHcm91cHMiLCJtYXBTdHlsZXMiLCJERUZBVUxUX01BUF9TVFlMRVMiLCJyZWR1Y2UiLCJhY2N1IiwiY3VyciIsImlkIiwibWFwYm94QXBpQWNjZXNzVG9rZW4iLCJtYXBib3hBcGlVcmwiLCJERUZBVUxUX01BUEJPWF9BUElfVVJMIiwibWFwU3R5bGVzUmVwbGFjZURlZmF1bHQiLCJpbnB1dFN0eWxlIiwiZ2V0SW5pdGlhbElucHV0U3R5bGUiLCJ0aHJlZURCdWlsZGluZ0NvbG9yIiwiY3VzdG9tM0RCdWlsZGluZ0NvbG9yIiwibWFwU3R5bGVVcGRhdGVycyIsIklOSVRJQUxfTUFQX1NUWUxFIiwiZ2V0TWFwU3R5bGVzIiwibWFwU3R5bGUiLCJzdHlsZSIsImVkaXRhYmxlIiwiT2JqZWN0Iiwia2V5cyIsImxlbmd0aCIsImJvdHRvbU1hcFN0eWxlIiwiaGFzVG9wTGF5ZXIiLCJ2YWx1ZXMiLCJzb21lIiwidiIsInRvcExheWVycyIsImtleSIsInRvcE1hcFN0eWxlIiwiZmluZExheWVyRmlsbENvbG9yIiwibGF5ZXIiLCJwYWludCIsImdldDNEQnVpbGRpbmdDb2xvciIsImJhY2tncm91bmRMYXllciIsImxheWVycyIsImZpbmQiLCJidWlsZGluZ0xheWVyIiwibWF0Y2giLCJidWlsZGluZ0NvbG9yIiwib3BlcmF0aW9uIiwiYWxwaGEiLCJyZ2JPYmoiLCJyIiwiZyIsImIiLCJnZXRMYXllckdyb3Vwc0Zyb21TdHlsZSIsIkFycmF5IiwiaXNBcnJheSIsIkRFRkFVTFRfTEFZRVJfR1JPVVBTIiwiZmlsdGVyIiwibGciLCJpbml0TWFwU3R5bGVVcGRhdGVyIiwic3RhdGUiLCJhY3Rpb24iLCJwYXlsb2FkIiwibWFwQ29uZmlnQ2hhbmdlVXBkYXRlciIsIm1hcFN0eWxlQ2hhbmdlVXBkYXRlciIsImRlZmF1bHRMR1Zpc2liaWxpdHkiLCJsb2FkTWFwU3R5bGVzVXBkYXRlciIsIm5ld1N0eWxlcyIsImFkZExheWVyR3JvdXBzIiwibGF5ZXJHcm91cHMiLCJuZXdTdGF0ZSIsImxvYWRNYXBTdHlsZUVyclVwZGF0ZXIiLCJyZXF1ZXN0TWFwU3R5bGVzVXBkYXRlciIsImxvYWRNYXBTdHlsZVRhc2tzIiwiZ2V0TG9hZE1hcFN0eWxlVGFza3MiLCJyZWNlaXZlTWFwQ29uZmlnVXBkYXRlciIsImNvbmZpZyIsIm1lcmdlZCIsIkJvb2xlYW4iLCJUYXNrIiwiYWxsIiwibWFwIiwidXJsIiwiYWNjZXNzVG9rZW4iLCJMT0FEX01BUF9TVFlMRV9UQVNLIiwiYmltYXAiLCJyZXN1bHRzIiwibG9hZE1hcFN0eWxlRXJyIiwicmVzZXRNYXBDb25maWdNYXBTdHlsZVVwZGF0ZXIiLCJlbXB0eUNvbmZpZyIsImluaXRpYWxTdGF0ZSIsImxvYWRDdXN0b21NYXBTdHlsZVVwZGF0ZXIiLCJpY29uIiwiZXJyb3IiLCJsYWJlbCIsIm5hbWUiLCJ1bmRlZmluZWQiLCJpbnB1dE1hcFN0eWxlVXBkYXRlciIsIm1hcFN0YXRlIiwidXBkYXRlZCIsImlzVmFsaWQiLCJzdHlsZVVybCIsImFkZEN1c3RvbU1hcFN0eWxlVXBkYXRlciIsInN0eWxlSWQiLCJzZXQzZEJ1aWxkaW5nQ29sb3JVcGRhdGVyIiwiY29sb3IiLCJjdXN0b20iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7QUFvQkE7O0FBQ0E7O0FBR0E7O0FBU0E7O0FBS0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7Ozs7Ozs7Ozs7QUFFQSxJQUFNQSxrQkFBa0IsR0FBRyxTQUEzQjs7QUFFQSxJQUFNQyxlQUFlLEdBQUcsU0FBbEJBLGVBQWtCLEdBQU07QUFDNUIsTUFBTUMsa0JBQWtCLEdBQUcsRUFBM0I7QUFDQSxNQUFNQyxTQUFTLEdBQUcsTUFBbEI7QUFDQSxNQUFNQyxjQUFjLEdB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Ozs7Ozs7OztBQU9PLElBQU1DLHlCQUF5Qix1Q0FBRyxTQUE1QkEseUJBQTRCLENBQUM1QyxLQUFEO0FBQUEsTUFBa0I2QyxLQUFsQixVQUFTM0MsT0FBVDtBQUFBLHlDQUNwQ0YsS0FEb0M7QUFFdkMxQyxJQUFBQSxtQkFBbUIsRUFBRXVGLEtBRmtCO0FBR3ZDdEYsSUFBQUEscUJBQXFCLEVBQUU7QUFIZ0I7QUFBQSxDQUFsQztBQU1QOzs7Ozs7QUFJTyxTQUFTRixvQkFBVCxHQUFnQztBQUNyQyxTQUFPO0FBQ0xrRSxJQUFBQSxXQUFXLEVBQUUsSUFEUjtBQUVMVSxJQUFBQSxLQUFLLEVBQUUsS0FGRjtBQUdMTyxJQUFBQSxPQUFPLEVBQUUsS0FISjtBQUlMTixJQUFBQSxLQUFLLEVBQUUsSUFKRjtBQUtMdEUsSUFBQUEsS0FBSyxFQUFFLElBTEY7QUFNTDBELElBQUFBLEdBQUcsRUFBRSxJQU5BO0FBT0xVLElBQUFBLElBQUksRUFBRSxJQVBEO0FBUUxjLElBQUFBLE1BQU0sRUFBRTtBQVJILEdBQVA7QUFVRCIsInNvdXJjZXNDb250ZW50IjpbIi8vIENvcHlyaWdodCAoYykgMjAyMyBVYmVyIFRlY2hub2xvZ2llcywgSW5jLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcbi8vIG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlIFwiU29mdHdhcmVcIiksIHRvIGRlYWxcbi8vIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmcgd2l0aG91dCBsaW1pdGF0aW9uIHRoZSByaWdodHNcbi8vIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcbi8vIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXQgcGVyc29ucyB0byB3aG9tIHRoZSBTb2Z0d2FyZSBpc1xuLy8gZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uczpcbi8vXG4vLyBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxuLy8gYWxsIGNvcGllcyBvciBzdWJzdGFudGlhbCBwb3J0aW9ucyBvZiB0aGUgU29mdHdhcmUuXG4vL1xuLy8gVEhFIFNPRlRXQVJFIElTIFBST1ZJREVEIFwiQVMgSVNcIiwgV0lUSE9VVCBXQVJSQU5UWSBPRiBBTlkgS0lORCwgRVhQUkVTUyBPUlxuLy8gSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXG4vLyBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVIgUFVSUE9TRSBBTkQgTk9OSU5GUklOR0VNRU5ULiBJTiBOTyBFVkVOVCBTSEFMTCBUSEVcbi8vIEFVVEhPUlMgT1IgQ09QWVJJR0hUIEhPTERFUlMgQkUgTElBQkxFIEZPUiBBTlkgQ0xBSU0sIERBTUFHRVMgT1IgT1RIRVJcbi8vIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXG4vLyBPVVQgT0YgT1IgSU4gQ09OTkVDVElPTiBXSVRIIFRIRSBTT0ZUV0FSRSBPUiBUSEUgVVNFIE9SIE9USEVSIERFQUxJTkdTIElOXG4vLyBUSEUgU09GVFdBUkUuXG5cbmltcG9ydCBUYXNrLCB7d2l0aFRhc2t9IGZyb20gJ3JlYWN0LXBhbG0vdGFza3MnO1xuaW1wb3J0IGNsb25lRGVlcCBmcm9tICdsb2Rhc2guY2xvbmVkZWVwJztcblxuLy8gVXRpbHNcbmltcG9ydCB7XG4gIGdldERlZmF1bHRMYXllckdyb3VwVmlzaWJpbGl0eSxcbiAgaXNWYWxpZFN0eWxlVXJsLFxuICBnZXRTdHlsZURvd25sb2FkVXJsLFxuICBtZXJnZUxheWVyR3JvdXBWaXNpYmlsaXR5LFxuICBlZGl0VG9wTWFwU3R5bGUsXG4gIGVkaXRCb3R0b21NYXBTdHlsZSxcbiAgZ2V0U3R5bGVJbWFnZUljb25cbn0gZnJvbSAndXRpbHMvbWFwLXN0eWxlLXV0aWxzL21hcGJveC1nbC1zdHlsZS1lZGl0b3InO1xuaW1wb3J0IHtcbiAgREVGQVVMVF9NQVBfU1RZTEVTLFxuICBERUZBVUxUX0xBWUVSX0dST1VQUyxcbiAgREVGQVVMVF9NQVBCT1hfQVBJX1VSTFxufSBmcm9tICdjb25zdGFudHMvZGVmYXVsdC1zZXR0aW5ncyc7XG5pbXBvcnQge2dlbmVyYXRlSGFzaElkfSBmcm9tICd1dGlscy91dGlscyc7XG5pbXBvcnQge0xPQURfTUFQX1NUWUxFX1RBU0t9IGZyb20gJ3Rhc2tzL3Rhc2tzJztcbmltcG9ydCB7bG9hZE1hcFN0eWxlcywgbG9hZE1hcFN0eWxlRXJyfSBmcm9tICdhY3Rpb25zL21hcC1zdHlsZS1hY3Rpb25zJztcbmltcG9ydCB7cmdifSBmcm9tICdkMy1jb2xvcic7XG5pbXBvcnQge2hleFRvUmdifSBmcm9tICd1dGlscy9jb2xvci11dGlscyc7XG5cbmNvbnN0IERFRkFVTFRfQkxER19DT0xPUiA9ICcjRDFDRUM3JztcblxuY29uc3QgZ2V0RGVmYXVsdFN0YXRlID0gKCkgPT4ge1xuICBjb25zdCB2aXNpYmxlTGF5ZXJHcm91cHMgPSB7fTtcbiAgY29uc3Qgc3R5bGVUeXBlID0gJ2F1dG8nO1xuICBjb25zdCB0b3BMYXllckdyb3VwcyA9IHt9O1xuXG4gIHJldHVybiB7XG4gICAgc3R5bGVUeXBlLFxuICAgIHZpc2libGVMYXllckdyb3VwcyxcbiAgICB0b3BMYXllckdyb3VwcyxcbiAgICBtYXBTdHlsZXM6IERFRkFVTFRfTUFQX1NUWUxFUy5yZWR1Y2UoXG4gICAgICAoYWNjdSwgY3VycikgPT4gKHtcbiAgICAgICAgLi4uYWNjdSxcbiAgICAgICAgW2N1cnIuaWRdOiBjdXJyXG4gICAgICB9KSxcbiAgICAgIHt9XG4gICAgKSxcbiAgICAvLyBzYXZlIG1hcGJveCBhY2Nlc3MgdG9rZW5cbiAgICBtYXBib3hBcGlBY2Nlc3NUb2tlbjogbnVsbCxcbiAgICBtYXBib3hBcGlVcmw6IERFRkFVTFRfTUFQQk9YX0FQSV9VUkwsXG4gICAgbWFwU3R5bGVzUmVwbGFjZURlZmF1bHQ6IGZhbHNlLFxuICAgIGlucHV0U3R5bGU6IGdldEluaXRpYWxJbnB1dFN0eWxlKCksXG4gICAgdGhyZWVEQnVpbGRpbmdDb2xvcjogaGV4VG9SZ2IoREVGQVVMVF9CTERHX0NPTE9SKSxcbiAgICBjdXN0b20zREJ1aWxkaW5nQ29sb3I6IGZhbHNlXG4gIH07XG59O1xuXG4vKipcbiAqIFVwZGF0ZXJzIGZvciBgbWFwU3R5bGVgLiBDYW4gYmUgdXNlZCBpbiB5b3VyIHJvb3QgcmVkdWNlciB0byBkaXJlY3RseSBtb2RpZnkga2VwbGVyLmdsJ3Mgc3RhdGUuXG4gKiBSZWFkIG1vcmUgYWJvdXQgW1VzaW5nIHVwZGF0ZXJzXSguLi9hZHZhbmNlZC11c2FnZS91c2luZy11cGRhdGVycy5tZClcbiAqIEBwdWJsaWNcbiAqIEBleGFtcGxlXG4gKlxuICogaW1wb3J0IGtlcGxlckdsUmVkdWNlciwge21hcFN0eWxlVXBkYXRlcnN9IGZyb20gJ2tlcGxlci5nbC9yZWR1Y2Vycyc7XG4gKiAvLyBSb290IFJlZHVjZXJcbiAqIGNvbnN0IHJlZHVjZXJzID0gY29tYmluZVJlZHVjZXJzKHtcbiAqICBrZXBsZXJHbDoga2VwbGVyR2xSZWR1Y2VyLFxuICogIGFwcDogYXBwUmVkdWNlclxuICogfSk7XG4gKlxuICogY29uc3QgY29tcG9zZWRSZWR1Y2VyID0gKHN0YXRlLCBhY3Rpb24pID0+IHtcbiAqICBzd2l0Y2ggKGFjdGlvbi50eXBlKSB7XG4gKiAgICAvLyBjbGljayBidXR0b24gdG8gaGlkZSBsYWJlbCBmcm9tIGJhY2tncm91bmQgbWFwXG4gKiAgICBjYXNlICdDTElDS19CVVRUT04nOlxuICogICAgICByZXR1cm4ge1xuICogICAgICAgIC4uLnN0YXRlLFxuICogICAgICAgIGtlcGxlckdsOiB7XG4gKiAgICAgICAgICAuLi5zdGF0ZS5rZXBsZXJHbCxcbiAqICAgICAgICAgIGZvbzoge1xuICogICAgICAgICAgICAgLi4uc3RhdGUua2VwbGVyR2wuZm9vLFxuICogICAgICAgICAgICAgbWFwU3R5bGU6IG1hcFN0eWxlVXBkYXRlcnMubWFwQ29uZmlnQ2hhbmdlVXBkYXRlcihcbiAqICAgICAgICAgICAgICAgbWFwU3R5bGUsXG4gKiAgICAgICAgICAgICAgIHtwYXlsb2FkOiB7dmlzaWJsZUxheWVyR3JvdXBzOiB7bGFiZWw6IGZhbHNlLCByb2FkOiB0cnVlLCBiYWNrZ3JvdW5kOiB0cnVlfX19XG4gKiAgICAgICAgICAgICApXG4gKiAgICAgICAgICB9XG4gKiAgICAgICAgfVxuICogICAgICB9O1xuICogIH1cbiAqICByZXR1cm4gcmVkdWNlcnMoc3RhdGUsIGFjdGlvbik7XG4gKiB9O1xuICpcbiAqIGV4cG9ydCBkZWZhdWx0IGNvbXBvc2VkUmVkdWNlcjtcbiAqL1xuLyogZXNsaW50LWRpc2FibGUgbm8tdW51c2VkLXZhcnMgKi9cbmNvbnN0IG1hcFN0eWxlVXBkYXRlcnMgPSBudWxsO1xuLyogZXNsaW50LWVuYWJsZSBuby11bnVzZWQtdmFycyAqL1xuLyoqXG4gKiBEZWZhdWx0IGluaXRpYWwgYG1hcFN0eWxlYFxuICogQG1lbWJlcm9mIG1hcFN0eWxlVXBkYXRlcnNcbiAqIEBjb25zdGFudFxuICogQHByb3BlcnR5IHtzdHJpbmd9IHN0eWxlVHlwZSAtIERlZmF1bHQ6IGAnZGFyaydgXG4gKiBAcHJvcGVydHkge09iamVjdH0gdmlzaWJsZUxheWVyR3JvdXBzIC0gRGVmYXVsdDogYHt9YFxuICogQHByb3BlcnR5IHtPYmplY3R9IHRvcExheWVyR3JvdXBzIC0gRGVmYXVsdDogYHt9YFxuICogQHByb3BlcnR5IHtPYmplY3R9IG1hcFN0eWxlcyAtIG1hcHBpbmcgZnJvbSBzdHlsZSBrZXkgdG8gc3R5bGUgb2JqZWN0XG4gKiBAcHJvcGVydHkge3N0cmluZ30gbWFwYm94QXBpQWNjZXNzVG9rZW4gLSBEZWZhdWx0OiBgbnVsbGBcbiAqIEBQcm9wZXJ0eSB7c3RyaW5nfSBtYXBib3hBcGlVcmwgLSBEZWZhdWx0IG51bGxcbiAqIEBQcm9wZXJ0eSB7Qm9vbGVhbn0gbWFwU3R5bGVzUmVwbGFjZURlZmF1bHQgLSBEZWZhdWx0OiBgZmFsc2VgXG4gKiBAcHJvcGVydHkge09iamVjdH0gaW5wdXRTdHlsZSAtIERlZmF1bHQ6IGB7fWBcbiAqIEBwcm9wZXJ0eSB7QXJyYXl9IHRocmVlREJ1aWxkaW5nQ29sb3IgLSBEZWZhdWx0OiBgW3IsIGcsIGJdYFxuICogQHB1YmxpY1xuICovXG5leHBvcnQgY29uc3QgSU5JVElBTF9NQVBfU1RZTEUgPSBnZXREZWZhdWx0U3RhdGUoKTtcblxuLyoqXG4gKiBDcmVhdGUgdHdvIG1hcCBzdHlsZXMgZnJvbSBwcmVzZXQgbWFwIHN0eWxlLCBvbmUgZm9yIHRvcCBtYXAgb25lIGZvciBib3R0b21cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3R5bGVUeXBlIC0gY3VycmVudCBtYXAgc3R5bGVcbiAqIEBwYXJhbSB7T2JqZWN0fSB2aXNpYmxlTGF5ZXJHcm91cHMgLSB2aXNpYmxlIGxheWVycyBvZiBib3R0b20gbWFwXG4gKiBAcGFyYW0ge09iamVjdH0gdG9wTGF5ZXJHcm91cHMgLSB2aXNpYmxlIGxheWVycyBvZiB0b3AgbWFwXG4gKiBAcGFyYW0ge09iamVjdH0gbWFwU3R5bGVzIC0gYSBkaWN0aW9uYXJ5IG9mIGFsbCBtYXAgc3R5bGVzXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBib3R0b21NYXBTdHlsZSB8IHRvcE1hcFN0eWxlIHwgaXNSYXN0ZXJcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE1hcFN0eWxlcyh7XG4gIHN0eWxlVHlwZSxcbiAgdmlzaWJsZUxheWVyR3JvdXBzLFxuICB0b3BMYXllckdyb3VwcyxcbiAgbWFwU3R5bGVzXG59KSB7XG4gIGNvbnN0IG1hcFN0eWxlID0gbWFwU3R5bGVzW3N0eWxlVHlwZV07XG5cbiAgLy8gc3R5bGUgbWlnaHQgbm90IGJlIGxvYWRlZCB5ZXRcbiAgaWYgKCFtYXBTdHlsZSB8fCAhbWFwU3R5bGUuc3R5bGUpIHtcbiAgICByZXR1cm4ge307XG4gIH1cblxuICBjb25zdCBlZGl0YWJsZSA9IE9iamVjdC5rZXlzKHZpc2libGVMYXllckdyb3VwcykubGVuZ3RoO1xuXG4gIGNvbnN0IGJvdHRvbU1hcFN0eWxlID0gIWVkaXRhYmxlXG4gICAgPyBtYXBTdHlsZS5zdHlsZVxuICAgIDogZWRpdEJvdHRvbU1hcFN0eWxlKHtcbiAgICAgICAgaWQ6IHN0eWxlVHlwZSxcbiAgICAgICAgbWFwU3R5bGUsXG4gICAgICAgIHZpc2libGVMYXllckdyb3Vwc1xuICAgICAgfSk7XG5cbiAgY29uc3QgaGFzVG9wTGF5ZXIgPSBlZGl0YWJsZSAmJiBPYmplY3QudmFsdWVzKHRvcExheWVyR3JvdXBzKS5zb21lKHYgPT4gdik7XG5cbiAgLy8gbXV0ZSB0b3AgbGF5ZXIgaWYgbm90IHZpc2libGUgaW4gYm90dG9tIGxheWVyXG4gIGNvbnN0IHRvcExheWVycyA9XG4gICAgaGFzVG9wTGF5ZXIgJiZcbiAgICBPYmplY3Qua2V5cyh0b3BMYXllckdyb3VwcykucmVkdWNlKFxuICAgICAgKGFjY3UsIGtleSkgPT4gKHtcbiAgICAgICAgLi4uYWNjdSxcbiAgICAgICAgW2tleV06IHRvcExheWVyR3JvdXBzW2tleV0gJiYgdmlzaWJsZUxheWVyR3JvdXBzW2tleV1cbiAgICAgIH0pLFxuICAgICAge31cbiAgICApO1xuXG4gIGNvbnN0IHRvcE1hcFN0eWxlID0gaGFzVG9wTGF5ZXJcbiAgICA/IGVkaXRUb3BNYXBTdHlsZSh7XG4gICAgICAgIGlkOiBzdHlsZVR5cGUsXG4gICAgICAgIG1hcFN0eWxlLFxuICAgICAgICB2aXNpYmxlTGF5ZXJHcm91cHM6IHRvcExheWVyc1xuICAgICAgfSlcbiAgICA6IG51bGw7XG5cbiAgcmV0dXJuIHtib3R0b21NYXBTdHlsZSwgdG9wTWFwU3R5bGUsIGVkaXRhYmxlfTtcbn1cblxuZnVuY3Rpb24gZmluZExheWVyRmlsbENvbG9yKGxheWVyKSB7XG4gIHJldHVybiBsYXllciAmJiBsYXllci5wYWludCAmJiBsYXllci5wYWludFsnYmFja2dyb3VuZC1jb2xvciddO1xufVxuXG5mdW5jdGlvbiBnZXQzREJ1aWxkaW5nQ29sb3Ioc3R5bGUpIHtcbiAgLy8gc2V0IGJ1aWxkaW5nIGNvbG9yIHRvIGJlIHRoZSBzYW1lIGFzIHRoZSBiYWNrZ3JvdW5kIGNvbG9yLlxuICBpZiAoIXN0eWxlLnN0eWxlKSB7XG4gICAgcmV0dXJuIERFRkFVTFRfQkxER19DT0xPUjtcbiAgfVxuXG4gIGNvbnN0IGJhY2tncm91bmRMYXllciA9IChzdHlsZS5zdHlsZS5sYXllcnMgfHwgW10pLmZpbmQoXG4gICAgKHtpZH0pID0+IGlkID09PSAnYmFja2dyb3VuZCdcbiAgKTtcblxuICBjb25zdCBidWlsZGluZ0xheWVyID0gKHN0eWxlLnN0eWxlLmxheWVycyB8fCBbXSkuZmluZCgoe2lkfSkgPT5cbiAgICBpZC5tYXRjaCgvYnVpbGRpbmcvKVxuICApO1xuXG4gIGNvbnN0IGJ1aWxkaW5nQ29sb3IgPVxuICAgIGZpbmRMYXllckZpbGxDb2xvcihidWlsZGluZ0xheWVyKSB8fFxuICAgIGZpbmRMYXllckZpbGxDb2xvcihiYWNrZ3JvdW5kTGF5ZXIpIHx8XG4gICAgREVGQVVMVF9CTERHX0NPTE9SO1xuXG4gIC8vIGJyaWdodGVuIG9yIGRhcmtlbiBidWlsZGluZyBiYXNlZCBvbiBzdHlsZVxuICBjb25zdCBvcGVyYXRpb24gPSBzdHlsZS5pZC5tYXRjaCgvKD89KGRhcmt8bmlnaHQpKS8pID8gJ2JyaWdodGVyJyA6ICdkYXJrZXInO1xuXG4gIGNvbnN0IGFscGhhID0gMC4yO1xuICBjb25zdCByZ2JPYmogPSByZ2IoYnVpbGRpbmdDb2xvcilbb3BlcmF0aW9uXShbYWxwaGFdKTtcbiAgcmV0dXJuIFtyZ2JPYmouciwgcmdiT2JqLmcsIHJnYk9iai5iXTtcbn1cblxuZnVuY3Rpb24gZ2V0TGF5ZXJHcm91cHNGcm9tU3R5bGUoc3R5bGUpIHtcbiAgcmV0dXJuIEFycmF5LmlzQXJyYXkoc3R5bGUubGF5ZXJzKVxuICAgID8gREVGQVVMVF9MQVlFUl9HUk9VUFMuZmlsdGVyKGxnID0+IHN0eWxlLmxheWVycy5maWx0ZXIobGcuZmlsdGVyKS5sZW5ndGgpXG4gICAgOiBbXTtcbn1cblxuLy8gVXBkYXRlcnNcbi8qKlxuICogUHJvcGFnYXRlIGBtYXBTdHlsZWAgcmVkdWNlciB3aXRoIGBtYXBib3hBcGlBY2Nlc3NUb2tlbmAgYW5kIGBtYXBTdHlsZXNSZXBsYWNlRGVmYXVsdGAuXG4gKiBpZiBtYXBTdHlsZXNSZXBsYWNlRGVmYXVsdCBpcyB0cnVlIG1hcFN0eWxlcyBpcyBlbXB0aWVkOyBsb2FkTWFwU3R5bGVzVXBkYXRlcigpIHdpbGxcbiAqIHBvcHVsYXRlIG1hcFN0eWxlcy5cbiAqXG4gKiBAbWVtYmVyb2YgbWFwU3R5bGVVcGRhdGVyc1xuICogQHBhcmFtIHtPYmplY3R9IHN0YXRlXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uLnBheWxvYWRcbiAqIEBwYXJhbSB7c3RyaW5nfSBhY3Rpb24ucGF5bG9hZC5tYXBib3hBcGlBY2Nlc3NUb2tlblxuICogQHJldHVybnMge09iamVjdH0gbmV4dFN0YXRlXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBjb25zdCBpbml0TWFwU3R5bGVVcGRhdGVyID0gKHN0YXRlLCBhY3Rpb24pID0+ICh7XG4gIC4uLnN0YXRlLFxuICAvLyBzYXZlIG1hcGJveCBhY2Nlc3MgdG9rZW4gdG8gbWFwIHN0eWxlIHN0YXRlXG4gIG1hcGJveEFwaUFjY2Vzc1Rva2VuOiAoYWN0aW9uLnBheWxvYWQgfHwge30pLm1hcGJveEFwaUFjY2Vzc1Rva2VuLFxuICBtYXBib3hBcGlVcmw6IChhY3Rpb24ucGF5bG9hZCB8fCB7fSkubWFwYm94QXBpVXJsIHx8IHN0YXRlLm1hcGJveEFwaVVybCxcbiAgbWFwU3R5bGVzOlxuICAgIGFjdGlvbi5wYXlsb2FkICYmICFhY3Rpb24ucGF5bG9hZC5tYXBTdHlsZXNSZXBsYWNlRGVmYXVsdFxuICAgICAgPyBzdGF0ZS5tYXBTdHlsZXNcbiAgICAgIDoge30sXG4gIG1hcFN0eWxlc1JlcGxhY2VEZWZhdWx0OiBhY3Rpb24ucGF5bG9hZC5tYXBTdHlsZXNSZXBsYWNlRGVmYXVsdCB8fCBmYWxzZVxufSk7XG4vLyB9KTtcblxuLyoqXG4gKiBVcGRhdGUgYHZpc2libGVMYXllckdyb3Vwc2B0byBjaGFuZ2UgbGF5ZXIgZ3JvdXAgdmlzaWJpbGl0eVxuICogQG1lbWJlcm9mIG1hcFN0eWxlVXBkYXRlcnNcbiAqIEBwYXJhbSB7T2JqZWN0fSBzdGF0ZSBgbWFwU3R5bGVgXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uLnBheWxvYWQgbmV3IGNvbmZpZyBge3Zpc2libGVMYXllckdyb3Vwczoge2xhYmVsOiBmYWxzZSwgcm9hZDogdHJ1ZSwgYmFja2dyb3VuZDogdHJ1ZX19YFxuICogQHJldHVybnMge09iamVjdH0gbmV4dFN0YXRlXG4gKiBAcHVibGljXG4gKi9cbmV4cG9ydCBjb25zdCBtYXBDb25maWdDaGFuZ2VVcGRhdGVyID0gKHN0YXRlLCBhY3Rpb24pID0+ICh7XG4gIC4uLnN0YXRlLFxuICAuLi5hY3Rpb24ucGF5bG9hZCxcbiAgLi4uZ2V0TWFwU3R5bGVzKHtcbiAgICAuLi5zdGF0ZSxcbiAgICAuLi5hY3Rpb24ucGF5bG9hZFxuICB9KVxufSk7XG5cbi8qKlxuICogQ2hhbmdlIHRvIGFub3RoZXIgbWFwIHN0eWxlLiBUaGUgc2VsZWN0ZWQgc3R5bGUgc2hvdWxkIGFscmVhZHkgYmVlbiBsb2FkZWQgaW50byBgbWFwU3R5bGUubWFwU3R5bGVzYFxuICogQG1lbWJlcm9mIG1hcFN0eWxlVXBkYXRlcnNcbiAqIEBwYXJhbSB7T2JqZWN0fSBzdGF0ZSBgbWFwU3R5bGVgXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uXG4gKiBAcGFyYW0ge3N0cmluZ30gYWN0aW9uLnBheWxvYWRcbiAqIEByZXR1cm5zIHtPYmplY3R9IG5leHRTdGF0ZVxuICogQHB1YmxpY1xuICovXG5leHBvcnQgY29uc3QgbWFwU3R5bGVDaGFuZ2VVcGRhdGVyID0gKHN0YXRlLCB7cGF5bG9hZDogc3R5bGVUeXBlfSkgPT4ge1xuICBpZiAoIXN0YXRlLm1hcFN0eWxlc1tzdHlsZVR5cGVdKSB7XG4gICAgLy8gd2UgbWlnaHQgbm90IGhhdmUgcmVjZWl2ZWQgdGhlIHN0eWxlIHlldFxuICAgIHJldHVybiBzdGF0ZTtcbiAgfVxuICBjb25zdCBkZWZhdWx0TEdWaXNpYmlsaXR5ID0gZ2V0RGVmYXVsdExheWVyR3JvdXBWaXNpYmlsaXR5KFxuICAgIHN0YXRlLm1hcFN0eWxlc1tzdHlsZVR5cGVdXG4gICk7XG5cbiAgY29uc3QgdmlzaWJsZUxheWVyR3JvdXBzID0gbWVyZ2VMYXllckdyb3VwVmlzaWJpbGl0eShcbiAgICBkZWZhdWx0TEdWaXNpYmlsaXR5LFxuICAgIHN0YXRlLnZpc2libGVMYXllckdyb3Vwc1xuICApO1xuXG4gIGNvbnN0IHRocmVlREJ1aWxkaW5nQ29sb3IgPSBzdGF0ZS5jdXN0b20zREJ1aWxkaW5nQ29sb3JcbiAgICA/IHN0YXRlLnRocmVlREJ1aWxkaW5nQ29sb3JcbiAgICA6IGdldDNEQnVpbGRpbmdDb2xvcihzdGF0ZS5tYXBTdHlsZXNbc3R5bGVUeXBlXSk7XG4gIHJldHVybiB7XG4gICAgLi4uc3RhdGUsXG4gICAgc3R5bGVUeXBlLFxuICAgIHZpc2libGVMYXllckdyb3VwcyxcbiAgICB0aHJlZURCdWlsZGluZ0NvbG9yLFxuICAgIC4uLmdldE1hcFN0eWxlcyh7XG4gICAgICAuLi5zdGF0ZSxcbiAgICAgIHZpc2libGVMYXllckdyb3VwcyxcbiAgICAgIHN0eWxlVHlwZVxuICAgIH0pXG4gIH07XG59O1xuXG4vKipcbiAqIENhbGxiYWNrIHdoZW4gbG9hZCBtYXAgc3R5bGUgc3VjY2Vzc1xuICogQG1lbWJlcm9mIG1hcFN0eWxlVXBkYXRlcnNcbiAqIEBwYXJhbSB7T2JqZWN0fSBzdGF0ZSBgbWFwU3R5bGVgXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uXG4gKiBAcGFyYW0ge09iamVjdH0gYWN0aW9uLnBheWxvYWQgYSBge1tpZF06IHN0eWxlfWAgbWFwcGluZ1xuICogQHJldHVybiB7T2JqZWN0fSBuZXh0U3RhdGVcbiAqIEBwdWJsaWNcbiAqL1xuZXhwb3J0IGNvbnN0IGxvYWRNYXBTdHlsZXNVcGRhdGVyID0gKHN0YXRlLCBhY3Rpb24pID0+IHtcbiAgY29uc3QgbmV3U3R5bGVzID0gYWN0aW9uLnBheWxvYWQgfHwge307XG4gIGNvbnN0IGFkZExheWVyR3JvdXBzID0gT2JqZWN0LmtleXMobmV3U3R5bGVzKS5yZWR1Y2UoXG4gICAgKGFjY3UsIGlkKSA9PiAoe1xuICAgICAgLi4uYWNjdSxcbiAgICAgIFtpZF06IHtcbiAgICAgICAgLi4ubmV3U3R5bGVzW2lkXSxcbiAgICAgICAgbGF5ZXJHcm91cHM6XG4gICAgICAgICAgbmV3U3R5bGVzW2lkXS5sYXllckdyb3VwcyB8fFxuICAgICAgICAgIGdldExheWVyR3JvdXBzRnJvbVN0eWxlKG5ld1N0eWxlc1tpZF0uc3R5bGUpXG4gICAgICB9XG4gICAgfSksXG4gICAge31cbiAgKTtcblxuICAvLyBhZGQgbmV3IHN0eWxlcyB0byBzdGF0ZVxuICBjb25zdCBuZXdTdGF0ZSA9IHtcbiAgICAuLi5zdGF0ZSxcbiAgICBtYXBTdHlsZXM6IHtcbiAgICAgIC4uLnN0YXRlLm1hcFN0eWxlcyxcbiAgICAgIC4uLmFkZExheWVyR3JvdXBzXG4gICAgfVxuICB9O1xuXG4gIHJldHVybiBuZXdTdHlsZXNbc3RhdGUuc3R5bGVUeXBlXVxuICAgID8gbWFwU3R5bGVDaGFuZ2VVcGRhdGVyKG5ld1N0YXRlLCB7cGF5bG9hZDogc3RhdGUuc3R5bGVUeXBlfSlcbiAgICA6IG5ld1N0YXRlO1xufTtcblxuLyoqXG4gKiBDYWxsYmFjayB3aGVuIGxvYWQgbWFwIHN0eWxlIGVycm9yXG4gKiBAbWVtYmVyb2YgbWFwU3R5bGVVcGRhdGVyc1xuICogQHBhcmFtIHtPYmplY3R9IHN0YXRlIGBtYXBTdHlsZWBcbiAqIEBwYXJhbSB7T2JqZWN0fSBhY3Rpb25cbiAqIEBwYXJhbSB7Kn0gYWN0aW9uLnBheWxvYWQgZXJyb3JcbiAqIEByZXR1cm5zIHtPYmplY3R9IG5leHRTdGF0ZVxuICogQHB1YmxpY1xuICovXG4vLyBkbyBub3RoaW5nIGZvciBub3csIGlmIGRpZG4ndCBsb2FkLCBza2lwIGl0XG5leHBvcnQgY29uc3QgbG9hZE1hcFN0eWxlRXJyVXBkYXRlciA9IHN0YXRlID0+IHN0YXRlO1xuXG5leHBvcnQgY29uc3QgcmVxdWVzdE1hcFN0eWxlc1VwZGF0ZXIgPSAoc3RhdGUsIHtwYXlsb2FkOiBtYXBTdHlsZXN9KSA9PiB7XG4gIGNvbnN0IGxvYWRNYXBTdHlsZVRhc2tzID0gZ2V0TG9hZE1hcFN0eWxlVGFza3MoXG4gICAgbWFwU3R5bGVzLFxuICAgIHN0YXRlLm1hcGJveEFwaUFjY2Vzc1Rva2VuLFxuICAgIHN0YXRlLm1hcGJveEFwaVVybFxuICApO1xuICB