UNPKG

leaflet-labeled-circle

Version:

Special type of SVG marker with a label inside and draggable around the anchor point

1,076 lines (884 loc) 78.3 kB
(function(){function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s}return e})()({1:[function(require,module,exports){ 'use strict'; /** * Leaflet SVG circle marker with detachable and draggable label and text * * @author Alexander Milevski <info@w8r.name> * @license MIT * @preserve */ module.exports = require('./src/marker'); },{"./src/marker":9}],2:[function(require,module,exports){ require('./src/SVG'); require('./src/SVG.VML'); require('./src/Canvas'); require('./src/Path.Transform'); require('./src/Path.Drag'); module.exports = L.Path.Drag; },{"./src/Canvas":3,"./src/Path.Drag":4,"./src/Path.Transform":5,"./src/SVG":7,"./src/SVG.VML":6}],3:[function(require,module,exports){ function TRUE_FN () { return true; } L.Canvas.include({ /** * Do nothing * @param {L.Path} layer */ _resetTransformPath: function(layer) { if (!this._containerCopy) return; delete this._containerCopy; if (layer._containsPoint_) { layer._containsPoint = layer._containsPoint_; delete layer._containsPoint_; this._requestRedraw(layer); } }, /** * Algorithm outline: * * 1. pre-transform - clear the path out of the canvas, copy canvas state * 2. at every frame: * 2.1. save * 2.2. redraw the canvas from saved one * 2.3. transform * 2.4. draw path * 2.5. restore * 3. Repeat * * @param {L.Path} layer * @param {Array.<Number>} matrix */ transformPath: function(layer, matrix) { var copy = this._containerCopy; var ctx = this._ctx, copyCtx; var m = L.Browser.retina ? 2 : 1; var bounds = this._bounds; var size = bounds.getSize(); var pos = bounds.min; if (!copy) { // get copy of all rendered layers copy = this._containerCopy = document.createElement('canvas'); copyCtx = copy.getContext('2d'); // document.body.appendChild(copy); copy.width = m * size.x; copy.height = m * size.y; this._removePath(layer); this._redraw(); copyCtx.translate(m * bounds.min.x, m * bounds.min.y); copyCtx.drawImage(this._container, 0, 0); this._initPath(layer); // avoid flickering because of the 'mouseover's layer._containsPoint_ = layer._containsPoint; layer._containsPoint = TRUE_FN; } ctx.save(); ctx.clearRect(pos.x, pos.y, size.x * m, size.y * m); ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.restore(); ctx.save(); ctx.drawImage(this._containerCopy, 0, 0, size.x, size.y); ctx.transform.apply(ctx, matrix); // now draw one layer only this._drawing = true; layer._updatePath(); this._drawing = false; ctx.restore(); } }); },{}],4:[function(require,module,exports){ var END = { mousedown: 'mouseup', touchstart: 'touchend', pointerdown: 'touchend', MSPointerDown: 'touchend' }; var MOVE = { mousedown: 'mousemove', touchstart: 'touchmove', pointerdown: 'touchmove', MSPointerDown: 'touchmove' }; function distance(a, b) { var dx = a.x - b.x, dy = a.y - b.y; return Math.sqrt(dx * dx + dy * dy); } /** * Drag handler * @class L.Path.Drag * @extends {L.Handler} */ L.Handler.PathDrag = L.Handler.extend( /** @lends L.Path.Drag.prototype */ { statics: { DRAGGING_CLS: 'leaflet-path-draggable', }, /** * @param {L.Path} path * @constructor */ initialize: function(path) { /** * @type {L.Path} */ this._path = path; /** * @type {Array.<Number>} */ this._matrix = null; /** * @type {L.Point} */ this._startPoint = null; /** * @type {L.Point} */ this._dragStartPoint = null; /** * @type {Boolean} */ this._mapDraggingWasEnabled = false; }, /** * Enable dragging */ addHooks: function() { this._path.on('mousedown', this._onDragStart, this); this._path.options.className = this._path.options.className ? (this._path.options.className + ' ' + L.Handler.PathDrag.DRAGGING_CLS) : L.Handler.PathDrag.DRAGGING_CLS; if (this._path._path) { L.DomUtil.addClass(this._path._path, L.Handler.PathDrag.DRAGGING_CLS); } }, /** * Disable dragging */ removeHooks: function() { this._path.off('mousedown', this._onDragStart, this); this._path.options.className = this._path.options.className .replace(new RegExp('\\s+' + L.Handler.PathDrag.DRAGGING_CLS), ''); if (this._path._path) { L.DomUtil.removeClass(this._path._path, L.Handler.PathDrag.DRAGGING_CLS); } }, /** * @return {Boolean} */ moved: function() { return this._path._dragMoved; }, /** * Start drag * @param {L.MouseEvent} evt */ _onDragStart: function(evt) { var eventType = evt.originalEvent._simulated ? 'touchstart' : evt.originalEvent.type; this._mapDraggingWasEnabled = false; this._startPoint = evt.containerPoint.clone(); this._dragStartPoint = evt.containerPoint.clone(); this._matrix = [1, 0, 0, 1, 0, 0]; L.DomEvent.stop(evt.originalEvent); L.DomUtil.addClass(this._path._renderer._container, 'leaflet-interactive'); L.DomEvent .on(document, MOVE[eventType], this._onDrag, this) .on(document, END[eventType], this._onDragEnd, this); if (this._path._map.dragging.enabled()) { // I guess it's required because mousdown gets simulated with a delay //this._path._map.dragging._draggable._onUp(evt); this._path._map.dragging.disable(); this._mapDraggingWasEnabled = true; } this._path._dragMoved = false; if (this._path._popup) { // that might be a case on touch devices as well this._path._popup._close(); } this._replaceCoordGetters(evt); }, /** * Dragging * @param {L.MouseEvent} evt */ _onDrag: function(evt) { L.DomEvent.stop(evt); var first = (evt.touches && evt.touches.length >= 1 ? evt.touches[0] : evt); var containerPoint = this._path._map.mouseEventToContainerPoint(first); // skip taps if (evt.type === 'touchmove' && !this._path._dragMoved) { var totalMouseDragDistance = this._dragStartPoint.distanceTo(containerPoint); if (totalMouseDragDistance <= this._path._map.options.tapTolerance) { return; } } var x = containerPoint.x; var y = containerPoint.y; var dx = x - this._startPoint.x; var dy = y - this._startPoint.y; // Send events only if point was moved if (dx || dy) { if (!this._path._dragMoved) { this._path._dragMoved = true; this._path.fire('dragstart', evt); // we don't want that to happen on click this._path.bringToFront(); } this._matrix[4] += dx; this._matrix[5] += dy; this._startPoint.x = x; this._startPoint.y = y; this._path.fire('predrag', evt); this._path._transform(this._matrix); this._path.fire('drag', evt); } }, /** * Dragging stopped, apply * @param {L.MouseEvent} evt */ _onDragEnd: function(evt) { var containerPoint = this._path._map.mouseEventToContainerPoint(evt); var moved = this.moved(); // apply matrix if (moved) { this._transformPoints(this._matrix); this._path._updatePath(); this._path._project(); this._path._transform(null); L.DomEvent.stop(evt); } L.DomEvent.off(document, 'mousemove touchmove', this._onDrag, this); L.DomEvent.off(document, 'mouseup touchend', this._onDragEnd, this); this._restoreCoordGetters(); // consistency if (moved) { this._path.fire('dragend', { distance: distance(this._dragStartPoint, containerPoint) }); // hack for skipping the click in canvas-rendered layers var contains = this._path._containsPoint; this._path._containsPoint = L.Util.falseFn; L.Util.requestAnimFrame(function() { L.DomEvent.skipped({ type: 'click' }); this._path._containsPoint = contains; }, this); } this._matrix = null; this._startPoint = null; this._dragStartPoint = null; this._path._dragMoved = false; if (this._mapDraggingWasEnabled) { if (moved) L.DomEvent.fakeStop({ type: 'click' }); this._path._map.dragging.enable(); } }, /** * Applies transformation, does it in one sweep for performance, * so don't be surprised about the code repetition. * * [ x ] [ a b tx ] [ x ] [ a * x + b * y + tx ] * [ y ] = [ c d ty ] [ y ] = [ c * x + d * y + ty ] * * @param {Array.<Number>} matrix */ _transformPoints: function(matrix, dest) { var path = this._path; var i, len, latlng; var px = L.point(matrix[4], matrix[5]); var crs = path._map.options.crs; var transformation = crs.transformation; var scale = crs.scale(path._map.getZoom()); var projection = crs.projection; var diff = transformation.untransform(px, scale) .subtract(transformation.untransform(L.point(0, 0), scale)); var applyTransform = !dest; path._bounds = new L.LatLngBounds(); // console.time('transform'); // all shifts are in-place if (path._point) { // L.Circle dest = projection.unproject( projection.project(path._latlng)._add(diff)); if (applyTransform) { path._latlng = dest; path._point._add(px); } } else if (path._rings || path._parts) { // everything else var rings = path._rings || path._parts; var latlngs = path._latlngs; dest = dest || latlngs; if (!L.Util.isArray(latlngs[0])) { // polyline latlngs = [latlngs]; dest = [dest]; } for (i = 0, len = rings.length; i < len; i++) { dest[i] = dest[i] || []; for (var j = 0, jj = rings[i].length; j < jj; j++) { latlng = latlngs[i][j]; dest[i][j] = projection .unproject(projection.project(latlng)._add(diff)); if (applyTransform) { path._bounds.extend(latlngs[i][j]); rings[i][j]._add(px); } } } } return dest; // console.timeEnd('transform'); }, /** * If you want to read the latlngs during the drag - your right, * but they have to be transformed */ _replaceCoordGetters: function() { if (this._path.getLatLng) { // Circle, CircleMarker this._path.getLatLng_ = this._path.getLatLng; this._path.getLatLng = L.Util.bind(function() { return this.dragging._transformPoints(this.dragging._matrix, {}); }, this._path); } else if (this._path.getLatLngs) { this._path.getLatLngs_ = this._path.getLatLngs; this._path.getLatLngs = L.Util.bind(function() { return this.dragging._transformPoints(this.dragging._matrix, []); }, this._path); } }, /** * Put back the getters */ _restoreCoordGetters: function() { if (this._path.getLatLng_) { this._path.getLatLng = this._path.getLatLng_; delete this._path.getLatLng_; } else if (this._path.getLatLngs_) { this._path.getLatLngs = this._path.getLatLngs_; delete this._path.getLatLngs_; } } }); /** * @param {L.Path} layer * @return {L.Path} */ L.Handler.PathDrag.makeDraggable = function(layer) { layer.dragging = new L.Handler.PathDrag(layer); return layer; }; /** * Also expose as a method * @return {L.Path} */ L.Path.prototype.makeDraggable = function() { return L.Handler.PathDrag.makeDraggable(this); }; L.Path.addInitHook(function() { if (this.options.draggable) { // ensure interactive this.options.interactive = true; if (this.dragging) { this.dragging.enable(); } else { L.Handler.PathDrag.makeDraggable(this); this.dragging.enable(); } } else if (this.dragging) { this.dragging.disable(); } }); },{}],5:[function(require,module,exports){ /** * Leaflet vector features drag functionality * @author Alexander Milevski <info@w8r.name> * @preserve */ /** * Matrix transform path for SVG/VML * Renderer-independent */ L.Path.include({ /** * Applies matrix transformation to SVG * @param {Array.<Number>?} matrix */ _transform: function(matrix) { if (this._renderer) { if (matrix) { this._renderer.transformPath(this, matrix); } else { // reset transform matrix this._renderer._resetTransformPath(this); this._update(); } } return this; }, /** * Check if the feature was dragged, that'll supress the click event * on mouseup. That fixes popups for example * * @param {MouseEvent} e */ _onMouseClick: function(e) { if ((this.dragging && this.dragging.moved()) || (this._map.dragging && this._map.dragging.moved())) { return; } this._fireMouseEvent(e); } }); },{}],6:[function(require,module,exports){ L.SVG.include(!L.Browser.vml ? {} : { /** * Reset transform matrix */ _resetTransformPath: function(layer) { if (layer._skew) { // super important! workaround for a 'jumping' glitch: // disable transform before removing it layer._skew.on = false; layer._path.removeChild(layer._skew); layer._skew = null; } }, /** * Applies matrix transformation to VML * @param {L.Path} layer * @param {Array.<Number>} matrix */ transformPath: function(layer, matrix) { var skew = layer._skew; if (!skew) { skew = L.SVG.create('skew'); layer._path.appendChild(skew); skew.style.behavior = 'url(#default#VML)'; layer._skew = skew; } // handle skew/translate separately, cause it's broken var mt = matrix[0].toFixed(8) + ' ' + matrix[1].toFixed(8) + ' ' + matrix[2].toFixed(8) + ' ' + matrix[3].toFixed(8) + ' 0 0'; var offset = Math.floor(matrix[4]).toFixed() + ', ' + Math.floor(matrix[5]).toFixed() + ''; var s = this._path.style; var l = parseFloat(s.left); var t = parseFloat(s.top); var w = parseFloat(s.width); var h = parseFloat(s.height); if (isNaN(l)) l = 0; if (isNaN(t)) t = 0; if (isNaN(w) || !w) w = 1; if (isNaN(h) || !h) h = 1; var origin = (-l / w - 0.5).toFixed(8) + ' ' + (-t / h - 0.5).toFixed(8); skew.on = 'f'; skew.matrix = mt; skew.origin = origin; skew.offset = offset; skew.on = true; } }); },{}],7:[function(require,module,exports){ L.SVG.include({ /** * Reset transform matrix */ _resetTransformPath: function(layer) { layer._path.setAttributeNS(null, 'transform', ''); }, /** * Applies matrix transformation to SVG * @param {L.Path} layer * @param {Array.<Number>} matrix */ transformPath: function(layer, matrix) { layer._path.setAttributeNS(null, 'transform', 'matrix(' + matrix.join(' ') + ')'); } }); },{}],8:[function(require,module,exports){ (function (global){ "use strict"; var L = typeof window !== "undefined" ? window['L'] : typeof global !== "undefined" ? global['L'] : null; var Circle = L.CircleMarker.extend({ options: { textStyle: { color: '#fff', fontSize: 12, fontWeight: 300 }, shiftY: 7 }, /** * @class LabeledCircle * @constructor * @extends {L.CircleMarker} * @param {String} text * @param {L.LatLng} latlng * @param {Object=} options */ initialize: function initialize(text, latlng, options) { /** * @type {String} */ this._text = text; /** * @type {SVGTextElement} */ this._textElement = null; /** * @type {TextNode} */ this._textNode = null; /** * @type {Object|Null} */ this._textLayer = null; L.CircleMarker.prototype.initialize.call(this, latlng, options); }, /** * @param {String} text * @return {LabeledCircle} */ setText: function setText(text) { this._text = text; if (this._textNode) { this._textElement.removeChild(this._textNode); } this._textNode = document.createTextNode(this._text); this._textElement.appendChild(this._textNode); return this; }, /** * @return {String} */ getText: function getText() { return this._text; }, /** * Also bring text to front * @override */ bringToFront: function bringToFront() { L.CircleMarker.prototype.bringToFront.call(this); this._groupTextToPath(); }, /** * @override */ bringToBack: function bringToBack() { L.CircleMarker.prototype.bringToBack.call(this); this._groupTextToPath(); }, /** * Put text in the right position in the dom */ _groupTextToPath: function _groupTextToPath() { var path = this._path; var textElement = this._textElement; var next = path.nextSibling; var parent = path.parentNode; if (textElement && parent) { if (next && next !== textElement) { parent.insertBefore(textElement, next); } else { parent.appendChild(textElement); } } }, /** * Position the text in container */ _updatePath: function _updatePath() { L.CircleMarker.prototype._updatePath.call(this); this._updateTextPosition(); }, /** * @override */ _transform: function _transform(matrix) { L.CircleMarker.prototype._transform.call(this, matrix); // wrap textElement with a fake layer for renderer // to be able to transform it this._textLayer = this._textLayer || { _path: this._textElement }; if (matrix) { this._renderer.transformPath(this._textLayer, matrix); } else { this._renderer._resetTransformPath(this._textLayer); this._updateTextPosition(); this._textLayer = null; } }, /** * @param {L.Map} map * @return {LabeledCircle} */ onAdd: function onAdd(map) { L.CircleMarker.prototype.onAdd.call(this, map); this._initText(); this._updateTextPosition(); this.setStyle({}); return this; }, /** * Create and insert text */ _initText: function _initText() { this._textElement = L.SVG.create('text'); this.setText(this._text); this._renderer._rootGroup.appendChild(this._textElement); }, /** * Calculate position for text */ _updateTextPosition: function _updateTextPosition() { var textElement = this._textElement; if (textElement) { var bbox = textElement.getBBox(); var textPosition = this._point.subtract(L.point(bbox.width, -bbox.height + this.options.shiftY).divideBy(2)); textElement.setAttribute('x', textPosition.x); textElement.setAttribute('y', textPosition.y); this._groupTextToPath(); } }, /** * Set text style */ setStyle: function setStyle(style) { L.CircleMarker.prototype.setStyle.call(this, style); if (this._textElement) { var styles = this.options.textStyle; for (var prop in styles) { if (styles.hasOwnProperty(prop)) { var styleProp = prop; if (prop === 'color') { styleProp = 'stroke'; } this._textElement.style[styleProp] = styles[prop]; } } } }, /** * Remove text */ onRemove: function onRemove(map) { if (this._textElement) { if (this._textElement.parentNode) { this._textElement.parentNode.removeChild(this._textElement); } this._textElement = null; this._textNode = null; this._textLayer = null; } return L.CircleMarker.prototype.onRemove.call(this, map); } }); module.exports = L.TextCircle = Circle; L.textCircle = function (text, latlng, options) { return new Circle(text, latlng, options); }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{}],9:[function(require,module,exports){ (function (global){ "use strict"; var L = typeof window !== "undefined" ? window['L'] : typeof global !== "undefined" ? global['L'] : null; var Circle = require('./circle'); require('leaflet-path-drag'); var LabeledMarker = L.FeatureGroup.extend({ options: { /** * @param {LabeledMarker} marker * @param {Object} feature * @return {String} */ getLabelText: function getLabelText(marker, feature) { return feature.properties.text; }, /** * @param {LabeledMarker} marker * @param {Object} feature * @param {L.LatLng} latlng * @return {L.LatLng} */ getLabelPosition: function getLabelPosition(marker, feature, latlng) { return feature.properties.labelPosition ? L.latLng(feature.properties.labelPosition.slice().reverse()) : latlng; }, labelPositionKey: 'labelPosition', markerOptions: { color: '#f00', fillOpacity: 0.75, draggable: true, radius: 15 }, anchorOptions: { color: '#00f', radius: 3 }, lineOptions: { color: '#f00', dashArray: [2, 6], lineCap: 'square', weight: 2 } }, /** * @class LabeledMarker * @constructor * @extends {L.FeatureGroup} * * @param {L.LatLng} latlng * @param {Object=} feature * @param {Object=} options */ initialize: function initialize(latlng, feature, options) { L.Util.setOptions(this, options); /** * @type {Object} */ this.feature = feature || { type: 'Feature', properties: {}, geometry: { 'type': 'Point' } }; /** * @type {L.LatLng} */ this._latlng = latlng; /** * @type {CircleLabel} */ this._marker = null; /** * @type {L.CircleMarker} */ this._anchor = null; /** * @type {L.Polyline} */ this._line = null; /** * @type {L.Point} */ this._initialDistance = null; this._createLayers(); L.LayerGroup.prototype.initialize.call(this, [this._anchor, this._line, this._marker]); }, /** * @return {L.LatLng} */ getLabelPosition: function getLabelPosition() { return this._marker.getLatLng(); }, /** * @return {L.LatLng} */ getLatLng: function getLatLng() { return this._latlng; }, /** * Serialize * @return {Object} */ toGeoJSON: function toGeoJSON(geometryCollection) { var feature = L.GeoJSON.getFeature(this, { type: 'Point', coordinates: L.GeoJSON.latLngToCoords(this._anchor.getLatLng()) }); feature.properties[this.options.labelPositionKey] = L.GeoJSON.latLngToCoords(this._marker.getLatLng()); feature.properties.text = this._marker.getText(); return geometryCollection ? L.LabeledCircleMarker.toGeometryCollection(feature, this.options.labelPositionKey) : feature; }, /** * @param {String} text * @return {LabeledMarker} */ setText: function setText(text) { this._marker.setText(text); return this; }, /** * Creates anchor, line and label */ _createLayers: function _createLayers() { var opts = this.options; var pos = opts.getLabelPosition(this, this.feature, this._latlng); var text = opts.getLabelText(this, this.feature); if ('draggable' in opts) { opts.markerOptions.draggable = opts.draggable; } this._marker = new Circle(text, pos, L.Util.extend({ interactive: this.options.interactive }, LabeledMarker.prototype.options.markerOptions, opts.markerOptions)).on('drag', this._onMarkerDrag, this).on('dragstart', this._onMarkerDragStart, this).on('dragend', this._onMarkerDragEnd, this); this._anchor = new L.CircleMarker(this._latlng, L.Util.extend({}, LabeledMarker.prototype.options.anchorOptions, opts.anchorOptions)); this._line = new L.Polyline([this._latlng, this._marker.getLatLng()], L.Util.extend({}, LabeledMarker.prototype.options.lineOptions, opts.lineOptions)); }, /** * Store shift to be precise while dragging * @param {Event} evt */ _onMarkerDragStart: function _onMarkerDragStart(evt) { this._initialDistance = L.DomEvent.getMousePosition(evt).subtract(this._map.latLngToContainerPoint(this._marker.getLatLng())); this.fire('label:' + evt.type, evt); //L.Util.requestAnimFrame(this._marker.bringToFront, this._marker); }, /** * Line dragging * @param {DragEvent} evt */ _onMarkerDrag: function _onMarkerDrag(evt) { var latlng = this._map.containerPointToLatLng(L.DomEvent.getMousePosition(evt)._subtract(this._initialDistance)); this._line.setLatLngs([latlng, this._latlng]); this.fire('label:' + evt.type, evt); }, _onMarkerDragEnd: function _onMarkerDragEnd(evt) { this._line.setLatLngs([this._marker.getLatLng(), this._latlng]); this.fire('label:' + evt.type, evt); }, enableDragging: function enableDragging() { if (this._marker.dragging) this._marker.dragging.enable(); return this; }, disableDragging: function disableDragging() { if (this._marker.dragging) this._marker.dragging.disable(); return this; } }); /** * @param {Object} feature * @param {String=} key * @return {Object} */ function toGeometryCollection(feature, key) { key = key || 'labelPosition'; var anchorPos = feature.geometry.coordinates.slice(); var labelPos = feature.properties[key]; if (!labelPos) throw new Error('No label position set'); labelPos = labelPos.slice(); var geometries = [{ type: 'Point', coordinates: anchorPos }, { type: 'LineString', coordinates: [anchorPos.slice(), labelPos] }, { type: 'Point', coordinates: labelPos.slice() }, { type: 'Point', coordinates: labelPos.slice() }]; return { type: 'Feature', properties: L.Util.extend({}, feature.properties, { geometriesTypes: ['anchor', 'connection', 'label', 'textbox'] }), bbox: feature.bbox, geometry: { type: 'GeometryCollection', geometries: geometries } }; } LabeledMarker.toGeometryCollection = toGeometryCollection; L.LabeledCircleMarker = LabeledMarker; L.labeledCircleMarker = function (latlng, feature, options) { return new LabeledMarker(latlng, feature, options); }; module.exports = LabeledMarker; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) },{"./circle":8,"leaflet-path-drag":2}]},{},[1]) //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJpbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9sZWFmbGV0LXBhdGgtZHJhZy9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9sZWFmbGV0LXBhdGgtZHJhZy9zcmMvQ2FudmFzLmpzIiwibm9kZV9tb2R1bGVzL2xlYWZsZXQtcGF0aC1kcmFnL3NyYy9QYXRoLkRyYWcuanMiLCJub2RlX21vZHVsZXMvbGVhZmxldC1wYXRoLWRyYWcvc3JjL1BhdGguVHJhbnNmb3JtLmpzIiwibm9kZV9tb2R1bGVzL2xlYWZsZXQtcGF0aC1kcmFnL3NyYy9TVkcuVk1MLmpzIiwibm9kZV9tb2R1bGVzL2xlYWZsZXQtcGF0aC1kcmFnL3NyYy9TVkcuanMiLCJzcmMvY2lyY2xlLmpzIiwic3JjL21hcmtlci5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7O0FDQUE7Ozs7Ozs7QUFPQSxPQUFPLE9BQVAsR0FBaUIsUUFBUSxjQUFSLENBQWpCOzs7QUNQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ1BBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFD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VTtBQUNSLFlBQU0sb0JBREU7QUFFUixrQkFBWTtBQUZKO0FBTkwsR0FBUDtBQVdEOztBQUVELGNBQWMsb0JBQWQsR0FBcUMsb0JBQXJDOztBQUVBLEVBQUUsbUJBQUYsR0FBd0IsYUFBeEI7QUFDQSxFQUFFLG1CQUFGLEdBQXdCLFVBQUMsTUFBRCxFQUFTLE9BQVQsRUFBa0IsT0FBbEIsRUFBOEI7QUFDcEQsU0FBTyxJQUFJLGFBQUosQ0FBa0IsTUFBbEIsRUFBMEIsT0FBMUIsRUFBbUMsT0FBbkMsQ0FBUDtBQUNELENBRkQ7O0FBSUEsT0FBTyxPQUFQLEdBQWlCLGFBQWpCIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24oKXtmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc31yZXR1cm4gZX0pKCkiLCIvKipcbiAqIExlYWZsZXQgU1ZHIGNpcmNsZSBtYXJrZXIgd2l0aCBkZXRhY2hhYmxlIGFuZCBkcmFnZ2FibGUgbGFiZWwgYW5kIHRleHRcbiAqXG4gKiBAYXV0aG9yIEFsZXhhbmRlciBNaWxldnNraSA8aW5mb0B3OHIubmFtZT5cbiAqIEBsaWNlbnNlIE1JVFxuICogQHByZXNlcnZlXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gcmVxdWlyZSgnLi9zcmMvbWFya2VyJyk7XG4iLCJyZXF1aXJlKCcuL3NyYy9TVkcnKTtcbnJlcXVpcmUoJy4vc3JjL1NWRy5WTUwnKTtcbnJlcXVpcmUoJy4vc3JjL0NhbnZhcycpO1xucmVxdWlyZSgnLi9zcmMvUGF0aC5UcmFuc2Zvcm0nKTtcbnJlcXVpcmUoJy4vc3JjL1BhdGguRHJhZycpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEwuUGF0aC5EcmFnO1xuIiwiZnVuY3Rpb24gVFJVRV9GTiAoKSB7IHJldHVybiB0cnVlOyB9XG5cbkwuQ2FudmFzLmluY2x1ZGUoe1xuXG4gIC8qKlxuICAgKiBEbyBub3RoaW5nXG4gICAqIEBwYXJhbSAge0wuUGF0aH0gbGF5ZXJcbiAgICovXG4gIF9yZXNldFRyYW5zZm9ybVBhdGg6IGZ1bmN0aW9uKGxheWVyKSB7XG4gICAgaWYgKCF0aGlzLl9jb250YWluZXJDb3B5KSByZXR1cm47XG5cbiAgICBkZWxldGUgdGhpcy5fY29udGFpbmVyQ29weTtcblxuICAgIGlmIChsYXllci5fY29udGFpbnNQb2ludF8pIHtcbiAgICAgIGxheWVyLl9jb250YWluc1BvaW50ID0gbGF5ZXIuX2NvbnRhaW5zUG9pbnRfO1xuICAgICAgZGVsZXRlIGxheWVyLl9jb250YWluc1BvaW50XztcblxuICAgICAgdGhpcy5fcmVxdWVzdFJlZHJhdyhsYXllcik7XG4gICAgfVxuICB9LFxuXG5cbiAgLyoqXG4gICAqIEFsZ29yaXRobSBvdXRsaW5lOlxuICAgKlxuICAgKiAxLiBwcmUtdHJhbnNmb3JtIC0gY2xlYXIgdGhlIHBhdGggb3V0IG9mIHRoZSBjYW52YXMsIGNvcHkgY2FudmFzIHN0YXRlXG4gICAqIDIuIGF0IGV2ZXJ5IGZyYW1lOlxuICAgKiAgICAyLjEuIHNhdmVcbiAgICogICAgMi4yLiByZWRyYXcgdGhlIGNhbnZhcyBmcm9tIHNhdmVkIG9uZVxuICAgKiAgICAyLjMuIHRyYW5zZm9ybVxuICAgKiAgICAyLjQuIGRyYXcgcGF0aFxuICAgKiAgICAyLjUuIHJlc3RvcmVcbiAgICogMy4gUmVwZWF0XG4gICAqXG4gICAqIEBwYXJhbSAge0wuUGF0aH0gICAgICAgICBsYXllclxuICAgKiBAcGFyYW0gIHtBcnJheS48TnVtYmVyPn0gbWF0cml4XG4gICAqL1xuICB0cmFuc2Zvcm1QYXRoOiBmdW5jdGlvbihsYXllciwgbWF0cml4KSB7XG4gICAgdmFyIGNvcHkgICA9IHRoaXMuX2NvbnRhaW5lckNvcHk7XG4gICAgdmFyIGN0eCAgICA9IHRoaXMuX2N0eCwgY29weUN0eDtcbiAgICB2YXIgbSAgICAgID0gTC5Ccm93c2VyLnJldGluYSA/IDIgOiAxO1xuICAgIHZhciBib3VuZHMgPSB0aGlzLl9ib3VuZHM7XG4gICAgdmFyIHNpemUgICA9IGJvdW5kcy5nZXRTaXplKCk7XG4gICAgdmFyIHBvcyAgICA9IGJvdW5kcy5taW47XG5cbiAgICBpZiAoIWNvcHkpIHsgLy8gZ2V0IGNvcHkgb2YgYWxsIHJlbmRlcmVkIGxheWVyc1xuICAgICAgY29weSA9IHRoaXMuX2NvbnRhaW5lckNvcHkgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcbiAgICAgIGNvcHlDdHggPSBjb3B5LmdldENvbnRleHQoJzJkJyk7XG4gICAgICAvLyBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGNvcHkpO1xuXG4gICAgICBjb3B5LndpZHRoICA9IG0gKiBzaXplLng7XG4gICAgICBjb3B5LmhlaWdodCA9IG0gKiBzaXplLnk7XG5cbiAgICAgIHRoaXMuX3JlbW92ZVBhdGgobGF5ZXIpO1xuICAgICAgdGhpcy5fcmVkcmF3KCk7XG5cbiAgICAgIGNvcHlDdHgudHJhbnNsYXRlKG0gKiBib3VuZHMubWluLngsIG0gKiBib3VuZHMubWluLnkpO1xuICAgICAgY29weUN0eC5kcmF3SW1hZ2UodGhpcy5fY29udGFpbmVyLCAwLCAwKTtcbiAgICAgIHRoaXMuX2luaXRQYXRoKGxheWVyKTtcblxuICAgICAgLy8gYXZvaWQgZmxpY2tlcmluZyBiZWNhdXNlIG9mIHRoZSAnbW91c2VvdmVyJ3NcbiAgICAgIGxheWVyLl9jb250YWluc1BvaW50XyA9IGxheWVyLl9jb250YWluc1BvaW50O1xuICAgICAgbGF5ZXIuX2NvbnRhaW5zUG9pbnQgID0gVFJVRV9GTjtcbiAgICB9XG5cbiAgICBjdHguc2F2ZSgpO1xuICAgIGN0eC5jbGVhclJlY3QocG9zLngsIHBvcy55LCBzaXplLnggKiBtLCBzaXplLnkgKiBtKTtcbiAgICBjdHguc2V0VHJhbnNmb3JtKDEsIDAsIDAsIDEsIDAsIDApO1xuICAgIGN0eC5yZXN0b3JlKCk7XG4gICAgY3R4LnNhdmUoKTtcblxuICAgIGN0eC5kcmF3SW1hZ2UodGhpcy5fY29udGFpbmVyQ29weSwgMCwgMCwgc2l6ZS54LCBzaXplLnkpO1xuICAgIGN0eC50cmFuc2Zvcm0uYXBwbHkoY3R4LCBtYXRyaXgpO1xuXG4gICAgLy8gbm93IGRyYXcgb25lIGxheWVyIG9ubHlcbiAgICB0aGlzLl9kcmF3aW5nID0gdHJ1ZTtcbiAgICBsYXllci5fdXBkYXRlUGF0aCgpO1xuICAgIHRoaXMuX2RyYXdpbmcgPSBmYWxzZTtcblxuICAgIGN0eC5yZXN0b3JlKCk7XG4gIH1cblxufSk7XG4iLCJ2YXIgRU5EID0ge1xuICBtb3VzZWRvd246ICAgICAnbW91c2V1cCcsXG4gIHRvdWNoc3RhcnQ6ICAgICd0b3VjaGVuZCcsXG4gIHBvaW50ZXJkb3duOiAgICd0b3VjaGVuZCcsXG4gIE1TUG9pbnRlckRvd246ICd0b3VjaGVuZCdcbn07XG5cbnZhciBNT1ZFID0ge1xuICBtb3VzZWRvd246ICAgICAnbW91c2Vtb3ZlJyxcbiAgdG91Y2hzdGFydDogICAgJ3RvdWNobW92ZScsXG4gIHBvaW50ZXJkb3duOiAgICd0b3VjaG1vdmUnLFxuICBNU1BvaW50ZXJEb3duOiAndG91Y2htb3ZlJ1xufTtcblxuZnVuY3Rpb24gZGlzdGFuY2UoYSwgYikge1xuICB2YXIgZHggPSBhLnggLSBiLngsIGR5ID0gYS55IC0gYi55O1xuICByZXR1cm4gTWF0aC5zcXJ0KGR4ICogZHggKyBkeSAqIGR5KTtcbn1cblxuLyoqXG4gKiBEcmFnIGhhbmRsZXJcbiAqIEBjbGFzcyBMLlBhdGguRHJhZ1xuICogQGV4dGVuZHMge0wuSGFuZGxlcn1cbiAqL1xuTC5IYW5kbGVyLlBhdGhEcmFnID0gTC5IYW5kbGVyLmV4dGVuZCggLyoqIEBsZW5kcyAgTC5QYXRoLkRyYWcucHJvdG90eXBlICovIHtcblxuICBzdGF0aWNzOiB7XG4gICAgRFJBR0dJTkdfQ0xTOiAnbGVhZmxldC1wYXRoLWRyYWdnYWJsZScsXG4gIH0sXG5cblxuICAvKipcbiAgICogQHBhcmFtICB7TC5QYXRofSBwYXRoXG4gICAqIEBjb25zdHJ1Y3RvclxuICAgKi9cbiAgaW5pdGlhbGl6ZTogZnVuY3Rpb24ocGF0aCkge1xuXG4gICAgLyoqXG4gICAgICogQHR5cGUge0wuUGF0aH1cbiAgICAgKi9cbiAgICB0aGlzLl9wYXRoID0gcGF0aDtcblxuICAgIC8qKlxuICAgICAqIEB0eXBlIHtBcnJheS48TnVtYmVyPn1cbiAgICAgKi9cbiAgICB0aGlzLl9tYXRyaXggPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogQHR5cGUge0wuUG9pbnR9XG4gICAgICovXG4gICAgdGhpcy5fc3RhcnRQb2ludCA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBAdHlwZSB7TC5Qb2ludH1cbiAgICAgKi9cbiAgICB0aGlzLl9kcmFnU3RhcnRQb2ludCA9IG51bGw7XG5cbiAgICAvKipcbiAgICAgKiBAdHlwZSB7Qm9vbGVhbn1cbiAgICAgKi9cbiAgICB0aGlzLl9tYXBEcmFnZ2luZ1dhc0VuYWJsZWQgPSBmYWxzZTtcblxuICB9LFxuXG4gIC8qKlxuICAgKiBFbmFibGUgZHJhZ2dpbmdcbiAgICovXG4gIGFkZEhvb2tzOiBmdW5jdGlvbigpIHtcbiAgICB0aGlzLl9wYXRoLm9uKCdtb3VzZWRvd24nLCB0aGlzLl9vbkRyYWdTdGFydCwgdGhpcyk7XG5cbiAgICB0aGlzLl9wYXRoLm9wdGlvbnMuY2xhc3NOYW1lID0gdGhpcy5fcGF0aC5vcHRpb25zLmNsYXNzTmFtZSA/XG4gICAgICAgICh0aGlzLl9wYXRoLm9wdGlvbnMuY2xhc3NOYW1lICsgJyAnICsgTC5IYW5kbGVyLlBhdGhEcmFnLkRSQUdHSU5HX0NMUykgOlxuICAgICAgICAgTC5IYW5kbGVyLlBhdGhEcmFnLkRSQUdHSU5HX0NMUztcblxuICAgIGlmICh0aGlzLl9wYXRoLl9wYXRoKSB7XG4gICAgICBMLkRvbVV0aWwuYWRkQ2xhc3ModGhpcy5fcGF0aC5fcGF0aCwgTC5IYW5kbGVyLlBhdGhEcmFnLkRSQUdHSU5HX0NMUyk7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBEaXNhYmxlIGRyYWdnaW5nXG4gICAqL1xuICByZW1vdmVIb29rczogZnVuY3Rpb24oKSB7XG4gICAgdGhpcy5fcGF0aC5vZmYoJ21vdXNlZG93bicsIHRoaXMuX29uRHJhZ1N0YXJ0LCB0aGlzKTtcblxuICAgIHRoaXMuX3BhdGgub3B0aW9ucy5jbGFzc05hbWUgPSB0aGlzLl9wYXRoLm9wdGlvbnMuY2xhc3NOYW1lXG4gICAgICAucmVwbGFjZShuZXcgUmVnRXhwKCdcXFxccysnICsgTC5IYW5kbGVyLlBhdGhEcmFnLkRSQUdHSU5HX0NMUyksICcnKTtcbiAgICBpZiAodGhpcy5fcGF0aC5fcGF0aCkge1xuICAgICAgTC5Eb21VdGlsLnJlbW92ZUNsYXNzKHRoaXMuX3BhdGguX3BhdGgsIEwuSGFuZGxlci5QYXRoRHJhZy5EUkFHR0lOR19DTFMpO1xuICAgIH1cbiAgfSxcblxuICAvKipcbiAgICogQHJldHVybiB7Qm9vbGVhbn1cbiAgICovXG4gIG1vdmVkOiBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5fcGF0aC5fZHJhZ01vdmVkO1xuICB9LFxuXG4gIC8qKlxuICAgKiBTdGFydCBkcmFnXG4gICAqIEBwYXJhbSAge0wuTW91c2VFdmVudH0gZXZ0XG4gICAqL1xuICBfb25EcmFnU3RhcnQ6IGZ1bmN0aW9uKGV2dCkge1xuICAgIHZhciBldmVudFR5cGUgPSBldnQub3JpZ2luYWxFdmVudC5fc2ltdWxhdGVkID8gJ3RvdWNoc3RhcnQnIDogZXZ0Lm9yaWdpbmFsRXZlbnQudHlwZTtcblxuICAgIHRoaXMuX21hcERyYWdnaW5nV2FzRW5hYmxlZCA9IGZhbHNlO1xuICAgIHRoaXMuX3N0YXJ0UG9pbnQgPSBldnQuY29udGFpbmVyUG9pbnQuY2xvbmUoKTtcbiAgICB0aGlzLl9kcmFnU3RhcnRQb2ludCA9IGV2dC5jb250YWluZXJQb2ludC5jbG9uZSgpO1xuICAgIHRoaXMuX21hdHJpeCA9IFsxLCAwLCAwLCAxLCAwLCAwXTtcbiAgICBMLkRvbUV2ZW50LnN0b3AoZXZ0Lm9yaWdpbmFsRXZlbnQpO1xuXG4gICAgTC5Eb21VdGls