UNPKG

kepler.gl

Version:

kepler.gl is a webgl based application to visualize large scale location data in the browser

246 lines (236 loc) 31.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getCursor = getCursor; exports.getTooltip = getTooltip; exports.isDrawingActive = isDrawingActive; exports.onClick = onClick; exports.onHover = onHover; var _constants = require("@kepler.gl/constants"); // SPDX-License-Identifier: MIT // Copyright contributors to the kepler.gl project /** * Returns true if drawing is active. * @param editorMenuActive Indicates whether the editor side menu is active. * @param mode Current editing mode. * @returs Returns true if drawing is active. */ function isDrawingActive(editorMenuActive, mode) { return editorMenuActive && (mode === _constants.EDITOR_MODES.DRAW_POLYGON || mode === _constants.EDITOR_MODES.DRAW_RECTANGLE); } /** * Handles click event for Editor layer. * @param info Information about clicked object. * @param event Event object. * @param params * @param params.editorMenuActive * @param params.editor * @param params.onLayerClick * @param params.setSelectedFeature * @param params.mapIndex * @returns Returns true is the click is handled. */ // eslint-disable-next-line complexity function onClick(info, event, _ref) { var _info$layer; var editorMenuActive = _ref.editorMenuActive, editor = _ref.editor, setSelectedFeature = _ref.setSelectedFeature, onLayerClick = _ref.onLayerClick, _ref$mapIndex = _ref.mapIndex, mapIndex = _ref$mapIndex === void 0 ? 0 : _ref$mapIndex; var drawingActive = isDrawingActive(editorMenuActive, editor.mode); if ((info === null || info === void 0 || (_info$layer = info.layer) === null || _info$layer === void 0 ? void 0 : _info$layer.id) === _constants.EDITOR_LAYER_ID && info !== null && info !== void 0 && info.object) { var _info$object$geometry; var objectType = (_info$object$geometry = info.object.geometry) === null || _info$object$geometry === void 0 ? void 0 : _info$object$geometry.type; if (drawingActive) { if (editor.selectedFeature) { setSelectedFeature(null); } } else if (objectType !== null && objectType !== void 0 && objectType.endsWith('Polygon') || objectType !== null && objectType !== void 0 && objectType.endsWith('Point')) { var _event$srcEvent; var clickContext; if (event.rightButton && Array.isArray((_event$srcEvent = event.srcEvent) === null || _event$srcEvent === void 0 ? void 0 : _event$srcEvent.point)) { var point = event.srcEvent.point; clickContext = { mapIndex: mapIndex, rightClick: true, position: { x: point[0], y: point[1] } }; } if (objectType !== null && objectType !== void 0 && objectType.endsWith('Polygon')) { setSelectedFeature(info.object, clickContext); } else { // don't select points setSelectedFeature(editor.selectedFeature, clickContext); } } // hide tooltips from regular data layers onLayerClick(null, event); } else if (drawingActive) { // prevent interaction with other layers onLayerClick(null, event); } else { if (editor.selectedFeature) { if (event.rightButton) { return true; } // click outside removes selection setSelectedFeature(null); } return false; } return true; } /** * Handles hover event for Editor layer. * @param info Information about hovered object. * @param params * @param params.editorMenuActive * @param params.editor * @param params.hoverInfo * @returns Returns true is hover is handled. */ function onHover(info, _ref2) { var _info$layer2, _hoverInfo$layer; var hoverInfo = _ref2.hoverInfo, editor = _ref2.editor, editorMenuActive = _ref2.editorMenuActive; if (isDrawingActive(editorMenuActive, editor.mode)) { return true; } return (info === null || info === void 0 || (_info$layer2 = info.layer) === null || _info$layer2 === void 0 ? void 0 : _info$layer2.id) === _constants.EDITOR_LAYER_ID && (hoverInfo === null || hoverInfo === void 0 || (_hoverInfo$layer = hoverInfo.layer) === null || _hoverInfo$layer === void 0 ? void 0 : _hoverInfo$layer.id) === _constants.EDITOR_LAYER_ID; } /** * For small tooltips with short messages, e.g. "Drag to move the point", * use the values below to decide when to position a tooltip to the left * of the cursor or above the cursor, depending on proximity to the edge of * the viewport to prevent the tooltip from being cut off. */ var MIN_DISTANCE_TO_LEFT_EDGE = 200; var MIN_DISTANCE_TO_BOTTOM_EDGE = 100; /** * Returns tooltip based on interactions with Editor layer. * @param info Information about hovered object. * @param params * @param params.editorMenuActive * @param params.editor * @param params.theme * @raturns Returns a tooltip object compatible with Deck.getTooltip() */ // eslint-disable-next-line complexity function getTooltip( // TODO PickingInfo type in deck typings doesn't include viewport and pixel info, _ref3) { var _viewport$width, _pixel$, _viewport$height, _pixel$2, _editor$selectionCont; var editor = _ref3.editor, theme = _ref3.theme, editorMenuActive = _ref3.editorMenuActive; var object = info.object, layer = info.layer, _info$viewport = info.viewport, viewport = _info$viewport === void 0 ? {} : _info$viewport, _info$pixel = info.pixel, pixel = _info$pixel === void 0 ? [] : _info$pixel; var closeToLeftEdge = ((_viewport$width = viewport === null || viewport === void 0 ? void 0 : viewport.width) !== null && _viewport$width !== void 0 ? _viewport$width : 0) - ((_pixel$ = pixel === null || pixel === void 0 ? void 0 : pixel[0]) !== null && _pixel$ !== void 0 ? _pixel$ : 0) < MIN_DISTANCE_TO_LEFT_EDGE; var closeToBottomEdge = ((_viewport$height = viewport === null || viewport === void 0 ? void 0 : viewport.height) !== null && _viewport$height !== void 0 ? _viewport$height : 0) - ((_pixel$2 = pixel === null || pixel === void 0 ? void 0 : pixel[1]) !== null && _pixel$2 !== void 0 ? _pixel$2 : 0) < MIN_DISTANCE_TO_BOTTOM_EDGE; // don't show the tooltip when the menu is visible if ((_editor$selectionCont = editor.selectionContext) !== null && _editor$selectionCont !== void 0 && _editor$selectionCont.rightClick) { return null; } if (isDrawingActive(editorMenuActive, editor.mode)) { var _layer$state; // TODO save interaction state in editor object if (layer !== null && layer !== void 0 && (_layer$state = layer.state) !== null && _layer$state !== void 0 && (_layer$state = _layer$state.mode) !== null && _layer$state !== void 0 && (_layer$state = _layer$state._clickSequence) !== null && _layer$state !== void 0 && _layer$state.length) { return null; } return getTooltipObject('Click to start new feature', theme, { leftOfCursor: closeToLeftEdge, aboveCursor: closeToBottomEdge }); } if ((layer === null || layer === void 0 ? void 0 : layer.id) === _constants.EDITOR_LAYER_ID) { var _object$properties, _object$geometry, _object$properties2; var selectedFeature = editor.selectedFeature; if (selectedFeature) { if (!object || object.id && object.id === selectedFeature.id) { return getTooltipObject('Right click to view options\nDrag to move the feature', theme, { leftOfCursor: closeToLeftEdge, aboveCursor: closeToBottomEdge }); } } if ((object === null || object === void 0 || (_object$properties = object.properties) === null || _object$properties === void 0 ? void 0 : _object$properties.editHandleType) === 'intermediate') { return getTooltipObject('Click to insert a point', theme, { leftOfCursor: closeToLeftEdge, aboveCursor: closeToBottomEdge }); } if ((object === null || object === void 0 || (_object$geometry = object.geometry) === null || _object$geometry === void 0 ? void 0 : _object$geometry.type) === 'Point' || (object === null || object === void 0 || (_object$properties2 = object.properties) === null || _object$properties2 === void 0 ? void 0 : _object$properties2.guideType) === 'tentative') { return getTooltipObject('Drag to move the point', theme, { leftOfCursor: closeToLeftEdge, aboveCursor: closeToBottomEdge }); } return getTooltipObject('Click to select the feature\nRight click to view options', theme, { leftOfCursor: closeToLeftEdge, aboveCursor: closeToBottomEdge }); } return null; } /** * Returns cursor type based on interactions with Editor layer. * @param params * @param params.editorMenuActive * @param params.editor * @param params.hoverInfo * @returns Returns cursor type. */ function getCursor(_ref4) { var _hoverInfo$layer2; var editorMenuActive = _ref4.editorMenuActive, editor = _ref4.editor, hoverInfo = _ref4.hoverInfo; if (isDrawingActive(editorMenuActive, editor.mode)) { return 'crosshair'; } if ((hoverInfo === null || hoverInfo === void 0 || (_hoverInfo$layer2 = hoverInfo.layer) === null || _hoverInfo$layer2 === void 0 ? void 0 : _hoverInfo$layer2.id) === _constants.EDITOR_LAYER_ID && editor.selectedFeature) { return 'move'; } return null; } /** * Returns a tooltip object that can be used as a Deck tooltip. * Positioning can be modified if the cursor is close to the bottom or left edge of the viewport. * @param text Text to show. * @param theme Current theme. * @param position.leftOfCursor Tooltip should display to the left of the cursor. * @param position.aboveCursor Tooltip should display above cursor. */ function getTooltipObject(text, theme, position) { var leftOfCursor = position.leftOfCursor, aboveCursor = position.aboveCursor; var marginTop = aboveCursor ? '-70px' : '15px'; var marginLeft = leftOfCursor ? '-200px' : '15px'; return { text: text, style: { 'margin-top': marginTop, 'margin-left': marginLeft, 'font-family': theme.fontFamily, 'font-size': theme.tooltipFontSize, 'font-weight': 400, padding: '7px 18px', 'box-shadow': theme.tooltipBoxShadow, 'background-color': theme.tooltipBg, color: theme.tooltipColor, 'border-radius': theme.primaryBtnRadius } }; } //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfY29uc3RhbnRzIiwicmVxdWlyZSIsImlzRHJhd2luZ0FjdGl2ZSIsImVkaXRvck1lbnVBY3RpdmUiLCJtb2RlIiwiRURJVE9SX01PREVTIiwiRFJBV19QT0xZR09OIiwiRFJBV19SRUNUQU5HTEUiLCJvbkNsaWNrIiwiaW5mbyIsImV2ZW50IiwiX3JlZiIsIl9pbmZvJGxheWVyIiwiZWRpdG9yIiwic2V0U2VsZWN0ZWRGZWF0dXJlIiwib25MYXllckNsaWNrIiwiX3JlZiRtYXBJbmRleCIsIm1hcEluZGV4IiwiZHJhd2luZ0FjdGl2ZSIsImxheWVyIiwiaWQiLCJFRElUT1JfTEFZRVJfSUQiLCJvYmplY3QiLCJfaW5mbyRvYmplY3QkZ2VvbWV0cnkiLCJvYmplY3RUeXBlIiwiZ2VvbWV0cnkiLCJ0eXBlIiwic2VsZWN0ZWRGZWF0dXJlIiwiZW5kc1dpdGgiLCJfZXZlbnQkc3JjRXZlbnQiLCJjbGlja0NvbnRleHQiLCJyaWdodEJ1dHRvbiIsIkFycmF5IiwiaXNBcnJheSIsInNyY0V2ZW50IiwicG9pbnQiLCJyaWdodENsaWNrIiwicG9zaXRpb24iLCJ4IiwieSIsIm9uSG92ZXIiLCJfcmVmMiIsIl9pbmZvJGxheWVyMiIsIl9ob3ZlckluZm8kbGF5ZXIiLCJob3ZlckluZm8iLCJNSU5fRElTVEFOQ0VfVE9fTEVGVF9FREdFIiwiTUlOX0RJU1RBTkNFX1RPX0JPVFRPTV9FREdFIiwiZ2V0VG9vbHRpcCIsIl9yZWYzIiwiX3ZpZXdwb3J0JHdpZHRoIiwiX3BpeGVsJCIsIl92aWV3cG9ydCRoZWlnaHQiLCJfcGl4ZWwkMiIsIl9lZGl0b3Ikc2VsZWN0aW9uQ29udCIsInRoZW1lIiwiX2luZm8kdmlld3BvcnQiLCJ2aWV3cG9ydCIsIl9pbmZvJHBpeGVsIiwicGl4ZWwiLCJjbG9zZVRvTGVmdEVkZ2UiLCJ3aWR0aCIsImNsb3NlVG9Cb3R0b21FZGdlIiwiaGVpZ2h0Iiwic2VsZWN0aW9uQ29udGV4dCIsIl9sYXllciRzdGF0ZSIsInN0YXRlIiwiX2NsaWNrU2VxdWVuY2UiLCJsZW5ndGgiLCJnZXRUb29sdGlwT2JqZWN0IiwibGVmdE9mQ3Vyc29yIiwiYWJvdmVDdXJzb3IiLCJfb2JqZWN0JHByb3BlcnRpZXMiLCJfb2JqZWN0JGdlb21ldHJ5IiwiX29iamVjdCRwcm9wZXJ0aWVzMiIsInByb3BlcnRpZXMiLCJlZGl0SGFuZGxlVHlwZSIsImd1aWRlVHlwZSIsImdldEN1cnNvciIsIl9yZWY0IiwiX2hvdmVySW5mbyRsYXllcjIiLCJ0ZXh0IiwibWFyZ2luVG9wIiwibWFyZ2luTGVmdCIsInN0eWxlIiwiZm9udEZhbWlseSIsInRvb2x0aXBGb250U2l6ZSIsInBhZGRpbmciLCJ0b29sdGlwQm94U2hhZG93IiwidG9vbHRpcEJnIiwiY29sb3IiLCJ0b29sdGlwQ29sb3IiLCJwcmltYXJ5QnRuUmFkaXVzIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL2VkaXRvci1sYXllci9lZGl0b3ItbGF5ZXItdXRpbHMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IE1JVFxuLy8gQ29weXJpZ2h0IGNvbnRyaWJ1dG9ycyB0byB0aGUga2VwbGVyLmdsIHByb2plY3RcblxuaW1wb3J0IHtFZGl0b3IsIEZlYXR1cmUsIEZlYXR1cmVTZWxlY3Rpb25Db250ZXh0LCBQaWNrSW5mb30gZnJvbSAnQGtlcGxlci5nbC90eXBlcyc7XG5pbXBvcnQge0VESVRPUl9MQVlFUl9JRCwgRURJVE9SX01PREVTfSBmcm9tICdAa2VwbGVyLmdsL2NvbnN0YW50cyc7XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIGlmIGRyYXdpbmcgaXMgYWN0aXZlLlxuICogQHBhcmFtIGVkaXRvck1lbnVBY3RpdmUgSW5kaWNhdGVzIHdoZXRoZXIgdGhlIGVkaXRvciBzaWRlIG1lbnUgaXMgYWN0aXZlLlxuICogQHBhcmFtIG1vZGUgQ3VycmVudCBlZGl0aW5nIG1vZGUuXG4gKiBAcmV0dXJzIFJldHVybnMgdHJ1ZSBpZiBkcmF3aW5nIGlzIGFjdGl2ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzRHJhd2luZ0FjdGl2ZShlZGl0b3JNZW51QWN0aXZlOiBib29sZWFuLCBtb2RlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIChcbiAgICBlZGl0b3JNZW51QWN0aXZlICYmIChtb2RlID09PSBFRElUT1JfTU9ERVMuRFJBV19QT0xZR09OIHx8IG1vZGUgPT09IEVESVRPUl9NT0RFUy5EUkFXX1JFQ1RBTkdMRSlcbiAgKTtcbn1cblxuLyoqXG4gKiBIYW5kbGVzIGNsaWNrIGV2ZW50IGZvciBFZGl0b3IgbGF5ZXIuXG4gKiBAcGFyYW0gaW5mbyBJbmZvcm1hdGlvbiBhYm91dCBjbGlja2VkIG9iamVjdC5cbiAqIEBwYXJhbSBldmVudCBFdmVudCBvYmplY3QuXG4gKiBAcGFyYW0gcGFyYW1zXG4gKiBAcGFyYW0gcGFyYW1zLmVkaXRvck1lbnVBY3RpdmVcbiAqIEBwYXJhbSBwYXJhbXMuZWRpdG9yXG4gKiBAcGFyYW0gcGFyYW1zLm9uTGF5ZXJDbGlja1xuICogQHBhcmFtIHBhcmFtcy5zZXRTZWxlY3RlZEZlYXR1cmVcbiAqIEBwYXJhbSBwYXJhbXMubWFwSW5kZXhcbiAqIEByZXR1cm5zIFJldHVybnMgdHJ1ZSBpcyB0aGUgY2xpY2sgaXMgaGFuZGxlZC5cbiAqL1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbmV4cG9ydCBmdW5jdGlvbiBvbkNsaWNrKFxuICBpbmZvOiBQaWNrSW5mbyxcbiAgZXZlbnQ6IGFueSxcbiAge1xuICAgIGVkaXRvck1lbnVBY3RpdmUsXG4gICAgZWRpdG9yLFxuICAgIHNldFNlbGVjdGVkRmVhdHVyZSxcbiAgICBvbkxheWVyQ2xpY2ssXG4gICAgbWFwSW5kZXggPSAwXG4gIH06IHtcbiAgICBlZGl0b3JNZW51QWN0aXZlOiBib29sZWFuO1xuICAgIGVkaXRvcjogRWRpdG9yO1xuICAgIG9uTGF5ZXJDbGljazogKGRhdGEsIGNsaWNrRXZlbnQpID0+IGFueTtcbiAgICBzZXRTZWxlY3RlZEZlYXR1cmU6IChcbiAgICAgIGZlYXR1cmU6IEZlYXR1cmUgfCBudWxsLFxuICAgICAgc2VsZWN0aW9uQ29udGV4dD86IEZlYXR1cmVTZWxlY3Rpb25Db250ZXh0XG4gICAgKSA9PiBhbnk7XG4gICAgbWFwSW5kZXg/OiBudW1iZXI7XG4gIH1cbik6IGJvb2xlYW4ge1xuICBjb25zdCBkcmF3aW5nQWN0aXZlID0gaXNEcmF3aW5nQWN0aXZlKGVkaXRvck1lbnVBY3RpdmUsIGVkaXRvci5tb2RlKTtcblxuICBpZiAoaW5mbz8ubGF5ZXI/LmlkID09PSBFRElUT1JfTEFZRVJfSUQgJiYgaW5mbz8ub2JqZWN0KSB7XG4gICAgY29uc3Qgb2JqZWN0VHlwZSA9IGluZm8ub2JqZWN0Lmdlb21ldHJ5Py50eXBlO1xuXG4gICAgaWYgKGRyYXdpbmdBY3RpdmUpIHtcbiAgICAgIGlmIChlZGl0b3Iuc2VsZWN0ZWRGZWF0dXJlKSB7XG4gICAgICAgIHNldFNlbGVjdGVkRmVhdHVyZShudWxsKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKG9iamVjdFR5cGU/LmVuZHNXaXRoKCdQb2x5Z29uJykgfHwgb2JqZWN0VHlwZT8uZW5kc1dpdGgoJ1BvaW50JykpIHtcbiAgICAgIGxldCBjbGlja0NvbnRleHQ7XG4gICAgICBpZiAoZXZlbnQucmlnaHRCdXR0b24gJiYgQXJyYXkuaXNBcnJheShldmVudC5zcmNFdmVudD8ucG9pbnQpKSB7XG4gICAgICAgIGNvbnN0IHtwb2ludH0gPSBldmVudC5zcmNFdmVudDtcbiAgICAgICAgY2xpY2tDb250ZXh0ID0ge1xuICAgICAgICAgIG1hcEluZGV4LFxuICAgICAgICAgIHJpZ2h0Q2xpY2s6IHRydWUsXG4gICAgICAgICAgcG9zaXRpb246IHtcbiAgICAgICAgICAgIHg6IHBvaW50WzBdLFxuICAgICAgICAgICAgeTogcG9pbnRbMV1cbiAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICB9XG5cbiAgICAgIGlmIChvYmplY3RUeXBlPy5lbmRzV2l0aCgnUG9seWdvbicpKSB7XG4gICAgICAgIHNldFNlbGVjdGVkRmVhdHVyZShpbmZvLm9iamVjdCwgY2xpY2tDb250ZXh0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIGRvbid0IHNlbGVjdCBwb2ludHNcbiAgICAgICAgc2V0U2VsZWN0ZWRGZWF0dXJlKGVkaXRvci5zZWxlY3RlZEZlYXR1cmUsIGNsaWNrQ29udGV4dCk7XG4gICAgICB9XG4gICAgfVxuICAgIC8vIGhpZGUgdG9vbHRpcHMgZnJvbSByZWd1bGFyIGRhdGEgbGF5ZXJzXG4gICAgb25MYXllckNsaWNrKG51bGwsIGV2ZW50KTtcbiAgfSBlbHNlIGlmIChkcmF3aW5nQWN0aXZlKSB7XG4gICAgLy8gcHJldmVudCBpbnRlcmFjdGlvbiB3aXRoIG90aGVyIGxheWVyc1xuICAgIG9uTGF5ZXJDbGljayhudWxsLCBldmVudCk7XG4gIH0gZWxzZSB7XG4gICAgaWYgKGVkaXRvci5zZWxlY3RlZEZlYXR1cmUpIHtcbiAgICAgIGlmIChldmVudC5yaWdodEJ1dHRvbikge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cblxuICAgICAgLy8gY2xpY2sgb3V0c2lkZSByZW1vdmVzIHNlbGVjdGlvblxuICAgICAgc2V0U2VsZWN0ZWRGZWF0dXJlKG51bGwpO1xuICAgIH1cblxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICByZXR1cm4gdHJ1ZTtcbn1cblxuLyoqXG4gKiBIYW5kbGVzIGhvdmVyIGV2ZW50IGZvciBFZGl0b3IgbGF5ZXIuXG4gKiBAcGFyYW0gaW5mbyBJbmZvcm1hdGlvbiBhYm91dCBob3ZlcmVkIG9iamVjdC5cbiAqIEBwYXJhbSBwYXJhbXNcbiAqIEBwYXJhbSBwYXJhbXMuZWRpdG9yTWVudUFjdGl2ZVxuICogQHBhcmFtIHBhcmFtcy5lZGl0b3JcbiAqIEBwYXJhbSBwYXJhbXMuaG92ZXJJbmZvXG4gKiBAcmV0dXJucyBSZXR1cm5zIHRydWUgaXMgaG92ZXIgaXMgaGFuZGxlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIG9uSG92ZXIoXG4gIGluZm86IFBpY2tJbmZvLFxuICB7aG92ZXJJbmZvLCBlZGl0b3IsIGVkaXRvck1lbnVBY3RpdmV9OiB7ZWRpdG9yTWVudUFjdGl2ZTogYm9vbGVhbjsgZWRpdG9yOiBFZGl0b3I7IGhvdmVySW5mb31cbik6IGJvb2xlYW4ge1xuICBpZiAoaXNEcmF3aW5nQWN0aXZlKGVkaXRvck1lbnVBY3RpdmUsIGVkaXRvci5tb2RlKSkge1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgcmV0dXJuIGluZm8/LmxheWVyPy5pZCA9PT0gRURJVE9SX0xBWUVSX0lEICYmIGhvdmVySW5mbz8ubGF5ZXI/LmlkID09PSBFRElUT1JfTEFZRVJfSUQ7XG59XG5cbi8qKlxuICogRm9yIHNtYWxsIHRvb2x0aXBzIHdpdGggc2hvcnQgbWVzc2FnZXMsIGUuZy4gXCJEcmFnIHRvIG1vdmUgdGhlIHBvaW50XCIsXG4gKiB1c2UgdGhlIHZhbHVlcyBiZWxvdyB0byBkZWNpZGUgd2hlbiB0byBwb3NpdGlvbiBhIHRvb2x0aXAgdG8gdGhlIGxlZnRcbiAqIG9mIHRoZSBjdXJzb3Igb3IgYWJvdmUgdGhlIGN1cnNvciwgZGVwZW5kaW5nIG9uIHByb3hpbWl0eSB0byB0aGUgZWRnZSBvZlxuICogdGhlIHZpZXdwb3J0IHRvIHByZXZlbnQgdGhlIHRvb2x0aXAgZnJvbSBiZWluZyBjdXQgb2ZmLlxuICovXG5jb25zdCBNSU5fRElTVEFOQ0VfVE9fTEVGVF9FREdFID0gMjAwO1xuY29uc3QgTUlOX0RJU1RBTkNFX1RPX0JPVFRPTV9FREdFID0gMTAwO1xuXG4vKipcbiAqIFJldHVybnMgdG9vbHRpcCBiYXNlZCBvbiBpbnRlcmFjdGlvbnMgd2l0aCBFZGl0b3IgbGF5ZXIuXG4gKiBAcGFyYW0gaW5mbyBJbmZvcm1hdGlvbiBhYm91dCBob3ZlcmVkIG9iamVjdC5cbiAqIEBwYXJhbSBwYXJhbXNcbiAqIEBwYXJhbSBwYXJhbXMuZWRpdG9yTWVudUFjdGl2ZVxuICogQHBhcmFtIHBhcmFtcy5lZGl0b3JcbiAqIEBwYXJhbSBwYXJhbXMudGhlbWVcbiAqIEByYXR1cm5zIFJldHVybnMgYSB0b29sdGlwIG9iamVjdCBjb21wYXRpYmxlIHdpdGggRGVjay5nZXRUb29sdGlwKClcbiAqL1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBsZXhpdHlcbmV4cG9ydCBmdW5jdGlvbiBnZXRUb29sdGlwKFxuICAvLyBUT0RPIFBpY2tpbmdJbmZvIHR5cGUgaW4gZGVjayB0eXBpbmdzIGRvZXNuJ3QgaW5jbHVkZSB2aWV3cG9ydCBhbmQgcGl4ZWxcbiAgaW5mbzogUGlja0luZm8gJiB7dmlld3BvcnQ6IHt3aWR0aD86IG51bWJlcjsgaGVpZ2h0PzogbnVtYmVyfTsgcGl4ZWw6IG51bWJlcltdfSxcbiAge2VkaXRvciwgdGhlbWUsIGVkaXRvck1lbnVBY3RpdmV9OiB7ZWRpdG9yTWVudUFjdGl2ZTogYm9vbGVhbjsgZWRpdG9yOiBFZGl0b3I7IHRoZW1lOiBhbnl9XG4pOiBvYmplY3QgfCBudWxsIHtcbiAgY29uc3Qge29iamVjdCwgbGF5ZXIsIHZpZXdwb3J0ID0ge30sIHBpeGVsID0gW119ID0gaW5mbztcbiAgY29uc3QgY2xvc2VUb0xlZnRFZGdlID0gKHZpZXdwb3J0Py53aWR0aCA/PyAwKSAtIChwaXhlbD8uWzBdID8/IDApIDwgTUlOX0RJU1RBTkNFX1RPX0xFRlRfRURHRTtcbiAgY29uc3QgY2xvc2VUb0JvdHRvbUVkZ2UgPVxuICAgICh2aWV3cG9ydD8uaGVpZ2h0ID8/IDApIC0gKHBpeGVsPy5bMV0gPz8gMCkgPCBNSU5fRElTVEFOQ0VfVE9fQk9UVE9NX0VER0U7XG5cbiAgLy8gZG9uJ3Qgc2hvdyB0aGUgdG9vbHRpcCB3aGVuIHRoZSBtZW51IGlzIHZpc2libGVcbiAgaWYgKGVkaXRvci5zZWxlY3Rpb25Db250ZXh0Py5yaWdodENsaWNrKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICBpZiAoaXNEcmF3aW5nQWN0aXZlKGVkaXRvck1lbnVBY3RpdmUsIGVkaXRvci5tb2RlKSkge1xuICAgIC8vIFRPRE8gc2F2ZSBpbnRlcmFjdGlvbiBzdGF0ZSBpbiBlZGl0b3Igb2JqZWN0XG4gICAgaWYgKFxuICAgICAgKGxheWVyPy5zdGF0ZSBhcyB7bW9kZT86IHtfY2xpY2tTZXF1ZW5jZT86IHVua25vd25bXX19IHwgdW5kZWZpbmVkKT8ubW9kZT8uX2NsaWNrU2VxdWVuY2VcbiAgICAgICAgPy5sZW5ndGhcbiAgICApIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIHJldHVybiBnZXRUb29sdGlwT2JqZWN0KCdDbGljayB0byBzdGFydCBuZXcgZmVhdHVyZScsIHRoZW1lLCB7XG4gICAgICBsZWZ0T2ZDdXJzb3I6IGNsb3NlVG9MZWZ0RWRnZSxcbiAgICAgIGFib3ZlQ3Vyc29yOiBjbG9zZVRvQm90dG9tRWRnZVxuICAgIH0pO1xuICB9XG5cbiAgaWYgKGxheWVyPy5pZCA9PT0gRURJVE9SX0xBWUVSX0lEKSB7XG4gICAgY29uc3Qge3NlbGVjdGVkRmVhdHVyZX0gPSBlZGl0b3I7XG5cbiAgICBpZiAoc2VsZWN0ZWRGZWF0dXJlKSB7XG4gICAgICBpZiAoIW9iamVjdCB8fCAob2JqZWN0LmlkICYmIG9iamVjdC5pZCA9PT0gc2VsZWN0ZWRGZWF0dXJlLmlkKSkge1xuICAgICAgICByZXR1cm4gZ2V0VG9vbHRpcE9iamVjdCgnUmlnaHQgY2xpY2sgdG8gdmlldyBvcHRpb25zXFxuRHJhZyB0byBtb3ZlIHRoZSBmZWF0dXJlJywgdGhlbWUsIHtcbiAgICAgICAgICBsZWZ0T2ZDdXJzb3I6IGNsb3NlVG9MZWZ0RWRnZSxcbiAgICAgICAgICBhYm92ZUN1cnNvcjogY2xvc2VUb0JvdHRvbUVkZ2VcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKG9iamVjdD8ucHJvcGVydGllcz8uZWRpdEhhbmRsZVR5cGUgPT09ICdpbnRlcm1lZGlhdGUnKSB7XG4gICAgICByZXR1cm4gZ2V0VG9vbHRpcE9iamVjdCgnQ2xpY2sgdG8gaW5zZXJ0IGEgcG9pbnQnLCB0aGVtZSwge1xuICAgICAgICBsZWZ0T2ZDdXJzb3I6IGNsb3NlVG9MZWZ0RWRnZSxcbiAgICAgICAgYWJvdmVDdXJzb3I6IGNsb3NlVG9Cb3R0b21FZGdlXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAob2JqZWN0Py5nZW9tZXRyeT8udHlwZSA9PT0gJ1BvaW50JyB8fCBvYmplY3Q/LnByb3BlcnRpZXM/Lmd1aWRlVHlwZSA9PT0gJ3RlbnRhdGl2ZScpIHtcbiAgICAgIHJldHVybiBnZXRUb29sdGlwT2JqZWN0KCdEcmFnIHRvIG1vdmUgdGhlIHBvaW50JywgdGhlbWUsIHtcbiAgICAgICAgbGVmdE9mQ3Vyc29yOiBjbG9zZVRvTGVmdEVkZ2UsXG4gICAgICAgIGFib3ZlQ3Vyc29yOiBjbG9zZVRvQm90dG9tRWRnZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGdldFRvb2x0aXBPYmplY3QoJ0NsaWNrIHRvIHNlbGVjdCB0aGUgZmVhdHVyZVxcblJpZ2h0IGNsaWNrIHRvIHZpZXcgb3B0aW9ucycsIHRoZW1lLCB7XG4gICAgICBsZWZ0T2ZDdXJzb3I6IGNsb3NlVG9MZWZ0RWRnZSxcbiAgICAgIGFib3ZlQ3Vyc29yOiBjbG9zZVRvQm90dG9tRWRnZVxuICAgIH0pO1xuICB9XG5cbiAgcmV0dXJuIG51bGw7XG59XG5cbi8qKlxuICogUmV0dXJucyBjdXJzb3IgdHlwZSBiYXNlZCBvbiBpbnRlcmFjdGlvbnMgd2l0aCBFZGl0b3IgbGF5ZXIuXG4gKiBAcGFyYW0gcGFyYW1zXG4gKiBAcGFyYW0gcGFyYW1zLmVkaXRvck1lbnVBY3RpdmVcbiAqIEBwYXJhbSBwYXJhbXMuZWRpdG9yXG4gKiBAcGFyYW0gcGFyYW1zLmhvdmVySW5mb1xuICogQHJldHVybnMgUmV0dXJucyBjdXJzb3IgdHlwZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEN1cnNvcih7XG4gIGVkaXRvck1lbnVBY3RpdmUsXG4gIGVkaXRvcixcbiAgaG92ZXJJbmZvXG59OiB7XG4gIGVkaXRvck1lbnVBY3RpdmU6IGJvb2xlYW47XG4gIGVkaXRvcjogRWRpdG9yO1xuICBob3ZlckluZm86IGFueTtcbn0pOiBzdHJpbmcgfCBudWxsIHtcbiAgaWYgKGlzRHJhd2luZ0FjdGl2ZShlZGl0b3JNZW51QWN0aXZlLCBlZGl0b3IubW9kZSkpIHtcbiAgICByZXR1cm4gJ2Nyb3NzaGFpcic7XG4gIH1cblxuICBpZiAoaG92ZXJJbmZvPy5sYXllcj8uaWQgPT09IEVESVRPUl9MQVlFUl9JRCAmJiBlZGl0b3Iuc2VsZWN0ZWRGZWF0dXJlKSB7XG4gICAgcmV0dXJuICdtb3ZlJztcbiAgfVxuXG4gIHJldHVybiBudWxsO1xufVxuXG4vKipcbiAqIFJldHVybnMgYSB0b29sdGlwIG9iamVjdCB0aGF0IGNhbiBiZSB1c2VkIGFzIGEgRGVjayB0b29sdGlwLlxuICogUG9zaXRpb25pbmcgY2FuIGJlIG1vZGlmaWVkIGlmIHRoZSBjdXJzb3IgaXMgY2xvc2UgdG8gdGhlIGJvdHRvbSBvciBsZWZ0IGVkZ2Ugb2YgdGhlIHZpZXdwb3J0LlxuICogQHBhcmFtIHRleHQgVGV4dCB0byBzaG93LlxuICogQHBhcmFtIHRoZW1lIEN1cnJlbnQgdGhlbWUuXG4gKiBAcGFyYW0gcG9zaXRpb24ubGVmdE9mQ3Vyc29yIFRvb2x0aXAgc2hvdWxkIGRpc3BsYXkgdG8gdGhlIGxlZnQgb2YgdGhlIGN1cnNvci5cbiAqIEBwYXJhbSBwb3NpdGlvbi5hYm92ZUN1cnNvciBUb29sdGlwIHNob3VsZCBkaXNwbGF5IGFib3ZlIGN1cnNvci5cbiAqL1xuZnVuY3Rpb24gZ2V0VG9vbHRpcE9iamVjdChcbiAgdGV4dDogc3RyaW5nLFxuICB0aGVtZTogYW55LFxuICBwb3NpdGlvbjoge2xlZnRPZkN1cnNvcjogYm9vbGVhbjsgYWJvdmVDdXJzb3I6IGJvb2xlYW59XG4pOiB7dGV4dDogc3RyaW5nOyBzdHlsZTogb2JqZWN0fSB7XG4gIGNvbnN0IHtsZWZ0T2ZDdXJzb3IsIGFib3ZlQ3Vyc29yfSA9IHBvc2l0aW9uO1xuICBjb25zdCBtYXJnaW5Ub3AgPSBhYm92ZUN1cnNvciA/ICctNzBweCcgOiAnMTVweCc7XG4gIGNvbnN0IG1hcmdpbkxlZnQgPSBsZWZ0T2ZDdXJzb3IgPyAnLTIwMHB4JyA6ICcxNXB4JztcbiAgcmV0dXJuIHtcbiAgICB0ZXh0LFxuICAgIHN0eWxlOiB7XG4gICAgICAnbWFyZ2luLXRvcCc6IG1hcmdpblRvcCxcbiAgICAgICdtYXJnaW4tbGVmdCc6IG1hcmdpbkxlZnQsXG4gICAgICAnZm9udC1mYW1pbHknOiB0aGVtZS5mb250RmFtaWx5LFxuICAgICAgJ2ZvbnQtc2l6ZSc6IHRoZW1lLnRvb2x0aXBGb250U2l6ZSxcbiAgICAgICdmb250LXdlaWdodCc6IDQwMCxcbiAgICAgIHBhZGRpbmc6ICc3cHggMThweCcsXG4gICAgICAnYm94LXNoYWRvdyc6IHRoZW1lLnRvb2x0aXBCb3hTaGFkb3csXG4gICAgICAnYmFja2dyb3VuZC1jb2xvcic6IHRoZW1lLnRvb2x0aXBCZyxcbiAgICAgIGNvbG9yOiB0aGVtZS50b29sdGlwQ29sb3IsXG4gICAgICAnYm9yZGVyLXJhZGl1cyc6IHRoZW1lLnByaW1hcnlCdG5SYWRpdXNcbiAgICB9XG4gIH07XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUFJQSxJQUFBQSxVQUFBLEdBQUFDLE9BQUE7QUFKQTtBQUNBOztBQUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPLFNBQVNDLGVBQWVBLENBQUNDLGdCQUF5QixFQUFFQyxJQUFZLEVBQVc7RUFDaEYsT0FDRUQsZ0JBQWdCLEtBQUtDLElBQUksS0FBS0MsdUJBQVksQ0FBQ0MsWUFBWSxJQUFJRixJQUFJLEtBQUtDLHVCQUFZLENBQUNFLGNBQWMsQ0FBQztBQUVwRzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPLFNBQVNDLE9BQU9BLENBQ3JCQyxJQUFjLEVBQ2RDLEtBQVUsRUFBQUMsSUFBQSxFQWlCRDtFQUFBLElBQUFDLFdBQUE7RUFBQSxJQWZQVCxnQkFBZ0IsR0FBQVEsSUFBQSxDQUFoQlIsZ0JBQWdCO0lB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