kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
176 lines (171 loc) • 27.6 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = useLegendPosition;
exports.useCalcLegendPosition = useCalcLegendPosition;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _react = require("react");
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; } // SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
var MARGIN = {
left: 10,
top: 10,
right: 10,
bottom: 30
};
var DEFAULT_POSITION = {
x: MARGIN.right,
y: MARGIN.bottom,
anchorX: 'right',
anchorY: 'bottom'
};
var MIN_CONTENT_HEIGHT = 100;
var MAP_CONTROL_HEADER_FULL_HEIGHT = 34;
function useCalcLegendPosition(_ref) {
var legendContentRef = _ref.legendContentRef,
isSidePanelShown = _ref.isSidePanelShown,
sidePanelWidth = _ref.sidePanelWidth;
return (0, _react.useCallback)(function () {
var _legendContentRef$cur;
var root = (_legendContentRef$cur = legendContentRef.current) === null || _legendContentRef$cur === void 0 ? void 0 : _legendContentRef$cur.closest('.kepler-gl');
var legendContent = legendContentRef.current;
if (!legendContent || !(root instanceof HTMLElement)) {
return DEFAULT_POSITION;
}
var legendRect = legendContent.getBoundingClientRect();
var mapRootBounds = root.getBoundingClientRect();
var leftSidebarOffset = isSidePanelShown ? sidePanelWidth : 0;
var leftOffset = Math.max(MARGIN.left, legendRect.left - mapRootBounds.left - leftSidebarOffset);
var rightOffset = Math.max(MARGIN.right, mapRootBounds.right - legendRect.right);
var topOffset = Math.max(MARGIN.top, legendRect.top - mapRootBounds.top);
var bottomOffset = Math.max(MARGIN.bottom, mapRootBounds.bottom - legendRect.bottom);
return _objectSpread(_objectSpread({}, leftOffset < rightOffset ? {
x: leftOffset + leftSidebarOffset,
anchorX: 'left'
} : {
x: rightOffset,
anchorX: 'right'
}), topOffset < bottomOffset ? {
y: topOffset,
anchorY: 'top'
} : {
y: bottomOffset,
anchorY: 'bottom'
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSidePanelShown, sidePanelWidth]);
}
/**
* Returns a function that calculates the anchored position of the map legend
* that is being dragged.
*/
function useLegendPosition(_ref2) {
var _settings$position, _settings$contentHeig, _theme$sidePanel;
var legendContentRef = _ref2.legendContentRef,
isSidePanelShown = _ref2.isSidePanelShown,
settings = _ref2.settings,
onChangeSettings = _ref2.onChangeSettings,
theme = _ref2.theme,
mapHeight = _ref2.mapHeight,
mapWidth = _ref2.mapWidth;
var pos = (_settings$position = settings === null || settings === void 0 ? void 0 : settings.position) !== null && _settings$position !== void 0 ? _settings$position : DEFAULT_POSITION;
var contentHeight = (_settings$contentHeig = settings === null || settings === void 0 ? void 0 : settings.contentHeight) !== null && _settings$contentHeig !== void 0 ? _settings$contentHeig : -1;
var positionStyles = (0, _react.useMemo)(function () {
return (0, _defineProperty2["default"])((0, _defineProperty2["default"])({}, pos.anchorX, pos.x), pos.anchorY, pos.y);
}, [pos]);
var startHeightRef = (0, _react.useRef)(0);
var sidePanelWidth = ((_theme$sidePanel = theme.sidePanel) === null || _theme$sidePanel === void 0 ? void 0 : _theme$sidePanel.width) || 0;
// Calculate dynamic max content height based on map root dimensions
var maxContentHeight = (0, _react.useMemo)(function () {
if (!mapHeight) return undefined;
// Available height minus margins and header
return mapHeight - MARGIN.top - MARGIN.bottom - MAP_CONTROL_HEADER_FULL_HEIGHT;
}, [mapHeight]);
var calcPosition = useCalcLegendPosition({
legendContentRef: legendContentRef,
isSidePanelShown: isSidePanelShown,
sidePanelWidth: sidePanelWidth
});
var updatePosition = (0, _react.useCallback)(function () {
return onChangeSettings({
position: calcPosition()
});
}, [calcPosition, onChangeSettings]);
var startResize = (0, _react.useCallback)(function () {
var _legendContentRef$cur2;
var content = (_legendContentRef$cur2 = legendContentRef.current) === null || _legendContentRef$cur2 === void 0 ? void 0 : _legendContentRef$cur2.querySelector('.map-control__panel-content');
if (content instanceof HTMLElement) {
startHeightRef.current = content.offsetHeight;
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
var resize = (0, _react.useCallback)(function (deltaY) {
var _legendContentRef$cur3;
var root = (_legendContentRef$cur3 = legendContentRef.current) === null || _legendContentRef$cur3 === void 0 ? void 0 : _legendContentRef$cur3.closest('.kepler-gl');
var legendContent = legendContentRef.current;
if (root instanceof HTMLElement && legendContent) {
var mapRootBounds = root.getBoundingClientRect();
var legendRect = legendContent.getBoundingClientRect();
var remainingHeight = mapRootBounds.bottom - (legendRect.top + MAP_CONTROL_HEADER_FULL_HEIGHT + MARGIN.bottom);
// Use maxContentHeight if available, otherwise fall back to viewport-based calculation
var maxHeight = maxContentHeight ? Math.min(maxContentHeight, remainingHeight) : remainingHeight;
var nextHeight = Math.min(maxHeight, Math.max(MIN_CONTENT_HEIGHT, startHeightRef.current + deltaY));
onChangeSettings({
contentHeight: nextHeight
});
if (contentHeight > 0 && pos.anchorY === 'bottom') {
onChangeSettings({
position: _objectSpread(_objectSpread({}, pos), {}, {
y: pos.y - (nextHeight - contentHeight)
})
});
}
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[contentHeight, pos, onChangeSettings, maxContentHeight]);
// Shift when side panel is shown/hidden
var posRef = (0, _react.useRef)(pos);
posRef.current = pos;
(0, _react.useEffect)(function () {
var currentPos = posRef.current;
if (currentPos.anchorX === 'left') {
if (isSidePanelShown) {
if (currentPos.x <= sidePanelWidth + MARGIN.left) {
onChangeSettings({
position: _objectSpread(_objectSpread({}, currentPos), {}, {
x: sidePanelWidth + MARGIN.left
})
});
}
} else {
onChangeSettings({
position: _objectSpread(_objectSpread({}, currentPos), {}, {
x: Math.max(MARGIN.left, currentPos.x - sidePanelWidth)
})
});
}
}
}, [isSidePanelShown, onChangeSettings, sidePanelWidth]);
// Clamp contentHeight when map resizes to ensure legend stays within available space
(0, _react.useEffect)(function () {
if (!mapWidth || !mapHeight || !legendContentRef.current) return;
if (maxContentHeight && contentHeight > 0 && contentHeight > maxContentHeight) {
onChangeSettings({
contentHeight: maxContentHeight
});
}
}, [mapWidth, mapHeight, contentHeight, onChangeSettings, maxContentHeight, legendContentRef]);
return {
positionStyles: positionStyles,
updatePosition: updatePosition,
contentHeight: contentHeight,
maxContentHeight: maxContentHeight,
startResize: startResize,
resize: resize
};
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfcmVhY3QiLCJyZXF1aXJlIiwib3duS2V5cyIsImUiLCJyIiwidCIsIk9iamVjdCIsImtleXMiLCJnZXRPd25Qcm9wZXJ0eVN5bWJvbHMiLCJvIiwiZmlsdGVyIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwiZW51bWVyYWJsZSIsInB1c2giLCJhcHBseSIsIl9vYmplY3RTcHJlYWQiLCJhcmd1bWVudHMiLCJsZW5ndGgiLCJmb3JFYWNoIiwiX2RlZmluZVByb3BlcnR5MiIsImdldE93blByb3BlcnR5RGVzY3JpcHRvcnMiLCJkZWZpbmVQcm9wZXJ0aWVzIiwiZGVmaW5lUHJvcGVydHkiLCJNQVJHSU4iLCJsZWZ0IiwidG9wIiwicmlnaHQiLCJib3R0b20iLCJERUZBVUxUX1BPU0lUSU9OIiwieCIsInkiLCJhbmNob3JYIiwiYW5jaG9yWSIsIk1JTl9DT05URU5UX0hFSUdIVCIsIk1BUF9DT05UUk9MX0hFQURFUl9GVUxMX0hFSUdIVCIsInVzZUNhbGNMZWdlbmRQb3NpdGlvbiIsIl9yZWYiLCJsZWdlbmRDb250ZW50UmVmIiwiaXNTaWRlUGFuZWxTaG93biIsInNpZGVQYW5lbFdpZHRoIiwidXNlQ2FsbGJhY2siLCJfbGVnZW5kQ29udGVudFJlZiRjdXIiLCJyb290IiwiY3VycmVudCIsImNsb3Nlc3QiLCJsZWdlbmRDb250ZW50IiwiSFRNTEVsZW1lbnQiLCJsZWdlbmRSZWN0IiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwibWFwUm9vdEJvdW5kcyIsImxlZnRTaWRlYmFyT2Zmc2V0IiwibGVmdE9mZnNldCIsIk1hdGgiLCJtYXgiLCJyaWdodE9mZnNldCIsInRvcE9mZnNldCIsImJvdHRvbU9mZnNldCIsInVzZUxlZ2VuZFBvc2l0aW9uIiwiX3JlZjIiLCJfc2V0dGluZ3MkcG9zaXRpb24iLCJfc2V0dGluZ3MkY29udGVudEhlaWciLCJfdGhlbWUkc2lkZVBhbmVsIiwic2V0dGluZ3MiLCJvbkNoYW5nZVNldHRpbmdzIiwidGhlbWUiLCJtYXBIZWlnaHQiLCJtYXBXaWR0aCIsInBvcyIsInBvc2l0aW9uIiwiY29udGVudEhlaWdodCIsInBvc2l0aW9uU3R5bGVzIiwidXNlTWVtbyIsInN0YXJ0SGVpZ2h0UmVmIiwidXNlUmVmIiwic2lkZVBhbmVsIiwid2lkdGgiLCJtYXhDb250ZW50SGVpZ2h0IiwidW5kZWZpbmVkIiwiY2FsY1Bvc2l0aW9uIiwidXBkYXRlUG9zaXRpb24iLCJzdGFydFJlc2l6ZSIsIl9sZWdlbmRDb250ZW50UmVmJGN1cjIiLCJjb250ZW50IiwicXVlcnlTZWxlY3RvciIsIm9mZnNldEhlaWdodCIsInJlc2l6ZSIsImRlbHRhWSIsIl9sZWdlbmRDb250ZW50UmVmJGN1cjMiLCJyZW1haW5pbmdIZWlnaHQiLCJtYXhIZWlnaHQiLCJtaW4iLCJuZXh0SGVpZ2h0IiwicG9zUmVmIiwidXNlRWZmZWN0IiwiY3VycmVudFBvcyJdLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ob29rcy91c2UtbGVnZW5kLXBvc2l0aW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVRcbi8vIENvcHlyaWdodCBjb250cmlidXRvcnMgdG8gdGhlIGtlcGxlci5nbCBwcm9qZWN0XG5cbmltcG9ydCB7dXNlTWVtbywgdXNlUmVmLCB1c2VDYWxsYmFjaywgdXNlRWZmZWN0fSBmcm9tICdyZWFjdCc7XG5cbmltcG9ydCB7TWFwTGVnZW5kQ29udHJvbFNldHRpbmdzfSBmcm9tICdAa2VwbGVyLmdsL3R5cGVzJztcblxudHlwZSBQYXJhbXMgPSB7XG4gIGxlZ2VuZENvbnRlbnRSZWY6IFJlYWN0Lk11dGFibGVSZWZPYmplY3Q8SFRNTEVsZW1lbnQgfCBudWxsPjtcbiAgaXNTaWRlUGFuZWxTaG93bjogYm9vbGVhbjtcbiAgc2V0dGluZ3M/OiBNYXBMZWdlbmRDb250cm9sU2V0dGluZ3M7XG4gIG9uQ2hhbmdlU2V0dGluZ3M6IChzZXR0aW5nczogUGFydGlhbDxNYXBMZWdlbmRDb250cm9sU2V0dGluZ3M+KSA9PiB2b2lkO1xuICB0aGVtZTogUmVjb3JkPHN0cmluZywgYW55PjtcbiAgbWFwSGVpZ2h0PzogbnVtYmVyO1xuICBtYXBXaWR0aD86IG51bWJlcjtcbn07XG5cbnR5cGUgUmV0dXJuVHlwZSA9IHtcbiAgcG9zaXRpb25TdHlsZXM6IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xuICB1cGRhdGVQb3NpdGlvbjogKCkgPT4gdm9pZDtcbiAgY29udGVudEhlaWdodDogbnVtYmVyO1xuICBtYXhDb250ZW50SGVpZ2h0PzogbnVtYmVyO1xuICBzdGFydFJlc2l6ZTogKCkgPT4gdm9pZDtcbiAgcmVzaXplOiAoZGVsdGFZOiBudW1iZXIpID0+IHZvaWQ7XG59O1xuXG5jb25zdCBNQVJHSU4gPSB7XG4gIGxlZnQ6IDEwLFxuICB0b3A6IDEwLFxuICByaWdodDogMTAsXG4gIGJvdHRvbTogMzBcbn07XG5jb25zdCBERUZBVUxUX1BPU0lUSU9OOiBNYXBMZWdlbmRDb250cm9sU2V0dGluZ3NbJ3Bvc2l0aW9uJ10gPSB7XG4gIHg6IE1BUkdJTi5yaWdodCxcbiAgeTogTUFSR0lOLmJvdHRvbSxcbiAgYW5jaG9yWDogJ3JpZ2h0JyxcbiAgYW5jaG9yWTogJ2JvdHRvbSdcbn07XG5jb25zdCBNSU5fQ09OVEVOVF9IRUlHSFQgPSAxMDA7XG5jb25zdCBNQVBfQ09OVFJPTF9IRUFERVJfRlVMTF9IRUlHSFQgPSAzNDtcblxuZXhwb3J0IHR5cGUgVXNlQ2FsY0xlZ2VuZFBvc2l0aW9uUHJvcHMgPSB7XG4gIGxlZ2VuZENvbnRlbnRSZWY6IFJlYWN0Lk11dGFibGVSZWZPYmplY3Q8SFRNTEVsZW1lbnQgfCBudWxsPjtcbiAgaXNTaWRlUGFuZWxTaG93bjogYm9vbGVhbjtcbiAgc2lkZVBhbmVsV2lkdGg6IG51bWJlcjtcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiB1c2VDYWxjTGVnZW5kUG9zaXRpb24oe1xuICBsZWdlbmRDb250ZW50UmVmLFxuICBpc1NpZGVQYW5lbFNob3duLFxuICBzaWRlUGFuZWxXaWR0aFxufTogVXNlQ2FsY0xlZ2VuZFBvc2l0aW9uUHJvcHMpIHtcbiAgcmV0dXJuIHVzZUNhbGxiYWNrKCgpOiBNYXBMZWdlbmRDb250cm9sU2V0dGluZ3NbJ3Bvc2l0aW9uJ10gPT4ge1xuICAgIGNvbnN0IHJvb3QgPSBsZWdlbmRDb250ZW50UmVmLmN1cnJlbnQ/LmNsb3Nlc3QoJy5rZXBsZXItZ2wnKTtcbiAgICBjb25zdCBsZWdlbmRDb250ZW50ID0gbGVnZW5kQ29udGVudFJlZi5jdXJyZW50O1xuICAgIGlmICghbGVnZW5kQ29udGVudCB8fCAhKHJvb3QgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCkpIHtcbiAgICAgIHJldHVybiBERUZBVUxUX1BPU0lUSU9OO1xuICAgIH1cbiAgICBjb25zdCBsZWdlbmRSZWN0ID0gbGVnZW5kQ29udGVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICBjb25zdCBtYXBSb290Qm91bmRzID0gcm9vdC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICBjb25zdCBsZWZ0U2lkZWJhck9mZnNldCA9IGlzU2lkZVBhbmVsU2hvd24gPyBzaWRlUGFuZWxXaWR0aCA6IDA7XG5cbiAgICBjb25zdCBsZWZ0T2Zmc2V0ID0gTWF0aC5tYXgoXG4gICAgICBNQVJHSU4ubGVmdCxcbiAgICAgIGxlZ2VuZFJlY3QubGVmdCAtIG1hcFJvb3RCb3VuZHMubGVmdCAtIGxlZnRTaWRlYmFyT2Zmc2V0XG4gICAgKTtcbiAgICBjb25zdCByaWdodE9mZnNldCA9IE1hdGgubWF4KE1BUkdJTi5yaWdodCwgbWFwUm9vdEJvdW5kcy5yaWdodCAtIGxlZ2VuZFJlY3QucmlnaHQpO1xuXG4gICAgY29uc3QgdG9wT2Zmc2V0ID0gTWF0aC5tYXgoTUFSR0lOLnRvcCwgbGVnZW5kUmVjdC50b3AgLSBtYXBSb290Qm91bmRzLnRvcCk7XG4gICAgY29uc3QgYm90dG9tT2Zmc2V0ID0gTWF0aC5tYXgoTUFSR0lOLmJvdHRvbSwgbWFwUm9vdEJvdW5kcy5ib3R0b20gLSBsZWdlbmRSZWN0LmJvdHRvbSk7XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4uKGxlZnRPZmZzZXQgPCByaWdodE9mZnNldFxuICAgICAgICA/IHt4OiBsZWZ0T2Zmc2V0ICsgbGVmdFNpZGViYXJPZmZzZXQsIGFuY2hvclg6ICdsZWZ0J31cbiAgICAgICAgOiB7eDogcmlnaHRPZmZzZXQsIGFuY2hvclg6ICdyaWdodCd9KSxcbiAgICAgIC4uLih0b3BPZmZzZXQgPCBib3R0b21PZmZzZXRcbiAgICAgICAgPyB7eTogdG9wT2Zmc2V0LCBhbmNob3JZOiAndG9wJ31cbiAgICAgICAgOiB7eTogYm90dG9tT2Zmc2V0LCBhbmNob3JZOiAnYm90dG9tJ30pXG4gICAgfTtcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVhY3QtaG9va3MvZXhoYXVzdGl2ZS1kZXBzXG4gIH0sIFtpc1NpZGVQYW5lbFNob3duLCBzaWRlUGFuZWxXaWR0aF0pO1xufVxuXG4vKipcbiAqIFJldHVybnMgYSBmdW5jdGlvbiB0aGF0IGNhbGN1bGF0ZXMgdGhlIGFuY2hvcmVkIHBvc2l0aW9uIG9mIHRoZSBtYXAgbGVnZW5kXG4gKiB0aGF0IGlzIGJlaW5nIGRyYWdnZWQuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVzZUxlZ2VuZFBvc2l0aW9uKHtcbiAgbGVnZW5kQ29udGVudFJlZixcbiAgaXNTaWRlUGFuZWxTaG93bixcbiAgc2V0dGluZ3MsXG4gIG9uQ2hhbmdlU2V0dGluZ3MsXG4gIHRoZW1lLFxuICBtYXBIZWlnaHQsXG4gIG1hcFdpZHRoXG59OiBQYXJhbXMpOiBSZXR1cm5UeXBlIHtcbiAgY29uc3QgcG9zID0gc2V0dGluZ3M/LnBvc2l0aW9uID8/IERFRkFVTFRfUE9TSVRJT047XG4gIGNvbnN0IGNvbnRlbnRIZWlnaHQgPSBzZXR0aW5ncz8uY29udGVudEhlaWdodCA/PyAtMTtcbiAgY29uc3QgcG9zaXRpb25TdHlsZXMgPSB1c2VNZW1vKCgpID0+ICh7W3Bvcy5hbmNob3JYXTogcG9zLngsIFtwb3MuYW5jaG9yWV06IHBvcy55fSksIFtwb3NdKTtcbiAgY29uc3Qgc3RhcnRIZWlnaHRSZWYgPSB1c2VSZWYoMCk7XG4gIGNvbnN0IHNpZGVQYW5lbFdpZHRoID0gdGhlbWUuc2lkZVBhbmVsPy53aWR0aCB8fCAwO1xuXG4gIC8vIENhbGN1bGF0ZSBkeW5hbWljIG1heCBjb250ZW50IGhlaWdodCBiYXNlZCBvbiBtYXAgcm9vdCBkaW1lbnNpb25zXG4gIGNvbnN0IG1heENvbnRlbnRIZWlnaHQgPSB1c2VNZW1vKCgpID0+IHtcbiAgICBpZiAoIW1hcEhlaWdodCkgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAvLyBBdmFpbGFibGUgaGVpZ2h0IG1pbnVzIG1hcmdpbnMgYW5kIGhlYWRlclxuICAgIHJldHVybiBtYXBIZWlnaHQgLSBNQVJHSU4udG9wIC0gTUFSR0lOLmJvdHRvbSAtIE1BUF9DT05UUk9MX0hFQURFUl9GVUxMX0hFSUdIVDtcbiAgfSwgW21hcEhlaWdodF0pO1xuXG4gIGNvbnN0IGNhbGNQb3NpdGlvbiA9IHVzZUNhbGNMZWdlbmRQb3NpdGlvbih7XG4gICAgbGVnZW5kQ29udGVudFJlZixcbiAgICBpc1NpZGVQYW5lbFNob3duLFxuICAgIHNpZGVQYW5lbFdpZHRoXG4gIH0pO1xuICBjb25zdCB1cGRhdGVQb3NpdGlvbiA9IHVzZUNhbGxiYWNrKFxuICAgICgpID0+IG9uQ2hhbmdlU2V0dGluZ3Moe3Bvc2l0aW9uOiBjYWxjUG9zaXRpb24oKX0pLFxuICAgIFtjYWxjUG9zaXRpb24sIG9uQ2hhbmdlU2V0dGluZ3NdXG4gICk7XG5cbiAgY29uc3Qgc3RhcnRSZXNpemUgPSB1c2VDYWxsYmFjaygoKSA9PiB7XG4gICAgY29uc3QgY29udGVudCA9IGxlZ2VuZENvbnRlbnRSZWYuY3VycmVudD8ucXVlcnlTZWxlY3RvcignLm1hcC1jb250cm9sX19wYW5lbC1jb250ZW50Jyk7XG4gICAgaWYgKGNvbnRlbnQgaW5zdGFuY2VvZiBIVE1MRWxlbWVudCkge1xuICAgICAgc3RhcnRIZWlnaHRSZWYuY3VycmVudCA9IGNvbnRlbnQub2Zmc2V0SGVpZ2h0O1xuICAgIH1cbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVhY3QtaG9va3MvZXhoYXVzdGl2ZS1kZXBzXG4gIH0sIFtdKTtcbiAgY29uc3QgcmVzaXplID0gdXNlQ2FsbGJhY2soXG4gICAgZGVsdGFZID0+IHtcbiAgICAgIGNvbnN0IHJvb3QgPSBsZWdlbmRDb250ZW50UmVmLmN1cnJlbnQ/LmNsb3Nlc3QoJy5rZXBsZXItZ2wnKTtcbiAgICAgIGNvbnN0IGxlZ2VuZENvbnRlbnQgPSBsZWdlbmRDb250ZW50UmVmLmN1cnJlbnQ7XG4gICAgICBpZiAocm9vdCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50ICYmIGxlZ2VuZENvbnRlbnQpIHtcbiAgICAgICAgY29uc3QgbWFwUm9vdEJvdW5kcyA9IHJvb3QuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIGNvbnN0IGxlZ2VuZFJlY3QgPSBsZWdlbmRDb250ZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBjb25zdCByZW1haW5pbmdIZWlnaHQgPVxuICAgICAgICAgIG1hcFJvb3RCb3VuZHMuYm90dG9tIC0gKGxlZ2VuZFJlY3QudG9wICsgTUFQX0NPTlRST0xfSEVBREVSX0ZVTExfSEVJR0hUICsgTUFSR0lOLmJvdHRvbSk7XG4gICAgICAgIC8vIFVzZSBtYXhDb250ZW50SGVpZ2h0IGlmIGF2YWlsYWJsZSwgb3RoZXJ3aXNlIGZhbGwgYmFjayB0byB2aWV3cG9ydC1iYXNlZCBjYWxjdWxhdGlvblxuICAgICAgICBjb25zdCBtYXhIZWlnaHQgPSBtYXhDb250ZW50SGVpZ2h0XG4gICAgICAgICAgPyBNYXRoLm1pbihtYXhDb250ZW50SGVpZ2h0LCByZW1haW5pbmdIZWlnaHQpXG4gICAgICAgICAgOiByZW1haW5pbmdIZWlnaHQ7XG4gICAgICAgIGNvbnN0IG5leHRIZWlnaHQgPSBNYXRoLm1pbihcbiAgICAgICAgICBtYXhIZWlnaHQsXG4gICAgICAgICAgTWF0aC5tYXgoTUlOX0NPTlRFTlRfSEVJR0hULCBzdGFydEhlaWdodFJlZi5jdXJyZW50ICsgZGVsdGFZKVxuICAgICAgICApO1xuICAgICAgICBvbkNoYW5nZVNldHRpbmdzKHtjb250ZW50SGVpZ2h0OiBuZXh0SGVpZ2h0fSk7XG4gICAgICAgIGlmIChjb250ZW50SGVpZ2h0ID4gMCAmJiBwb3MuYW5jaG9yWSA9PT0gJ2JvdHRvbScpIHtcbiAgICAgICAgICBvbkNoYW5nZVNldHRpbmdzKHtwb3NpdGlvbjogey4uLnBvcywgeTogcG9zLnkgLSAobmV4dEhlaWdodCAtIGNvbnRlbnRIZWlnaHQpfX0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgcmVhY3QtaG9va3MvZXhoYXVzdGl2ZS1kZXBzXG4gICAgW2NvbnRlbnRIZWlnaHQsIHBvcywgb25DaGFuZ2VTZXR0aW5ncywgbWF4Q29udGVudEhlaWdodF1cbiAgKTtcblxuICAvLyBTaGlmdCB3aGVuIHNpZGUgcGFuZWwgaXMgc2hvd24vaGlkZGVuXG4gIGNvbnN0IHBvc1JlZiA9IHVzZVJlZihwb3MpO1xuICBwb3NSZWYuY3VycmVudCA9IHBvcztcbiAgdXNlRWZmZWN0KCgpID0+IHtcbiAgICBjb25zdCBjdXJyZW50UG9zID0gcG9zUmVmLmN1cnJlbnQ7XG4gICAgaWYgKGN1cnJlbnRQb3MuYW5jaG9yWCA9PT0gJ2xlZnQnKSB7XG4gICAgICBpZiAoaXNTaWRlUGFuZWxTaG93bikge1xuICAgICAgICBpZiAoY3VycmVudFBvcy54IDw9IHNpZGVQYW5lbFdpZHRoICsgTUFSR0lOLmxlZnQpIHtcbiAgICAgICAgICBvbkNoYW5nZVNldHRpbmdzKHtwb3NpdGlvbjogey4uLmN1cnJlbnRQb3MsIHg6IHNpZGVQYW5lbFdpZHRoICsgTUFSR0lOLmxlZnR9fSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG9uQ2hhbmdlU2V0dGluZ3Moe1xuICAgICAgICAgIHBvc2l0aW9uOiB7Li4uY3VycmVudFBvcywgeDogTWF0aC5tYXgoTUFSR0lOLmxlZnQsIGN1cnJlbnRQb3MueCAtIHNpZGVQYW5lbFdpZHRoKX1cbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9LCBbaXNTaWRlUGFuZWxTaG93biwgb25DaGFuZ2VTZXR0aW5ncywgc2lkZVBhbmVsV2lkdGhdKTtcblxuICAvLyBDbGFtcCBjb250ZW50SGVpZ2h0IHdoZW4gbWFwIHJlc2l6ZXMgdG8gZW5zdXJlIGxlZ2VuZCBzdGF5cyB3aXRoaW4gYXZhaWxhYmxlIHNwYWNlXG4gIHVzZUVmZmVjdCgoKSA9PiB7XG4gICAgaWYgKCFtYXBXaWR0aCB8fCAhbWFwSGVpZ2h0IHx8ICFsZWdlbmRDb250ZW50UmVmLmN1cnJlbnQpIHJldHVybjtcbiAgICBpZiAobWF4Q29udGVudEhlaWdodCAmJiBjb250ZW50SGVpZ2h0ID4gMCAmJiBjb250ZW50SGVpZ2h0ID4gbWF4Q29udGVudEhlaWdodCkge1xuICAgICAgb25DaGFuZ2VTZXR0aW5ncyh7Y29udGVudEhlaWdodDogbWF4Q29udGVudEhlaWdodH0pO1xuICAgIH1cbiAgfSwgW21hcFdpZHRoLCBtYXBIZWlnaHQsIGNvbnRlbnRIZWlnaHQsIG9uQ2hhbmdlU2V0dGluZ3MsIG1heENvbnRlbnRIZWlnaHQsIGxlZ2VuZENvbnRlbnRSZWZdKTtcblxuICByZXR1cm4ge3Bvc2l0aW9uU3R5bGVzLCB1cGRhdGVQb3NpdGlvbiwgY29udGVudEhlaWdodCwgbWF4Q29udGVudEhlaWdodCwgc3RhcnRSZXNpemUsIHJlc2l6ZX07XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUdBLElBQUFBLE1BQUEsR0FBQUMsT0FBQTtBQUE4RCxTQUFBQyxRQUFBQyxDQUFBLEVBQUFDLENBQUEsUUFBQUMsQ0FBQSxHQUFBQyxNQUFBLENBQUFDLElBQUEsQ0FBQUosQ0FBQSxPQUFBRyxNQUFBLENBQUFFLHFCQUFBLFFBQUFDLENBQUEsR0FBQUgsTUFBQSxDQUFBRSxxQkFBQSxDQUFBTCxDQUFBLEdBQUFDLENBQUEsS0FB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