UNPKG

@nebula.gl/layers

Version:

A suite of 3D-enabled data editing layers, suitable for deck.gl

295 lines (210 loc) 31.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SplitPolygonHandler = void 0; var _booleanPointInPolygon = _interopRequireDefault(require("@turf/boolean-point-in-polygon")); var _difference = _interopRequireDefault(require("@turf/difference")); var _buffer = _interopRequireDefault(require("@turf/buffer")); var _lineIntersect = _interopRequireDefault(require("@turf/line-intersect")); var _helpers = require("@turf/helpers"); var _bearing = _interopRequireDefault(require("@turf/bearing")); var _distance = _interopRequireDefault(require("@turf/distance")); var _destination = _interopRequireDefault(require("@turf/destination")); var _polygonToLine = _interopRequireDefault(require("@turf/polygon-to-line")); var _nearestPointOnLine = _interopRequireDefault(require("@turf/nearest-point-on-line")); var _utils = require("../utils"); var _modeHandler = require("./mode-handler"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && Symbol.iterator in Object(iter)) return Array.from(iter); } function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(n); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); } function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; } function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } function _get(target, property, receiver) { if (typeof Reflect !== "undefined" && Reflect.get) { _get = Reflect.get; } else { _get = function _get(target, property, receiver) { var base = _superPropBase(target, property); if (!base) return; var desc = Object.getOwnPropertyDescriptor(base, property); if (desc.get) { return desc.get.call(receiver); } return desc.value; }; } return _get(target, property, receiver || target); } function _superPropBase(object, property) { while (!Object.prototype.hasOwnProperty.call(object, property)) { object = _getPrototypeOf(object); if (object === null) break; } return object; } function _createSuper(Derived) { return function () { var Super = _getPrototypeOf(Derived), result; if (_isNativeReflectConstruct()) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } // TODO edit-modes: delete handlers once EditMode fully implemented var SplitPolygonHandler = /*#__PURE__*/function (_ModeHandler) { _inherits(SplitPolygonHandler, _ModeHandler); var _super = _createSuper(SplitPolygonHandler); function SplitPolygonHandler() { _classCallCheck(this, SplitPolygonHandler); return _super.apply(this, arguments); } _createClass(SplitPolygonHandler, [{ key: "calculateGroundCoords", value: function calculateGroundCoords(clickSequence, groundCoords) { var modeConfig = this.getModeConfig(); if (!modeConfig || !modeConfig.lock90Degree || !clickSequence.length) { return groundCoords; } if (clickSequence.length === 1) { // if first point is clicked, then find closest polygon point and build ~90deg vector var firstPoint = clickSequence[0]; var selectedGeometry = this.getSelectedGeometry(); // @ts-ignore var feature = (0, _polygonToLine["default"])(selectedGeometry); var lines = feature.type === 'FeatureCollection' ? feature.features : [feature]; var minDistance = Number.MAX_SAFE_INTEGER; var closestPoint = null; // If Multipolygon, then we should find nearest polygon line and stick split to it. lines.forEach(function (line) { var snapPoint = (0, _nearestPointOnLine["default"])(line, firstPoint); var distanceFromOrigin = (0, _distance["default"])(snapPoint, firstPoint); if (minDistance > distanceFromOrigin) { minDistance = distanceFromOrigin; closestPoint = snapPoint; } }); if (closestPoint) { // closest point is used as 90degree entry to the polygon var lastBearing = (0, _bearing["default"])(firstPoint, closestPoint); var currentDistance = (0, _distance["default"])(firstPoint, groundCoords, { units: 'meters' }); return (0, _destination["default"])(firstPoint, currentDistance, lastBearing, { units: 'meters' }).geometry.coordinates; } return groundCoords; } // Allow only 90 degree turns var lastPoint = clickSequence[clickSequence.length - 1]; var _generatePointsParall = (0, _utils.generatePointsParallelToLinePoints)(clickSequence[clickSequence.length - 2], lastPoint, groundCoords), _generatePointsParall2 = _slicedToArray(_generatePointsParall, 1), approximatePoint = _generatePointsParall2[0]; // align point with current ground var nearestPt = (0, _nearestPointOnLine["default"])((0, _helpers.lineString)([lastPoint, approximatePoint]), groundCoords).geometry.coordinates; return nearestPt; } }, { key: "handleClick", value: function handleClick(event) { _get(_getPrototypeOf(SplitPolygonHandler.prototype), "handleClick", this).call(this, _objectSpread({}, event, { groundCoords: this.calculateGroundCoords(this.getClickSequence(), event.groundCoords) })); var editAction = null; var tentativeFeature = this.getTentativeFeature(); var selectedGeometry = this.getSelectedGeometry(); var clickSequence = this.getClickSequence(); if (!selectedGeometry) { // eslint-disable-next-line no-console,no-undef console.warn('A polygon must be selected for splitting'); this._setTentativeFeature(null); return editAction; } var pt = { type: 'Point', coordinates: clickSequence[clickSequence.length - 1] }; // @ts-ignore var isPointInPolygon = (0, _booleanPointInPolygon["default"])(pt, selectedGeometry); if (clickSequence.length > 1 && tentativeFeature && !isPointInPolygon) { this.resetClickSequence(); // @ts-ignore var isLineInterectingWithPolygon = (0, _lineIntersect["default"])(tentativeFeature, selectedGeometry); if (isLineInterectingWithPolygon.features.length === 0) { this._setTentativeFeature(null); return editAction; } return this.splitPolygon(); } return editAction; } }, { key: "handlePointerMove", value: function handlePointerMove(_ref) { var groundCoords = _ref.groundCoords; var clickSequence = this.getClickSequence(); var result = { editAction: null, cancelMapPan: false }; if (clickSequence.length === 0) { // nothing to do yet return result; } this._setTentativeFeature({ type: 'Feature', geometry: { type: 'LineString', coordinates: [].concat(_toConsumableArray(clickSequence), [this.calculateGroundCoords(clickSequence, groundCoords)]) } }); return result; } }, { key: "splitPolygon", value: function splitPolygon() { var selectedGeometry = this.getSelectedGeometry(); var tentativeFeature = this.getTentativeFeature(); var featureIndex = this.getSelectedFeatureIndexes()[0]; var modeConfig = this.getModeConfig() || {}; // Default gap in between the polygon var _modeConfig$gap = modeConfig.gap, gap = _modeConfig$gap === void 0 ? 0.1 : _modeConfig$gap, _modeConfig$units = modeConfig.units, units = _modeConfig$units === void 0 ? 'centimeters' : _modeConfig$units; if (gap === 0) { gap = 0.1; units = 'centimeters'; } // @ts-ignore var buffer = (0, _buffer["default"])(tentativeFeature, gap, { units: units }); // @ts-ignore var updatedGeometry = (0, _difference["default"])(selectedGeometry, buffer); this._setTentativeFeature(null); if (!updatedGeometry) { // eslint-disable-next-line no-console,no-undef console.warn('Canceling edit. Split Polygon erased'); return null; } var _updatedGeometry$geom = updatedGeometry.geometry, type = _updatedGeometry$geom.type, coordinates = _updatedGeometry$geom.coordinates; var updatedCoordinates = []; if (type === 'Polygon') { // Update the coordinates as per Multipolygon // @ts-ignore updatedCoordinates = coordinates.map(function (c) { return [c]; }); } else { // Handle Case when Multipolygon has holes // @ts-ignore updatedCoordinates = coordinates.reduce(function (agg, prev) { prev.forEach(function (p) { agg.push([p]); }); return agg; }, []); } // Update the type to Mulitpolygon var updatedData = this.getImmutableFeatureCollection().replaceGeometry(featureIndex, { type: 'MultiPolygon', coordinates: updatedCoordinates }); var editAction = { updatedData: updatedData.getObject(), editType: 'split', featureIndexes: [featureIndex], editContext: null }; return editAction; } }]); return SplitPolygonHandler; }(_modeHandler.ModeHandler); exports.SplitPolygonHandler = SplitPolygonHandler; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9tb2RlLWhhbmRsZXJzL3NwbGl0LXBvbHlnb24taGFuZGxlci50cyJdLCJuYW1lcyI6WyJTcGxpdFBvbHlnb25IYW5kbGVyIiwiY2xpY2tTZXF1ZW5jZSIsImdyb3VuZENvb3JkcyIsIm1vZGVDb25maWciLCJnZXRNb2RlQ29uZmlnIiwibG9jazkwRGVncmVlIiwibGVuZ3RoIiwiZmlyc3RQb2ludCIsInNlbGVjdGVkR2VvbWV0cnkiLCJnZXRTZWxlY3RlZEdlb21ldHJ5IiwiZmVhdHVyZSIsImxpbmVzIiwidHlwZSIsImZlYXR1cmVzIiwibWluRGlzdGFuY2UiLCJOdW1iZXIiLCJNQVhfU0FGRV9JTlRFR0VSIiwiY2xvc2VzdFBvaW50IiwiZm9yRWFjaCIsImxpbmUiLCJzbmFwUG9pbnQiLCJkaXN0YW5jZUZyb21PcmlnaW4iLCJsYXN0QmVhcmluZyIsImN1cnJlbnREaXN0YW5jZSIsInVuaXRzIiwiZ2VvbWV0cnkiLCJjb29yZGluYXRlcyIsImxhc3RQb2ludCIsImFwcHJveGltYXRlUG9pbnQiLCJuZWFyZXN0UHQiLCJldmVudCIsImNhbGN1bGF0ZUdyb3VuZENvb3JkcyIsImdldENsaWNrU2VxdWVuY2UiLCJlZGl0QWN0aW9uIiwidGVudGF0aXZlRmVhdHVyZSIsImdldFRlbnRhdGl2ZUZlYXR1cmUiLCJjb25zb2xlIiwid2FybiIsIl9zZXRUZW50YXRpdmVGZWF0dXJlIiwicHQiLCJpc1BvaW50SW5Qb2x5Z29uIiwicmVzZXRDbGlja1NlcXVlbmNlIiwiaXNMaW5lSW50ZXJlY3RpbmdXaXRoUG9seWdvbiIsInNwbGl0UG9seWdvbiIsInJlc3VsdCIsImNhbmNlbE1hcFBhbiIsImZlYXR1cmVJbmRleCIsImdldFNlbGVjdGVkRmVhdHVyZUluZGV4ZXMiLCJnYXAiLCJidWZmZXIiLCJ1cGRhdGVkR2VvbWV0cnkiLCJ1cGRhdGVkQ29vcmRpbmF0ZXMiLCJtYXAiLCJjIiwicmVkdWNlIiwiYWdnIiwicHJldiIsInAiLCJwdXNoIiwidXBkYXRlZERhdGEiLCJnZXRJbW11dGFibGVGZWF0dXJlQ29sbGVjdGlvbiIsInJlcGxhY2VHZW9tZXRyeSIsImdldE9iamVjdCIsImVkaXRUeXBlIiwiZmVhdHVyZUluZGV4ZXMiLCJlZGl0Q29udGV4dCIsIk1vZGVIYW5kbGVyIl0sIm1hcHBpbmdzIjoiOzs7Ozs7O0FBQUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBRUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBRUE7SUFDYUEsbUI7Ozs7Ozs7Ozs7Ozs7MENBQ1dDLGEsRUFBb0JDLFksRUFBbUI7QUFDM0QsVUFBTUMsVUFBVSxHQUFHLEtBQUtDLGFBQUwsRUFBbkI7O0FBQ0EsVUFBSSxDQUFDRCxVQUFELElBQWUsQ0FBQ0EsVUFBVSxDQUFDRSxZQUEzQixJQUEyQyxDQUFDSixhQUFhLENBQUNLLE1BQTlELEVBQXNFO0FBQ3BFLGVBQU9KLFlBQVA7QUFDRDs7QUFDRCxVQUFJRCxhQUFhLENBQUNLLE1BQWQsS0FBeUIsQ0FBN0IsRUFBZ0M7QUFDOUI7QUFDQSxZQUFNQyxVQUFVLEdBQUdOLGFBQWEsQ0FBQyxDQUFELENBQWhDO0FBQ0EsWUFBTU8sZ0JBQWdCLEdBQUcsS0FBS0MsbUJBQUwsRUFBekIsQ0FIOEIsQ0FJOUI7O0FBQ0EsWUFBTUMsT0FBTyxHQUFHLCtCQUFrQkYsZ0JBQWxCLENBQWhCO0FBRUEsWUFBTUcsS0FBSyxHQUFHRCxPQUFPLENBQUNFLElBQVIsS0FBaUIsbUJBQWpCLEdBQXVDRixPQUFPLENBQUNHLFFBQS9DLEdBQTBELENBQUNILE9BQUQsQ0FBeEU7QUFDQSxZQUFJSSxXQUFXLEdBQUdDLE1BQU0sQ0FBQ0MsZ0JBQXpCO0FBQ0EsWUFBSUMsWUFBWSxHQUFHLElBQW5CLENBVDhCLENBVTlCOztBQUNBTixRQUFBQSxLQUFLLENBQUNPLE9BQU4sQ0FBYyxVQUFDQyxJQUFELEVBQVU7QUFDdEIsY0FBTUMs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WUFBckQsRUFBbUU7QUFDckZsQyxRQUFBQSxJQUFJLEVBQUUsY0FEK0U7QUFFckZjLFFBQUFBLFdBQVcsRUFBRXlCO0FBRndFLE9BQW5FLENBQXBCO0FBS0EsVUFBTWxCLFVBQXNCLEdBQUc7QUFDN0IwQixRQUFBQSxXQUFXLEVBQUVBLFdBQVcsQ0FBQ0csU0FBWixFQURnQjtBQUU3QkMsUUFBQUEsUUFBUSxFQUFFLE9BRm1CO0FBRzdCQyxRQUFBQSxjQUFjLEVBQUUsQ0FBQ2xCLFlBQUQsQ0FIYTtBQUk3Qm1CLFFBQUFBLFdBQVcsRUFBRTtBQUpnQixPQUEvQjtBQU9BLGFBQU9oQyxVQUFQO0FBQ0Q7Ozs7RUFqS3NDaUMsd0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYm9vbGVhblBvaW50SW5Qb2x5Z29uIGZyb20gJ0B0dXJmL2Jvb2xlYW4tcG9pbnQtaW4tcG9seWdvbic7XG5pbXBvcnQgdHVyZkRpZmZlcmVuY2UgZnJvbSAnQHR1cmYvZGlmZmVyZW5jZSc7XG5pbXBvcnQgdHVyZkJ1ZmZlciBmcm9tICdAdHVyZi9idWZmZXInO1xuaW1wb3J0IGxpbmVJbnRlcnNlY3QgZnJvbSAnQHR1cmYvbGluZS1pbnRlcnNlY3QnO1xuaW1wb3J0IHsgbGluZVN0cmluZyB9IGZyb20gJ0B0dXJmL2hlbHBlcnMnO1xuaW1wb3J0IHR1cmZCZWFyaW5nIGZyb20gJ0B0dXJmL2JlYXJpbmcnO1xuaW1wb3J0IHR1cmZEaXN0YW5jZSBmcm9tICdAdHVyZi9kaXN0YW5jZSc7XG5pbXBvcnQgdHVyZkRlc3RpbmF0aW9uIGZyb20gJ0B0dXJmL2Rlc3RpbmF0aW9uJztcbmltcG9ydCB0dXJmUG9seWdvblRvTGluZSBmcm9tICdAdHVyZi9wb2x5Z29uLXRvLWxpbmUnO1xuaW1wb3J0IG5lYXJlc3RQb2ludE9uTGluZSBmcm9tICdAdHVyZi9uZWFyZXN0LXBvaW50LW9uLWxpbmUnO1xuaW1wb3J0IHsgZ2VuZXJhdGVQb2ludHNQYXJhbGxlbFRvTGluZVBvaW50cyB9IGZyb20gJy4uL3V0aWxzJztcbmltcG9ydCB7IENsaWNrRXZlbnQsIFBvaW50ZXJNb3ZlRXZlbnQgfSBmcm9tICcuLi9ldmVudC10eXBlcyc7XG5pbXBvcnQgeyBFZGl0QWN0aW9uLCBNb2RlSGFuZGxlciB9IGZyb20gJy4vbW9kZS1oYW5kbGVyJztcblxuLy8gVE9ETyBlZGl0LW1vZGVzOiBkZWxldGUgaGFuZGxlcnMgb25jZSBFZGl0TW9kZSBmdWxseSBpbXBsZW1lbnRlZFxuZXhwb3J0IGNsYXNzIFNwbGl0UG9seWdvbkhhbmRsZXIgZXh0ZW5kcyBNb2RlSGFuZGxlciB7XG4gIGNhbGN1bGF0ZUdyb3VuZENvb3JkcyhjbGlja1NlcXVlbmNlOiBhbnksIGdyb3VuZENvb3JkczogYW55KSB7XG4gICAgY29uc3QgbW9kZUNvbmZpZyA9IHRoaXMuZ2V0TW9kZUNvbmZpZygpO1xuICAgIGlmICghbW9kZUNvbmZpZyB8fCAhbW9kZUNvbmZpZy5sb2NrOTBEZWdyZWUgfHwgIWNsaWNrU2VxdWVuY2UubGVuZ3RoKSB7XG4gICAgICByZXR1cm4gZ3JvdW5kQ29vcmRzO1xuICAgIH1cbiAgICBpZiAoY2xpY2tTZXF1ZW5jZS5sZW5ndGggPT09IDEpIHtcbiAgICAgIC8vIGlmIGZpcnN0IHBvaW50IGlzIGNsaWNrZWQsIHRoZW4gZmluZCBjbG9zZXN0IHBvbHlnb24gcG9pbnQgYW5kIGJ1aWxkIH45MGRlZyB2ZWN0b3JcbiAgICAgIGNvbnN0IGZpcnN0UG9pbnQgPSBjbGlja1NlcXVlbmNlWzBdO1xuICAgICAgY29uc3Qgc2VsZWN0ZWRHZW9tZXRyeSA9IHRoaXMuZ2V0U2VsZWN0ZWRHZW9tZXRyeSgpO1xuICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgY29uc3QgZmVhdHVyZSA9IHR1cmZQb2x5Z29uVG9MaW5lKHNlbGVjdGVkR2VvbWV0cnkpO1xuXG4gICAgICBjb25zdCBsaW5lcyA9IGZlYXR1cmUudHlwZSA9PT0gJ0ZlYXR1cmVDb2xsZWN0aW9uJyA/IGZlYXR1cmUuZmVhdHVyZXMgOiBbZmVhdHVyZV07XG4gICAgICBsZXQgbWluRGlzdGFuY2UgPSBOdW1iZXIuTUFYX1NBRkVfSU5URUdFUjtcbiAgICAgIGxldCBjbG9zZXN0UG9pbnQgPSBudWxsO1xuICAgICAgLy8gSWYgTXVsdGlwb2x5Z29uLCB0aGVuIHdlIHNob3VsZCBmaW5kIG5lYXJlc3QgcG9seWdvbiBsaW5lIGFuZCBzdGljayBzcGxpdCB0byBpdC5cbiAgICAgIGxpbmVzLmZvckVhY2goKGxpbmUpID0+IHtcbiAgICAgICAgY29uc3Qgc25hcFBvaW50ID0gbmVhcmVzdFBvaW50T25MaW5lKGxpbmUsIGZpcnN0UG9pbnQpO1xuICAgICAgICBjb25zdCBkaXN0YW5jZUZyb21PcmlnaW4gPSB0dXJmRGlzdGFuY2Uoc25hcFBvaW50LCBmaXJzdFBvaW50KTtcbiAgICAgICAgaWYgKG1pbkRpc3RhbmNlID4gZGlzdGFuY2VGcm9tT3JpZ2luKSB7XG4gICAgICAgICAgbWluRGlzdGFuY2UgPSBkaXN0YW5jZUZyb21PcmlnaW47XG4gICAgICAgICAgY2xvc2VzdFBvaW50ID0gc25hcFBvaW50O1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgaWYgKGNsb3Nlc3RQb2ludCkge1xuICAgICAgICAvLyBjbG9zZXN0IHBvaW50IGlzIHVzZWQgYXMgOTBkZWdyZWUgZW50cnkgdG8gdGhlIHBvbHlnb25cbiAgICAgICAgY29uc3QgbGFzdEJlYXJpbmcgPSB0dXJmQmVhcmluZyhmaXJzdFBvaW50LCBjbG9zZXN0UG9pbnQpO1xuICAgICAgICBjb25zdCBjdXJyZW50RGlzdGFuY2UgPSB0dXJmRGlzdGFuY2UoZmlyc3RQb2ludCwgZ3JvdW5kQ29vcmRzLCB7IHVuaXRzOiAnbWV0ZXJzJyB9KTtcbiAgICAgICAgcmV0dXJuIHR1cmZEZXN0aW5hdGlvbihmaXJzdFBvaW50LCBjdXJyZW50RGlzdGFuY2UsIGxhc3RCZWFyaW5nLCB7XG4gICAgICAgICAgdW5pdHM6ICdtZXRlcnMnLFxuICAgICAgICB9KS5nZW9tZXRyeS5jb29yZGluYXRlcztcbiAgICAgIH1cbiAgICAgIHJldHVybiBncm91bmRDb29yZHM7XG4gICAgfVxuICAgIC8vIEFsbG93IG9ubHkgOTAgZGVncmVlIHR1cm5zXG4gICAgY29uc3QgbGFzdFBvaW50ID0gY2xpY2tTZXF1ZW5jZVtjbGlja1NlcXVlbmNlLmxlbmd0aCAtIDFdO1xuICAgIGNvbnN0IFthcHByb3hpbWF0ZVBvaW50XSA9IGdlbmVyYXRlUG9pbnRzUGFyYWxsZWxUb0xpbmVQb2ludHMoXG4gICAgICBjbGlja1NlcXVlbmNlW2NsaWNrU2VxdWVuY2UubGVuZ3RoIC0gMl0sXG4gICAgICBsYXN0UG9pbnQsXG4gICAgICBncm91bmRDb29yZHNcbiAgICApO1xuICAgIC8vIGFsaWduIHBvaW50IHdpdGggY3VycmVudCBncm91bmRcbiAgICBjb25zdCBuZWFyZXN0UHQgPSBuZWFyZXN0UG9pbnRPbkxpbmUobGluZVN0cmluZyhbbGFzdFBvaW50LCBhcHByb3hpbWF0ZVBvaW50XSksIGdyb3VuZENvb3JkcylcbiAgICAgIC5nZW9tZXRyeS5jb29yZGluYXRlcztcbiAgICByZXR1cm4gbmVhcmVzdFB0O1xuICB9XG5cbiAgaGFuZGxlQ2xpY2soZXZlbnQ6IENsaWNrRXZlbnQpOiBFZGl0QWN0aW9uIHwgbnVsbCB8IHVuZGVmaW5lZCB7XG4gICAgc3VwZXIuaGFuZGxlQ2xpY2soe1xuICAgICAgLi4uZXZlbnQsXG4gICAgICBncm91bmRDb29yZHM6IHRoaXMuY2FsY3VsYXRlR3JvdW5kQ29vcmRzKHRoaXMuZ2V0Q2xpY2tTZXF1ZW5jZSgpLCBldmVudC5ncm91bmRDb29yZHMpLFxuICAgIH0pO1xuICAgIGNvbnN0IGVkaXRBY3Rpb246IEVkaXRBY3Rpb24gfCBudWxsIHwgdW5kZWZpbmVkID0gbnVsbDtcbiAgICBjb25zdCB0ZW50YXRpdmVGZWF0dXJlID0gdGhpcy5nZXRUZW50YXRpdmVGZWF0dXJlKCk7XG4gICAgY29uc3Qgc2VsZWN0ZWRHZW9tZXRyeSA9IHRoaXMuZ2V0U2VsZWN0ZWRHZW9tZXRyeSgpO1xuICAgIGNvbnN0IGNsaWNrU2VxdWVuY2UgPSB0aGlzLmdldENsaWNrU2VxdWVuY2UoKTtcblxuICAgIGlmICghc2VsZWN0ZWRHZW9tZXRyeSkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWNvbnNvbGUsbm8tdW5kZWZcbiAgICAgIGNvbnNvbGUud2FybignQSBwb2x5Z29uIG11c3QgYmUgc2VsZWN0ZWQgZm9yIHNwbGl0dGluZycpO1xuICAgICAgdGhpcy5fc2V0VGVudGF0aXZlRmVhdHVyZShudWxsKTtcbiAgICAgIHJldHVybiBlZGl0QWN0aW9uO1xuICAgIH1cbiAgICBjb25zdCBwdCA9IHtcbiAgICAgIHR5cGU6ICdQb2ludCcsXG4gICAgICBjb29yZGluYXRlczogY2xpY2tTZXF1ZW5jZVtjbGlja1NlcXVlbmNlLmxlbmd0aCAtIDFdLFxuICAgIH07XG4gICAgLy8gQHRzLWlnbm9yZVxuICAgIGNvbnN0IGlzUG9pbnRJblBvbHlnb24gPSBib29sZWFuUG9pbnRJblBvbHlnb24ocHQsIHNlbGVjdGVkR2VvbWV0cnkpO1xuICAgIGlmIChjbGlja1NlcXVlbmNlLmxlbmd0aCA+IDEgJiYgdGVudGF0aXZlRmVhdHVyZSAmJiAhaXNQb2ludEluUG9seWdvbikge1xuICAgICAgdGhpcy5yZXNldENsaWNrU2VxdWVuY2UoKTtcbiAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgIGNvbnN0IGlzTGluZUludGVyZWN0aW5nV2l0aFBvbHlnb24gPSBsaW5lSW50ZXJzZWN0KHRlbnRhdGl2ZUZlYXR1cmUsIHNlbGVjdGVkR2VvbWV0cnkpO1xuICAgICAgaWYgKGlzTGluZUludGVyZWN0aW5nV2l0aFBvbHlnb24uZmVhdHVyZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHRoaXMuX3NldFRlbnRhdGl2ZUZlYXR1cmUobnVsbCk7XG4gICAgICAgIHJldHVybiBlZGl0QWN0aW9uO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXMuc3BsaXRQb2x5Z29uKCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGVkaXRBY3Rpb247XG4gIH1cblxuICBoYW5kbGVQb2ludGVyTW92ZSh7XG4gICAgZ3JvdW5kQ29vcmRzLFxuICB9OiBQb2ludGVyTW92ZUV2ZW50KTogeyBlZGl0QWN0aW9uOiBFZGl0QWN0aW9uIHwgbnVsbCB8IHVuZGVmaW5lZDsgY2FuY2VsTWFwUGFuOiBib29sZWFuIH0ge1xuICAgIGNvbnN0IGNsaWNrU2VxdWVuY2UgPSB0aGlzLmdldENsaWNrU2VxdWVuY2UoKTtcbiAgICBjb25zdCByZXN1bHQgPSB7IGVkaXRBY3Rpb246IG51bGwsIGNhbmNlbE1hcFBhbjogZmFsc2UgfTtcblxuICAgIGlmIChjbGlja1NlcXVlbmNlLmxlbmd0aCA9PT0gMCkge1xuICAgICAgLy8gbm90aGluZyB0byBkbyB5ZXRcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfVxuXG4gICAgdGhpcy5fc2V0VGVudGF0aXZlRmVhdHVyZSh7XG4gICAgICB0eXBlOiAnRmVhdHVyZScsXG4gICAgICBnZW9tZXRyeToge1xuICAgICAgICB0eXBlOiAnTGluZVN0cmluZycsXG4gICAgICAgIGNvb3JkaW5hdGVzOiBbLi4uY2xpY2tTZXF1ZW5jZSwgdGhpcy5jYWxjdWxhdGVHcm91bmRDb29yZHMoY2xpY2tTZXF1ZW5jZSwgZ3JvdW5kQ29vcmRzKV0sXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxuXG4gIHNwbGl0UG9seWdvbigpIHtcbiAgICBjb25zdCBzZWxlY3RlZEdlb21ldHJ5ID0gdGhpcy5nZXRTZWxlY3RlZEdlb21ldHJ5KCk7XG4gICAgY29uc3QgdGVudGF0aXZlRmVhdHVyZSA9IHRoaXMuZ2V0VGVudGF0aXZlRmVhdHVyZSgpO1xuICAgIGNvbnN0IGZlYXR1cmVJbmRleCA9IHRoaXMuZ2V0U2VsZWN0ZWRGZWF0dXJlSW5kZXhlcygpWzBdO1xuICAgIGNvbnN0IG1vZGVDb25maWcgPSB0aGlzLmdldE1vZGVDb25maWcoKSB8fCB7fTtcblxuICAgIC8vIERlZmF1bHQgZ2FwIGluIGJldHdlZW4gdGhlIHBvbHlnb25cbiAgICBsZXQgeyBnYXAgPSAwLjEsIHVuaXRzID0gJ2NlbnRpbWV0ZXJzJyB9ID0gbW9kZUNvbmZpZztcbiAgICBpZiAoZ2FwID09PSAwKSB7XG4gICAgICBnYXAgPSAwLjE7XG4gICAgICB1bml0cyA9ICdjZW50aW1ldGVycyc7XG4gICAgfVxuICAgIC8vIEB0cy1pZ25vcmVcbiAgICBjb25zdCBidWZmZXIgPSB0dXJmQnVmZmVyKHRlbnRhdGl2ZUZlYXR1cmUsIGdhcCwgeyB1bml0cyB9KTtcbiAgICAvLyBAdHMtaWdub3JlXG4gICAgY29uc3QgdXBkYXRlZEdlb21ldHJ5ID0gdHVyZkRpZmZlcmVuY2Uoc2VsZWN0ZWRHZW9tZXRyeSwgYnVmZmVyKTtcbiAgICB0aGlzLl9zZXRUZW50YXRpdmVGZWF0dXJlKG51bGwpO1xuICAgIGlmICghdXBkYXRlZEdlb21ldHJ5KSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tY29uc29sZSxuby11bmRlZlxuICAgICAgY29uc29sZS53YXJuKCdDYW5jZWxpbmcgZWRpdC4gU3BsaXQgUG9seWdvbiBlcmFzZWQnKTtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IHsgdHlwZSwgY29vcmRpbmF0ZXMgfSA9IHVwZGF0ZWRHZW9tZXRyeS5nZW9tZXRyeTtcbiAgICBsZXQgdXBkYXRlZENvb3JkaW5hdGVzID0gW107XG4gICAgaWYgKHR5cGUgPT09ICdQb2x5Z29uJykge1xuICAgICAgLy8gVXBkYXRlIHRoZSBjb29yZGluYXRlcyBhcyBwZXIgTXVsdGlwb2x5Z29uXG4gICAgICAvLyBAdHMtaWdub3JlXG4gICAgICB1cGRhdGVkQ29vcmRpbmF0ZXMgPSBjb29yZGluYXRlcy5tYXAoKGMpID0+IFtjXSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIEhhbmRsZSBDYXNlIHdoZW4gTXVsdGlwb2x5Z29uIGhhcyBob2xlc1xuICAgICAgLy8gQHRzLWlnbm9yZVxuICAgICAgdXBkYXRlZENvb3JkaW5hdGVzID0gY29vcmRpbmF0ZXMucmVkdWNlKChhZ2csIHByZXYpID0+IHtcbiAgICAgICAgcHJldi5mb3JFYWNoKChwKSA9PiB7XG4gICAgICAgICAgYWdnLnB1c2goW3BdKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBhZ2c7XG4gICAgICB9LCBbXSk7XG4gICAgfVxuXG4gICAgLy8gVXBkYXRlIHRoZSB0eXBlIHRvIE11bGl0cG9seWdvblxuICAgIGNvbnN0IHVwZGF0ZWREYXRhID0gdGhpcy5nZXRJbW11dGFibGVGZWF0dXJlQ29sbGVjdGlvbigpLnJlcGxhY2VHZW9tZXRyeShmZWF0dXJlSW5kZXgsIHtcbiAgICAgIHR5cGU6ICdNdWx0aVBvbHlnb24nLFxuICAgICAgY29vcmRpbmF0ZXM6IHVwZGF0ZWRDb29yZGluYXRlcyxcbiAgICB9KTtcblxuICAgIGNvbnN0IGVkaXRBY3Rpb246IEVkaXRBY3Rpb24gPSB7XG4gICAgICB1cGRhdGVkRGF0YTogdXBkYXRlZERhdGEuZ2V0T2JqZWN0KCksXG4gICAgICBlZGl0VHlwZTogJ3NwbGl0JyxcbiAgICAgIGZlYXR1cmVJbmRleGVzOiBbZmVhdHVyZUluZGV4XSxcbiAgICAgIGVkaXRDb250ZXh0OiBudWxsLFxuICAgIH07XG5cbiAgICByZXR1cm4gZWRpdEFjdGlvbjtcbiAgfVxufVxuIl19