kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
532 lines (419 loc) • 51.4 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _defineProperty2 = require('babel-runtime/helpers/defineProperty');
var _defineProperty3 = _interopRequireDefault(_defineProperty2);
var _extends4 = require('babel-runtime/helpers/extends');
var _extends5 = _interopRequireDefault(_extends4);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
exports.default = MapContainerFactory;
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _reactMapGl = require('react-map-gl');
var _reactMapGl2 = _interopRequireDefault(_reactMapGl);
var _deck = require('deck.gl');
var _deck2 = _interopRequireDefault(_deck);
var _luma = require('luma.gl');
var _pickingModule = require('../shaderlib/picking-module');
var _pickingModule2 = _interopRequireDefault(_pickingModule);
var _brushingModule = require('../shaderlib/brushing-module');
var _brushingModule2 = _interopRequireDefault(_brushingModule);
var _mapPopover = require('./map/map-popover');
var _mapPopover2 = _interopRequireDefault(_mapPopover);
var _mapControl = require('./map/map-control');
var _mapControl2 = _interopRequireDefault(_mapControl);
var _styledComponents = require('./common/styled-components');
var _mapboxUtils = require('../layers/mapbox-utils');
var _mapboxUtils2 = require('../utils/map-style-utils/mapbox-utils');
var _defaultSettings = require('../constants/default-settings');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// components
// 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.
// libraries
var MAP_STYLE = {
container: {
display: 'inline-block',
position: 'relative'
},
top: {
position: 'absolute', top: '0px', pointerEvents: 'none'
}
};
// default-settings
// Overlay type
var getGlConst = function getGlConst(d) {
return _luma.GL[d];
};
var MAPBOXGL_STYLE_UPDATE = 'style.load';
MapContainerFactory.deps = [_mapPopover2.default, _mapControl2.default];
function MapContainerFactory(MapPopover, MapControl) {
var _class, _temp;
var MapContainer = (_temp = _class = function (_Component) {
(0, _inherits3.default)(MapContainer, _Component);
function MapContainer(props) {
(0, _classCallCheck3.default)(this, MapContainer);
var _this = (0, _possibleConstructorReturn3.default)(this, (MapContainer.__proto__ || Object.getPrototypeOf(MapContainer)).call(this, props));
_this._onCloseMapPopover = function () {
_this.props.visStateActions.onLayerClick(null);
};
_this._onLayerSetDomain = function (idx, colorDomain) {
_this.props.visStateActions.layerConfigChange(_this.props.layers[idx], {
colorDomain: colorDomain
});
};
_this._onWebGLInitialized = function (gl) {
(0, _luma.registerShaderModules)([_pickingModule2.default, _brushingModule2.default], {
ignoreMultipleRegistrations: true
});
// allow Uint32 indices in building layer
// gl.getExtension('OES_element_index_uint');
};
_this._onMouseMove = function (evt) {
var brush = _this.props.interactionConfig.brush;
if (evt.nativeEvent && brush.enabled) {
_this.setState({
mousePosition: [evt.nativeEvent.offsetX, evt.nativeEvent.offsetY]
});
}
};
_this._handleMapToggleLayer = function (layerId) {
var _this$props = _this.props,
_this$props$index = _this$props.index,
mapIndex = _this$props$index === undefined ? 0 : _this$props$index,
visStateActions = _this$props.visStateActions;
visStateActions.toggleLayerForMap(mapIndex, layerId);
};
_this._setMapboxMap = function (mapbox) {
if (!_this._map && mapbox) {
_this._map = mapbox.getMap();
// bind mapboxgl event listener
_this._map.on(MAPBOXGL_STYLE_UPDATE, function () {
// force refresh mapboxgl layers
(0, _mapboxUtils.updateMapboxLayers)(_this._map, _this._renderMapboxLayers(), _this.previousLayers, _this.props.mapLayers, { force: true });
if (typeof _this.props.onMapStyleLoaded === 'function') {
_this.props.onMapStyleLoaded(_this._map);
}
});
_this._map.on('render', function () {
if (typeof _this.props.onMapRender === 'function') {
_this.props.onMapRender(_this._map);
}
});
}
};
_this._onBeforeRender = function (_ref) {
var gl = _ref.gl;
_this._setlayerBlending(gl);
};
_this._setlayerBlending = function (gl) {
var blending = _defaultSettings.LAYER_BLENDINGS[_this.props.layerBlending];
var blendFunc = blending.blendFunc,
blendEquation = blending.blendEquation;
(0, _luma.setParameters)(gl, (0, _extends5.default)((0, _defineProperty3.default)({}, _luma.GL.BLEND, true), blendFunc ? {
blendFunc: blendFunc.map(getGlConst),
blendEquation: Array.isArray(blendEquation) ? blendEquation.map(getGlConst) : getGlConst(blendEquation)
} : {}));
};
_this._renderLayer = function (overlays, idx) {
var _this$props2 = _this.props,
layers = _this$props2.layers,
layerData = _this$props2.layerData,
hoverInfo = _this$props2.hoverInfo,
clicked = _this$props2.clicked,
mapLayers = _this$props2.mapLayers,
mapState = _this$props2.mapState,
interactionConfig = _this$props2.interactionConfig;
var mousePosition = _this.state.mousePosition;
var layer = layers[idx];
var data = layerData[idx];
var layerInteraction = {
mousePosition: mousePosition
};
var objectHovered = clicked || hoverInfo;
var layerCallbacks = {
onSetLayerDomain: function onSetLayerDomain(val) {
return _this._onLayerSetDomain(idx, val);
}
};
if (!_this._shouldRenderLayer(layer, data, mapLayers)) {
return overlays;
}
var layerOverlay = [];
// Layer is Layer class
if (typeof layer.renderLayer === 'function') {
layerOverlay = layer.renderLayer({
data: data,
idx: idx,
layerInteraction: layerInteraction,
objectHovered: objectHovered,
mapState: mapState,
interactionConfig: interactionConfig,
layerCallbacks: layerCallbacks
});
}
if (layerOverlay.length) {
overlays = overlays.concat(layerOverlay);
}
return overlays;
};
_this.state = {
mousePosition: [0, 0]
};
_this.previousLayers = {
// [layers.id]: mapboxLayerConfig
};
return _this;
}
(0, _createClass3.default)(MapContainer, [{
key: 'componentWillUnmount',
value: function componentWillUnmount() {
// unbind mapboxgl event listener
if (this._map) {
this._map.off(MAPBOXGL_STYLE_UPDATE);
}
}
/* component private functions */
}, {
key: '_renderObjectLayerPopover',
/* component render functions */
/* eslint-disable complexity */
value: function _renderObjectLayerPopover() {
// TODO: move this into reducer so it can be tested
var _props = this.props,
mapState = _props.mapState,
hoverInfo = _props.hoverInfo,
clicked = _props.clicked,
datasets = _props.datasets,
interactionConfig = _props.interactionConfig,
layers = _props.layers,
mapLayers = _props.mapLayers;
// if clicked something, ignore hover behavior
var objectInfo = clicked || hoverInfo;
if (!interactionConfig.tooltip.enabled || !objectInfo || !objectInfo.picked) {
// nothing hovered
return null;
}
var lngLat = objectInfo.lngLat,
object = objectInfo.object,
overlay = objectInfo.layer;
// deckgl layer to kepler-gl layer
var layer = layers[overlay.props.idx];
if (!layer || !layer.config.isVisible || !object || !layer.getHoverData || mapLayers && !mapLayers[layer.id].isVisible) {
// layer is not visible
return null;
}
var dataId = layer.config.dataId;
var _datasets$dataId = datasets[dataId],
allData = _datasets$dataId.allData,
fields = _datasets$dataId.fields;
var data = layer.getHoverData(object, allData);
// project lnglat to screen so that tooltip follows the object on zoom
var viewport = overlay.context.viewport;
var _ref2 = this._getHoverXY(viewport, lngLat) || objectInfo,
x = _ref2.x,
y = _ref2.y;
var popoverProps = {
data: data,
fields: fields,
fieldsToShow: interactionConfig.tooltip.config.fieldsToShow[dataId],
layer: layer,
isVisible: true,
x: x,
y: y,
freezed: Boolean(clicked),
onClose: this._onCloseMapPopover,
mapState: mapState
};
return _react2.default.createElement(
'div',
null,
_react2.default.createElement(MapPopover, popoverProps)
);
}
/* eslint-enable complexity */
}, {
key: '_getHoverXY',
value: function _getHoverXY(viewport, lngLat) {
var screenCoord = !viewport || !lngLat ? null : viewport.project(lngLat);
return screenCoord && { x: screenCoord[0], y: screenCoord[1] };
}
}, {
key: '_shouldRenderLayer',
value: function _shouldRenderLayer(layer, data, mapLayers) {
var isAvailableAndVisible = !(mapLayers && mapLayers[layer.id]) || mapLayers[layer.id].isVisible;
return layer.shouldRenderLayer(data) && isAvailableAndVisible;
}
}, {
key: '_renderOverlay',
value: function _renderOverlay() {
var _props2 = this.props,
mapState = _props2.mapState,
layerData = _props2.layerData,
layerOrder = _props2.layerOrder,
visStateActions = _props2.visStateActions;
var deckGlLayers = [];
// wait until data is ready before render data layers
if (layerData && layerData.length) {
// last layer render first
deckGlLayers = layerOrder.slice().reverse().reduce(this._renderLayer, []);
}
return _react2.default.createElement(_deck2.default, {
viewState: mapState,
id: 'default-deckgl-overlay',
layers: deckGlLayers,
onWebGLInitialized: this._onWebGLInitialized,
onBeforeRender: this._onBeforeRender,
onLayerHover: visStateActions.onLayerHover,
onLayerClick: visStateActions.onLayerClick
});
}
}, {
key: '_renderMapboxLayers',
value: function _renderMapboxLayers() {
var _props3 = this.props,
layers = _props3.layers,
layerData = _props3.layerData,
layerOrder = _props3.layerOrder;
return (0, _mapboxUtils.generateMapboxLayers)(layers, layerData, layerOrder);
}
}, {
key: '_renderMapboxOverlays',
value: function _renderMapboxOverlays() {
if (this._map && this._map.isStyleLoaded()) {
var mapboxLayers = this._renderMapboxLayers();
(0, _mapboxUtils.updateMapboxLayers)(this._map, mapboxLayers, this.previousLayers, this.props.mapLayers);
this.previousLayers = mapboxLayers.reduce(function (final, layer) {
return (0, _extends5.default)({}, final, (0, _defineProperty3.default)({}, layer.id, layer.config));
}, {});
}
}
}, {
key: 'render',
value: function render() {
var _props4 = this.props,
mapState = _props4.mapState,
mapStyle = _props4.mapStyle,
mapStateActions = _props4.mapStateActions;
var updateMap = mapStateActions.updateMap,
onMapClick = mapStateActions.onMapClick;
if (!mapStyle.bottomMapStyle) {
// style not yet loaded
return _react2.default.createElement('div', null);
}
var _props5 = this.props,
mapLayers = _props5.mapLayers,
layers = _props5.layers,
datasets = _props5.datasets,
mapboxApiAccessToken = _props5.mapboxApiAccessToken,
mapControls = _props5.mapControls,
toggleMapControl = _props5.toggleMapControl;
var mapProps = (0, _extends5.default)({}, mapState, {
preserveDrawingBuffer: true,
mapboxApiAccessToken: mapboxApiAccessToken,
onViewportChange: updateMap,
transformRequest: _mapboxUtils2.transformRequest
});
return _react2.default.createElement(
_styledComponents.StyledMapContainer,
{ style: MAP_STYLE.container, onMouseMove: this._onMouseMove },
_react2.default.createElement(MapControl, {
datasets: datasets,
dragRotate: mapState.dragRotate,
isSplit: mapState.isSplit,
isExport: this.props.isExport,
layers: layers,
mapIndex: this.props.index,
mapLayers: mapLayers,
mapControls: mapControls,
scale: mapState.scale || 1,
top: 0,
onTogglePerspective: mapStateActions.togglePerspective,
onToggleSplitMap: mapStateActions.toggleSplitMap,
onMapToggleLayer: this._handleMapToggleLayer,
onToggleFullScreen: mapStateActions.toggleFullScreen,
onToggleMapControl: toggleMapControl
}),
_react2.default.createElement(
this.props.MapComponent,
(0, _extends5.default)({}, mapProps, {
key: 'bottom',
ref: this._setMapboxMap,
mapStyle: mapStyle.bottomMapStyle,
onClick: onMapClick,
getCursor: this.props.hoverInfo ? function () {
return 'pointer';
} : undefined
}),
this._renderOverlay(),
this._renderMapboxOverlays()
),
mapStyle.topMapStyle && _react2.default.createElement(
'div',
{ style: MAP_STYLE.top },
_react2.default.createElement(this.props.MapComponent, (0, _extends5.default)({}, mapProps, {
key: 'top',
mapStyle: mapStyle.topMapStyle
}))
),
this._renderObjectLayerPopover()
);
}
}]);
return MapContainer;
}(_react.Component), _class.propTypes = {
// required
datasets: _propTypes2.default.object,
interactionConfig: _propTypes2.default.object.isRequired,
layerBlending: _propTypes2.default.string.isRequired,
layerOrder: _propTypes2.default.arrayOf(_propTypes2.default.any).isRequired,
layerData: _propTypes2.default.arrayOf(_propTypes2.default.any).isRequired,
layers: _propTypes2.default.arrayOf(_propTypes2.default.any).isRequired,
mapState: _propTypes2.default.object.isRequired,
mapStyle: _propTypes2.default.object.isRequired,
mapControls: _propTypes2.default.object.isRequired,
mapboxApiAccessToken: _propTypes2.default.string.isRequired,
toggleMapControl: _propTypes2.default.func.isRequired,
visStateActions: _propTypes2.default.object.isRequired,
mapStateActions: _propTypes2.default.object.isRequired,
// optional
isExport: _propTypes2.default.bool,
clicked: _propTypes2.default.object,
hoverInfo: _propTypes2.default.object,
mapLayers: _propTypes2.default.object,
onMapToggleLayer: _propTypes2.default.func,
onMapStyleLoaded: _propTypes2.default.func,
onMapRender: _propTypes2.default.func
}, _class.defaultProps = {
MapComponent: _reactMapGl2.default
}, _temp);
return MapContainer;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9jb21wb25lbnRzL21hcC1jb250YWluZXIuanMiXSwibmFtZXMiOlsiTWFwQ29udGFpbmVyRmFjdG9yeSIsIk1BUF9TVFlMRSIsImNvbnRhaW5lciIsImRpc3BsYXkiLCJwb3NpdGlvbiIsInRvcCIsInBvaW50ZXJFdmVudHMiLCJnZXRHbENvbnN0IiwiR0wiLCJkIiwiTUFQQk9YR0xfU1RZTEVfVVBEQVRFIiwiZGVwcyIsIk1hcFBvcG92ZXJGYWN0b3J5IiwiTWFwQ29udHJvbEZhY3RvcnkiLCJNYXBQb3BvdmVyIiwiTWFwQ29udHJvbCIsIk1hcENvbnRhaW5lciIsInByb3BzIiwiX29uQ2xvc2VNYXBQb3BvdmVyIiwidmlzU3RhdGVBY3Rpb25zIiwib25MYXllckNsaWNrIiwiX29uTGF5ZXJTZXREb21haW4iLCJpZHgiLCJjb2xvckRvbWFpbiIsImxheWVyQ29uZmlnQ2hhbmdlIiwibGF5ZXJzIiwiX29uV2ViR0xJbml0aWFsaXplZCIsInBpY2tpbmdNb2R1bGUiLCJicnVzaGluZ01vZHVsZSIsImlnbm9yZU11bHRpcGxlUmVnaXN0cmF0aW9ucyIsIl9vbk1vdXNlTW92ZSIsImJydXNoIiwiaW50ZXJhY3Rpb25Db25maWciLCJldnQiLCJuYXRpdmVFdmVudCIsImVuYWJsZWQiLCJzZXRTdGF0ZSIsIm1vdXNlUG9zaXRpb24iLCJvZmZzZXRYIiwib2Zmc2V0WSIsIl9oYW5kbGVNYXBUb2dnbGVMYXllciIsImluZGV4IiwibWFwSW5kZXgiLCJ0b2dnbGVMYXllckZvck1hcCIsImxheWVySWQiLCJfc2V0TWFwYm94TWFwIiwibWFwYm94IiwiX21hcCIsImdldE1hcCIsIm9uIiwiX3JlbmRlck1hcGJveExheWVycyIsInByZXZpb3VzTGF5ZXJzIiwibWFwTGF5ZXJzIiwiZm9yY2UiLCJvbk1hcFN0eWxlTG9hZGVkIiwib25NYXBSZW5kZXIiLCJfb25CZWZvcmVSZW5kZXIiLCJnbCIsIl9zZXRsYXllckJsZW5kaW5nIiwiYmxlbmRpbmciLCJMQVlFUl9CTEVORElOR1MiLCJsYXllckJsZW5kaW5nIiwiYmxlbmRGdW5jIiwiYmxlbmRFcXVhdGlvbiIsIkJMRU5EIiwibWFwIiwiQXJyYXkiLCJpc0FycmF5IiwiX3JlbmRlckxheWVyIiwib3ZlcmxheXMiLCJsYXllckRhdGEiLCJob3ZlckluZm8iLCJjbGlja2VkIiwibWFwU3RhdGUiLCJzdGF0ZSIsImxheWVyIiwiZGF0YSIsImxheWVySW50ZXJhY3Rpb24iLCJvYmplY3RIb3ZlcmVkIiwibGF5ZXJDYWxsYmFja3MiLCJvblNldExheWVyRG9tYWluIiwidmFsIiwiX3Nob3VsZFJlbmRlckxheWVyIiwibGF5ZXJPdmVybGF5IiwicmVuZGVyTGF5ZXIiLCJsZW5ndGgiLCJjb25jYXQiLCJvZmYiLCJkYXRhc2V0cyIsIm9iamVjdEluZm8iLCJ0b29sdGlwIiwicGlja2VkIiwibG5nTGF0Iiwib2JqZWN0Iiwib3ZlcmxheSIsImNvbmZpZyIsImlzVmlzaWJsZSIsImdldEhvdmVyRGF0YSIsImlkIiwiZGF0YUlkIiwiYWxsRGF0YSIsImZpZWxkcyIsInZpZXdwb3J0IiwiY29udGV4dCIsIl9nZXRIb3ZlclhZIiwieCIsInkiLCJwb3BvdmVyUHJvcHMiLCJmaWVsZHNUb1Nob3ciLCJmcmVlemVkIiwiQm9vbGVhbiIsIm9uQ2xvc2UiLCJzY3JlZW5Db29yZCIsInByb2plY3QiLCJpc0F2YWlsYWJsZUFuZFZpc2libGUiLCJzaG91bGRSZW5kZXJMYXllciIsImxheWVyT3JkZXIiLCJkZWNrR2xMYXllcnMiLCJzbGljZSIsInJldmVyc2UiLCJyZWR1Y2UiLCJvbkxheWVySG92ZXIiLCJpc1N0eWxlTG9hZGVkIiwibWFwYm94TGF5ZXJzIiwiZmluYWwiLCJtYXBTdHlsZSIsIm1hcFN0YXRlQWN0aW9ucyIsInVwZGF0ZU1hcCIsIm9uTWFwQ2xpY2siLCJib3R0b21NYXBTdHlsZSIsIm1hcGJveEFwaUFjY2Vzc1Rva2VuIiwibWFwQ29udHJvbHMiLCJ0b2dnbGVNYXBDb250cm9sIiwibWFwUHJvcHMiLCJwcmVzZXJ2ZURyYXdpbmdCdWZmZXIiLCJvblZpZXdwb3J0Q2hhbmdlIiwidHJhbnNmb3JtUmVxdWVzdCIsImRyYWdSb3RhdGUiLCJpc1NwbGl0IiwiaXNFeHBvcnQiLCJzY2FsZSIsInRvZ2dsZVBlcnNwZWN0aXZlIiwidG9nZ2xlU3BsaXRNYXAiLCJ0b2dnbGVGdWxsU2NyZWVuIiwidW5kZWZpbmVkIiwiX3JlbmRlck92ZXJsYXkiLCJfcmVuZGVyTWFwYm94T3ZlcmxheXMiLCJ0b3BNYXBTdHlsZSIsIl9yZW5kZXJPYmplY3RMYXllclBvcG92ZXIiLCJDb21wb25lbnQiLCJwcm9wVHlwZXMiLCJQcm9wVHlwZXMiLCJpc1JlcXVpcmVkIiwic3RyaW5nIiwiYXJyYXlPZiIsImFueSIsImZ1bmMiLCJib29sIiwib25NYXBUb2dnbGVMYXllciIsImRlZmF1bHRQcm9wcyIsIk1hcENvbXBvbmVudCIsIk1hcGJveEdMTWFwIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7a0JBMkR3QkEsbUI7O0FBdEN4Qjs7OztBQUNBOzs7O0FBQ0E7Ozs7QUFDQTs7OztBQUNBOztBQUVBOzs7O0FBQ0E7Ozs7QUFHQTs7OztBQUNBOzs7O0FBQ0E7O0FBR0E7O0FBRUE7O0FBR0E7Ozs7QUFYQTtBQTlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQXVCQSxJQUFNQyxZQUFZO0FBQ2hCQyxhQUFXO0FBQ1RDLGFBQVMsY0FEQTtBQUVUQyxjQUFVO0FBRkQsR0FESztBQUtoQkMsT0FBSztBQUNIRCxjQUFVLFVBRFAsRUFDbUJDLEtBQUssS0FEeEIsRUFDK0JDLGVBQWU7QUFEOUM7QUFMVyxDQUFsQjs7QUFIQTs7O0FBTEE7OztBQWtCQSxJQUFNQyxhQUFhLFNBQWJBLFVBQWE7QUFBQSxTQUFLQyxTQUFHQyxDQUFILENBQUw7QUFBQSxDQUFuQjs7QUFFQSxJQUFNQyx3QkFB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QUFjQztBQURNLEdBNUIwQzs7O0FBbVlsRSxTQUFPakosWUFBUDtBQUNEIiwiZmlsZSI6Im1hcC1jb250YWluZXIuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBDb3B5cmlnaHQgKGMpIDIwMTggVWJlciBUZWNobm9sb2dpZXMsIEluYy5cbi8vXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYSBjb3B5XG4vLyBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZSBcIlNvZnR3YXJlXCIpLCB0byBkZWFsXG4vLyBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXG4vLyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsXG4vLyBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0IHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXNcbi8vIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWQgaW5cbi8vIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuLy9cbi8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1Jcbi8vIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZLFxuLy8gRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFXG4vLyBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSXG4vLyBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SIE9USEVSV0lTRSwgQVJJU0lORyBGUk9NLFxuLy8gT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFIFVTRSBPUiBPVEhFUiBERUFMSU5HUyBJTlxuLy8gVEhFIFNPRlRXQVJFLlxuXG4vLyBsaWJyYXJpZXNcbmltcG9ydCBSZWFjdCwge0NvbXBvbmVudH0gZnJvbSAncmVhY3QnO1xuaW1wb3J0IFByb3BUeXBlcyBmcm9tICdwcm9wLXR5cGVzJztcbmltcG9ydCBNYXBib3hHTE1hcCBmcm9tICdyZWFjdC1tYXAtZ2wnO1xuaW1wb3J0IERlY2tHTCBmcm9tICdkZWNrLmdsJztcbmltcG9ydCB7R0x9IGZyb20gJ2x1bWEuZ2wnO1xuaW1wb3J0IHtyZWdpc3RlclNoYWRlck1vZHVsZXMsIHNldFBhcmFtZXRlcnN9IGZyb20gJ2x1bWEuZ2wnO1xuaW1wb3J0IHBpY2tpbmdNb2R1bGUgZnJvbSAnc2hhZGVybGliL3BpY2tpbmctbW9kdWxlJztcbmltcG9ydCBicnVzaGluZ01vZHVsZSBmcm9tICdzaGFkZXJsaWIvYnJ1c2hpbmctbW9kdWxlJztcblxuLy8gY29tcG9uZW50c1xuaW1wb3J0IE1hcFBvcG92ZXJGYWN0b3J5IGZyb20gJ2NvbXBvbmVudHMvbWFwL21hcC1wb3BvdmVyJztcbmltcG9ydCBNYXBDb250cm9sRmFjdG9yeSBmcm9tICdjb21wb25lbnRzL21hcC9tYXAtY29udHJvbCc7XG5pbXBvcnQge1N0eWxlZE1hcENvbnRhaW5lcn0gZnJvbSAnY29tcG9uZW50cy9jb21tb24vc3R5bGVkLWNvbXBvbmVudHMnO1xuXG4vLyBPdmVybGF5IHR5cGVcbmltcG9ydCB7Z2VuZXJhdGVNYXBib3hMYXllcnMsIHVwZGF0ZU1hcGJveExheWVyc30gZnJvbSAnLi4vbGF5ZXJzL21hcGJveC11dGlscyc7XG5cbmltcG9ydCB7dHJhbnNmb3JtUmVxdWVzdH0gZnJvbSAndXRpbHMvbWFwLXN0eWxlLXV0aWxzL21hcGJveC11dGlscyc7XG5cbi8vIGRlZmF1bHQtc2V0dGluZ3NcbmltcG9ydCB7TEFZRVJfQkxFTkRJTkdTfSBmcm9tICdjb25zdGFudHMvZGVmYXVsdC1zZXR0aW5ncyc7XG5cbmNvbnN0IE1BUF9TVFlMRSA9IHtcbiAgY29udGFpbmVyOiB7XG4gICAgZGlzcGxheTogJ2lubGluZS1ibG9jaycsXG4gICAgcG9zaXRpb246ICdyZWxhdGl2ZSdcbiAgfSxcbiAgdG9wOiB7XG4gICAgcG9zaXRpb246ICdhYnNvbHV0ZScsIHRvcDogJzBweCcsIHBvaW50ZXJFdmVudHM6ICdub25lJ1xuICB9XG59O1xuXG5jb25zdCBnZXRHbENvbnN0ID0gZCA9PiBHTFtkXTtcblxuY29uc3QgTUFQQk9YR0xfU1RZTEVfVVBEQVRFID0gJ3N0eWxlLmxvYWQnO1xuTWFwQ29udGFpbmVyRmFjdG9yeS5kZXBzID0gW1xuICBNYXBQb3BvdmVyRmFjdG9yeSwgTWFwQ29udHJvbEZhY3RvcnldO1xuXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBNYXBDb250YWluZXJGYWN0b3J5KE1hcFBvcG92ZXIsIE1hcENvbnRyb2wpIHtcbiAgY2xhc3MgTWFwQ29udGFpbmVyIGV4dGVuZHMgQ29tcG9uZW50IHtcbiAgICBzdGF0aWMgcHJvcFR5cGVzID0ge1xuICAgICAgLy8gcmVxdWlyZWRcbiAgICAgIGRhdGFzZXRzOiBQcm9wVHlwZXMub2JqZWN0LFxuICAgICAgaW50ZXJhY3Rpb25Db25maWc6IFByb3BUeXBlcy5vYmplY3QuaXNSZXF1aXJlZCxcbiAgICAgIGxheWVyQmxlbmRpbmc6IFByb3BUeXBlcy5zdHJpbmcuaXNSZXF1aXJlZCxcbiAgICAgIGxheWVyT3JkZXI6IFByb3BUeXBlcy5hcnJheU9mKFByb3BUeXBlcy5hbnkpLmlzUmVxdWlyZWQsXG4gICAgICBsYXllckRhdGE6IFByb3BUeXBlcy5hcnJheU9mKFByb3BUeXBlcy5hbnkpLmlzUmVxdWlyZWQsXG4gICAgICBsYXllcnM6IFByb3BUeXBlcy5hcnJheU9mKFByb3BUeXBlcy5hbnkpLmlzUmVxdWlyZWQsXG4gICAgICBtYXBTdGF0ZTogUHJvcFR5cGVzLm9iamVjdC5pc1JlcXVpcmVkLFxuICAgICAgbWFwU3R5bGU6IFByb3BUeXBlcy5vYmplY3QuaXNSZXF1aXJlZCxcbiAgICAgIG1hcENvbnRyb2xzOiBQcm9wVHlwZXMub2JqZWN0LmlzUmVxdWlyZWQsXG4gICAgICBtYXBib3hBcGlBY2Nlc3NUb2tlbjogUHJvcFR5cGVzLnN0cmluZy5pc1JlcXVpcmVkLFxuICAgICAgdG9nZ2xlTWFwQ29udHJvbDogUHJvcFR5cGVzLmZ1bmMuaXNSZXF1aXJlZCxcbiAgICAgIHZpc1N0YXRlQWN0aW9uczogUHJvcFR5cGVzLm9iamVjdC5pc1JlcXVpcmVkLFxuICAgICAgbWFwU3RhdGVBY3Rpb25zOiBQcm9wVHlwZXMub2JqZWN0LmlzUmVxdWlyZWQsXG5cbiAgICAgIC8vIG9wdGlvbmFsXG4gICAgICBpc0V4cG9ydDogUHJvcFR5cGVzLmJvb2wsXG4gICAgICBjbGlja2VkOiBQcm9wVHlwZXMub2JqZWN0LFxuICAgICAgaG92ZXJJbmZvOiBQcm9wVHlwZXMub2JqZWN0LFxuICAgICAgbWFwTGF5ZXJzOiBQcm9wVHlwZXMub2JqZWN0LFxuICAgICAgb25NYXBUb2dnbGVMYXllcjogUHJvcFR5cGVzLmZ1bmMsXG4gICAgICBvbk1hcFN0eWxlTG9hZGVkOiBQcm9wVHlwZXMuZnVuYyxcbiAgICAgIG9uTWFwUmVuZGVyOiBQcm9wVHlwZXMuZnVuY1xuICAgIH07XG5cbiAgICBzdGF0aWMgZGVmYXVsdFByb3BzID0ge1xuICAgICAgTWFwQ29tcG9uZW50OiBNYXBib3hHTE1hcFxuICAgIH07XG5cbiAgICBjb25zdHJ1Y3Rvcihwcm9wcykge1xuICAgICAgc3VwZXIocHJvcHMpO1xuICAgICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgICAgbW91c2VQb3NpdGlvbjogWzAsIDBdXG4gICAgICB9O1xuICAgICAgdGhpcy5wcmV2aW91c0xheWVycyA9IHtcbiAgICAgICAgLy8gW2xheWVycy5pZF06IG1hcGJveExheWVyQ29uZmlnXG4gICAgICB9O1xuICAgIH1cblxuICAgIGNvbXBvbmVudFdpbGxVbm1vdW50KCkge1xuICAgICAgLy8gdW5iaW5kIG1hcGJveGdsIGV2ZW50IGxpc3RlbmVyXG4gICAgICBpZiAodGhpcy5fbWFwKSB7XG4gICAgICAgIHRoaXMuX21hcC5vZmYoTUFQQk9YR0xfU1RZTEVfVVBEQVRFKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvKiBjb21wb25lbnQgcHJpdmF0ZSBmdW5jdGlvbnMgKi9cbiAgICBfb25DbG9zZU1hcFBvcG92ZXIgPSAoKSA9PiB7XG4gICAgICB0aGlzLnByb3BzLnZpc1N0YXRlQWN0aW9ucy5vbkxheWVyQ2xpY2sobnVsbCk7XG4gICAgfTtcblxuICAgIF9vbkxheWVyU2V0RG9tYWluID0gKGlkeCwgY29sb3JEb21haW4pID0+IHtcbiAgICAgIHRoaXMucHJvcHMudmlzU3RhdGVBY3Rpb25zLmxheWVyQ29uZmlnQ2hhbmdlKHRoaXMucHJvcHMubGF5ZXJzW2lkeF0sIHtcbiAgICAgICAgY29sb3JEb21haW5cbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICBfb25XZWJHTEluaXRpYWxpemVkID0gZ2wgPT4ge1xuICAgICAgcmVnaXN0ZXJTaGFkZXJNb2R1bGVzKFxuICAgICAgICBbcGlja2luZ01vZHVsZSwgYnJ1c2hpbmdNb2R1bGVdLCB7XG4gICAgICAgICAgaWdub3JlTXVsdGlwbGVSZWdpc3RyYXRpb25zOiB0cnVlXG4gICAgICB9KTtcblxuICAgICAgLy8gYWxsb3cgVWludDMyIGluZGljZXMgaW4gYnVpbGRpbmcgbGF5ZXJcbiAgICAgIC8vIGdsLmdldEV4dGVuc2lvbignT0VTX2VsZW1lbnRfaW5kZXhfdWludCcpO1xuICAgIH07XG5cbiAgICBfb25Nb3VzZU1vdmUgPSBldnQgPT4ge1xuICAgICAgY29uc3Qge2ludGVyYWN0aW9uQ29uZmlnOiB7YnJ1c2h9fSA9IHRoaXMucHJvcHM7XG5cbiAgICAgIGlmIChldnQubmF0aXZlRXZlbnQgJiYgYnJ1c2guZW5hYmxlZCkge1xuICAgICAgICB0aGlzLnNldFN0YXRlKHtcbiAgICAgICAgICBtb3VzZVBvc2l0aW9uOiBbZXZ0Lm5hdGl2ZUV2ZW50Lm9mZnNldFgsIGV2dC5uYXRpdmVFdmVudC5vZmZzZXRZXVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgX2hhbmRsZU1hcFRvZ2dsZUxheWVyID0gbGF5ZXJJZCA9PiB7XG4gICAgICBjb25zdCB7aW5kZXg6IG1hcEluZGV4ID0gMCwgdmlzU3RhdGVBY3Rpb25zfSA9IHRoaXMucHJvcHM7XG4gICAgICB2aXNTdGF0ZUFjdGlvbnMudG9nZ2xlTGF5ZXJGb3JNYXAobWFwSW5kZXgsIGxheWVySWQpO1xuICAgIH07XG5cbiAgICBfc2V0TWFwYm94TWFwID0gKG1hcGJveCkgPT4ge1xuICAgICAgaWYgKCF0aGlzLl9tYXAgJiYgbWFwYm94KSB7XG4gICAgICAgIHRoaXMuX21hcCA9IG1hcGJveC5nZXRNYXAoKTtcbiAgICAgICAgLy8gYmluZCBtYXBib3hnbCBldmVudCBsaXN0ZW5lclxuICAgICAgICB0aGlzLl9tYXAub24oTUFQQk9YR0xfU1RZTEVfVVBEQVRFLCAoKSA9PiB7XG4gICAgICAgICAgLy8gZm9yY2UgcmVmcmVzaCBtYXBib3hnbCBsYXllcnNcblxuICAgICAgICAgIHVwZGF0ZU1hcGJveExheWVycyhcbiAgICAgICAgICAgIHRoaXMuX21hcCxcbiAgICAgICAgICAgIHRoaXMuX3JlbmRlck1hcGJveExheWVycygpLFxuICAgICAgICAgICAgdGhpcy5wcmV2aW91c0xheWVycyxcbiAgICAgICAgICAgIHRoaXMucHJvcHMubWFwTGF5ZXJzLFxuICAgICAgICAgICAge2ZvcmNlOiB0cnVlfVxuICAgICAgICAgICk7XG5cbiAgICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMub25NYXBTdHlsZUxvYWRlZCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgdGhpcy5wcm9wcy5vbk1hcFN0eWxlTG9hZGVkKHRoaXMuX21hcCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLl9tYXAub24oJ3JlbmRlcicsICgpID0+IHtcbiAgICAgICAgICBpZiAodHlwZW9mIHRoaXMucHJvcHMub25NYXBSZW5kZXIgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIHRoaXMucHJvcHMub25NYXBSZW5kZXIodGhpcy5fbWFwKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIF9vbkJlZm9yZVJlbmRlciA9ICh7Z2x9KSA9PiB7XG4gICAgICB0aGlzLl9zZXRsYXllckJsZW5kaW5nKGdsKTtcbiAgICB9O1xuXG4gICAgX3NldGxheWVyQmxlbmRpbmcgPSBnbCA9PiB7XG4gICAgICBjb25zdCBibGVuZGluZyA9IExBWUVSX0JMRU5ESU5HU1t0aGlzLnByb3BzLmxheWVyQmxlbmRpbmddO1xuICAgICAgY29uc3Qge2JsZW5kRnVuYywgYmxlbmRFcXVhdGlvbn0gPSBibGVuZGluZztcblxuICAgICAgc2V0UGFyYW1ldGVycyhnbCwge1xuICAgICAgICBbR0wuQkxFTkRdOiB0cnVlLFxuICAgICAgICAuLi4oYmxlbmRGdW5jID8ge1xuICAgICAgICAgIGJsZW5kRnVuYzogYmxlbmRGdW5jLm1hcChnZXRHbENvbnN0KSxcbiAgICAgICAgICBibGVuZEVxdWF0aW9uOiBBcnJheS5pc0FycmF5KGJsZW5kRXF1YXRpb24pID8gYmxlbmRFcXVhdGlvbi5tYXAoZ2V0R2xDb25zdCkgOiBnZXRHbENvbnN0KGJsZW5kRXF1YXRpb24pXG4gICAgICAgIH0gOiB7fSlcbiAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKiBjb21wb25lbnQgcmVuZGVyIGZ1bmN0aW9ucyAqL1xuICAgIC8qIGVzbGludC1kaXNhYmxlIGNvbXBsZXhpdHkgKi9cbiAgICBfcmVuZGVyT2JqZWN0TGF5ZXJQb3BvdmVyKCkge1xuICAgICAgLy8gVE9ETzogbW92ZSB0aGlzIGludG8gcmVkdWNlciBzbyBpdCBjYW4gYmUgdGVzdGVkXG4gICAgICBjb25zdCB7XG4gICAgICAgIG1hcFN0YXRlLFxuICAgICAgICBob3ZlckluZm8sXG4gICAgICAgIGNsaWNrZWQsXG4gICAgICAgIGRhdGFzZXRzLFxuICAgICAgICBpbnRlcmFjdGlvbkNvbmZpZyxcbiAgICAgICAgbGF5ZXJzLFxuICAgICAgICBtYXBMYXllcnNcbiAgICAgIH0gPSB0aGlzLnByb3BzO1xuXG4gICAgICAvLyBpZiBjbGlja2VkIHNvbWV0aGluZywgaWdub3JlIGhvdmVyIGJlaGF2aW9yXG4gICAgICBjb25zdCBvYmplY3RJbmZvID0gY2xpY2tlZCB8fCBob3ZlckluZm87XG4gICAgICBpZiAoXG4gICAgICAgICFpbnRlcmFjdGlvbkNvbmZpZy50b29sdGlwLmVuYWJsZWQgfHxcbiAgICAgICAgIW9iamVjdEluZm8gfHxcbiAgICAgICAgIW9iamVjdEluZm8ucGlja2VkXG4gICAgICApIHtcbiAgICAgICAgLy8gbm90aGluZyBob3ZlcmVkXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7bG5nTGF0LCBvYmplY3QsIGxheWVyOiBvdmVybGF5fSA9IG9iamVjdEluZm87XG5cbiAgICAgIC8vIGRlY2tnbCBsYXllciB0byBrZXBsZXItZ2wgbGF5ZXJcbiAgICAgIGNvbnN0IGxheWVyID0gbGF5ZXJzW292ZXJsYXkucHJvcHMuaWR4XTtcblxuICAgICAgaWYgKFxuICAgICAgICAhbGF5ZXIgfHxcbiAgICAgICAgIWxheWVyLmNvbmZpZy5pc1Zpc2libGUgfHxcbiAgICAgICAgIW9iamVjdCB8fFxuICAgICAgICAhbGF5ZXIuZ2V0SG92ZXJEYXRhIHx8XG4gICAgICAgIChtYXBMYXllcnMgJiYgIW1hcExheWVyc1tsYXllci5pZF0uaXNWaXNpYmxlKVxuICAgICAgKSB7XG4gICAgICAgIC8vIGxheWVyIGlzIG5vdCB2aXNpYmxlXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7Y29uZmlnOiB7ZGF0YUlkfX0gPSBsYXllcjtcbiAgICAgIGNvbnN0IHthbGxEYXRhLCBmaWVsZHN9ID0gZGF0YXNldHNbZGF0YUlkXTtcbiAgICAgIGNvbnN0IGRhdGEgPSBsYXllci5nZXRIb3ZlckRhdGEob2JqZWN0LCBhbGxEYXRhKTtcblxuICAgICAgLy8gcHJvamVjdCBsbmdsYXQgdG8gc2NyZWVuIHNvIHRoYXQgdG9vbHRpcCBmb2xsb3dzIHRoZSBvYmplY3Qgb24gem9vbVxuICAgICAgY29uc3Qge3ZpZXdwb3J0fSA9IG92ZXJsYXkuY29udGV4dDtcbiAgICAgIGNvbnN0IHt4LCB5fSA9IHRoaXMuX2dldEhvdmVyWFkodmlld3BvcnQsIGxuZ0xhdCkgfHwgb2JqZWN0SW5mbztcblxuICAgICAgY29uc3QgcG9wb3ZlclByb3BzID0ge1xuICAgICAgICBkYXRhLFxuICAgICAgICBmaWVsZHMsXG4gICAgICAgIGZpZWxkc1RvU2hvdzogaW50ZXJhY3Rpb25Db25maWcudG9vbHRpcC5jb25maWcuZmllbGRzVG9TaG93W2RhdGFJZF0sXG4gICAgICAgIGxheWVyLFxuICAgICAgICBpc1Zpc2libGU6IHRydWUsXG4gICAgICAgIHgsXG4gICAgICAgIHksXG4gICAgICAgIGZyZWV6ZWQ6IEJvb2xlYW4oY2xpY2tlZCksXG4gICAgICAgIG9uQ2xvc2U6IHRoaXMuX29uQ2xvc2VNYXBQb3BvdmVyLFxuICAgICAgICBtYXBTdGF0ZVxuICAgICAgfTtcblxuICAgICAgcmV0dXJuIChcbiAgICAgICAgPGRpdj5cbiAgICAgICAgICA8TWFwUG9wb3ZlciB7Li4ucG9wb3ZlclByb3BzfSAvPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICk7XG4gICAgfVxuXG4gICAgLyogZXNsaW50LWVuYWJsZSBjb21wbGV4aXR5ICovXG5cbiAgICBfZ2V0SG92ZXJYWSh2aWV3cG9ydCwgbG5nTGF0KSB7XG4gICAgICBjb25zdCBzY3JlZW5Db29yZCA9ICF2aWV3cG9ydCB8fCAhbG5nTGF0ID8gbnVsbCA6IHZpZXdwb3J0LnByb2plY3QobG5nTGF0KTtcblxuICAgICAgcmV0dXJuIHNjcmVlbkNvb3JkICYmIHt4OiBzY3JlZW5Db29yZFswXSwgeTogc2NyZWVuQ29vcmRbMV19O1xuICAgIH1cblxuICAgIF9zaG91bGRSZW5kZXJMYXllcihsYXllciwgZGF0YSwgbWFwTGF5ZXJzKSB7XG4gICAgICBjb25zdCBpc0F2YWlsYWJsZUFuZFZpc2libGUgPVxuICAgICAgICAhKG1hcExheWVycyAmJiBtYXBMYXllcnNbbGF5ZXIuaWRdKSB8fCBtYXBMYXllcnNbbGF5ZXIuaWRdLmlzVmlzaWJsZTtcbiAgICAgIHJldHVybiBsYXllci5zaG91bGRSZW5kZXJMYXllcihkYXRhKSAmJiBpc0F2YWlsYWJsZUFuZFZpc2libGU7XG4gICAgfVxuXG4gICAgX3JlbmRlckxheWVyID0gKG92ZXJsYXlzLCBpZHgpID0+IHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgbGF5ZXJzLFxuICAgICAgICBsYXllckRhdGEsXG4gICAgICAgIGhvdmVySW5mbyxcbiAgICAgICAgY2xpY2tlZCxcbiAgICAgICAgbWFwTGF5ZXJzLFxuICAgICAgICBtYXBTdGF0ZSxcbiAgICAgICAgaW50ZXJhY3Rpb25Db25maWdcbiAgICAgIH0gPSB0aGlzLnByb3BzO1xuICAgICAgY29uc3Qge21vdXNlUG9zaXRpb259ID0gdGhpcy5zdGF0ZTtcbiAgICAgIGNvbnN0IGxheWVyID0gbGF5ZXJzW2lkeF07XG4gICAgICBjb25zdCBkYXRhID0gbGF5ZXJEYXRhW2lkeF07XG5cbiAgICAgIGNvbnN0IGxheWVySW50ZXJhY3Rpb24gPSB7XG4gICAgICAgIG1vdXNlUG9zaXRpb25cbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IG9iamVjdEhvdmVyZWQgPSBjbGlja2VkIHx8IGhvdmVySW5mbztcbiAgICAgIGNvbnN0IGxheWVyQ2FsbGJhY2tzID0ge1xuICAgICAgICBvblNldExheWVyRG9tYWluOiB2YWwgPT4gdGhpcy5fb25MYXllclNldERvbWFpbihpZHgsIHZhbClcbiAgICAgIH07XG5cbiAgICAgIGlmICghdGhpcy5fc2hvdWxkUmVuZGVyTGF5ZXIobGF5ZXIsIGRhdGEsIG1hcExheWVycykpIHtcbiAgICAgICAgcmV0dXJuIG92ZXJsYXlzO1xuICAgICAgfVxuXG4gICAgICBsZXQgbGF5ZXJPdmVybGF5ID0gW107XG5cbiAgICAgIC8vIExheWVyIGlzIExheWVyIGNsYXNzXG4gICAgICBpZiAodHlwZW9mIGxheWVyLnJlbmRlckxheWVyID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIGxheWVyT3ZlcmxheSA9IGxheWVyLnJlbmRlckxheWVyKHtcbiAgICAgICAgICBkYXRhLFxuICAgICAgICAgIGlkeCxcbiAgICAgICAgICBsYXllckludGVyYWN0aW9uLFxuICAgICAgICAgIG9iamVjdEhvdmVyZWQsXG4gICAgICAgICAgbWFwU3RhdGUsXG4gICAgICAgICAgaW50ZXJhY3Rpb25Db25maWcsXG4gICAgICAgICAgbGF5ZXJDYWxsYmFja3NcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIGlmIChsYXllck92ZXJsYXkubGVuZ3RoKSB7XG4gICAgICAgIG92ZXJsYXlzID0gb3ZlcmxheXMuY29uY2F0KGxheWVyT3ZlcmxheSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gb3ZlcmxheXM7XG4gICAgfTtcblxuICAgIF9yZW5kZXJPdmVybGF5KCkge1xuICAgICAgY29uc3Qge1xuICAgICAgICBtYXBTdGF0ZSxcbiAgICAgICAgbGF5ZXJEYXRhLFxuICAgICAgICBsYXllck9yZGVyLFxuICAgICAgICB2aXNTdGF0ZUFjdGlvbnNcbiAgICAgIH0gPSB0aGlzLnByb3BzO1xuXG4gICAgICBsZXQgZGVja0dsTGF5ZXJzID0gW107XG5cbiAgICAgIC8vIHdhaXQgdW50aWwgZGF0YSBpcyByZWFkeSBiZWZvcmUgcmVuZGVyIGRhdGEgbGF5ZXJzXG4gICAgICBpZiAobGF5ZXJEYXRhICYmIGxheWVyRGF0YS5sZW5ndGgpIHtcbiAgICAgICAgLy8gbGFzdCBsYXllciByZW5kZXIgZmlyc3RcbiAgICAgICAgZGVja0dsTGF5ZXJzID0gbGF5ZXJPcmRlclxuICAgICAgICAgIC5zbGljZSgpXG4gICAgICAgICAgLnJldmVyc2UoKVxuICAgICAgICAgIC5yZWR1Y2UodGhpcy5fcmVuZGVyTGF5ZXIsIFtdKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIChcbiAgICAgICAgPERlY2tHTFxuICAgICAgICAgIHZpZXdTdGF0ZT17bWFwU3RhdGV9XG4gICAgICAgICAgaWQ9XCJkZWZhdWx0LWRlY2tnbC1vdmVybGF5XCJcbiAgICAgICAgICBsYXllcnM9e2RlY2tHbExheWVyc31cbiAgICAgICAgICBvbldlYkdMSW5pdGlhbGl6ZWQ9e3RoaXMuX29uV2ViR0xJbml0aWFsaXplZH1cbiAgICAgICAgICBvbkJlZm9yZVJlbmRlcj17dGhpcy5fb25CZWZvcmVSZW5kZXJ9XG4gICAgICAgICAgb25MYXllckhvdmVyPXt2aXNTdGF0ZUFjdGlvbnMub25MYXllckhvdmVyfVxuICAgICAgICAgIG9uTGF5ZXJDbGljaz17dmlzU3RhdGVBY3Rpb25zLm9uTGF5ZXJDbGlja31cbiAgICAgICAgLz5cbiAgICAgICk7XG4gICAgfVxuXG4gICAgX3JlbmRlck1hcGJveExheWVycygpIHtcbiAgICAgIGNvbnN0IHtcbiAgICAgICAgbGF5ZXJzLFxuICAgICAgICBsYXllckRhdGEsXG4gICAgICAgIGxheWVyT3JkZXJcbiAgICAgIH0gPSB0aGlzLnByb3BzO1xuXG4gICAgICByZXR1cm4gZ2VuZXJhdGVNYXBib3hMYXllcnMobGF5ZXJzLCBsYXllckRhdGEsIGxheWVyT3JkZXIpO1xuICAgIH1cblxuICAgIF9yZW5kZXJNYXBib3hPdmVybGF5cygpIHtcbiAgICAgIGlmICh0aGlzLl9tYXAgJiYgdGhpcy5fbWFwLmlzU3R5bGVMb2FkZWQoKSkge1xuXG4gICAgICAgIGNvbnN0IG1hcGJveExheWVycyA9IHRoaXMuX3JlbmRlck1hcGJveExheWVycygpO1xuXG4gICAgICAgIHVwZGF0ZU1hcGJveExheWVycyhcbiAgICAgICAgICB0aGlzLl9tYXAsXG4gICAgICAgICAgbWFwYm94TGF5ZXJzLFxuICAgICAgICAgIHRoaXMucHJldmlvdXNMYXllcnMsXG4gICAgICAgICAgdGhpcy5wcm9wcy5tYXBMYXllcnNcbiAgICAgICAgKTtcblxuICAgICAgICB0aGlzLnByZXZpb3VzTGF5ZXJzID0gbWFwYm94TGF5ZXJzLnJlZHVjZSgoZmluYWwsIGxheWVyKSA9PiAoe1xuICAgICAgICAgIC4uLmZpbmFsLFxuICAgICAgICAgIFtsYXllci5pZF06IGxheWVyLmNvbmZpZ1xuICAgICAgICB9KSwge30pXG4gICAgICB9XG4gICAgfVxuXG4gICAgcmVuZGVyKCkge1xuICAgICAgY29uc3Qge21hcFN0YXRlLCBtYXBTdHlsZSwgbWFwU3RhdGVBY3Rpb25zfSA9IHRoaXMucHJvcHM7XG4gICAgICBjb25zdCB7dXBkYXRlTWFwLCBvbk1hcENsaWNrfSA9IG1hcFN0YXRlQWN0aW9ucztcblxuICAgICAgaWYgKCFtYXBTdHlsZS5ib3R0b21NYXBTdHlsZSkge1xuICAgICAgICAvLyBzdHlsZSBub3QgeWV0IGxvYWRlZFxuICAgICAgICByZXR1cm4gPGRpdi8+O1xuICAgICAgfVxuXG4gICAgICBjb25zdCB7bWFwTGF5ZXJzLCBsYXllcnMsIGRhdGFzZXRzLCBtYXBib3hBcGlBY2Nlc3NUb2tlbixcbiAgICAgICAgbWFwQ29udHJvbHMsIHRvZ2dsZU1hcENvbnRyb2x9ID0gdGhpcy5wcm9wcztcblxuICAgICAgY29uc3QgbWFwUHJvcHMgPSB7XG4gICAgICAgIC4uLm1hcFN0YXRlLFxuICAgICAgICBwcmVzZXJ2ZURyYXdpbmdCdWZmZXI6IHRydWUsXG4gICAgICAgIG1hcGJveEFwaUFjY2Vzc1Rva2VuLFxuICAgICAgICBvblZpZXdwb3J0Q2hhbmdlOiB1cGRhdGVNYXAsXG4gICAgICAgIHRyYW5zZm9ybVJlcXVlc3RcbiAgICAgIH07XG5cbiAgICAgIHJldHVybiAoXG4gICAgICAgIDxTdHlsZWRNYXBDb250YWluZXIgc3R5bGU9e01BUF9TVFlMRS5jb250YWluZXJ9IG9uTW91c2VNb3ZlPXt0aGlzLl9vbk1vdXNlTW92ZX0+XG4gICAgICAgICAgPE1hcENvbnRyb2xcbiAgICAgICAgICAgIGRhdGFzZXRzPXtkYXRhc2V0c31cbiAgICAgICAgICAgIGRyYWdSb3RhdGU9e21hcFN0YXRlLmRyYWdSb3RhdGV9XG4gICAgICAgICAgICBpc1NwbGl0PXttYXBTdGF0ZS5pc1NwbGl0fVxuICAgICAgICAgICAgaXNFeHBvcnQ9e3RoaXMucHJvcHMuaXNFeHBvcnR9XG4gICAgICAgICAgICBsYXllcnM9e2xheWVyc31cbiAgICAgICAgICAgIG1hcEluZGV4PXt0aGlzLnByb3BzLmluZGV4fVxuICAgICAgICAgICAgbWFwTGF5ZXJzPXttYXBMYXllcnN9XG4gICAgICAgICAgICBtYXBDb250cm9scz17bWFwQ29udHJvbHN9XG4gICAgICAgICAgICBzY2FsZT17bWFwU3RhdGUuc2NhbGUgfHwgMX1cbiAgICAgICAgICAgIHRvcD17MH1cbiAgICAgICAgICAgIG9uVG9nZ2xlUGVyc3BlY3RpdmU9e21hcFN0YXRlQWN0aW9ucy50b2dnbGVQZXJzcGVjdGl2ZX1cbiAgICAgICAgICAgIG9