` element\r\n// and optionally an object literal with `Map options`.\r\n//\r\n// @alternative\r\n// @factory L.map(el: HTMLElement, options?: Map options)\r\n// Instantiates a map object given an instance of a `
` HTML element\r\n// and optionally an object literal with `Map options`.\r\nfunction createMap(id, options) {\r\n\treturn new Map(id, options);\r\n}\n\n/*\r\n * @class Control\r\n * @aka L.Control\r\n * @inherits Class\r\n *\r\n * L.Control is a base class for implementing map controls. Handles positioning.\r\n * All other controls extend from this class.\r\n */\r\n\r\nvar Control = Class.extend({\r\n\t// @section\r\n\t// @aka Control options\r\n\toptions: {\r\n\t\t// @option position: String = 'topright'\r\n\t\t// The position of the control (one of the map corners). Possible values are `'topleft'`,\r\n\t\t// `'topright'`, `'bottomleft'` or `'bottomright'`\r\n\t\tposition: 'topright'\r\n\t},\r\n\r\n\tinitialize: function (options) {\r\n\t\tsetOptions(this, options);\r\n\t},\r\n\r\n\t/* @section\r\n\t * Classes extending L.Control will inherit the following methods:\r\n\t *\r\n\t * @method getPosition: string\r\n\t * Returns the position of the control.\r\n\t */\r\n\tgetPosition: function () {\r\n\t\treturn this.options.position;\r\n\t},\r\n\r\n\t// @method setPosition(position: string): this\r\n\t// Sets the position of the control.\r\n\tsetPosition: function (position) {\r\n\t\tvar map = this._map;\r\n\r\n\t\tif (map) {\r\n\t\t\tmap.removeControl(this);\r\n\t\t}\r\n\r\n\t\tthis.options.position = position;\r\n\r\n\t\tif (map) {\r\n\t\t\tmap.addControl(this);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getContainer: HTMLElement\r\n\t// Returns the HTMLElement that contains the control.\r\n\tgetContainer: function () {\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\t// @method addTo(map: Map): this\r\n\t// Adds the control to the given map.\r\n\taddTo: function (map) {\r\n\t\tthis.remove();\r\n\t\tthis._map = map;\r\n\r\n\t\tvar container = this._container = this.onAdd(map),\r\n\t\t pos = this.getPosition(),\r\n\t\t corner = map._controlCorners[pos];\r\n\r\n\t\taddClass(container, 'leaflet-control');\r\n\r\n\t\tif (pos.indexOf('bottom') !== -1) {\r\n\t\t\tcorner.insertBefore(container, corner.firstChild);\r\n\t\t} else {\r\n\t\t\tcorner.appendChild(container);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method remove: this\r\n\t// Removes the control from the map it is currently active on.\r\n\tremove: function () {\r\n\t\tif (!this._map) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tremove(this._container);\r\n\r\n\t\tif (this.onRemove) {\r\n\t\t\tthis.onRemove(this._map);\r\n\t\t}\r\n\r\n\t\tthis._map = null;\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_refocusOnMap: function (e) {\r\n\t\t// if map exists and event is not a keyboard event\r\n\t\tif (this._map && e && e.screenX > 0 && e.screenY > 0) {\r\n\t\t\tthis._map.getContainer().focus();\r\n\t\t}\r\n\t}\r\n});\r\n\r\nvar control = function (options) {\r\n\treturn new Control(options);\r\n};\r\n\r\n/* @section Extension methods\r\n * @uninheritable\r\n *\r\n * Every control should extend from `L.Control` and (re-)implement the following methods.\r\n *\r\n * @method onAdd(map: Map): HTMLElement\r\n * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).\r\n *\r\n * @method onRemove(map: Map)\r\n * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).\r\n */\r\n\r\n/* @namespace Map\r\n * @section Methods for Layers and Controls\r\n */\r\nMap.include({\r\n\t// @method addControl(control: Control): this\r\n\t// Adds the given control to the map\r\n\taddControl: function (control) {\r\n\t\tcontrol.addTo(this);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeControl(control: Control): this\r\n\t// Removes the given control from the map\r\n\tremoveControl: function (control) {\r\n\t\tcontrol.remove();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initControlPos: function () {\r\n\t\tvar corners = this._controlCorners = {},\r\n\t\t l = 'leaflet-',\r\n\t\t container = this._controlContainer =\r\n\t\t create$1('div', l + 'control-container', this._container);\r\n\r\n\t\tfunction createCorner(vSide, hSide) {\r\n\t\t\tvar className = l + vSide + ' ' + l + hSide;\r\n\r\n\t\t\tcorners[vSide + hSide] = create$1('div', className, container);\r\n\t\t}\r\n\r\n\t\tcreateCorner('top', 'left');\r\n\t\tcreateCorner('top', 'right');\r\n\t\tcreateCorner('bottom', 'left');\r\n\t\tcreateCorner('bottom', 'right');\r\n\t},\r\n\r\n\t_clearControlPos: function () {\r\n\t\tfor (var i in this._controlCorners) {\r\n\t\t\tremove(this._controlCorners[i]);\r\n\t\t}\r\n\t\tremove(this._controlContainer);\r\n\t\tdelete this._controlCorners;\r\n\t\tdelete this._controlContainer;\r\n\t}\r\n});\n\n/*\r\n * @class Control.Layers\r\n * @aka L.Control.Layers\r\n * @inherits Control\r\n *\r\n * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](http://leafletjs.com/examples/layers-control/)). Extends `Control`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var baseLayers = {\r\n * \t\"Mapbox\": mapbox,\r\n * \t\"OpenStreetMap\": osm\r\n * };\r\n *\r\n * var overlays = {\r\n * \t\"Marker\": marker,\r\n * \t\"Roads\": roadsLayer\r\n * };\r\n *\r\n * L.control.layers(baseLayers, overlays).addTo(map);\r\n * ```\r\n *\r\n * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:\r\n *\r\n * ```js\r\n * {\r\n * \"
\": layer1,\r\n * \"\": layer2\r\n * }\r\n * ```\r\n *\r\n * The layer names can contain HTML, which allows you to add additional styling to the items:\r\n *\r\n * ```js\r\n * {\" My Layer \": myLayer}\r\n * ```\r\n */\r\n\r\nvar Layers = Control.extend({\r\n\t// @section\r\n\t// @aka Control.Layers options\r\n\toptions: {\r\n\t\t// @option collapsed: Boolean = true\r\n\t\t// If `true`, the control will be collapsed into an icon and expanded on mouse hover or touch.\r\n\t\tcollapsed: true,\r\n\t\tposition: 'topright',\r\n\r\n\t\t// @option autoZIndex: Boolean = true\r\n\t\t// If `true`, the control will assign zIndexes in increasing order to all of its layers so that the order is preserved when switching them on/off.\r\n\t\tautoZIndex: true,\r\n\r\n\t\t// @option hideSingleBase: Boolean = false\r\n\t\t// If `true`, the base layers in the control will be hidden when there is only one.\r\n\t\thideSingleBase: false,\r\n\r\n\t\t// @option sortLayers: Boolean = false\r\n\t\t// Whether to sort the layers. When `false`, layers will keep the order\r\n\t\t// in which they were added to the control.\r\n\t\tsortLayers: false,\r\n\r\n\t\t// @option sortFunction: Function = *\r\n\t\t// A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)\r\n\t\t// that will be used for sorting the layers, when `sortLayers` is `true`.\r\n\t\t// The function receives both the `L.Layer` instances and their names, as in\r\n\t\t// `sortFunction(layerA, layerB, nameA, nameB)`.\r\n\t\t// By default, it sorts layers alphabetically by their name.\r\n\t\tsortFunction: function (layerA, layerB, nameA, nameB) {\r\n\t\t\treturn nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);\r\n\t\t}\r\n\t},\r\n\r\n\tinitialize: function (baseLayers, overlays, options) {\r\n\t\tsetOptions(this, options);\r\n\r\n\t\tthis._layerControlInputs = [];\r\n\t\tthis._layers = [];\r\n\t\tthis._lastZIndex = 0;\r\n\t\tthis._handlingClick = false;\r\n\r\n\t\tfor (var i in baseLayers) {\r\n\t\t\tthis._addLayer(baseLayers[i], i);\r\n\t\t}\r\n\r\n\t\tfor (i in overlays) {\r\n\t\t\tthis._addLayer(overlays[i], i, true);\r\n\t\t}\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._initLayout();\r\n\t\tthis._update();\r\n\r\n\t\tthis._map = map;\r\n\t\tmap.on('zoomend', this._checkDisabledLayers, this);\r\n\r\n\t\tfor (var i = 0; i < this._layers.length; i++) {\r\n\t\t\tthis._layers[i].layer.on('add remove', this._onLayerChange, this);\r\n\t\t}\r\n\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\taddTo: function (map) {\r\n\t\tControl.prototype.addTo.call(this, map);\r\n\t\t// Trigger expand after Layers Control has been inserted into DOM so that is now has an actual height.\r\n\t\treturn this._expandIfNotCollapsed();\r\n\t},\r\n\r\n\tonRemove: function () {\r\n\t\tthis._map.off('zoomend', this._checkDisabledLayers, this);\r\n\r\n\t\tfor (var i = 0; i < this._layers.length; i++) {\r\n\t\t\tthis._layers[i].layer.off('add remove', this._onLayerChange, this);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addBaseLayer(layer: Layer, name: String): this\r\n\t// Adds a base layer (radio button entry) with the given name to the control.\r\n\taddBaseLayer: function (layer, name) {\r\n\t\tthis._addLayer(layer, name);\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method addOverlay(layer: Layer, name: String): this\r\n\t// Adds an overlay (checkbox entry) with the given name to the control.\r\n\taddOverlay: function (layer, name) {\r\n\t\tthis._addLayer(layer, name, true);\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method removeLayer(layer: Layer): this\r\n\t// Remove the given layer from the control.\r\n\tremoveLayer: function (layer) {\r\n\t\tlayer.off('add remove', this._onLayerChange, this);\r\n\r\n\t\tvar obj = this._getLayer(stamp(layer));\r\n\t\tif (obj) {\r\n\t\t\tthis._layers.splice(this._layers.indexOf(obj), 1);\r\n\t\t}\r\n\t\treturn (this._map) ? this._update() : this;\r\n\t},\r\n\r\n\t// @method expand(): this\r\n\t// Expand the control container if collapsed.\r\n\texpand: function () {\r\n\t\taddClass(this._container, 'leaflet-control-layers-expanded');\r\n\t\tthis._form.style.height = null;\r\n\t\tvar acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);\r\n\t\tif (acceptableHeight < this._form.clientHeight) {\r\n\t\t\taddClass(this._form, 'leaflet-control-layers-scrollbar');\r\n\t\t\tthis._form.style.height = acceptableHeight + 'px';\r\n\t\t} else {\r\n\t\t\tremoveClass(this._form, 'leaflet-control-layers-scrollbar');\r\n\t\t}\r\n\t\tthis._checkDisabledLayers();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method collapse(): this\r\n\t// Collapse the control container if expanded.\r\n\tcollapse: function () {\r\n\t\tremoveClass(this._container, 'leaflet-control-layers-expanded');\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initLayout: function () {\r\n\t\tvar className = 'leaflet-control-layers',\r\n\t\t container = this._container = create$1('div', className),\r\n\t\t collapsed = this.options.collapsed;\r\n\r\n\t\t// makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released\r\n\t\tcontainer.setAttribute('aria-haspopup', true);\r\n\r\n\t\tdisableClickPropagation(container);\r\n\t\tdisableScrollPropagation(container);\r\n\r\n\t\tvar form = this._form = create$1('form', className + '-list');\r\n\r\n\t\tif (collapsed) {\r\n\t\t\tthis._map.on('click', this.collapse, this);\r\n\r\n\t\t\tif (!android) {\r\n\t\t\t\ton(container, {\r\n\t\t\t\t\tmouseenter: this.expand,\r\n\t\t\t\t\tmouseleave: this.collapse\r\n\t\t\t\t}, this);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar link = this._layersLink = create$1('a', className + '-toggle', container);\r\n\t\tlink.href = '#';\r\n\t\tlink.title = 'Layers';\r\n\r\n\t\tif (touch) {\r\n\t\t\ton(link, 'click', stop);\r\n\t\t\ton(link, 'click', this.expand, this);\r\n\t\t} else {\r\n\t\t\ton(link, 'focus', this.expand, this);\r\n\t\t}\r\n\r\n\t\tif (!collapsed) {\r\n\t\t\tthis.expand();\r\n\t\t}\r\n\r\n\t\tthis._baseLayersList = create$1('div', className + '-base', form);\r\n\t\tthis._separator = create$1('div', className + '-separator', form);\r\n\t\tthis._overlaysList = create$1('div', className + '-overlays', form);\r\n\r\n\t\tcontainer.appendChild(form);\r\n\t},\r\n\r\n\t_getLayer: function (id) {\r\n\t\tfor (var i = 0; i < this._layers.length; i++) {\r\n\r\n\t\t\tif (this._layers[i] && stamp(this._layers[i].layer) === id) {\r\n\t\t\t\treturn this._layers[i];\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t_addLayer: function (layer, name, overlay) {\r\n\t\tif (this._map) {\r\n\t\t\tlayer.on('add remove', this._onLayerChange, this);\r\n\t\t}\r\n\r\n\t\tthis._layers.push({\r\n\t\t\tlayer: layer,\r\n\t\t\tname: name,\r\n\t\t\toverlay: overlay\r\n\t\t});\r\n\r\n\t\tif (this.options.sortLayers) {\r\n\t\t\tthis._layers.sort(bind(function (a, b) {\r\n\t\t\t\treturn this.options.sortFunction(a.layer, b.layer, a.name, b.name);\r\n\t\t\t}, this));\r\n\t\t}\r\n\r\n\t\tif (this.options.autoZIndex && layer.setZIndex) {\r\n\t\t\tthis._lastZIndex++;\r\n\t\t\tlayer.setZIndex(this._lastZIndex);\r\n\t\t}\r\n\r\n\t\tthis._expandIfNotCollapsed();\r\n\t},\r\n\r\n\t_update: function () {\r\n\t\tif (!this._container) { return this; }\r\n\r\n\t\tempty(this._baseLayersList);\r\n\t\tempty(this._overlaysList);\r\n\r\n\t\tthis._layerControlInputs = [];\r\n\t\tvar baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;\r\n\r\n\t\tfor (i = 0; i < this._layers.length; i++) {\r\n\t\t\tobj = this._layers[i];\r\n\t\t\tthis._addItem(obj);\r\n\t\t\toverlaysPresent = overlaysPresent || obj.overlay;\r\n\t\t\tbaseLayersPresent = baseLayersPresent || !obj.overlay;\r\n\t\t\tbaseLayersCount += !obj.overlay ? 1 : 0;\r\n\t\t}\r\n\r\n\t\t// Hide base layers section if there's only one layer.\r\n\t\tif (this.options.hideSingleBase) {\r\n\t\t\tbaseLayersPresent = baseLayersPresent && baseLayersCount > 1;\r\n\t\t\tthis._baseLayersList.style.display = baseLayersPresent ? '' : 'none';\r\n\t\t}\r\n\r\n\t\tthis._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_onLayerChange: function (e) {\r\n\t\tif (!this._handlingClick) {\r\n\t\t\tthis._update();\r\n\t\t}\r\n\r\n\t\tvar obj = this._getLayer(stamp(e.target));\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Layer events\r\n\t\t// @event baselayerchange: LayersControlEvent\r\n\t\t// Fired when the base layer is changed through the [layer control](#control-layers).\r\n\t\t// @event overlayadd: LayersControlEvent\r\n\t\t// Fired when an overlay is selected through the [layer control](#control-layers).\r\n\t\t// @event overlayremove: LayersControlEvent\r\n\t\t// Fired when an overlay is deselected through the [layer control](#control-layers).\r\n\t\t// @namespace Control.Layers\r\n\t\tvar type = obj.overlay ?\r\n\t\t\t(e.type === 'add' ? 'overlayadd' : 'overlayremove') :\r\n\t\t\t(e.type === 'add' ? 'baselayerchange' : null);\r\n\r\n\t\tif (type) {\r\n\t\t\tthis._map.fire(type, obj);\r\n\t\t}\r\n\t},\r\n\r\n\t// IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)\r\n\t_createRadioElement: function (name, checked) {\r\n\r\n\t\tvar radioHtml = ' ';\r\n\r\n\t\tvar radioFragment = document.createElement('div');\r\n\t\tradioFragment.innerHTML = radioHtml;\r\n\r\n\t\treturn radioFragment.firstChild;\r\n\t},\r\n\r\n\t_addItem: function (obj) {\r\n\t\tvar label = document.createElement('label'),\r\n\t\t checked = this._map.hasLayer(obj.layer),\r\n\t\t input;\r\n\r\n\t\tif (obj.overlay) {\r\n\t\t\tinput = document.createElement('input');\r\n\t\t\tinput.type = 'checkbox';\r\n\t\t\tinput.className = 'leaflet-control-layers-selector';\r\n\t\t\tinput.defaultChecked = checked;\r\n\t\t} else {\r\n\t\t\tinput = this._createRadioElement('leaflet-base-layers', checked);\r\n\t\t}\r\n\r\n\t\tthis._layerControlInputs.push(input);\r\n\t\tinput.layerId = stamp(obj.layer);\r\n\r\n\t\ton(input, 'click', this._onInputClick, this);\r\n\r\n\t\tvar name = document.createElement('span');\r\n\t\tname.innerHTML = ' ' + obj.name;\r\n\r\n\t\t// Helps from preventing layer control flicker when checkboxes are disabled\r\n\t\t// https://github.com/Leaflet/Leaflet/issues/2771\r\n\t\tvar holder = document.createElement('div');\r\n\r\n\t\tlabel.appendChild(holder);\r\n\t\tholder.appendChild(input);\r\n\t\tholder.appendChild(name);\r\n\r\n\t\tvar container = obj.overlay ? this._overlaysList : this._baseLayersList;\r\n\t\tcontainer.appendChild(label);\r\n\r\n\t\tthis._checkDisabledLayers();\r\n\t\treturn label;\r\n\t},\r\n\r\n\t_onInputClick: function () {\r\n\t\tvar inputs = this._layerControlInputs,\r\n\t\t input, layer;\r\n\t\tvar addedLayers = [],\r\n\t\t removedLayers = [];\r\n\r\n\t\tthis._handlingClick = true;\r\n\r\n\t\tfor (var i = inputs.length - 1; i >= 0; i--) {\r\n\t\t\tinput = inputs[i];\r\n\t\t\tlayer = this._getLayer(input.layerId).layer;\r\n\r\n\t\t\tif (input.checked) {\r\n\t\t\t\taddedLayers.push(layer);\r\n\t\t\t} else if (!input.checked) {\r\n\t\t\t\tremovedLayers.push(layer);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// Bugfix issue 2318: Should remove all old layers before readding new ones\r\n\t\tfor (i = 0; i < removedLayers.length; i++) {\r\n\t\t\tif (this._map.hasLayer(removedLayers[i])) {\r\n\t\t\t\tthis._map.removeLayer(removedLayers[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t\tfor (i = 0; i < addedLayers.length; i++) {\r\n\t\t\tif (!this._map.hasLayer(addedLayers[i])) {\r\n\t\t\t\tthis._map.addLayer(addedLayers[i]);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._handlingClick = false;\r\n\r\n\t\tthis._refocusOnMap();\r\n\t},\r\n\r\n\t_checkDisabledLayers: function () {\r\n\t\tvar inputs = this._layerControlInputs,\r\n\t\t input,\r\n\t\t layer,\r\n\t\t zoom = this._map.getZoom();\r\n\r\n\t\tfor (var i = inputs.length - 1; i >= 0; i--) {\r\n\t\t\tinput = inputs[i];\r\n\t\t\tlayer = this._getLayer(input.layerId).layer;\r\n\t\t\tinput.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||\r\n\t\t\t (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);\r\n\r\n\t\t}\r\n\t},\r\n\r\n\t_expandIfNotCollapsed: function () {\r\n\t\tif (this._map && !this.options.collapsed) {\r\n\t\t\tthis.expand();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_expand: function () {\r\n\t\t// Backward compatibility, remove me in 1.1.\r\n\t\treturn this.expand();\r\n\t},\r\n\r\n\t_collapse: function () {\r\n\t\t// Backward compatibility, remove me in 1.1.\r\n\t\treturn this.collapse();\r\n\t}\r\n\r\n});\r\n\r\n\r\n// @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)\r\n// Creates an attribution control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation.\r\nvar layers = function (baseLayers, overlays, options) {\r\n\treturn new Layers(baseLayers, overlays, options);\r\n};\n\n/*\r\n * @class Control.Zoom\r\n * @aka L.Control.Zoom\r\n * @inherits Control\r\n *\r\n * A basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default unless you set its [`zoomControl` option](#map-zoomcontrol) to `false`. Extends `Control`.\r\n */\r\n\r\nvar Zoom = Control.extend({\r\n\t// @section\r\n\t// @aka Control.Zoom options\r\n\toptions: {\r\n\t\tposition: 'topleft',\r\n\r\n\t\t// @option zoomInText: String = '+'\r\n\t\t// The text set on the 'zoom in' button.\r\n\t\tzoomInText: '+',\r\n\r\n\t\t// @option zoomInTitle: String = 'Zoom in'\r\n\t\t// The title set on the 'zoom in' button.\r\n\t\tzoomInTitle: 'Zoom in',\r\n\r\n\t\t// @option zoomOutText: String = '−'\r\n\t\t// The text set on the 'zoom out' button.\r\n\t\tzoomOutText: '−',\r\n\r\n\t\t// @option zoomOutTitle: String = 'Zoom out'\r\n\t\t// The title set on the 'zoom out' button.\r\n\t\tzoomOutTitle: 'Zoom out'\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tvar zoomName = 'leaflet-control-zoom',\r\n\t\t container = create$1('div', zoomName + ' leaflet-bar'),\r\n\t\t options = this.options;\r\n\r\n\t\tthis._zoomInButton = this._createButton(options.zoomInText, options.zoomInTitle,\r\n\t\t zoomName + '-in', container, this._zoomIn);\r\n\t\tthis._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,\r\n\t\t zoomName + '-out', container, this._zoomOut);\r\n\r\n\t\tthis._updateDisabled();\r\n\t\tmap.on('zoomend zoomlevelschange', this._updateDisabled, this);\r\n\r\n\t\treturn container;\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tmap.off('zoomend zoomlevelschange', this._updateDisabled, this);\r\n\t},\r\n\r\n\tdisable: function () {\r\n\t\tthis._disabled = true;\r\n\t\tthis._updateDisabled();\r\n\t\treturn this;\r\n\t},\r\n\r\n\tenable: function () {\r\n\t\tthis._disabled = false;\r\n\t\tthis._updateDisabled();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_zoomIn: function (e) {\r\n\t\tif (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {\r\n\t\t\tthis._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));\r\n\t\t}\r\n\t},\r\n\r\n\t_zoomOut: function (e) {\r\n\t\tif (!this._disabled && this._map._zoom > this._map.getMinZoom()) {\r\n\t\t\tthis._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));\r\n\t\t}\r\n\t},\r\n\r\n\t_createButton: function (html, title, className, container, fn) {\r\n\t\tvar link = create$1('a', className, container);\r\n\t\tlink.innerHTML = html;\r\n\t\tlink.href = '#';\r\n\t\tlink.title = title;\r\n\r\n\t\t/*\r\n\t\t * Will force screen readers like VoiceOver to read this as \"Zoom in - button\"\r\n\t\t */\r\n\t\tlink.setAttribute('role', 'button');\r\n\t\tlink.setAttribute('aria-label', title);\r\n\r\n\t\tdisableClickPropagation(link);\r\n\t\ton(link, 'click', stop);\r\n\t\ton(link, 'click', fn, this);\r\n\t\ton(link, 'click', this._refocusOnMap, this);\r\n\r\n\t\treturn link;\r\n\t},\r\n\r\n\t_updateDisabled: function () {\r\n\t\tvar map = this._map,\r\n\t\t className = 'leaflet-disabled';\r\n\r\n\t\tremoveClass(this._zoomInButton, className);\r\n\t\tremoveClass(this._zoomOutButton, className);\r\n\r\n\t\tif (this._disabled || map._zoom === map.getMinZoom()) {\r\n\t\t\taddClass(this._zoomOutButton, className);\r\n\t\t}\r\n\t\tif (this._disabled || map._zoom === map.getMaxZoom()) {\r\n\t\t\taddClass(this._zoomInButton, className);\r\n\t\t}\r\n\t}\r\n});\r\n\r\n// @namespace Map\r\n// @section Control options\r\n// @option zoomControl: Boolean = true\r\n// Whether a [zoom control](#control-zoom) is added to the map by default.\r\nMap.mergeOptions({\r\n\tzoomControl: true\r\n});\r\n\r\nMap.addInitHook(function () {\r\n\tif (this.options.zoomControl) {\r\n\t\tthis.zoomControl = new Zoom();\r\n\t\tthis.addControl(this.zoomControl);\r\n\t}\r\n});\r\n\r\n// @namespace Control.Zoom\r\n// @factory L.control.zoom(options: Control.Zoom options)\r\n// Creates a zoom control\r\nvar zoom = function (options) {\r\n\treturn new Zoom(options);\r\n};\n\n/*\n * @class Control.Scale\n * @aka L.Control.Scale\n * @inherits Control\n *\n * A simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial (mi/ft) systems. Extends `Control`.\n *\n * @example\n *\n * ```js\n * L.control.scale().addTo(map);\n * ```\n */\n\nvar Scale = Control.extend({\n\t// @section\n\t// @aka Control.Scale options\n\toptions: {\n\t\tposition: 'bottomleft',\n\n\t\t// @option maxWidth: Number = 100\n\t\t// Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).\n\t\tmaxWidth: 100,\n\n\t\t// @option metric: Boolean = True\n\t\t// Whether to show the metric scale line (m/km).\n\t\tmetric: true,\n\n\t\t// @option imperial: Boolean = True\n\t\t// Whether to show the imperial scale line (mi/ft).\n\t\timperial: true\n\n\t\t// @option updateWhenIdle: Boolean = false\n\t\t// If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).\n\t},\n\n\tonAdd: function (map) {\n\t\tvar className = 'leaflet-control-scale',\n\t\t container = create$1('div', className),\n\t\t options = this.options;\n\n\t\tthis._addScales(options, className + '-line', container);\n\n\t\tmap.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);\n\t\tmap.whenReady(this._update, this);\n\n\t\treturn container;\n\t},\n\n\tonRemove: function (map) {\n\t\tmap.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);\n\t},\n\n\t_addScales: function (options, className, container) {\n\t\tif (options.metric) {\n\t\t\tthis._mScale = create$1('div', className, container);\n\t\t}\n\t\tif (options.imperial) {\n\t\t\tthis._iScale = create$1('div', className, container);\n\t\t}\n\t},\n\n\t_update: function () {\n\t\tvar map = this._map,\n\t\t y = map.getSize().y / 2;\n\n\t\tvar maxMeters = map.distance(\n\t\t\tmap.containerPointToLatLng([0, y]),\n\t\t\tmap.containerPointToLatLng([this.options.maxWidth, y]));\n\n\t\tthis._updateScales(maxMeters);\n\t},\n\n\t_updateScales: function (maxMeters) {\n\t\tif (this.options.metric && maxMeters) {\n\t\t\tthis._updateMetric(maxMeters);\n\t\t}\n\t\tif (this.options.imperial && maxMeters) {\n\t\t\tthis._updateImperial(maxMeters);\n\t\t}\n\t},\n\n\t_updateMetric: function (maxMeters) {\n\t\tvar meters = this._getRoundNum(maxMeters),\n\t\t label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';\n\n\t\tthis._updateScale(this._mScale, label, meters / maxMeters);\n\t},\n\n\t_updateImperial: function (maxMeters) {\n\t\tvar maxFeet = maxMeters * 3.2808399,\n\t\t maxMiles, miles, feet;\n\n\t\tif (maxFeet > 5280) {\n\t\t\tmaxMiles = maxFeet / 5280;\n\t\t\tmiles = this._getRoundNum(maxMiles);\n\t\t\tthis._updateScale(this._iScale, miles + ' mi', miles / maxMiles);\n\n\t\t} else {\n\t\t\tfeet = this._getRoundNum(maxFeet);\n\t\t\tthis._updateScale(this._iScale, feet + ' ft', feet / maxFeet);\n\t\t}\n\t},\n\n\t_updateScale: function (scale, text, ratio) {\n\t\tscale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';\n\t\tscale.innerHTML = text;\n\t},\n\n\t_getRoundNum: function (num) {\n\t\tvar pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),\n\t\t d = num / pow10;\n\n\t\td = d >= 10 ? 10 :\n\t\t d >= 5 ? 5 :\n\t\t d >= 3 ? 3 :\n\t\t d >= 2 ? 2 : 1;\n\n\t\treturn pow10 * d;\n\t}\n});\n\n\n// @factory L.control.scale(options?: Control.Scale options)\n// Creates an scale control with the given options.\nvar scale = function (options) {\n\treturn new Scale(options);\n};\n\n/*\r\n * @class Control.Attribution\r\n * @aka L.Control.Attribution\r\n * @inherits Control\r\n *\r\n * The attribution control allows you to display attribution data in a small text box on a map. It is put on the map by default unless you set its [`attributionControl` option](#map-attributioncontrol) to `false`, and it fetches attribution texts from layers with the [`getAttribution` method](#layer-getattribution) automatically. Extends Control.\r\n */\r\n\r\nvar Attribution = Control.extend({\r\n\t// @section\r\n\t// @aka Control.Attribution options\r\n\toptions: {\r\n\t\tposition: 'bottomright',\r\n\r\n\t\t// @option prefix: String = 'Leaflet'\r\n\t\t// The HTML text shown before the attributions. Pass `false` to disable.\r\n\t\tprefix: 'Leaflet '\r\n\t},\r\n\r\n\tinitialize: function (options) {\r\n\t\tsetOptions(this, options);\r\n\r\n\t\tthis._attributions = {};\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tmap.attributionControl = this;\r\n\t\tthis._container = create$1('div', 'leaflet-control-attribution');\r\n\t\tdisableClickPropagation(this._container);\r\n\r\n\t\t// TODO ugly, refactor\r\n\t\tfor (var i in map._layers) {\r\n\t\t\tif (map._layers[i].getAttribution) {\r\n\t\t\t\tthis.addAttribution(map._layers[i].getAttribution());\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tthis._update();\r\n\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\t// @method setPrefix(prefix: String): this\r\n\t// Sets the text before the attributions.\r\n\tsetPrefix: function (prefix) {\r\n\t\tthis.options.prefix = prefix;\r\n\t\tthis._update();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method addAttribution(text: String): this\r\n\t// Adds an attribution text (e.g. `'Vector data © Mapbox'`).\r\n\taddAttribution: function (text) {\r\n\t\tif (!text) { return this; }\r\n\r\n\t\tif (!this._attributions[text]) {\r\n\t\t\tthis._attributions[text] = 0;\r\n\t\t}\r\n\t\tthis._attributions[text]++;\r\n\r\n\t\tthis._update();\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeAttribution(text: String): this\r\n\t// Removes an attribution text.\r\n\tremoveAttribution: function (text) {\r\n\t\tif (!text) { return this; }\r\n\r\n\t\tif (this._attributions[text]) {\r\n\t\t\tthis._attributions[text]--;\r\n\t\t\tthis._update();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_update: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tvar attribs = [];\r\n\r\n\t\tfor (var i in this._attributions) {\r\n\t\t\tif (this._attributions[i]) {\r\n\t\t\t\tattribs.push(i);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tvar prefixAndAttribs = [];\r\n\r\n\t\tif (this.options.prefix) {\r\n\t\t\tprefixAndAttribs.push(this.options.prefix);\r\n\t\t}\r\n\t\tif (attribs.length) {\r\n\t\t\tprefixAndAttribs.push(attribs.join(', '));\r\n\t\t}\r\n\r\n\t\tthis._container.innerHTML = prefixAndAttribs.join(' | ');\r\n\t}\r\n});\r\n\r\n// @namespace Map\r\n// @section Control options\r\n// @option attributionControl: Boolean = true\r\n// Whether a [attribution control](#control-attribution) is added to the map by default.\r\nMap.mergeOptions({\r\n\tattributionControl: true\r\n});\r\n\r\nMap.addInitHook(function () {\r\n\tif (this.options.attributionControl) {\r\n\t\tnew Attribution().addTo(this);\r\n\t}\r\n});\r\n\r\n// @namespace Control.Attribution\r\n// @factory L.control.attribution(options: Control.Attribution options)\r\n// Creates an attribution control.\r\nvar attribution = function (options) {\r\n\treturn new Attribution(options);\r\n};\n\nControl.Layers = Layers;\nControl.Zoom = Zoom;\nControl.Scale = Scale;\nControl.Attribution = Attribution;\n\ncontrol.layers = layers;\ncontrol.zoom = zoom;\ncontrol.scale = scale;\ncontrol.attribution = attribution;\n\n/*\n\tL.Handler is a base class for handler classes that are used internally to inject\n\tinteraction features like dragging to classes like Map and Marker.\n*/\n\n// @class Handler\n// @aka L.Handler\n// Abstract class for map interaction handlers\n\nvar Handler = Class.extend({\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\t},\n\n\t// @method enable(): this\n\t// Enables the handler\n\tenable: function () {\n\t\tif (this._enabled) { return this; }\n\n\t\tthis._enabled = true;\n\t\tthis.addHooks();\n\t\treturn this;\n\t},\n\n\t// @method disable(): this\n\t// Disables the handler\n\tdisable: function () {\n\t\tif (!this._enabled) { return this; }\n\n\t\tthis._enabled = false;\n\t\tthis.removeHooks();\n\t\treturn this;\n\t},\n\n\t// @method enabled(): Boolean\n\t// Returns `true` if the handler is enabled\n\tenabled: function () {\n\t\treturn !!this._enabled;\n\t}\n\n\t// @section Extension methods\n\t// Classes inheriting from `Handler` must implement the two following methods:\n\t// @method addHooks()\n\t// Called when the handler is enabled, should add event hooks.\n\t// @method removeHooks()\n\t// Called when the handler is disabled, should remove the event hooks added previously.\n});\n\n// @section There is static function which can be called without instantiating L.Handler:\n// @function addTo(map: Map, name: String): this\n// Adds a new Handler to the given map with the given name.\nHandler.addTo = function (map, name) {\n\tmap.addHandler(name, this);\n\treturn this;\n};\n\nvar Mixin = {Events: Events};\n\n/*\r\n * @class Draggable\r\n * @aka L.Draggable\r\n * @inherits Evented\r\n *\r\n * A class for making DOM elements draggable (including touch support).\r\n * Used internally for map and marker dragging. Only works for elements\r\n * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).\r\n *\r\n * @example\r\n * ```js\r\n * var draggable = new L.Draggable(elementToDrag);\r\n * draggable.enable();\r\n * ```\r\n */\r\n\r\nvar START = touch ? 'touchstart mousedown' : 'mousedown';\r\nvar END = {\r\n\tmousedown: 'mouseup',\r\n\ttouchstart: 'touchend',\r\n\tpointerdown: 'touchend',\r\n\tMSPointerDown: 'touchend'\r\n};\r\nvar MOVE = {\r\n\tmousedown: 'mousemove',\r\n\ttouchstart: 'touchmove',\r\n\tpointerdown: 'touchmove',\r\n\tMSPointerDown: 'touchmove'\r\n};\r\n\r\n\r\nvar Draggable = Evented.extend({\r\n\r\n\toptions: {\r\n\t\t// @section\r\n\t\t// @aka Draggable options\r\n\t\t// @option clickTolerance: Number = 3\r\n\t\t// The max number of pixels a user can shift the mouse pointer during a click\r\n\t\t// for it to be considered a valid click (as opposed to a mouse drag).\r\n\t\tclickTolerance: 3\r\n\t},\r\n\r\n\t// @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options)\r\n\t// Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).\r\n\tinitialize: function (element, dragStartTarget, preventOutline$$1, options) {\r\n\t\tsetOptions(this, options);\r\n\r\n\t\tthis._element = element;\r\n\t\tthis._dragStartTarget = dragStartTarget || element;\r\n\t\tthis._preventOutline = preventOutline$$1;\r\n\t},\r\n\r\n\t// @method enable()\r\n\t// Enables the dragging ability\r\n\tenable: function () {\r\n\t\tif (this._enabled) { return; }\r\n\r\n\t\ton(this._dragStartTarget, START, this._onDown, this);\r\n\r\n\t\tthis._enabled = true;\r\n\t},\r\n\r\n\t// @method disable()\r\n\t// Disables the dragging ability\r\n\tdisable: function () {\r\n\t\tif (!this._enabled) { return; }\r\n\r\n\t\t// If we're currently dragging this draggable,\r\n\t\t// disabling it counts as first ending the drag.\r\n\t\tif (Draggable._dragging === this) {\r\n\t\t\tthis.finishDrag();\r\n\t\t}\r\n\r\n\t\toff(this._dragStartTarget, START, this._onDown, this);\r\n\r\n\t\tthis._enabled = false;\r\n\t\tthis._moved = false;\r\n\t},\r\n\r\n\t_onDown: function (e) {\r\n\t\t// Ignore simulated events, since we handle both touch and\r\n\t\t// mouse explicitly; otherwise we risk getting duplicates of\r\n\t\t// touch events, see #4315.\r\n\t\t// Also ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (e._simulated || !this._enabled) { return; }\r\n\r\n\t\tthis._moved = false;\r\n\r\n\t\tif (hasClass(this._element, 'leaflet-zoom-anim')) { return; }\r\n\r\n\t\tif (Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }\r\n\t\tDraggable._dragging = this; // Prevent dragging multiple objects at once.\r\n\r\n\t\tif (this._preventOutline) {\r\n\t\t\tpreventOutline(this._element);\r\n\t\t}\r\n\r\n\t\tdisableImageDrag();\r\n\t\tdisableTextSelection();\r\n\r\n\t\tif (this._moving) { return; }\r\n\r\n\t\t// @event down: Event\r\n\t\t// Fired when a drag is about to start.\r\n\t\tthis.fire('down');\r\n\r\n\t\tvar first = e.touches ? e.touches[0] : e;\r\n\r\n\t\tthis._startPoint = new Point(first.clientX, first.clientY);\r\n\r\n\t\ton(document, MOVE[e.type], this._onMove, this);\r\n\t\ton(document, END[e.type], this._onUp, this);\r\n\t},\r\n\r\n\t_onMove: function (e) {\r\n\t\t// Ignore simulated events, since we handle both touch and\r\n\t\t// mouse explicitly; otherwise we risk getting duplicates of\r\n\t\t// touch events, see #4315.\r\n\t\t// Also ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (e._simulated || !this._enabled) { return; }\r\n\r\n\t\tif (e.touches && e.touches.length > 1) {\r\n\t\t\tthis._moved = true;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tvar first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),\r\n\t\t newPoint = new Point(first.clientX, first.clientY),\r\n\t\t offset = newPoint.subtract(this._startPoint);\r\n\r\n\t\tif (!offset.x && !offset.y) { return; }\r\n\t\tif (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; }\r\n\r\n\t\tpreventDefault(e);\r\n\r\n\t\tif (!this._moved) {\r\n\t\t\t// @event dragstart: Event\r\n\t\t\t// Fired when a drag starts\r\n\t\t\tthis.fire('dragstart');\r\n\r\n\t\t\tthis._moved = true;\r\n\t\t\tthis._startPos = getPosition(this._element).subtract(offset);\r\n\r\n\t\t\taddClass(document.body, 'leaflet-dragging');\r\n\r\n\t\t\tthis._lastTarget = e.target || e.srcElement;\r\n\t\t\t// IE and Edge do not give the element, so fetch it\r\n\t\t\t// if necessary\r\n\t\t\tif ((window.SVGElementInstance) && (this._lastTarget instanceof SVGElementInstance)) {\r\n\t\t\t\tthis._lastTarget = this._lastTarget.correspondingUseElement;\r\n\t\t\t}\r\n\t\t\taddClass(this._lastTarget, 'leaflet-drag-target');\r\n\t\t}\r\n\r\n\t\tthis._newPos = this._startPos.add(offset);\r\n\t\tthis._moving = true;\r\n\r\n\t\tcancelAnimFrame(this._animRequest);\r\n\t\tthis._lastEvent = e;\r\n\t\tthis._animRequest = requestAnimFrame(this._updatePosition, this, true);\r\n\t},\r\n\r\n\t_updatePosition: function () {\r\n\t\tvar e = {originalEvent: this._lastEvent};\r\n\r\n\t\t// @event predrag: Event\r\n\t\t// Fired continuously during dragging *before* each corresponding\r\n\t\t// update of the element's position.\r\n\t\tthis.fire('predrag', e);\r\n\t\tsetPosition(this._element, this._newPos);\r\n\r\n\t\t// @event drag: Event\r\n\t\t// Fired continuously during dragging.\r\n\t\tthis.fire('drag', e);\r\n\t},\r\n\r\n\t_onUp: function (e) {\r\n\t\t// Ignore simulated events, since we handle both touch and\r\n\t\t// mouse explicitly; otherwise we risk getting duplicates of\r\n\t\t// touch events, see #4315.\r\n\t\t// Also ignore the event if disabled; this happens in IE11\r\n\t\t// under some circumstances, see #3666.\r\n\t\tif (e._simulated || !this._enabled) { return; }\r\n\t\tthis.finishDrag();\r\n\t},\r\n\r\n\tfinishDrag: function () {\r\n\t\tremoveClass(document.body, 'leaflet-dragging');\r\n\r\n\t\tif (this._lastTarget) {\r\n\t\t\tremoveClass(this._lastTarget, 'leaflet-drag-target');\r\n\t\t\tthis._lastTarget = null;\r\n\t\t}\r\n\r\n\t\tfor (var i in MOVE) {\r\n\t\t\toff(document, MOVE[i], this._onMove, this);\r\n\t\t\toff(document, END[i], this._onUp, this);\r\n\t\t}\r\n\r\n\t\tenableImageDrag();\r\n\t\tenableTextSelection();\r\n\r\n\t\tif (this._moved && this._moving) {\r\n\t\t\t// ensure drag is not fired after dragend\r\n\t\t\tcancelAnimFrame(this._animRequest);\r\n\r\n\t\t\t// @event dragend: DragEndEvent\r\n\t\t\t// Fired when the drag ends.\r\n\t\t\tthis.fire('dragend', {\r\n\t\t\t\tdistance: this._newPos.distanceTo(this._startPos)\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tthis._moving = false;\r\n\t\tDraggable._dragging = false;\r\n\t}\r\n\r\n});\n\n/*\r\n * @namespace LineUtil\r\n *\r\n * Various utility functions for polyline points processing, used by Leaflet internally to make polylines lightning-fast.\r\n */\r\n\r\n// Simplify polyline with vertex reduction and Douglas-Peucker simplification.\r\n// Improves rendering performance dramatically by lessening the number of points to draw.\r\n\r\n// @function simplify(points: Point[], tolerance: Number): Point[]\r\n// Dramatically reduces the number of points in a polyline while retaining\r\n// its shape and returns a new array of simplified points, using the\r\n// [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm).\r\n// Used for a huge performance boost when processing/displaying Leaflet polylines for\r\n// each zoom level and also reducing visual noise. tolerance affects the amount of\r\n// simplification (lesser value means higher quality but slower and with more points).\r\n// Also released as a separated micro-library [Simplify.js](http://mourner.github.com/simplify-js/).\r\nfunction simplify(points, tolerance) {\r\n\tif (!tolerance || !points.length) {\r\n\t\treturn points.slice();\r\n\t}\r\n\r\n\tvar sqTolerance = tolerance * tolerance;\r\n\r\n\t // stage 1: vertex reduction\r\n\t points = _reducePoints(points, sqTolerance);\r\n\r\n\t // stage 2: Douglas-Peucker simplification\r\n\t points = _simplifyDP(points, sqTolerance);\r\n\r\n\treturn points;\r\n}\r\n\r\n// @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number\r\n// Returns the distance between point `p` and segment `p1` to `p2`.\r\nfunction pointToSegmentDistance(p, p1, p2) {\r\n\treturn Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true));\r\n}\r\n\r\n// @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number\r\n// Returns the closest point from a point `p` on a segment `p1` to `p2`.\r\nfunction closestPointOnSegment(p, p1, p2) {\r\n\treturn _sqClosestPointOnSegment(p, p1, p2);\r\n}\r\n\r\n// Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm\r\nfunction _simplifyDP(points, sqTolerance) {\r\n\r\n\tvar len = points.length,\r\n\t ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,\r\n\t markers = new ArrayConstructor(len);\r\n\r\n\t markers[0] = markers[len - 1] = 1;\r\n\r\n\t_simplifyDPStep(points, markers, sqTolerance, 0, len - 1);\r\n\r\n\tvar i,\r\n\t newPoints = [];\r\n\r\n\tfor (i = 0; i < len; i++) {\r\n\t\tif (markers[i]) {\r\n\t\t\tnewPoints.push(points[i]);\r\n\t\t}\r\n\t}\r\n\r\n\treturn newPoints;\r\n}\r\n\r\nfunction _simplifyDPStep(points, markers, sqTolerance, first, last) {\r\n\r\n\tvar maxSqDist = 0,\r\n\tindex, i, sqDist;\r\n\r\n\tfor (i = first + 1; i <= last - 1; i++) {\r\n\t\tsqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true);\r\n\r\n\t\tif (sqDist > maxSqDist) {\r\n\t\t\tindex = i;\r\n\t\t\tmaxSqDist = sqDist;\r\n\t\t}\r\n\t}\r\n\r\n\tif (maxSqDist > sqTolerance) {\r\n\t\tmarkers[index] = 1;\r\n\r\n\t\t_simplifyDPStep(points, markers, sqTolerance, first, index);\r\n\t\t_simplifyDPStep(points, markers, sqTolerance, index, last);\r\n\t}\r\n}\r\n\r\n// reduce points that are too close to each other to a single point\r\nfunction _reducePoints(points, sqTolerance) {\r\n\tvar reducedPoints = [points[0]];\r\n\r\n\tfor (var i = 1, prev = 0, len = points.length; i < len; i++) {\r\n\t\tif (_sqDist(points[i], points[prev]) > sqTolerance) {\r\n\t\t\treducedPoints.push(points[i]);\r\n\t\t\tprev = i;\r\n\t\t}\r\n\t}\r\n\tif (prev < len - 1) {\r\n\t\treducedPoints.push(points[len - 1]);\r\n\t}\r\n\treturn reducedPoints;\r\n}\r\n\r\nvar _lastCode;\r\n\r\n// @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean\r\n// Clips the segment a to b by rectangular bounds with the\r\n// [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm)\r\n// (modifying the segment points directly!). Used by Leaflet to only show polyline\r\n// points that are on the screen or near, increasing performance.\r\nfunction clipSegment(a, b, bounds, useLastCode, round) {\r\n\tvar codeA = useLastCode ? _lastCode : _getBitCode(a, bounds),\r\n\t codeB = _getBitCode(b, bounds),\r\n\r\n\t codeOut, p, newCode;\r\n\r\n\t // save 2nd code to avoid calculating it on the next segment\r\n\t _lastCode = codeB;\r\n\r\n\twhile (true) {\r\n\t\t// if a,b is inside the clip window (trivial accept)\r\n\t\tif (!(codeA | codeB)) {\r\n\t\t\treturn [a, b];\r\n\t\t}\r\n\r\n\t\t// if a,b is outside the clip window (trivial reject)\r\n\t\tif (codeA & codeB) {\r\n\t\t\treturn false;\r\n\t\t}\r\n\r\n\t\t// other cases\r\n\t\tcodeOut = codeA || codeB;\r\n\t\tp = _getEdgeIntersection(a, b, codeOut, bounds, round);\r\n\t\tnewCode = _getBitCode(p, bounds);\r\n\r\n\t\tif (codeOut === codeA) {\r\n\t\t\ta = p;\r\n\t\t\tcodeA = newCode;\r\n\t\t} else {\r\n\t\t\tb = p;\r\n\t\t\tcodeB = newCode;\r\n\t\t}\r\n\t}\r\n}\r\n\r\nfunction _getEdgeIntersection(a, b, code, bounds, round) {\r\n\tvar dx = b.x - a.x,\r\n\t dy = b.y - a.y,\r\n\t min = bounds.min,\r\n\t max = bounds.max,\r\n\t x, y;\r\n\r\n\tif (code & 8) { // top\r\n\t\tx = a.x + dx * (max.y - a.y) / dy;\r\n\t\ty = max.y;\r\n\r\n\t} else if (code & 4) { // bottom\r\n\t\tx = a.x + dx * (min.y - a.y) / dy;\r\n\t\ty = min.y;\r\n\r\n\t} else if (code & 2) { // right\r\n\t\tx = max.x;\r\n\t\ty = a.y + dy * (max.x - a.x) / dx;\r\n\r\n\t} else if (code & 1) { // left\r\n\t\tx = min.x;\r\n\t\ty = a.y + dy * (min.x - a.x) / dx;\r\n\t}\r\n\r\n\treturn new Point(x, y, round);\r\n}\r\n\r\nfunction _getBitCode(p, bounds) {\r\n\tvar code = 0;\r\n\r\n\tif (p.x < bounds.min.x) { // left\r\n\t\tcode |= 1;\r\n\t} else if (p.x > bounds.max.x) { // right\r\n\t\tcode |= 2;\r\n\t}\r\n\r\n\tif (p.y < bounds.min.y) { // bottom\r\n\t\tcode |= 4;\r\n\t} else if (p.y > bounds.max.y) { // top\r\n\t\tcode |= 8;\r\n\t}\r\n\r\n\treturn code;\r\n}\r\n\r\n// square distance (to avoid unnecessary Math.sqrt calls)\r\nfunction _sqDist(p1, p2) {\r\n\tvar dx = p2.x - p1.x,\r\n\t dy = p2.y - p1.y;\r\n\treturn dx * dx + dy * dy;\r\n}\r\n\r\n// return closest point on segment or distance to that point\r\nfunction _sqClosestPointOnSegment(p, p1, p2, sqDist) {\r\n\tvar x = p1.x,\r\n\t y = p1.y,\r\n\t dx = p2.x - x,\r\n\t dy = p2.y - y,\r\n\t dot = dx * dx + dy * dy,\r\n\t t;\r\n\r\n\tif (dot > 0) {\r\n\t\tt = ((p.x - x) * dx + (p.y - y) * dy) / dot;\r\n\r\n\t\tif (t > 1) {\r\n\t\t\tx = p2.x;\r\n\t\t\ty = p2.y;\r\n\t\t} else if (t > 0) {\r\n\t\t\tx += dx * t;\r\n\t\t\ty += dy * t;\r\n\t\t}\r\n\t}\r\n\r\n\tdx = p.x - x;\r\n\tdy = p.y - y;\r\n\r\n\treturn sqDist ? dx * dx + dy * dy : new Point(x, y);\r\n}\r\n\r\n\r\n// @function isFlat(latlngs: LatLng[]): Boolean\r\n// Returns true if `latlngs` is a flat array, false is nested.\r\nfunction isFlat(latlngs) {\r\n\treturn !isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');\r\n}\r\n\r\nfunction _flat(latlngs) {\r\n\tconsole.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.');\r\n\treturn isFlat(latlngs);\r\n}\r\n\n\nvar LineUtil = (Object.freeze || Object)({\n\tsimplify: simplify,\n\tpointToSegmentDistance: pointToSegmentDistance,\n\tclosestPointOnSegment: closestPointOnSegment,\n\tclipSegment: clipSegment,\n\t_getEdgeIntersection: _getEdgeIntersection,\n\t_getBitCode: _getBitCode,\n\t_sqClosestPointOnSegment: _sqClosestPointOnSegment,\n\tisFlat: isFlat,\n\t_flat: _flat\n});\n\n/*\r\n * @namespace PolyUtil\r\n * Various utility functions for polygon geometries.\r\n */\r\n\r\n/* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]\r\n * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).\r\n * Used by Leaflet to only show polygon points that are on the screen or near, increasing\r\n * performance. Note that polygon points needs different algorithm for clipping\r\n * than polyline, so there's a separate method for it.\r\n */\r\nfunction clipPolygon(points, bounds, round) {\r\n\tvar clippedPoints,\r\n\t edges = [1, 4, 2, 8],\r\n\t i, j, k,\r\n\t a, b,\r\n\t len, edge, p;\r\n\r\n\tfor (i = 0, len = points.length; i < len; i++) {\r\n\t\tpoints[i]._code = _getBitCode(points[i], bounds);\r\n\t}\r\n\r\n\t// for each edge (left, bottom, right, top)\r\n\tfor (k = 0; k < 4; k++) {\r\n\t\tedge = edges[k];\r\n\t\tclippedPoints = [];\r\n\r\n\t\tfor (i = 0, len = points.length, j = len - 1; i < len; j = i++) {\r\n\t\t\ta = points[i];\r\n\t\t\tb = points[j];\r\n\r\n\t\t\t// if a is inside the clip window\r\n\t\t\tif (!(a._code & edge)) {\r\n\t\t\t\t// if b is outside the clip window (a->b goes out of screen)\r\n\t\t\t\tif (b._code & edge) {\r\n\t\t\t\t\tp = _getEdgeIntersection(b, a, edge, bounds, round);\r\n\t\t\t\t\tp._code = _getBitCode(p, bounds);\r\n\t\t\t\t\tclippedPoints.push(p);\r\n\t\t\t\t}\r\n\t\t\t\tclippedPoints.push(a);\r\n\r\n\t\t\t// else if b is inside the clip window (a->b enters the screen)\r\n\t\t\t} else if (!(b._code & edge)) {\r\n\t\t\t\tp = _getEdgeIntersection(b, a, edge, bounds, round);\r\n\t\t\t\tp._code = _getBitCode(p, bounds);\r\n\t\t\t\tclippedPoints.push(p);\r\n\t\t\t}\r\n\t\t}\r\n\t\tpoints = clippedPoints;\r\n\t}\r\n\r\n\treturn points;\r\n}\r\n\n\nvar PolyUtil = (Object.freeze || Object)({\n\tclipPolygon: clipPolygon\n});\n\n/*\r\n * @namespace Projection\r\n * @section\r\n * Leaflet comes with a set of already defined Projections out of the box:\r\n *\r\n * @projection L.Projection.LonLat\r\n *\r\n * Equirectangular, or Plate Carree projection — the most simple projection,\r\n * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as\r\n * latitude. Also suitable for flat worlds, e.g. game maps. Used by the\r\n * `EPSG:4326` and `Simple` CRS.\r\n */\r\n\r\nvar LonLat = {\r\n\tproject: function (latlng) {\r\n\t\treturn new Point(latlng.lng, latlng.lat);\r\n\t},\r\n\r\n\tunproject: function (point) {\r\n\t\treturn new LatLng(point.y, point.x);\r\n\t},\r\n\r\n\tbounds: new Bounds([-180, -90], [180, 90])\r\n};\n\n/*\r\n * @namespace Projection\r\n * @projection L.Projection.Mercator\r\n *\r\n * Elliptical Mercator projection — more complex than Spherical Mercator. Takes into account that Earth is a geoid, not a perfect sphere. Used by the EPSG:3395 CRS.\r\n */\r\n\r\nvar Mercator = {\r\n\tR: 6378137,\r\n\tR_MINOR: 6356752.314245179,\r\n\r\n\tbounds: new Bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]),\r\n\r\n\tproject: function (latlng) {\r\n\t\tvar d = Math.PI / 180,\r\n\t\t r = this.R,\r\n\t\t y = latlng.lat * d,\r\n\t\t tmp = this.R_MINOR / r,\r\n\t\t e = Math.sqrt(1 - tmp * tmp),\r\n\t\t con = e * Math.sin(y);\r\n\r\n\t\tvar ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);\r\n\t\ty = -r * Math.log(Math.max(ts, 1E-10));\r\n\r\n\t\treturn new Point(latlng.lng * d * r, y);\r\n\t},\r\n\r\n\tunproject: function (point) {\r\n\t\tvar d = 180 / Math.PI,\r\n\t\t r = this.R,\r\n\t\t tmp = this.R_MINOR / r,\r\n\t\t e = Math.sqrt(1 - tmp * tmp),\r\n\t\t ts = Math.exp(-point.y / r),\r\n\t\t phi = Math.PI / 2 - 2 * Math.atan(ts);\r\n\r\n\t\tfor (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {\r\n\t\t\tcon = e * Math.sin(phi);\r\n\t\t\tcon = Math.pow((1 - con) / (1 + con), e / 2);\r\n\t\t\tdphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;\r\n\t\t\tphi += dphi;\r\n\t\t}\r\n\r\n\t\treturn new LatLng(phi * d, point.x * d / r);\r\n\t}\r\n};\n\n/*\n * @class Projection\n\n * An object with methods for projecting geographical coordinates of the world onto\n * a flat surface (and back). See [Map projection](http://en.wikipedia.org/wiki/Map_projection).\n\n * @property bounds: Bounds\n * The bounds (specified in CRS units) where the projection is valid\n\n * @method project(latlng: LatLng): Point\n * Projects geographical coordinates into a 2D point.\n * Only accepts actual `L.LatLng` instances, not arrays.\n\n * @method unproject(point: Point): LatLng\n * The inverse of `project`. Projects a 2D point into a geographical location.\n * Only accepts actual `L.Point` instances, not arrays.\n\n * Note that the projection instances do not inherit from Leafet's `Class` object,\n * and can't be instantiated. Also, new classes can't inherit from them,\n * and methods can't be added to them with the `include` function.\n\n */\n\n\n\n\nvar index = (Object.freeze || Object)({\n\tLonLat: LonLat,\n\tMercator: Mercator,\n\tSphericalMercator: SphericalMercator\n});\n\n/*\r\n * @namespace CRS\r\n * @crs L.CRS.EPSG3395\r\n *\r\n * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.\r\n */\r\nvar EPSG3395 = extend({}, Earth, {\r\n\tcode: 'EPSG:3395',\r\n\tprojection: Mercator,\r\n\r\n\ttransformation: (function () {\r\n\t\tvar scale = 0.5 / (Math.PI * Mercator.R);\r\n\t\treturn toTransformation(scale, 0.5, -scale, 0.5);\r\n\t}())\r\n});\n\n/*\r\n * @namespace CRS\r\n * @crs L.CRS.EPSG4326\r\n *\r\n * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.\r\n *\r\n * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic),\r\n * which is a breaking change from 0.7.x behaviour. If you are using a `TileLayer`\r\n * with this CRS, ensure that there are two 256x256 pixel tiles covering the\r\n * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90),\r\n * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set.\r\n */\r\n\r\nvar EPSG4326 = extend({}, Earth, {\r\n\tcode: 'EPSG:4326',\r\n\tprojection: LonLat,\r\n\ttransformation: toTransformation(1 / 180, 1, -1 / 180, 0.5)\r\n});\n\n/*\n * @namespace CRS\n * @crs L.CRS.Simple\n *\n * A simple CRS that maps longitude and latitude into `x` and `y` directly.\n * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`\n * axis should still be inverted (going from bottom to top). `distance()` returns\n * simple euclidean distance.\n */\n\nvar Simple = extend({}, CRS, {\n\tprojection: LonLat,\n\ttransformation: toTransformation(1, 0, -1, 0),\n\n\tscale: function (zoom) {\n\t\treturn Math.pow(2, zoom);\n\t},\n\n\tzoom: function (scale) {\n\t\treturn Math.log(scale) / Math.LN2;\n\t},\n\n\tdistance: function (latlng1, latlng2) {\n\t\tvar dx = latlng2.lng - latlng1.lng,\n\t\t dy = latlng2.lat - latlng1.lat;\n\n\t\treturn Math.sqrt(dx * dx + dy * dy);\n\t},\n\n\tinfinite: true\n});\n\nCRS.Earth = Earth;\nCRS.EPSG3395 = EPSG3395;\nCRS.EPSG3857 = EPSG3857;\nCRS.EPSG900913 = EPSG900913;\nCRS.EPSG4326 = EPSG4326;\nCRS.Simple = Simple;\n\n/*\n * @class Layer\n * @inherits Evented\n * @aka L.Layer\n * @aka ILayer\n *\n * A set of methods from the Layer base class that all Leaflet layers use.\n * Inherits all methods, options and events from `L.Evented`.\n *\n * @example\n *\n * ```js\n * var layer = L.Marker(latlng).addTo(map);\n * layer.addTo(map);\n * layer.remove();\n * ```\n *\n * @event add: Event\n * Fired after the layer is added to a map\n *\n * @event remove: Event\n * Fired after the layer is removed from a map\n */\n\n\nvar Layer = Evented.extend({\n\n\t// Classes extending `L.Layer` will inherit the following options:\n\toptions: {\n\t\t// @option pane: String = 'overlayPane'\n\t\t// By default the layer will be added to the map's [overlay pane](#map-overlaypane). Overriding this option will cause the layer to be placed on another pane by default.\n\t\tpane: 'overlayPane',\n\n\t\t// @option attribution: String = null\n\t\t// String to be shown in the attribution control, describes the layer data, e.g. \"© Mapbox\".\n\t\tattribution: null,\n\n\t\tbubblingMouseEvents: true\n\t},\n\n\t/* @section\n\t * Classes extending `L.Layer` will inherit the following methods:\n\t *\n\t * @method addTo(map: Map|LayerGroup): this\n\t * Adds the layer to the given map or layer group.\n\t */\n\taddTo: function (map) {\n\t\tmap.addLayer(this);\n\t\treturn this;\n\t},\n\n\t// @method remove: this\n\t// Removes the layer from the map it is currently active on.\n\tremove: function () {\n\t\treturn this.removeFrom(this._map || this._mapToAdd);\n\t},\n\n\t// @method removeFrom(map: Map): this\n\t// Removes the layer from the given map\n\tremoveFrom: function (obj) {\n\t\tif (obj) {\n\t\t\tobj.removeLayer(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getPane(name? : String): HTMLElement\n\t// Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer.\n\tgetPane: function (name) {\n\t\treturn this._map.getPane(name ? (this.options[name] || name) : this.options.pane);\n\t},\n\n\taddInteractiveTarget: function (targetEl) {\n\t\tthis._map._targets[stamp(targetEl)] = this;\n\t\treturn this;\n\t},\n\n\tremoveInteractiveTarget: function (targetEl) {\n\t\tdelete this._map._targets[stamp(targetEl)];\n\t\treturn this;\n\t},\n\n\t// @method getAttribution: String\n\t// Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution).\n\tgetAttribution: function () {\n\t\treturn this.options.attribution;\n\t},\n\n\t_layerAdd: function (e) {\n\t\tvar map = e.target;\n\n\t\t// check in case layer gets added and then removed before the map is ready\n\t\tif (!map.hasLayer(this)) { return; }\n\n\t\tthis._map = map;\n\t\tthis._zoomAnimated = map._zoomAnimated;\n\n\t\tif (this.getEvents) {\n\t\t\tvar events = this.getEvents();\n\t\t\tmap.on(events, this);\n\t\t\tthis.once('remove', function () {\n\t\t\t\tmap.off(events, this);\n\t\t\t}, this);\n\t\t}\n\n\t\tthis.onAdd(map);\n\n\t\tif (this.getAttribution && map.attributionControl) {\n\t\t\tmap.attributionControl.addAttribution(this.getAttribution());\n\t\t}\n\n\t\tthis.fire('add');\n\t\tmap.fire('layeradd', {layer: this});\n\t}\n});\n\n/* @section Extension methods\n * @uninheritable\n *\n * Every layer should extend from `L.Layer` and (re-)implement the following methods.\n *\n * @method onAdd(map: Map): this\n * Should contain code that creates DOM elements for the layer, adds them to `map panes` where they should belong and puts listeners on relevant map events. Called on [`map.addLayer(layer)`](#map-addlayer).\n *\n * @method onRemove(map: Map): this\n * Should contain all clean up code that removes the layer's elements from the DOM and removes listeners previously added in [`onAdd`](#layer-onadd). Called on [`map.removeLayer(layer)`](#map-removelayer).\n *\n * @method getEvents(): Object\n * This optional method should return an object like `{ viewreset: this._reset }` for [`addEventListener`](#evented-addeventlistener). The event handlers in this object will be automatically added and removed from the map with your layer.\n *\n * @method getAttribution(): String\n * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible.\n *\n * @method beforeAdd(map: Map): this\n * Optional method. Called on [`map.addLayer(layer)`](#map-addlayer), before the layer is added to the map, before events are initialized, without waiting until the map is in a usable state. Use for early initialization only.\n */\n\n\n/* @namespace Map\n * @section Layer events\n *\n * @event layeradd: LayerEvent\n * Fired when a new layer is added to the map.\n *\n * @event layerremove: LayerEvent\n * Fired when some layer is removed from the map\n *\n * @section Methods for Layers and Controls\n */\nMap.include({\n\t// @method addLayer(layer: Layer): this\n\t// Adds the given layer to the map\n\taddLayer: function (layer) {\n\t\tif (!layer._layerAdd) {\n\t\t\tthrow new Error('The provided object is not a Layer.');\n\t\t}\n\n\t\tvar id = stamp(layer);\n\t\tif (this._layers[id]) { return this; }\n\t\tthis._layers[id] = layer;\n\n\t\tlayer._mapToAdd = this;\n\n\t\tif (layer.beforeAdd) {\n\t\t\tlayer.beforeAdd(this);\n\t\t}\n\n\t\tthis.whenReady(layer._layerAdd, layer);\n\n\t\treturn this;\n\t},\n\n\t// @method removeLayer(layer: Layer): this\n\t// Removes the given layer from the map.\n\tremoveLayer: function (layer) {\n\t\tvar id = stamp(layer);\n\n\t\tif (!this._layers[id]) { return this; }\n\n\t\tif (this._loaded) {\n\t\t\tlayer.onRemove(this);\n\t\t}\n\n\t\tif (layer.getAttribution && this.attributionControl) {\n\t\t\tthis.attributionControl.removeAttribution(layer.getAttribution());\n\t\t}\n\n\t\tdelete this._layers[id];\n\n\t\tif (this._loaded) {\n\t\t\tthis.fire('layerremove', {layer: layer});\n\t\t\tlayer.fire('remove');\n\t\t}\n\n\t\tlayer._map = layer._mapToAdd = null;\n\n\t\treturn this;\n\t},\n\n\t// @method hasLayer(layer: Layer): Boolean\n\t// Returns `true` if the given layer is currently added to the map\n\thasLayer: function (layer) {\n\t\treturn !!layer && (stamp(layer) in this._layers);\n\t},\n\n\t/* @method eachLayer(fn: Function, context?: Object): this\n\t * Iterates over the layers of the map, optionally specifying context of the iterator function.\n\t * ```\n\t * map.eachLayer(function(layer){\n\t * layer.bindPopup('Hello');\n\t * });\n\t * ```\n\t */\n\teachLayer: function (method, context) {\n\t\tfor (var i in this._layers) {\n\t\t\tmethod.call(context, this._layers[i]);\n\t\t}\n\t\treturn this;\n\t},\n\n\t_addLayers: function (layers) {\n\t\tlayers = layers ? (isArray(layers) ? layers : [layers]) : [];\n\n\t\tfor (var i = 0, len = layers.length; i < len; i++) {\n\t\t\tthis.addLayer(layers[i]);\n\t\t}\n\t},\n\n\t_addZoomLimit: function (layer) {\n\t\tif (isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {\n\t\t\tthis._zoomBoundLayers[stamp(layer)] = layer;\n\t\t\tthis._updateZoomLevels();\n\t\t}\n\t},\n\n\t_removeZoomLimit: function (layer) {\n\t\tvar id = stamp(layer);\n\n\t\tif (this._zoomBoundLayers[id]) {\n\t\t\tdelete this._zoomBoundLayers[id];\n\t\t\tthis._updateZoomLevels();\n\t\t}\n\t},\n\n\t_updateZoomLevels: function () {\n\t\tvar minZoom = Infinity,\n\t\t maxZoom = -Infinity,\n\t\t oldZoomSpan = this._getZoomSpan();\n\n\t\tfor (var i in this._zoomBoundLayers) {\n\t\t\tvar options = this._zoomBoundLayers[i].options;\n\n\t\t\tminZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom);\n\t\t\tmaxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom);\n\t\t}\n\n\t\tthis._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom;\n\t\tthis._layersMinZoom = minZoom === Infinity ? undefined : minZoom;\n\n\t\t// @section Map state change events\n\t\t// @event zoomlevelschange: Event\n\t\t// Fired when the number of zoomlevels on the map is changed due\n\t\t// to adding or removing a layer.\n\t\tif (oldZoomSpan !== this._getZoomSpan()) {\n\t\t\tthis.fire('zoomlevelschange');\n\t\t}\n\n\t\tif (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) {\n\t\t\tthis.setZoom(this._layersMaxZoom);\n\t\t}\n\t\tif (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) {\n\t\t\tthis.setZoom(this._layersMinZoom);\n\t\t}\n\t}\n});\n\n/*\r\n * @class LayerGroup\r\n * @aka L.LayerGroup\r\n * @inherits Layer\r\n *\r\n * Used to group several layers and handle them as one. If you add it to the map,\r\n * any layers added or removed from the group will be added/removed on the map as\r\n * well. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.layerGroup([marker1, marker2])\r\n * \t.addLayer(polyline)\r\n * \t.addTo(map);\r\n * ```\r\n */\r\n\r\nvar LayerGroup = Layer.extend({\r\n\r\n\tinitialize: function (layers, options) {\r\n\t\tsetOptions(this, options);\r\n\r\n\t\tthis._layers = {};\r\n\r\n\t\tvar i, len;\r\n\r\n\t\tif (layers) {\r\n\t\t\tfor (i = 0, len = layers.length; i < len; i++) {\r\n\t\t\t\tthis.addLayer(layers[i]);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addLayer(layer: Layer): this\r\n\t// Adds the given layer to the group.\r\n\taddLayer: function (layer) {\r\n\t\tvar id = this.getLayerId(layer);\r\n\r\n\t\tthis._layers[id] = layer;\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._map.addLayer(layer);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method removeLayer(layer: Layer): this\r\n\t// Removes the given layer from the group.\r\n\t// @alternative\r\n\t// @method removeLayer(id: Number): this\r\n\t// Removes the layer with the given internal ID from the group.\r\n\tremoveLayer: function (layer) {\r\n\t\tvar id = layer in this._layers ? layer : this.getLayerId(layer);\r\n\r\n\t\tif (this._map && this._layers[id]) {\r\n\t\t\tthis._map.removeLayer(this._layers[id]);\r\n\t\t}\r\n\r\n\t\tdelete this._layers[id];\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method hasLayer(layer: Layer): Boolean\r\n\t// Returns `true` if the given layer is currently added to the group.\r\n\t// @alternative\r\n\t// @method hasLayer(id: Number): Boolean\r\n\t// Returns `true` if the given internal ID is currently added to the group.\r\n\thasLayer: function (layer) {\r\n\t\treturn !!layer && (layer in this._layers || this.getLayerId(layer) in this._layers);\r\n\t},\r\n\r\n\t// @method clearLayers(): this\r\n\t// Removes all the layers from the group.\r\n\tclearLayers: function () {\r\n\t\treturn this.eachLayer(this.removeLayer, this);\r\n\t},\r\n\r\n\t// @method invoke(methodName: String, …): this\r\n\t// Calls `methodName` on every layer contained in this group, passing any\r\n\t// additional parameters. Has no effect if the layers contained do not\r\n\t// implement `methodName`.\r\n\tinvoke: function (methodName) {\r\n\t\tvar args = Array.prototype.slice.call(arguments, 1),\r\n\t\t i, layer;\r\n\r\n\t\tfor (i in this._layers) {\r\n\t\t\tlayer = this._layers[i];\r\n\r\n\t\t\tif (layer[methodName]) {\r\n\t\t\t\tlayer[methodName].apply(layer, args);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis.eachLayer(map.addLayer, map);\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tthis.eachLayer(map.removeLayer, map);\r\n\t},\r\n\r\n\t// @method eachLayer(fn: Function, context?: Object): this\r\n\t// Iterates over the layers of the group, optionally specifying context of the iterator function.\r\n\t// ```js\r\n\t// group.eachLayer(function (layer) {\r\n\t// \tlayer.bindPopup('Hello');\r\n\t// });\r\n\t// ```\r\n\teachLayer: function (method, context) {\r\n\t\tfor (var i in this._layers) {\r\n\t\t\tmethod.call(context, this._layers[i]);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getLayer(id: Number): Layer\r\n\t// Returns the layer with the given internal ID.\r\n\tgetLayer: function (id) {\r\n\t\treturn this._layers[id];\r\n\t},\r\n\r\n\t// @method getLayers(): Layer[]\r\n\t// Returns an array of all the layers added to the group.\r\n\tgetLayers: function () {\r\n\t\tvar layers = [];\r\n\t\tthis.eachLayer(layers.push, layers);\r\n\t\treturn layers;\r\n\t},\r\n\r\n\t// @method setZIndex(zIndex: Number): this\r\n\t// Calls `setZIndex` on every layer contained in this group, passing the z-index.\r\n\tsetZIndex: function (zIndex) {\r\n\t\treturn this.invoke('setZIndex', zIndex);\r\n\t},\r\n\r\n\t// @method getLayerId(layer: Layer): Number\r\n\t// Returns the internal ID for a layer\r\n\tgetLayerId: function (layer) {\r\n\t\treturn stamp(layer);\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.layerGroup(layers?: Layer[], options?: Object)\r\n// Create a layer group, optionally given an initial set of layers and an `options` object.\r\nvar layerGroup = function (layers, options) {\r\n\treturn new LayerGroup(layers, options);\r\n};\n\n/*\r\n * @class FeatureGroup\r\n * @aka L.FeatureGroup\r\n * @inherits LayerGroup\r\n *\r\n * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers:\r\n * * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip))\r\n * * Events are propagated to the `FeatureGroup`, so if the group has an event\r\n * handler, it will handle events from any of the layers. This includes mouse events\r\n * and custom events.\r\n * * Has `layeradd` and `layerremove` events\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.featureGroup([marker1, marker2, polyline])\r\n * \t.bindPopup('Hello world!')\r\n * \t.on('click', function() { alert('Clicked on a member of the group!'); })\r\n * \t.addTo(map);\r\n * ```\r\n */\r\n\r\nvar FeatureGroup = LayerGroup.extend({\r\n\r\n\taddLayer: function (layer) {\r\n\t\tif (this.hasLayer(layer)) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tlayer.addEventParent(this);\r\n\r\n\t\tLayerGroup.prototype.addLayer.call(this, layer);\r\n\r\n\t\t// @event layeradd: LayerEvent\r\n\t\t// Fired when a layer is added to this `FeatureGroup`\r\n\t\treturn this.fire('layeradd', {layer: layer});\r\n\t},\r\n\r\n\tremoveLayer: function (layer) {\r\n\t\tif (!this.hasLayer(layer)) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tif (layer in this._layers) {\r\n\t\t\tlayer = this._layers[layer];\r\n\t\t}\r\n\r\n\t\tlayer.removeEventParent(this);\r\n\r\n\t\tLayerGroup.prototype.removeLayer.call(this, layer);\r\n\r\n\t\t// @event layerremove: LayerEvent\r\n\t\t// Fired when a layer is removed from this `FeatureGroup`\r\n\t\treturn this.fire('layerremove', {layer: layer});\r\n\t},\r\n\r\n\t// @method setStyle(style: Path options): this\r\n\t// Sets the given path options to each layer of the group that has a `setStyle` method.\r\n\tsetStyle: function (style) {\r\n\t\treturn this.invoke('setStyle', style);\r\n\t},\r\n\r\n\t// @method bringToFront(): this\r\n\t// Brings the layer group to the top of all other layers\r\n\tbringToFront: function () {\r\n\t\treturn this.invoke('bringToFront');\r\n\t},\r\n\r\n\t// @method bringToBack(): this\r\n\t// Brings the layer group to the back of all other layers\r\n\tbringToBack: function () {\r\n\t\treturn this.invoke('bringToBack');\r\n\t},\r\n\r\n\t// @method getBounds(): LatLngBounds\r\n\t// Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).\r\n\tgetBounds: function () {\r\n\t\tvar bounds = new LatLngBounds();\r\n\r\n\t\tfor (var id in this._layers) {\r\n\t\t\tvar layer = this._layers[id];\r\n\t\t\tbounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());\r\n\t\t}\r\n\t\treturn bounds;\r\n\t}\r\n});\r\n\r\n// @factory L.featureGroup(layers: Layer[])\r\n// Create a feature group, optionally given an initial set of layers.\r\nvar featureGroup = function (layers) {\r\n\treturn new FeatureGroup(layers);\r\n};\n\n/*\r\n * @class Icon\r\n * @aka L.Icon\r\n *\r\n * Represents an icon to provide when creating a marker.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var myIcon = L.icon({\r\n * iconUrl: 'my-icon.png',\r\n * iconRetinaUrl: 'my-icon@2x.png',\r\n * iconSize: [38, 95],\r\n * iconAnchor: [22, 94],\r\n * popupAnchor: [-3, -76],\r\n * shadowUrl: 'my-icon-shadow.png',\r\n * shadowRetinaUrl: 'my-icon-shadow@2x.png',\r\n * shadowSize: [68, 95],\r\n * shadowAnchor: [22, 94]\r\n * });\r\n *\r\n * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\r\n * ```\r\n *\r\n * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default.\r\n *\r\n */\r\n\r\nvar Icon = Class.extend({\r\n\r\n\t/* @section\r\n\t * @aka Icon options\r\n\t *\r\n\t * @option iconUrl: String = null\r\n\t * **(required)** The URL to the icon image (absolute or relative to your script path).\r\n\t *\r\n\t * @option iconRetinaUrl: String = null\r\n\t * The URL to a retina sized version of the icon image (absolute or relative to your\r\n\t * script path). Used for Retina screen devices.\r\n\t *\r\n\t * @option iconSize: Point = null\r\n\t * Size of the icon image in pixels.\r\n\t *\r\n\t * @option iconAnchor: Point = null\r\n\t * The coordinates of the \"tip\" of the icon (relative to its top left corner). The icon\r\n\t * will be aligned so that this point is at the marker's geographical location. Centered\r\n\t * by default if size is specified, also can be set in CSS with negative margins.\r\n\t *\r\n\t * @option popupAnchor: Point = [0, 0]\r\n\t * The coordinates of the point from which popups will \"open\", relative to the icon anchor.\r\n\t *\r\n\t * @option tooltipAnchor: Point = [0, 0]\r\n\t * The coordinates of the point from which tooltips will \"open\", relative to the icon anchor.\r\n\t *\r\n\t * @option shadowUrl: String = null\r\n\t * The URL to the icon shadow image. If not specified, no shadow image will be created.\r\n\t *\r\n\t * @option shadowRetinaUrl: String = null\r\n\t *\r\n\t * @option shadowSize: Point = null\r\n\t * Size of the shadow image in pixels.\r\n\t *\r\n\t * @option shadowAnchor: Point = null\r\n\t * The coordinates of the \"tip\" of the shadow (relative to its top left corner) (the same\r\n\t * as iconAnchor if not specified).\r\n\t *\r\n\t * @option className: String = ''\r\n\t * A custom class name to assign to both icon and shadow images. Empty by default.\r\n\t */\r\n\r\n\toptions: {\r\n\t\tpopupAnchor: [0, 0],\r\n\t\ttooltipAnchor: [0, 0],\r\n\t},\r\n\r\n\tinitialize: function (options) {\r\n\t\tsetOptions(this, options);\r\n\t},\r\n\r\n\t// @method createIcon(oldIcon?: HTMLElement): HTMLElement\r\n\t// Called internally when the icon has to be shown, returns a ` ` HTML element\r\n\t// styled according to the options.\r\n\tcreateIcon: function (oldIcon) {\r\n\t\treturn this._createIcon('icon', oldIcon);\r\n\t},\r\n\r\n\t// @method createShadow(oldIcon?: HTMLElement): HTMLElement\r\n\t// As `createIcon`, but for the shadow beneath it.\r\n\tcreateShadow: function (oldIcon) {\r\n\t\treturn this._createIcon('shadow', oldIcon);\r\n\t},\r\n\r\n\t_createIcon: function (name, oldIcon) {\r\n\t\tvar src = this._getIconUrl(name);\r\n\r\n\t\tif (!src) {\r\n\t\t\tif (name === 'icon') {\r\n\t\t\t\tthrow new Error('iconUrl not set in Icon options (see the docs).');\r\n\t\t\t}\r\n\t\t\treturn null;\r\n\t\t}\r\n\r\n\t\tvar img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null);\r\n\t\tthis._setIconStyles(img, name);\r\n\r\n\t\treturn img;\r\n\t},\r\n\r\n\t_setIconStyles: function (img, name) {\r\n\t\tvar options = this.options;\r\n\t\tvar sizeOption = options[name + 'Size'];\r\n\r\n\t\tif (typeof sizeOption === 'number') {\r\n\t\t\tsizeOption = [sizeOption, sizeOption];\r\n\t\t}\r\n\r\n\t\tvar size = toPoint(sizeOption),\r\n\t\t anchor = toPoint(name === 'shadow' && options.shadowAnchor || options.iconAnchor ||\r\n\t\t size && size.divideBy(2, true));\r\n\r\n\t\timg.className = 'leaflet-marker-' + name + ' ' + (options.className || '');\r\n\r\n\t\tif (anchor) {\r\n\t\t\timg.style.marginLeft = (-anchor.x) + 'px';\r\n\t\t\timg.style.marginTop = (-anchor.y) + 'px';\r\n\t\t}\r\n\r\n\t\tif (size) {\r\n\t\t\timg.style.width = size.x + 'px';\r\n\t\t\timg.style.height = size.y + 'px';\r\n\t\t}\r\n\t},\r\n\r\n\t_createImg: function (src, el) {\r\n\t\tel = el || document.createElement('img');\r\n\t\tel.src = src;\r\n\t\treturn el;\r\n\t},\r\n\r\n\t_getIconUrl: function (name) {\r\n\t\treturn retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.icon(options: Icon options)\r\n// Creates an icon instance with the given options.\r\nfunction icon(options) {\r\n\treturn new Icon(options);\r\n}\n\n/*\n * @miniclass Icon.Default (Icon)\n * @aka L.Icon.Default\n * @section\n *\n * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when\n * no icon is specified. Points to the blue marker image distributed with Leaflet\n * releases.\n *\n * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options`\n * (which is a set of `Icon options`).\n *\n * If you want to _completely_ replace the default icon, override the\n * `L.Marker.prototype.options.icon` with your own icon instead.\n */\n\nvar IconDefault = Icon.extend({\n\n\toptions: {\n\t\ticonUrl: 'marker-icon.png',\n\t\ticonRetinaUrl: 'marker-icon-2x.png',\n\t\tshadowUrl: 'marker-shadow.png',\n\t\ticonSize: [25, 41],\n\t\ticonAnchor: [12, 41],\n\t\tpopupAnchor: [1, -34],\n\t\ttooltipAnchor: [16, -28],\n\t\tshadowSize: [41, 41]\n\t},\n\n\t_getIconUrl: function (name) {\n\t\tif (!IconDefault.imagePath) {\t// Deprecated, backwards-compatibility only\n\t\t\tIconDefault.imagePath = this._detectIconPath();\n\t\t}\n\n\t\t// @option imagePath: String\n\t\t// `Icon.Default` will try to auto-detect the location of the\n\t\t// blue icon images. If you are placing these images in a non-standard\n\t\t// way, set this option to point to the right path.\n\t\treturn (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name);\n\t},\n\n\t_detectIconPath: function () {\n\t\tvar el = create$1('div', 'leaflet-default-icon-path', document.body);\n\t\tvar path = getStyle(el, 'background-image') ||\n\t\t getStyle(el, 'backgroundImage');\t// IE8\n\n\t\tdocument.body.removeChild(el);\n\n\t\tif (path === null || path.indexOf('url') !== 0) {\n\t\t\tpath = '';\n\t\t} else {\n\t\t\tpath = path.replace(/^url\\([\"']?/, '').replace(/marker-icon\\.png[\"']?\\)$/, '');\n\t\t}\n\n\t\treturn path;\n\t}\n});\n\n/*\n * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.\n */\n\n\n/* @namespace Marker\n * @section Interaction handlers\n *\n * Interaction handlers are properties of a marker instance that allow you to control interaction behavior in runtime, enabling or disabling certain features such as dragging (see `Handler` methods). Example:\n *\n * ```js\n * marker.dragging.disable();\n * ```\n *\n * @property dragging: Handler\n * Marker dragging handler (by both mouse and touch). Only valid when the marker is on the map (Otherwise set [`marker.options.draggable`](#marker-draggable)).\n */\n\nvar MarkerDrag = Handler.extend({\n\tinitialize: function (marker) {\n\t\tthis._marker = marker;\n\t},\n\n\taddHooks: function () {\n\t\tvar icon = this._marker._icon;\n\n\t\tif (!this._draggable) {\n\t\t\tthis._draggable = new Draggable(icon, icon, true);\n\t\t}\n\n\t\tthis._draggable.on({\n\t\t\tdragstart: this._onDragStart,\n\t\t\tpredrag: this._onPreDrag,\n\t\t\tdrag: this._onDrag,\n\t\t\tdragend: this._onDragEnd\n\t\t}, this).enable();\n\n\t\taddClass(icon, 'leaflet-marker-draggable');\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._draggable.off({\n\t\t\tdragstart: this._onDragStart,\n\t\t\tpredrag: this._onPreDrag,\n\t\t\tdrag: this._onDrag,\n\t\t\tdragend: this._onDragEnd\n\t\t}, this).disable();\n\n\t\tif (this._marker._icon) {\n\t\t\tremoveClass(this._marker._icon, 'leaflet-marker-draggable');\n\t\t}\n\t},\n\n\tmoved: function () {\n\t\treturn this._draggable && this._draggable._moved;\n\t},\n\n\t_adjustPan: function (e) {\n\t\tvar marker = this._marker,\n\t\t map = marker._map,\n\t\t speed = this._marker.options.autoPanSpeed,\n\t\t padding = this._marker.options.autoPanPadding,\n\t\t iconPos = L.DomUtil.getPosition(marker._icon),\n\t\t bounds = map.getPixelBounds(),\n\t\t origin = map.getPixelOrigin();\n\n\t\tvar panBounds = toBounds(\n\t\t\tbounds.min._subtract(origin).add(padding),\n\t\t\tbounds.max._subtract(origin).subtract(padding)\n\t\t);\n\n\t\tif (!panBounds.contains(iconPos)) {\n\t\t\t// Compute incremental movement\n\t\t\tvar movement = toPoint(\n\t\t\t\t(Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) -\n\t\t\t\t(Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x),\n\n\t\t\t\t(Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) -\n\t\t\t\t(Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y)\n\t\t\t).multiplyBy(speed);\n\n\t\t\tmap.panBy(movement, {animate: false});\n\n\t\t\tthis._draggable._newPos._add(movement);\n\t\t\tthis._draggable._startPos._add(movement);\n\n\t\t\tL.DomUtil.setPosition(marker._icon, this._draggable._newPos);\n\t\t\tthis._onDrag(e);\n\n\t\t\tthis._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));\n\t\t}\n\t},\n\n\t_onDragStart: function () {\n\t\t// @section Dragging events\n\t\t// @event dragstart: Event\n\t\t// Fired when the user starts dragging the marker.\n\n\t\t// @event movestart: Event\n\t\t// Fired when the marker starts moving (because of dragging).\n\n\t\tthis._oldLatLng = this._marker.getLatLng();\n\t\tthis._marker\n\t\t .closePopup()\n\t\t .fire('movestart')\n\t\t .fire('dragstart');\n\t},\n\n\t_onPreDrag: function (e) {\n\t\tif (this._marker.options.autoPan) {\n\t\t\tcancelAnimFrame(this._panRequest);\n\t\t\tthis._panRequest = requestAnimFrame(this._adjustPan.bind(this, e));\n\t\t}\n\t},\n\n\t_onDrag: function (e) {\n\t\tvar marker = this._marker,\n\t\t shadow = marker._shadow,\n\t\ticonPos = getPosition(marker._icon),\n\t\t latlng = marker._map.layerPointToLatLng(iconPos);\n\n\t\t// update shadow position\n\t\tif (shadow) {\n\t\t\tsetPosition(shadow, iconPos);\n\t\t}\n\n\t\tmarker._latlng = latlng;\n\t\te.latlng = latlng;\n\t\te.oldLatLng = this._oldLatLng;\n\n\t\t// @event drag: Event\n\t\t// Fired repeatedly while the user drags the marker.\n\t\tmarker\n\t\t .fire('move', e)\n\t\t .fire('drag', e);\n\t},\n\n\t_onDragEnd: function (e) {\n\t\t// @event dragend: DragEndEvent\n\t\t// Fired when the user stops dragging the marker.\n\n\t\t cancelAnimFrame(this._panRequest);\n\n\t\t// @event moveend: Event\n\t\t// Fired when the marker stops moving (because of dragging).\n\t\tdelete this._oldLatLng;\n\t\tthis._marker\n\t\t .fire('moveend')\n\t\t .fire('dragend', e);\n\t}\n});\n\n/*\r\n * @class Marker\r\n * @inherits Interactive layer\r\n * @aka L.Marker\r\n * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.marker([50.5, 30.5]).addTo(map);\r\n * ```\r\n */\r\n\r\nvar Marker = Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka Marker options\r\n\toptions: {\r\n\t\t// @option icon: Icon = *\r\n\t\t// Icon instance to use for rendering the marker.\r\n\t\t// See [Icon documentation](#L.Icon) for details on how to customize the marker icon.\r\n\t\t// If not specified, a common instance of `L.Icon.Default` is used.\r\n\t\ticon: new IconDefault(),\r\n\r\n\t\t// Option inherited from \"Interactive layer\" abstract class\r\n\t\tinteractive: true,\r\n\r\n\t\t// @option draggable: Boolean = false\r\n\t\t// Whether the marker is draggable with mouse/touch or not.\r\n\t\tdraggable: false,\r\n\r\n\t\t// @option autoPan: Boolean = false\r\n\t\t// Set it to `true` if you want the map to do panning animation when marker hits the edges.\r\n\t\tautoPan: false,\r\n\r\n\t\t// @option autoPanPadding: Point = Point(50, 50)\r\n\t\t// Equivalent of setting both top left and bottom right autopan padding to the same value.\r\n\t\tautoPanPadding: [50, 50],\r\n\r\n\t\t// @option autoPanSpeed: Number = 10\r\n\t\t// Number of pixels the map should move by.\r\n\t\tautoPanSpeed: 10,\r\n\r\n\t\t// @option keyboard: Boolean = true\r\n\t\t// Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.\r\n\t\tkeyboard: true,\r\n\r\n\t\t// @option title: String = ''\r\n\t\t// Text for the browser tooltip that appear on marker hover (no tooltip by default).\r\n\t\ttitle: '',\r\n\r\n\t\t// @option alt: String = ''\r\n\t\t// Text for the `alt` attribute of the icon image (useful for accessibility).\r\n\t\talt: '',\r\n\r\n\t\t// @option zIndexOffset: Number = 0\r\n\t\t// By default, marker images zIndex is set automatically based on its latitude. Use this option if you want to put the marker on top of all others (or below), specifying a high value like `1000` (or high negative value, respectively).\r\n\t\tzIndexOffset: 0,\r\n\r\n\t\t// @option opacity: Number = 1.0\r\n\t\t// The opacity of the marker.\r\n\t\topacity: 1,\r\n\r\n\t\t// @option riseOnHover: Boolean = false\r\n\t\t// If `true`, the marker will get on top of others when you hover the mouse over it.\r\n\t\triseOnHover: false,\r\n\r\n\t\t// @option riseOffset: Number = 250\r\n\t\t// The z-index offset used for the `riseOnHover` feature.\r\n\t\triseOffset: 250,\r\n\r\n\t\t// @option pane: String = 'markerPane'\r\n\t\t// `Map pane` where the markers icon will be added.\r\n\t\tpane: 'markerPane',\r\n\r\n\t\t// @option bubblingMouseEvents: Boolean = false\r\n\t\t// When `true`, a mouse event on this marker will trigger the same event on the map\r\n\t\t// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).\r\n\t\tbubblingMouseEvents: false\r\n\t},\r\n\r\n\t/* @section\r\n\t *\r\n\t * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods:\r\n\t */\r\n\r\n\tinitialize: function (latlng, options) {\r\n\t\tsetOptions(this, options);\r\n\t\tthis._latlng = toLatLng(latlng);\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tmap.on('zoomanim', this._animateZoom, this);\r\n\t\t}\r\n\r\n\t\tthis._initIcon();\r\n\t\tthis.update();\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tif (this.dragging && this.dragging.enabled()) {\r\n\t\t\tthis.options.draggable = true;\r\n\t\t\tthis.dragging.removeHooks();\r\n\t\t}\r\n\t\tdelete this.dragging;\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tmap.off('zoomanim', this._animateZoom, this);\r\n\t\t}\r\n\r\n\t\tthis._removeIcon();\r\n\t\tthis._removeShadow();\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\treturn {\r\n\t\t\tzoom: this.update,\r\n\t\t\tviewreset: this.update\r\n\t\t};\r\n\t},\r\n\r\n\t// @method getLatLng: LatLng\r\n\t// Returns the current geographical position of the marker.\r\n\tgetLatLng: function () {\r\n\t\treturn this._latlng;\r\n\t},\r\n\r\n\t// @method setLatLng(latlng: LatLng): this\r\n\t// Changes the marker position to the given point.\r\n\tsetLatLng: function (latlng) {\r\n\t\tvar oldLatLng = this._latlng;\r\n\t\tthis._latlng = toLatLng(latlng);\r\n\t\tthis.update();\r\n\r\n\t\t// @event move: Event\r\n\t\t// Fired when the marker is moved via [`setLatLng`](#marker-setlatlng) or by [dragging](#marker-dragging). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.\r\n\t\treturn this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});\r\n\t},\r\n\r\n\t// @method setZIndexOffset(offset: Number): this\r\n\t// Changes the [zIndex offset](#marker-zindexoffset) of the marker.\r\n\tsetZIndexOffset: function (offset) {\r\n\t\tthis.options.zIndexOffset = offset;\r\n\t\treturn this.update();\r\n\t},\r\n\r\n\t// @method setIcon(icon: Icon): this\r\n\t// Changes the marker icon.\r\n\tsetIcon: function (icon) {\r\n\r\n\t\tthis.options.icon = icon;\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._initIcon();\r\n\t\t\tthis.update();\r\n\t\t}\r\n\r\n\t\tif (this._popup) {\r\n\t\t\tthis.bindPopup(this._popup, this._popup.options);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\tgetElement: function () {\r\n\t\treturn this._icon;\r\n\t},\r\n\r\n\tupdate: function () {\r\n\r\n\t\tif (this._icon && this._map) {\r\n\t\t\tvar pos = this._map.latLngToLayerPoint(this._latlng).round();\r\n\t\t\tthis._setPos(pos);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_initIcon: function () {\r\n\t\tvar options = this.options,\r\n\t\t classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');\r\n\r\n\t\tvar icon = options.icon.createIcon(this._icon),\r\n\t\t addIcon = false;\r\n\r\n\t\t// if we're not reusing the icon, remove the old one and init new one\r\n\t\tif (icon !== this._icon) {\r\n\t\t\tif (this._icon) {\r\n\t\t\t\tthis._removeIcon();\r\n\t\t\t}\r\n\t\t\taddIcon = true;\r\n\r\n\t\t\tif (options.title) {\r\n\t\t\t\ticon.title = options.title;\r\n\t\t\t}\r\n\r\n\t\t\tif (icon.tagName === 'IMG') {\r\n\t\t\t\ticon.alt = options.alt || '';\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\taddClass(icon, classToAdd);\r\n\r\n\t\tif (options.keyboard) {\r\n\t\t\ticon.tabIndex = '0';\r\n\t\t}\r\n\r\n\t\tthis._icon = icon;\r\n\r\n\t\tif (options.riseOnHover) {\r\n\t\t\tthis.on({\r\n\t\t\t\tmouseover: this._bringToFront,\r\n\t\t\t\tmouseout: this._resetZIndex\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tvar newShadow = options.icon.createShadow(this._shadow),\r\n\t\t addShadow = false;\r\n\r\n\t\tif (newShadow !== this._shadow) {\r\n\t\t\tthis._removeShadow();\r\n\t\t\taddShadow = true;\r\n\t\t}\r\n\r\n\t\tif (newShadow) {\r\n\t\t\taddClass(newShadow, classToAdd);\r\n\t\t\tnewShadow.alt = '';\r\n\t\t}\r\n\t\tthis._shadow = newShadow;\r\n\r\n\r\n\t\tif (options.opacity < 1) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\r\n\r\n\t\tif (addIcon) {\r\n\t\t\tthis.getPane().appendChild(this._icon);\r\n\t\t}\r\n\t\tthis._initInteraction();\r\n\t\tif (newShadow && addShadow) {\r\n\t\t\tthis.getPane('shadowPane').appendChild(this._shadow);\r\n\t\t}\r\n\t},\r\n\r\n\t_removeIcon: function () {\r\n\t\tif (this.options.riseOnHover) {\r\n\t\t\tthis.off({\r\n\t\t\t\tmouseover: this._bringToFront,\r\n\t\t\t\tmouseout: this._resetZIndex\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\tremove(this._icon);\r\n\t\tthis.removeInteractiveTarget(this._icon);\r\n\r\n\t\tthis._icon = null;\r\n\t},\r\n\r\n\t_removeShadow: function () {\r\n\t\tif (this._shadow) {\r\n\t\t\tremove(this._shadow);\r\n\t\t}\r\n\t\tthis._shadow = null;\r\n\t},\r\n\r\n\t_setPos: function (pos) {\r\n\t\tsetPosition(this._icon, pos);\r\n\r\n\t\tif (this._shadow) {\r\n\t\t\tsetPosition(this._shadow, pos);\r\n\t\t}\r\n\r\n\t\tthis._zIndex = pos.y + this.options.zIndexOffset;\r\n\r\n\t\tthis._resetZIndex();\r\n\t},\r\n\r\n\t_updateZIndex: function (offset) {\r\n\t\tthis._icon.style.zIndex = this._zIndex + offset;\r\n\t},\r\n\r\n\t_animateZoom: function (opt) {\r\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();\r\n\r\n\t\tthis._setPos(pos);\r\n\t},\r\n\r\n\t_initInteraction: function () {\r\n\r\n\t\tif (!this.options.interactive) { return; }\r\n\r\n\t\taddClass(this._icon, 'leaflet-interactive');\r\n\r\n\t\tthis.addInteractiveTarget(this._icon);\r\n\r\n\t\tif (MarkerDrag) {\r\n\t\t\tvar draggable = this.options.draggable;\r\n\t\t\tif (this.dragging) {\r\n\t\t\t\tdraggable = this.dragging.enabled();\r\n\t\t\t\tthis.dragging.disable();\r\n\t\t\t}\r\n\r\n\t\t\tthis.dragging = new MarkerDrag(this);\r\n\r\n\t\t\tif (draggable) {\r\n\t\t\t\tthis.dragging.enable();\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setOpacity(opacity: Number): this\r\n\t// Changes the opacity of the marker.\r\n\tsetOpacity: function (opacity) {\r\n\t\tthis.options.opacity = opacity;\r\n\t\tif (this._map) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_updateOpacity: function () {\r\n\t\tvar opacity = this.options.opacity;\r\n\r\n\t\tsetOpacity(this._icon, opacity);\r\n\r\n\t\tif (this._shadow) {\r\n\t\t\tsetOpacity(this._shadow, opacity);\r\n\t\t}\r\n\t},\r\n\r\n\t_bringToFront: function () {\r\n\t\tthis._updateZIndex(this.options.riseOffset);\r\n\t},\r\n\r\n\t_resetZIndex: function () {\r\n\t\tthis._updateZIndex(0);\r\n\t},\r\n\r\n\t_getPopupAnchor: function () {\r\n\t\treturn this.options.icon.options.popupAnchor;\r\n\t},\r\n\r\n\t_getTooltipAnchor: function () {\r\n\t\treturn this.options.icon.options.tooltipAnchor;\r\n\t}\r\n});\r\n\r\n\r\n// factory L.marker(latlng: LatLng, options? : Marker options)\r\n\r\n// @factory L.marker(latlng: LatLng, options? : Marker options)\r\n// Instantiates a Marker object given a geographical point and optionally an options object.\r\nfunction marker(latlng, options) {\r\n\treturn new Marker(latlng, options);\r\n}\n\n/*\n * @class Path\n * @aka L.Path\n * @inherits Interactive layer\n *\n * An abstract class that contains options and constants shared between vector\n * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`.\n */\n\nvar Path = Layer.extend({\n\n\t// @section\n\t// @aka Path options\n\toptions: {\n\t\t// @option stroke: Boolean = true\n\t\t// Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles.\n\t\tstroke: true,\n\n\t\t// @option color: String = '#3388ff'\n\t\t// Stroke color\n\t\tcolor: '#3388ff',\n\n\t\t// @option weight: Number = 3\n\t\t// Stroke width in pixels\n\t\tweight: 3,\n\n\t\t// @option opacity: Number = 1.0\n\t\t// Stroke opacity\n\t\topacity: 1,\n\n\t\t// @option lineCap: String= 'round'\n\t\t// A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke.\n\t\tlineCap: 'round',\n\n\t\t// @option lineJoin: String = 'round'\n\t\t// A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke.\n\t\tlineJoin: 'round',\n\n\t\t// @option dashArray: String = null\n\t\t// A string that defines the stroke [dash pattern](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dasharray). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).\n\t\tdashArray: null,\n\n\t\t// @option dashOffset: String = null\n\t\t// A string that defines the [distance into the dash pattern to start the dash](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dashoffset). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).\n\t\tdashOffset: null,\n\n\t\t// @option fill: Boolean = depends\n\t\t// Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles.\n\t\tfill: false,\n\n\t\t// @option fillColor: String = *\n\t\t// Fill color. Defaults to the value of the [`color`](#path-color) option\n\t\tfillColor: null,\n\n\t\t// @option fillOpacity: Number = 0.2\n\t\t// Fill opacity.\n\t\tfillOpacity: 0.2,\n\n\t\t// @option fillRule: String = 'evenodd'\n\t\t// A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined.\n\t\tfillRule: 'evenodd',\n\n\t\t// className: '',\n\n\t\t// Option inherited from \"Interactive layer\" abstract class\n\t\tinteractive: true,\n\n\t\t// @option bubblingMouseEvents: Boolean = true\n\t\t// When `true`, a mouse event on this path will trigger the same event on the map\n\t\t// (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used).\n\t\tbubblingMouseEvents: true\n\t},\n\n\tbeforeAdd: function (map) {\n\t\t// Renderer is set here because we need to call renderer.getEvents\n\t\t// before this.getEvents.\n\t\tthis._renderer = map.getRenderer(this);\n\t},\n\n\tonAdd: function () {\n\t\tthis._renderer._initPath(this);\n\t\tthis._reset();\n\t\tthis._renderer._addPath(this);\n\t},\n\n\tonRemove: function () {\n\t\tthis._renderer._removePath(this);\n\t},\n\n\t// @method redraw(): this\n\t// Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.\n\tredraw: function () {\n\t\tif (this._map) {\n\t\t\tthis._renderer._updatePath(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method setStyle(style: Path options): this\n\t// Changes the appearance of a Path based on the options in the `Path options` object.\n\tsetStyle: function (style) {\n\t\tsetOptions(this, style);\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._updateStyle(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToFront(): this\n\t// Brings the layer to the top of all path layers.\n\tbringToFront: function () {\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._bringToFront(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToBack(): this\n\t// Brings the layer to the bottom of all path layers.\n\tbringToBack: function () {\n\t\tif (this._renderer) {\n\t\t\tthis._renderer._bringToBack(this);\n\t\t}\n\t\treturn this;\n\t},\n\n\tgetElement: function () {\n\t\treturn this._path;\n\t},\n\n\t_reset: function () {\n\t\t// defined in child classes\n\t\tthis._project();\n\t\tthis._update();\n\t},\n\n\t_clickTolerance: function () {\n\t\t// used when doing hit detection for Canvas layers\n\t\treturn (this.options.stroke ? this.options.weight / 2 : 0) + this._renderer.options.tolerance;\n\t}\n});\n\n/*\n * @class CircleMarker\n * @aka L.CircleMarker\n * @inherits Path\n *\n * A circle of a fixed size with radius specified in pixels. Extends `Path`.\n */\n\nvar CircleMarker = Path.extend({\n\n\t// @section\n\t// @aka CircleMarker options\n\toptions: {\n\t\tfill: true,\n\n\t\t// @option radius: Number = 10\n\t\t// Radius of the circle marker, in pixels\n\t\tradius: 10\n\t},\n\n\tinitialize: function (latlng, options) {\n\t\tsetOptions(this, options);\n\t\tthis._latlng = toLatLng(latlng);\n\t\tthis._radius = this.options.radius;\n\t},\n\n\t// @method setLatLng(latLng: LatLng): this\n\t// Sets the position of a circle marker to a new location.\n\tsetLatLng: function (latlng) {\n\t\tthis._latlng = toLatLng(latlng);\n\t\tthis.redraw();\n\t\treturn this.fire('move', {latlng: this._latlng});\n\t},\n\n\t// @method getLatLng(): LatLng\n\t// Returns the current geographical position of the circle marker\n\tgetLatLng: function () {\n\t\treturn this._latlng;\n\t},\n\n\t// @method setRadius(radius: Number): this\n\t// Sets the radius of a circle marker. Units are in pixels.\n\tsetRadius: function (radius) {\n\t\tthis.options.radius = this._radius = radius;\n\t\treturn this.redraw();\n\t},\n\n\t// @method getRadius(): Number\n\t// Returns the current radius of the circle\n\tgetRadius: function () {\n\t\treturn this._radius;\n\t},\n\n\tsetStyle : function (options) {\n\t\tvar radius = options && options.radius || this._radius;\n\t\tPath.prototype.setStyle.call(this, options);\n\t\tthis.setRadius(radius);\n\t\treturn this;\n\t},\n\n\t_project: function () {\n\t\tthis._point = this._map.latLngToLayerPoint(this._latlng);\n\t\tthis._updateBounds();\n\t},\n\n\t_updateBounds: function () {\n\t\tvar r = this._radius,\n\t\t r2 = this._radiusY || r,\n\t\t w = this._clickTolerance(),\n\t\t p = [r + w, r2 + w];\n\t\tthis._pxBounds = new Bounds(this._point.subtract(p), this._point.add(p));\n\t},\n\n\t_update: function () {\n\t\tif (this._map) {\n\t\t\tthis._updatePath();\n\t\t}\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updateCircle(this);\n\t},\n\n\t_empty: function () {\n\t\treturn this._radius && !this._renderer._bounds.intersects(this._pxBounds);\n\t},\n\n\t// Needed by the `Canvas` renderer for interactivity\n\t_containsPoint: function (p) {\n\t\treturn p.distanceTo(this._point) <= this._radius + this._clickTolerance();\n\t}\n});\n\n\n// @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options)\n// Instantiates a circle marker object given a geographical point, and an optional options object.\nfunction circleMarker(latlng, options) {\n\treturn new CircleMarker(latlng, options);\n}\n\n/*\n * @class Circle\n * @aka L.Circle\n * @inherits CircleMarker\n *\n * A class for drawing circle overlays on a map. Extends `CircleMarker`.\n *\n * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion).\n *\n * @example\n *\n * ```js\n * L.circle([50.5, 30.5], {radius: 200}).addTo(map);\n * ```\n */\n\nvar Circle = CircleMarker.extend({\n\n\tinitialize: function (latlng, options, legacyOptions) {\n\t\tif (typeof options === 'number') {\n\t\t\t// Backwards compatibility with 0.7.x factory (latlng, radius, options?)\n\t\t\toptions = extend({}, legacyOptions, {radius: options});\n\t\t}\n\t\tsetOptions(this, options);\n\t\tthis._latlng = toLatLng(latlng);\n\n\t\tif (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); }\n\n\t\t// @section\n\t\t// @aka Circle options\n\t\t// @option radius: Number; Radius of the circle, in meters.\n\t\tthis._mRadius = this.options.radius;\n\t},\n\n\t// @method setRadius(radius: Number): this\n\t// Sets the radius of a circle. Units are in meters.\n\tsetRadius: function (radius) {\n\t\tthis._mRadius = radius;\n\t\treturn this.redraw();\n\t},\n\n\t// @method getRadius(): Number\n\t// Returns the current radius of a circle. Units are in meters.\n\tgetRadius: function () {\n\t\treturn this._mRadius;\n\t},\n\n\t// @method getBounds(): LatLngBounds\n\t// Returns the `LatLngBounds` of the path.\n\tgetBounds: function () {\n\t\tvar half = [this._radius, this._radiusY || this._radius];\n\n\t\treturn new LatLngBounds(\n\t\t\tthis._map.layerPointToLatLng(this._point.subtract(half)),\n\t\t\tthis._map.layerPointToLatLng(this._point.add(half)));\n\t},\n\n\tsetStyle: Path.prototype.setStyle,\n\n\t_project: function () {\n\n\t\tvar lng = this._latlng.lng,\n\t\t lat = this._latlng.lat,\n\t\t map = this._map,\n\t\t crs = map.options.crs;\n\n\t\tif (crs.distance === Earth.distance) {\n\t\t\tvar d = Math.PI / 180,\n\t\t\t latR = (this._mRadius / Earth.R) / d,\n\t\t\t top = map.project([lat + latR, lng]),\n\t\t\t bottom = map.project([lat - latR, lng]),\n\t\t\t p = top.add(bottom).divideBy(2),\n\t\t\t lat2 = map.unproject(p).lat,\n\t\t\t lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) /\n\t\t\t (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;\n\n\t\t\tif (isNaN(lngR) || lngR === 0) {\n\t\t\t\tlngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425\n\t\t\t}\n\n\t\t\tthis._point = p.subtract(map.getPixelOrigin());\n\t\t\tthis._radius = isNaN(lngR) ? 0 : p.x - map.project([lat2, lng - lngR]).x;\n\t\t\tthis._radiusY = p.y - top.y;\n\n\t\t} else {\n\t\t\tvar latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));\n\n\t\t\tthis._point = map.latLngToLayerPoint(this._latlng);\n\t\t\tthis._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;\n\t\t}\n\n\t\tthis._updateBounds();\n\t}\n});\n\n// @factory L.circle(latlng: LatLng, options?: Circle options)\n// Instantiates a circle object given a geographical point, and an options object\n// which contains the circle radius.\n// @alternative\n// @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options)\n// Obsolete way of instantiating a circle, for compatibility with 0.7.x code.\n// Do not use in new applications or plugins.\nfunction circle(latlng, options, legacyOptions) {\n\treturn new Circle(latlng, options, legacyOptions);\n}\n\n/*\n * @class Polyline\n * @aka L.Polyline\n * @inherits Path\n *\n * A class for drawing polyline overlays on a map. Extends `Path`.\n *\n * @example\n *\n * ```js\n * // create a red polyline from an array of LatLng points\n * var latlngs = [\n * \t[45.51, -122.68],\n * \t[37.77, -122.43],\n * \t[34.04, -118.2]\n * ];\n *\n * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);\n *\n * // zoom the map to the polyline\n * map.fitBounds(polyline.getBounds());\n * ```\n *\n * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:\n *\n * ```js\n * // create a red polyline from an array of arrays of LatLng points\n * var latlngs = [\n * \t[[45.51, -122.68],\n * \t [37.77, -122.43],\n * \t [34.04, -118.2]],\n * \t[[40.78, -73.91],\n * \t [41.83, -87.62],\n * \t [32.76, -96.72]]\n * ];\n * ```\n */\n\n\nvar Polyline = Path.extend({\n\n\t// @section\n\t// @aka Polyline options\n\toptions: {\n\t\t// @option smoothFactor: Number = 1.0\n\t\t// How much to simplify the polyline on each zoom level. More means\n\t\t// better performance and smoother look, and less means more accurate representation.\n\t\tsmoothFactor: 1.0,\n\n\t\t// @option noClip: Boolean = false\n\t\t// Disable polyline clipping.\n\t\tnoClip: false\n\t},\n\n\tinitialize: function (latlngs, options) {\n\t\tsetOptions(this, options);\n\t\tthis._setLatLngs(latlngs);\n\t},\n\n\t// @method getLatLngs(): LatLng[]\n\t// Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.\n\tgetLatLngs: function () {\n\t\treturn this._latlngs;\n\t},\n\n\t// @method setLatLngs(latlngs: LatLng[]): this\n\t// Replaces all the points in the polyline with the given array of geographical points.\n\tsetLatLngs: function (latlngs) {\n\t\tthis._setLatLngs(latlngs);\n\t\treturn this.redraw();\n\t},\n\n\t// @method isEmpty(): Boolean\n\t// Returns `true` if the Polyline has no LatLngs.\n\tisEmpty: function () {\n\t\treturn !this._latlngs.length;\n\t},\n\n\t// @method closestLayerPoint: Point\n\t// Returns the point closest to `p` on the Polyline.\n\tclosestLayerPoint: function (p) {\n\t\tvar minDistance = Infinity,\n\t\t minPoint = null,\n\t\t closest = _sqClosestPointOnSegment,\n\t\t p1, p2;\n\n\t\tfor (var j = 0, jLen = this._parts.length; j < jLen; j++) {\n\t\t\tvar points = this._parts[j];\n\n\t\t\tfor (var i = 1, len = points.length; i < len; i++) {\n\t\t\t\tp1 = points[i - 1];\n\t\t\t\tp2 = points[i];\n\n\t\t\t\tvar sqDist = closest(p, p1, p2, true);\n\n\t\t\t\tif (sqDist < minDistance) {\n\t\t\t\t\tminDistance = sqDist;\n\t\t\t\t\tminPoint = closest(p, p1, p2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (minPoint) {\n\t\t\tminPoint.distance = Math.sqrt(minDistance);\n\t\t}\n\t\treturn minPoint;\n\t},\n\n\t// @method getCenter(): LatLng\n\t// Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the polyline.\n\tgetCenter: function () {\n\t\t// throws error when not yet added to map as this center calculation requires projected coordinates\n\t\tif (!this._map) {\n\t\t\tthrow new Error('Must add layer to map before using getCenter()');\n\t\t}\n\n\t\tvar i, halfDist, segDist, dist, p1, p2, ratio,\n\t\t points = this._rings[0],\n\t\t len = points.length;\n\n\t\tif (!len) { return null; }\n\n\t\t// polyline centroid algorithm; only uses the first ring if there are multiple\n\n\t\tfor (i = 0, halfDist = 0; i < len - 1; i++) {\n\t\t\thalfDist += points[i].distanceTo(points[i + 1]) / 2;\n\t\t}\n\n\t\t// The line is so small in the current view that all points are on the same pixel.\n\t\tif (halfDist === 0) {\n\t\t\treturn this._map.layerPointToLatLng(points[0]);\n\t\t}\n\n\t\tfor (i = 0, dist = 0; i < len - 1; i++) {\n\t\t\tp1 = points[i];\n\t\t\tp2 = points[i + 1];\n\t\t\tsegDist = p1.distanceTo(p2);\n\t\t\tdist += segDist;\n\n\t\t\tif (dist > halfDist) {\n\t\t\t\tratio = (dist - halfDist) / segDist;\n\t\t\t\treturn this._map.layerPointToLatLng([\n\t\t\t\t\tp2.x - ratio * (p2.x - p1.x),\n\t\t\t\t\tp2.y - ratio * (p2.y - p1.y)\n\t\t\t\t]);\n\t\t\t}\n\t\t}\n\t},\n\n\t// @method getBounds(): LatLngBounds\n\t// Returns the `LatLngBounds` of the path.\n\tgetBounds: function () {\n\t\treturn this._bounds;\n\t},\n\n\t// @method addLatLng(latlng: LatLng, latlngs? LatLng[]): this\n\t// Adds a given point to the polyline. By default, adds to the first ring of\n\t// the polyline in case of a multi-polyline, but can be overridden by passing\n\t// a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).\n\taddLatLng: function (latlng, latlngs) {\n\t\tlatlngs = latlngs || this._defaultShape();\n\t\tlatlng = toLatLng(latlng);\n\t\tlatlngs.push(latlng);\n\t\tthis._bounds.extend(latlng);\n\t\treturn this.redraw();\n\t},\n\n\t_setLatLngs: function (latlngs) {\n\t\tthis._bounds = new LatLngBounds();\n\t\tthis._latlngs = this._convertLatLngs(latlngs);\n\t},\n\n\t_defaultShape: function () {\n\t\treturn isFlat(this._latlngs) ? this._latlngs : this._latlngs[0];\n\t},\n\n\t// recursively convert latlngs input into actual LatLng instances; calculate bounds along the way\n\t_convertLatLngs: function (latlngs) {\n\t\tvar result = [],\n\t\t flat = isFlat(latlngs);\n\n\t\tfor (var i = 0, len = latlngs.length; i < len; i++) {\n\t\t\tif (flat) {\n\t\t\t\tresult[i] = toLatLng(latlngs[i]);\n\t\t\t\tthis._bounds.extend(result[i]);\n\t\t\t} else {\n\t\t\t\tresult[i] = this._convertLatLngs(latlngs[i]);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t},\n\n\t_project: function () {\n\t\tvar pxBounds = new Bounds();\n\t\tthis._rings = [];\n\t\tthis._projectLatlngs(this._latlngs, this._rings, pxBounds);\n\n\t\tvar w = this._clickTolerance(),\n\t\t p = new Point(w, w);\n\n\t\tif (this._bounds.isValid() && pxBounds.isValid()) {\n\t\t\tpxBounds.min._subtract(p);\n\t\t\tpxBounds.max._add(p);\n\t\t\tthis._pxBounds = pxBounds;\n\t\t}\n\t},\n\n\t// recursively turns latlngs into a set of rings with projected coordinates\n\t_projectLatlngs: function (latlngs, result, projectedBounds) {\n\t\tvar flat = latlngs[0] instanceof LatLng,\n\t\t len = latlngs.length,\n\t\t i, ring;\n\n\t\tif (flat) {\n\t\t\tring = [];\n\t\t\tfor (i = 0; i < len; i++) {\n\t\t\t\tring[i] = this._map.latLngToLayerPoint(latlngs[i]);\n\t\t\t\tprojectedBounds.extend(ring[i]);\n\t\t\t}\n\t\t\tresult.push(ring);\n\t\t} else {\n\t\t\tfor (i = 0; i < len; i++) {\n\t\t\t\tthis._projectLatlngs(latlngs[i], result, projectedBounds);\n\t\t\t}\n\t\t}\n\t},\n\n\t// clip polyline by renderer bounds so that we have less to render for performance\n\t_clipPoints: function () {\n\t\tvar bounds = this._renderer._bounds;\n\n\t\tthis._parts = [];\n\t\tif (!this._pxBounds || !this._pxBounds.intersects(bounds)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.options.noClip) {\n\t\t\tthis._parts = this._rings;\n\t\t\treturn;\n\t\t}\n\n\t\tvar parts = this._parts,\n\t\t i, j, k, len, len2, segment, points;\n\n\t\tfor (i = 0, k = 0, len = this._rings.length; i < len; i++) {\n\t\t\tpoints = this._rings[i];\n\n\t\t\tfor (j = 0, len2 = points.length; j < len2 - 1; j++) {\n\t\t\t\tsegment = clipSegment(points[j], points[j + 1], bounds, j, true);\n\n\t\t\t\tif (!segment) { continue; }\n\n\t\t\t\tparts[k] = parts[k] || [];\n\t\t\t\tparts[k].push(segment[0]);\n\n\t\t\t\t// if segment goes out of screen, or it's the last one, it's the end of the line part\n\t\t\t\tif ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {\n\t\t\t\t\tparts[k].push(segment[1]);\n\t\t\t\t\tk++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// simplify each clipped part of the polyline for performance\n\t_simplifyPoints: function () {\n\t\tvar parts = this._parts,\n\t\t tolerance = this.options.smoothFactor;\n\n\t\tfor (var i = 0, len = parts.length; i < len; i++) {\n\t\t\tparts[i] = simplify(parts[i], tolerance);\n\t\t}\n\t},\n\n\t_update: function () {\n\t\tif (!this._map) { return; }\n\n\t\tthis._clipPoints();\n\t\tthis._simplifyPoints();\n\t\tthis._updatePath();\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updatePoly(this);\n\t},\n\n\t// Needed by the `Canvas` renderer for interactivity\n\t_containsPoint: function (p, closed) {\n\t\tvar i, j, k, len, len2, part,\n\t\t w = this._clickTolerance();\n\n\t\tif (!this._pxBounds || !this._pxBounds.contains(p)) { return false; }\n\n\t\t// hit detection for polylines\n\t\tfor (i = 0, len = this._parts.length; i < len; i++) {\n\t\t\tpart = this._parts[i];\n\n\t\t\tfor (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {\n\t\t\t\tif (!closed && (j === 0)) { continue; }\n\n\t\t\t\tif (pointToSegmentDistance(p, part[k], part[j]) <= w) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n});\n\n// @factory L.polyline(latlngs: LatLng[], options?: Polyline options)\n// Instantiates a polyline object given an array of geographical points and\n// optionally an options object. You can create a `Polyline` object with\n// multiple separate lines (`MultiPolyline`) by passing an array of arrays\n// of geographic points.\nfunction polyline(latlngs, options) {\n\treturn new Polyline(latlngs, options);\n}\n\n// Retrocompat. Allow plugins to support Leaflet versions before and after 1.1.\nPolyline._flat = _flat;\n\n/*\n * @class Polygon\n * @aka L.Polygon\n * @inherits Polyline\n *\n * A class for drawing polygon overlays on a map. Extends `Polyline`.\n *\n * Note that points you pass when creating a polygon shouldn't have an additional last point equal to the first one — it's better to filter out such points.\n *\n *\n * @example\n *\n * ```js\n * // create a red polygon from an array of LatLng points\n * var latlngs = [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]];\n *\n * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map);\n *\n * // zoom the map to the polygon\n * map.fitBounds(polygon.getBounds());\n * ```\n *\n * You can also pass an array of arrays of latlngs, with the first array representing the outer shape and the other arrays representing holes in the outer shape:\n *\n * ```js\n * var latlngs = [\n * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring\n * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole\n * ];\n * ```\n *\n * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape.\n *\n * ```js\n * var latlngs = [\n * [ // first polygon\n * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring\n * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole\n * ],\n * [ // second polygon\n * [[41, -111.03],[45, -111.04],[45, -104.05],[41, -104.05]]\n * ]\n * ];\n * ```\n */\n\nvar Polygon = Polyline.extend({\n\n\toptions: {\n\t\tfill: true\n\t},\n\n\tisEmpty: function () {\n\t\treturn !this._latlngs.length || !this._latlngs[0].length;\n\t},\n\n\tgetCenter: function () {\n\t\t// throws error when not yet added to map as this center calculation requires projected coordinates\n\t\tif (!this._map) {\n\t\t\tthrow new Error('Must add layer to map before using getCenter()');\n\t\t}\n\n\t\tvar i, j, p1, p2, f, area, x, y, center,\n\t\t points = this._rings[0],\n\t\t len = points.length;\n\n\t\tif (!len) { return null; }\n\n\t\t// polygon centroid algorithm; only uses the first ring if there are multiple\n\n\t\tarea = x = y = 0;\n\n\t\tfor (i = 0, j = len - 1; i < len; j = i++) {\n\t\t\tp1 = points[i];\n\t\t\tp2 = points[j];\n\n\t\t\tf = p1.y * p2.x - p2.y * p1.x;\n\t\t\tx += (p1.x + p2.x) * f;\n\t\t\ty += (p1.y + p2.y) * f;\n\t\t\tarea += f * 3;\n\t\t}\n\n\t\tif (area === 0) {\n\t\t\t// Polygon is so small that all points are on same pixel.\n\t\t\tcenter = points[0];\n\t\t} else {\n\t\t\tcenter = [x / area, y / area];\n\t\t}\n\t\treturn this._map.layerPointToLatLng(center);\n\t},\n\n\t_convertLatLngs: function (latlngs) {\n\t\tvar result = Polyline.prototype._convertLatLngs.call(this, latlngs),\n\t\t len = result.length;\n\n\t\t// remove last point if it equals first one\n\t\tif (len >= 2 && result[0] instanceof LatLng && result[0].equals(result[len - 1])) {\n\t\t\tresult.pop();\n\t\t}\n\t\treturn result;\n\t},\n\n\t_setLatLngs: function (latlngs) {\n\t\tPolyline.prototype._setLatLngs.call(this, latlngs);\n\t\tif (isFlat(this._latlngs)) {\n\t\t\tthis._latlngs = [this._latlngs];\n\t\t}\n\t},\n\n\t_defaultShape: function () {\n\t\treturn isFlat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0];\n\t},\n\n\t_clipPoints: function () {\n\t\t// polygons need a different clipping algorithm so we redefine that\n\n\t\tvar bounds = this._renderer._bounds,\n\t\t w = this.options.weight,\n\t\t p = new Point(w, w);\n\n\t\t// increase clip padding by stroke width to avoid stroke on clip edges\n\t\tbounds = new Bounds(bounds.min.subtract(p), bounds.max.add(p));\n\n\t\tthis._parts = [];\n\t\tif (!this._pxBounds || !this._pxBounds.intersects(bounds)) {\n\t\t\treturn;\n\t\t}\n\n\t\tif (this.options.noClip) {\n\t\t\tthis._parts = this._rings;\n\t\t\treturn;\n\t\t}\n\n\t\tfor (var i = 0, len = this._rings.length, clipped; i < len; i++) {\n\t\t\tclipped = clipPolygon(this._rings[i], bounds, true);\n\t\t\tif (clipped.length) {\n\t\t\t\tthis._parts.push(clipped);\n\t\t\t}\n\t\t}\n\t},\n\n\t_updatePath: function () {\n\t\tthis._renderer._updatePoly(this, true);\n\t},\n\n\t// Needed by the `Canvas` renderer for interactivity\n\t_containsPoint: function (p) {\n\t\tvar inside = false,\n\t\t part, p1, p2, i, j, k, len, len2;\n\n\t\tif (!this._pxBounds.contains(p)) { return false; }\n\n\t\t// ray casting algorithm for detecting if point is in polygon\n\t\tfor (i = 0, len = this._parts.length; i < len; i++) {\n\t\t\tpart = this._parts[i];\n\n\t\t\tfor (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {\n\t\t\t\tp1 = part[j];\n\t\t\t\tp2 = part[k];\n\n\t\t\t\tif (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {\n\t\t\t\t\tinside = !inside;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// also check if it's on polygon stroke\n\t\treturn inside || Polyline.prototype._containsPoint.call(this, p, true);\n\t}\n\n});\n\n\n// @factory L.polygon(latlngs: LatLng[], options?: Polyline options)\nfunction polygon(latlngs, options) {\n\treturn new Polygon(latlngs, options);\n}\n\n/*\r\n * @class GeoJSON\r\n * @aka L.GeoJSON\r\n * @inherits FeatureGroup\r\n *\r\n * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse\r\n * GeoJSON data and display it on the map. Extends `FeatureGroup`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.geoJSON(data, {\r\n * \tstyle: function (feature) {\r\n * \t\treturn {color: feature.properties.color};\r\n * \t}\r\n * }).bindPopup(function (layer) {\r\n * \treturn layer.feature.properties.description;\r\n * }).addTo(map);\r\n * ```\r\n */\r\n\r\nvar GeoJSON = FeatureGroup.extend({\r\n\r\n\t/* @section\r\n\t * @aka GeoJSON options\r\n\t *\r\n\t * @option pointToLayer: Function = *\r\n\t * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally\r\n\t * called when data is added, passing the GeoJSON point feature and its `LatLng`.\r\n\t * The default is to spawn a default `Marker`:\r\n\t * ```js\r\n\t * function(geoJsonPoint, latlng) {\r\n\t * \treturn L.marker(latlng);\r\n\t * }\r\n\t * ```\r\n\t *\r\n\t * @option style: Function = *\r\n\t * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,\r\n\t * called internally when data is added.\r\n\t * The default value is to not override any defaults:\r\n\t * ```js\r\n\t * function (geoJsonFeature) {\r\n\t * \treturn {}\r\n\t * }\r\n\t * ```\r\n\t *\r\n\t * @option onEachFeature: Function = *\r\n\t * A `Function` that will be called once for each created `Feature`, after it has\r\n\t * been created and styled. Useful for attaching events and popups to features.\r\n\t * The default is to do nothing with the newly created layers:\r\n\t * ```js\r\n\t * function (feature, layer) {}\r\n\t * ```\r\n\t *\r\n\t * @option filter: Function = *\r\n\t * A `Function` that will be used to decide whether to include a feature or not.\r\n\t * The default is to include all features:\r\n\t * ```js\r\n\t * function (geoJsonFeature) {\r\n\t * \treturn true;\r\n\t * }\r\n\t * ```\r\n\t * Note: dynamically changing the `filter` option will have effect only on newly\r\n\t * added data. It will _not_ re-evaluate already included features.\r\n\t *\r\n\t * @option coordsToLatLng: Function = *\r\n\t * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.\r\n\t * The default is the `coordsToLatLng` static method.\r\n\t */\r\n\r\n\tinitialize: function (geojson, options) {\r\n\t\tsetOptions(this, options);\r\n\r\n\t\tthis._layers = {};\r\n\r\n\t\tif (geojson) {\r\n\t\t\tthis.addData(geojson);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method addData( data ): this\r\n\t// Adds a GeoJSON object to the layer.\r\n\taddData: function (geojson) {\r\n\t\tvar features = isArray(geojson) ? geojson : geojson.features,\r\n\t\t i, len, feature;\r\n\r\n\t\tif (features) {\r\n\t\t\tfor (i = 0, len = features.length; i < len; i++) {\r\n\t\t\t\t// only add this if geometry or geometries are set and not null\r\n\t\t\t\tfeature = features[i];\r\n\t\t\t\tif (feature.geometries || feature.geometry || feature.features || feature.coordinates) {\r\n\t\t\t\t\tthis.addData(feature);\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tvar options = this.options;\r\n\r\n\t\tif (options.filter && !options.filter(geojson)) { return this; }\r\n\r\n\t\tvar layer = geometryToLayer(geojson, options);\r\n\t\tif (!layer) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\t\tlayer.feature = asFeature(geojson);\r\n\r\n\t\tlayer.defaultOptions = layer.options;\r\n\t\tthis.resetStyle(layer);\r\n\r\n\t\tif (options.onEachFeature) {\r\n\t\t\toptions.onEachFeature(geojson, layer);\r\n\t\t}\r\n\r\n\t\treturn this.addLayer(layer);\r\n\t},\r\n\r\n\t// @method resetStyle( layer ): this\r\n\t// Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.\r\n\tresetStyle: function (layer) {\r\n\t\t// reset any custom styles\r\n\t\tlayer.options = extend({}, layer.defaultOptions);\r\n\t\tthis._setLayerStyle(layer, this.options.style);\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setStyle( style ): this\r\n\t// Changes styles of GeoJSON vector layers with the given style function.\r\n\tsetStyle: function (style) {\r\n\t\treturn this.eachLayer(function (layer) {\r\n\t\t\tthis._setLayerStyle(layer, style);\r\n\t\t}, this);\r\n\t},\r\n\r\n\t_setLayerStyle: function (layer, style) {\r\n\t\tif (typeof style === 'function') {\r\n\t\t\tstyle = style(layer.feature);\r\n\t\t}\r\n\t\tif (layer.setStyle) {\r\n\t\t\tlayer.setStyle(style);\r\n\t\t}\r\n\t}\r\n});\r\n\r\n// @section\r\n// There are several static functions which can be called without instantiating L.GeoJSON:\r\n\r\n// @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer\r\n// Creates a `Layer` from a given GeoJSON feature. Can use a custom\r\n// [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng)\r\n// functions if provided as options.\r\nfunction geometryToLayer(geojson, options) {\r\n\r\n\tvar geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,\r\n\t coords = geometry ? geometry.coordinates : null,\r\n\t layers = [],\r\n\t pointToLayer = options && options.pointToLayer,\r\n\t _coordsToLatLng = options && options.coordsToLatLng || coordsToLatLng,\r\n\t latlng, latlngs, i, len;\r\n\r\n\tif (!coords && !geometry) {\r\n\t\treturn null;\r\n\t}\r\n\r\n\tswitch (geometry.type) {\r\n\tcase 'Point':\r\n\t\tlatlng = _coordsToLatLng(coords);\r\n\t\treturn pointToLayer ? pointToLayer(geojson, latlng) : new Marker(latlng);\r\n\r\n\tcase 'MultiPoint':\r\n\t\tfor (i = 0, len = coords.length; i < len; i++) {\r\n\t\t\tlatlng = _coordsToLatLng(coords[i]);\r\n\t\t\tlayers.push(pointToLayer ? pointToLayer(geojson, latlng) : new Marker(latlng));\r\n\t\t}\r\n\t\treturn new FeatureGroup(layers);\r\n\r\n\tcase 'LineString':\r\n\tcase 'MultiLineString':\r\n\t\tlatlngs = coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, _coordsToLatLng);\r\n\t\treturn new Polyline(latlngs, options);\r\n\r\n\tcase 'Polygon':\r\n\tcase 'MultiPolygon':\r\n\t\tlatlngs = coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, _coordsToLatLng);\r\n\t\treturn new Polygon(latlngs, options);\r\n\r\n\tcase 'GeometryCollection':\r\n\t\tfor (i = 0, len = geometry.geometries.length; i < len; i++) {\r\n\t\t\tvar layer = geometryToLayer({\r\n\t\t\t\tgeometry: geometry.geometries[i],\r\n\t\t\t\ttype: 'Feature',\r\n\t\t\t\tproperties: geojson.properties\r\n\t\t\t}, options);\r\n\r\n\t\t\tif (layer) {\r\n\t\t\t\tlayers.push(layer);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn new FeatureGroup(layers);\r\n\r\n\tdefault:\r\n\t\tthrow new Error('Invalid GeoJSON object.');\r\n\t}\r\n}\r\n\r\n// @function coordsToLatLng(coords: Array): LatLng\r\n// Creates a `LatLng` object from an array of 2 numbers (longitude, latitude)\r\n// or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.\r\nfunction coordsToLatLng(coords) {\r\n\treturn new LatLng(coords[1], coords[0], coords[2]);\r\n}\r\n\r\n// @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array\r\n// Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array.\r\n// `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default).\r\n// Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function.\r\nfunction coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) {\r\n\tvar latlngs = [];\r\n\r\n\tfor (var i = 0, len = coords.length, latlng; i < len; i++) {\r\n\t\tlatlng = levelsDeep ?\r\n\t\t\tcoordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) :\r\n\t\t\t(_coordsToLatLng || coordsToLatLng)(coords[i]);\r\n\r\n\t\tlatlngs.push(latlng);\r\n\t}\r\n\r\n\treturn latlngs;\r\n}\r\n\r\n// @function latLngToCoords(latlng: LatLng, precision?: Number): Array\r\n// Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)\r\nfunction latLngToCoords(latlng, precision) {\r\n\tprecision = typeof precision === 'number' ? precision : 6;\r\n\treturn latlng.alt !== undefined ?\r\n\t\t[formatNum(latlng.lng, precision), formatNum(latlng.lat, precision), formatNum(latlng.alt, precision)] :\r\n\t\t[formatNum(latlng.lng, precision), formatNum(latlng.lat, precision)];\r\n}\r\n\r\n// @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean): Array\r\n// Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)\r\n// `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default.\r\nfunction latLngsToCoords(latlngs, levelsDeep, closed, precision) {\r\n\tvar coords = [];\r\n\r\n\tfor (var i = 0, len = latlngs.length; i < len; i++) {\r\n\t\tcoords.push(levelsDeep ?\r\n\t\t\tlatLngsToCoords(latlngs[i], levelsDeep - 1, closed, precision) :\r\n\t\t\tlatLngToCoords(latlngs[i], precision));\r\n\t}\r\n\r\n\tif (!levelsDeep && closed) {\r\n\t\tcoords.push(coords[0]);\r\n\t}\r\n\r\n\treturn coords;\r\n}\r\n\r\nfunction getFeature(layer, newGeometry) {\r\n\treturn layer.feature ?\r\n\t\textend({}, layer.feature, {geometry: newGeometry}) :\r\n\t\tasFeature(newGeometry);\r\n}\r\n\r\n// @function asFeature(geojson: Object): Object\r\n// Normalize GeoJSON geometries/features into GeoJSON features.\r\nfunction asFeature(geojson) {\r\n\tif (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') {\r\n\t\treturn geojson;\r\n\t}\r\n\r\n\treturn {\r\n\t\ttype: 'Feature',\r\n\t\tproperties: {},\r\n\t\tgeometry: geojson\r\n\t};\r\n}\r\n\r\nvar PointToGeoJSON = {\r\n\ttoGeoJSON: function (precision) {\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: 'Point',\r\n\t\t\tcoordinates: latLngToCoords(this.getLatLng(), precision)\r\n\t\t});\r\n\t}\r\n};\r\n\r\n// @namespace Marker\r\n// @method toGeoJSON(): Object\r\n// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).\r\nMarker.include(PointToGeoJSON);\r\n\r\n// @namespace CircleMarker\r\n// @method toGeoJSON(): Object\r\n// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).\r\nCircle.include(PointToGeoJSON);\r\nCircleMarker.include(PointToGeoJSON);\r\n\r\n\r\n// @namespace Polyline\r\n// @method toGeoJSON(): Object\r\n// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).\r\nPolyline.include({\r\n\ttoGeoJSON: function (precision) {\r\n\t\tvar multi = !isFlat(this._latlngs);\r\n\r\n\t\tvar coords = latLngsToCoords(this._latlngs, multi ? 1 : 0, false, precision);\r\n\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: (multi ? 'Multi' : '') + 'LineString',\r\n\t\t\tcoordinates: coords\r\n\t\t});\r\n\t}\r\n});\r\n\r\n// @namespace Polygon\r\n// @method toGeoJSON(): Object\r\n// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).\r\nPolygon.include({\r\n\ttoGeoJSON: function (precision) {\r\n\t\tvar holes = !isFlat(this._latlngs),\r\n\t\t multi = holes && !isFlat(this._latlngs[0]);\r\n\r\n\t\tvar coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true, precision);\r\n\r\n\t\tif (!holes) {\r\n\t\t\tcoords = [coords];\r\n\t\t}\r\n\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: (multi ? 'Multi' : '') + 'Polygon',\r\n\t\t\tcoordinates: coords\r\n\t\t});\r\n\t}\r\n});\r\n\r\n\r\n// @namespace LayerGroup\r\nLayerGroup.include({\r\n\ttoMultiPoint: function (precision) {\r\n\t\tvar coords = [];\r\n\r\n\t\tthis.eachLayer(function (layer) {\r\n\t\t\tcoords.push(layer.toGeoJSON(precision).geometry.coordinates);\r\n\t\t});\r\n\r\n\t\treturn getFeature(this, {\r\n\t\t\ttype: 'MultiPoint',\r\n\t\t\tcoordinates: coords\r\n\t\t});\r\n\t},\r\n\r\n\t// @method toGeoJSON(): Object\r\n\t// Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`).\r\n\ttoGeoJSON: function (precision) {\r\n\r\n\t\tvar type = this.feature && this.feature.geometry && this.feature.geometry.type;\r\n\r\n\t\tif (type === 'MultiPoint') {\r\n\t\t\treturn this.toMultiPoint(precision);\r\n\t\t}\r\n\r\n\t\tvar isGeometryCollection = type === 'GeometryCollection',\r\n\t\t jsons = [];\r\n\r\n\t\tthis.eachLayer(function (layer) {\r\n\t\t\tif (layer.toGeoJSON) {\r\n\t\t\t\tvar json = layer.toGeoJSON(precision);\r\n\t\t\t\tif (isGeometryCollection) {\r\n\t\t\t\t\tjsons.push(json.geometry);\r\n\t\t\t\t} else {\r\n\t\t\t\t\tvar feature = asFeature(json);\r\n\t\t\t\t\t// Squash nested feature collections\r\n\t\t\t\t\tif (feature.type === 'FeatureCollection') {\r\n\t\t\t\t\t\tjsons.push.apply(jsons, feature.features);\r\n\t\t\t\t\t} else {\r\n\t\t\t\t\t\tjsons.push(feature);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\tif (isGeometryCollection) {\r\n\t\t\treturn getFeature(this, {\r\n\t\t\t\tgeometries: jsons,\r\n\t\t\t\ttype: 'GeometryCollection'\r\n\t\t\t});\r\n\t\t}\r\n\r\n\t\treturn {\r\n\t\t\ttype: 'FeatureCollection',\r\n\t\t\tfeatures: jsons\r\n\t\t};\r\n\t}\r\n});\r\n\r\n// @namespace GeoJSON\r\n// @factory L.geoJSON(geojson?: Object, options?: GeoJSON options)\r\n// Creates a GeoJSON layer. Optionally accepts an object in\r\n// [GeoJSON format](http://geojson.org/geojson-spec.html) to display on the map\r\n// (you can alternatively add it later with `addData` method) and an `options` object.\r\nfunction geoJSON(geojson, options) {\r\n\treturn new GeoJSON(geojson, options);\r\n}\r\n\r\n// Backward compatibility.\r\nvar geoJson = geoJSON;\n\n/*\r\n * @class ImageOverlay\r\n * @aka L.ImageOverlay\r\n * @inherits Interactive layer\r\n *\r\n * Used to load and display a single image over specific bounds of the map. Extends `Layer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',\r\n * \timageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];\r\n * L.imageOverlay(imageUrl, imageBounds).addTo(map);\r\n * ```\r\n */\r\n\r\nvar ImageOverlay = Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka ImageOverlay options\r\n\toptions: {\r\n\t\t// @option opacity: Number = 1.0\r\n\t\t// The opacity of the image overlay.\r\n\t\topacity: 1,\r\n\r\n\t\t// @option alt: String = ''\r\n\t\t// Text for the `alt` attribute of the image (useful for accessibility).\r\n\t\talt: '',\r\n\r\n\t\t// @option interactive: Boolean = false\r\n\t\t// If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.\r\n\t\tinteractive: false,\r\n\r\n\t\t// @option crossOrigin: Boolean = false\r\n\t\t// If true, the image will have its crossOrigin attribute set to ''. This is needed if you want to access image pixel data.\r\n\t\tcrossOrigin: false,\r\n\r\n\t\t// @option errorOverlayUrl: String = ''\r\n\t\t// URL to the overlay image to show in place of the overlay that failed to load.\r\n\t\terrorOverlayUrl: '',\r\n\r\n\t\t// @option zIndex: Number = 1\r\n\t\t// The explicit [zIndex](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index) of the tile layer.\r\n\t\tzIndex: 1,\r\n\r\n\t\t// @option className: String = ''\r\n\t\t// A custom class name to assign to the image. Empty by default.\r\n\t\tclassName: '',\r\n\t},\r\n\r\n\tinitialize: function (url, bounds, options) { // (String, LatLngBounds, Object)\r\n\t\tthis._url = url;\r\n\t\tthis._bounds = toLatLngBounds(bounds);\r\n\r\n\t\tsetOptions(this, options);\r\n\t},\r\n\r\n\tonAdd: function () {\r\n\t\tif (!this._image) {\r\n\t\t\tthis._initImage();\r\n\r\n\t\t\tif (this.options.opacity < 1) {\r\n\t\t\t\tthis._updateOpacity();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (this.options.interactive) {\r\n\t\t\taddClass(this._image, 'leaflet-interactive');\r\n\t\t\tthis.addInteractiveTarget(this._image);\r\n\t\t}\r\n\r\n\t\tthis.getPane().appendChild(this._image);\r\n\t\tthis._reset();\r\n\t},\r\n\r\n\tonRemove: function () {\r\n\t\tremove(this._image);\r\n\t\tif (this.options.interactive) {\r\n\t\t\tthis.removeInteractiveTarget(this._image);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setOpacity(opacity: Number): this\r\n\t// Sets the opacity of the overlay.\r\n\tsetOpacity: function (opacity) {\r\n\t\tthis.options.opacity = opacity;\r\n\r\n\t\tif (this._image) {\r\n\t\t\tthis._updateOpacity();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\tsetStyle: function (styleOpts) {\r\n\t\tif (styleOpts.opacity) {\r\n\t\t\tthis.setOpacity(styleOpts.opacity);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToFront(): this\r\n\t// Brings the layer to the top of all overlays.\r\n\tbringToFront: function () {\r\n\t\tif (this._map) {\r\n\t\t\ttoFront(this._image);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToBack(): this\r\n\t// Brings the layer to the bottom of all overlays.\r\n\tbringToBack: function () {\r\n\t\tif (this._map) {\r\n\t\t\ttoBack(this._image);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setUrl(url: String): this\r\n\t// Changes the URL of the image.\r\n\tsetUrl: function (url) {\r\n\t\tthis._url = url;\r\n\r\n\t\tif (this._image) {\r\n\t\t\tthis._image.src = url;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method setBounds(bounds: LatLngBounds): this\r\n\t// Update the bounds that this ImageOverlay covers\r\n\tsetBounds: function (bounds) {\r\n\t\tthis._bounds = toLatLngBounds(bounds);\r\n\r\n\t\tif (this._map) {\r\n\t\t\tthis._reset();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = {\r\n\t\t\tzoom: this._reset,\r\n\t\t\tviewreset: this._reset\r\n\t\t};\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tevents.zoomanim = this._animateZoom;\r\n\t\t}\r\n\r\n\t\treturn events;\r\n\t},\r\n\r\n\t// @method: setZIndex(value: Number) : this\r\n\t// Changes the [zIndex](#imageoverlay-zindex) of the image overlay.\r\n\tsetZIndex: function (value) {\r\n\t\tthis.options.zIndex = value;\r\n\t\tthis._updateZIndex();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getBounds(): LatLngBounds\r\n\t// Get the bounds that this ImageOverlay covers\r\n\tgetBounds: function () {\r\n\t\treturn this._bounds;\r\n\t},\r\n\r\n\t// @method getElement(): HTMLElement\r\n\t// Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement)\r\n\t// used by this overlay.\r\n\tgetElement: function () {\r\n\t\treturn this._image;\r\n\t},\r\n\r\n\t_initImage: function () {\r\n\t\tvar wasElementSupplied = this._url.tagName === 'IMG';\r\n\t\tvar img = this._image = wasElementSupplied ? this._url : create$1('img');\r\n\r\n\t\taddClass(img, 'leaflet-image-layer');\r\n\t\tif (this._zoomAnimated) { addClass(img, 'leaflet-zoom-animated'); }\r\n\t\tif (this.options.className) { addClass(img, this.options.className); }\r\n\r\n\t\timg.onselectstart = falseFn;\r\n\t\timg.onmousemove = falseFn;\r\n\r\n\t\t// @event load: Event\r\n\t\t// Fired when the ImageOverlay layer has loaded its image\r\n\t\timg.onload = bind(this.fire, this, 'load');\r\n\t\timg.onerror = bind(this._overlayOnError, this, 'error');\r\n\r\n\t\tif (this.options.crossOrigin) {\r\n\t\t\timg.crossOrigin = '';\r\n\t\t}\r\n\r\n\t\tif (this.options.zIndex) {\r\n\t\t\tthis._updateZIndex();\r\n\t\t}\r\n\r\n\t\tif (wasElementSupplied) {\r\n\t\t\tthis._url = img.src;\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\timg.src = this._url;\r\n\t\timg.alt = this.options.alt;\r\n\t},\r\n\r\n\t_animateZoom: function (e) {\r\n\t\tvar scale = this._map.getZoomScale(e.zoom),\r\n\t\t offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;\r\n\r\n\t\tsetTransform(this._image, offset, scale);\r\n\t},\r\n\r\n\t_reset: function () {\r\n\t\tvar image = this._image,\r\n\t\t bounds = new Bounds(\r\n\t\t this._map.latLngToLayerPoint(this._bounds.getNorthWest()),\r\n\t\t this._map.latLngToLayerPoint(this._bounds.getSouthEast())),\r\n\t\t size = bounds.getSize();\r\n\r\n\t\tsetPosition(image, bounds.min);\r\n\r\n\t\timage.style.width = size.x + 'px';\r\n\t\timage.style.height = size.y + 'px';\r\n\t},\r\n\r\n\t_updateOpacity: function () {\r\n\t\tsetOpacity(this._image, this.options.opacity);\r\n\t},\r\n\r\n\t_updateZIndex: function () {\r\n\t\tif (this._image && this.options.zIndex !== undefined && this.options.zIndex !== null) {\r\n\t\t\tthis._image.style.zIndex = this.options.zIndex;\r\n\t\t}\r\n\t},\r\n\r\n\t_overlayOnError: function () {\r\n\t\t// @event error: Event\r\n\t\t// Fired when the ImageOverlay layer has loaded its image\r\n\t\tthis.fire('error');\r\n\r\n\t\tvar errorUrl = this.options.errorOverlayUrl;\r\n\t\tif (errorUrl && this._url !== errorUrl) {\r\n\t\t\tthis._url = errorUrl;\r\n\t\t\tthis._image.src = errorUrl;\r\n\t\t}\r\n\t}\r\n});\r\n\r\n// @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)\r\n// Instantiates an image overlay object given the URL of the image and the\r\n// geographical bounds it is tied to.\r\nvar imageOverlay = function (url, bounds, options) {\r\n\treturn new ImageOverlay(url, bounds, options);\r\n};\n\n/*\r\n * @class VideoOverlay\r\n * @aka L.VideoOverlay\r\n * @inherits ImageOverlay\r\n *\r\n * Used to load and display a video player over specific bounds of the map. Extends `ImageOverlay`.\r\n *\r\n * A video overlay uses the [``](https://developer.mozilla.org/docs/Web/HTML/Element/video)\r\n * HTML5 element.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var videoUrl = 'https://www.mapbox.com/bites/00188/patricia_nasa.webm',\r\n * \tvideoBounds = [[ 32, -130], [ 13, -100]];\r\n * L.VideoOverlay(videoUrl, videoBounds ).addTo(map);\r\n * ```\r\n */\r\n\r\nvar VideoOverlay = ImageOverlay.extend({\r\n\r\n\t// @section\r\n\t// @aka VideoOverlay options\r\n\toptions: {\r\n\t\t// @option autoplay: Boolean = true\r\n\t\t// Whether the video starts playing automatically when loaded.\r\n\t\tautoplay: true,\r\n\r\n\t\t// @option loop: Boolean = true\r\n\t\t// Whether the video will loop back to the beginning when played.\r\n\t\tloop: true\r\n\t},\r\n\r\n\t_initImage: function () {\r\n\t\tvar wasElementSupplied = this._url.tagName === 'VIDEO';\r\n\t\tvar vid = this._image = wasElementSupplied ? this._url : create$1('video');\r\n\r\n\t\taddClass(vid, 'leaflet-image-layer');\r\n\t\tif (this._zoomAnimated) { addClass(vid, 'leaflet-zoom-animated'); }\r\n\r\n\t\tvid.onselectstart = falseFn;\r\n\t\tvid.onmousemove = falseFn;\r\n\r\n\t\t// @event load: Event\r\n\t\t// Fired when the video has finished loading the first frame\r\n\t\tvid.onloadeddata = bind(this.fire, this, 'load');\r\n\r\n\t\tif (wasElementSupplied) {\r\n\t\t\tvar sourceElements = vid.getElementsByTagName('source');\r\n\t\t\tvar sources = [];\r\n\t\t\tfor (var j = 0; j < sourceElements.length; j++) {\r\n\t\t\t\tsources.push(sourceElements[j].src);\r\n\t\t\t}\r\n\r\n\t\t\tthis._url = (sourceElements.length > 0) ? sources : [vid.src];\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!isArray(this._url)) { this._url = [this._url]; }\r\n\r\n\t\tvid.autoplay = !!this.options.autoplay;\r\n\t\tvid.loop = !!this.options.loop;\r\n\t\tfor (var i = 0; i < this._url.length; i++) {\r\n\t\t\tvar source = create$1('source');\r\n\t\t\tsource.src = this._url[i];\r\n\t\t\tvid.appendChild(source);\r\n\t\t}\r\n\t}\r\n\r\n\t// @method getElement(): HTMLVideoElement\r\n\t// Returns the instance of [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement)\r\n\t// used by this overlay.\r\n});\r\n\r\n\r\n// @factory L.videoOverlay(video: String|Array|HTMLVideoElement, bounds: LatLngBounds, options?: VideoOverlay options)\r\n// Instantiates an image overlay object given the URL of the video (or array of URLs, or even a video element) and the\r\n// geographical bounds it is tied to.\r\n\r\nfunction videoOverlay(video, bounds, options) {\r\n\treturn new VideoOverlay(video, bounds, options);\r\n}\n\n/*\r\n * @class DivOverlay\r\n * @inherits Layer\r\n * @aka L.DivOverlay\r\n * Base model for L.Popup and L.Tooltip. Inherit from it for custom popup like plugins.\r\n */\r\n\r\n// @namespace DivOverlay\r\nvar DivOverlay = Layer.extend({\r\n\r\n\t// @section\r\n\t// @aka DivOverlay options\r\n\toptions: {\r\n\t\t// @option offset: Point = Point(0, 7)\r\n\t\t// The offset of the popup position. Useful to control the anchor\r\n\t\t// of the popup when opening it on some overlays.\r\n\t\toffset: [0, 7],\r\n\r\n\t\t// @option className: String = ''\r\n\t\t// A custom CSS class name to assign to the popup.\r\n\t\tclassName: '',\r\n\r\n\t\t// @option pane: String = 'popupPane'\r\n\t\t// `Map pane` where the popup will be added.\r\n\t\tpane: 'popupPane'\r\n\t},\r\n\r\n\tinitialize: function (options, source) {\r\n\t\tsetOptions(this, options);\r\n\r\n\t\tthis._source = source;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tthis._zoomAnimated = map._zoomAnimated;\r\n\r\n\t\tif (!this._container) {\r\n\t\t\tthis._initLayout();\r\n\t\t}\r\n\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tsetOpacity(this._container, 0);\r\n\t\t}\r\n\r\n\t\tclearTimeout(this._removeTimeout);\r\n\t\tthis.getPane().appendChild(this._container);\r\n\t\tthis.update();\r\n\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tsetOpacity(this._container, 1);\r\n\t\t}\r\n\r\n\t\tthis.bringToFront();\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tif (map._fadeAnimated) {\r\n\t\t\tsetOpacity(this._container, 0);\r\n\t\t\tthis._removeTimeout = setTimeout(bind(remove, undefined, this._container), 200);\r\n\t\t} else {\r\n\t\t\tremove(this._container);\r\n\t\t}\r\n\t},\r\n\r\n\t// @namespace Popup\r\n\t// @method getLatLng: LatLng\r\n\t// Returns the geographical point of popup.\r\n\tgetLatLng: function () {\r\n\t\treturn this._latlng;\r\n\t},\r\n\r\n\t// @method setLatLng(latlng: LatLng): this\r\n\t// Sets the geographical point where the popup will open.\r\n\tsetLatLng: function (latlng) {\r\n\t\tthis._latlng = toLatLng(latlng);\r\n\t\tif (this._map) {\r\n\t\t\tthis._updatePosition();\r\n\t\t\tthis._adjustPan();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getContent: String|HTMLElement\r\n\t// Returns the content of the popup.\r\n\tgetContent: function () {\r\n\t\treturn this._content;\r\n\t},\r\n\r\n\t// @method setContent(htmlContent: String|HTMLElement|Function): this\r\n\t// Sets the HTML content of the popup. If a function is passed the source layer will be passed to the function. The function should return a `String` or `HTMLElement` to be used in the popup.\r\n\tsetContent: function (content) {\r\n\t\tthis._content = content;\r\n\t\tthis.update();\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getElement: String|HTMLElement\r\n\t// Alias for [getContent()](#popup-getcontent)\r\n\tgetElement: function () {\r\n\t\treturn this._container;\r\n\t},\r\n\r\n\t// @method update: null\r\n\t// Updates the popup content, layout and position. Useful for updating the popup after something inside changed, e.g. image loaded.\r\n\tupdate: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tthis._container.style.visibility = 'hidden';\r\n\r\n\t\tthis._updateContent();\r\n\t\tthis._updateLayout();\r\n\t\tthis._updatePosition();\r\n\r\n\t\tthis._container.style.visibility = '';\r\n\r\n\t\tthis._adjustPan();\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = {\r\n\t\t\tzoom: this._updatePosition,\r\n\t\t\tviewreset: this._updatePosition\r\n\t\t};\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tevents.zoomanim = this._animateZoom;\r\n\t\t}\r\n\t\treturn events;\r\n\t},\r\n\r\n\t// @method isOpen: Boolean\r\n\t// Returns `true` when the popup is visible on the map.\r\n\tisOpen: function () {\r\n\t\treturn !!this._map && this._map.hasLayer(this);\r\n\t},\r\n\r\n\t// @method bringToFront: this\r\n\t// Brings this popup in front of other popups (in the same map pane).\r\n\tbringToFront: function () {\r\n\t\tif (this._map) {\r\n\t\t\ttoFront(this._container);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method bringToBack: this\r\n\t// Brings this popup to the back of other popups (in the same map pane).\r\n\tbringToBack: function () {\r\n\t\tif (this._map) {\r\n\t\t\ttoBack(this._container);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t_updateContent: function () {\r\n\t\tif (!this._content) { return; }\r\n\r\n\t\tvar node = this._contentNode;\r\n\t\tvar content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content;\r\n\r\n\t\tif (typeof content === 'string') {\r\n\t\t\tnode.innerHTML = content;\r\n\t\t} else {\r\n\t\t\twhile (node.hasChildNodes()) {\r\n\t\t\t\tnode.removeChild(node.firstChild);\r\n\t\t\t}\r\n\t\t\tnode.appendChild(content);\r\n\t\t}\r\n\t\tthis.fire('contentupdate');\r\n\t},\r\n\r\n\t_updatePosition: function () {\r\n\t\tif (!this._map) { return; }\r\n\r\n\t\tvar pos = this._map.latLngToLayerPoint(this._latlng),\r\n\t\t offset = toPoint(this.options.offset),\r\n\t\t anchor = this._getAnchor();\r\n\r\n\t\tif (this._zoomAnimated) {\r\n\t\t\tsetPosition(this._container, pos.add(anchor));\r\n\t\t} else {\r\n\t\t\toffset = offset.add(pos).add(anchor);\r\n\t\t}\r\n\r\n\t\tvar bottom = this._containerBottom = -offset.y,\r\n\t\t left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;\r\n\r\n\t\t// bottom position the popup in case the height of the popup changes (images loading etc)\r\n\t\tthis._container.style.bottom = bottom + 'px';\r\n\t\tthis._container.style.left = left + 'px';\r\n\t},\r\n\r\n\t_getAnchor: function () {\r\n\t\treturn [0, 0];\r\n\t}\r\n\r\n});\n\n/*\r\n * @class Popup\r\n * @inherits DivOverlay\r\n * @aka L.Popup\r\n * Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to\r\n * open popups while making sure that only one popup is open at one time\r\n * (recommended for usability), or use [Map.addLayer](#map-addlayer) to open as many as you want.\r\n *\r\n * @example\r\n *\r\n * If you want to just bind a popup to marker click and then open it, it's really easy:\r\n *\r\n * ```js\r\n * marker.bindPopup(popupContent).openPopup();\r\n * ```\r\n * Path overlays like polylines also have a `bindPopup` method.\r\n * Here's a more complicated way to open a popup on a map:\r\n *\r\n * ```js\r\n * var popup = L.popup()\r\n * \t.setLatLng(latlng)\r\n * \t.setContent('Hello world! This is a nice popup.
')\r\n * \t.openOn(map);\r\n * ```\r\n */\r\n\r\n\r\n// @namespace Popup\r\nvar Popup = DivOverlay.extend({\r\n\r\n\t// @section\r\n\t// @aka Popup options\r\n\toptions: {\r\n\t\t// @option maxWidth: Number = 300\r\n\t\t// Max width of the popup, in pixels.\r\n\t\tmaxWidth: 300,\r\n\r\n\t\t// @option minWidth: Number = 50\r\n\t\t// Min width of the popup, in pixels.\r\n\t\tminWidth: 50,\r\n\r\n\t\t// @option maxHeight: Number = null\r\n\t\t// If set, creates a scrollable container of the given height\r\n\t\t// inside a popup if its content exceeds it.\r\n\t\tmaxHeight: null,\r\n\r\n\t\t// @option autoPan: Boolean = true\r\n\t\t// Set it to `false` if you don't want the map to do panning animation\r\n\t\t// to fit the opened popup.\r\n\t\tautoPan: true,\r\n\r\n\t\t// @option autoPanPaddingTopLeft: Point = null\r\n\t\t// The margin between the popup and the top left corner of the map\r\n\t\t// view after autopanning was performed.\r\n\t\tautoPanPaddingTopLeft: null,\r\n\r\n\t\t// @option autoPanPaddingBottomRight: Point = null\r\n\t\t// The margin between the popup and the bottom right corner of the map\r\n\t\t// view after autopanning was performed.\r\n\t\tautoPanPaddingBottomRight: null,\r\n\r\n\t\t// @option autoPanPadding: Point = Point(5, 5)\r\n\t\t// Equivalent of setting both top left and bottom right autopan padding to the same value.\r\n\t\tautoPanPadding: [5, 5],\r\n\r\n\t\t// @option keepInView: Boolean = false\r\n\t\t// Set it to `true` if you want to prevent users from panning the popup\r\n\t\t// off of the screen while it is open.\r\n\t\tkeepInView: false,\r\n\r\n\t\t// @option closeButton: Boolean = true\r\n\t\t// Controls the presence of a close button in the popup.\r\n\t\tcloseButton: true,\r\n\r\n\t\t// @option autoClose: Boolean = true\r\n\t\t// Set it to `false` if you want to override the default behavior of\r\n\t\t// the popup closing when another popup is opened.\r\n\t\tautoClose: true,\r\n\r\n\t\t// @option closeOnEscapeKey: Boolean = true\r\n\t\t// Set it to `false` if you want to override the default behavior of\r\n\t\t// the ESC key for closing of the popup.\r\n\t\tcloseOnEscapeKey: true,\r\n\r\n\t\t// @option closeOnClick: Boolean = *\r\n\t\t// Set it if you want to override the default behavior of the popup closing when user clicks\r\n\t\t// on the map. Defaults to the map's [`closePopupOnClick`](#map-closepopuponclick) option.\r\n\r\n\t\t// @option className: String = ''\r\n\t\t// A custom CSS class name to assign to the popup.\r\n\t\tclassName: ''\r\n\t},\r\n\r\n\t// @namespace Popup\r\n\t// @method openOn(map: Map): this\r\n\t// Adds the popup to the map and closes the previous one. The same as `map.openPopup(popup)`.\r\n\topenOn: function (map) {\r\n\t\tmap.openPopup(this);\r\n\t\treturn this;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\t\tDivOverlay.prototype.onAdd.call(this, map);\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event popupopen: PopupEvent\r\n\t\t// Fired when a popup is opened in the map\r\n\t\tmap.fire('popupopen', {popup: this});\r\n\r\n\t\tif (this._source) {\r\n\t\t\t// @namespace Layer\r\n\t\t\t// @section Popup events\r\n\t\t\t// @event popupopen: PopupEvent\r\n\t\t\t// Fired when a popup bound to this layer is opened\r\n\t\t\tthis._source.fire('popupopen', {popup: this}, true);\r\n\t\t\t// For non-path layers, we toggle the popup when clicking\r\n\t\t\t// again the layer, so prevent the map to reopen it.\r\n\t\t\tif (!(this._source instanceof Path)) {\r\n\t\t\t\tthis._source.on('preclick', stopPropagation);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\tonRemove: function (map) {\r\n\t\tDivOverlay.prototype.onRemove.call(this, map);\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event popupclose: PopupEvent\r\n\t\t// Fired when a popup in the map is closed\r\n\t\tmap.fire('popupclose', {popup: this});\r\n\r\n\t\tif (this._source) {\r\n\t\t\t// @namespace Layer\r\n\t\t\t// @section Popup events\r\n\t\t\t// @event popupclose: PopupEvent\r\n\t\t\t// Fired when a popup bound to this layer is closed\r\n\t\t\tthis._source.fire('popupclose', {popup: this}, true);\r\n\t\t\tif (!(this._source instanceof Path)) {\r\n\t\t\t\tthis._source.off('preclick', stopPropagation);\r\n\t\t\t}\r\n\t\t}\r\n\t},\r\n\r\n\tgetEvents: function () {\r\n\t\tvar events = DivOverlay.prototype.getEvents.call(this);\r\n\r\n\t\tif (this.options.closeOnClick !== undefined ? this.options.closeOnClick : this._map.options.closePopupOnClick) {\r\n\t\t\tevents.preclick = this._close;\r\n\t\t}\r\n\r\n\t\tif (this.options.keepInView) {\r\n\t\t\tevents.moveend = this._adjustPan;\r\n\t\t}\r\n\r\n\t\treturn events;\r\n\t},\r\n\r\n\t_close: function () {\r\n\t\tif (this._map) {\r\n\t\t\tthis._map.closePopup(this);\r\n\t\t}\r\n\t},\r\n\r\n\t_initLayout: function () {\r\n\t\tvar prefix = 'leaflet-popup',\r\n\t\t container = this._container = create$1('div',\r\n\t\t\tprefix + ' ' + (this.options.className || '') +\r\n\t\t\t' leaflet-zoom-animated');\r\n\r\n\t\tvar wrapper = this._wrapper = create$1('div', prefix + '-content-wrapper', container);\r\n\t\tthis._contentNode = create$1('div', prefix + '-content', wrapper);\r\n\r\n\t\tdisableClickPropagation(wrapper);\r\n\t\tdisableScrollPropagation(this._contentNode);\r\n\t\ton(wrapper, 'contextmenu', stopPropagation);\r\n\r\n\t\tthis._tipContainer = create$1('div', prefix + '-tip-container', container);\r\n\t\tthis._tip = create$1('div', prefix + '-tip', this._tipContainer);\r\n\r\n\t\tif (this.options.closeButton) {\r\n\t\t\tvar closeButton = this._closeButton = create$1('a', prefix + '-close-button', container);\r\n\t\t\tcloseButton.href = '#close';\r\n\t\t\tcloseButton.innerHTML = '×';\r\n\r\n\t\t\ton(closeButton, 'click', this._onCloseButtonClick, this);\r\n\t\t}\r\n\t},\r\n\r\n\t_updateLayout: function () {\r\n\t\tvar container = this._contentNode,\r\n\t\t style = container.style;\r\n\r\n\t\tstyle.width = '';\r\n\t\tstyle.whiteSpace = 'nowrap';\r\n\r\n\t\tvar width = container.offsetWidth;\r\n\t\twidth = Math.min(width, this.options.maxWidth);\r\n\t\twidth = Math.max(width, this.options.minWidth);\r\n\r\n\t\tstyle.width = (width + 1) + 'px';\r\n\t\tstyle.whiteSpace = '';\r\n\r\n\t\tstyle.height = '';\r\n\r\n\t\tvar height = container.offsetHeight,\r\n\t\t maxHeight = this.options.maxHeight,\r\n\t\t scrolledClass = 'leaflet-popup-scrolled';\r\n\r\n\t\tif (maxHeight && height > maxHeight) {\r\n\t\t\tstyle.height = maxHeight + 'px';\r\n\t\t\taddClass(container, scrolledClass);\r\n\t\t} else {\r\n\t\t\tremoveClass(container, scrolledClass);\r\n\t\t}\r\n\r\n\t\tthis._containerWidth = this._container.offsetWidth;\r\n\t},\r\n\r\n\t_animateZoom: function (e) {\r\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center),\r\n\t\t anchor = this._getAnchor();\r\n\t\tsetPosition(this._container, pos.add(anchor));\r\n\t},\r\n\r\n\t_adjustPan: function () {\r\n\t\tif (!this.options.autoPan || (this._map._panAnim && this._map._panAnim._inProgress)) { return; }\r\n\r\n\t\tvar map = this._map,\r\n\t\t marginBottom = parseInt(getStyle(this._container, 'marginBottom'), 10) || 0,\r\n\t\t containerHeight = this._container.offsetHeight + marginBottom,\r\n\t\t containerWidth = this._containerWidth,\r\n\t\t layerPos = new Point(this._containerLeft, -containerHeight - this._containerBottom);\r\n\r\n\t\tlayerPos._add(getPosition(this._container));\r\n\r\n\t\tvar containerPos = map.layerPointToContainerPoint(layerPos),\r\n\t\t padding = toPoint(this.options.autoPanPadding),\r\n\t\t paddingTL = toPoint(this.options.autoPanPaddingTopLeft || padding),\r\n\t\t paddingBR = toPoint(this.options.autoPanPaddingBottomRight || padding),\r\n\t\t size = map.getSize(),\r\n\t\t dx = 0,\r\n\t\t dy = 0;\r\n\r\n\t\tif (containerPos.x + containerWidth + paddingBR.x > size.x) { // right\r\n\t\t\tdx = containerPos.x + containerWidth - size.x + paddingBR.x;\r\n\t\t}\r\n\t\tif (containerPos.x - dx - paddingTL.x < 0) { // left\r\n\t\t\tdx = containerPos.x - paddingTL.x;\r\n\t\t}\r\n\t\tif (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom\r\n\t\t\tdy = containerPos.y + containerHeight - size.y + paddingBR.y;\r\n\t\t}\r\n\t\tif (containerPos.y - dy - paddingTL.y < 0) { // top\r\n\t\t\tdy = containerPos.y - paddingTL.y;\r\n\t\t}\r\n\r\n\t\t// @namespace Map\r\n\t\t// @section Popup events\r\n\t\t// @event autopanstart: Event\r\n\t\t// Fired when the map starts autopanning when opening a popup.\r\n\t\tif (dx || dy) {\r\n\t\t\tmap\r\n\t\t\t .fire('autopanstart')\r\n\t\t\t .panBy([dx, dy]);\r\n\t\t}\r\n\t},\r\n\r\n\t_onCloseButtonClick: function (e) {\r\n\t\tthis._close();\r\n\t\tstop(e);\r\n\t},\r\n\r\n\t_getAnchor: function () {\r\n\t\t// Where should we anchor the popup on the source layer?\r\n\t\treturn toPoint(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);\r\n\t}\r\n\r\n});\r\n\r\n// @namespace Popup\r\n// @factory L.popup(options?: Popup options, source?: Layer)\r\n// Instantiates a `Popup` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the popup with a reference to the Layer to which it refers.\r\nvar popup = function (options, source) {\r\n\treturn new Popup(options, source);\r\n};\r\n\r\n\r\n/* @namespace Map\r\n * @section Interaction Options\r\n * @option closePopupOnClick: Boolean = true\r\n * Set it to `false` if you don't want popups to close when user clicks the map.\r\n */\r\nMap.mergeOptions({\r\n\tclosePopupOnClick: true\r\n});\r\n\r\n\r\n// @namespace Map\r\n// @section Methods for Layers and Controls\r\nMap.include({\r\n\t// @method openPopup(popup: Popup): this\r\n\t// Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability).\r\n\t// @alternative\r\n\t// @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this\r\n\t// Creates a popup with the specified content and options and opens it in the given point on a map.\r\n\topenPopup: function (popup, latlng, options) {\r\n\t\tif (!(popup instanceof Popup)) {\r\n\t\t\tpopup = new Popup(options).setContent(popup);\r\n\t\t}\r\n\r\n\t\tif (latlng) {\r\n\t\t\tpopup.setLatLng(latlng);\r\n\t\t}\r\n\r\n\t\tif (this.hasLayer(popup)) {\r\n\t\t\treturn this;\r\n\t\t}\r\n\r\n\t\tif (this._popup && this._popup.options.autoClose) {\r\n\t\t\tthis.closePopup();\r\n\t\t}\r\n\r\n\t\tthis._popup = popup;\r\n\t\treturn this.addLayer(popup);\r\n\t},\r\n\r\n\t// @method closePopup(popup?: Popup): this\r\n\t// Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).\r\n\tclosePopup: function (popup) {\r\n\t\tif (!popup || popup === this._popup) {\r\n\t\t\tpopup = this._popup;\r\n\t\t\tthis._popup = null;\r\n\t\t}\r\n\t\tif (popup) {\r\n\t\t\tthis.removeLayer(popup);\r\n\t\t}\r\n\t\treturn this;\r\n\t}\r\n});\r\n\r\n/*\r\n * @namespace Layer\r\n * @section Popup methods example\r\n *\r\n * All layers share a set of methods convenient for binding popups to it.\r\n *\r\n * ```js\r\n * var layer = L.Polygon(latlngs).bindPopup('Hi There!').addTo(map);\r\n * layer.openPopup();\r\n * layer.closePopup();\r\n * ```\r\n *\r\n * Popups will also be automatically opened when the layer is clicked on and closed when the layer is removed from the map or another popup is opened.\r\n */\r\n\r\n// @section Popup methods\r\nLayer.include({\r\n\r\n\t// @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this\r\n\t// Binds a popup to the layer with the passed `content` and sets up the\r\n\t// necessary event listeners. If a `Function` is passed it will receive\r\n\t// the layer as the first argument and should return a `String` or `HTMLElement`.\r\n\tbindPopup: function (content, options) {\r\n\r\n\t\tif (content instanceof Popup) {\r\n\t\t\tsetOptions(content, options);\r\n\t\t\tthis._popup = content;\r\n\t\t\tcontent._source = this;\r\n\t\t} else {\r\n\t\t\tif (!this._popup || options) {\r\n\t\t\t\tthis._popup = new Popup(options, this);\r\n\t\t\t}\r\n\t\t\tthis._popup.setContent(content);\r\n\t\t}\r\n\r\n\t\tif (!this._popupHandlersAdded) {\r\n\t\t\tthis.on({\r\n\t\t\t\tclick: this._openPopup,\r\n\t\t\t\tkeypress: this._onKeyPress,\r\n\t\t\t\tremove: this.closePopup,\r\n\t\t\t\tmove: this._movePopup\r\n\t\t\t});\r\n\t\t\tthis._popupHandlersAdded = true;\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method unbindPopup(): this\r\n\t// Removes the popup previously bound with `bindPopup`.\r\n\tunbindPopup: function () {\r\n\t\tif (this._popup) {\r\n\t\t\tthis.off({\r\n\t\t\t\tclick: this._openPopup,\r\n\t\t\t\tkeypress: this._onKeyPress,\r\n\t\t\t\tremove: this.closePopup,\r\n\t\t\t\tmove: this._movePopup\r\n\t\t\t});\r\n\t\t\tthis._popupHandlersAdded = false;\r\n\t\t\tthis._popup = null;\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method openPopup(latlng?: LatLng): this\r\n\t// Opens the bound popup at the specified `latlng` or at the default popup anchor if no `latlng` is passed.\r\n\topenPopup: function (layer, latlng) {\r\n\t\tif (!(layer instanceof Layer)) {\r\n\t\t\tlatlng = layer;\r\n\t\t\tlayer = this;\r\n\t\t}\r\n\r\n\t\tif (layer instanceof FeatureGroup) {\r\n\t\t\tfor (var id in this._layers) {\r\n\t\t\t\tlayer = this._layers[id];\r\n\t\t\t\tbreak;\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tif (!latlng) {\r\n\t\t\tlatlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();\r\n\t\t}\r\n\r\n\t\tif (this._popup && this._map) {\r\n\t\t\t// set popup source to this layer\r\n\t\t\tthis._popup._source = layer;\r\n\r\n\t\t\t// update the popup (content, layout, ect...)\r\n\t\t\tthis._popup.update();\r\n\r\n\t\t\t// open the popup on the map\r\n\t\t\tthis._map.openPopup(this._popup, latlng);\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method closePopup(): this\r\n\t// Closes the popup bound to this layer if it is open.\r\n\tclosePopup: function () {\r\n\t\tif (this._popup) {\r\n\t\t\tthis._popup._close();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method togglePopup(): this\r\n\t// Opens or closes the popup bound to this layer depending on its current state.\r\n\ttogglePopup: function (target) {\r\n\t\tif (this._popup) {\r\n\t\t\tif (this._popup._map) {\r\n\t\t\t\tthis.closePopup();\r\n\t\t\t} else {\r\n\t\t\t\tthis.openPopup(target);\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method isPopupOpen(): boolean\r\n\t// Returns `true` if the popup bound to this layer is currently open.\r\n\tisPopupOpen: function () {\r\n\t\treturn (this._popup ? this._popup.isOpen() : false);\r\n\t},\r\n\r\n\t// @method setPopupContent(content: String|HTMLElement|Popup): this\r\n\t// Sets the content of the popup bound to this layer.\r\n\tsetPopupContent: function (content) {\r\n\t\tif (this._popup) {\r\n\t\t\tthis._popup.setContent(content);\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method getPopup(): Popup\r\n\t// Returns the popup bound to this layer.\r\n\tgetPopup: function () {\r\n\t\treturn this._popup;\r\n\t},\r\n\r\n\t_openPopup: function (e) {\r\n\t\tvar layer = e.layer || e.target;\r\n\r\n\t\tif (!this._popup) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\tif (!this._map) {\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// prevent map click\r\n\t\tstop(e);\r\n\r\n\t\t// if this inherits from Path its a vector and we can just\r\n\t\t// open the popup at the new location\r\n\t\tif (layer instanceof Path) {\r\n\t\t\tthis.openPopup(e.layer || e.target, e.latlng);\r\n\t\t\treturn;\r\n\t\t}\r\n\r\n\t\t// otherwise treat it like a marker and figure out\r\n\t\t// if we should toggle it open/closed\r\n\t\tif (this._map.hasLayer(this._popup) && this._popup._source === layer) {\r\n\t\t\tthis.closePopup();\r\n\t\t} else {\r\n\t\t\tthis.openPopup(layer, e.latlng);\r\n\t\t}\r\n\t},\r\n\r\n\t_movePopup: function (e) {\r\n\t\tthis._popup.setLatLng(e.latlng);\r\n\t},\r\n\r\n\t_onKeyPress: function (e) {\r\n\t\tif (e.originalEvent.keyCode === 13) {\r\n\t\t\tthis._openPopup(e);\r\n\t\t}\r\n\t}\r\n});\n\n/*\n * @class Tooltip\n * @inherits DivOverlay\n * @aka L.Tooltip\n * Used to display small texts on top of map layers.\n *\n * @example\n *\n * ```js\n * marker.bindTooltip(\"my tooltip text\").openTooltip();\n * ```\n * Note about tooltip offset. Leaflet takes two options in consideration\n * for computing tooltip offsetting:\n * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.\n * Add a positive x offset to move the tooltip to the right, and a positive y offset to\n * move it to the bottom. Negatives will move to the left and top.\n * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You\n * should adapt this value if you use a custom icon.\n */\n\n\n// @namespace Tooltip\nvar Tooltip = DivOverlay.extend({\n\n\t// @section\n\t// @aka Tooltip options\n\toptions: {\n\t\t// @option pane: String = 'tooltipPane'\n\t\t// `Map pane` where the tooltip will be added.\n\t\tpane: 'tooltipPane',\n\n\t\t// @option offset: Point = Point(0, 0)\n\t\t// Optional offset of the tooltip position.\n\t\toffset: [0, 0],\n\n\t\t// @option direction: String = 'auto'\n\t\t// Direction where to open the tooltip. Possible values are: `right`, `left`,\n\t\t// `top`, `bottom`, `center`, `auto`.\n\t\t// `auto` will dynamically switch between `right` and `left` according to the tooltip\n\t\t// position on the map.\n\t\tdirection: 'auto',\n\n\t\t// @option permanent: Boolean = false\n\t\t// Whether to open the tooltip permanently or only on mouseover.\n\t\tpermanent: false,\n\n\t\t// @option sticky: Boolean = false\n\t\t// If true, the tooltip will follow the mouse instead of being fixed at the feature center.\n\t\tsticky: false,\n\n\t\t// @option interactive: Boolean = false\n\t\t// If true, the tooltip will listen to the feature events.\n\t\tinteractive: false,\n\n\t\t// @option opacity: Number = 0.9\n\t\t// Tooltip container opacity.\n\t\topacity: 0.9\n\t},\n\n\tonAdd: function (map) {\n\t\tDivOverlay.prototype.onAdd.call(this, map);\n\t\tthis.setOpacity(this.options.opacity);\n\n\t\t// @namespace Map\n\t\t// @section Tooltip events\n\t\t// @event tooltipopen: TooltipEvent\n\t\t// Fired when a tooltip is opened in the map.\n\t\tmap.fire('tooltipopen', {tooltip: this});\n\n\t\tif (this._source) {\n\t\t\t// @namespace Layer\n\t\t\t// @section Tooltip events\n\t\t\t// @event tooltipopen: TooltipEvent\n\t\t\t// Fired when a tooltip bound to this layer is opened.\n\t\t\tthis._source.fire('tooltipopen', {tooltip: this}, true);\n\t\t}\n\t},\n\n\tonRemove: function (map) {\n\t\tDivOverlay.prototype.onRemove.call(this, map);\n\n\t\t// @namespace Map\n\t\t// @section Tooltip events\n\t\t// @event tooltipclose: TooltipEvent\n\t\t// Fired when a tooltip in the map is closed.\n\t\tmap.fire('tooltipclose', {tooltip: this});\n\n\t\tif (this._source) {\n\t\t\t// @namespace Layer\n\t\t\t// @section Tooltip events\n\t\t\t// @event tooltipclose: TooltipEvent\n\t\t\t// Fired when a tooltip bound to this layer is closed.\n\t\t\tthis._source.fire('tooltipclose', {tooltip: this}, true);\n\t\t}\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = DivOverlay.prototype.getEvents.call(this);\n\n\t\tif (touch && !this.options.permanent) {\n\t\t\tevents.preclick = this._close;\n\t\t}\n\n\t\treturn events;\n\t},\n\n\t_close: function () {\n\t\tif (this._map) {\n\t\t\tthis._map.closeTooltip(this);\n\t\t}\n\t},\n\n\t_initLayout: function () {\n\t\tvar prefix = 'leaflet-tooltip',\n\t\t className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');\n\n\t\tthis._contentNode = this._container = create$1('div', className);\n\t},\n\n\t_updateLayout: function () {},\n\n\t_adjustPan: function () {},\n\n\t_setPosition: function (pos) {\n\t\tvar map = this._map,\n\t\t container = this._container,\n\t\t centerPoint = map.latLngToContainerPoint(map.getCenter()),\n\t\t tooltipPoint = map.layerPointToContainerPoint(pos),\n\t\t direction = this.options.direction,\n\t\t tooltipWidth = container.offsetWidth,\n\t\t tooltipHeight = container.offsetHeight,\n\t\t offset = toPoint(this.options.offset),\n\t\t anchor = this._getAnchor();\n\n\t\tif (direction === 'top') {\n\t\t\tpos = pos.add(toPoint(-tooltipWidth / 2 + offset.x, -tooltipHeight + offset.y + anchor.y, true));\n\t\t} else if (direction === 'bottom') {\n\t\t\tpos = pos.subtract(toPoint(tooltipWidth / 2 - offset.x, -offset.y, true));\n\t\t} else if (direction === 'center') {\n\t\t\tpos = pos.subtract(toPoint(tooltipWidth / 2 + offset.x, tooltipHeight / 2 - anchor.y + offset.y, true));\n\t\t} else if (direction === 'right' || direction === 'auto' && tooltipPoint.x < centerPoint.x) {\n\t\t\tdirection = 'right';\n\t\t\tpos = pos.add(toPoint(offset.x + anchor.x, anchor.y - tooltipHeight / 2 + offset.y, true));\n\t\t} else {\n\t\t\tdirection = 'left';\n\t\t\tpos = pos.subtract(toPoint(tooltipWidth + anchor.x - offset.x, tooltipHeight / 2 - anchor.y - offset.y, true));\n\t\t}\n\n\t\tremoveClass(container, 'leaflet-tooltip-right');\n\t\tremoveClass(container, 'leaflet-tooltip-left');\n\t\tremoveClass(container, 'leaflet-tooltip-top');\n\t\tremoveClass(container, 'leaflet-tooltip-bottom');\n\t\taddClass(container, 'leaflet-tooltip-' + direction);\n\t\tsetPosition(container, pos);\n\t},\n\n\t_updatePosition: function () {\n\t\tvar pos = this._map.latLngToLayerPoint(this._latlng);\n\t\tthis._setPosition(pos);\n\t},\n\n\tsetOpacity: function (opacity) {\n\t\tthis.options.opacity = opacity;\n\n\t\tif (this._container) {\n\t\t\tsetOpacity(this._container, opacity);\n\t\t}\n\t},\n\n\t_animateZoom: function (e) {\n\t\tvar pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);\n\t\tthis._setPosition(pos);\n\t},\n\n\t_getAnchor: function () {\n\t\t// Where should we anchor the tooltip on the source layer?\n\t\treturn toPoint(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);\n\t}\n\n});\n\n// @namespace Tooltip\n// @factory L.tooltip(options?: Tooltip options, source?: Layer)\n// Instantiates a Tooltip object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.\nvar tooltip = function (options, source) {\n\treturn new Tooltip(options, source);\n};\n\n// @namespace Map\n// @section Methods for Layers and Controls\nMap.include({\n\n\t// @method openTooltip(tooltip: Tooltip): this\n\t// Opens the specified tooltip.\n\t// @alternative\n\t// @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this\n\t// Creates a tooltip with the specified content and options and open it.\n\topenTooltip: function (tooltip, latlng, options) {\n\t\tif (!(tooltip instanceof Tooltip)) {\n\t\t\ttooltip = new Tooltip(options).setContent(tooltip);\n\t\t}\n\n\t\tif (latlng) {\n\t\t\ttooltip.setLatLng(latlng);\n\t\t}\n\n\t\tif (this.hasLayer(tooltip)) {\n\t\t\treturn this;\n\t\t}\n\n\t\treturn this.addLayer(tooltip);\n\t},\n\n\t// @method closeTooltip(tooltip?: Tooltip): this\n\t// Closes the tooltip given as parameter.\n\tcloseTooltip: function (tooltip) {\n\t\tif (tooltip) {\n\t\t\tthis.removeLayer(tooltip);\n\t\t}\n\t\treturn this;\n\t}\n\n});\n\n/*\n * @namespace Layer\n * @section Tooltip methods example\n *\n * All layers share a set of methods convenient for binding tooltips to it.\n *\n * ```js\n * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);\n * layer.openTooltip();\n * layer.closeTooltip();\n * ```\n */\n\n// @section Tooltip methods\nLayer.include({\n\n\t// @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this\n\t// Binds a tooltip to the layer with the passed `content` and sets up the\n\t// necessary event listeners. If a `Function` is passed it will receive\n\t// the layer as the first argument and should return a `String` or `HTMLElement`.\n\tbindTooltip: function (content, options) {\n\n\t\tif (content instanceof Tooltip) {\n\t\t\tsetOptions(content, options);\n\t\t\tthis._tooltip = content;\n\t\t\tcontent._source = this;\n\t\t} else {\n\t\t\tif (!this._tooltip || options) {\n\t\t\t\tthis._tooltip = new Tooltip(options, this);\n\t\t\t}\n\t\t\tthis._tooltip.setContent(content);\n\n\t\t}\n\n\t\tthis._initTooltipInteractions();\n\n\t\tif (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {\n\t\t\tthis.openTooltip();\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t// @method unbindTooltip(): this\n\t// Removes the tooltip previously bound with `bindTooltip`.\n\tunbindTooltip: function () {\n\t\tif (this._tooltip) {\n\t\t\tthis._initTooltipInteractions(true);\n\t\t\tthis.closeTooltip();\n\t\t\tthis._tooltip = null;\n\t\t}\n\t\treturn this;\n\t},\n\n\t_initTooltipInteractions: function (remove$$1) {\n\t\tif (!remove$$1 && this._tooltipHandlersAdded) { return; }\n\t\tvar onOff = remove$$1 ? 'off' : 'on',\n\t\t events = {\n\t\t\tremove: this.closeTooltip,\n\t\t\tmove: this._moveTooltip\n\t\t };\n\t\tif (!this._tooltip.options.permanent) {\n\t\t\tevents.mouseover = this._openTooltip;\n\t\t\tevents.mouseout = this.closeTooltip;\n\t\t\tif (this._tooltip.options.sticky) {\n\t\t\t\tevents.mousemove = this._moveTooltip;\n\t\t\t}\n\t\t\tif (touch) {\n\t\t\t\tevents.click = this._openTooltip;\n\t\t\t}\n\t\t} else {\n\t\t\tevents.add = this._openTooltip;\n\t\t}\n\t\tthis[onOff](events);\n\t\tthis._tooltipHandlersAdded = !remove$$1;\n\t},\n\n\t// @method openTooltip(latlng?: LatLng): this\n\t// Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.\n\topenTooltip: function (layer, latlng) {\n\t\tif (!(layer instanceof Layer)) {\n\t\t\tlatlng = layer;\n\t\t\tlayer = this;\n\t\t}\n\n\t\tif (layer instanceof FeatureGroup) {\n\t\t\tfor (var id in this._layers) {\n\t\t\t\tlayer = this._layers[id];\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (!latlng) {\n\t\t\tlatlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();\n\t\t}\n\n\t\tif (this._tooltip && this._map) {\n\n\t\t\t// set tooltip source to this layer\n\t\t\tthis._tooltip._source = layer;\n\n\t\t\t// update the tooltip (content, layout, ect...)\n\t\t\tthis._tooltip.update();\n\n\t\t\t// open the tooltip on the map\n\t\t\tthis._map.openTooltip(this._tooltip, latlng);\n\n\t\t\t// Tooltip container may not be defined if not permanent and never\n\t\t\t// opened.\n\t\t\tif (this._tooltip.options.interactive && this._tooltip._container) {\n\t\t\t\taddClass(this._tooltip._container, 'leaflet-clickable');\n\t\t\t\tthis.addInteractiveTarget(this._tooltip._container);\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t// @method closeTooltip(): this\n\t// Closes the tooltip bound to this layer if it is open.\n\tcloseTooltip: function () {\n\t\tif (this._tooltip) {\n\t\t\tthis._tooltip._close();\n\t\t\tif (this._tooltip.options.interactive && this._tooltip._container) {\n\t\t\t\tremoveClass(this._tooltip._container, 'leaflet-clickable');\n\t\t\t\tthis.removeInteractiveTarget(this._tooltip._container);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method toggleTooltip(): this\n\t// Opens or closes the tooltip bound to this layer depending on its current state.\n\ttoggleTooltip: function (target) {\n\t\tif (this._tooltip) {\n\t\t\tif (this._tooltip._map) {\n\t\t\t\tthis.closeTooltip();\n\t\t\t} else {\n\t\t\t\tthis.openTooltip(target);\n\t\t\t}\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method isTooltipOpen(): boolean\n\t// Returns `true` if the tooltip bound to this layer is currently open.\n\tisTooltipOpen: function () {\n\t\treturn this._tooltip.isOpen();\n\t},\n\n\t// @method setTooltipContent(content: String|HTMLElement|Tooltip): this\n\t// Sets the content of the tooltip bound to this layer.\n\tsetTooltipContent: function (content) {\n\t\tif (this._tooltip) {\n\t\t\tthis._tooltip.setContent(content);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getTooltip(): Tooltip\n\t// Returns the tooltip bound to this layer.\n\tgetTooltip: function () {\n\t\treturn this._tooltip;\n\t},\n\n\t_openTooltip: function (e) {\n\t\tvar layer = e.layer || e.target;\n\n\t\tif (!this._tooltip || !this._map) {\n\t\t\treturn;\n\t\t}\n\t\tthis.openTooltip(layer, this._tooltip.options.sticky ? e.latlng : undefined);\n\t},\n\n\t_moveTooltip: function (e) {\n\t\tvar latlng = e.latlng, containerPoint, layerPoint;\n\t\tif (this._tooltip.options.sticky && e.originalEvent) {\n\t\t\tcontainerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);\n\t\t\tlayerPoint = this._map.containerPointToLayerPoint(containerPoint);\n\t\t\tlatlng = this._map.layerPointToLatLng(layerPoint);\n\t\t}\n\t\tthis._tooltip.setLatLng(latlng);\n\t}\n});\n\n/*\n * @class DivIcon\n * @aka L.DivIcon\n * @inherits Icon\n *\n * Represents a lightweight icon for markers that uses a simple ``\n * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options.\n *\n * @example\n * ```js\n * var myIcon = L.divIcon({className: 'my-div-icon'});\n * // you can set .my-div-icon styles in CSS\n *\n * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);\n * ```\n *\n * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow.\n */\n\nvar DivIcon = Icon.extend({\n\toptions: {\n\t\t// @section\n\t\t// @aka DivIcon options\n\t\ticonSize: [12, 12], // also can be set through CSS\n\n\t\t// iconAnchor: (Point),\n\t\t// popupAnchor: (Point),\n\n\t\t// @option html: String = ''\n\t\t// Custom HTML code to put inside the div element, empty by default.\n\t\thtml: false,\n\n\t\t// @option bgPos: Point = [0, 0]\n\t\t// Optional relative position of the background, in pixels\n\t\tbgPos: null,\n\n\t\tclassName: 'leaflet-div-icon'\n\t},\n\n\tcreateIcon: function (oldIcon) {\n\t\tvar div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),\n\t\t options = this.options;\n\n\t\tdiv.innerHTML = options.html !== false ? options.html : '';\n\n\t\tif (options.bgPos) {\n\t\t\tvar bgPos = toPoint(options.bgPos);\n\t\t\tdiv.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';\n\t\t}\n\t\tthis._setIconStyles(div, 'icon');\n\n\t\treturn div;\n\t},\n\n\tcreateShadow: function () {\n\t\treturn null;\n\t}\n});\n\n// @factory L.divIcon(options: DivIcon options)\n// Creates a `DivIcon` instance with the given options.\nfunction divIcon(options) {\n\treturn new DivIcon(options);\n}\n\nIcon.Default = IconDefault;\n\n/*\n * @class GridLayer\n * @inherits Layer\n * @aka L.GridLayer\n *\n * Generic class for handling a tiled grid of HTML elements. This is the base class for all tile layers and replaces `TileLayer.Canvas`.\n * GridLayer can be extended to create a tiled grid of HTML elements like `
`, ` ` or ``. GridLayer will handle creating and animating these DOM elements for you.\n *\n *\n * @section Synchronous usage\n * @example\n *\n * To create a custom layer, extend GridLayer and implement the `createTile()` method, which will be passed a `Point` object with the `x`, `y`, and `z` (zoom level) coordinates to draw your tile.\n *\n * ```js\n * var CanvasLayer = L.GridLayer.extend({\n * createTile: function(coords){\n * // create a
element for drawing\n * var tile = L.DomUtil.create('canvas', 'leaflet-tile');\n *\n * // setup tile width and height according to the options\n * var size = this.getTileSize();\n * tile.width = size.x;\n * tile.height = size.y;\n *\n * // get a canvas context and draw something on it using coords.x, coords.y and coords.z\n * var ctx = tile.getContext('2d');\n *\n * // return the tile so it can be rendered on screen\n * return tile;\n * }\n * });\n * ```\n *\n * @section Asynchronous usage\n * @example\n *\n * Tile creation can also be asynchronous, this is useful when using a third-party drawing library. Once the tile is finished drawing it can be passed to the `done()` callback.\n *\n * ```js\n * var CanvasLayer = L.GridLayer.extend({\n * createTile: function(coords, done){\n * var error;\n *\n * // create a element for drawing\n * var tile = L.DomUtil.create('canvas', 'leaflet-tile');\n *\n * // setup tile width and height according to the options\n * var size = this.getTileSize();\n * tile.width = size.x;\n * tile.height = size.y;\n *\n * // draw something asynchronously and pass the tile to the done() callback\n * setTimeout(function() {\n * done(error, tile);\n * }, 1000);\n *\n * return tile;\n * }\n * });\n * ```\n *\n * @section\n */\n\n\nvar GridLayer = Layer.extend({\n\n\t// @section\n\t// @aka GridLayer options\n\toptions: {\n\t\t// @option tileSize: Number|Point = 256\n\t\t// Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise.\n\t\ttileSize: 256,\n\n\t\t// @option opacity: Number = 1.0\n\t\t// Opacity of the tiles. Can be used in the `createTile()` function.\n\t\topacity: 1,\n\n\t\t// @option updateWhenIdle: Boolean = (depends)\n\t\t// Load new tiles only when panning ends.\n\t\t// `true` by default on mobile browsers, in order to avoid too many requests and keep smooth navigation.\n\t\t// `false` otherwise in order to display new tiles _during_ panning, since it is easy to pan outside the\n\t\t// [`keepBuffer`](#gridlayer-keepbuffer) option in desktop browsers.\n\t\tupdateWhenIdle: mobile,\n\n\t\t// @option updateWhenZooming: Boolean = true\n\t\t// By default, a smooth zoom animation (during a [touch zoom](#map-touchzoom) or a [`flyTo()`](#map-flyto)) will update grid layers every integer zoom level. Setting this option to `false` will update the grid layer only when the smooth animation ends.\n\t\tupdateWhenZooming: true,\n\n\t\t// @option updateInterval: Number = 200\n\t\t// Tiles will not update more than once every `updateInterval` milliseconds when panning.\n\t\tupdateInterval: 200,\n\n\t\t// @option zIndex: Number = 1\n\t\t// The explicit zIndex of the tile layer.\n\t\tzIndex: 1,\n\n\t\t// @option bounds: LatLngBounds = undefined\n\t\t// If set, tiles will only be loaded inside the set `LatLngBounds`.\n\t\tbounds: null,\n\n\t\t// @option minZoom: Number = 0\n\t\t// The minimum zoom level down to which this layer will be displayed (inclusive).\n\t\tminZoom: 0,\n\n\t\t// @option maxZoom: Number = undefined\n\t\t// The maximum zoom level up to which this layer will be displayed (inclusive).\n\t\tmaxZoom: undefined,\n\n\t\t// @option maxNativeZoom: Number = undefined\n\t\t// Maximum zoom number the tile source has available. If it is specified,\n\t\t// the tiles on all zoom levels higher than `maxNativeZoom` will be loaded\n\t\t// from `maxNativeZoom` level and auto-scaled.\n\t\tmaxNativeZoom: undefined,\n\n\t\t// @option minNativeZoom: Number = undefined\n\t\t// Minimum zoom number the tile source has available. If it is specified,\n\t\t// the tiles on all zoom levels lower than `minNativeZoom` will be loaded\n\t\t// from `minNativeZoom` level and auto-scaled.\n\t\tminNativeZoom: undefined,\n\n\t\t// @option noWrap: Boolean = false\n\t\t// Whether the layer is wrapped around the antimeridian. If `true`, the\n\t\t// GridLayer will only be displayed once at low zoom levels. Has no\n\t\t// effect when the [map CRS](#map-crs) doesn't wrap around. Can be used\n\t\t// in combination with [`bounds`](#gridlayer-bounds) to prevent requesting\n\t\t// tiles outside the CRS limits.\n\t\tnoWrap: false,\n\n\t\t// @option pane: String = 'tilePane'\n\t\t// `Map pane` where the grid layer will be added.\n\t\tpane: 'tilePane',\n\n\t\t// @option className: String = ''\n\t\t// A custom class name to assign to the tile layer. Empty by default.\n\t\tclassName: '',\n\n\t\t// @option keepBuffer: Number = 2\n\t\t// When panning the map, keep this many rows and columns of tiles before unloading them.\n\t\tkeepBuffer: 2\n\t},\n\n\tinitialize: function (options) {\n\t\tsetOptions(this, options);\n\t},\n\n\tonAdd: function () {\n\t\tthis._initContainer();\n\n\t\tthis._levels = {};\n\t\tthis._tiles = {};\n\n\t\tthis._resetView();\n\t\tthis._update();\n\t},\n\n\tbeforeAdd: function (map) {\n\t\tmap._addZoomLimit(this);\n\t},\n\n\tonRemove: function (map) {\n\t\tthis._removeAllTiles();\n\t\tremove(this._container);\n\t\tmap._removeZoomLimit(this);\n\t\tthis._container = null;\n\t\tthis._tileZoom = undefined;\n\t},\n\n\t// @method bringToFront: this\n\t// Brings the tile layer to the top of all tile layers.\n\tbringToFront: function () {\n\t\tif (this._map) {\n\t\t\ttoFront(this._container);\n\t\t\tthis._setAutoZIndex(Math.max);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method bringToBack: this\n\t// Brings the tile layer to the bottom of all tile layers.\n\tbringToBack: function () {\n\t\tif (this._map) {\n\t\t\ttoBack(this._container);\n\t\t\tthis._setAutoZIndex(Math.min);\n\t\t}\n\t\treturn this;\n\t},\n\n\t// @method getContainer: HTMLElement\n\t// Returns the HTML element that contains the tiles for this layer.\n\tgetContainer: function () {\n\t\treturn this._container;\n\t},\n\n\t// @method setOpacity(opacity: Number): this\n\t// Changes the [opacity](#gridlayer-opacity) of the grid layer.\n\tsetOpacity: function (opacity) {\n\t\tthis.options.opacity = opacity;\n\t\tthis._updateOpacity();\n\t\treturn this;\n\t},\n\n\t// @method setZIndex(zIndex: Number): this\n\t// Changes the [zIndex](#gridlayer-zindex) of the grid layer.\n\tsetZIndex: function (zIndex) {\n\t\tthis.options.zIndex = zIndex;\n\t\tthis._updateZIndex();\n\n\t\treturn this;\n\t},\n\n\t// @method isLoading: Boolean\n\t// Returns `true` if any tile in the grid layer has not finished loading.\n\tisLoading: function () {\n\t\treturn this._loading;\n\t},\n\n\t// @method redraw: this\n\t// Causes the layer to clear all the tiles and request them again.\n\tredraw: function () {\n\t\tif (this._map) {\n\t\t\tthis._removeAllTiles();\n\t\t\tthis._update();\n\t\t}\n\t\treturn this;\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = {\n\t\t\tviewprereset: this._invalidateAll,\n\t\t\tviewreset: this._resetView,\n\t\t\tzoom: this._resetView,\n\t\t\tmoveend: this._onMoveEnd\n\t\t};\n\n\t\tif (!this.options.updateWhenIdle) {\n\t\t\t// update tiles on move, but not more often than once per given interval\n\t\t\tif (!this._onMove) {\n\t\t\t\tthis._onMove = throttle(this._onMoveEnd, this.options.updateInterval, this);\n\t\t\t}\n\n\t\t\tevents.move = this._onMove;\n\t\t}\n\n\t\tif (this._zoomAnimated) {\n\t\t\tevents.zoomanim = this._animateZoom;\n\t\t}\n\n\t\treturn events;\n\t},\n\n\t// @section Extension methods\n\t// Layers extending `GridLayer` shall reimplement the following method.\n\t// @method createTile(coords: Object, done?: Function): HTMLElement\n\t// Called only internally, must be overridden by classes extending `GridLayer`.\n\t// Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback\n\t// is specified, it must be called when the tile has finished loading and drawing.\n\tcreateTile: function () {\n\t\treturn document.createElement('div');\n\t},\n\n\t// @section\n\t// @method getTileSize: Point\n\t// Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method.\n\tgetTileSize: function () {\n\t\tvar s = this.options.tileSize;\n\t\treturn s instanceof Point ? s : new Point(s, s);\n\t},\n\n\t_updateZIndex: function () {\n\t\tif (this._container && this.options.zIndex !== undefined && this.options.zIndex !== null) {\n\t\t\tthis._container.style.zIndex = this.options.zIndex;\n\t\t}\n\t},\n\n\t_setAutoZIndex: function (compare) {\n\t\t// go through all other layers of the same pane, set zIndex to max + 1 (front) or min - 1 (back)\n\n\t\tvar layers = this.getPane().children,\n\t\t edgeZIndex = -compare(-Infinity, Infinity); // -Infinity for max, Infinity for min\n\n\t\tfor (var i = 0, len = layers.length, zIndex; i < len; i++) {\n\n\t\t\tzIndex = layers[i].style.zIndex;\n\n\t\t\tif (layers[i] !== this._container && zIndex) {\n\t\t\t\tedgeZIndex = compare(edgeZIndex, +zIndex);\n\t\t\t}\n\t\t}\n\n\t\tif (isFinite(edgeZIndex)) {\n\t\t\tthis.options.zIndex = edgeZIndex + compare(-1, 1);\n\t\t\tthis._updateZIndex();\n\t\t}\n\t},\n\n\t_updateOpacity: function () {\n\t\tif (!this._map) { return; }\n\n\t\t// IE doesn't inherit filter opacity properly, so we're forced to set it on tiles\n\t\tif (ielt9) { return; }\n\n\t\tsetOpacity(this._container, this.options.opacity);\n\n\t\tvar now = +new Date(),\n\t\t nextFrame = false,\n\t\t willPrune = false;\n\n\t\tfor (var key in this._tiles) {\n\t\t\tvar tile = this._tiles[key];\n\t\t\tif (!tile.current || !tile.loaded) { continue; }\n\n\t\t\tvar fade = Math.min(1, (now - tile.loaded) / 200);\n\n\t\t\tsetOpacity(tile.el, fade);\n\t\t\tif (fade < 1) {\n\t\t\t\tnextFrame = true;\n\t\t\t} else {\n\t\t\t\tif (tile.active) {\n\t\t\t\t\twillPrune = true;\n\t\t\t\t} else {\n\t\t\t\t\tthis._onOpaqueTile(tile);\n\t\t\t\t}\n\t\t\t\ttile.active = true;\n\t\t\t}\n\t\t}\n\n\t\tif (willPrune && !this._noPrune) { this._pruneTiles(); }\n\n\t\tif (nextFrame) {\n\t\t\tcancelAnimFrame(this._fadeFrame);\n\t\t\tthis._fadeFrame = requestAnimFrame(this._updateOpacity, this);\n\t\t}\n\t},\n\n\t_onOpaqueTile: falseFn,\n\n\t_initContainer: function () {\n\t\tif (this._container) { return; }\n\n\t\tthis._container = create$1('div', 'leaflet-layer ' + (this.options.className || ''));\n\t\tthis._updateZIndex();\n\n\t\tif (this.options.opacity < 1) {\n\t\t\tthis._updateOpacity();\n\t\t}\n\n\t\tthis.getPane().appendChild(this._container);\n\t},\n\n\t_updateLevels: function () {\n\n\t\tvar zoom = this._tileZoom,\n\t\t maxZoom = this.options.maxZoom;\n\n\t\tif (zoom === undefined) { return undefined; }\n\n\t\tfor (var z in this._levels) {\n\t\t\tif (this._levels[z].el.children.length || z === zoom) {\n\t\t\t\tthis._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);\n\t\t\t\tthis._onUpdateLevel(z);\n\t\t\t} else {\n\t\t\t\tremove(this._levels[z].el);\n\t\t\t\tthis._removeTilesAtZoom(z);\n\t\t\t\tthis._onRemoveLevel(z);\n\t\t\t\tdelete this._levels[z];\n\t\t\t}\n\t\t}\n\n\t\tvar level = this._levels[zoom],\n\t\t map = this._map;\n\n\t\tif (!level) {\n\t\t\tlevel = this._levels[zoom] = {};\n\n\t\t\tlevel.el = create$1('div', 'leaflet-tile-container leaflet-zoom-animated', this._container);\n\t\t\tlevel.el.style.zIndex = maxZoom;\n\n\t\t\tlevel.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();\n\t\t\tlevel.zoom = zoom;\n\n\t\t\tthis._setZoomTransform(level, map.getCenter(), map.getZoom());\n\n\t\t\t// force the browser to consider the newly added element for transition\n\t\t\tfalseFn(level.el.offsetWidth);\n\n\t\t\tthis._onCreateLevel(level);\n\t\t}\n\n\t\tthis._level = level;\n\n\t\treturn level;\n\t},\n\n\t_onUpdateLevel: falseFn,\n\n\t_onRemoveLevel: falseFn,\n\n\t_onCreateLevel: falseFn,\n\n\t_pruneTiles: function () {\n\t\tif (!this._map) {\n\t\t\treturn;\n\t\t}\n\n\t\tvar key, tile;\n\n\t\tvar zoom = this._map.getZoom();\n\t\tif (zoom > this.options.maxZoom ||\n\t\t\tzoom < this.options.minZoom) {\n\t\t\tthis._removeAllTiles();\n\t\t\treturn;\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\ttile = this._tiles[key];\n\t\t\ttile.retain = tile.current;\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\ttile = this._tiles[key];\n\t\t\tif (tile.current && !tile.active) {\n\t\t\t\tvar coords = tile.coords;\n\t\t\t\tif (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) {\n\t\t\t\t\tthis._retainChildren(coords.x, coords.y, coords.z, coords.z + 2);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tfor (key in this._tiles) {\n\t\t\tif (!this._tiles[key].retain) {\n\t\t\t\tthis._removeTile(key);\n\t\t\t}\n\t\t}\n\t},\n\n\t_removeTilesAtZoom: function (zoom) {\n\t\tfor (var key in this._tiles) {\n\t\t\tif (this._tiles[key].coords.z !== zoom) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis._removeTile(key);\n\t\t}\n\t},\n\n\t_removeAllTiles: function () {\n\t\tfor (var key in this._tiles) {\n\t\t\tthis._removeTile(key);\n\t\t}\n\t},\n\n\t_invalidateAll: function () {\n\t\tfor (var z in this._levels) {\n\t\t\tremove(this._levels[z].el);\n\t\t\tthis._onRemoveLevel(z);\n\t\t\tdelete this._levels[z];\n\t\t}\n\t\tthis._removeAllTiles();\n\n\t\tthis._tileZoom = undefined;\n\t},\n\n\t_retainParent: function (x, y, z, minZoom) {\n\t\tvar x2 = Math.floor(x / 2),\n\t\t y2 = Math.floor(y / 2),\n\t\t z2 = z - 1,\n\t\t coords2 = new Point(+x2, +y2);\n\t\tcoords2.z = +z2;\n\n\t\tvar key = this._tileCoordsToKey(coords2),\n\t\t tile = this._tiles[key];\n\n\t\tif (tile && tile.active) {\n\t\t\ttile.retain = true;\n\t\t\treturn true;\n\n\t\t} else if (tile && tile.loaded) {\n\t\t\ttile.retain = true;\n\t\t}\n\n\t\tif (z2 > minZoom) {\n\t\t\treturn this._retainParent(x2, y2, z2, minZoom);\n\t\t}\n\n\t\treturn false;\n\t},\n\n\t_retainChildren: function (x, y, z, maxZoom) {\n\n\t\tfor (var i = 2 * x; i < 2 * x + 2; i++) {\n\t\t\tfor (var j = 2 * y; j < 2 * y + 2; j++) {\n\n\t\t\t\tvar coords = new Point(i, j);\n\t\t\t\tcoords.z = z + 1;\n\n\t\t\t\tvar key = this._tileCoordsToKey(coords),\n\t\t\t\t tile = this._tiles[key];\n\n\t\t\t\tif (tile && tile.active) {\n\t\t\t\t\ttile.retain = true;\n\t\t\t\t\tcontinue;\n\n\t\t\t\t} else if (tile && tile.loaded) {\n\t\t\t\t\ttile.retain = true;\n\t\t\t\t}\n\n\t\t\t\tif (z + 1 < maxZoom) {\n\t\t\t\t\tthis._retainChildren(i, j, z + 1, maxZoom);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t_resetView: function (e) {\n\t\tvar animating = e && (e.pinch || e.flyTo);\n\t\tthis._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);\n\t},\n\n\t_animateZoom: function (e) {\n\t\tthis._setView(e.center, e.zoom, true, e.noUpdate);\n\t},\n\n\t_clampZoom: function (zoom) {\n\t\tvar options = this.options;\n\n\t\tif (undefined !== options.minNativeZoom && zoom < options.minNativeZoom) {\n\t\t\treturn options.minNativeZoom;\n\t\t}\n\n\t\tif (undefined !== options.maxNativeZoom && options.maxNativeZoom < zoom) {\n\t\t\treturn options.maxNativeZoom;\n\t\t}\n\n\t\treturn zoom;\n\t},\n\n\t_setView: function (center, zoom, noPrune, noUpdate) {\n\t\tvar tileZoom = this._clampZoom(Math.round(zoom));\n\t\tif ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) ||\n\t\t (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) {\n\t\t\ttileZoom = undefined;\n\t\t}\n\n\t\tvar tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom);\n\n\t\tif (!noUpdate || tileZoomChanged) {\n\n\t\t\tthis._tileZoom = tileZoom;\n\n\t\t\tif (this._abortLoading) {\n\t\t\t\tthis._abortLoading();\n\t\t\t}\n\n\t\t\tthis._updateLevels();\n\t\t\tthis._resetGrid();\n\n\t\t\tif (tileZoom !== undefined) {\n\t\t\t\tthis._update(center);\n\t\t\t}\n\n\t\t\tif (!noPrune) {\n\t\t\t\tthis._pruneTiles();\n\t\t\t}\n\n\t\t\t// Flag to prevent _updateOpacity from pruning tiles during\n\t\t\t// a zoom anim or a pinch gesture\n\t\t\tthis._noPrune = !!noPrune;\n\t\t}\n\n\t\tthis._setZoomTransforms(center, zoom);\n\t},\n\n\t_setZoomTransforms: function (center, zoom) {\n\t\tfor (var i in this._levels) {\n\t\t\tthis._setZoomTransform(this._levels[i], center, zoom);\n\t\t}\n\t},\n\n\t_setZoomTransform: function (level, center, zoom) {\n\t\tvar scale = this._map.getZoomScale(zoom, level.zoom),\n\t\t translate = level.origin.multiplyBy(scale)\n\t\t .subtract(this._map._getNewPixelOrigin(center, zoom)).round();\n\n\t\tif (any3d) {\n\t\t\tsetTransform(level.el, translate, scale);\n\t\t} else {\n\t\t\tsetPosition(level.el, translate);\n\t\t}\n\t},\n\n\t_resetGrid: function () {\n\t\tvar map = this._map,\n\t\t crs = map.options.crs,\n\t\t tileSize = this._tileSize = this.getTileSize(),\n\t\t tileZoom = this._tileZoom;\n\n\t\tvar bounds = this._map.getPixelWorldBounds(this._tileZoom);\n\t\tif (bounds) {\n\t\t\tthis._globalTileRange = this._pxBoundsToTileRange(bounds);\n\t\t}\n\n\t\tthis._wrapX = crs.wrapLng && !this.options.noWrap && [\n\t\t\tMath.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),\n\t\t\tMath.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)\n\t\t];\n\t\tthis._wrapY = crs.wrapLat && !this.options.noWrap && [\n\t\t\tMath.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),\n\t\t\tMath.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)\n\t\t];\n\t},\n\n\t_onMoveEnd: function () {\n\t\tif (!this._map || this._map._animatingZoom) { return; }\n\n\t\tthis._update();\n\t},\n\n\t_getTiledPixelBounds: function (center) {\n\t\tvar map = this._map,\n\t\t mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),\n\t\t scale = map.getZoomScale(mapZoom, this._tileZoom),\n\t\t pixelCenter = map.project(center, this._tileZoom).floor(),\n\t\t halfSize = map.getSize().divideBy(scale * 2);\n\n\t\treturn new Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));\n\t},\n\n\t// Private method to load tiles in the grid's active zoom level according to map bounds\n\t_update: function (center) {\n\t\tvar map = this._map;\n\t\tif (!map) { return; }\n\t\tvar zoom = this._clampZoom(map.getZoom());\n\n\t\tif (center === undefined) { center = map.getCenter(); }\n\t\tif (this._tileZoom === undefined) { return; }\t// if out of minzoom/maxzoom\n\n\t\tvar pixelBounds = this._getTiledPixelBounds(center),\n\t\t tileRange = this._pxBoundsToTileRange(pixelBounds),\n\t\t tileCenter = tileRange.getCenter(),\n\t\t queue = [],\n\t\t margin = this.options.keepBuffer,\n\t\t noPruneRange = new Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),\n\t\t tileRange.getTopRight().add([margin, -margin]));\n\n\t\t// Sanity check: panic if the tile range contains Infinity somewhere.\n\t\tif (!(isFinite(tileRange.min.x) &&\n\t\t isFinite(tileRange.min.y) &&\n\t\t isFinite(tileRange.max.x) &&\n\t\t isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); }\n\n\t\tfor (var key in this._tiles) {\n\t\t\tvar c = this._tiles[key].coords;\n\t\t\tif (c.z !== this._tileZoom || !noPruneRange.contains(new Point(c.x, c.y))) {\n\t\t\t\tthis._tiles[key].current = false;\n\t\t\t}\n\t\t}\n\n\t\t// _update just loads more tiles. If the tile zoom level differs too much\n\t\t// from the map's, let _setView reset levels and prune old tiles.\n\t\tif (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }\n\n\t\t// create a queue of coordinates to load tiles from\n\t\tfor (var j = tileRange.min.y; j <= tileRange.max.y; j++) {\n\t\t\tfor (var i = tileRange.min.x; i <= tileRange.max.x; i++) {\n\t\t\t\tvar coords = new Point(i, j);\n\t\t\t\tcoords.z = this._tileZoom;\n\n\t\t\t\tif (!this._isValidTile(coords)) { continue; }\n\n\t\t\t\tvar tile = this._tiles[this._tileCoordsToKey(coords)];\n\t\t\t\tif (tile) {\n\t\t\t\t\ttile.current = true;\n\t\t\t\t} else {\n\t\t\t\t\tqueue.push(coords);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// sort tile queue to load tiles in order of their distance to center\n\t\tqueue.sort(function (a, b) {\n\t\t\treturn a.distanceTo(tileCenter) - b.distanceTo(tileCenter);\n\t\t});\n\n\t\tif (queue.length !== 0) {\n\t\t\t// if it's the first batch of tiles to load\n\t\t\tif (!this._loading) {\n\t\t\t\tthis._loading = true;\n\t\t\t\t// @event loading: Event\n\t\t\t\t// Fired when the grid layer starts loading tiles.\n\t\t\t\tthis.fire('loading');\n\t\t\t}\n\n\t\t\t// create DOM fragment to append tiles in one batch\n\t\t\tvar fragment = document.createDocumentFragment();\n\n\t\t\tfor (i = 0; i < queue.length; i++) {\n\t\t\t\tthis._addTile(queue[i], fragment);\n\t\t\t}\n\n\t\t\tthis._level.el.appendChild(fragment);\n\t\t}\n\t},\n\n\t_isValidTile: function (coords) {\n\t\tvar crs = this._map.options.crs;\n\n\t\tif (!crs.infinite) {\n\t\t\t// don't load tile if it's out of bounds and not wrapped\n\t\t\tvar bounds = this._globalTileRange;\n\t\t\tif ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||\n\t\t\t (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }\n\t\t}\n\n\t\tif (!this.options.bounds) { return true; }\n\n\t\t// don't load tile if it doesn't intersect the bounds in options\n\t\tvar tileBounds = this._tileCoordsToBounds(coords);\n\t\treturn toLatLngBounds(this.options.bounds).overlaps(tileBounds);\n\t},\n\n\t_keyToBounds: function (key) {\n\t\treturn this._tileCoordsToBounds(this._keyToTileCoords(key));\n\t},\n\n\t_tileCoordsToNwSe: function (coords) {\n\t\tvar map = this._map,\n\t\t tileSize = this.getTileSize(),\n\t\t nwPoint = coords.scaleBy(tileSize),\n\t\t sePoint = nwPoint.add(tileSize),\n\t\t nw = map.unproject(nwPoint, coords.z),\n\t\t se = map.unproject(sePoint, coords.z);\n\t\treturn [nw, se];\n\t},\n\n\t// converts tile coordinates to its geographical bounds\n\t_tileCoordsToBounds: function (coords) {\n\t\tvar bp = this._tileCoordsToNwSe(coords),\n\t\t bounds = new LatLngBounds(bp[0], bp[1]);\n\n\t\tif (!this.options.noWrap) {\n\t\t\tbounds = this._map.wrapLatLngBounds(bounds);\n\t\t}\n\t\treturn bounds;\n\t},\n\t// converts tile coordinates to key for the tile cache\n\t_tileCoordsToKey: function (coords) {\n\t\treturn coords.x + ':' + coords.y + ':' + coords.z;\n\t},\n\n\t// converts tile cache key to coordinates\n\t_keyToTileCoords: function (key) {\n\t\tvar k = key.split(':'),\n\t\t coords = new Point(+k[0], +k[1]);\n\t\tcoords.z = +k[2];\n\t\treturn coords;\n\t},\n\n\t_removeTile: function (key) {\n\t\tvar tile = this._tiles[key];\n\t\tif (!tile) { return; }\n\n\t\t// Cancels any pending http requests associated with the tile\n\t\t// unless we're on Android's stock browser,\n\t\t// see https://github.com/Leaflet/Leaflet/issues/137\n\t\tif (!androidStock) {\n\t\t\ttile.el.setAttribute('src', emptyImageUrl);\n\t\t}\n\t\tremove(tile.el);\n\n\t\tdelete this._tiles[key];\n\n\t\t// @event tileunload: TileEvent\n\t\t// Fired when a tile is removed (e.g. when a tile goes off the screen).\n\t\tthis.fire('tileunload', {\n\t\t\ttile: tile.el,\n\t\t\tcoords: this._keyToTileCoords(key)\n\t\t});\n\t},\n\n\t_initTile: function (tile) {\n\t\taddClass(tile, 'leaflet-tile');\n\n\t\tvar tileSize = this.getTileSize();\n\t\ttile.style.width = tileSize.x + 'px';\n\t\ttile.style.height = tileSize.y + 'px';\n\n\t\ttile.onselectstart = falseFn;\n\t\ttile.onmousemove = falseFn;\n\n\t\t// update opacity on tiles in IE7-8 because of filter inheritance problems\n\t\tif (ielt9 && this.options.opacity < 1) {\n\t\t\tsetOpacity(tile, this.options.opacity);\n\t\t}\n\n\t\t// without this hack, tiles disappear after zoom on Chrome for Android\n\t\t// https://github.com/Leaflet/Leaflet/issues/2078\n\t\tif (android && !android23) {\n\t\t\ttile.style.WebkitBackfaceVisibility = 'hidden';\n\t\t}\n\t},\n\n\t_addTile: function (coords, container) {\n\t\tvar tilePos = this._getTilePos(coords),\n\t\t key = this._tileCoordsToKey(coords);\n\n\t\tvar tile = this.createTile(this._wrapCoords(coords), bind(this._tileReady, this, coords));\n\n\t\tthis._initTile(tile);\n\n\t\t// if createTile is defined with a second argument (\"done\" callback),\n\t\t// we know that tile is async and will be ready later; otherwise\n\t\tif (this.createTile.length < 2) {\n\t\t\t// mark tile as ready, but delay one frame for opacity animation to happen\n\t\t\trequestAnimFrame(bind(this._tileReady, this, coords, null, tile));\n\t\t}\n\n\t\tsetPosition(tile, tilePos);\n\n\t\t// save tile in cache\n\t\tthis._tiles[key] = {\n\t\t\tel: tile,\n\t\t\tcoords: coords,\n\t\t\tcurrent: true\n\t\t};\n\n\t\tcontainer.appendChild(tile);\n\t\t// @event tileloadstart: TileEvent\n\t\t// Fired when a tile is requested and starts loading.\n\t\tthis.fire('tileloadstart', {\n\t\t\ttile: tile,\n\t\t\tcoords: coords\n\t\t});\n\t},\n\n\t_tileReady: function (coords, err, tile) {\n\t\tif (!this._map) { return; }\n\n\t\tif (err) {\n\t\t\t// @event tileerror: TileErrorEvent\n\t\t\t// Fired when there is an error loading a tile.\n\t\t\tthis.fire('tileerror', {\n\t\t\t\terror: err,\n\t\t\t\ttile: tile,\n\t\t\t\tcoords: coords\n\t\t\t});\n\t\t}\n\n\t\tvar key = this._tileCoordsToKey(coords);\n\n\t\ttile = this._tiles[key];\n\t\tif (!tile) { return; }\n\n\t\ttile.loaded = +new Date();\n\t\tif (this._map._fadeAnimated) {\n\t\t\tsetOpacity(tile.el, 0);\n\t\t\tcancelAnimFrame(this._fadeFrame);\n\t\t\tthis._fadeFrame = requestAnimFrame(this._updateOpacity, this);\n\t\t} else {\n\t\t\ttile.active = true;\n\t\t\tthis._pruneTiles();\n\t\t}\n\n\t\tif (!err) {\n\t\t\taddClass(tile.el, 'leaflet-tile-loaded');\n\n\t\t\t// @event tileload: TileEvent\n\t\t\t// Fired when a tile loads.\n\t\t\tthis.fire('tileload', {\n\t\t\t\ttile: tile.el,\n\t\t\t\tcoords: coords\n\t\t\t});\n\t\t}\n\n\t\tif (this._noTilesToLoad()) {\n\t\t\tthis._loading = false;\n\t\t\t// @event load: Event\n\t\t\t// Fired when the grid layer loaded all visible tiles.\n\t\t\tthis.fire('load');\n\n\t\t\tif (ielt9 || !this._map._fadeAnimated) {\n\t\t\t\trequestAnimFrame(this._pruneTiles, this);\n\t\t\t} else {\n\t\t\t\t// Wait a bit more than 0.2 secs (the duration of the tile fade-in)\n\t\t\t\t// to trigger a pruning.\n\t\t\t\tsetTimeout(bind(this._pruneTiles, this), 250);\n\t\t\t}\n\t\t}\n\t},\n\n\t_getTilePos: function (coords) {\n\t\treturn coords.scaleBy(this.getTileSize()).subtract(this._level.origin);\n\t},\n\n\t_wrapCoords: function (coords) {\n\t\tvar newCoords = new Point(\n\t\t\tthis._wrapX ? wrapNum(coords.x, this._wrapX) : coords.x,\n\t\t\tthis._wrapY ? wrapNum(coords.y, this._wrapY) : coords.y);\n\t\tnewCoords.z = coords.z;\n\t\treturn newCoords;\n\t},\n\n\t_pxBoundsToTileRange: function (bounds) {\n\t\tvar tileSize = this.getTileSize();\n\t\treturn new Bounds(\n\t\t\tbounds.min.unscaleBy(tileSize).floor(),\n\t\t\tbounds.max.unscaleBy(tileSize).ceil().subtract([1, 1]));\n\t},\n\n\t_noTilesToLoad: function () {\n\t\tfor (var key in this._tiles) {\n\t\t\tif (!this._tiles[key].loaded) { return false; }\n\t\t}\n\t\treturn true;\n\t}\n});\n\n// @factory L.gridLayer(options?: GridLayer options)\n// Creates a new instance of GridLayer with the supplied options.\nfunction gridLayer(options) {\n\treturn new GridLayer(options);\n}\n\n/*\r\n * @class TileLayer\r\n * @inherits GridLayer\r\n * @aka L.TileLayer\r\n * Used to load and display tile layers on the map. Extends `GridLayer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * L.tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}).addTo(map);\r\n * ```\r\n *\r\n * @section URL template\r\n * @example\r\n *\r\n * A string of the following form:\r\n *\r\n * ```\r\n * 'http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'\r\n * ```\r\n *\r\n * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add \"@2x\" to the URL to load retina tiles.\r\n *\r\n * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:\r\n *\r\n * ```\r\n * L.tileLayer('http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});\r\n * ```\r\n */\r\n\r\n\r\nvar TileLayer = GridLayer.extend({\r\n\r\n\t// @section\r\n\t// @aka TileLayer options\r\n\toptions: {\r\n\t\t// @option minZoom: Number = 0\r\n\t\t// The minimum zoom level down to which this layer will be displayed (inclusive).\r\n\t\tminZoom: 0,\r\n\r\n\t\t// @option maxZoom: Number = 18\r\n\t\t// The maximum zoom level up to which this layer will be displayed (inclusive).\r\n\t\tmaxZoom: 18,\r\n\r\n\t\t// @option subdomains: String|String[] = 'abc'\r\n\t\t// Subdomains of the tile service. Can be passed in the form of one string (where each letter is a subdomain name) or an array of strings.\r\n\t\tsubdomains: 'abc',\r\n\r\n\t\t// @option errorTileUrl: String = ''\r\n\t\t// URL to the tile image to show in place of the tile that failed to load.\r\n\t\terrorTileUrl: '',\r\n\r\n\t\t// @option zoomOffset: Number = 0\r\n\t\t// The zoom number used in tile URLs will be offset with this value.\r\n\t\tzoomOffset: 0,\r\n\r\n\t\t// @option tms: Boolean = false\r\n\t\t// If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).\r\n\t\ttms: false,\r\n\r\n\t\t// @option zoomReverse: Boolean = false\r\n\t\t// If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)\r\n\t\tzoomReverse: false,\r\n\r\n\t\t// @option detectRetina: Boolean = false\r\n\t\t// If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution.\r\n\t\tdetectRetina: false,\r\n\r\n\t\t// @option crossOrigin: Boolean = false\r\n\t\t// If true, all tiles will have their crossOrigin attribute set to ''. This is needed if you want to access tile pixel data.\r\n\t\tcrossOrigin: false\r\n\t},\r\n\r\n\tinitialize: function (url, options) {\r\n\r\n\t\tthis._url = url;\r\n\r\n\t\toptions = setOptions(this, options);\r\n\r\n\t\t// detecting retina displays, adjusting tileSize and zoom levels\r\n\t\tif (options.detectRetina && retina && options.maxZoom > 0) {\r\n\r\n\t\t\toptions.tileSize = Math.floor(options.tileSize / 2);\r\n\r\n\t\t\tif (!options.zoomReverse) {\r\n\t\t\t\toptions.zoomOffset++;\r\n\t\t\t\toptions.maxZoom--;\r\n\t\t\t} else {\r\n\t\t\t\toptions.zoomOffset--;\r\n\t\t\t\toptions.minZoom++;\r\n\t\t\t}\r\n\r\n\t\t\toptions.minZoom = Math.max(0, options.minZoom);\r\n\t\t}\r\n\r\n\t\tif (typeof options.subdomains === 'string') {\r\n\t\t\toptions.subdomains = options.subdomains.split('');\r\n\t\t}\r\n\r\n\t\t// for https://github.com/Leaflet/Leaflet/issues/137\r\n\t\tif (!android) {\r\n\t\t\tthis.on('tileunload', this._onTileRemove);\r\n\t\t}\r\n\t},\r\n\r\n\t// @method setUrl(url: String, noRedraw?: Boolean): this\r\n\t// Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).\r\n\tsetUrl: function (url, noRedraw) {\r\n\t\tthis._url = url;\r\n\r\n\t\tif (!noRedraw) {\r\n\t\t\tthis.redraw();\r\n\t\t}\r\n\t\treturn this;\r\n\t},\r\n\r\n\t// @method createTile(coords: Object, done?: Function): HTMLElement\r\n\t// Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)\r\n\t// to return an ` ` HTML element with the appropriate image URL given `coords`. The `done`\r\n\t// callback is called when the tile has been loaded.\r\n\tcreateTile: function (coords, done) {\r\n\t\tvar tile = document.createElement('img');\r\n\r\n\t\ton(tile, 'load', bind(this._tileOnLoad, this, done, tile));\r\n\t\ton(tile, 'error', bind(this._tileOnError, this, done, tile));\r\n\r\n\t\tif (this.options.crossOrigin) {\r\n\t\t\ttile.crossOrigin = '';\r\n\t\t}\r\n\r\n\t\t/*\r\n\t\t Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons\r\n\t\t http://www.w3.org/TR/WCAG20-TECHS/H67\r\n\t\t*/\r\n\t\ttile.alt = '';\r\n\r\n\t\t/*\r\n\t\t Set role=\"presentation\" to force screen readers to ignore this\r\n\t\t https://www.w3.org/TR/wai-aria/roles#textalternativecomputation\r\n\t\t*/\r\n\t\ttile.setAttribute('role', 'presentation');\r\n\r\n\t\ttile.src = this.getTileUrl(coords);\r\n\r\n\t\treturn tile;\r\n\t},\r\n\r\n\t// @section Extension methods\r\n\t// @uninheritable\r\n\t// Layers extending `TileLayer` might reimplement the following method.\r\n\t// @method getTileUrl(coords: Object): String\r\n\t// Called only internally, returns the URL for a tile given its coordinates.\r\n\t// Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.\r\n\tgetTileUrl: function (coords) {\r\n\t\tvar data = {\r\n\t\t\tr: retina ? '@2x' : '',\r\n\t\t\ts: this._getSubdomain(coords),\r\n\t\t\tx: coords.x,\r\n\t\t\ty: coords.y,\r\n\t\t\tz: this._getZoomForUrl()\r\n\t\t};\r\n\t\tif (this._map && !this._map.options.crs.infinite) {\r\n\t\t\tvar invertedY = this._globalTileRange.max.y - coords.y;\r\n\t\t\tif (this.options.tms) {\r\n\t\t\t\tdata['y'] = invertedY;\r\n\t\t\t}\r\n\t\t\tdata['-y'] = invertedY;\r\n\t\t}\r\n\r\n\t\treturn template(this._url, extend(data, this.options));\r\n\t},\r\n\r\n\t_tileOnLoad: function (done, tile) {\r\n\t\t// For https://github.com/Leaflet/Leaflet/issues/3332\r\n\t\tif (ielt9) {\r\n\t\t\tsetTimeout(bind(done, this, null, tile), 0);\r\n\t\t} else {\r\n\t\t\tdone(null, tile);\r\n\t\t}\r\n\t},\r\n\r\n\t_tileOnError: function (done, tile, e) {\r\n\t\tvar errorUrl = this.options.errorTileUrl;\r\n\t\tif (errorUrl && tile.getAttribute('src') !== errorUrl) {\r\n\t\t\ttile.src = errorUrl;\r\n\t\t}\r\n\t\tdone(e, tile);\r\n\t},\r\n\r\n\t_onTileRemove: function (e) {\r\n\t\te.tile.onload = null;\r\n\t},\r\n\r\n\t_getZoomForUrl: function () {\r\n\t\tvar zoom = this._tileZoom,\r\n\t\tmaxZoom = this.options.maxZoom,\r\n\t\tzoomReverse = this.options.zoomReverse,\r\n\t\tzoomOffset = this.options.zoomOffset;\r\n\r\n\t\tif (zoomReverse) {\r\n\t\t\tzoom = maxZoom - zoom;\r\n\t\t}\r\n\r\n\t\treturn zoom + zoomOffset;\r\n\t},\r\n\r\n\t_getSubdomain: function (tilePoint) {\r\n\t\tvar index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;\r\n\t\treturn this.options.subdomains[index];\r\n\t},\r\n\r\n\t// stops loading all tiles in the background layer\r\n\t_abortLoading: function () {\r\n\t\tvar i, tile;\r\n\t\tfor (i in this._tiles) {\r\n\t\t\tif (this._tiles[i].coords.z !== this._tileZoom) {\r\n\t\t\t\ttile = this._tiles[i].el;\r\n\r\n\t\t\t\ttile.onload = falseFn;\r\n\t\t\t\ttile.onerror = falseFn;\r\n\r\n\t\t\t\tif (!tile.complete) {\r\n\t\t\t\t\ttile.src = emptyImageUrl;\r\n\t\t\t\t\tremove(tile);\r\n\t\t\t\t\tdelete this._tiles[i];\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)\r\n// Instantiates a tile layer object given a `URL template` and optionally an options object.\r\n\r\nfunction tileLayer(url, options) {\r\n\treturn new TileLayer(url, options);\r\n}\n\n/*\r\n * @class TileLayer.WMS\r\n * @inherits TileLayer\r\n * @aka L.TileLayer.WMS\r\n * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`.\r\n *\r\n * @example\r\n *\r\n * ```js\r\n * var nexrad = L.tileLayer.wms(\"http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi\", {\r\n * \tlayers: 'nexrad-n0r-900913',\r\n * \tformat: 'image/png',\r\n * \ttransparent: true,\r\n * \tattribution: \"Weather data © 2012 IEM Nexrad\"\r\n * });\r\n * ```\r\n */\r\n\r\nvar TileLayerWMS = TileLayer.extend({\r\n\r\n\t// @section\r\n\t// @aka TileLayer.WMS options\r\n\t// If any custom options not documented here are used, they will be sent to the\r\n\t// WMS server as extra parameters in each request URL. This can be useful for\r\n\t// [non-standard vendor WMS parameters](http://docs.geoserver.org/stable/en/user/services/wms/vendor.html).\r\n\tdefaultWmsParams: {\r\n\t\tservice: 'WMS',\r\n\t\trequest: 'GetMap',\r\n\r\n\t\t// @option layers: String = ''\r\n\t\t// **(required)** Comma-separated list of WMS layers to show.\r\n\t\tlayers: '',\r\n\r\n\t\t// @option styles: String = ''\r\n\t\t// Comma-separated list of WMS styles.\r\n\t\tstyles: '',\r\n\r\n\t\t// @option format: String = 'image/jpeg'\r\n\t\t// WMS image format (use `'image/png'` for layers with transparency).\r\n\t\tformat: 'image/jpeg',\r\n\r\n\t\t// @option transparent: Boolean = false\r\n\t\t// If `true`, the WMS service will return images with transparency.\r\n\t\ttransparent: false,\r\n\r\n\t\t// @option version: String = '1.1.1'\r\n\t\t// Version of the WMS service to use\r\n\t\tversion: '1.1.1'\r\n\t},\r\n\r\n\toptions: {\r\n\t\t// @option crs: CRS = null\r\n\t\t// Coordinate Reference System to use for the WMS requests, defaults to\r\n\t\t// map CRS. Don't change this if you're not sure what it means.\r\n\t\tcrs: null,\r\n\r\n\t\t// @option uppercase: Boolean = false\r\n\t\t// If `true`, WMS request parameter keys will be uppercase.\r\n\t\tuppercase: false\r\n\t},\r\n\r\n\tinitialize: function (url, options) {\r\n\r\n\t\tthis._url = url;\r\n\r\n\t\tvar wmsParams = extend({}, this.defaultWmsParams);\r\n\r\n\t\t// all keys that are not TileLayer options go to WMS params\r\n\t\tfor (var i in options) {\r\n\t\t\tif (!(i in this.options)) {\r\n\t\t\t\twmsParams[i] = options[i];\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\toptions = setOptions(this, options);\r\n\r\n\t\tvar realRetina = options.detectRetina && retina ? 2 : 1;\r\n\t\tvar tileSize = this.getTileSize();\r\n\t\twmsParams.width = tileSize.x * realRetina;\r\n\t\twmsParams.height = tileSize.y * realRetina;\r\n\r\n\t\tthis.wmsParams = wmsParams;\r\n\t},\r\n\r\n\tonAdd: function (map) {\r\n\r\n\t\tthis._crs = this.options.crs || map.options.crs;\r\n\t\tthis._wmsVersion = parseFloat(this.wmsParams.version);\r\n\r\n\t\tvar projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';\r\n\t\tthis.wmsParams[projectionKey] = this._crs.code;\r\n\r\n\t\tTileLayer.prototype.onAdd.call(this, map);\r\n\t},\r\n\r\n\tgetTileUrl: function (coords) {\r\n\r\n\t\tvar tileBounds = this._tileCoordsToNwSe(coords),\r\n\t\t crs = this._crs,\r\n\t\t bounds = toBounds(crs.project(tileBounds[0]), crs.project(tileBounds[1])),\r\n\t\t min = bounds.min,\r\n\t\t max = bounds.max,\r\n\t\t bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ?\r\n\t\t [min.y, min.x, max.y, max.x] :\r\n\t\t [min.x, min.y, max.x, max.y]).join(','),\r\n\t\turl = L.TileLayer.prototype.getTileUrl.call(this, coords);\r\n\t\treturn url +\r\n\t\t\tgetParamString(this.wmsParams, url, this.options.uppercase) +\r\n\t\t\t(this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;\r\n\t},\r\n\r\n\t// @method setParams(params: Object, noRedraw?: Boolean): this\r\n\t// Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).\r\n\tsetParams: function (params, noRedraw) {\r\n\r\n\t\textend(this.wmsParams, params);\r\n\r\n\t\tif (!noRedraw) {\r\n\t\t\tthis.redraw();\r\n\t\t}\r\n\r\n\t\treturn this;\r\n\t}\r\n});\r\n\r\n\r\n// @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options)\r\n// Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object.\r\nfunction tileLayerWMS(url, options) {\r\n\treturn new TileLayerWMS(url, options);\r\n}\n\nTileLayer.WMS = TileLayerWMS;\ntileLayer.wms = tileLayerWMS;\n\n/*\n * @class Renderer\n * @inherits Layer\n * @aka L.Renderer\n *\n * Base class for vector renderer implementations (`SVG`, `Canvas`). Handles the\n * DOM container of the renderer, its bounds, and its zoom animation.\n *\n * A `Renderer` works as an implicit layer group for all `Path`s - the renderer\n * itself can be added or removed to the map. All paths use a renderer, which can\n * be implicit (the map will decide the type of renderer and use it automatically)\n * or explicit (using the [`renderer`](#path-renderer) option of the path).\n *\n * Do not use this class directly, use `SVG` and `Canvas` instead.\n *\n * @event update: Event\n * Fired when the renderer updates its bounds, center and zoom, for example when\n * its map has moved\n */\n\nvar Renderer = Layer.extend({\n\n\t// @section\n\t// @aka Renderer options\n\toptions: {\n\t\t// @option padding: Number = 0.1\n\t\t// How much to extend the clip area around the map view (relative to its size)\n\t\t// e.g. 0.1 would be 10% of map view in each direction\n\t\tpadding: 0.1,\n\n\t\t// @option tolerance: Number = 0\n\t\t// How much to extend click tolerance round a path/object on the map\n\t\ttolerance : 0\n\t},\n\n\tinitialize: function (options) {\n\t\tsetOptions(this, options);\n\t\tstamp(this);\n\t\tthis._layers = this._layers || {};\n\t},\n\n\tonAdd: function () {\n\t\tif (!this._container) {\n\t\t\tthis._initContainer(); // defined by renderer implementations\n\n\t\t\tif (this._zoomAnimated) {\n\t\t\t\taddClass(this._container, 'leaflet-zoom-animated');\n\t\t\t}\n\t\t}\n\n\t\tthis.getPane().appendChild(this._container);\n\t\tthis._update();\n\t\tthis.on('update', this._updatePaths, this);\n\t},\n\n\tonRemove: function () {\n\t\tthis.off('update', this._updatePaths, this);\n\t\tthis._destroyContainer();\n\t},\n\n\tgetEvents: function () {\n\t\tvar events = {\n\t\t\tviewreset: this._reset,\n\t\t\tzoom: this._onZoom,\n\t\t\tmoveend: this._update,\n\t\t\tzoomend: this._onZoomEnd\n\t\t};\n\t\tif (this._zoomAnimated) {\n\t\t\tevents.zoomanim = this._onAnimZoom;\n\t\t}\n\t\treturn events;\n\t},\n\n\t_onAnimZoom: function (ev) {\n\t\tthis._updateTransform(ev.center, ev.zoom);\n\t},\n\n\t_onZoom: function () {\n\t\tthis._updateTransform(this._map.getCenter(), this._map.getZoom());\n\t},\n\n\t_updateTransform: function (center, zoom) {\n\t\tvar scale = this._map.getZoomScale(zoom, this._zoom),\n\t\t position = getPosition(this._container),\n\t\t viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),\n\t\t currentCenterPoint = this._map.project(this._center, zoom),\n\t\t destCenterPoint = this._map.project(center, zoom),\n\t\t centerOffset = destCenterPoint.subtract(currentCenterPoint),\n\n\t\t topLeftOffset = viewHalf.multiplyBy(-scale).add(position).add(viewHalf).subtract(centerOffset);\n\n\t\tif (any3d) {\n\t\t\tsetTransform(this._container, topLeftOffset, scale);\n\t\t} else {\n\t\t\tsetPosition(this._container, topLeftOffset);\n\t\t}\n\t},\n\n\t_reset: function () {\n\t\tthis._update();\n\t\tthis._updateTransform(this._center, this._zoom);\n\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._reset();\n\t\t}\n\t},\n\n\t_onZoomEnd: function () {\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._project();\n\t\t}\n\t},\n\n\t_updatePaths: function () {\n\t\tfor (var id in this._layers) {\n\t\t\tthis._layers[id]._update();\n\t\t}\n\t},\n\n\t_update: function () {\n\t\t// Update pixel bounds of renderer container (for positioning/sizing/clipping later)\n\t\t// Subclasses are responsible of firing the 'update' event.\n\t\tvar p = this.options.padding,\n\t\t size = this._map.getSize(),\n\t\t min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();\n\n\t\tthis._bounds = new Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());\n\n\t\tthis._center = this._map.getCenter();\n\t\tthis._zoom = this._map.getZoom();\n\t}\n});\n\n/*\n * @class Canvas\n * @inherits Renderer\n * @aka L.Canvas\n *\n * Allows vector layers to be displayed with [``](https://developer.mozilla.org/docs/Web/API/Canvas_API).\n * Inherits `Renderer`.\n *\n * Due to [technical limitations](http://caniuse.com/#search=canvas), Canvas is not\n * available in all web browsers, notably IE8, and overlapping geometries might\n * not display properly in some edge cases.\n *\n * @example\n *\n * Use Canvas by default for all paths in the map:\n *\n * ```js\n * var map = L.map('map', {\n * \trenderer: L.canvas()\n * });\n * ```\n *\n * Use a Canvas renderer with extra padding for specific vector geometries:\n *\n * ```js\n * var map = L.map('map');\n * var myRenderer = L.canvas({ padding: 0.5 });\n * var line = L.polyline( coordinates, { renderer: myRenderer } );\n * var circle = L.circle( center, { renderer: myRenderer } );\n * ```\n */\n\nvar Canvas = Renderer.extend({\n\tgetEvents: function () {\n\t\tvar events = Renderer.prototype.getEvents.call(this);\n\t\tevents.viewprereset = this._onViewPreReset;\n\t\treturn events;\n\t},\n\n\t_onViewPreReset: function () {\n\t\t// Set a flag so that a viewprereset+moveend+viewreset only updates&redraws once\n\t\tthis._postponeUpdatePaths = true;\n\t},\n\n\tonAdd: function () {\n\t\tRenderer.prototype.onAdd.call(this);\n\n\t\t// Redraw vectors since canvas is cleared upon removal,\n\t\t// in case of removing the renderer itself from the map.\n\t\tthis._draw();\n\t},\n\n\t_initContainer: function () {\n\t\tvar container = this._container = document.createElement('canvas');\n\n\t\ton(container, 'mousemove', throttle(this._onMouseMove, 32, this), this);\n\t\ton(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this);\n\t\ton(container, 'mouseout', this._handleMouseOut, this);\n\n\t\tthis._ctx = container.getContext('2d');\n\t},\n\n\t_destroyContainer: function () {\n\t\tdelete this._ctx;\n\t\tremove(this._container);\n\t\toff(this._container);\n\t\tdelete this._container;\n\t},\n\n\t_updatePaths: function () {\n\t\tif (this._postponeUpdatePaths) { return; }\n\n\t\tvar layer;\n\t\tthis._redrawBounds = null;\n\t\tfor (var id in this._layers) {\n\t\t\tlayer = this._layers[id];\n\t\t\tlayer._update();\n\t\t}\n\t\tthis._redraw();\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom && this._bounds) { return; }\n\n\t\tthis._drawnLayers = {};\n\n\t\tRenderer.prototype._update.call(this);\n\n\t\tvar b = this._bounds,\n\t\t container = this._container,\n\t\t size = b.getSize(),\n\t\t m = retina ? 2 : 1;\n\n\t\tsetPosition(container, b.min);\n\n\t\t// set canvas size (also clearing it); use double size on retina\n\t\tcontainer.width = m * size.x;\n\t\tcontainer.height = m * size.y;\n\t\tcontainer.style.width = size.x + 'px';\n\t\tcontainer.style.height = size.y + 'px';\n\n\t\tif (retina) {\n\t\t\tthis._ctx.scale(2, 2);\n\t\t}\n\n\t\t// translate so we use the same path coordinates after canvas element moves\n\t\tthis._ctx.translate(-b.min.x, -b.min.y);\n\n\t\t// Tell paths to redraw themselves\n\t\tthis.fire('update');\n\t},\n\n\t_reset: function () {\n\t\tRenderer.prototype._reset.call(this);\n\n\t\tif (this._postponeUpdatePaths) {\n\t\t\tthis._postponeUpdatePaths = false;\n\t\t\tthis._updatePaths();\n\t\t}\n\t},\n\n\t_initPath: function (layer) {\n\t\tthis._updateDashArray(layer);\n\t\tthis._layers[stamp(layer)] = layer;\n\n\t\tvar order = layer._order = {\n\t\t\tlayer: layer,\n\t\t\tprev: this._drawLast,\n\t\t\tnext: null\n\t\t};\n\t\tif (this._drawLast) { this._drawLast.next = order; }\n\t\tthis._drawLast = order;\n\t\tthis._drawFirst = this._drawFirst || this._drawLast;\n\t},\n\n\t_addPath: function (layer) {\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_removePath: function (layer) {\n\t\tvar order = layer._order;\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else {\n\t\t\tthis._drawLast = prev;\n\t\t}\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else {\n\t\t\tthis._drawFirst = next;\n\t\t}\n\n\t\tdelete layer._order;\n\n\t\tdelete this._layers[L.stamp(layer)];\n\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updatePath: function (layer) {\n\t\t// Redraw the union of the layer's old pixel\n\t\t// bounds and the new pixel bounds.\n\t\tthis._extendRedrawBounds(layer);\n\t\tlayer._project();\n\t\tlayer._update();\n\t\t// The redraw will extend the redraw bounds\n\t\t// with the new pixel bounds.\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tthis._updateDashArray(layer);\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_updateDashArray: function (layer) {\n\t\tif (layer.options.dashArray) {\n\t\t\tvar parts = layer.options.dashArray.split(','),\n\t\t\t dashArray = [],\n\t\t\t i;\n\t\t\tfor (i = 0; i < parts.length; i++) {\n\t\t\t\tdashArray.push(Number(parts[i]));\n\t\t\t}\n\t\t\tlayer.options._dashArray = dashArray;\n\t\t}\n\t},\n\n\t_requestRedraw: function (layer) {\n\t\tif (!this._map) { return; }\n\n\t\tthis._extendRedrawBounds(layer);\n\t\tthis._redrawRequest = this._redrawRequest || requestAnimFrame(this._redraw, this);\n\t},\n\n\t_extendRedrawBounds: function (layer) {\n\t\tif (layer._pxBounds) {\n\t\t\tvar padding = (layer.options.weight || 0) + 1;\n\t\t\tthis._redrawBounds = this._redrawBounds || new Bounds();\n\t\t\tthis._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));\n\t\t\tthis._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));\n\t\t}\n\t},\n\n\t_redraw: function () {\n\t\tthis._redrawRequest = null;\n\n\t\tif (this._redrawBounds) {\n\t\t\tthis._redrawBounds.min._floor();\n\t\t\tthis._redrawBounds.max._ceil();\n\t\t}\n\n\t\tthis._clear(); // clear layers in redraw bounds\n\t\tthis._draw(); // draw layers\n\n\t\tthis._redrawBounds = null;\n\t},\n\n\t_clear: function () {\n\t\tvar bounds = this._redrawBounds;\n\t\tif (bounds) {\n\t\t\tvar size = bounds.getSize();\n\t\t\tthis._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);\n\t\t} else {\n\t\t\tthis._ctx.clearRect(0, 0, this._container.width, this._container.height);\n\t\t}\n\t},\n\n\t_draw: function () {\n\t\tvar layer, bounds = this._redrawBounds;\n\t\tthis._ctx.save();\n\t\tif (bounds) {\n\t\t\tvar size = bounds.getSize();\n\t\t\tthis._ctx.beginPath();\n\t\t\tthis._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);\n\t\t\tthis._ctx.clip();\n\t\t}\n\n\t\tthis._drawing = true;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) {\n\t\t\t\tlayer._updatePath();\n\t\t\t}\n\t\t}\n\n\t\tthis._drawing = false;\n\n\t\tthis._ctx.restore(); // Restore state before clipping.\n\t},\n\n\t_updatePoly: function (layer, closed) {\n\t\tif (!this._drawing) { return; }\n\n\t\tvar i, j, len2, p,\n\t\t parts = layer._parts,\n\t\t len = parts.length,\n\t\t ctx = this._ctx;\n\n\t\tif (!len) { return; }\n\n\t\tthis._drawnLayers[layer._leaflet_id] = layer;\n\n\t\tctx.beginPath();\n\n\t\tfor (i = 0; i < len; i++) {\n\t\t\tfor (j = 0, len2 = parts[i].length; j < len2; j++) {\n\t\t\t\tp = parts[i][j];\n\t\t\t\tctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);\n\t\t\t}\n\t\t\tif (closed) {\n\t\t\t\tctx.closePath();\n\t\t\t}\n\t\t}\n\n\t\tthis._fillStroke(ctx, layer);\n\n\t\t// TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature\n\t},\n\n\t_updateCircle: function (layer) {\n\n\t\tif (!this._drawing || layer._empty()) { return; }\n\n\t\tvar p = layer._point,\n\t\t ctx = this._ctx,\n\t\t r = Math.max(Math.round(layer._radius), 1),\n\t\t s = (Math.max(Math.round(layer._radiusY), 1) || r) / r;\n\n\t\tthis._drawnLayers[layer._leaflet_id] = layer;\n\n\t\tif (s !== 1) {\n\t\t\tctx.save();\n\t\t\tctx.scale(1, s);\n\t\t}\n\n\t\tctx.beginPath();\n\t\tctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);\n\n\t\tif (s !== 1) {\n\t\t\tctx.restore();\n\t\t}\n\n\t\tthis._fillStroke(ctx, layer);\n\t},\n\n\t_fillStroke: function (ctx, layer) {\n\t\tvar options = layer.options;\n\n\t\tif (options.fill) {\n\t\t\tctx.globalAlpha = options.fillOpacity;\n\t\t\tctx.fillStyle = options.fillColor || options.color;\n\t\t\tctx.fill(options.fillRule || 'evenodd');\n\t\t}\n\n\t\tif (options.stroke && options.weight !== 0) {\n\t\t\tif (ctx.setLineDash) {\n\t\t\t\tctx.setLineDash(layer.options && layer.options._dashArray || []);\n\t\t\t}\n\t\t\tctx.globalAlpha = options.opacity;\n\t\t\tctx.lineWidth = options.weight;\n\t\t\tctx.strokeStyle = options.color;\n\t\t\tctx.lineCap = options.lineCap;\n\t\t\tctx.lineJoin = options.lineJoin;\n\t\t\tctx.stroke();\n\t\t}\n\t},\n\n\t// Canvas obviously doesn't have mouse events for individual drawn objects,\n\t// so we emulate that by calculating what's under the mouse on mousemove/click manually\n\n\t_onClick: function (e) {\n\t\tvar point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (layer.options.interactive && layer._containsPoint(point) && !this._map._draggableMoved(layer)) {\n\t\t\t\tclickedLayer = layer;\n\t\t\t}\n\t\t}\n\t\tif (clickedLayer) {\n\t\t\tfakeStop(e);\n\t\t\tthis._fireEvent([clickedLayer], e);\n\t\t}\n\t},\n\n\t_onMouseMove: function (e) {\n\t\tif (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }\n\n\t\tvar point = this._map.mouseEventToLayerPoint(e);\n\t\tthis._handleMouseHover(e, point);\n\t},\n\n\n\t_handleMouseOut: function (e) {\n\t\tvar layer = this._hoveredLayer;\n\t\tif (layer) {\n\t\t\t// if we're leaving the layer, fire mouseout\n\t\t\tremoveClass(this._container, 'leaflet-interactive');\n\t\t\tthis._fireEvent([layer], e, 'mouseout');\n\t\t\tthis._hoveredLayer = null;\n\t\t}\n\t},\n\n\t_handleMouseHover: function (e, point) {\n\t\tvar layer, candidateHoveredLayer;\n\n\t\tfor (var order = this._drawFirst; order; order = order.next) {\n\t\t\tlayer = order.layer;\n\t\t\tif (layer.options.interactive && layer._containsPoint(point)) {\n\t\t\t\tcandidateHoveredLayer = layer;\n\t\t\t}\n\t\t}\n\n\t\tif (candidateHoveredLayer !== this._hoveredLayer) {\n\t\t\tthis._handleMouseOut(e);\n\n\t\t\tif (candidateHoveredLayer) {\n\t\t\t\taddClass(this._container, 'leaflet-interactive'); // change cursor\n\t\t\t\tthis._fireEvent([candidateHoveredLayer], e, 'mouseover');\n\t\t\t\tthis._hoveredLayer = candidateHoveredLayer;\n\t\t\t}\n\t\t}\n\n\t\tif (this._hoveredLayer) {\n\t\t\tthis._fireEvent([this._hoveredLayer], e);\n\t\t}\n\t},\n\n\t_fireEvent: function (layers, e, type) {\n\t\tthis._map._fireDOMEvent(e, type || e.type, layers);\n\t},\n\n\t_bringToFront: function (layer) {\n\t\tvar order = layer._order;\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else {\n\t\t\t// Already last\n\t\t\treturn;\n\t\t}\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else if (next) {\n\t\t\t// Update first entry unless this is the\n\t\t\t// single entry\n\t\t\tthis._drawFirst = next;\n\t\t}\n\n\t\torder.prev = this._drawLast;\n\t\tthis._drawLast.next = order;\n\n\t\torder.next = null;\n\t\tthis._drawLast = order;\n\n\t\tthis._requestRedraw(layer);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\tvar order = layer._order;\n\t\tvar next = order.next;\n\t\tvar prev = order.prev;\n\n\t\tif (prev) {\n\t\t\tprev.next = next;\n\t\t} else {\n\t\t\t// Already first\n\t\t\treturn;\n\t\t}\n\t\tif (next) {\n\t\t\tnext.prev = prev;\n\t\t} else if (prev) {\n\t\t\t// Update last entry unless this is the\n\t\t\t// single entry\n\t\t\tthis._drawLast = prev;\n\t\t}\n\n\t\torder.prev = null;\n\n\t\torder.next = this._drawFirst;\n\t\tthis._drawFirst.prev = order;\n\t\tthis._drawFirst = order;\n\n\t\tthis._requestRedraw(layer);\n\t}\n});\n\n// @factory L.canvas(options?: Renderer options)\n// Creates a Canvas renderer with the given options.\nfunction canvas$1(options) {\n\treturn canvas ? new Canvas(options) : null;\n}\n\n/*\n * Thanks to Dmitry Baranovsky and his Raphael library for inspiration!\n */\n\n\nvar vmlCreate = (function () {\n\ttry {\n\t\tdocument.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');\n\t\treturn function (name) {\n\t\t\treturn document.createElement('');\n\t\t};\n\t} catch (e) {\n\t\treturn function (name) {\n\t\t\treturn document.createElement('<' + name + ' xmlns=\"urn:schemas-microsoft.com:vml\" class=\"lvml\">');\n\t\t};\n\t}\n})();\n\n\n/*\n * @class SVG\n *\n * Although SVG is not available on IE7 and IE8, these browsers support [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language), and the SVG renderer will fall back to VML in this case.\n *\n * VML was deprecated in 2012, which means VML functionality exists only for backwards compatibility\n * with old versions of Internet Explorer.\n */\n\n// mixin to redefine some SVG methods to handle VML syntax which is similar but with some differences\nvar vmlMixin = {\n\n\t_initContainer: function () {\n\t\tthis._container = create$1('div', 'leaflet-vml-container');\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom) { return; }\n\t\tRenderer.prototype._update.call(this);\n\t\tthis.fire('update');\n\t},\n\n\t_initPath: function (layer) {\n\t\tvar container = layer._container = vmlCreate('shape');\n\n\t\taddClass(container, 'leaflet-vml-shape ' + (this.options.className || ''));\n\n\t\tcontainer.coordsize = '1 1';\n\n\t\tlayer._path = vmlCreate('path');\n\t\tcontainer.appendChild(layer._path);\n\n\t\tthis._updateStyle(layer);\n\t\tthis._layers[stamp(layer)] = layer;\n\t},\n\n\t_addPath: function (layer) {\n\t\tvar container = layer._container;\n\t\tthis._container.appendChild(container);\n\n\t\tif (layer.options.interactive) {\n\t\t\tlayer.addInteractiveTarget(container);\n\t\t}\n\t},\n\n\t_removePath: function (layer) {\n\t\tvar container = layer._container;\n\t\tremove(container);\n\t\tlayer.removeInteractiveTarget(container);\n\t\tdelete this._layers[stamp(layer)];\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tvar stroke = layer._stroke,\n\t\t fill = layer._fill,\n\t\t options = layer.options,\n\t\t container = layer._container;\n\n\t\tcontainer.stroked = !!options.stroke;\n\t\tcontainer.filled = !!options.fill;\n\n\t\tif (options.stroke) {\n\t\t\tif (!stroke) {\n\t\t\t\tstroke = layer._stroke = vmlCreate('stroke');\n\t\t\t}\n\t\t\tcontainer.appendChild(stroke);\n\t\t\tstroke.weight = options.weight + 'px';\n\t\t\tstroke.color = options.color;\n\t\t\tstroke.opacity = options.opacity;\n\n\t\t\tif (options.dashArray) {\n\t\t\t\tstroke.dashStyle = isArray(options.dashArray) ?\n\t\t\t\t options.dashArray.join(' ') :\n\t\t\t\t options.dashArray.replace(/( *, *)/g, ' ');\n\t\t\t} else {\n\t\t\t\tstroke.dashStyle = '';\n\t\t\t}\n\t\t\tstroke.endcap = options.lineCap.replace('butt', 'flat');\n\t\t\tstroke.joinstyle = options.lineJoin;\n\n\t\t} else if (stroke) {\n\t\t\tcontainer.removeChild(stroke);\n\t\t\tlayer._stroke = null;\n\t\t}\n\n\t\tif (options.fill) {\n\t\t\tif (!fill) {\n\t\t\t\tfill = layer._fill = vmlCreate('fill');\n\t\t\t}\n\t\t\tcontainer.appendChild(fill);\n\t\t\tfill.color = options.fillColor || options.color;\n\t\t\tfill.opacity = options.fillOpacity;\n\n\t\t} else if (fill) {\n\t\t\tcontainer.removeChild(fill);\n\t\t\tlayer._fill = null;\n\t\t}\n\t},\n\n\t_updateCircle: function (layer) {\n\t\tvar p = layer._point.round(),\n\t\t r = Math.round(layer._radius),\n\t\t r2 = Math.round(layer._radiusY || r);\n\n\t\tthis._setPath(layer, layer._empty() ? 'M0 0' :\n\t\t\t'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));\n\t},\n\n\t_setPath: function (layer, path) {\n\t\tlayer._path.v = path;\n\t},\n\n\t_bringToFront: function (layer) {\n\t\ttoFront(layer._container);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\ttoBack(layer._container);\n\t}\n};\n\nvar create$2 = vml ? vmlCreate : svgCreate;\n\n/*\n * @class SVG\n * @inherits Renderer\n * @aka L.SVG\n *\n * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG).\n * Inherits `Renderer`.\n *\n * Due to [technical limitations](http://caniuse.com/#search=svg), SVG is not\n * available in all web browsers, notably Android 2.x and 3.x.\n *\n * Although SVG is not available on IE7 and IE8, these browsers support\n * [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language)\n * (a now deprecated technology), and the SVG renderer will fall back to VML in\n * this case.\n *\n * @example\n *\n * Use SVG by default for all paths in the map:\n *\n * ```js\n * var map = L.map('map', {\n * \trenderer: L.svg()\n * });\n * ```\n *\n * Use a SVG renderer with extra padding for specific vector geometries:\n *\n * ```js\n * var map = L.map('map');\n * var myRenderer = L.svg({ padding: 0.5 });\n * var line = L.polyline( coordinates, { renderer: myRenderer } );\n * var circle = L.circle( center, { renderer: myRenderer } );\n * ```\n */\n\nvar SVG = Renderer.extend({\n\n\tgetEvents: function () {\n\t\tvar events = Renderer.prototype.getEvents.call(this);\n\t\tevents.zoomstart = this._onZoomStart;\n\t\treturn events;\n\t},\n\n\t_initContainer: function () {\n\t\tthis._container = create$2('svg');\n\n\t\t// makes it possible to click through svg root; we'll reset it back in individual paths\n\t\tthis._container.setAttribute('pointer-events', 'none');\n\n\t\tthis._rootGroup = create$2('g');\n\t\tthis._container.appendChild(this._rootGroup);\n\t},\n\n\t_destroyContainer: function () {\n\t\tremove(this._container);\n\t\toff(this._container);\n\t\tdelete this._container;\n\t\tdelete this._rootGroup;\n\t\tdelete this._svgSize;\n\t},\n\n\t_onZoomStart: function () {\n\t\t// Drag-then-pinch interactions might mess up the center and zoom.\n\t\t// In this case, the easiest way to prevent this is re-do the renderer\n\t\t// bounds and padding when the zooming starts.\n\t\tthis._update();\n\t},\n\n\t_update: function () {\n\t\tif (this._map._animatingZoom && this._bounds) { return; }\n\n\t\tRenderer.prototype._update.call(this);\n\n\t\tvar b = this._bounds,\n\t\t size = b.getSize(),\n\t\t container = this._container;\n\n\t\t// set size of svg-container if changed\n\t\tif (!this._svgSize || !this._svgSize.equals(size)) {\n\t\t\tthis._svgSize = size;\n\t\t\tcontainer.setAttribute('width', size.x);\n\t\t\tcontainer.setAttribute('height', size.y);\n\t\t}\n\n\t\t// movement: update container viewBox so that we don't have to change coordinates of individual layers\n\t\tsetPosition(container, b.min);\n\t\tcontainer.setAttribute('viewBox', [b.min.x, b.min.y, size.x, size.y].join(' '));\n\n\t\tthis.fire('update');\n\t},\n\n\t// methods below are called by vector layers implementations\n\n\t_initPath: function (layer) {\n\t\tvar path = layer._path = create$2('path');\n\n\t\t// @namespace Path\n\t\t// @option className: String = null\n\t\t// Custom class name set on an element. Only for SVG renderer.\n\t\tif (layer.options.className) {\n\t\t\taddClass(path, layer.options.className);\n\t\t}\n\n\t\tif (layer.options.interactive) {\n\t\t\taddClass(path, 'leaflet-interactive');\n\t\t}\n\n\t\tthis._updateStyle(layer);\n\t\tthis._layers[stamp(layer)] = layer;\n\t},\n\n\t_addPath: function (layer) {\n\t\tif (!this._rootGroup) { this._initContainer(); }\n\t\tthis._rootGroup.appendChild(layer._path);\n\t\tlayer.addInteractiveTarget(layer._path);\n\t},\n\n\t_removePath: function (layer) {\n\t\tremove(layer._path);\n\t\tlayer.removeInteractiveTarget(layer._path);\n\t\tdelete this._layers[stamp(layer)];\n\t},\n\n\t_updatePath: function (layer) {\n\t\tlayer._project();\n\t\tlayer._update();\n\t},\n\n\t_updateStyle: function (layer) {\n\t\tvar path = layer._path,\n\t\t options = layer.options;\n\n\t\tif (!path) { return; }\n\n\t\tif (options.stroke) {\n\t\t\tpath.setAttribute('stroke', options.color);\n\t\t\tpath.setAttribute('stroke-opacity', options.opacity);\n\t\t\tpath.setAttribute('stroke-width', options.weight);\n\t\t\tpath.setAttribute('stroke-linecap', options.lineCap);\n\t\t\tpath.setAttribute('stroke-linejoin', options.lineJoin);\n\n\t\t\tif (options.dashArray) {\n\t\t\t\tpath.setAttribute('stroke-dasharray', options.dashArray);\n\t\t\t} else {\n\t\t\t\tpath.removeAttribute('stroke-dasharray');\n\t\t\t}\n\n\t\t\tif (options.dashOffset) {\n\t\t\t\tpath.setAttribute('stroke-dashoffset', options.dashOffset);\n\t\t\t} else {\n\t\t\t\tpath.removeAttribute('stroke-dashoffset');\n\t\t\t}\n\t\t} else {\n\t\t\tpath.setAttribute('stroke', 'none');\n\t\t}\n\n\t\tif (options.fill) {\n\t\t\tpath.setAttribute('fill', options.fillColor || options.color);\n\t\t\tpath.setAttribute('fill-opacity', options.fillOpacity);\n\t\t\tpath.setAttribute('fill-rule', options.fillRule || 'evenodd');\n\t\t} else {\n\t\t\tpath.setAttribute('fill', 'none');\n\t\t}\n\t},\n\n\t_updatePoly: function (layer, closed) {\n\t\tthis._setPath(layer, pointsToPath(layer._parts, closed));\n\t},\n\n\t_updateCircle: function (layer) {\n\t\tvar p = layer._point,\n\t\t r = Math.max(Math.round(layer._radius), 1),\n\t\t r2 = Math.max(Math.round(layer._radiusY), 1) || r,\n\t\t arc = 'a' + r + ',' + r2 + ' 0 1,0 ';\n\n\t\t// drawing a circle with two half-arcs\n\t\tvar d = layer._empty() ? 'M0 0' :\n\t\t\t'M' + (p.x - r) + ',' + p.y +\n\t\t\tarc + (r * 2) + ',0 ' +\n\t\t\tarc + (-r * 2) + ',0 ';\n\n\t\tthis._setPath(layer, d);\n\t},\n\n\t_setPath: function (layer, path) {\n\t\tlayer._path.setAttribute('d', path);\n\t},\n\n\t// SVG does not have the concept of zIndex so we resort to changing the DOM order of elements\n\t_bringToFront: function (layer) {\n\t\ttoFront(layer._path);\n\t},\n\n\t_bringToBack: function (layer) {\n\t\ttoBack(layer._path);\n\t}\n});\n\nif (vml) {\n\tSVG.include(vmlMixin);\n}\n\n// @namespace SVG\n// @factory L.svg(options?: Renderer options)\n// Creates a SVG renderer with the given options.\nfunction svg$1(options) {\n\treturn svg || vml ? new SVG(options) : null;\n}\n\nMap.include({\n\t// @namespace Map; @method getRenderer(layer: Path): Renderer\n\t// Returns the instance of `Renderer` that should be used to render the given\n\t// `Path`. It will ensure that the `renderer` options of the map and paths\n\t// are respected, and that the renderers do exist on the map.\n\tgetRenderer: function (layer) {\n\t\t// @namespace Path; @option renderer: Renderer\n\t\t// Use this specific instance of `Renderer` for this path. Takes\n\t\t// precedence over the map's [default renderer](#map-renderer).\n\t\tvar renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;\n\n\t\tif (!renderer) {\n\t\t\t// @namespace Map; @option preferCanvas: Boolean = false\n\t\t\t// Whether `Path`s should be rendered on a `Canvas` renderer.\n\t\t\t// By default, all `Path`s are rendered in a `SVG` renderer.\n\t\t\trenderer = this._renderer = (this.options.preferCanvas && canvas$1()) || svg$1();\n\t\t}\n\n\t\tif (!this.hasLayer(renderer)) {\n\t\t\tthis.addLayer(renderer);\n\t\t}\n\t\treturn renderer;\n\t},\n\n\t_getPaneRenderer: function (name) {\n\t\tif (name === 'overlayPane' || name === undefined) {\n\t\t\treturn false;\n\t\t}\n\n\t\tvar renderer = this._paneRenderers[name];\n\t\tif (renderer === undefined) {\n\t\t\trenderer = (SVG && svg$1({pane: name})) || (Canvas && canvas$1({pane: name}));\n\t\t\tthis._paneRenderers[name] = renderer;\n\t\t}\n\t\treturn renderer;\n\t}\n});\n\n/*\n * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.\n */\n\n/*\n * @class Rectangle\n * @aka L.Rectangle\n * @inherits Polygon\n *\n * A class for drawing rectangle overlays on a map. Extends `Polygon`.\n *\n * @example\n *\n * ```js\n * // define rectangle geographical bounds\n * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];\n *\n * // create an orange rectangle\n * L.rectangle(bounds, {color: \"#ff7800\", weight: 1}).addTo(map);\n *\n * // zoom the map to the rectangle bounds\n * map.fitBounds(bounds);\n * ```\n *\n */\n\n\nvar Rectangle = Polygon.extend({\n\tinitialize: function (latLngBounds, options) {\n\t\tPolygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);\n\t},\n\n\t// @method setBounds(latLngBounds: LatLngBounds): this\n\t// Redraws the rectangle with the passed bounds.\n\tsetBounds: function (latLngBounds) {\n\t\treturn this.setLatLngs(this._boundsToLatLngs(latLngBounds));\n\t},\n\n\t_boundsToLatLngs: function (latLngBounds) {\n\t\tlatLngBounds = toLatLngBounds(latLngBounds);\n\t\treturn [\n\t\t\tlatLngBounds.getSouthWest(),\n\t\t\tlatLngBounds.getNorthWest(),\n\t\t\tlatLngBounds.getNorthEast(),\n\t\t\tlatLngBounds.getSouthEast()\n\t\t];\n\t}\n});\n\n\n// @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options)\nfunction rectangle(latLngBounds, options) {\n\treturn new Rectangle(latLngBounds, options);\n}\n\nSVG.create = create$2;\nSVG.pointsToPath = pointsToPath;\n\nGeoJSON.geometryToLayer = geometryToLayer;\nGeoJSON.coordsToLatLng = coordsToLatLng;\nGeoJSON.coordsToLatLngs = coordsToLatLngs;\nGeoJSON.latLngToCoords = latLngToCoords;\nGeoJSON.latLngsToCoords = latLngsToCoords;\nGeoJSON.getFeature = getFeature;\nGeoJSON.asFeature = asFeature;\n\n/*\n * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map\n * (zoom to a selected bounding box), enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @option boxZoom: Boolean = true\n\t// Whether the map can be zoomed to a rectangular area specified by\n\t// dragging the mouse while pressing the shift key.\n\tboxZoom: true\n});\n\nvar BoxZoom = Handler.extend({\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\t\tthis._container = map._container;\n\t\tthis._pane = map._panes.overlayPane;\n\t\tthis._resetStateTimeout = 0;\n\t\tmap.on('unload', this._destroy, this);\n\t},\n\n\taddHooks: function () {\n\t\ton(this._container, 'mousedown', this._onMouseDown, this);\n\t},\n\n\tremoveHooks: function () {\n\t\toff(this._container, 'mousedown', this._onMouseDown, this);\n\t},\n\n\tmoved: function () {\n\t\treturn this._moved;\n\t},\n\n\t_destroy: function () {\n\t\tremove(this._pane);\n\t\tdelete this._pane;\n\t},\n\n\t_resetState: function () {\n\t\tthis._resetStateTimeout = 0;\n\t\tthis._moved = false;\n\t},\n\n\t_clearDeferredResetState: function () {\n\t\tif (this._resetStateTimeout !== 0) {\n\t\t\tclearTimeout(this._resetStateTimeout);\n\t\t\tthis._resetStateTimeout = 0;\n\t\t}\n\t},\n\n\t_onMouseDown: function (e) {\n\t\tif (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }\n\n\t\t// Clear the deferred resetState if it hasn't executed yet, otherwise it\n\t\t// will interrupt the interaction and orphan a box element in the container.\n\t\tthis._clearDeferredResetState();\n\t\tthis._resetState();\n\n\t\tdisableTextSelection();\n\t\tdisableImageDrag();\n\n\t\tthis._startPoint = this._map.mouseEventToContainerPoint(e);\n\n\t\ton(document, {\n\t\t\tcontextmenu: stop,\n\t\t\tmousemove: this._onMouseMove,\n\t\t\tmouseup: this._onMouseUp,\n\t\t\tkeydown: this._onKeyDown\n\t\t}, this);\n\t},\n\n\t_onMouseMove: function (e) {\n\t\tif (!this._moved) {\n\t\t\tthis._moved = true;\n\n\t\t\tthis._box = create$1('div', 'leaflet-zoom-box', this._container);\n\t\t\taddClass(this._container, 'leaflet-crosshair');\n\n\t\t\tthis._map.fire('boxzoomstart');\n\t\t}\n\n\t\tthis._point = this._map.mouseEventToContainerPoint(e);\n\n\t\tvar bounds = new Bounds(this._point, this._startPoint),\n\t\t size = bounds.getSize();\n\n\t\tsetPosition(this._box, bounds.min);\n\n\t\tthis._box.style.width = size.x + 'px';\n\t\tthis._box.style.height = size.y + 'px';\n\t},\n\n\t_finish: function () {\n\t\tif (this._moved) {\n\t\t\tremove(this._box);\n\t\t\tremoveClass(this._container, 'leaflet-crosshair');\n\t\t}\n\n\t\tenableTextSelection();\n\t\tenableImageDrag();\n\n\t\toff(document, {\n\t\t\tcontextmenu: stop,\n\t\t\tmousemove: this._onMouseMove,\n\t\t\tmouseup: this._onMouseUp,\n\t\t\tkeydown: this._onKeyDown\n\t\t}, this);\n\t},\n\n\t_onMouseUp: function (e) {\n\t\tif ((e.which !== 1) && (e.button !== 1)) { return; }\n\n\t\tthis._finish();\n\n\t\tif (!this._moved) { return; }\n\t\t// Postpone to next JS tick so internal click event handling\n\t\t// still see it as \"moved\".\n\t\tthis._clearDeferredResetState();\n\t\tthis._resetStateTimeout = setTimeout(bind(this._resetState, this), 0);\n\n\t\tvar bounds = new LatLngBounds(\n\t\t this._map.containerPointToLatLng(this._startPoint),\n\t\t this._map.containerPointToLatLng(this._point));\n\n\t\tthis._map\n\t\t\t.fitBounds(bounds)\n\t\t\t.fire('boxzoomend', {boxZoomBounds: bounds});\n\t},\n\n\t_onKeyDown: function (e) {\n\t\tif (e.keyCode === 27) {\n\t\t\tthis._finish();\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property boxZoom: Handler\n// Box (shift-drag with mouse) zoom handler.\nMap.addInitHook('addHandler', 'boxZoom', BoxZoom);\n\n/*\n * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\n\nMap.mergeOptions({\n\t// @option doubleClickZoom: Boolean|String = true\n\t// Whether the map can be zoomed in by double clicking on it and\n\t// zoomed out by double clicking while holding shift. If passed\n\t// `'center'`, double-click zoom will zoom to the center of the\n\t// view regardless of where the mouse was.\n\tdoubleClickZoom: true\n});\n\nvar DoubleClickZoom = Handler.extend({\n\taddHooks: function () {\n\t\tthis._map.on('dblclick', this._onDoubleClick, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._map.off('dblclick', this._onDoubleClick, this);\n\t},\n\n\t_onDoubleClick: function (e) {\n\t\tvar map = this._map,\n\t\t oldZoom = map.getZoom(),\n\t\t delta = map.options.zoomDelta,\n\t\t zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;\n\n\t\tif (map.options.doubleClickZoom === 'center') {\n\t\t\tmap.setZoom(zoom);\n\t\t} else {\n\t\t\tmap.setZoomAround(e.containerPoint, zoom);\n\t\t}\n\t}\n});\n\n// @section Handlers\n//\n// Map properties include interaction handlers that allow you to control\n// interaction behavior in runtime, enabling or disabling certain features such\n// as dragging or touch zoom (see `Handler` methods). For example:\n//\n// ```js\n// map.doubleClickZoom.disable();\n// ```\n//\n// @property doubleClickZoom: Handler\n// Double click zoom handler.\nMap.addInitHook('addHandler', 'doubleClickZoom', DoubleClickZoom);\n\n/*\n * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @option dragging: Boolean = true\n\t// Whether the map be draggable with mouse/touch or not.\n\tdragging: true,\n\n\t// @section Panning Inertia Options\n\t// @option inertia: Boolean = *\n\t// If enabled, panning of the map will have an inertia effect where\n\t// the map builds momentum while dragging and continues moving in\n\t// the same direction for some time. Feels especially nice on touch\n\t// devices. Enabled by default unless running on old Android devices.\n\tinertia: !android23,\n\n\t// @option inertiaDeceleration: Number = 3000\n\t// The rate with which the inertial movement slows down, in pixels/second².\n\tinertiaDeceleration: 3400, // px/s^2\n\n\t// @option inertiaMaxSpeed: Number = Infinity\n\t// Max speed of the inertial movement, in pixels/second.\n\tinertiaMaxSpeed: Infinity, // px/s\n\n\t// @option easeLinearity: Number = 0.2\n\teaseLinearity: 0.2,\n\n\t// TODO refactor, move to CRS\n\t// @option worldCopyJump: Boolean = false\n\t// With this option enabled, the map tracks when you pan to another \"copy\"\n\t// of the world and seamlessly jumps to the original one so that all overlays\n\t// like markers and vector layers are still visible.\n\tworldCopyJump: false,\n\n\t// @option maxBoundsViscosity: Number = 0.0\n\t// If `maxBounds` is set, this option will control how solid the bounds\n\t// are when dragging the map around. The default value of `0.0` allows the\n\t// user to drag outside the bounds at normal speed, higher values will\n\t// slow down map dragging outside bounds, and `1.0` makes the bounds fully\n\t// solid, preventing the user from dragging outside the bounds.\n\tmaxBoundsViscosity: 0.0\n});\n\nvar Drag = Handler.extend({\n\taddHooks: function () {\n\t\tif (!this._draggable) {\n\t\t\tvar map = this._map;\n\n\t\t\tthis._draggable = new Draggable(map._mapPane, map._container);\n\n\t\t\tthis._draggable.on({\n\t\t\t\tdragstart: this._onDragStart,\n\t\t\t\tdrag: this._onDrag,\n\t\t\t\tdragend: this._onDragEnd\n\t\t\t}, this);\n\n\t\t\tthis._draggable.on('predrag', this._onPreDragLimit, this);\n\t\t\tif (map.options.worldCopyJump) {\n\t\t\t\tthis._draggable.on('predrag', this._onPreDragWrap, this);\n\t\t\t\tmap.on('zoomend', this._onZoomEnd, this);\n\n\t\t\t\tmap.whenReady(this._onZoomEnd, this);\n\t\t\t}\n\t\t}\n\t\taddClass(this._map._container, 'leaflet-grab leaflet-touch-drag');\n\t\tthis._draggable.enable();\n\t\tthis._positions = [];\n\t\tthis._times = [];\n\t},\n\n\tremoveHooks: function () {\n\t\tremoveClass(this._map._container, 'leaflet-grab');\n\t\tremoveClass(this._map._container, 'leaflet-touch-drag');\n\t\tthis._draggable.disable();\n\t},\n\n\tmoved: function () {\n\t\treturn this._draggable && this._draggable._moved;\n\t},\n\n\tmoving: function () {\n\t\treturn this._draggable && this._draggable._moving;\n\t},\n\n\t_onDragStart: function () {\n\t\tvar map = this._map;\n\n\t\tmap._stop();\n\t\tif (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {\n\t\t\tvar bounds = toLatLngBounds(this._map.options.maxBounds);\n\n\t\t\tthis._offsetLimit = toBounds(\n\t\t\t\tthis._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),\n\t\t\t\tthis._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1)\n\t\t\t\t\t.add(this._map.getSize()));\n\n\t\t\tthis._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity));\n\t\t} else {\n\t\t\tthis._offsetLimit = null;\n\t\t}\n\n\t\tmap\n\t\t .fire('movestart')\n\t\t .fire('dragstart');\n\n\t\tif (map.options.inertia) {\n\t\t\tthis._positions = [];\n\t\t\tthis._times = [];\n\t\t}\n\t},\n\n\t_onDrag: function (e) {\n\t\tif (this._map.options.inertia) {\n\t\t\tvar time = this._lastTime = +new Date(),\n\t\t\t pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;\n\n\t\t\tthis._positions.push(pos);\n\t\t\tthis._times.push(time);\n\n\t\t\tthis._prunePositions(time);\n\t\t}\n\n\t\tthis._map\n\t\t .fire('move', e)\n\t\t .fire('drag', e);\n\t},\n\n\t_prunePositions: function (time) {\n\t\twhile (this._positions.length > 1 && time - this._times[0] > 50) {\n\t\t\tthis._positions.shift();\n\t\t\tthis._times.shift();\n\t\t}\n\t},\n\n\t_onZoomEnd: function () {\n\t\tvar pxCenter = this._map.getSize().divideBy(2),\n\t\t pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);\n\n\t\tthis._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;\n\t\tthis._worldWidth = this._map.getPixelWorldBounds().getSize().x;\n\t},\n\n\t_viscousLimit: function (value, threshold) {\n\t\treturn value - (value - threshold) * this._viscosity;\n\t},\n\n\t_onPreDragLimit: function () {\n\t\tif (!this._viscosity || !this._offsetLimit) { return; }\n\n\t\tvar offset = this._draggable._newPos.subtract(this._draggable._startPos);\n\n\t\tvar limit = this._offsetLimit;\n\t\tif (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); }\n\t\tif (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); }\n\t\tif (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); }\n\t\tif (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); }\n\n\t\tthis._draggable._newPos = this._draggable._startPos.add(offset);\n\t},\n\n\t_onPreDragWrap: function () {\n\t\t// TODO refactor to be able to adjust map pane position after zoom\n\t\tvar worldWidth = this._worldWidth,\n\t\t halfWidth = Math.round(worldWidth / 2),\n\t\t dx = this._initialWorldOffset,\n\t\t x = this._draggable._newPos.x,\n\t\t newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,\n\t\t newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,\n\t\t newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;\n\n\t\tthis._draggable._absPos = this._draggable._newPos.clone();\n\t\tthis._draggable._newPos.x = newX;\n\t},\n\n\t_onDragEnd: function (e) {\n\t\tvar map = this._map,\n\t\t options = map.options,\n\n\t\t noInertia = !options.inertia || this._times.length < 2;\n\n\t\tmap.fire('dragend', e);\n\n\t\tif (noInertia) {\n\t\t\tmap.fire('moveend');\n\n\t\t} else {\n\t\t\tthis._prunePositions(+new Date());\n\n\t\t\tvar direction = this._lastPos.subtract(this._positions[0]),\n\t\t\t duration = (this._lastTime - this._times[0]) / 1000,\n\t\t\t ease = options.easeLinearity,\n\n\t\t\t speedVector = direction.multiplyBy(ease / duration),\n\t\t\t speed = speedVector.distanceTo([0, 0]),\n\n\t\t\t limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),\n\t\t\t limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),\n\n\t\t\t decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),\n\t\t\t offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();\n\n\t\t\tif (!offset.x && !offset.y) {\n\t\t\t\tmap.fire('moveend');\n\n\t\t\t} else {\n\t\t\t\toffset = map._limitOffset(offset, map.options.maxBounds);\n\n\t\t\t\trequestAnimFrame(function () {\n\t\t\t\t\tmap.panBy(offset, {\n\t\t\t\t\t\tduration: decelerationDuration,\n\t\t\t\t\t\teaseLinearity: ease,\n\t\t\t\t\t\tnoMoveStart: true,\n\t\t\t\t\t\tanimate: true\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property dragging: Handler\n// Map dragging handler (by both mouse and touch).\nMap.addInitHook('addHandler', 'dragging', Drag);\n\n/*\n * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.\n */\n\n// @namespace Map\n// @section Keyboard Navigation Options\nMap.mergeOptions({\n\t// @option keyboard: Boolean = true\n\t// Makes the map focusable and allows users to navigate the map with keyboard\n\t// arrows and `+`/`-` keys.\n\tkeyboard: true,\n\n\t// @option keyboardPanDelta: Number = 80\n\t// Amount of pixels to pan when pressing an arrow key.\n\tkeyboardPanDelta: 80\n});\n\nvar Keyboard = Handler.extend({\n\n\tkeyCodes: {\n\t\tleft: [37],\n\t\tright: [39],\n\t\tdown: [40],\n\t\tup: [38],\n\t\tzoomIn: [187, 107, 61, 171],\n\t\tzoomOut: [189, 109, 54, 173]\n\t},\n\n\tinitialize: function (map) {\n\t\tthis._map = map;\n\n\t\tthis._setPanDelta(map.options.keyboardPanDelta);\n\t\tthis._setZoomDelta(map.options.zoomDelta);\n\t},\n\n\taddHooks: function () {\n\t\tvar container = this._map._container;\n\n\t\t// make the container focusable by tabbing\n\t\tif (container.tabIndex <= 0) {\n\t\t\tcontainer.tabIndex = '0';\n\t\t}\n\n\t\ton(container, {\n\t\t\tfocus: this._onFocus,\n\t\t\tblur: this._onBlur,\n\t\t\tmousedown: this._onMouseDown\n\t\t}, this);\n\n\t\tthis._map.on({\n\t\t\tfocus: this._addHooks,\n\t\t\tblur: this._removeHooks\n\t\t}, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tthis._removeHooks();\n\n\t\toff(this._map._container, {\n\t\t\tfocus: this._onFocus,\n\t\t\tblur: this._onBlur,\n\t\t\tmousedown: this._onMouseDown\n\t\t}, this);\n\n\t\tthis._map.off({\n\t\t\tfocus: this._addHooks,\n\t\t\tblur: this._removeHooks\n\t\t}, this);\n\t},\n\n\t_onMouseDown: function () {\n\t\tif (this._focused) { return; }\n\n\t\tvar body = document.body,\n\t\t docEl = document.documentElement,\n\t\t top = body.scrollTop || docEl.scrollTop,\n\t\t left = body.scrollLeft || docEl.scrollLeft;\n\n\t\tthis._map._container.focus();\n\n\t\twindow.scrollTo(left, top);\n\t},\n\n\t_onFocus: function () {\n\t\tthis._focused = true;\n\t\tthis._map.fire('focus');\n\t},\n\n\t_onBlur: function () {\n\t\tthis._focused = false;\n\t\tthis._map.fire('blur');\n\t},\n\n\t_setPanDelta: function (panDelta) {\n\t\tvar keys = this._panKeys = {},\n\t\t codes = this.keyCodes,\n\t\t i, len;\n\n\t\tfor (i = 0, len = codes.left.length; i < len; i++) {\n\t\t\tkeys[codes.left[i]] = [-1 * panDelta, 0];\n\t\t}\n\t\tfor (i = 0, len = codes.right.length; i < len; i++) {\n\t\t\tkeys[codes.right[i]] = [panDelta, 0];\n\t\t}\n\t\tfor (i = 0, len = codes.down.length; i < len; i++) {\n\t\t\tkeys[codes.down[i]] = [0, panDelta];\n\t\t}\n\t\tfor (i = 0, len = codes.up.length; i < len; i++) {\n\t\t\tkeys[codes.up[i]] = [0, -1 * panDelta];\n\t\t}\n\t},\n\n\t_setZoomDelta: function (zoomDelta) {\n\t\tvar keys = this._zoomKeys = {},\n\t\t codes = this.keyCodes,\n\t\t i, len;\n\n\t\tfor (i = 0, len = codes.zoomIn.length; i < len; i++) {\n\t\t\tkeys[codes.zoomIn[i]] = zoomDelta;\n\t\t}\n\t\tfor (i = 0, len = codes.zoomOut.length; i < len; i++) {\n\t\t\tkeys[codes.zoomOut[i]] = -zoomDelta;\n\t\t}\n\t},\n\n\t_addHooks: function () {\n\t\ton(document, 'keydown', this._onKeyDown, this);\n\t},\n\n\t_removeHooks: function () {\n\t\toff(document, 'keydown', this._onKeyDown, this);\n\t},\n\n\t_onKeyDown: function (e) {\n\t\tif (e.altKey || e.ctrlKey || e.metaKey) { return; }\n\n\t\tvar key = e.keyCode,\n\t\t map = this._map,\n\t\t offset;\n\n\t\tif (key in this._panKeys) {\n\n\t\t\tif (map._panAnim && map._panAnim._inProgress) { return; }\n\n\t\t\toffset = this._panKeys[key];\n\t\t\tif (e.shiftKey) {\n\t\t\t\toffset = toPoint(offset).multiplyBy(3);\n\t\t\t}\n\n\t\t\tmap.panBy(offset);\n\n\t\t\tif (map.options.maxBounds) {\n\t\t\t\tmap.panInsideBounds(map.options.maxBounds);\n\t\t\t}\n\n\t\t} else if (key in this._zoomKeys) {\n\t\t\tmap.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);\n\n\t\t} else if (key === 27 && map._popup && map._popup.options.closeOnEscapeKey) {\n\t\t\tmap.closePopup();\n\n\t\t} else {\n\t\t\treturn;\n\t\t}\n\n\t\tstop(e);\n\t}\n});\n\n// @section Handlers\n// @section Handlers\n// @property keyboard: Handler\n// Keyboard navigation handler.\nMap.addInitHook('addHandler', 'keyboard', Keyboard);\n\n/*\n * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @section Mousewheel options\n\t// @option scrollWheelZoom: Boolean|String = true\n\t// Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,\n\t// it will zoom to the center of the view regardless of where the mouse was.\n\tscrollWheelZoom: true,\n\n\t// @option wheelDebounceTime: Number = 40\n\t// Limits the rate at which a wheel can fire (in milliseconds). By default\n\t// user can't zoom via wheel more often than once per 40 ms.\n\twheelDebounceTime: 40,\n\n\t// @option wheelPxPerZoomLevel: Number = 60\n\t// How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))\n\t// mean a change of one full zoom level. Smaller values will make wheel-zooming\n\t// faster (and vice versa).\n\twheelPxPerZoomLevel: 60\n});\n\nvar ScrollWheelZoom = Handler.extend({\n\taddHooks: function () {\n\t\ton(this._map._container, 'mousewheel', this._onWheelScroll, this);\n\n\t\tthis._delta = 0;\n\t},\n\n\tremoveHooks: function () {\n\t\toff(this._map._container, 'mousewheel', this._onWheelScroll, this);\n\t},\n\n\t_onWheelScroll: function (e) {\n\t\tvar delta = getWheelDelta(e);\n\n\t\tvar debounce = this._map.options.wheelDebounceTime;\n\n\t\tthis._delta += delta;\n\t\tthis._lastMousePos = this._map.mouseEventToContainerPoint(e);\n\n\t\tif (!this._startTime) {\n\t\t\tthis._startTime = +new Date();\n\t\t}\n\n\t\tvar left = Math.max(debounce - (+new Date() - this._startTime), 0);\n\n\t\tclearTimeout(this._timer);\n\t\tthis._timer = setTimeout(bind(this._performZoom, this), left);\n\n\t\tstop(e);\n\t},\n\n\t_performZoom: function () {\n\t\tvar map = this._map,\n\t\t zoom = map.getZoom(),\n\t\t snap = this._map.options.zoomSnap || 0;\n\n\t\tmap._stop(); // stop panning and fly animations if any\n\n\t\t// map the delta with a sigmoid function to -4..4 range leaning on -1..1\n\t\tvar d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),\n\t\t d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,\n\t\t d4 = snap ? Math.ceil(d3 / snap) * snap : d3,\n\t\t delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;\n\n\t\tthis._delta = 0;\n\t\tthis._startTime = null;\n\n\t\tif (!delta) { return; }\n\n\t\tif (map.options.scrollWheelZoom === 'center') {\n\t\t\tmap.setZoom(zoom + delta);\n\t\t} else {\n\t\t\tmap.setZoomAround(this._lastMousePos, zoom + delta);\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property scrollWheelZoom: Handler\n// Scroll wheel zoom handler.\nMap.addInitHook('addHandler', 'scrollWheelZoom', ScrollWheelZoom);\n\n/*\n * L.Map.Tap is used to enable mobile hacks like quick taps and long hold.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @section Touch interaction options\n\t// @option tap: Boolean = true\n\t// Enables mobile hacks for supporting instant taps (fixing 200ms click\n\t// delay on iOS/Android) and touch holds (fired as `contextmenu` events).\n\ttap: true,\n\n\t// @option tapTolerance: Number = 15\n\t// The max number of pixels a user can shift his finger during touch\n\t// for it to be considered a valid tap.\n\ttapTolerance: 15\n});\n\nvar Tap = Handler.extend({\n\taddHooks: function () {\n\t\ton(this._map._container, 'touchstart', this._onDown, this);\n\t},\n\n\tremoveHooks: function () {\n\t\toff(this._map._container, 'touchstart', this._onDown, this);\n\t},\n\n\t_onDown: function (e) {\n\t\tif (!e.touches) { return; }\n\n\t\tpreventDefault(e);\n\n\t\tthis._fireClick = true;\n\n\t\t// don't simulate click or track longpress if more than 1 touch\n\t\tif (e.touches.length > 1) {\n\t\t\tthis._fireClick = false;\n\t\t\tclearTimeout(this._holdTimeout);\n\t\t\treturn;\n\t\t}\n\n\t\tvar first = e.touches[0],\n\t\t el = first.target;\n\n\t\tthis._startPos = this._newPos = new Point(first.clientX, first.clientY);\n\n\t\t// if touching a link, highlight it\n\t\tif (el.tagName && el.tagName.toLowerCase() === 'a') {\n\t\t\taddClass(el, 'leaflet-active');\n\t\t}\n\n\t\t// simulate long hold but setting a timeout\n\t\tthis._holdTimeout = setTimeout(bind(function () {\n\t\t\tif (this._isTapValid()) {\n\t\t\t\tthis._fireClick = false;\n\t\t\t\tthis._onUp();\n\t\t\t\tthis._simulateEvent('contextmenu', first);\n\t\t\t}\n\t\t}, this), 1000);\n\n\t\tthis._simulateEvent('mousedown', first);\n\n\t\ton(document, {\n\t\t\ttouchmove: this._onMove,\n\t\t\ttouchend: this._onUp\n\t\t}, this);\n\t},\n\n\t_onUp: function (e) {\n\t\tclearTimeout(this._holdTimeout);\n\n\t\toff(document, {\n\t\t\ttouchmove: this._onMove,\n\t\t\ttouchend: this._onUp\n\t\t}, this);\n\n\t\tif (this._fireClick && e && e.changedTouches) {\n\n\t\t\tvar first = e.changedTouches[0],\n\t\t\t el = first.target;\n\n\t\t\tif (el && el.tagName && el.tagName.toLowerCase() === 'a') {\n\t\t\t\tremoveClass(el, 'leaflet-active');\n\t\t\t}\n\n\t\t\tthis._simulateEvent('mouseup', first);\n\n\t\t\t// simulate click if the touch didn't move too much\n\t\t\tif (this._isTapValid()) {\n\t\t\t\tthis._simulateEvent('click', first);\n\t\t\t}\n\t\t}\n\t},\n\n\t_isTapValid: function () {\n\t\treturn this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;\n\t},\n\n\t_onMove: function (e) {\n\t\tvar first = e.touches[0];\n\t\tthis._newPos = new Point(first.clientX, first.clientY);\n\t\tthis._simulateEvent('mousemove', first);\n\t},\n\n\t_simulateEvent: function (type, e) {\n\t\tvar simulatedEvent = document.createEvent('MouseEvents');\n\n\t\tsimulatedEvent._simulated = true;\n\t\te.target._simulatedClick = true;\n\n\t\tsimulatedEvent.initMouseEvent(\n\t\t type, true, true, window, 1,\n\t\t e.screenX, e.screenY,\n\t\t e.clientX, e.clientY,\n\t\t false, false, false, false, 0, null);\n\n\t\te.target.dispatchEvent(simulatedEvent);\n\t}\n});\n\n// @section Handlers\n// @property tap: Handler\n// Mobile touch hacks (quick tap and touch hold) handler.\nif (touch && !pointer) {\n\tMap.addInitHook('addHandler', 'tap', Tap);\n}\n\n/*\n * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.\n */\n\n// @namespace Map\n// @section Interaction Options\nMap.mergeOptions({\n\t// @section Touch interaction options\n\t// @option touchZoom: Boolean|String = *\n\t// Whether the map can be zoomed by touch-dragging with two fingers. If\n\t// passed `'center'`, it will zoom to the center of the view regardless of\n\t// where the touch events (fingers) were. Enabled for touch-capable web\n\t// browsers except for old Androids.\n\ttouchZoom: touch && !android23,\n\n\t// @option bounceAtZoomLimits: Boolean = true\n\t// Set it to false if you don't want the map to zoom beyond min/max zoom\n\t// and then bounce back when pinch-zooming.\n\tbounceAtZoomLimits: true\n});\n\nvar TouchZoom = Handler.extend({\n\taddHooks: function () {\n\t\taddClass(this._map._container, 'leaflet-touch-zoom');\n\t\ton(this._map._container, 'touchstart', this._onTouchStart, this);\n\t},\n\n\tremoveHooks: function () {\n\t\tremoveClass(this._map._container, 'leaflet-touch-zoom');\n\t\toff(this._map._container, 'touchstart', this._onTouchStart, this);\n\t},\n\n\t_onTouchStart: function (e) {\n\t\tvar map = this._map;\n\t\tif (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }\n\n\t\tvar p1 = map.mouseEventToContainerPoint(e.touches[0]),\n\t\t p2 = map.mouseEventToContainerPoint(e.touches[1]);\n\n\t\tthis._centerPoint = map.getSize()._divideBy(2);\n\t\tthis._startLatLng = map.containerPointToLatLng(this._centerPoint);\n\t\tif (map.options.touchZoom !== 'center') {\n\t\t\tthis._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));\n\t\t}\n\n\t\tthis._startDist = p1.distanceTo(p2);\n\t\tthis._startZoom = map.getZoom();\n\n\t\tthis._moved = false;\n\t\tthis._zooming = true;\n\n\t\tmap._stop();\n\n\t\ton(document, 'touchmove', this._onTouchMove, this);\n\t\ton(document, 'touchend', this._onTouchEnd, this);\n\n\t\tpreventDefault(e);\n\t},\n\n\t_onTouchMove: function (e) {\n\t\tif (!e.touches || e.touches.length !== 2 || !this._zooming) { return; }\n\n\t\tvar map = this._map,\n\t\t p1 = map.mouseEventToContainerPoint(e.touches[0]),\n\t\t p2 = map.mouseEventToContainerPoint(e.touches[1]),\n\t\t scale = p1.distanceTo(p2) / this._startDist;\n\n\t\tthis._zoom = map.getScaleZoom(scale, this._startZoom);\n\n\t\tif (!map.options.bounceAtZoomLimits && (\n\t\t\t(this._zoom < map.getMinZoom() && scale < 1) ||\n\t\t\t(this._zoom > map.getMaxZoom() && scale > 1))) {\n\t\t\tthis._zoom = map._limitZoom(this._zoom);\n\t\t}\n\n\t\tif (map.options.touchZoom === 'center') {\n\t\t\tthis._center = this._startLatLng;\n\t\t\tif (scale === 1) { return; }\n\t\t} else {\n\t\t\t// Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng\n\t\t\tvar delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);\n\t\t\tif (scale === 1 && delta.x === 0 && delta.y === 0) { return; }\n\t\t\tthis._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom);\n\t\t}\n\n\t\tif (!this._moved) {\n\t\t\tmap._moveStart(true, false);\n\t\t\tthis._moved = true;\n\t\t}\n\n\t\tcancelAnimFrame(this._animRequest);\n\n\t\tvar moveFn = bind(map._move, map, this._center, this._zoom, {pinch: true, round: false});\n\t\tthis._animRequest = requestAnimFrame(moveFn, this, true);\n\n\t\tpreventDefault(e);\n\t},\n\n\t_onTouchEnd: function () {\n\t\tif (!this._moved || !this._zooming) {\n\t\t\tthis._zooming = false;\n\t\t\treturn;\n\t\t}\n\n\t\tthis._zooming = false;\n\t\tcancelAnimFrame(this._animRequest);\n\n\t\toff(document, 'touchmove', this._onTouchMove);\n\t\toff(document, 'touchend', this._onTouchEnd);\n\n\t\t// Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.\n\t\tif (this._map.options.zoomAnimation) {\n\t\t\tthis._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);\n\t\t} else {\n\t\t\tthis._map._resetView(this._center, this._map._limitZoom(this._zoom));\n\t\t}\n\t}\n});\n\n// @section Handlers\n// @property touchZoom: Handler\n// Touch zoom handler.\nMap.addInitHook('addHandler', 'touchZoom', TouchZoom);\n\nMap.BoxZoom = BoxZoom;\nMap.DoubleClickZoom = DoubleClickZoom;\nMap.Drag = Drag;\nMap.Keyboard = Keyboard;\nMap.ScrollWheelZoom = ScrollWheelZoom;\nMap.Tap = Tap;\nMap.TouchZoom = TouchZoom;\n\n// misc\r\n\r\nvar oldL = window.L;\r\nfunction noConflict() {\r\n\twindow.L = oldL;\r\n\treturn this;\r\n}\r\n\r\n// Always export us to window global (see #2364)\r\nwindow.L = exports;\r\n\r\nObject.freeze = freeze;\n\nexports.version = version;\nexports.noConflict = noConflict;\nexports.Control = Control;\nexports.control = control;\nexports.Browser = Browser;\nexports.Evented = Evented;\nexports.Mixin = Mixin;\nexports.Util = Util;\nexports.Class = Class;\nexports.Handler = Handler;\nexports.extend = extend;\nexports.bind = bind;\nexports.stamp = stamp;\nexports.setOptions = setOptions;\nexports.DomEvent = DomEvent;\nexports.DomUtil = DomUtil;\nexports.PosAnimation = PosAnimation;\nexports.Draggable = Draggable;\nexports.LineUtil = LineUtil;\nexports.PolyUtil = PolyUtil;\nexports.Point = Point;\nexports.point = toPoint;\nexports.Bounds = Bounds;\nexports.bounds = toBounds;\nexports.Transformation = Transformation;\nexports.transformation = toTransformation;\nexports.Projection = index;\nexports.LatLng = LatLng;\nexports.latLng = toLatLng;\nexports.LatLngBounds = LatLngBounds;\nexports.latLngBounds = toLatLngBounds;\nexports.CRS = CRS;\nexports.GeoJSON = GeoJSON;\nexports.geoJSON = geoJSON;\nexports.geoJson = geoJson;\nexports.Layer = Layer;\nexports.LayerGroup = LayerGroup;\nexports.layerGroup = layerGroup;\nexports.FeatureGroup = FeatureGroup;\nexports.featureGroup = featureGroup;\nexports.ImageOverlay = ImageOverlay;\nexports.imageOverlay = imageOverlay;\nexports.VideoOverlay = VideoOverlay;\nexports.videoOverlay = videoOverlay;\nexports.DivOverlay = DivOverlay;\nexports.Popup = Popup;\nexports.popup = popup;\nexports.Tooltip = Tooltip;\nexports.tooltip = tooltip;\nexports.Icon = Icon;\nexports.icon = icon;\nexports.DivIcon = DivIcon;\nexports.divIcon = divIcon;\nexports.Marker = Marker;\nexports.marker = marker;\nexports.TileLayer = TileLayer;\nexports.tileLayer = tileLayer;\nexports.GridLayer = GridLayer;\nexports.gridLayer = gridLayer;\nexports.SVG = SVG;\nexports.svg = svg$1;\nexports.Renderer = Renderer;\nexports.Canvas = Canvas;\nexports.canvas = canvas$1;\nexports.Path = Path;\nexports.CircleMarker = CircleMarker;\nexports.circleMarker = circleMarker;\nexports.Circle = Circle;\nexports.circle = circle;\nexports.Polyline = Polyline;\nexports.polyline = polyline;\nexports.Polygon = Polygon;\nexports.polygon = polygon;\nexports.Rectangle = Rectangle;\nexports.rectangle = rectangle;\nexports.Map = Map;\nexports.map = createMap;\n\n})));\n//# sourceMappingURL=leaflet-src.js.map\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvbGVhZmxldC9kaXN0L2xlYWZsZXQtc3JjLmpzPzllYjciXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCO0FBQ3hCLENBQUMsNEJBQTRCOztBQUU3Qjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsZ0NBQWdDLFlBQVk7O0FBRTVDO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG9DQUFvQyxTQUFTO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esb0JBQW9CLGNBQWM7O0FBRWxDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDBEQUEwRCxtQkFBbUI7QUFDN0U7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsb0JBQW9CLGVBQWU7O0FBRW5DO0FBQ0EsOEVBQThFLEVBQUUsR0FBRyxFQUFFO0FBQ3JGLDRCQUE0QixtQkFBbUI7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0Isa0JBQWtCO0FBQ2xDLHdCQUF3QixVQUFVO0FBQ2xDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9DQUFvQzs7QUFFcEM7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsK0RBQStELHlCQUF5Qjs7QUFFeEY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsOEJBQThCLFFBQVE7O0FBRXRDO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxnREFBZ0QsU0FBUztBQUN6RDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsbUNBQW1DO0FBQ25DOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGtEQUFrRCxRQUFROztBQUUxRDs7QUFFQSxnQkFBZ0IscUJBQXFCO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLHVDQUF1QztBQUNyRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBOztBQUVBLHNDQUFzQyxTQUFTO0FBQy9DO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOztBQUVBLEdBQUc7QUFDSDs7QUFFQSxzQ0FBc0MsU0FBUztBQUMvQztBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIscUJBQXFCO0FBQzFDOztBQUVBO0FBQ0EseUNBQXlDLFNBQVM7QUFDbEQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHNCQUFzQixRQUFROztBQUU5Qjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHNDQUFzQyxTQUFTO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxzQ0FBc0MsU0FBUztBQUMvQztBQUNBLDRCQUE0QixVQUFVO0FBQ3RDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QyxhQUFhOztBQUVwRCx1QkFBdUI7QUFDdkI7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBOztBQUVBO0FBQ0E7QUFDQSwyQ0FBMkMsU0FBUztBQUNwRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNDQUFzQyxhQUFhOztBQUVuRDtBQUNBO0FBQ0E7QUFDQSwwREFBMEQsYUFBYTtBQUN2RTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQSxXQUFXOztBQUVYO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esd0JBQXdCO0FBQ3hCO0FBQ0Esd0JBQXdCO0FBQ3hCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSx3Q0FBd0MscUJBQXFCO0FBQzdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxVQUFVLFFBQVE7O0FBRWxCOztBQUVBLHFDQUFxQyxTQUFTO0FBQzlDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSwyQkFBMkI7QUFDM0I7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsMkJBQTJCO0FBQzNCO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxrQkFBa0I7QUFDbEIsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxrQkFBa0I7QUFDbEIsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0M7QUFDaEM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSw4QkFBOEI7QUFDOUI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHlDQUF5QztBQUN6QyxnQkFBZ0IsUUFBUTs7QUFFeEI7O0FBRUEsc0NBQXNDLFNBQVM7QUFDL0M7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBOztBQUVBLHNCQUFzQixhQUFhOztBQUVuQyxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsMkJBQTJCO0FBQzNCO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixjQUFjOztBQUU5Qjs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxpQkFBaUI7QUFDL0IsY0FBYyxpQkFBaUI7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLGNBQWM7O0FBRTNCOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSx5Q0FBeUMseUJBQXlCLE9BQU8sc0NBQXNDOztBQUUvRztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCLGFBQWE7O0FBRW5DO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEscUJBQXFCO0FBQ3JCOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0NBQXdDO0FBQ3hDO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDO0FBQ3JDO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsd0JBQXdCO0FBQ3hCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGLENBQUM7O0FBRUQsMEJBQTBCO0FBQzFCO0FBQ0EsQ0FBQzs7QUFFRCxrQkFBa0I7QUFDbEI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdDQUFnQyxTQUFTO0FBQ3pDOztBQUVBLG1DQUFtQyxVQUFVO0FBQzdDO0FBQ0E7QUFDQTs7QUFFQSxrQ0FBa0M7QUFDbEM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSx5QkFBeUI7QUFDekI7O0FBRUEsNEJBQTRCO0FBQzVCOztBQUVBLDJCQUEyQjtBQUMzQjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLGdDQUFnQztBQUNoQzs7QUFFQTtBQUNBLGdGQUFnRjtBQUNoRixtQ0FBbUM7QUFDbkM7O0FBRUEsNEJBQTRCO0FBQzVCOztBQUVBLDZCQUE2QjtBQUM3Qjs7QUFFQSw0QkFBNEI7QUFDNUI7O0FBRUEsNkJBQTZCO0FBQzdCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSwwQkFBMEI7QUFDMUI7O0FBRUEsMkJBQTJCO0FBQzNCOztBQUVBLCtCQUErQjtBQUMvQjs7QUFFQSw4QkFBOEI7QUFDOUI7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDZCQUE2QjtBQUM3Qjs7QUFFQSxtQ0FBbUM7QUFDbkM7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsa0NBQWtDO0FBQ2xDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsRUFBRTtBQUNGO0FBQ0E7QUFDQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEVBQUU7QUFDRjs7QUFFQSxFQUFFO0FBQ0Y7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxFQUFFO0FBQ0Y7O0FBRUEsRUFBRTtBQUNGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLG1HQUFtRyxRQUFROztBQUUzRztBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLDhDQUE4QyxRQUFRO0FBQ3REO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUEsa0JBQWtCLFFBQVE7O0FBRTFCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsK0NBQStDLFFBQVE7QUFDdkQ7QUFDQSxxQkFBcUI7QUFDckI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLDZDQUE2Qyx1Q0FBdUM7QUFDcEY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7O0FBRUEscUNBQXFDLFNBQVM7QUFDOUM7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGdEQUFnRCx1Q0FBdUM7QUFDdkY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7O0FBRUEscUNBQXFDLFNBQVM7QUFDOUM7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSw0Q0FBNEMsYUFBYTs7QUFFekQ7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsRUFBRTtBQUNGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsZ0JBQWdCLGFBQWE7O0FBRTdCO0FBQ0E7O0FBRUEsRUFBRTtBQUNGO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFO0FBQ0Y7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRSw0QkFBNEI7QUFDOUI7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxnQkFBZ0IsYUFBYTs7QUFFN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOzs7OztBQUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsU0FBUztBQUNoRDtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBLG9CQUFvQixRQUFRO0FBQzVCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdCQUFnQixrQkFBa0I7QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IsUUFBUTtBQUM5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLFFBQVE7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSwwQkFBMEIsUUFBUTs7QUFFbEM7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkRBQTZEO0FBQzdEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRixxQ0FBcUM7QUFDckM7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx5REFBeUQsWUFBWTtBQUNyRTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7O0FBR0Y7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsMkJBQTJCLHlCQUF5QjtBQUNwRCwwQkFBMEIscURBQXFEO0FBQy9FOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtDQUErQyxjQUFjO0FBQzdELEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSx3Q0FBd0MsY0FBYztBQUN0RCxFQUFFOztBQUVGOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLG9DQUFvQztBQUNwQywyQ0FBMkMsYUFBYTtBQUN4RCxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLG9CQUFvQix5Q0FBeUM7QUFDN0Qsb0JBQW9CLHlDQUF5QztBQUM3RCxvQkFBb0IsMEJBQTBCOztBQUU5Qzs7QUFFQSxpQkFBaUIsNkNBQTZDO0FBQzlELGlCQUFpQiwrREFBK0Q7O0FBRWhGLHVCQUF1QixpQ0FBaUM7O0FBRXhEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNLFlBQVk7O0FBRWxCLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IsYUFBYTs7QUFFbkM7QUFDQTtBQUNBO0FBQ0EsR0FBRyxzQkFBc0IsY0FBYzs7QUFFdkM7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLCtCQUErQixhQUFhOztBQUU1QztBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQSxpRUFBaUUsWUFBWTtBQUM3RTtBQUNBLE1BQU0sY0FBYztBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCLGFBQWE7O0FBRW5DOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9EQUFvRDtBQUNwRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSx5REFBeUQ7QUFDekQ7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7O0FBR0Y7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsK0NBQStDO0FBQy9DO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0M7QUFDL0M7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DO0FBQ25DO0FBQ0EsRUFBRTs7O0FBR0Y7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOzs7QUFHRjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDRDQUE0QztBQUM1QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QixzQkFBc0Isc0JBQXNCLEVBQUUsRUFBRTtBQUN2RSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0NBQStDLE9BQU87QUFDdEQ7QUFDQSxrQkFBa0IsT0FBTztBQUN6QjtBQUNBLGlDQUFpQyxPQUFPO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQSxvQ0FBb0MsUUFBUTs7QUFFNUM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QjtBQUN4QjtBQUNBO0FBQ0E7O0FBRUEsbUJBQW1CLFFBQVE7O0FBRTNCO0FBQ0E7O0FBRUEsd0JBQXdCLFFBQVE7O0FBRWhDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxpQkFBaUIsb0JBQW9CO0FBQ3JDO0FBQ0E7QUFDQSxvR0FBb0csUUFBUTtBQUM1RztBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLDhDQUE4QyxTQUFTO0FBQ3ZEO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQyxhQUFhO0FBQ2hELEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxFQUFFOzs7QUFHRjs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQSxnQkFBZ0IsZUFBZTs7QUFFL0I7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsZ0JBQWdCLGVBQWU7O0FBRS9CO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0Esa0ZBQWtGLGNBQWM7O0FBRWhHOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQSw0QkFBNEIsYUFBYTs7QUFFekM7O0FBRUE7QUFDQTtBQUNBLDhFQUE4RSxjQUFjOztBQUU1RjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxxRUFBcUUsY0FBYzs7QUFFbkY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLHVCQUF1QixRQUFROztBQUUvQjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQSw2QkFBNkIsUUFBUTs7QUFFckM7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLENBQUM7O0FBRUQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLHlDQUF5QztBQUN6QztBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxpQkFBaUIseUJBQXlCO0FBQzFDO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBLGlCQUFpQix5QkFBeUI7QUFDMUM7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLGlCQUFpQix5QkFBeUI7O0FBRTFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLHlCQUF5QixhQUFhOztBQUV0QztBQUNBOztBQUVBO0FBQ0E7O0FBRUEsYUFBYSx5QkFBeUI7QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLGlDQUFpQyxRQUFRO0FBQ3pDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxhQUFhLDBCQUEwQjtBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsd0JBQXdCO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGlDQUFpQyxRQUFRO0FBQ3pDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDRDQUE0QztBQUM1QztBQUNBLHdCQUF3Qjs7QUFFeEI7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQSx1REFBdUQ7QUFDdkQ7QUFDQSxjQUFjLGFBQWE7O0FBRTNCO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxjQUFjLGFBQWE7O0FBRTNCO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLG1CQUFtQixRQUFROztBQUUzQjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCLGFBQWE7O0FBRW5DO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLGFBQWE7O0FBRXBDO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGFBQWE7O0FBRWI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IsUUFBUTs7QUFFOUI7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QixRQUFROztBQUUvQjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxzQkFBc0I7QUFDdEI7QUFDQSx1Q0FBdUM7QUFDdkM7QUFDQSx1Q0FBdUMsUUFBUTs7QUFFL0M7O0FBRUEscURBQXFELFFBQVE7O0FBRTdELGlHQUFpRyxRQUFRO0FBQ3pHLDZCQUE2Qjs7QUFFN0I7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEscUJBQXFCLFFBQVE7O0FBRTdCO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0Esc0JBQXNCO0FBQ3RCO0FBQ0EsdUNBQXVDO0FBQ3ZDO0FBQ0EsdUNBQXVDLFFBQVE7O0FBRS9DO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSwrQkFBK0IsUUFBUTtBQUN2Qyw4RUFBOEUsUUFBUTs7QUFFdEY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLFdBQVc7O0FBRVg7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxzQkFBc0I7QUFDdEI7QUFDQSx1Q0FBdUM7QUFDdkM7QUFDQSx1Q0FBdUMsUUFBUTtBQUMvQztBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLFlBQVksU0FBUztBQUNyQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsb0JBQW9CLGVBQWU7QUFDbkM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSwrQ0FBK0MsU0FBUztBQUN4RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsZ0JBQWdCO0FBQ2hCO0FBQ0E7O0FBRUEsRUFBRSxxQkFBcUI7QUFDdkI7QUFDQTs7QUFFQSxFQUFFLHFCQUFxQjtBQUN2QjtBQUNBOztBQUVBLEVBQUUscUJBQXFCO0FBQ3ZCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsMEJBQTBCO0FBQzFCO0FBQ0EsRUFBRSwrQkFBK0I7QUFDakM7QUFDQTs7QUFFQSwwQkFBMEI7QUFDMUI7QUFDQSxFQUFFLCtCQUErQjtBQUNqQztBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGlDQUFpQyxTQUFTO0FBQzFDO0FBQ0E7O0FBRUE7QUFDQSxZQUFZLE9BQU87QUFDbkI7QUFDQTs7QUFFQSwrQ0FBK0MsU0FBUztBQUN4RDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsa0NBQWtDLGlDQUFpQztBQUNuRTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7Ozs7QUFLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCO0FBQ3hCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHdCQUF3QjtBQUN4QjtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxzQkFBc0I7QUFDdEI7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0EsNEJBQTRCLFFBQVE7O0FBRXBDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx3QkFBd0IsWUFBWTtBQUNwQztBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdURBQXVELHlCQUF5QjtBQUNoRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EseUJBQXlCLGFBQWE7QUFDdEM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQSwwQkFBMEIsYUFBYTs7QUFFdkM7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLDZCQUE2QixhQUFhO0FBQzFDO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBLHNDQUFzQyxTQUFTO0FBQy9DO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLG1DQUFtQyxTQUFTO0FBQzVDO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7O0FBR0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCLDRDQUE0QyxFQUFFO0FBQzNFO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsZ0NBQWdDLGFBQWE7QUFDN0MsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsbUNBQW1DLGFBQWE7QUFDaEQsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSw4QkFBOEIsYUFBYTtBQUMzQztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQSwrQkFBK0I7QUFDL0I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSw2Q0FBNkM7O0FBRTdDOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSx3QkFBd0IsZUFBZTs7QUFFdkM7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNEJBQTRCLDJDQUEyQztBQUN2RSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGOztBQUVBLGtDQUFrQyxRQUFROztBQUUxQzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7O0FBR0Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLHFCQUFxQjtBQUNqRCxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkJBQTJCLFlBQVk7QUFDdkM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0Isa0JBQWtCLGdCQUFnQjtBQUN4RDtBQUNBO0FBQ0E7O0FBRUEsbUNBQW1DLGdEQUFnRDs7QUFFbkY7QUFDQTtBQUNBLDRCQUE0QjtBQUM1QjtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsZ0RBQWdEO0FBQ2hEOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHO0FBQ0g7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsYUFBYTtBQUNwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsNENBQTRDLFVBQVU7QUFDdEQ7O0FBRUEsdUNBQXVDLFNBQVM7QUFDaEQ7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLGFBQWEsYUFBYTs7QUFFMUIsaUNBQWlDOztBQUVqQywyQkFBMkIsYUFBYTtBQUN4QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHVCQUF1QixhQUFhO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRixtRUFBbUU7QUFDbkU7QUFDQTtBQUNBOztBQUVBLHVDQUF1QyxTQUFTO0FBQ2hEO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLDhDQUE4QyxTQUFTO0FBQ3ZEOztBQUVBLG9DQUFvQyxjQUFjO0FBQ2xEOztBQUVBLG1CQUFtQixVQUFVOztBQUU3QjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxxQ0FBcUMsU0FBUztBQUM5QztBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLG1CQUFtQixRQUFROztBQUUzQjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHVEQUF1RCxjQUFjOztBQUVyRTtBQUNBLHVDQUF1QyxTQUFTO0FBQ2hEOztBQUVBLGdEQUFnRCxVQUFVO0FBQzFELCtCQUErQixVQUFVOztBQUV6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLGFBQWE7QUFDbEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsYUFBYSxhQUFhOztBQUUxQixnQ0FBZ0M7O0FBRWhDOztBQUVBLDBCQUEwQixTQUFTO0FBQ25DO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxvREFBb0QsU0FBUztBQUM3RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxvQ0FBb0MsY0FBYzs7QUFFbEQ7QUFDQSx1Q0FBdUMsU0FBUztBQUNoRDs7QUFFQSxnREFBZ0QsVUFBVTtBQUMxRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxxQ0FBcUMsU0FBUztBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLG1EQUFtRCxhQUFhOztBQUVoRTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQjtBQUMzQjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxrQ0FBa0MsU0FBUztBQUMzQztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLCtDQUErQyxTQUFTO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsNkNBQTZDLFNBQVM7QUFDdEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsc0NBQXNDLFNBQVM7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFdBQVcsa0JBQWtCLHNCQUFzQjtBQUNuRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUYsOENBQThDO0FBQzlDO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSwyQkFBMkIsd0NBQXdDO0FBQ25FLCtCQUErQix1Q0FBdUM7O0FBRXRFO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDJCQUEyQix3Q0FBd0M7O0FBRW5FO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQiwyQkFBMkI7QUFDN0M7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsNEJBQTRCLHlCQUF5Qjs7QUFFckQ7QUFDQTtBQUNBLGlCQUFpQixzQkFBc0I7QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxtQkFBbUIsUUFBUTs7QUFFM0I7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLHVCQUF1QixRQUFROztBQUUvQjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLG1CQUFtQixRQUFROztBQUUzQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUEsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLFlBQVk7O0FBRXJDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUMsWUFBWTtBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQkFBMEIsWUFBWTs7QUFFdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9DQUFvQyxZQUFZO0FBQ2hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDOztBQUVsQztBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLHdGQUF3RixRQUFROztBQUVoRztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLCtEQUErRDtBQUMvRDtBQUNBO0FBQ0EsOENBQThDO0FBQzlDO0FBQ0E7QUFDQSxnRUFBZ0U7QUFDaEU7QUFDQTtBQUNBLDhDQUE4QztBQUM5QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyQkFBMkIsY0FBYzs7QUFFekM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQyxjQUFjO0FBQ25EO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCLGNBQWM7O0FBRTFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0MsY0FBYztBQUNwRDtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGLDhCQUE4Qjs7QUFFOUIsMkJBQTJCOztBQUUzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0EsR0FBRztBQUNIO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLGlEQUFpRCxRQUFRO0FBQ3pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQix5QkFBeUI7QUFDcEQ7QUFDQTtBQUNBLDhCQUE4QixhQUFhO0FBQzNDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0EsaURBQWlEOztBQUVqRCw4Q0FBOEMsU0FBUzs7QUFFdkQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0EsbUJBQW1CLFFBQVE7O0FBRTNCO0FBQ0EsY0FBYyxRQUFROztBQUV0Qjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHVDQUF1QyxVQUFVOztBQUVqRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG9DQUFvQyxvQkFBb0I7O0FBRXhEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBLHdCQUF3QixRQUFROztBQUVoQztBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTs7QUFFQSwyQkFBMkIsa0JBQWtCOztBQUU3QztBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxFQUFFOztBQUVGOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUEscUJBQXFCLGVBQWU7QUFDcEMsc0JBQXNCLGVBQWU7O0FBRXJDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0EsK0NBQStDLFFBQVE7O0FBRXZEO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLGFBQWEsUUFBUTtBQUNyQjs7QUFFQSw2QkFBNkIsMEJBQTBCO0FBQ3ZELHFDQUFxQyxRQUFRLEVBQUU7O0FBRS9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLGtFQUFrRTs7QUFFdkc7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSw0Q0FBNEMsNkJBQTZCLFFBQVE7O0FBRWpGO0FBQ0EsK0JBQStCLHNCQUFzQjtBQUNyRCxnQ0FBZ0Msc0JBQXNCO0FBQ3REO0FBQ0E7O0FBRUEscUNBQXFDLFVBQVU7O0FBRS9DO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxjQUFjLGtCQUFrQjtBQUNoQztBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnRkFBZ0YsY0FBYztBQUM5Rjs7QUFFQSw2QkFBNkIsYUFBYTs7QUFFMUM7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLGNBQWMsUUFBUTs7QUFFdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0Esd0RBQXdEO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBLG1CQUFtQixRQUFROztBQUUzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTs7QUFFQTtBQUNBLGNBQWMsUUFBUTs7QUFFdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxrQ0FBa0MsY0FBYztBQUNoRDtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLEVBQUUseUJBQXlCLEVBQUUsRUFBRSxFQUFFLEVBQUUsRUFBRSxNQUFNLElBQUksSUFBSSxXQUFXO0FBQ3RGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLEVBQUUsd0JBQXdCLEVBQUUsRUFBRSxFQUFFLEVBQUUsR0FBRyxFQUFFO0FBQ25EO0FBQ0E7QUFDQSxLQUFLLEVBQUUsd0hBQXdILDJDQUEyQyxnREFBZ0QsRUFBRSxrQkFBa0IsRUFBRSxRQUFRLEVBQUUsd0JBQXdCLEVBQUUsOEJBQThCO0FBQ2xUO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLEVBQUUsaUJBQWlCLElBQUksRUFBRSxFQUFFLEVBQUUsRUFBRSxFQUFFLEVBQUUsUUFBUSxXQUFXO0FBQzlFO0FBQ0E7OztBQUdBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7OztBQUdEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQSwyQkFBMkI7O0FBRTNCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EseUJBQXlCOztBQUV6QjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhCQUE4QixlQUFlO0FBQzdDLHdDQUF3Qyx1QkFBdUI7QUFDL0QsbUNBQW1DLHVCQUF1QjtBQUMxRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLGtDQUFrQyxRQUFROztBQUUxQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQSxpREFBaUQsUUFBUTs7QUFFekQ7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsd0NBQXdDO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLDZCQUE2QjtBQUNwRDtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxrQkFBa0I7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0EsbUJBQW1CLFFBQVE7O0FBRTNCO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdCQUFnQjtBQUNoQixlQUFlOztBQUVmO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxtQ0FBbUMsT0FBTztBQUMxQztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLHNCQUFzQjtBQUN0QixFQUFFOztBQUVGO0FBQ0EsdUJBQXVCLFFBQVE7O0FBRS9CO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGFBQWEsUUFBUTs7QUFFckI7O0FBRUE7O0FBRUEsYUFBYSxTQUFTO0FBQ3RCLHNDQUFzQyxVQUFVO0FBQ2hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQSx5Q0FBeUMsUUFBUTs7QUFFakQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsbUNBQW1DLE9BQU87QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLDhFQUE4RSxRQUFROztBQUV0RjtBQUNBO0FBQ0EsRUFBRTs7O0FBR0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQSxtQ0FBbUMsT0FBTztBQUMxQztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxxREFBcUQ7QUFDckQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQSxpQ0FBaUMsUUFBUTtBQUN6QztBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQixlQUFlO0FBQzFDLHdDQUF3Qyx1QkFBdUI7QUFDL0QsbUNBQW1DLHVCQUF1QjtBQUMxRDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBLGlEQUFpRDtBQUNqRDs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0EsaURBQWlELFFBQVE7O0FBRXpEOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQSx5QkFBeUIsdUJBQXVCO0FBQ2hEO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQSxjQUFjLFFBQVE7O0FBRXRCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSw2QkFBNkIsV0FBVywyQkFBMkIsV0FBVztBQUM5RTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IsNEJBQTRCO0FBQ3BEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7O0FBR0Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLDZEQUE2RCxjQUFjOztBQUUzRTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBLDRDQUE0QyxRQUFROztBQUVwRDs7QUFFQSxxQkFBcUIsUUFBUTtBQUM3QjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHdCQUF3QixzQkFBc0I7QUFDOUMsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQSwrQ0FBK0MsUUFBUTs7QUFFdkQ7O0FBRUE7QUFDQSwrQkFBK0Isc0RBQXNEO0FBQ3JGLCtCQUErQixzREFBc0Q7QUFDckYsK0JBQStCLHNEQUFzRDtBQUNyRiwrQkFBK0Isc0RBQXNEOztBQUVyRjtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0Esc0JBQXNCLFFBQVE7O0FBRTlCO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQSwrQkFBK0I7QUFDL0I7QUFDQTs7QUFFQSxzQ0FBc0MsU0FBUztBQUMvQztBQUNBO0FBQ0EsdUNBQXVDLFNBQVM7QUFDaEQ7QUFDQTtBQUNBLHNDQUFzQyxTQUFTO0FBQy9DO0FBQ0E7QUFDQSxvQ0FBb0MsU0FBUztBQUM3QztBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLGdDQUFnQztBQUNoQztBQUNBOztBQUVBLHdDQUF3QyxTQUFTO0FBQ2pEO0FBQ0E7QUFDQSx5Q0FBeUMsU0FBUztBQUNsRDtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLDJDQUEyQyxRQUFROztBQUVuRDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsa0RBQWtELFFBQVE7O0FBRTFEO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHO0FBQ0g7O0FBRUEsR0FBRztBQUNIOztBQUVBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGNBQWM7O0FBRWQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLGVBQWUsUUFBUTs7QUFFdkI7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0EsbUJBQW1CLFFBQVE7O0FBRTNCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxvRkFBb0YsUUFBUTs7QUFFNUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLCtEQUErRCxRQUFROztBQUV2RTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxxQkFBcUIsUUFBUTtBQUM3QixHQUFHO0FBQ0g7QUFDQTtBQUNBLHVEQUF1RCxRQUFRO0FBQy9EO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsK0RBQStELDBCQUEwQjtBQUN6Rjs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsQ0FBQztBQUNEIiwiZmlsZSI6Ii4vbm9kZV9tb2R1bGVzL2xlYWZsZXQvZGlzdC9sZWFmbGV0LXNyYy5qcy5qcyIsInNvdXJjZXNDb250ZW50IjpbIi8qIEBwcmVzZXJ2ZVxuICogTGVhZmxldCAxLjMuMSwgYSBKUyBsaWJyYXJ5IGZvciBpbnRlcmFjdGl2ZSBtYXBzLiBodHRwOi8vbGVhZmxldGpzLmNvbVxuICogKGMpIDIwMTAtMjAxNyBWbGFkaW1pciBBZ2Fmb25raW4sIChjKSAyMDEwLTIwMTEgQ2xvdWRNYWRlXG4gKi9cblxuKGZ1bmN0aW9uIChnbG9iYWwsIGZhY3RvcnkpIHtcblx0dHlwZW9mIGV4cG9ydHMgPT09ICdvYmplY3QnICYmIHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnID8gZmFjdG9yeShleHBvcnRzKSA6XG5cdHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCA/IGRlZmluZShbJ2V4cG9ydHMnXSwgZmFjdG9yeSkgOlxuXHQoZmFjdG9yeSgoZ2xvYmFsLkwgPSB7fSkpKTtcbn0odGhpcywgKGZ1bmN0aW9uIChleHBvcnRzKSB7ICd1c2Ugc3RyaWN0JztcblxudmFyIHZlcnNpb24gPSBcIjEuMy4xXCI7XG5cbi8qXHJcbiAqIEBuYW1lc3BhY2UgVXRpbFxyXG4gKlxyXG4gKiBWYXJpb3VzIHV0aWxpdHkgZnVuY3Rpb25zLCB1c2VkIGJ5IExlYWZsZXQgaW50ZXJuYWxseS5cclxuICovXHJcblxyXG52YXIgZnJlZXplID0gT2JqZWN0LmZyZWV6ZTtcclxuT2JqZWN0LmZyZWV6ZSA9IGZ1bmN0aW9uIChvYmopIHsgcmV0dXJuIG9iajsgfTtcclxuXHJcbi8vIEBmdW5jdGlvbiBleHRlbmQoZGVzdDogT2JqZWN0LCBzcmM/OiBPYmplY3QpOiBPYmplY3RcclxuLy8gTWVyZ2VzIHRoZSBwcm9wZXJ0aWVzIG9mIHRoZSBgc3JjYCBvYmplY3QgKG9yIG11bHRpcGxlIG9iamVjdHMpIGludG8gYGRlc3RgIG9iamVjdCBhbmQgcmV0dXJucyB0aGUgbGF0dGVyLiBIYXMgYW4gYEwuZXh0ZW5kYCBzaG9ydGN1dC5cclxuZnVuY3Rpb24gZXh0ZW5kKGRlc3QpIHtcclxuXHR2YXIgaSwgaiwgbGVuLCBzcmM7XHJcblxyXG5cdGZvciAoaiA9IDEsIGxlbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGogPCBsZW47IGorKykge1xyXG5cdFx0c3JjID0gYXJndW1lbnRzW2pdO1xyXG5cdFx0Zm9yIChpIGluIHNyYykge1xyXG5cdFx0XHRkZXN0W2ldID0gc3JjW2ldO1xyXG5cdFx0fVxyXG5cdH1cclxuXHRyZXR1cm4gZGVzdDtcclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIGNyZWF0ZShwcm90bzogT2JqZWN0LCBwcm9wZXJ0aWVzPzogT2JqZWN0KTogT2JqZWN0XHJcbi8vIENvbXBhdGliaWxpdHkgcG9seWZpbGwgZm9yIFtPYmplY3QuY3JlYXRlXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9PYmplY3QvY3JlYXRlKVxyXG52YXIgY3JlYXRlID0gT2JqZWN0LmNyZWF0ZSB8fCAoZnVuY3Rpb24gKCkge1xyXG5cdGZ1bmN0aW9uIEYoKSB7fVxyXG5cdHJldHVybiBmdW5jdGlvbiAocHJvdG8pIHtcclxuXHRcdEYucHJvdG90eXBlID0gcHJvdG87XHJcblx0XHRyZXR1cm4gbmV3IEYoKTtcclxuXHR9O1xyXG59KSgpO1xyXG5cclxuLy8gQGZ1bmN0aW9uIGJpbmQoZm46IEZ1bmN0aW9uLCDigKYpOiBGdW5jdGlvblxyXG4vLyBSZXR1cm5zIGEgbmV3IGZ1bmN0aW9uIGJvdW5kIHRvIHRoZSBhcmd1bWVudHMgcGFzc2VkLCBsaWtlIFtGdW5jdGlvbi5wcm90b3R5cGUuYmluZF0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvRnVuY3Rpb24vYmluZCkuXHJcbi8vIEhhcyBhIGBMLmJpbmQoKWAgc2hvcnRjdXQuXHJcbmZ1bmN0aW9uIGJpbmQoZm4sIG9iaikge1xyXG5cdHZhciBzbGljZSA9IEFycmF5LnByb3RvdHlwZS5zbGljZTtcclxuXHJcblx0aWYgKGZuLmJpbmQpIHtcclxuXHRcdHJldHVybiBmbi5iaW5kLmFwcGx5KGZuLCBzbGljZS5jYWxsKGFyZ3VtZW50cywgMSkpO1xyXG5cdH1cclxuXHJcblx0dmFyIGFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMik7XHJcblxyXG5cdHJldHVybiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gZm4uYXBwbHkob2JqLCBhcmdzLmxlbmd0aCA/IGFyZ3MuY29uY2F0KHNsaWNlLmNhbGwoYXJndW1lbnRzKSkgOiBhcmd1bWVudHMpO1xyXG5cdH07XHJcbn1cclxuXHJcbi8vIEBwcm9wZXJ0eSBsYXN0SWQ6IE51bWJlclxyXG4vLyBMYXN0IHVuaXF1ZSBJRCB1c2VkIGJ5IFtgc3RhbXAoKWBdKCN1dGlsLXN0YW1wKVxyXG52YXIgbGFzdElkID0gMDtcclxuXHJcbi8vIEBmdW5jdGlvbiBzdGFtcChvYmo6IE9iamVjdCk6IE51bWJlclxyXG4vLyBSZXR1cm5zIHRoZSB1bmlxdWUgSUQgb2YgYW4gb2JqZWN0LCBhc3NpZ25pbmcgaXQgb25lIGlmIGl0IGRvZXNuJ3QgaGF2ZSBpdC5cclxuZnVuY3Rpb24gc3RhbXAob2JqKSB7XHJcblx0Lyplc2xpbnQtZGlzYWJsZSAqL1xyXG5cdG9iai5fbGVhZmxldF9pZCA9IG9iai5fbGVhZmxldF9pZCB8fCArK2xhc3RJZDtcclxuXHRyZXR1cm4gb2JqLl9sZWFmbGV0X2lkO1xyXG5cdC8qIGVzbGludC1lbmFibGUgKi9cclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIHRocm90dGxlKGZuOiBGdW5jdGlvbiwgdGltZTogTnVtYmVyLCBjb250ZXh0OiBPYmplY3QpOiBGdW5jdGlvblxyXG4vLyBSZXR1cm5zIGEgZnVuY3Rpb24gd2hpY2ggZXhlY3V0ZXMgZnVuY3Rpb24gYGZuYCB3aXRoIHRoZSBnaXZlbiBzY29wZSBgY29udGV4dGBcclxuLy8gKHNvIHRoYXQgdGhlIGB0aGlzYCBrZXl3b3JkIHJlZmVycyB0byBgY29udGV4dGAgaW5zaWRlIGBmbmAncyBjb2RlKS4gVGhlIGZ1bmN0aW9uXHJcbi8vIGBmbmAgd2lsbCBiZSBjYWxsZWQgbm8gbW9yZSB0aGFuIG9uZSB0aW1lIHBlciBnaXZlbiBhbW91bnQgb2YgYHRpbWVgLiBUaGUgYXJndW1lbnRzXHJcbi8vIHJlY2VpdmVkIGJ5IHRoZSBib3VuZCBmdW5jdGlvbiB3aWxsIGJlIGFueSBhcmd1bWVudHMgcGFzc2VkIHdoZW4gYmluZGluZyB0aGVcclxuLy8gZnVuY3Rpb24sIGZvbGxvd2VkIGJ5IGFueSBhcmd1bWVudHMgcGFzc2VkIHdoZW4gaW52b2tpbmcgdGhlIGJvdW5kIGZ1bmN0aW9uLlxyXG4vLyBIYXMgYW4gYEwudGhyb3R0bGVgIHNob3J0Y3V0LlxyXG5mdW5jdGlvbiB0aHJvdHRsZShmbiwgdGltZSwgY29udGV4dCkge1xyXG5cdHZhciBsb2NrLCBhcmdzLCB3cmFwcGVyRm4sIGxhdGVyO1xyXG5cclxuXHRsYXRlciA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdC8vIHJlc2V0IGxvY2sgYW5kIGNhbGwgaWYgcXVldWVkXHJcblx0XHRsb2NrID0gZmFsc2U7XHJcblx0XHRpZiAoYXJncykge1xyXG5cdFx0XHR3cmFwcGVyRm4uYXBwbHkoY29udGV4dCwgYXJncyk7XHJcblx0XHRcdGFyZ3MgPSBmYWxzZTtcclxuXHRcdH1cclxuXHR9O1xyXG5cclxuXHR3cmFwcGVyRm4gPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAobG9jaykge1xyXG5cdFx0XHQvLyBjYWxsZWQgdG9vIHNvb24sIHF1ZXVlIHRvIGNhbGwgbGF0ZXJcclxuXHRcdFx0YXJncyA9IGFyZ3VtZW50cztcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHQvLyBjYWxsIGFuZCBsb2NrIHVudGlsIGxhdGVyXHJcblx0XHRcdGZuLmFwcGx5KGNvbnRleHQsIGFyZ3VtZW50cyk7XHJcblx0XHRcdHNldFRpbWVvdXQobGF0ZXIsIHRpbWUpO1xyXG5cdFx0XHRsb2NrID0gdHJ1ZTtcclxuXHRcdH1cclxuXHR9O1xyXG5cclxuXHRyZXR1cm4gd3JhcHBlckZuO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gd3JhcE51bShudW06IE51bWJlciwgcmFuZ2U6IE51bWJlcltdLCBpbmNsdWRlTWF4PzogQm9vbGVhbik6IE51bWJlclxyXG4vLyBSZXR1cm5zIHRoZSBudW1iZXIgYG51bWAgbW9kdWxvIGByYW5nZWAgaW4gc3VjaCBhIHdheSBzbyBpdCBsaWVzIHdpdGhpblxyXG4vLyBgcmFuZ2VbMF1gIGFuZCBgcmFuZ2VbMV1gLiBUaGUgcmV0dXJuZWQgdmFsdWUgd2lsbCBiZSBhbHdheXMgc21hbGxlciB0aGFuXHJcbi8vIGByYW5nZVsxXWAgdW5sZXNzIGBpbmNsdWRlTWF4YCBpcyBzZXQgdG8gYHRydWVgLlxyXG5mdW5jdGlvbiB3cmFwTnVtKHgsIHJhbmdlLCBpbmNsdWRlTWF4KSB7XHJcblx0dmFyIG1heCA9IHJhbmdlWzFdLFxyXG5cdCAgICBtaW4gPSByYW5nZVswXSxcclxuXHQgICAgZCA9IG1heCAtIG1pbjtcclxuXHRyZXR1cm4geCA9PT0gbWF4ICYmIGluY2x1ZGVNYXggPyB4IDogKCh4IC0gbWluKSAlIGQgKyBkKSAlIGQgKyBtaW47XHJcbn1cclxuXHJcbi8vIEBmdW5jdGlvbiBmYWxzZUZuKCk6IEZ1bmN0aW9uXHJcbi8vIFJldHVybnMgYSBmdW5jdGlvbiB3aGljaCBhbHdheXMgcmV0dXJucyBgZmFsc2VgLlxyXG5mdW5jdGlvbiBmYWxzZUZuKCkgeyByZXR1cm4gZmFsc2U7IH1cclxuXHJcbi8vIEBmdW5jdGlvbiBmb3JtYXROdW0obnVtOiBOdW1iZXIsIGRpZ2l0cz86IE51bWJlcik6IE51bWJlclxyXG4vLyBSZXR1cm5zIHRoZSBudW1iZXIgYG51bWAgcm91bmRlZCB0byBgZGlnaXRzYCBkZWNpbWFscywgb3IgdG8gNiBkZWNpbWFscyBieSBkZWZhdWx0LlxyXG5mdW5jdGlvbiBmb3JtYXROdW0obnVtLCBkaWdpdHMpIHtcclxuXHR2YXIgcG93ID0gTWF0aC5wb3coMTAsIChkaWdpdHMgPT09IHVuZGVmaW5lZCA/IDYgOiBkaWdpdHMpKTtcclxuXHRyZXR1cm4gTWF0aC5yb3VuZChudW0gKiBwb3cpIC8gcG93O1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gdHJpbShzdHI6IFN0cmluZyk6IFN0cmluZ1xyXG4vLyBDb21wYXRpYmlsaXR5IHBvbHlmaWxsIGZvciBbU3RyaW5nLnByb3RvdHlwZS50cmltXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9TdHJpbmcvVHJpbSlcclxuZnVuY3Rpb24gdHJpbShzdHIpIHtcclxuXHRyZXR1cm4gc3RyLnRyaW0gPyBzdHIudHJpbSgpIDogc3RyLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKTtcclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIHNwbGl0V29yZHMoc3RyOiBTdHJpbmcpOiBTdHJpbmdbXVxyXG4vLyBUcmltcyBhbmQgc3BsaXRzIHRoZSBzdHJpbmcgb24gd2hpdGVzcGFjZSBhbmQgcmV0dXJucyB0aGUgYXJyYXkgb2YgcGFydHMuXHJcbmZ1bmN0aW9uIHNwbGl0V29yZHMoc3RyKSB7XHJcblx0cmV0dXJuIHRyaW0oc3RyKS5zcGxpdCgvXFxzKy8pO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gc2V0T3B0aW9ucyhvYmo6IE9iamVjdCwgb3B0aW9uczogT2JqZWN0KTogT2JqZWN0XHJcbi8vIE1lcmdlcyB0aGUgZ2l2ZW4gcHJvcGVydGllcyB0byB0aGUgYG9wdGlvbnNgIG9mIHRoZSBgb2JqYCBvYmplY3QsIHJldHVybmluZyB0aGUgcmVzdWx0aW5nIG9wdGlvbnMuIFNlZSBgQ2xhc3Mgb3B0aW9uc2AuIEhhcyBhbiBgTC5zZXRPcHRpb25zYCBzaG9ydGN1dC5cclxuZnVuY3Rpb24gc2V0T3B0aW9ucyhvYmosIG9wdGlvbnMpIHtcclxuXHRpZiAoIW9iai5oYXNPd25Qcm9wZXJ0eSgnb3B0aW9ucycpKSB7XHJcblx0XHRvYmoub3B0aW9ucyA9IG9iai5vcHRpb25zID8gY3JlYXRlKG9iai5vcHRpb25zKSA6IHt9O1xyXG5cdH1cclxuXHRmb3IgKHZhciBpIGluIG9wdGlvbnMpIHtcclxuXHRcdG9iai5vcHRpb25zW2ldID0gb3B0aW9uc1tpXTtcclxuXHR9XHJcblx0cmV0dXJuIG9iai5vcHRpb25zO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gZ2V0UGFyYW1TdHJpbmcob2JqOiBPYmplY3QsIGV4aXN0aW5nVXJsPzogU3RyaW5nLCB1cHBlcmNhc2U/OiBCb29sZWFuKTogU3RyaW5nXHJcbi8vIENvbnZlcnRzIGFuIG9iamVjdCBpbnRvIGEgcGFyYW1ldGVyIFVSTCBzdHJpbmcsIGUuZy4gYHthOiBcImZvb1wiLCBiOiBcImJhclwifWBcclxuLy8gdHJhbnNsYXRlcyB0byBgJz9hPWZvbyZiPWJhcidgLiBJZiBgZXhpc3RpbmdVcmxgIGlzIHNldCwgdGhlIHBhcmFtZXRlcnMgd2lsbFxyXG4vLyBiZSBhcHBlbmRlZCBhdCB0aGUgZW5kLiBJZiBgdXBwZXJjYXNlYCBpcyBgdHJ1ZWAsIHRoZSBwYXJhbWV0ZXIgbmFtZXMgd2lsbFxyXG4vLyBiZSB1cHBlcmNhc2VkIChlLmcuIGAnP0E9Zm9vJkI9YmFyJ2ApXHJcbmZ1bmN0aW9uIGdldFBhcmFtU3RyaW5nKG9iaiwgZXhpc3RpbmdVcmwsIHVwcGVyY2FzZSkge1xyXG5cdHZhciBwYXJhbXMgPSBbXTtcclxuXHRmb3IgKHZhciBpIGluIG9iaikge1xyXG5cdFx0cGFyYW1zLnB1c2goZW5jb2RlVVJJQ29tcG9uZW50KHVwcGVyY2FzZSA/IGkudG9VcHBlckNhc2UoKSA6IGkpICsgJz0nICsgZW5jb2RlVVJJQ29tcG9uZW50KG9ialtpXSkpO1xyXG5cdH1cclxuXHRyZXR1cm4gKCghZXhpc3RpbmdVcmwgfHwgZXhpc3RpbmdVcmwuaW5kZXhPZignPycpID09PSAtMSkgPyAnPycgOiAnJicpICsgcGFyYW1zLmpvaW4oJyYnKTtcclxufVxyXG5cclxudmFyIHRlbXBsYXRlUmUgPSAvXFx7ICooW1xcd18tXSspICpcXH0vZztcclxuXHJcbi8vIEBmdW5jdGlvbiB0ZW1wbGF0ZShzdHI6IFN0cmluZywgZGF0YTogT2JqZWN0KTogU3RyaW5nXHJcbi8vIFNpbXBsZSB0ZW1wbGF0aW5nIGZhY2lsaXR5LCBhY2NlcHRzIGEgdGVtcGxhdGUgc3RyaW5nIG9mIHRoZSBmb3JtIGAnSGVsbG8ge2F9LCB7Yn0nYFxyXG4vLyBhbmQgYSBkYXRhIG9iamVjdCBsaWtlIGB7YTogJ2ZvbycsIGI6ICdiYXInfWAsIHJldHVybnMgZXZhbHVhdGVkIHN0cmluZ1xyXG4vLyBgKCdIZWxsbyBmb28sIGJhcicpYC4gWW91IGNhbiBhbHNvIHNwZWNpZnkgZnVuY3Rpb25zIGluc3RlYWQgb2Ygc3RyaW5ncyBmb3JcclxuLy8gZGF0YSB2YWx1ZXMg4oCUIHRoZXkgd2lsbCBiZSBldmFsdWF0ZWQgcGFzc2luZyBgZGF0YWAgYXMgYW4gYXJndW1lbnQuXHJcbmZ1bmN0aW9uIHRlbXBsYXRlKHN0ciwgZGF0YSkge1xyXG5cdHJldHVybiBzdHIucmVwbGFjZSh0ZW1wbGF0ZVJlLCBmdW5jdGlvbiAoc3RyLCBrZXkpIHtcclxuXHRcdHZhciB2YWx1ZSA9IGRhdGFba2V5XTtcclxuXHJcblx0XHRpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkge1xyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ05vIHZhbHVlIHByb3ZpZGVkIGZvciB2YXJpYWJsZSAnICsgc3RyKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJykge1xyXG5cdFx0XHR2YWx1ZSA9IHZhbHVlKGRhdGEpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHZhbHVlO1xyXG5cdH0pO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gaXNBcnJheShvYmopOiBCb29sZWFuXHJcbi8vIENvbXBhdGliaWxpdHkgcG9seWZpbGwgZm9yIFtBcnJheS5pc0FycmF5XShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9BcnJheS9pc0FycmF5KVxyXG52YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXkgfHwgZnVuY3Rpb24gKG9iaikge1xyXG5cdHJldHVybiAoT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9iaikgPT09ICdbb2JqZWN0IEFycmF5XScpO1xyXG59O1xyXG5cclxuLy8gQGZ1bmN0aW9uIGluZGV4T2YoYXJyYXk6IEFycmF5LCBlbDogT2JqZWN0KTogTnVtYmVyXHJcbi8vIENvbXBhdGliaWxpdHkgcG9seWZpbGwgZm9yIFtBcnJheS5wcm90b3R5cGUuaW5kZXhPZl0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvaW5kZXhPZilcclxuZnVuY3Rpb24gaW5kZXhPZihhcnJheSwgZWwpIHtcclxuXHRmb3IgKHZhciBpID0gMDsgaSA8IGFycmF5Lmxlbmd0aDsgaSsrKSB7XHJcblx0XHRpZiAoYXJyYXlbaV0gPT09IGVsKSB7IHJldHVybiBpOyB9XHJcblx0fVxyXG5cdHJldHVybiAtMTtcclxufVxyXG5cclxuLy8gQHByb3BlcnR5IGVtcHR5SW1hZ2VVcmw6IFN0cmluZ1xyXG4vLyBEYXRhIFVSSSBzdHJpbmcgY29udGFpbmluZyBhIGJhc2U2NC1lbmNvZGVkIGVtcHR5IEdJRiBpbWFnZS5cclxuLy8gVXNlZCBhcyBhIGhhY2sgdG8gZnJlZSBtZW1vcnkgZnJvbSB1bnVzZWQgaW1hZ2VzIG9uIFdlYktpdC1wb3dlcmVkXHJcbi8vIG1vYmlsZSBkZXZpY2VzIChieSBzZXR0aW5nIGltYWdlIGBzcmNgIHRvIHRoaXMgc3RyaW5nKS5cclxudmFyIGVtcHR5SW1hZ2VVcmwgPSAnZGF0YTppbWFnZS9naWY7YmFzZTY0LFIwbEdPRGxoQVFBQkFBRC9BQ3dBQUFBQUFRQUJBQUFDQURzPSc7XHJcblxyXG4vLyBpbnNwaXJlZCBieSBodHRwOi8vcGF1bGlyaXNoLmNvbS8yMDExL3JlcXVlc3RhbmltYXRpb25mcmFtZS1mb3Itc21hcnQtYW5pbWF0aW5nL1xyXG5cclxuZnVuY3Rpb24gZ2V0UHJlZml4ZWQobmFtZSkge1xyXG5cdHJldHVybiB3aW5kb3dbJ3dlYmtpdCcgKyBuYW1lXSB8fCB3aW5kb3dbJ21veicgKyBuYW1lXSB8fCB3aW5kb3dbJ21zJyArIG5hbWVdO1xyXG59XHJcblxyXG52YXIgbGFzdFRpbWUgPSAwO1xyXG5cclxuLy8gZmFsbGJhY2sgZm9yIElFIDctOFxyXG5mdW5jdGlvbiB0aW1lb3V0RGVmZXIoZm4pIHtcclxuXHR2YXIgdGltZSA9ICtuZXcgRGF0ZSgpLFxyXG5cdCAgICB0aW1lVG9DYWxsID0gTWF0aC5tYXgoMCwgMTYgLSAodGltZSAtIGxhc3RUaW1lKSk7XHJcblxyXG5cdGxhc3RUaW1lID0gdGltZSArIHRpbWVUb0NhbGw7XHJcblx0cmV0dXJuIHdpbmRvdy5zZXRUaW1lb3V0KGZuLCB0aW1lVG9DYWxsKTtcclxufVxyXG5cclxudmFyIHJlcXVlc3RGbiA9IHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHwgZ2V0UHJlZml4ZWQoJ1JlcXVlc3RBbmltYXRpb25GcmFtZScpIHx8IHRpbWVvdXREZWZlcjtcclxudmFyIGNhbmNlbEZuID0gd2luZG93LmNhbmNlbEFuaW1hdGlvbkZyYW1lIHx8IGdldFByZWZpeGVkKCdDYW5jZWxBbmltYXRpb25GcmFtZScpIHx8XHJcblx0XHRnZXRQcmVmaXhlZCgnQ2FuY2VsUmVxdWVzdEFuaW1hdGlvbkZyYW1lJykgfHwgZnVuY3Rpb24gKGlkKSB7IHdpbmRvdy5jbGVhclRpbWVvdXQoaWQpOyB9O1xyXG5cclxuLy8gQGZ1bmN0aW9uIHJlcXVlc3RBbmltRnJhbWUoZm46IEZ1bmN0aW9uLCBjb250ZXh0PzogT2JqZWN0LCBpbW1lZGlhdGU/OiBCb29sZWFuKTogTnVtYmVyXHJcbi8vIFNjaGVkdWxlcyBgZm5gIHRvIGJlIGV4ZWN1dGVkIHdoZW4gdGhlIGJyb3dzZXIgcmVwYWludHMuIGBmbmAgaXMgYm91bmQgdG9cclxuLy8gYGNvbnRleHRgIGlmIGdpdmVuLiBXaGVuIGBpbW1lZGlhdGVgIGlzIHNldCwgYGZuYCBpcyBjYWxsZWQgaW1tZWRpYXRlbHkgaWZcclxuLy8gdGhlIGJyb3dzZXIgZG9lc24ndCBoYXZlIG5hdGl2ZSBzdXBwb3J0IGZvclxyXG4vLyBbYHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWVgXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9BUEkvd2luZG93L3JlcXVlc3RBbmltYXRpb25GcmFtZSksXHJcbi8vIG90aGVyd2lzZSBpdCdzIGRlbGF5ZWQuIFJldHVybnMgYSByZXF1ZXN0IElEIHRoYXQgY2FuIGJlIHVzZWQgdG8gY2FuY2VsIHRoZSByZXF1ZXN0LlxyXG5mdW5jdGlvbiByZXF1ZXN0QW5pbUZyYW1lKGZuLCBjb250ZXh0LCBpbW1lZGlhdGUpIHtcclxuXHRpZiAoaW1tZWRpYXRlICYmIHJlcXVlc3RGbiA9PT0gdGltZW91dERlZmVyKSB7XHJcblx0XHRmbi5jYWxsKGNvbnRleHQpO1xyXG5cdH0gZWxzZSB7XHJcblx0XHRyZXR1cm4gcmVxdWVzdEZuLmNhbGwod2luZG93LCBiaW5kKGZuLCBjb250ZXh0KSk7XHJcblx0fVxyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gY2FuY2VsQW5pbUZyYW1lKGlkOiBOdW1iZXIpOiB1bmRlZmluZWRcclxuLy8gQ2FuY2VscyBhIHByZXZpb3VzIGByZXF1ZXN0QW5pbUZyYW1lYC4gU2VlIGFsc28gW3dpbmRvdy5jYW5jZWxBbmltYXRpb25GcmFtZV0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvQVBJL3dpbmRvdy9jYW5jZWxBbmltYXRpb25GcmFtZSkuXHJcbmZ1bmN0aW9uIGNhbmNlbEFuaW1GcmFtZShpZCkge1xyXG5cdGlmIChpZCkge1xyXG5cdFx0Y2FuY2VsRm4uY2FsbCh3aW5kb3csIGlkKTtcclxuXHR9XHJcbn1cclxuXG5cbnZhciBVdGlsID0gKE9iamVjdC5mcmVlemUgfHwgT2JqZWN0KSh7XG5cdGZyZWV6ZTogZnJlZXplLFxuXHRleHRlbmQ6IGV4dGVuZCxcblx0Y3JlYXRlOiBjcmVhdGUsXG5cdGJpbmQ6IGJpbmQsXG5cdGxhc3RJZDogbGFzdElkLFxuXHRzdGFtcDogc3RhbXAsXG5cdHRocm90dGxlOiB0aHJvdHRsZSxcblx0d3JhcE51bTogd3JhcE51bSxcblx0ZmFsc2VGbjogZmFsc2VGbixcblx0Zm9ybWF0TnVtOiBmb3JtYXROdW0sXG5cdHRyaW06IHRyaW0sXG5cdHNwbGl0V29yZHM6IHNwbGl0V29yZHMsXG5cdHNldE9wdGlvbnM6IHNldE9wdGlvbnMsXG5cdGdldFBhcmFtU3RyaW5nOiBnZXRQYXJhbVN0cmluZyxcblx0dGVtcGxhdGU6IHRlbXBsYXRlLFxuXHRpc0FycmF5OiBpc0FycmF5LFxuXHRpbmRleE9mOiBpbmRleE9mLFxuXHRlbXB0eUltYWdlVXJsOiBlbXB0eUltYWdlVXJsLFxuXHRyZXF1ZXN0Rm46IHJlcXVlc3RGbixcblx0Y2FuY2VsRm46IGNhbmNlbEZuLFxuXHRyZXF1ZXN0QW5pbUZyYW1lOiByZXF1ZXN0QW5pbUZyYW1lLFxuXHRjYW5jZWxBbmltRnJhbWU6IGNhbmNlbEFuaW1GcmFtZVxufSk7XG5cbi8vIEBjbGFzcyBDbGFzc1xyXG4vLyBAYWthIEwuQ2xhc3NcclxuXHJcbi8vIEBzZWN0aW9uXHJcbi8vIEB1bmluaGVyaXRhYmxlXHJcblxyXG4vLyBUaGFua3MgdG8gSm9obiBSZXNpZyBhbmQgRGVhbiBFZHdhcmRzIGZvciBpbnNwaXJhdGlvbiFcclxuXHJcbmZ1bmN0aW9uIENsYXNzKCkge31cclxuXHJcbkNsYXNzLmV4dGVuZCA9IGZ1bmN0aW9uIChwcm9wcykge1xyXG5cclxuXHQvLyBAZnVuY3Rpb24gZXh0ZW5kKHByb3BzOiBPYmplY3QpOiBGdW5jdGlvblxyXG5cdC8vIFtFeHRlbmRzIHRoZSBjdXJyZW50IGNsYXNzXSgjY2xhc3MtaW5oZXJpdGFuY2UpIGdpdmVuIHRoZSBwcm9wZXJ0aWVzIHRvIGJlIGluY2x1ZGVkLlxyXG5cdC8vIFJldHVybnMgYSBKYXZhc2NyaXB0IGZ1bmN0aW9uIHRoYXQgaXMgYSBjbGFzcyBjb25zdHJ1Y3RvciAodG8gYmUgY2FsbGVkIHdpdGggYG5ld2ApLlxyXG5cdHZhciBOZXdDbGFzcyA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHQvLyBjYWxsIHRoZSBjb25zdHJ1Y3RvclxyXG5cdFx0aWYgKHRoaXMuaW5pdGlhbGl6ZSkge1xyXG5cdFx0XHR0aGlzLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBjYWxsIGFsbCBjb25zdHJ1Y3RvciBob29rc1xyXG5cdFx0dGhpcy5jYWxsSW5pdEhvb2tzKCk7XHJcblx0fTtcclxuXHJcblx0dmFyIHBhcmVudFByb3RvID0gTmV3Q2xhc3MuX19zdXBlcl9fID0gdGhpcy5wcm90b3R5cGU7XHJcblxyXG5cdHZhciBwcm90byA9IGNyZWF0ZShwYXJlbnRQcm90byk7XHJcblx0cHJvdG8uY29uc3RydWN0b3IgPSBOZXdDbGFzcztcclxuXHJcblx0TmV3Q2xhc3MucHJvdG90eXBlID0gcHJvdG87XHJcblxyXG5cdC8vIGluaGVyaXQgcGFyZW50J3Mgc3RhdGljc1xyXG5cdGZvciAodmFyIGkgaW4gdGhpcykge1xyXG5cdFx0aWYgKHRoaXMuaGFzT3duUHJvcGVydHkoaSkgJiYgaSAhPT0gJ3Byb3RvdHlwZScgJiYgaSAhPT0gJ19fc3VwZXJfXycpIHtcclxuXHRcdFx0TmV3Q2xhc3NbaV0gPSB0aGlzW2ldO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0Ly8gbWl4IHN0YXRpYyBwcm9wZXJ0aWVzIGludG8gdGhlIGNsYXNzXHJcblx0aWYgKHByb3BzLnN0YXRpY3MpIHtcclxuXHRcdGV4dGVuZChOZXdDbGFzcywgcHJvcHMuc3RhdGljcyk7XHJcblx0XHRkZWxldGUgcHJvcHMuc3RhdGljcztcclxuXHR9XHJcblxyXG5cdC8vIG1peCBpbmNsdWRlcyBpbnRvIHRoZSBwcm90b3R5cGVcclxuXHRpZiAocHJvcHMuaW5jbHVkZXMpIHtcclxuXHRcdGNoZWNrRGVwcmVjYXRlZE1peGluRXZlbnRzKHByb3BzLmluY2x1ZGVzKTtcclxuXHRcdGV4dGVuZC5hcHBseShudWxsLCBbcHJvdG9dLmNvbmNhdChwcm9wcy5pbmNsdWRlcykpO1xyXG5cdFx0ZGVsZXRlIHByb3BzLmluY2x1ZGVzO1xyXG5cdH1cclxuXHJcblx0Ly8gbWVyZ2Ugb3B0aW9uc1xyXG5cdGlmIChwcm90by5vcHRpb25zKSB7XHJcblx0XHRwcm9wcy5vcHRpb25zID0gZXh0ZW5kKGNyZWF0ZShwcm90by5vcHRpb25zKSwgcHJvcHMub3B0aW9ucyk7XHJcblx0fVxyXG5cclxuXHQvLyBtaXggZ2l2ZW4gcHJvcGVydGllcyBpbnRvIHRoZSBwcm90b3R5cGVcclxuXHRleHRlbmQocHJvdG8sIHByb3BzKTtcclxuXHJcblx0cHJvdG8uX2luaXRIb29rcyA9IFtdO1xyXG5cclxuXHQvLyBhZGQgbWV0aG9kIGZvciBjYWxsaW5nIGFsbCBob29rc1xyXG5cdHByb3RvLmNhbGxJbml0SG9va3MgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0aWYgKHRoaXMuX2luaXRIb29rc0NhbGxlZCkgeyByZXR1cm47IH1cclxuXHJcblx0XHRpZiAocGFyZW50UHJvdG8uY2FsbEluaXRIb29rcykge1xyXG5cdFx0XHRwYXJlbnRQcm90by5jYWxsSW5pdEhvb2tzLmNhbGwodGhpcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5faW5pdEhvb2tzQ2FsbGVkID0gdHJ1ZTtcclxuXHJcblx0XHRmb3IgKHZhciBpID0gMCwgbGVuID0gcHJvdG8uX2luaXRIb29rcy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG5cdFx0XHRwcm90by5faW5pdEhvb2tzW2ldLmNhbGwodGhpcyk7XHJcblx0XHR9XHJcblx0fTtcclxuXHJcblx0cmV0dXJuIE5ld0NsYXNzO1xyXG59O1xyXG5cclxuXHJcbi8vIEBmdW5jdGlvbiBpbmNsdWRlKHByb3BlcnRpZXM6IE9iamVjdCk6IHRoaXNcclxuLy8gW0luY2x1ZGVzIGEgbWl4aW5dKCNjbGFzcy1pbmNsdWRlcykgaW50byB0aGUgY3VycmVudCBjbGFzcy5cclxuQ2xhc3MuaW5jbHVkZSA9IGZ1bmN0aW9uIChwcm9wcykge1xyXG5cdGV4dGVuZCh0aGlzLnByb3RvdHlwZSwgcHJvcHMpO1xyXG5cdHJldHVybiB0aGlzO1xyXG59O1xyXG5cclxuLy8gQGZ1bmN0aW9uIG1lcmdlT3B0aW9ucyhvcHRpb25zOiBPYmplY3QpOiB0aGlzXHJcbi8vIFtNZXJnZXMgYG9wdGlvbnNgXSgjY2xhc3Mtb3B0aW9ucykgaW50byB0aGUgZGVmYXVsdHMgb2YgdGhlIGNsYXNzLlxyXG5DbGFzcy5tZXJnZU9wdGlvbnMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xyXG5cdGV4dGVuZCh0aGlzLnByb3RvdHlwZS5vcHRpb25zLCBvcHRpb25zKTtcclxuXHRyZXR1cm4gdGhpcztcclxufTtcclxuXHJcbi8vIEBmdW5jdGlvbiBhZGRJbml0SG9vayhmbjogRnVuY3Rpb24pOiB0aGlzXHJcbi8vIEFkZHMgYSBbY29uc3RydWN0b3IgaG9va10oI2NsYXNzLWNvbnN0cnVjdG9yLWhvb2tzKSB0byB0aGUgY2xhc3MuXHJcbkNsYXNzLmFkZEluaXRIb29rID0gZnVuY3Rpb24gKGZuKSB7IC8vIChGdW5jdGlvbikgfHwgKFN0cmluZywgYXJncy4uLilcclxuXHR2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XHJcblxyXG5cdHZhciBpbml0ID0gdHlwZW9mIGZuID09PSAnZnVuY3Rpb24nID8gZm4gOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR0aGlzW2ZuXS5hcHBseSh0aGlzLCBhcmdzKTtcclxuXHR9O1xyXG5cclxuXHR0aGlzLnByb3RvdHlwZS5faW5pdEhvb2tzID0gdGhpcy5wcm90b3R5cGUuX2luaXRIb29rcyB8fCBbXTtcclxuXHR0aGlzLnByb3RvdHlwZS5faW5pdEhvb2tzLnB1c2goaW5pdCk7XHJcblx0cmV0dXJuIHRoaXM7XHJcbn07XHJcblxyXG5mdW5jdGlvbiBjaGVja0RlcHJlY2F0ZWRNaXhpbkV2ZW50cyhpbmNsdWRlcykge1xyXG5cdGlmICh0eXBlb2YgTCA9PT0gJ3VuZGVmaW5lZCcgfHwgIUwgfHwgIUwuTWl4aW4pIHsgcmV0dXJuOyB9XHJcblxyXG5cdGluY2x1ZGVzID0gaXNBcnJheShpbmNsdWRlcykgPyBpbmNsdWRlcyA6IFtpbmNsdWRlc107XHJcblxyXG5cdGZvciAodmFyIGkgPSAwOyBpIDwgaW5jbHVkZXMubGVuZ3RoOyBpKyspIHtcclxuXHRcdGlmIChpbmNsdWRlc1tpXSA9PT0gTC5NaXhpbi5FdmVudHMpIHtcclxuXHRcdFx0Y29uc29sZS53YXJuKCdEZXByZWNhdGVkIGluY2x1ZGUgb2YgTC5NaXhpbi5FdmVudHM6ICcgK1xyXG5cdFx0XHRcdCd0aGlzIHByb3BlcnR5IHdpbGwgYmUgcmVtb3ZlZCBpbiBmdXR1cmUgcmVsZWFzZXMsICcgK1xyXG5cdFx0XHRcdCdwbGVhc2UgaW5oZXJpdCBmcm9tIEwuRXZlbnRlZCBpbnN0ZWFkLicsIG5ldyBFcnJvcigpLnN0YWNrKTtcclxuXHRcdH1cclxuXHR9XHJcbn1cblxuLypcclxuICogQGNsYXNzIEV2ZW50ZWRcclxuICogQGFrYSBMLkV2ZW50ZWRcclxuICogQGluaGVyaXRzIENsYXNzXHJcbiAqXHJcbiAqIEEgc2V0IG9mIG1ldGhvZHMgc2hhcmVkIGJldHdlZW4gZXZlbnQtcG93ZXJlZCBjbGFzc2VzIChsaWtlIGBNYXBgIGFuZCBgTWFya2VyYCkuIEdlbmVyYWxseSwgZXZlbnRzIGFsbG93IHlvdSB0byBleGVjdXRlIHNvbWUgZnVuY3Rpb24gd2hlbiBzb21ldGhpbmcgaGFwcGVucyB3aXRoIGFuIG9iamVjdCAoZS5nLiB0aGUgdXNlciBjbGlja3Mgb24gdGhlIG1hcCwgY2F1c2luZyB0aGUgbWFwIHRvIGZpcmUgYCdjbGljaydgIGV2ZW50KS5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogYGBganNcclxuICogbWFwLm9uKCdjbGljaycsIGZ1bmN0aW9uKGUpIHtcclxuICogXHRhbGVydChlLmxhdGxuZyk7XHJcbiAqIH0gKTtcclxuICogYGBgXHJcbiAqXHJcbiAqIExlYWZsZXQgZGVhbHMgd2l0aCBldmVudCBsaXN0ZW5lcnMgYnkgcmVmZXJlbmNlLCBzbyBpZiB5b3Ugd2FudCB0byBhZGQgYSBsaXN0ZW5lciBhbmQgdGhlbiByZW1vdmUgaXQsIGRlZmluZSBpdCBhcyBhIGZ1bmN0aW9uOlxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiBmdW5jdGlvbiBvbkNsaWNrKGUpIHsgLi4uIH1cclxuICpcclxuICogbWFwLm9uKCdjbGljaycsIG9uQ2xpY2spO1xyXG4gKiBtYXAub2ZmKCdjbGljaycsIG9uQ2xpY2spO1xyXG4gKiBgYGBcclxuICovXHJcblxyXG52YXIgRXZlbnRzID0ge1xyXG5cdC8qIEBtZXRob2Qgb24odHlwZTogU3RyaW5nLCBmbjogRnVuY3Rpb24sIGNvbnRleHQ/OiBPYmplY3QpOiB0aGlzXHJcblx0ICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIChgZm5gKSB0byBhIHBhcnRpY3VsYXIgZXZlbnQgdHlwZSBvZiB0aGUgb2JqZWN0LiBZb3UgY2FuIG9wdGlvbmFsbHkgc3BlY2lmeSB0aGUgY29udGV4dCBvZiB0aGUgbGlzdGVuZXIgKG9iamVjdCB0aGUgdGhpcyBrZXl3b3JkIHdpbGwgcG9pbnQgdG8pLiBZb3UgY2FuIGFsc28gcGFzcyBzZXZlcmFsIHNwYWNlLXNlcGFyYXRlZCB0eXBlcyAoZS5nLiBgJ2NsaWNrIGRibGNsaWNrJ2ApLlxyXG5cdCAqXHJcblx0ICogQGFsdGVybmF0aXZlXHJcblx0ICogQG1ldGhvZCBvbihldmVudE1hcDogT2JqZWN0KTogdGhpc1xyXG5cdCAqIEFkZHMgYSBzZXQgb2YgdHlwZS9saXN0ZW5lciBwYWlycywgZS5nLiBge2NsaWNrOiBvbkNsaWNrLCBtb3VzZW1vdmU6IG9uTW91c2VNb3ZlfWBcclxuXHQgKi9cclxuXHRvbjogZnVuY3Rpb24gKHR5cGVzLCBmbiwgY29udGV4dCkge1xyXG5cclxuXHRcdC8vIHR5cGVzIGNhbiBiZSBhIG1hcCBvZiB0eXBlcy9oYW5kbGVyc1xyXG5cdFx0aWYgKHR5cGVvZiB0eXBlcyA9PT0gJ29iamVjdCcpIHtcclxuXHRcdFx0Zm9yICh2YXIgdHlwZSBpbiB0eXBlcykge1xyXG5cdFx0XHRcdC8vIHdlIGRvbid0IHByb2Nlc3Mgc3BhY2Utc2VwYXJhdGVkIGV2ZW50cyBoZXJlIGZvciBwZXJmb3JtYW5jZTtcclxuXHRcdFx0XHQvLyBpdCdzIGEgaG90IHBhdGggc2luY2UgTGF5ZXIgdXNlcyB0aGUgb24ob2JqKSBzeW50YXhcclxuXHRcdFx0XHR0aGlzLl9vbih0eXBlLCB0eXBlc1t0eXBlXSwgZm4pO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0Ly8gdHlwZXMgY2FuIGJlIGEgc3RyaW5nIG9mIHNwYWNlLXNlcGFyYXRlZCB3b3Jkc1xyXG5cdFx0XHR0eXBlcyA9IHNwbGl0V29yZHModHlwZXMpO1xyXG5cclxuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IHR5cGVzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdFx0dGhpcy5fb24odHlwZXNbaV0sIGZuLCBjb250ZXh0KTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8qIEBtZXRob2Qgb2ZmKHR5cGU6IFN0cmluZywgZm4/OiBGdW5jdGlvbiwgY29udGV4dD86IE9iamVjdCk6IHRoaXNcclxuXHQgKiBSZW1vdmVzIGEgcHJldmlvdXNseSBhZGRlZCBsaXN0ZW5lciBmdW5jdGlvbi4gSWYgbm8gZnVuY3Rpb24gaXMgc3BlY2lmaWVkLCBpdCB3aWxsIHJlbW92ZSBhbGwgdGhlIGxpc3RlbmVycyBvZiB0aGF0IHBhcnRpY3VsYXIgZXZlbnQgZnJvbSB0aGUgb2JqZWN0LiBOb3RlIHRoYXQgaWYgeW91IHBhc3NlZCBhIGN1c3RvbSBjb250ZXh0IHRvIGBvbmAsIHlvdSBtdXN0IHBhc3MgdGhlIHNhbWUgY29udGV4dCB0byBgb2ZmYCBpbiBvcmRlciB0byByZW1vdmUgdGhlIGxpc3RlbmVyLlxyXG5cdCAqXHJcblx0ICogQGFsdGVybmF0aXZlXHJcblx0ICogQG1ldGhvZCBvZmYoZXZlbnRNYXA6IE9iamVjdCk6IHRoaXNcclxuXHQgKiBSZW1vdmVzIGEgc2V0IG9mIHR5cGUvbGlzdGVuZXIgcGFpcnMuXHJcblx0ICpcclxuXHQgKiBAYWx0ZXJuYXRpdmVcclxuXHQgKiBAbWV0aG9kIG9mZjogdGhpc1xyXG5cdCAqIFJlbW92ZXMgYWxsIGxpc3RlbmVycyB0byBhbGwgZXZlbnRzIG9uIHRoZSBvYmplY3QuXHJcblx0ICovXHJcblx0b2ZmOiBmdW5jdGlvbiAodHlwZXMsIGZuLCBjb250ZXh0KSB7XHJcblxyXG5cdFx0aWYgKCF0eXBlcykge1xyXG5cdFx0XHQvLyBjbGVhciBhbGwgbGlzdGVuZXJzIGlmIGNhbGxlZCB3aXRob3V0IGFyZ3VtZW50c1xyXG5cdFx0XHRkZWxldGUgdGhpcy5fZXZlbnRzO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAodHlwZW9mIHR5cGVzID09PSAnb2JqZWN0Jykge1xyXG5cdFx0XHRmb3IgKHZhciB0eXBlIGluIHR5cGVzKSB7XHJcblx0XHRcdFx0dGhpcy5fb2ZmKHR5cGUsIHR5cGVzW3R5cGVdLCBmbik7XHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR0eXBlcyA9IHNwbGl0V29yZHModHlwZXMpO1xyXG5cclxuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IHR5cGVzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdFx0dGhpcy5fb2ZmKHR5cGVzW2ldLCBmbiwgY29udGV4dCk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBhdHRhY2ggbGlzdGVuZXIgKHdpdGhvdXQgc3ludGFjdGljIHN1Z2FyIG5vdylcclxuXHRfb246IGZ1bmN0aW9uICh0eXBlLCBmbiwgY29udGV4dCkge1xyXG5cdFx0dGhpcy5fZXZlbnRzID0gdGhpcy5fZXZlbnRzIHx8IHt9O1xyXG5cclxuXHRcdC8qIGdldC9pbml0IGxpc3RlbmVycyBmb3IgdHlwZSAqL1xyXG5cdFx0dmFyIHR5cGVMaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHNbdHlwZV07XHJcblx0XHRpZiAoIXR5cGVMaXN0ZW5lcnMpIHtcclxuXHRcdFx0dHlwZUxpc3RlbmVycyA9IFtdO1xyXG5cdFx0XHR0aGlzLl9ldmVudHNbdHlwZV0gPSB0eXBlTGlzdGVuZXJzO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChjb250ZXh0ID09PSB0aGlzKSB7XHJcblx0XHRcdC8vIExlc3MgbWVtb3J5IGZvb3RwcmludC5cclxuXHRcdFx0Y29udGV4dCA9IHVuZGVmaW5lZDtcclxuXHRcdH1cclxuXHRcdHZhciBuZXdMaXN0ZW5lciA9IHtmbjogZm4sIGN0eDogY29udGV4dH0sXHJcblx0XHQgICAgbGlzdGVuZXJzID0gdHlwZUxpc3RlbmVycztcclxuXHJcblx0XHQvLyBjaGVjayBpZiBmbiBhbHJlYWR5IHRoZXJlXHJcblx0XHRmb3IgKHZhciBpID0gMCwgbGVuID0gbGlzdGVuZXJzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdGlmIChsaXN0ZW5lcnNbaV0uZm4gPT09IGZuICYmIGxpc3RlbmVyc1tpXS5jdHggPT09IGNvbnRleHQpIHtcclxuXHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRsaXN0ZW5lcnMucHVzaChuZXdMaXN0ZW5lcik7XHJcblx0fSxcclxuXHJcblx0X29mZjogZnVuY3Rpb24gKHR5cGUsIGZuLCBjb250ZXh0KSB7XHJcblx0XHR2YXIgbGlzdGVuZXJzLFxyXG5cdFx0ICAgIGksXHJcblx0XHQgICAgbGVuO1xyXG5cclxuXHRcdGlmICghdGhpcy5fZXZlbnRzKSB7IHJldHVybjsgfVxyXG5cclxuXHRcdGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcclxuXHJcblx0XHRpZiAoIWxpc3RlbmVycykge1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCFmbikge1xyXG5cdFx0XHQvLyBTZXQgYWxsIHJlbW92ZWQgbGlzdGVuZXJzIHRvIG5vb3Agc28gdGhleSBhcmUgbm90IGNhbGxlZCBpZiByZW1vdmUgaGFwcGVucyBpbiBmaXJlXHJcblx0XHRcdGZvciAoaSA9IDAsIGxlbiA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG5cdFx0XHRcdGxpc3RlbmVyc1tpXS5mbiA9IGZhbHNlRm47XHJcblx0XHRcdH1cclxuXHRcdFx0Ly8gY2xlYXIgYWxsIGxpc3RlbmVycyBmb3IgYSB0eXBlIGlmIGZ1bmN0aW9uIGlzbid0IHNwZWNpZmllZFxyXG5cdFx0XHRkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKGNvbnRleHQgPT09IHRoaXMpIHtcclxuXHRcdFx0Y29udGV4dCA9IHVuZGVmaW5lZDtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAobGlzdGVuZXJzKSB7XHJcblxyXG5cdFx0XHQvLyBmaW5kIGZuIGFuZCByZW1vdmUgaXRcclxuXHRcdFx0Zm9yIChpID0gMCwgbGVuID0gbGlzdGVuZXJzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdFx0dmFyIGwgPSBsaXN0ZW5lcnNbaV07XHJcblx0XHRcdFx0aWYgKGwuY3R4ICE9PSBjb250ZXh0KSB7IGNvbnRpbnVlOyB9XHJcblx0XHRcdFx0aWYgKGwuZm4gPT09IGZuKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gc2V0IHRoZSByZW1vdmVkIGxpc3RlbmVyIHRvIG5vb3Agc28gdGhhdCdzIG5vdCBjYWxsZWQgaWYgcmVtb3ZlIGhhcHBlbnMgaW4gZmlyZVxyXG5cdFx0XHRcdFx0bC5mbiA9IGZhbHNlRm47XHJcblxyXG5cdFx0XHRcdFx0aWYgKHRoaXMuX2ZpcmluZ0NvdW50KSB7XHJcblx0XHRcdFx0XHRcdC8qIGNvcHkgYXJyYXkgaW4gY2FzZSBldmVudHMgYXJlIGJlaW5nIGZpcmVkICovXHJcblx0XHRcdFx0XHRcdHRoaXMuX2V2ZW50c1t0eXBlXSA9IGxpc3RlbmVycyA9IGxpc3RlbmVycy5zbGljZSgpO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0bGlzdGVuZXJzLnNwbGljZShpLCAxKTtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBmaXJlKHR5cGU6IFN0cmluZywgZGF0YT86IE9iamVjdCwgcHJvcGFnYXRlPzogQm9vbGVhbik6IHRoaXNcclxuXHQvLyBGaXJlcyBhbiBldmVudCBvZiB0aGUgc3BlY2lmaWVkIHR5cGUuIFlvdSBjYW4gb3B0aW9uYWxseSBwcm92aWRlIGFuIGRhdGFcclxuXHQvLyBvYmplY3Qg4oCUIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgbGlzdGVuZXIgZnVuY3Rpb24gd2lsbCBjb250YWluIGl0c1xyXG5cdC8vIHByb3BlcnRpZXMuIFRoZSBldmVudCBjYW4gb3B0aW9uYWxseSBiZSBwcm9wYWdhdGVkIHRvIGV2ZW50IHBhcmVudHMuXHJcblx0ZmlyZTogZnVuY3Rpb24gKHR5cGUsIGRhdGEsIHByb3BhZ2F0ZSkge1xyXG5cdFx0aWYgKCF0aGlzLmxpc3RlbnModHlwZSwgcHJvcGFnYXRlKSkgeyByZXR1cm4gdGhpczsgfVxyXG5cclxuXHRcdHZhciBldmVudCA9IGV4dGVuZCh7fSwgZGF0YSwge1xyXG5cdFx0XHR0eXBlOiB0eXBlLFxyXG5cdFx0XHR0YXJnZXQ6IHRoaXMsXHJcblx0XHRcdHNvdXJjZVRhcmdldDogZGF0YSAmJiBkYXRhLnNvdXJjZVRhcmdldCB8fCB0aGlzXHJcblx0XHR9KTtcclxuXHJcblx0XHRpZiAodGhpcy5fZXZlbnRzKSB7XHJcblx0XHRcdHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHNbdHlwZV07XHJcblxyXG5cdFx0XHRpZiAobGlzdGVuZXJzKSB7XHJcblx0XHRcdFx0dGhpcy5fZmlyaW5nQ291bnQgPSAodGhpcy5fZmlyaW5nQ291bnQgKyAxKSB8fCAxO1xyXG5cdFx0XHRcdGZvciAodmFyIGkgPSAwLCBsZW4gPSBsaXN0ZW5lcnMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdFx0XHRcdHZhciBsID0gbGlzdGVuZXJzW2ldO1xyXG5cdFx0XHRcdFx0bC5mbi5jYWxsKGwuY3R4IHx8IHRoaXMsIGV2ZW50KTtcclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHRoaXMuX2ZpcmluZ0NvdW50LS07XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRpZiAocHJvcGFnYXRlKSB7XHJcblx0XHRcdC8vIHByb3BhZ2F0ZSB0aGUgZXZlbnQgdG8gcGFyZW50cyAoc2V0IHdpdGggYWRkRXZlbnRQYXJlbnQpXHJcblx0XHRcdHRoaXMuX3Byb3BhZ2F0ZUV2ZW50KGV2ZW50KTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGxpc3RlbnModHlwZTogU3RyaW5nKTogQm9vbGVhblxyXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIGEgcGFydGljdWxhciBldmVudCB0eXBlIGhhcyBhbnkgbGlzdGVuZXJzIGF0dGFjaGVkIHRvIGl0LlxyXG5cdGxpc3RlbnM6IGZ1bmN0aW9uICh0eXBlLCBwcm9wYWdhdGUpIHtcclxuXHRcdHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHMgJiYgdGhpcy5fZXZlbnRzW3R5cGVdO1xyXG5cdFx0aWYgKGxpc3RlbmVycyAmJiBsaXN0ZW5lcnMubGVuZ3RoKSB7IHJldHVybiB0cnVlOyB9XHJcblxyXG5cdFx0aWYgKHByb3BhZ2F0ZSkge1xyXG5cdFx0XHQvLyBhbHNvIGNoZWNrIHBhcmVudHMgZm9yIGxpc3RlbmVycyBpZiBldmVudCBwcm9wYWdhdGVzXHJcblx0XHRcdGZvciAodmFyIGlkIGluIHRoaXMuX2V2ZW50UGFyZW50cykge1xyXG5cdFx0XHRcdGlmICh0aGlzLl9ldmVudFBhcmVudHNbaWRdLmxpc3RlbnModHlwZSwgcHJvcGFnYXRlKSkgeyByZXR1cm4gdHJ1ZTsgfVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gZmFsc2U7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBvbmNlKOKApik6IHRoaXNcclxuXHQvLyBCZWhhdmVzIGFzIFtgb24o4oCmKWBdKCNldmVudGVkLW9uKSwgZXhjZXB0IHRoZSBsaXN0ZW5lciB3aWxsIG9ubHkgZ2V0IGZpcmVkIG9uY2UgYW5kIHRoZW4gcmVtb3ZlZC5cclxuXHRvbmNlOiBmdW5jdGlvbiAodHlwZXMsIGZuLCBjb250ZXh0KSB7XHJcblxyXG5cdFx0aWYgKHR5cGVvZiB0eXBlcyA9PT0gJ29iamVjdCcpIHtcclxuXHRcdFx0Zm9yICh2YXIgdHlwZSBpbiB0eXBlcykge1xyXG5cdFx0XHRcdHRoaXMub25jZSh0eXBlLCB0eXBlc1t0eXBlXSwgZm4pO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBoYW5kbGVyID0gYmluZChmdW5jdGlvbiAoKSB7XHJcblx0XHRcdHRoaXNcclxuXHRcdFx0ICAgIC5vZmYodHlwZXMsIGZuLCBjb250ZXh0KVxyXG5cdFx0XHQgICAgLm9mZih0eXBlcywgaGFuZGxlciwgY29udGV4dCk7XHJcblx0XHR9LCB0aGlzKTtcclxuXHJcblx0XHQvLyBhZGQgYSBsaXN0ZW5lciB0aGF0J3MgZXhlY3V0ZWQgb25jZSBhbmQgcmVtb3ZlZCBhZnRlciB0aGF0XHJcblx0XHRyZXR1cm4gdGhpc1xyXG5cdFx0ICAgIC5vbih0eXBlcywgZm4sIGNvbnRleHQpXHJcblx0XHQgICAgLm9uKHR5cGVzLCBoYW5kbGVyLCBjb250ZXh0KTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGFkZEV2ZW50UGFyZW50KG9iajogRXZlbnRlZCk6IHRoaXNcclxuXHQvLyBBZGRzIGFuIGV2ZW50IHBhcmVudCAtIGFuIGBFdmVudGVkYCB0aGF0IHdpbGwgcmVjZWl2ZSBwcm9wYWdhdGVkIGV2ZW50c1xyXG5cdGFkZEV2ZW50UGFyZW50OiBmdW5jdGlvbiAob2JqKSB7XHJcblx0XHR0aGlzLl9ldmVudFBhcmVudHMgPSB0aGlzLl9ldmVudFBhcmVudHMgfHwge307XHJcblx0XHR0aGlzLl9ldmVudFBhcmVudHNbc3RhbXAob2JqKV0gPSBvYmo7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHJlbW92ZUV2ZW50UGFyZW50KG9iajogRXZlbnRlZCk6IHRoaXNcclxuXHQvLyBSZW1vdmVzIGFuIGV2ZW50IHBhcmVudCwgc28gaXQgd2lsbCBzdG9wIHJlY2VpdmluZyBwcm9wYWdhdGVkIGV2ZW50c1xyXG5cdHJlbW92ZUV2ZW50UGFyZW50OiBmdW5jdGlvbiAob2JqKSB7XHJcblx0XHRpZiAodGhpcy5fZXZlbnRQYXJlbnRzKSB7XHJcblx0XHRcdGRlbGV0ZSB0aGlzLl9ldmVudFBhcmVudHNbc3RhbXAob2JqKV07XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfcHJvcGFnYXRlRXZlbnQ6IGZ1bmN0aW9uIChlKSB7XHJcblx0XHRmb3IgKHZhciBpZCBpbiB0aGlzLl9ldmVudFBhcmVudHMpIHtcclxuXHRcdFx0dGhpcy5fZXZlbnRQYXJlbnRzW2lkXS5maXJlKGUudHlwZSwgZXh0ZW5kKHtcclxuXHRcdFx0XHRsYXllcjogZS50YXJnZXQsXHJcblx0XHRcdFx0cHJvcGFnYXRlZEZyb206IGUudGFyZ2V0XHJcblx0XHRcdH0sIGUpLCB0cnVlKTtcclxuXHRcdH1cclxuXHR9XHJcbn07XHJcblxyXG4vLyBhbGlhc2VzOyB3ZSBzaG91bGQgZGl0Y2ggdGhvc2UgZXZlbnR1YWxseVxyXG5cclxuLy8gQG1ldGhvZCBhZGRFdmVudExpc3RlbmVyKOKApik6IHRoaXNcclxuLy8gQWxpYXMgdG8gW2BvbijigKYpYF0oI2V2ZW50ZWQtb24pXHJcbkV2ZW50cy5hZGRFdmVudExpc3RlbmVyID0gRXZlbnRzLm9uO1xyXG5cclxuLy8gQG1ldGhvZCByZW1vdmVFdmVudExpc3RlbmVyKOKApik6IHRoaXNcclxuLy8gQWxpYXMgdG8gW2BvZmYo4oCmKWBdKCNldmVudGVkLW9mZilcclxuXHJcbi8vIEBtZXRob2QgY2xlYXJBbGxFdmVudExpc3RlbmVycyjigKYpOiB0aGlzXHJcbi8vIEFsaWFzIHRvIFtgb2ZmKClgXSgjZXZlbnRlZC1vZmYpXHJcbkV2ZW50cy5yZW1vdmVFdmVudExpc3RlbmVyID0gRXZlbnRzLmNsZWFyQWxsRXZlbnRMaXN0ZW5lcnMgPSBFdmVudHMub2ZmO1xyXG5cclxuLy8gQG1ldGhvZCBhZGRPbmVUaW1lRXZlbnRMaXN0ZW5lcijigKYpOiB0aGlzXHJcbi8vIEFsaWFzIHRvIFtgb25jZSjigKYpYF0oI2V2ZW50ZWQtb25jZSlcclxuRXZlbnRzLmFkZE9uZVRpbWVFdmVudExpc3RlbmVyID0gRXZlbnRzLm9uY2U7XHJcblxyXG4vLyBAbWV0aG9kIGZpcmVFdmVudCjigKYpOiB0aGlzXHJcbi8vIEFsaWFzIHRvIFtgZmlyZSjigKYpYF0oI2V2ZW50ZWQtZmlyZSlcclxuRXZlbnRzLmZpcmVFdmVudCA9IEV2ZW50cy5maXJlO1xyXG5cclxuLy8gQG1ldGhvZCBoYXNFdmVudExpc3RlbmVycyjigKYpOiBCb29sZWFuXHJcbi8vIEFsaWFzIHRvIFtgbGlzdGVucyjigKYpYF0oI2V2ZW50ZWQtbGlzdGVucylcclxuRXZlbnRzLmhhc0V2ZW50TGlzdGVuZXJzID0gRXZlbnRzLmxpc3RlbnM7XHJcblxyXG52YXIgRXZlbnRlZCA9IENsYXNzLmV4dGVuZChFdmVudHMpO1xuXG4vKlxyXG4gKiBAY2xhc3MgUG9pbnRcclxuICogQGFrYSBMLlBvaW50XHJcbiAqXHJcbiAqIFJlcHJlc2VudHMgYSBwb2ludCB3aXRoIGB4YCBhbmQgYHlgIGNvb3JkaW5hdGVzIGluIHBpeGVscy5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogYGBganNcclxuICogdmFyIHBvaW50ID0gTC5wb2ludCgyMDAsIDMwMCk7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBBbGwgTGVhZmxldCBtZXRob2RzIGFuZCBvcHRpb25zIHRoYXQgYWNjZXB0IGBQb2ludGAgb2JqZWN0cyBhbHNvIGFjY2VwdCB0aGVtIGluIGEgc2ltcGxlIEFycmF5IGZvcm0gKHVubGVzcyBub3RlZCBvdGhlcndpc2UpLCBzbyB0aGVzZSBsaW5lcyBhcmUgZXF1aXZhbGVudDpcclxuICpcclxuICogYGBganNcclxuICogbWFwLnBhbkJ5KFsyMDAsIDMwMF0pO1xyXG4gKiBtYXAucGFuQnkoTC5wb2ludCgyMDAsIDMwMCkpO1xyXG4gKiBgYGBcclxuICpcclxuICogTm90ZSB0aGF0IGBQb2ludGAgZG9lcyBub3QgaW5oZXJpdCBmcm9tIExlYWZldCdzIGBDbGFzc2Agb2JqZWN0LFxyXG4gKiB3aGljaCBtZWFucyBuZXcgY2xhc3NlcyBjYW4ndCBpbmhlcml0IGZyb20gaXQsIGFuZCBuZXcgbWV0aG9kc1xyXG4gKiBjYW4ndCBiZSBhZGRlZCB0byBpdCB3aXRoIHRoZSBgaW5jbHVkZWAgZnVuY3Rpb24uXHJcbiAqL1xyXG5cclxuZnVuY3Rpb24gUG9pbnQoeCwgeSwgcm91bmQpIHtcclxuXHQvLyBAcHJvcGVydHkgeDogTnVtYmVyOyBUaGUgYHhgIGNvb3JkaW5hdGUgb2YgdGhlIHBvaW50XHJcblx0dGhpcy54ID0gKHJvdW5kID8gTWF0aC5yb3VuZCh4KSA6IHgpO1xyXG5cdC8vIEBwcm9wZXJ0eSB5OiBOdW1iZXI7IFRoZSBgeWAgY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnRcclxuXHR0aGlzLnkgPSAocm91bmQgPyBNYXRoLnJvdW5kKHkpIDogeSk7XHJcbn1cclxuXHJcbnZhciB0cnVuYyA9IE1hdGgudHJ1bmMgfHwgZnVuY3Rpb24gKHYpIHtcclxuXHRyZXR1cm4gdiA+IDAgPyBNYXRoLmZsb29yKHYpIDogTWF0aC5jZWlsKHYpO1xyXG59O1xyXG5cclxuUG9pbnQucHJvdG90eXBlID0ge1xyXG5cclxuXHQvLyBAbWV0aG9kIGNsb25lKCk6IFBvaW50XHJcblx0Ly8gUmV0dXJucyBhIGNvcHkgb2YgdGhlIGN1cnJlbnQgcG9pbnQuXHJcblx0Y2xvbmU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiBuZXcgUG9pbnQodGhpcy54LCB0aGlzLnkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgYWRkKG90aGVyUG9pbnQ6IFBvaW50KTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIHRoZSByZXN1bHQgb2YgYWRkaXRpb24gb2YgdGhlIGN1cnJlbnQgYW5kIHRoZSBnaXZlbiBwb2ludHMuXHJcblx0YWRkOiBmdW5jdGlvbiAocG9pbnQpIHtcclxuXHRcdC8vIG5vbi1kZXN0cnVjdGl2ZSwgcmV0dXJucyBhIG5ldyBwb2ludFxyXG5cdFx0cmV0dXJuIHRoaXMuY2xvbmUoKS5fYWRkKHRvUG9pbnQocG9pbnQpKTtcclxuXHR9LFxyXG5cclxuXHRfYWRkOiBmdW5jdGlvbiAocG9pbnQpIHtcclxuXHRcdC8vIGRlc3RydWN0aXZlLCB1c2VkIGRpcmVjdGx5IGZvciBwZXJmb3JtYW5jZSBpbiBzaXR1YXRpb25zIHdoZXJlIGl0J3Mgc2FmZSB0byBtb2RpZnkgZXhpc3RpbmcgcG9pbnRcclxuXHRcdHRoaXMueCArPSBwb2ludC54O1xyXG5cdFx0dGhpcy55ICs9IHBvaW50Lnk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHN1YnRyYWN0KG90aGVyUG9pbnQ6IFBvaW50KTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIHRoZSByZXN1bHQgb2Ygc3VidHJhY3Rpb24gb2YgdGhlIGdpdmVuIHBvaW50IGZyb20gdGhlIGN1cnJlbnQuXHJcblx0c3VidHJhY3Q6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuY2xvbmUoKS5fc3VidHJhY3QodG9Qb2ludChwb2ludCkpO1xyXG5cdH0sXHJcblxyXG5cdF9zdWJ0cmFjdDogZnVuY3Rpb24gKHBvaW50KSB7XHJcblx0XHR0aGlzLnggLT0gcG9pbnQueDtcclxuXHRcdHRoaXMueSAtPSBwb2ludC55O1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBkaXZpZGVCeShudW06IE51bWJlcik6IFBvaW50XHJcblx0Ly8gUmV0dXJucyB0aGUgcmVzdWx0IG9mIGRpdmlzaW9uIG9mIHRoZSBjdXJyZW50IHBvaW50IGJ5IHRoZSBnaXZlbiBudW1iZXIuXHJcblx0ZGl2aWRlQnk6IGZ1bmN0aW9uIChudW0pIHtcclxuXHRcdHJldHVybiB0aGlzLmNsb25lKCkuX2RpdmlkZUJ5KG51bSk7XHJcblx0fSxcclxuXHJcblx0X2RpdmlkZUJ5OiBmdW5jdGlvbiAobnVtKSB7XHJcblx0XHR0aGlzLnggLz0gbnVtO1xyXG5cdFx0dGhpcy55IC89IG51bTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgbXVsdGlwbHlCeShudW06IE51bWJlcik6IFBvaW50XHJcblx0Ly8gUmV0dXJucyB0aGUgcmVzdWx0IG9mIG11bHRpcGxpY2F0aW9uIG9mIHRoZSBjdXJyZW50IHBvaW50IGJ5IHRoZSBnaXZlbiBudW1iZXIuXHJcblx0bXVsdGlwbHlCeTogZnVuY3Rpb24gKG51bSkge1xyXG5cdFx0cmV0dXJuIHRoaXMuY2xvbmUoKS5fbXVsdGlwbHlCeShudW0pO1xyXG5cdH0sXHJcblxyXG5cdF9tdWx0aXBseUJ5OiBmdW5jdGlvbiAobnVtKSB7XHJcblx0XHR0aGlzLnggKj0gbnVtO1xyXG5cdFx0dGhpcy55ICo9IG51bTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2NhbGVCeShzY2FsZTogUG9pbnQpOiBQb2ludFxyXG5cdC8vIE11bHRpcGx5IGVhY2ggY29vcmRpbmF0ZSBvZiB0aGUgY3VycmVudCBwb2ludCBieSBlYWNoIGNvb3JkaW5hdGUgb2ZcclxuXHQvLyBgc2NhbGVgLiBJbiBsaW5lYXIgYWxnZWJyYSB0ZXJtcywgbXVsdGlwbHkgdGhlIHBvaW50IGJ5IHRoZVxyXG5cdC8vIFtzY2FsaW5nIG1hdHJpeF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU2NhbGluZ18lMjhnZW9tZXRyeSUyOSNNYXRyaXhfcmVwcmVzZW50YXRpb24pXHJcblx0Ly8gZGVmaW5lZCBieSBgc2NhbGVgLlxyXG5cdHNjYWxlQnk6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0cmV0dXJuIG5ldyBQb2ludCh0aGlzLnggKiBwb2ludC54LCB0aGlzLnkgKiBwb2ludC55KTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHVuc2NhbGVCeShzY2FsZTogUG9pbnQpOiBQb2ludFxyXG5cdC8vIEludmVyc2Ugb2YgYHNjYWxlQnlgLiBEaXZpZGUgZWFjaCBjb29yZGluYXRlIG9mIHRoZSBjdXJyZW50IHBvaW50IGJ5XHJcblx0Ly8gZWFjaCBjb29yZGluYXRlIG9mIGBzY2FsZWAuXHJcblx0dW5zY2FsZUJ5OiBmdW5jdGlvbiAocG9pbnQpIHtcclxuXHRcdHJldHVybiBuZXcgUG9pbnQodGhpcy54IC8gcG9pbnQueCwgdGhpcy55IC8gcG9pbnQueSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCByb3VuZCgpOiBQb2ludFxyXG5cdC8vIFJldHVybnMgYSBjb3B5IG9mIHRoZSBjdXJyZW50IHBvaW50IHdpdGggcm91bmRlZCBjb29yZGluYXRlcy5cclxuXHRyb3VuZDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuY2xvbmUoKS5fcm91bmQoKTtcclxuXHR9LFxyXG5cclxuXHRfcm91bmQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHRoaXMueCA9IE1hdGgucm91bmQodGhpcy54KTtcclxuXHRcdHRoaXMueSA9IE1hdGgucm91bmQodGhpcy55KTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZmxvb3IoKTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIGEgY29weSBvZiB0aGUgY3VycmVudCBwb2ludCB3aXRoIGZsb29yZWQgY29vcmRpbmF0ZXMgKHJvdW5kZWQgZG93bikuXHJcblx0Zmxvb3I6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLmNsb25lKCkuX2Zsb29yKCk7XHJcblx0fSxcclxuXHJcblx0X2Zsb29yOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR0aGlzLnggPSBNYXRoLmZsb29yKHRoaXMueCk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLmZsb29yKHRoaXMueSk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGNlaWwoKTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIGEgY29weSBvZiB0aGUgY3VycmVudCBwb2ludCB3aXRoIGNlaWxlZCBjb29yZGluYXRlcyAocm91bmRlZCB1cCkuXHJcblx0Y2VpbDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuY2xvbmUoKS5fY2VpbCgpO1xyXG5cdH0sXHJcblxyXG5cdF9jZWlsOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR0aGlzLnggPSBNYXRoLmNlaWwodGhpcy54KTtcclxuXHRcdHRoaXMueSA9IE1hdGguY2VpbCh0aGlzLnkpO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB0cnVuYygpOiBQb2ludFxyXG5cdC8vIFJldHVybnMgYSBjb3B5IG9mIHRoZSBjdXJyZW50IHBvaW50IHdpdGggdHJ1bmNhdGVkIGNvb3JkaW5hdGVzIChyb3VuZGVkIHRvd2FyZHMgemVybykuXHJcblx0dHJ1bmM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLmNsb25lKCkuX3RydW5jKCk7XHJcblx0fSxcclxuXHJcblx0X3RydW5jOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR0aGlzLnggPSB0cnVuYyh0aGlzLngpO1xyXG5cdFx0dGhpcy55ID0gdHJ1bmModGhpcy55KTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZGlzdGFuY2VUbyhvdGhlclBvaW50OiBQb2ludCk6IE51bWJlclxyXG5cdC8vIFJldHVybnMgdGhlIGNhcnRlc2lhbiBkaXN0YW5jZSBiZXR3ZWVuIHRoZSBjdXJyZW50IGFuZCB0aGUgZ2l2ZW4gcG9pbnRzLlxyXG5cdGRpc3RhbmNlVG86IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0cG9pbnQgPSB0b1BvaW50KHBvaW50KTtcclxuXHJcblx0XHR2YXIgeCA9IHBvaW50LnggLSB0aGlzLngsXHJcblx0XHQgICAgeSA9IHBvaW50LnkgLSB0aGlzLnk7XHJcblxyXG5cdFx0cmV0dXJuIE1hdGguc3FydCh4ICogeCArIHkgKiB5KTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGVxdWFscyhvdGhlclBvaW50OiBQb2ludCk6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgZ2l2ZW4gcG9pbnQgaGFzIHRoZSBzYW1lIGNvb3JkaW5hdGVzLlxyXG5cdGVxdWFsczogZnVuY3Rpb24gKHBvaW50KSB7XHJcblx0XHRwb2ludCA9IHRvUG9pbnQocG9pbnQpO1xyXG5cclxuXHRcdHJldHVybiBwb2ludC54ID09PSB0aGlzLnggJiZcclxuXHRcdCAgICAgICBwb2ludC55ID09PSB0aGlzLnk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBjb250YWlucyhvdGhlclBvaW50OiBQb2ludCk6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiBib3RoIGNvb3JkaW5hdGVzIG9mIHRoZSBnaXZlbiBwb2ludCBhcmUgbGVzcyB0aGFuIHRoZSBjb3JyZXNwb25kaW5nIGN1cnJlbnQgcG9pbnQgY29vcmRpbmF0ZXMgKGluIGFic29sdXRlIHZhbHVlcykuXHJcblx0Y29udGFpbnM6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0cG9pbnQgPSB0b1BvaW50KHBvaW50KTtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5hYnMocG9pbnQueCkgPD0gTWF0aC5hYnModGhpcy54KSAmJlxyXG5cdFx0ICAgICAgIE1hdGguYWJzKHBvaW50LnkpIDw9IE1hdGguYWJzKHRoaXMueSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB0b1N0cmluZygpOiBTdHJpbmdcclxuXHQvLyBSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwb2ludCBmb3IgZGVidWdnaW5nIHB1cnBvc2VzLlxyXG5cdHRvU3RyaW5nOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gJ1BvaW50KCcgK1xyXG5cdFx0ICAgICAgICBmb3JtYXROdW0odGhpcy54KSArICcsICcgK1xyXG5cdFx0ICAgICAgICBmb3JtYXROdW0odGhpcy55KSArICcpJztcclxuXHR9XHJcbn07XHJcblxyXG4vLyBAZmFjdG9yeSBMLnBvaW50KHg6IE51bWJlciwgeTogTnVtYmVyLCByb3VuZD86IEJvb2xlYW4pXHJcbi8vIENyZWF0ZXMgYSBQb2ludCBvYmplY3Qgd2l0aCB0aGUgZ2l2ZW4gYHhgIGFuZCBgeWAgY29vcmRpbmF0ZXMuIElmIG9wdGlvbmFsIGByb3VuZGAgaXMgc2V0IHRvIHRydWUsIHJvdW5kcyB0aGUgYHhgIGFuZCBgeWAgdmFsdWVzLlxyXG5cclxuLy8gQGFsdGVybmF0aXZlXHJcbi8vIEBmYWN0b3J5IEwucG9pbnQoY29vcmRzOiBOdW1iZXJbXSlcclxuLy8gRXhwZWN0cyBhbiBhcnJheSBvZiB0aGUgZm9ybSBgW3gsIHldYCBpbnN0ZWFkLlxyXG5cclxuLy8gQGFsdGVybmF0aXZlXHJcbi8vIEBmYWN0b3J5IEwucG9pbnQoY29vcmRzOiBPYmplY3QpXHJcbi8vIEV4cGVjdHMgYSBwbGFpbiBvYmplY3Qgb2YgdGhlIGZvcm0gYHt4OiBOdW1iZXIsIHk6IE51bWJlcn1gIGluc3RlYWQuXHJcbmZ1bmN0aW9uIHRvUG9pbnQoeCwgeSwgcm91bmQpIHtcclxuXHRpZiAoeCBpbnN0YW5jZW9mIFBvaW50KSB7XHJcblx0XHRyZXR1cm4geDtcclxuXHR9XHJcblx0aWYgKGlzQXJyYXkoeCkpIHtcclxuXHRcdHJldHVybiBuZXcgUG9pbnQoeFswXSwgeFsxXSk7XHJcblx0fVxyXG5cdGlmICh4ID09PSB1bmRlZmluZWQgfHwgeCA9PT0gbnVsbCkge1xyXG5cdFx0cmV0dXJuIHg7XHJcblx0fVxyXG5cdGlmICh0eXBlb2YgeCA9PT0gJ29iamVjdCcgJiYgJ3gnIGluIHggJiYgJ3knIGluIHgpIHtcclxuXHRcdHJldHVybiBuZXcgUG9pbnQoeC54LCB4LnkpO1xyXG5cdH1cclxuXHRyZXR1cm4gbmV3IFBvaW50KHgsIHksIHJvdW5kKTtcclxufVxuXG4vKlxyXG4gKiBAY2xhc3MgQm91bmRzXHJcbiAqIEBha2EgTC5Cb3VuZHNcclxuICpcclxuICogUmVwcmVzZW50cyBhIHJlY3Rhbmd1bGFyIGFyZWEgaW4gcGl4ZWwgY29vcmRpbmF0ZXMuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHZhciBwMSA9IEwucG9pbnQoMTAsIDEwKSxcclxuICogcDIgPSBMLnBvaW50KDQwLCA2MCksXHJcbiAqIGJvdW5kcyA9IEwuYm91bmRzKHAxLCBwMik7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBBbGwgTGVhZmxldCBtZXRob2RzIHRoYXQgYWNjZXB0IGBCb3VuZHNgIG9iamVjdHMgYWxzbyBhY2NlcHQgdGhlbSBpbiBhIHNpbXBsZSBBcnJheSBmb3JtICh1bmxlc3Mgbm90ZWQgb3RoZXJ3aXNlKSwgc28gdGhlIGJvdW5kcyBleGFtcGxlIGFib3ZlIGNhbiBiZSBwYXNzZWQgbGlrZSB0aGlzOlxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiBvdGhlckJvdW5kcy5pbnRlcnNlY3RzKFtbMTAsIDEwXSwgWzQwLCA2MF1dKTtcclxuICogYGBgXHJcbiAqXHJcbiAqIE5vdGUgdGhhdCBgQm91bmRzYCBkb2VzIG5vdCBpbmhlcml0IGZyb20gTGVhZmV0J3MgYENsYXNzYCBvYmplY3QsXHJcbiAqIHdoaWNoIG1lYW5zIG5ldyBjbGFzc2VzIGNhbid0IGluaGVyaXQgZnJvbSBpdCwgYW5kIG5ldyBtZXRob2RzXHJcbiAqIGNhbid0IGJlIGFkZGVkIHRvIGl0IHdpdGggdGhlIGBpbmNsdWRlYCBmdW5jdGlvbi5cclxuICovXHJcblxyXG5mdW5jdGlvbiBCb3VuZHMoYSwgYikge1xyXG5cdGlmICghYSkgeyByZXR1cm47IH1cclxuXHJcblx0dmFyIHBvaW50cyA9IGIgPyBbYSwgYl0gOiBhO1xyXG5cclxuXHRmb3IgKHZhciBpID0gMCwgbGVuID0gcG9pbnRzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHR0aGlzLmV4dGVuZChwb2ludHNbaV0pO1xyXG5cdH1cclxufVxyXG5cclxuQm91bmRzLnByb3RvdHlwZSA9IHtcclxuXHQvLyBAbWV0aG9kIGV4dGVuZChwb2ludDogUG9pbnQpOiB0aGlzXHJcblx0Ly8gRXh0ZW5kcyB0aGUgYm91bmRzIHRvIGNvbnRhaW4gdGhlIGdpdmVuIHBvaW50LlxyXG5cdGV4dGVuZDogZnVuY3Rpb24gKHBvaW50KSB7IC8vIChQb2ludClcclxuXHRcdHBvaW50ID0gdG9Qb2ludChwb2ludCk7XHJcblxyXG5cdFx0Ly8gQHByb3BlcnR5IG1pbjogUG9pbnRcclxuXHRcdC8vIFRoZSB0b3AgbGVmdCBjb3JuZXIgb2YgdGhlIHJlY3RhbmdsZS5cclxuXHRcdC8vIEBwcm9wZXJ0eSBtYXg6IFBvaW50XHJcblx0XHQvLyBUaGUgYm90dG9tIHJpZ2h0IGNvcm5lciBvZiB0aGUgcmVjdGFuZ2xlLlxyXG5cdFx0aWYgKCF0aGlzLm1pbiAmJiAhdGhpcy5tYXgpIHtcclxuXHRcdFx0dGhpcy5taW4gPSBwb2ludC5jbG9uZSgpO1xyXG5cdFx0XHR0aGlzLm1heCA9IHBvaW50LmNsb25lKCk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR0aGlzLm1pbi54ID0gTWF0aC5taW4ocG9pbnQueCwgdGhpcy5taW4ueCk7XHJcblx0XHRcdHRoaXMubWF4LnggPSBNYXRoLm1heChwb2ludC54LCB0aGlzLm1heC54KTtcclxuXHRcdFx0dGhpcy5taW4ueSA9IE1hdGgubWluKHBvaW50LnksIHRoaXMubWluLnkpO1xyXG5cdFx0XHR0aGlzLm1heC55ID0gTWF0aC5tYXgocG9pbnQueSwgdGhpcy5tYXgueSk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldENlbnRlcihyb3VuZD86IEJvb2xlYW4pOiBQb2ludFxyXG5cdC8vIFJldHVybnMgdGhlIGNlbnRlciBwb2ludCBvZiB0aGUgYm91bmRzLlxyXG5cdGdldENlbnRlcjogZnVuY3Rpb24gKHJvdW5kKSB7XHJcblx0XHRyZXR1cm4gbmV3IFBvaW50KFxyXG5cdFx0ICAgICAgICAodGhpcy5taW4ueCArIHRoaXMubWF4LngpIC8gMixcclxuXHRcdCAgICAgICAgKHRoaXMubWluLnkgKyB0aGlzLm1heC55KSAvIDIsIHJvdW5kKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldEJvdHRvbUxlZnQoKTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIHRoZSBib3R0b20tbGVmdCBwb2ludCBvZiB0aGUgYm91bmRzLlxyXG5cdGdldEJvdHRvbUxlZnQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiBuZXcgUG9pbnQodGhpcy5taW4ueCwgdGhpcy5tYXgueSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRUb3BSaWdodCgpOiBQb2ludFxyXG5cdC8vIFJldHVybnMgdGhlIHRvcC1yaWdodCBwb2ludCBvZiB0aGUgYm91bmRzLlxyXG5cdGdldFRvcFJpZ2h0OiBmdW5jdGlvbiAoKSB7IC8vIC0+IFBvaW50XHJcblx0XHRyZXR1cm4gbmV3IFBvaW50KHRoaXMubWF4LngsIHRoaXMubWluLnkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0VG9wTGVmdCgpOiBQb2ludFxyXG5cdC8vIFJldHVybnMgdGhlIHRvcC1sZWZ0IHBvaW50IG9mIHRoZSBib3VuZHMgKGkuZS4gW2B0aGlzLm1pbmBdKCNib3VuZHMtbWluKSkuXHJcblx0Z2V0VG9wTGVmdDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMubWluOyAvLyBsZWZ0LCB0b3BcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldEJvdHRvbVJpZ2h0KCk6IFBvaW50XHJcblx0Ly8gUmV0dXJucyB0aGUgYm90dG9tLXJpZ2h0IHBvaW50IG9mIHRoZSBib3VuZHMgKGkuZS4gW2B0aGlzLm1heGBdKCNib3VuZHMtbWF4KSkuXHJcblx0Z2V0Qm90dG9tUmlnaHQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLm1heDsgLy8gcmlnaHQsIGJvdHRvbVxyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0U2l6ZSgpOiBQb2ludFxyXG5cdC8vIFJldHVybnMgdGhlIHNpemUgb2YgdGhlIGdpdmVuIGJvdW5kc1xyXG5cdGdldFNpemU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLm1heC5zdWJ0cmFjdCh0aGlzLm1pbik7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBjb250YWlucyhvdGhlckJvdW5kczogQm91bmRzKTogQm9vbGVhblxyXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSByZWN0YW5nbGUgY29udGFpbnMgdGhlIGdpdmVuIG9uZS5cclxuXHQvLyBAYWx0ZXJuYXRpdmVcclxuXHQvLyBAbWV0aG9kIGNvbnRhaW5zKHBvaW50OiBQb2ludCk6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgcmVjdGFuZ2xlIGNvbnRhaW5zIHRoZSBnaXZlbiBwb2ludC5cclxuXHRjb250YWluczogZnVuY3Rpb24gKG9iaikge1xyXG5cdFx0dmFyIG1pbiwgbWF4O1xyXG5cclxuXHRcdGlmICh0eXBlb2Ygb2JqWzBdID09PSAnbnVtYmVyJyB8fCBvYmogaW5zdGFuY2VvZiBQb2ludCkge1xyXG5cdFx0XHRvYmogPSB0b1BvaW50KG9iaik7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRvYmogPSB0b0JvdW5kcyhvYmopO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChvYmogaW5zdGFuY2VvZiBCb3VuZHMpIHtcclxuXHRcdFx0bWluID0gb2JqLm1pbjtcclxuXHRcdFx0bWF4ID0gb2JqLm1heDtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdG1pbiA9IG1heCA9IG9iajtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gKG1pbi54ID49IHRoaXMubWluLngpICYmXHJcblx0XHQgICAgICAgKG1heC54IDw9IHRoaXMubWF4LngpICYmXHJcblx0XHQgICAgICAgKG1pbi55ID49IHRoaXMubWluLnkpICYmXHJcblx0XHQgICAgICAgKG1heC55IDw9IHRoaXMubWF4LnkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgaW50ZXJzZWN0cyhvdGhlckJvdW5kczogQm91bmRzKTogQm9vbGVhblxyXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSByZWN0YW5nbGUgaW50ZXJzZWN0cyB0aGUgZ2l2ZW4gYm91bmRzLiBUd28gYm91bmRzXHJcblx0Ly8gaW50ZXJzZWN0IGlmIHRoZXkgaGF2ZSBhdCBsZWFzdCBvbmUgcG9pbnQgaW4gY29tbW9uLlxyXG5cdGludGVyc2VjdHM6IGZ1bmN0aW9uIChib3VuZHMpIHsgLy8gKEJvdW5kcykgLT4gQm9vbGVhblxyXG5cdFx0Ym91bmRzID0gdG9Cb3VuZHMoYm91bmRzKTtcclxuXHJcblx0XHR2YXIgbWluID0gdGhpcy5taW4sXHJcblx0XHQgICAgbWF4ID0gdGhpcy5tYXgsXHJcblx0XHQgICAgbWluMiA9IGJvdW5kcy5taW4sXHJcblx0XHQgICAgbWF4MiA9IGJvdW5kcy5tYXgsXHJcblx0XHQgICAgeEludGVyc2VjdHMgPSAobWF4Mi54ID49IG1pbi54KSAmJiAobWluMi54IDw9IG1heC54KSxcclxuXHRcdCAgICB5SW50ZXJzZWN0cyA9IChtYXgyLnkgPj0gbWluLnkpICYmIChtaW4yLnkgPD0gbWF4LnkpO1xyXG5cclxuXHRcdHJldHVybiB4SW50ZXJzZWN0cyAmJiB5SW50ZXJzZWN0cztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIG92ZXJsYXBzKG90aGVyQm91bmRzOiBCb3VuZHMpOiBCb29sZWFuXHJcblx0Ly8gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIHJlY3RhbmdsZSBvdmVybGFwcyB0aGUgZ2l2ZW4gYm91bmRzLiBUd28gYm91bmRzXHJcblx0Ly8gb3ZlcmxhcCBpZiB0aGVpciBpbnRlcnNlY3Rpb24gaXMgYW4gYXJlYS5cclxuXHRvdmVybGFwczogZnVuY3Rpb24gKGJvdW5kcykgeyAvLyAoQm91bmRzKSAtPiBCb29sZWFuXHJcblx0XHRib3VuZHMgPSB0b0JvdW5kcyhib3VuZHMpO1xyXG5cclxuXHRcdHZhciBtaW4gPSB0aGlzLm1pbixcclxuXHRcdCAgICBtYXggPSB0aGlzLm1heCxcclxuXHRcdCAgICBtaW4yID0gYm91bmRzLm1pbixcclxuXHRcdCAgICBtYXgyID0gYm91bmRzLm1heCxcclxuXHRcdCAgICB4T3ZlcmxhcHMgPSAobWF4Mi54ID4gbWluLngpICYmIChtaW4yLnggPCBtYXgueCksXHJcblx0XHQgICAgeU92ZXJsYXBzID0gKG1heDIueSA+IG1pbi55KSAmJiAobWluMi55IDwgbWF4LnkpO1xyXG5cclxuXHRcdHJldHVybiB4T3ZlcmxhcHMgJiYgeU92ZXJsYXBzO1xyXG5cdH0sXHJcblxyXG5cdGlzVmFsaWQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiAhISh0aGlzLm1pbiAmJiB0aGlzLm1heCk7XHJcblx0fVxyXG59O1xyXG5cclxuXHJcbi8vIEBmYWN0b3J5IEwuYm91bmRzKGNvcm5lcjE6IFBvaW50LCBjb3JuZXIyOiBQb2ludClcclxuLy8gQ3JlYXRlcyBhIEJvdW5kcyBvYmplY3QgZnJvbSB0d28gY29ybmVycyBjb29yZGluYXRlIHBhaXJzLlxyXG4vLyBAYWx0ZXJuYXRpdmVcclxuLy8gQGZhY3RvcnkgTC5ib3VuZHMocG9pbnRzOiBQb2ludFtdKVxyXG4vLyBDcmVhdGVzIGEgQm91bmRzIG9iamVjdCBmcm9tIHRoZSBnaXZlbiBhcnJheSBvZiBwb2ludHMuXHJcbmZ1bmN0aW9uIHRvQm91bmRzKGEsIGIpIHtcclxuXHRpZiAoIWEgfHwgYSBpbnN0YW5jZW9mIEJvdW5kcykge1xyXG5cdFx0cmV0dXJuIGE7XHJcblx0fVxyXG5cdHJldHVybiBuZXcgQm91bmRzKGEsIGIpO1xyXG59XG5cbi8qXHJcbiAqIEBjbGFzcyBMYXRMbmdCb3VuZHNcclxuICogQGFrYSBMLkxhdExuZ0JvdW5kc1xyXG4gKlxyXG4gKiBSZXByZXNlbnRzIGEgcmVjdGFuZ3VsYXIgZ2VvZ3JhcGhpY2FsIGFyZWEgb24gYSBtYXAuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHZhciBjb3JuZXIxID0gTC5sYXRMbmcoNDAuNzEyLCAtNzQuMjI3KSxcclxuICogY29ybmVyMiA9IEwubGF0TG5nKDQwLjc3NCwgLTc0LjEyNSksXHJcbiAqIGJvdW5kcyA9IEwubGF0TG5nQm91bmRzKGNvcm5lcjEsIGNvcm5lcjIpO1xyXG4gKiBgYGBcclxuICpcclxuICogQWxsIExlYWZsZXQgbWV0aG9kcyB0aGF0IGFjY2VwdCBMYXRMbmdCb3VuZHMgb2JqZWN0cyBhbHNvIGFjY2VwdCB0aGVtIGluIGEgc2ltcGxlIEFycmF5IGZvcm0gKHVubGVzcyBub3RlZCBvdGhlcndpc2UpLCBzbyB0aGUgYm91bmRzIGV4YW1wbGUgYWJvdmUgY2FuIGJlIHBhc3NlZCBsaWtlIHRoaXM6XHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIG1hcC5maXRCb3VuZHMoW1xyXG4gKiBcdFs0MC43MTIsIC03NC4yMjddLFxyXG4gKiBcdFs0MC43NzQsIC03NC4xMjVdXHJcbiAqIF0pO1xyXG4gKiBgYGBcclxuICpcclxuICogQ2F1dGlvbjogaWYgdGhlIGFyZWEgY3Jvc3NlcyB0aGUgYW50aW1lcmlkaWFuIChvZnRlbiBjb25mdXNlZCB3aXRoIHRoZSBJbnRlcm5hdGlvbmFsIERhdGUgTGluZSksIHlvdSBtdXN0IHNwZWNpZnkgY29ybmVycyBfb3V0c2lkZV8gdGhlIFstMTgwLCAxODBdIGRlZ3JlZXMgbG9uZ2l0dWRlIHJhbmdlLlxyXG4gKlxyXG4gKiBOb3RlIHRoYXQgYExhdExuZ0JvdW5kc2AgZG9lcyBub3QgaW5oZXJpdCBmcm9tIExlYWZldCdzIGBDbGFzc2Agb2JqZWN0LFxyXG4gKiB3aGljaCBtZWFucyBuZXcgY2xhc3NlcyBjYW4ndCBpbmhlcml0IGZyb20gaXQsIGFuZCBuZXcgbWV0aG9kc1xyXG4gKiBjYW4ndCBiZSBhZGRlZCB0byBpdCB3aXRoIHRoZSBgaW5jbHVkZWAgZnVuY3Rpb24uXHJcbiAqL1xyXG5cclxuZnVuY3Rpb24gTGF0TG5nQm91bmRzKGNvcm5lcjEsIGNvcm5lcjIpIHsgLy8gKExhdExuZywgTGF0TG5nKSBvciAoTGF0TG5nW10pXHJcblx0aWYgKCFjb3JuZXIxKSB7IHJldHVybjsgfVxyXG5cclxuXHR2YXIgbGF0bG5ncyA9IGNvcm5lcjIgPyBbY29ybmVyMSwgY29ybmVyMl0gOiBjb3JuZXIxO1xyXG5cclxuXHRmb3IgKHZhciBpID0gMCwgbGVuID0gbGF0bG5ncy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG5cdFx0dGhpcy5leHRlbmQobGF0bG5nc1tpXSk7XHJcblx0fVxyXG59XHJcblxyXG5MYXRMbmdCb3VuZHMucHJvdG90eXBlID0ge1xyXG5cclxuXHQvLyBAbWV0aG9kIGV4dGVuZChsYXRsbmc6IExhdExuZyk6IHRoaXNcclxuXHQvLyBFeHRlbmQgdGhlIGJvdW5kcyB0byBjb250YWluIHRoZSBnaXZlbiBwb2ludFxyXG5cclxuXHQvLyBAYWx0ZXJuYXRpdmVcclxuXHQvLyBAbWV0aG9kIGV4dGVuZChvdGhlckJvdW5kczogTGF0TG5nQm91bmRzKTogdGhpc1xyXG5cdC8vIEV4dGVuZCB0aGUgYm91bmRzIHRvIGNvbnRhaW4gdGhlIGdpdmVuIGJvdW5kc1xyXG5cdGV4dGVuZDogZnVuY3Rpb24gKG9iaikge1xyXG5cdFx0dmFyIHN3ID0gdGhpcy5fc291dGhXZXN0LFxyXG5cdFx0ICAgIG5lID0gdGhpcy5fbm9ydGhFYXN0LFxyXG5cdFx0ICAgIHN3MiwgbmUyO1xyXG5cclxuXHRcdGlmIChvYmogaW5zdGFuY2VvZiBMYXRMbmcpIHtcclxuXHRcdFx0c3cyID0gb2JqO1xyXG5cdFx0XHRuZTIgPSBvYmo7XHJcblxyXG5cdFx0fSBlbHNlIGlmIChvYmogaW5zdGFuY2VvZiBMYXRMbmdCb3VuZHMpIHtcclxuXHRcdFx0c3cyID0gb2JqLl9zb3V0aFdlc3Q7XHJcblx0XHRcdG5lMiA9IG9iai5fbm9ydGhFYXN0O1xyXG5cclxuXHRcdFx0aWYgKCFzdzIgfHwgIW5lMikgeyByZXR1cm4gdGhpczsgfVxyXG5cclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdHJldHVybiBvYmogPyB0aGlzLmV4dGVuZCh0b0xhdExuZyhvYmopIHx8IHRvTGF0TG5nQm91bmRzKG9iaikpIDogdGhpcztcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIXN3ICYmICFuZSkge1xyXG5cdFx0XHR0aGlzLl9zb3V0aFdlc3QgPSBuZXcgTGF0TG5nKHN3Mi5sYXQsIHN3Mi5sbmcpO1xyXG5cdFx0XHR0aGlzLl9ub3J0aEVhc3QgPSBuZXcgTGF0TG5nKG5lMi5sYXQsIG5lMi5sbmcpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0c3cubGF0ID0gTWF0aC5taW4oc3cyLmxhdCwgc3cubGF0KTtcclxuXHRcdFx0c3cubG5nID0gTWF0aC5taW4oc3cyLmxuZywgc3cubG5nKTtcclxuXHRcdFx0bmUubGF0ID0gTWF0aC5tYXgobmUyLmxhdCwgbmUubGF0KTtcclxuXHRcdFx0bmUubG5nID0gTWF0aC5tYXgobmUyLmxuZywgbmUubG5nKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHBhZChidWZmZXJSYXRpbzogTnVtYmVyKTogTGF0TG5nQm91bmRzXHJcblx0Ly8gUmV0dXJucyBib3VuZHMgY3JlYXRlZCBieSBleHRlbmRpbmcgb3IgcmV0cmFjdGluZyB0aGUgY3VycmVudCBib3VuZHMgYnkgYSBnaXZlbiByYXRpbyBpbiBlYWNoIGRpcmVjdGlvbi5cclxuXHQvLyBGb3IgZXhhbXBsZSwgYSByYXRpbyBvZiAwLjUgZXh0ZW5kcyB0aGUgYm91bmRzIGJ5IDUwJSBpbiBlYWNoIGRpcmVjdGlvbi5cclxuXHQvLyBOZWdhdGl2ZSB2YWx1ZXMgd2lsbCByZXRyYWN0IHRoZSBib3VuZHMuXHJcblx0cGFkOiBmdW5jdGlvbiAoYnVmZmVyUmF0aW8pIHtcclxuXHRcdHZhciBzdyA9IHRoaXMuX3NvdXRoV2VzdCxcclxuXHRcdCAgICBuZSA9IHRoaXMuX25vcnRoRWFzdCxcclxuXHRcdCAgICBoZWlnaHRCdWZmZXIgPSBNYXRoLmFicyhzdy5sYXQgLSBuZS5sYXQpICogYnVmZmVyUmF0aW8sXHJcblx0XHQgICAgd2lkdGhCdWZmZXIgPSBNYXRoLmFicyhzdy5sbmcgLSBuZS5sbmcpICogYnVmZmVyUmF0aW87XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBMYXRMbmdCb3VuZHMoXHJcblx0XHQgICAgICAgIG5ldyBMYXRMbmcoc3cubGF0IC0gaGVpZ2h0QnVmZmVyLCBzdy5sbmcgLSB3aWR0aEJ1ZmZlciksXHJcblx0XHQgICAgICAgIG5ldyBMYXRMbmcobmUubGF0ICsgaGVpZ2h0QnVmZmVyLCBuZS5sbmcgKyB3aWR0aEJ1ZmZlcikpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0Q2VudGVyKCk6IExhdExuZ1xyXG5cdC8vIFJldHVybnMgdGhlIGNlbnRlciBwb2ludCBvZiB0aGUgYm91bmRzLlxyXG5cdGdldENlbnRlcjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIG5ldyBMYXRMbmcoXHJcblx0XHQgICAgICAgICh0aGlzLl9zb3V0aFdlc3QubGF0ICsgdGhpcy5fbm9ydGhFYXN0LmxhdCkgLyAyLFxyXG5cdFx0ICAgICAgICAodGhpcy5fc291dGhXZXN0LmxuZyArIHRoaXMuX25vcnRoRWFzdC5sbmcpIC8gMik7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRTb3V0aFdlc3QoKTogTGF0TG5nXHJcblx0Ly8gUmV0dXJucyB0aGUgc291dGgtd2VzdCBwb2ludCBvZiB0aGUgYm91bmRzLlxyXG5cdGdldFNvdXRoV2VzdDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX3NvdXRoV2VzdDtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldE5vcnRoRWFzdCgpOiBMYXRMbmdcclxuXHQvLyBSZXR1cm5zIHRoZSBub3J0aC1lYXN0IHBvaW50IG9mIHRoZSBib3VuZHMuXHJcblx0Z2V0Tm9ydGhFYXN0OiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5fbm9ydGhFYXN0O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0Tm9ydGhXZXN0KCk6IExhdExuZ1xyXG5cdC8vIFJldHVybnMgdGhlIG5vcnRoLXdlc3QgcG9pbnQgb2YgdGhlIGJvdW5kcy5cclxuXHRnZXROb3J0aFdlc3Q6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiBuZXcgTGF0TG5nKHRoaXMuZ2V0Tm9ydGgoKSwgdGhpcy5nZXRXZXN0KCkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0U291dGhFYXN0KCk6IExhdExuZ1xyXG5cdC8vIFJldHVybnMgdGhlIHNvdXRoLWVhc3QgcG9pbnQgb2YgdGhlIGJvdW5kcy5cclxuXHRnZXRTb3V0aEVhc3Q6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiBuZXcgTGF0TG5nKHRoaXMuZ2V0U291dGgoKSwgdGhpcy5nZXRFYXN0KCkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0V2VzdCgpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSB3ZXN0IGxvbmdpdHVkZSBvZiB0aGUgYm91bmRzXHJcblx0Z2V0V2VzdDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX3NvdXRoV2VzdC5sbmc7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRTb3V0aCgpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBzb3V0aCBsYXRpdHVkZSBvZiB0aGUgYm91bmRzXHJcblx0Z2V0U291dGg6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9zb3V0aFdlc3QubGF0O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0RWFzdCgpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBlYXN0IGxvbmdpdHVkZSBvZiB0aGUgYm91bmRzXHJcblx0Z2V0RWFzdDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX25vcnRoRWFzdC5sbmc7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXROb3J0aCgpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBub3J0aCBsYXRpdHVkZSBvZiB0aGUgYm91bmRzXHJcblx0Z2V0Tm9ydGg6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9ub3J0aEVhc3QubGF0O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgY29udGFpbnMob3RoZXJCb3VuZHM6IExhdExuZ0JvdW5kcyk6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgcmVjdGFuZ2xlIGNvbnRhaW5zIHRoZSBnaXZlbiBvbmUuXHJcblxyXG5cdC8vIEBhbHRlcm5hdGl2ZVxyXG5cdC8vIEBtZXRob2QgY29udGFpbnMgKGxhdGxuZzogTGF0TG5nKTogQm9vbGVhblxyXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSByZWN0YW5nbGUgY29udGFpbnMgdGhlIGdpdmVuIHBvaW50LlxyXG5cdGNvbnRhaW5zOiBmdW5jdGlvbiAob2JqKSB7IC8vIChMYXRMbmdCb3VuZHMpIG9yIChMYXRMbmcpIC0+IEJvb2xlYW5cclxuXHRcdGlmICh0eXBlb2Ygb2JqWzBdID09PSAnbnVtYmVyJyB8fCBvYmogaW5zdGFuY2VvZiBMYXRMbmcgfHwgJ2xhdCcgaW4gb2JqKSB7XHJcblx0XHRcdG9iaiA9IHRvTGF0TG5nKG9iaik7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRvYmogPSB0b0xhdExuZ0JvdW5kcyhvYmopO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBzdyA9IHRoaXMuX3NvdXRoV2VzdCxcclxuXHRcdCAgICBuZSA9IHRoaXMuX25vcnRoRWFzdCxcclxuXHRcdCAgICBzdzIsIG5lMjtcclxuXHJcblx0XHRpZiAob2JqIGluc3RhbmNlb2YgTGF0TG5nQm91bmRzKSB7XHJcblx0XHRcdHN3MiA9IG9iai5nZXRTb3V0aFdlc3QoKTtcclxuXHRcdFx0bmUyID0gb2JqLmdldE5vcnRoRWFzdCgpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0c3cyID0gbmUyID0gb2JqO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiAoc3cyLmxhdCA+PSBzdy5sYXQpICYmIChuZTIubGF0IDw9IG5lLmxhdCkgJiZcclxuXHRcdCAgICAgICAoc3cyLmxuZyA+PSBzdy5sbmcpICYmIChuZTIubG5nIDw9IG5lLmxuZyk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBpbnRlcnNlY3RzKG90aGVyQm91bmRzOiBMYXRMbmdCb3VuZHMpOiBCb29sZWFuXHJcblx0Ly8gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIHJlY3RhbmdsZSBpbnRlcnNlY3RzIHRoZSBnaXZlbiBib3VuZHMuIFR3byBib3VuZHMgaW50ZXJzZWN0IGlmIHRoZXkgaGF2ZSBhdCBsZWFzdCBvbmUgcG9pbnQgaW4gY29tbW9uLlxyXG5cdGludGVyc2VjdHM6IGZ1bmN0aW9uIChib3VuZHMpIHtcclxuXHRcdGJvdW5kcyA9IHRvTGF0TG5nQm91bmRzKGJvdW5kcyk7XHJcblxyXG5cdFx0dmFyIHN3ID0gdGhpcy5fc291dGhXZXN0LFxyXG5cdFx0ICAgIG5lID0gdGhpcy5fbm9ydGhFYXN0LFxyXG5cdFx0ICAgIHN3MiA9IGJvdW5kcy5nZXRTb3V0aFdlc3QoKSxcclxuXHRcdCAgICBuZTIgPSBib3VuZHMuZ2V0Tm9ydGhFYXN0KCksXHJcblxyXG5cdFx0ICAgIGxhdEludGVyc2VjdHMgPSAobmUyLmxhdCA+PSBzdy5sYXQpICYmIChzdzIubGF0IDw9IG5lLmxhdCksXHJcblx0XHQgICAgbG5nSW50ZXJzZWN0cyA9IChuZTIubG5nID49IHN3LmxuZykgJiYgKHN3Mi5sbmcgPD0gbmUubG5nKTtcclxuXHJcblx0XHRyZXR1cm4gbGF0SW50ZXJzZWN0cyAmJiBsbmdJbnRlcnNlY3RzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgb3ZlcmxhcHMob3RoZXJCb3VuZHM6IEJvdW5kcyk6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgcmVjdGFuZ2xlIG92ZXJsYXBzIHRoZSBnaXZlbiBib3VuZHMuIFR3byBib3VuZHMgb3ZlcmxhcCBpZiB0aGVpciBpbnRlcnNlY3Rpb24gaXMgYW4gYXJlYS5cclxuXHRvdmVybGFwczogZnVuY3Rpb24gKGJvdW5kcykge1xyXG5cdFx0Ym91bmRzID0gdG9MYXRMbmdCb3VuZHMoYm91bmRzKTtcclxuXHJcblx0XHR2YXIgc3cgPSB0aGlzLl9zb3V0aFdlc3QsXHJcblx0XHQgICAgbmUgPSB0aGlzLl9ub3J0aEVhc3QsXHJcblx0XHQgICAgc3cyID0gYm91bmRzLmdldFNvdXRoV2VzdCgpLFxyXG5cdFx0ICAgIG5lMiA9IGJvdW5kcy5nZXROb3J0aEVhc3QoKSxcclxuXHJcblx0XHQgICAgbGF0T3ZlcmxhcHMgPSAobmUyLmxhdCA+IHN3LmxhdCkgJiYgKHN3Mi5sYXQgPCBuZS5sYXQpLFxyXG5cdFx0ICAgIGxuZ092ZXJsYXBzID0gKG5lMi5sbmcgPiBzdy5sbmcpICYmIChzdzIubG5nIDwgbmUubG5nKTtcclxuXHJcblx0XHRyZXR1cm4gbGF0T3ZlcmxhcHMgJiYgbG5nT3ZlcmxhcHM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB0b0JCb3hTdHJpbmcoKTogU3RyaW5nXHJcblx0Ly8gUmV0dXJucyBhIHN0cmluZyB3aXRoIGJvdW5kaW5nIGJveCBjb29yZGluYXRlcyBpbiBhICdzb3V0aHdlc3RfbG5nLHNvdXRod2VzdF9sYXQsbm9ydGhlYXN0X2xuZyxub3J0aGVhc3RfbGF0JyBmb3JtYXQuIFVzZWZ1bCBmb3Igc2VuZGluZyByZXF1ZXN0cyB0byB3ZWIgc2VydmljZXMgdGhhdCByZXR1cm4gZ2VvIGRhdGEuXHJcblx0dG9CQm94U3RyaW5nOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gW3RoaXMuZ2V0V2VzdCgpLCB0aGlzLmdldFNvdXRoKCksIHRoaXMuZ2V0RWFzdCgpLCB0aGlzLmdldE5vcnRoKCldLmpvaW4oJywnKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGVxdWFscyhvdGhlckJvdW5kczogTGF0TG5nQm91bmRzLCBtYXhNYXJnaW4/OiBOdW1iZXIpOiBCb29sZWFuXHJcblx0Ly8gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIHJlY3RhbmdsZSBpcyBlcXVpdmFsZW50ICh3aXRoaW4gYSBzbWFsbCBtYXJnaW4gb2YgZXJyb3IpIHRvIHRoZSBnaXZlbiBib3VuZHMuIFRoZSBtYXJnaW4gb2YgZXJyb3IgY2FuIGJlIG92ZXJyaWRkZW4gYnkgc2V0dGluZyBgbWF4TWFyZ2luYCB0byBhIHNtYWxsIG51bWJlci5cclxuXHRlcXVhbHM6IGZ1bmN0aW9uIChib3VuZHMsIG1heE1hcmdpbikge1xyXG5cdFx0aWYgKCFib3VuZHMpIHsgcmV0dXJuIGZhbHNlOyB9XHJcblxyXG5cdFx0Ym91bmRzID0gdG9MYXRMbmdCb3VuZHMoYm91bmRzKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fc291dGhXZXN0LmVxdWFscyhib3VuZHMuZ2V0U291dGhXZXN0KCksIG1heE1hcmdpbikgJiZcclxuXHRcdCAgICAgICB0aGlzLl9ub3J0aEVhc3QuZXF1YWxzKGJvdW5kcy5nZXROb3J0aEVhc3QoKSwgbWF4TWFyZ2luKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGlzVmFsaWQoKTogQm9vbGVhblxyXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSBib3VuZHMgYXJlIHByb3Blcmx5IGluaXRpYWxpemVkLlxyXG5cdGlzVmFsaWQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiAhISh0aGlzLl9zb3V0aFdlc3QgJiYgdGhpcy5fbm9ydGhFYXN0KTtcclxuXHR9XHJcbn07XHJcblxyXG4vLyBUT0RPIEludGVybmF0aW9uYWwgZGF0ZSBsaW5lP1xyXG5cclxuLy8gQGZhY3RvcnkgTC5sYXRMbmdCb3VuZHMoY29ybmVyMTogTGF0TG5nLCBjb3JuZXIyOiBMYXRMbmcpXHJcbi8vIENyZWF0ZXMgYSBgTGF0TG5nQm91bmRzYCBvYmplY3QgYnkgZGVmaW5pbmcgdHdvIGRpYWdvbmFsbHkgb3Bwb3NpdGUgY29ybmVycyBvZiB0aGUgcmVjdGFuZ2xlLlxyXG5cclxuLy8gQGFsdGVybmF0aXZlXHJcbi8vIEBmYWN0b3J5IEwubGF0TG5nQm91bmRzKGxhdGxuZ3M6IExhdExuZ1tdKVxyXG4vLyBDcmVhdGVzIGEgYExhdExuZ0JvdW5kc2Agb2JqZWN0IGRlZmluZWQgYnkgdGhlIGdlb2dyYXBoaWNhbCBwb2ludHMgaXQgY29udGFpbnMuIFZlcnkgdXNlZnVsIGZvciB6b29taW5nIHRoZSBtYXAgdG8gZml0IGEgcGFydGljdWxhciBzZXQgb2YgbG9jYXRpb25zIHdpdGggW2BmaXRCb3VuZHNgXSgjbWFwLWZpdGJvdW5kcykuXHJcbmZ1bmN0aW9uIHRvTGF0TG5nQm91bmRzKGEsIGIpIHtcclxuXHRpZiAoYSBpbnN0YW5jZW9mIExhdExuZ0JvdW5kcykge1xyXG5cdFx0cmV0dXJuIGE7XHJcblx0fVxyXG5cdHJldHVybiBuZXcgTGF0TG5nQm91bmRzKGEsIGIpO1xyXG59XG5cbi8qIEBjbGFzcyBMYXRMbmdcclxuICogQGFrYSBMLkxhdExuZ1xyXG4gKlxyXG4gKiBSZXByZXNlbnRzIGEgZ2VvZ3JhcGhpY2FsIHBvaW50IHdpdGggYSBjZXJ0YWluIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYFxyXG4gKiB2YXIgbGF0bG5nID0gTC5sYXRMbmcoNTAuNSwgMzAuNSk7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBBbGwgTGVhZmxldCBtZXRob2RzIHRoYXQgYWNjZXB0IExhdExuZyBvYmplY3RzIGFsc28gYWNjZXB0IHRoZW0gaW4gYSBzaW1wbGUgQXJyYXkgZm9ybSBhbmQgc2ltcGxlIG9iamVjdCBmb3JtICh1bmxlc3Mgbm90ZWQgb3RoZXJ3aXNlKSwgc28gdGhlc2UgbGluZXMgYXJlIGVxdWl2YWxlbnQ6XHJcbiAqXHJcbiAqIGBgYFxyXG4gKiBtYXAucGFuVG8oWzUwLCAzMF0pO1xyXG4gKiBtYXAucGFuVG8oe2xvbjogMzAsIGxhdDogNTB9KTtcclxuICogbWFwLnBhblRvKHtsYXQ6IDUwLCBsbmc6IDMwfSk7XHJcbiAqIG1hcC5wYW5UbyhMLmxhdExuZyg1MCwgMzApKTtcclxuICogYGBgXHJcbiAqXHJcbiAqIE5vdGUgdGhhdCBgTGF0TG5nYCBkb2VzIG5vdCBpbmhlcml0IGZyb20gTGVhZmV0J3MgYENsYXNzYCBvYmplY3QsXHJcbiAqIHdoaWNoIG1lYW5zIG5ldyBjbGFzc2VzIGNhbid0IGluaGVyaXQgZnJvbSBpdCwgYW5kIG5ldyBtZXRob2RzXHJcbiAqIGNhbid0IGJlIGFkZGVkIHRvIGl0IHdpdGggdGhlIGBpbmNsdWRlYCBmdW5jdGlvbi5cclxuICovXHJcblxyXG5mdW5jdGlvbiBMYXRMbmcobGF0LCBsbmcsIGFsdCkge1xyXG5cdGlmIChpc05hTihsYXQpIHx8IGlzTmFOKGxuZykpIHtcclxuXHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBMYXRMbmcgb2JqZWN0OiAoJyArIGxhdCArICcsICcgKyBsbmcgKyAnKScpO1xyXG5cdH1cclxuXHJcblx0Ly8gQHByb3BlcnR5IGxhdDogTnVtYmVyXHJcblx0Ly8gTGF0aXR1ZGUgaW4gZGVncmVlc1xyXG5cdHRoaXMubGF0ID0gK2xhdDtcclxuXHJcblx0Ly8gQHByb3BlcnR5IGxuZzogTnVtYmVyXHJcblx0Ly8gTG9uZ2l0dWRlIGluIGRlZ3JlZXNcclxuXHR0aGlzLmxuZyA9ICtsbmc7XHJcblxyXG5cdC8vIEBwcm9wZXJ0eSBhbHQ6IE51bWJlclxyXG5cdC8vIEFsdGl0dWRlIGluIG1ldGVycyAob3B0aW9uYWwpXHJcblx0aWYgKGFsdCAhPT0gdW5kZWZpbmVkKSB7XHJcblx0XHR0aGlzLmFsdCA9ICthbHQ7XHJcblx0fVxyXG59XHJcblxyXG5MYXRMbmcucHJvdG90eXBlID0ge1xyXG5cdC8vIEBtZXRob2QgZXF1YWxzKG90aGVyTGF0TG5nOiBMYXRMbmcsIG1heE1hcmdpbj86IE51bWJlcik6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgZ2l2ZW4gYExhdExuZ2AgcG9pbnQgaXMgYXQgdGhlIHNhbWUgcG9zaXRpb24gKHdpdGhpbiBhIHNtYWxsIG1hcmdpbiBvZiBlcnJvcikuIFRoZSBtYXJnaW4gb2YgZXJyb3IgY2FuIGJlIG92ZXJyaWRkZW4gYnkgc2V0dGluZyBgbWF4TWFyZ2luYCB0byBhIHNtYWxsIG51bWJlci5cclxuXHRlcXVhbHM6IGZ1bmN0aW9uIChvYmosIG1heE1hcmdpbikge1xyXG5cdFx0aWYgKCFvYmopIHsgcmV0dXJuIGZhbHNlOyB9XHJcblxyXG5cdFx0b2JqID0gdG9MYXRMbmcob2JqKTtcclxuXHJcblx0XHR2YXIgbWFyZ2luID0gTWF0aC5tYXgoXHJcblx0XHQgICAgICAgIE1hdGguYWJzKHRoaXMubGF0IC0gb2JqLmxhdCksXHJcblx0XHQgICAgICAgIE1hdGguYWJzKHRoaXMubG5nIC0gb2JqLmxuZykpO1xyXG5cclxuXHRcdHJldHVybiBtYXJnaW4gPD0gKG1heE1hcmdpbiA9PT0gdW5kZWZpbmVkID8gMS4wRS05IDogbWF4TWFyZ2luKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHRvU3RyaW5nKCk6IFN0cmluZ1xyXG5cdC8vIFJldHVybnMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIHBvaW50IChmb3IgZGVidWdnaW5nIHB1cnBvc2VzKS5cclxuXHR0b1N0cmluZzogZnVuY3Rpb24gKHByZWNpc2lvbikge1xyXG5cdFx0cmV0dXJuICdMYXRMbmcoJyArXHJcblx0XHQgICAgICAgIGZvcm1hdE51bSh0aGlzLmxhdCwgcHJlY2lzaW9uKSArICcsICcgK1xyXG5cdFx0ICAgICAgICBmb3JtYXROdW0odGhpcy5sbmcsIHByZWNpc2lvbikgKyAnKSc7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBkaXN0YW5jZVRvKG90aGVyTGF0TG5nOiBMYXRMbmcpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBkaXN0YW5jZSAoaW4gbWV0ZXJzKSB0byB0aGUgZ2l2ZW4gYExhdExuZ2AgY2FsY3VsYXRlZCB1c2luZyB0aGUgW1NwaGVyaWNhbCBMYXcgb2YgQ29zaW5lc10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU3BoZXJpY2FsX2xhd19vZl9jb3NpbmVzKS5cclxuXHRkaXN0YW5jZVRvOiBmdW5jdGlvbiAob3RoZXIpIHtcclxuXHRcdHJldHVybiBFYXJ0aC5kaXN0YW5jZSh0aGlzLCB0b0xhdExuZyhvdGhlcikpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgd3JhcCgpOiBMYXRMbmdcclxuXHQvLyBSZXR1cm5zIGEgbmV3IGBMYXRMbmdgIG9iamVjdCB3aXRoIHRoZSBsb25naXR1ZGUgd3JhcHBlZCBzbyBpdCdzIGFsd2F5cyBiZXR3ZWVuIC0xODAgYW5kICsxODAgZGVncmVlcy5cclxuXHR3cmFwOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gRWFydGgud3JhcExhdExuZyh0aGlzKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHRvQm91bmRzKHNpemVJbk1ldGVyczogTnVtYmVyKTogTGF0TG5nQm91bmRzXHJcblx0Ly8gUmV0dXJucyBhIG5ldyBgTGF0TG5nQm91bmRzYCBvYmplY3QgaW4gd2hpY2ggZWFjaCBib3VuZGFyeSBpcyBgc2l6ZUluTWV0ZXJzLzJgIG1ldGVycyBhcGFydCBmcm9tIHRoZSBgTGF0TG5nYC5cclxuXHR0b0JvdW5kczogZnVuY3Rpb24gKHNpemVJbk1ldGVycykge1xyXG5cdFx0dmFyIGxhdEFjY3VyYWN5ID0gMTgwICogc2l6ZUluTWV0ZXJzIC8gNDAwNzUwMTcsXHJcblx0XHQgICAgbG5nQWNjdXJhY3kgPSBsYXRBY2N1cmFjeSAvIE1hdGguY29zKChNYXRoLlBJIC8gMTgwKSAqIHRoaXMubGF0KTtcclxuXHJcblx0XHRyZXR1cm4gdG9MYXRMbmdCb3VuZHMoXHJcblx0XHQgICAgICAgIFt0aGlzLmxhdCAtIGxhdEFjY3VyYWN5LCB0aGlzLmxuZyAtIGxuZ0FjY3VyYWN5XSxcclxuXHRcdCAgICAgICAgW3RoaXMubGF0ICsgbGF0QWNjdXJhY3ksIHRoaXMubG5nICsgbG5nQWNjdXJhY3ldKTtcclxuXHR9LFxyXG5cclxuXHRjbG9uZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIG5ldyBMYXRMbmcodGhpcy5sYXQsIHRoaXMubG5nLCB0aGlzLmFsdCk7XHJcblx0fVxyXG59O1xyXG5cclxuXHJcblxyXG4vLyBAZmFjdG9yeSBMLmxhdExuZyhsYXRpdHVkZTogTnVtYmVyLCBsb25naXR1ZGU6IE51bWJlciwgYWx0aXR1ZGU/OiBOdW1iZXIpOiBMYXRMbmdcclxuLy8gQ3JlYXRlcyBhbiBvYmplY3QgcmVwcmVzZW50aW5nIGEgZ2VvZ3JhcGhpY2FsIHBvaW50IHdpdGggdGhlIGdpdmVuIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUgKGFuZCBvcHRpb25hbGx5IGFsdGl0dWRlKS5cclxuXHJcbi8vIEBhbHRlcm5hdGl2ZVxyXG4vLyBAZmFjdG9yeSBMLmxhdExuZyhjb29yZHM6IEFycmF5KTogTGF0TG5nXHJcbi8vIEV4cGVjdHMgYW4gYXJyYXkgb2YgdGhlIGZvcm0gYFtOdW1iZXIsIE51bWJlcl1gIG9yIGBbTnVtYmVyLCBOdW1iZXIsIE51bWJlcl1gIGluc3RlYWQuXHJcblxyXG4vLyBAYWx0ZXJuYXRpdmVcclxuLy8gQGZhY3RvcnkgTC5sYXRMbmcoY29vcmRzOiBPYmplY3QpOiBMYXRMbmdcclxuLy8gRXhwZWN0cyBhbiBwbGFpbiBvYmplY3Qgb2YgdGhlIGZvcm0gYHtsYXQ6IE51bWJlciwgbG5nOiBOdW1iZXJ9YCBvciBge2xhdDogTnVtYmVyLCBsbmc6IE51bWJlciwgYWx0OiBOdW1iZXJ9YCBpbnN0ZWFkLlxyXG5cclxuZnVuY3Rpb24gdG9MYXRMbmcoYSwgYiwgYykge1xyXG5cdGlmIChhIGluc3RhbmNlb2YgTGF0TG5nKSB7XHJcblx0XHRyZXR1cm4gYTtcclxuXHR9XHJcblx0aWYgKGlzQXJyYXkoYSkgJiYgdHlwZW9mIGFbMF0gIT09ICdvYmplY3QnKSB7XHJcblx0XHRpZiAoYS5sZW5ndGggPT09IDMpIHtcclxuXHRcdFx0cmV0dXJuIG5ldyBMYXRMbmcoYVswXSwgYVsxXSwgYVsyXSk7XHJcblx0XHR9XHJcblx0XHRpZiAoYS5sZW5ndGggPT09IDIpIHtcclxuXHRcdFx0cmV0dXJuIG5ldyBMYXRMbmcoYVswXSwgYVsxXSk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gbnVsbDtcclxuXHR9XHJcblx0aWYgKGEgPT09IHVuZGVmaW5lZCB8fCBhID09PSBudWxsKSB7XHJcblx0XHRyZXR1cm4gYTtcclxuXHR9XHJcblx0aWYgKHR5cGVvZiBhID09PSAnb2JqZWN0JyAmJiAnbGF0JyBpbiBhKSB7XHJcblx0XHRyZXR1cm4gbmV3IExhdExuZyhhLmxhdCwgJ2xuZycgaW4gYSA/IGEubG5nIDogYS5sb24sIGEuYWx0KTtcclxuXHR9XHJcblx0aWYgKGIgPT09IHVuZGVmaW5lZCkge1xyXG5cdFx0cmV0dXJuIG51bGw7XHJcblx0fVxyXG5cdHJldHVybiBuZXcgTGF0TG5nKGEsIGIsIGMpO1xyXG59XG5cbi8qXHJcbiAqIEBuYW1lc3BhY2UgQ1JTXHJcbiAqIEBjcnMgTC5DUlMuQmFzZVxyXG4gKiBPYmplY3QgdGhhdCBkZWZpbmVzIGNvb3JkaW5hdGUgcmVmZXJlbmNlIHN5c3RlbXMgZm9yIHByb2plY3RpbmdcclxuICogZ2VvZ3JhcGhpY2FsIHBvaW50cyBpbnRvIHBpeGVsIChzY3JlZW4pIGNvb3JkaW5hdGVzIGFuZCBiYWNrIChhbmQgdG9cclxuICogY29vcmRpbmF0ZXMgaW4gb3RoZXIgdW5pdHMgZm9yIFtXTVNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1dlYl9NYXBfU2VydmljZSkgc2VydmljZXMpLiBTZWVcclxuICogW3NwYXRpYWwgcmVmZXJlbmNlIHN5c3RlbV0oaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Db29yZGluYXRlX3JlZmVyZW5jZV9zeXN0ZW0pLlxyXG4gKlxyXG4gKiBMZWFmbGV0IGRlZmluZXMgdGhlIG1vc3QgdXN1YWwgQ1JTcyBieSBkZWZhdWx0LiBJZiB5b3Ugd2FudCB0byB1c2UgYVxyXG4gKiBDUlMgbm90IGRlZmluZWQgYnkgZGVmYXVsdCwgdGFrZSBhIGxvb2sgYXQgdGhlXHJcbiAqIFtQcm9qNExlYWZsZXRdKGh0dHBzOi8vZ2l0aHViLmNvbS9rYXJ0ZW5hL1Byb2o0TGVhZmxldCkgcGx1Z2luLlxyXG4gKlxyXG4gKiBOb3RlIHRoYXQgdGhlIENSUyBpbnN0YW5jZXMgZG8gbm90IGluaGVyaXQgZnJvbSBMZWFmZXQncyBgQ2xhc3NgIG9iamVjdCxcclxuICogYW5kIGNhbid0IGJlIGluc3RhbnRpYXRlZC4gQWxzbywgbmV3IGNsYXNzZXMgY2FuJ3QgaW5oZXJpdCBmcm9tIHRoZW0sXHJcbiAqIGFuZCBtZXRob2RzIGNhbid0IGJlIGFkZGVkIHRvIHRoZW0gd2l0aCB0aGUgYGluY2x1ZGVgIGZ1bmN0aW9uLlxyXG4gKi9cclxuXHJcbnZhciBDUlMgPSB7XHJcblx0Ly8gQG1ldGhvZCBsYXRMbmdUb1BvaW50KGxhdGxuZzogTGF0TG5nLCB6b29tOiBOdW1iZXIpOiBQb2ludFxyXG5cdC8vIFByb2plY3RzIGdlb2dyYXBoaWNhbCBjb29yZGluYXRlcyBpbnRvIHBpeGVsIGNvb3JkaW5hdGVzIGZvciBhIGdpdmVuIHpvb20uXHJcblx0bGF0TG5nVG9Qb2ludDogZnVuY3Rpb24gKGxhdGxuZywgem9vbSkge1xyXG5cdFx0dmFyIHByb2plY3RlZFBvaW50ID0gdGhpcy5wcm9qZWN0aW9uLnByb2plY3QobGF0bG5nKSxcclxuXHRcdCAgICBzY2FsZSA9IHRoaXMuc2NhbGUoem9vbSk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMudHJhbnNmb3JtYXRpb24uX3RyYW5zZm9ybShwcm9qZWN0ZWRQb2ludCwgc2NhbGUpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgcG9pbnRUb0xhdExuZyhwb2ludDogUG9pbnQsIHpvb206IE51bWJlcik6IExhdExuZ1xyXG5cdC8vIFRoZSBpbnZlcnNlIG9mIGBsYXRMbmdUb1BvaW50YC4gUHJvamVjdHMgcGl4ZWwgY29vcmRpbmF0ZXMgb24gYSBnaXZlblxyXG5cdC8vIHpvb20gaW50byBnZW9ncmFwaGljYWwgY29vcmRpbmF0ZXMuXHJcblx0cG9pbnRUb0xhdExuZzogZnVuY3Rpb24gKHBvaW50LCB6b29tKSB7XHJcblx0XHR2YXIgc2NhbGUgPSB0aGlzLnNjYWxlKHpvb20pLFxyXG5cdFx0ICAgIHVudHJhbnNmb3JtZWRQb2ludCA9IHRoaXMudHJhbnNmb3JtYXRpb24udW50cmFuc2Zvcm0ocG9pbnQsIHNjYWxlKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5wcm9qZWN0aW9uLnVucHJvamVjdCh1bnRyYW5zZm9ybWVkUG9pbnQpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgcHJvamVjdChsYXRsbmc6IExhdExuZyk6IFBvaW50XHJcblx0Ly8gUHJvamVjdHMgZ2VvZ3JhcGhpY2FsIGNvb3JkaW5hdGVzIGludG8gY29vcmRpbmF0ZXMgaW4gdW5pdHMgYWNjZXB0ZWQgZm9yXHJcblx0Ly8gdGhpcyBDUlMgKGUuZy4gbWV0ZXJzIGZvciBFUFNHOjM4NTcsIGZvciBwYXNzaW5nIGl0IHRvIFdNUyBzZXJ2aWNlcykuXHJcblx0cHJvamVjdDogZnVuY3Rpb24gKGxhdGxuZykge1xyXG5cdFx0cmV0dXJuIHRoaXMucHJvamVjdGlvbi5wcm9qZWN0KGxhdGxuZyk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB1bnByb2plY3QocG9pbnQ6IFBvaW50KTogTGF0TG5nXHJcblx0Ly8gR2l2ZW4gYSBwcm9qZWN0ZWQgY29vcmRpbmF0ZSByZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIExhdExuZy5cclxuXHQvLyBUaGUgaW52ZXJzZSBvZiBgcHJvamVjdGAuXHJcblx0dW5wcm9qZWN0OiBmdW5jdGlvbiAocG9pbnQpIHtcclxuXHRcdHJldHVybiB0aGlzLnByb2plY3Rpb24udW5wcm9qZWN0KHBvaW50KTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNjYWxlKHpvb206IE51bWJlcik6IE51bWJlclxyXG5cdC8vIFJldHVybnMgdGhlIHNjYWxlIHVzZWQgd2hlbiB0cmFuc2Zvcm1pbmcgcHJvamVjdGVkIGNvb3JkaW5hdGVzIGludG9cclxuXHQvLyBwaXhlbCBjb29yZGluYXRlcyBmb3IgYSBwYXJ0aWN1bGFyIHpvb20uIEZvciBleGFtcGxlLCBpdCByZXR1cm5zXHJcblx0Ly8gYDI1NiAqIDJeem9vbWAgZm9yIE1lcmNhdG9yLWJhc2VkIENSUy5cclxuXHRzY2FsZTogZnVuY3Rpb24gKHpvb20pIHtcclxuXHRcdHJldHVybiAyNTYgKiBNYXRoLnBvdygyLCB6b29tKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHpvb20oc2NhbGU6IE51bWJlcik6IE51bWJlclxyXG5cdC8vIEludmVyc2Ugb2YgYHNjYWxlKClgLCByZXR1cm5zIHRoZSB6b29tIGxldmVsIGNvcnJlc3BvbmRpbmcgdG8gYSBzY2FsZVxyXG5cdC8vIGZhY3RvciBvZiBgc2NhbGVgLlxyXG5cdHpvb206IGZ1bmN0aW9uIChzY2FsZSkge1xyXG5cdFx0cmV0dXJuIE1hdGgubG9nKHNjYWxlIC8gMjU2KSAvIE1hdGguTE4yO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0UHJvamVjdGVkQm91bmRzKHpvb206IE51bWJlcik6IEJvdW5kc1xyXG5cdC8vIFJldHVybnMgdGhlIHByb2plY3Rpb24ncyBib3VuZHMgc2NhbGVkIGFuZCB0cmFuc2Zvcm1lZCBmb3IgdGhlIHByb3ZpZGVkIGB6b29tYC5cclxuXHRnZXRQcm9qZWN0ZWRCb3VuZHM6IGZ1bmN0aW9uICh6b29tKSB7XHJcblx0XHRpZiAodGhpcy5pbmZpbml0ZSkgeyByZXR1cm4gbnVsbDsgfVxyXG5cclxuXHRcdHZhciBiID0gdGhpcy5wcm9qZWN0aW9uLmJvdW5kcyxcclxuXHRcdCAgICBzID0gdGhpcy5zY2FsZSh6b29tKSxcclxuXHRcdCAgICBtaW4gPSB0aGlzLnRyYW5zZm9ybWF0aW9uLnRyYW5zZm9ybShiLm1pbiwgcyksXHJcblx0XHQgICAgbWF4ID0gdGhpcy50cmFuc2Zvcm1hdGlvbi50cmFuc2Zvcm0oYi5tYXgsIHMpO1xyXG5cclxuXHRcdHJldHVybiBuZXcgQm91bmRzKG1pbiwgbWF4KTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGRpc3RhbmNlKGxhdGxuZzE6IExhdExuZywgbGF0bG5nMjogTGF0TG5nKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0d28gZ2VvZ3JhcGhpY2FsIGNvb3JkaW5hdGVzLlxyXG5cclxuXHQvLyBAcHJvcGVydHkgY29kZTogU3RyaW5nXHJcblx0Ly8gU3RhbmRhcmQgY29kZSBuYW1lIG9mIHRoZSBDUlMgcGFzc2VkIGludG8gV01TIHNlcnZpY2VzIChlLmcuIGAnRVBTRzozODU3J2ApXHJcblx0Ly9cclxuXHQvLyBAcHJvcGVydHkgd3JhcExuZzogTnVtYmVyW11cclxuXHQvLyBBbiBhcnJheSBvZiB0d28gbnVtYmVycyBkZWZpbmluZyB3aGV0aGVyIHRoZSBsb25naXR1ZGUgKGhvcml6b250YWwpIGNvb3JkaW5hdGVcclxuXHQvLyBheGlzIHdyYXBzIGFyb3VuZCBhIGdpdmVuIHJhbmdlIGFuZCBob3cuIERlZmF1bHRzIHRvIGBbLTE4MCwgMTgwXWAgaW4gbW9zdFxyXG5cdC8vIGdlb2dyYXBoaWNhbCBDUlNzLiBJZiBgdW5kZWZpbmVkYCwgdGhlIGxvbmdpdHVkZSBheGlzIGRvZXMgbm90IHdyYXAgYXJvdW5kLlxyXG5cdC8vXHJcblx0Ly8gQHByb3BlcnR5IHdyYXBMYXQ6IE51bWJlcltdXHJcblx0Ly8gTGlrZSBgd3JhcExuZ2AsIGJ1dCBmb3IgdGhlIGxhdGl0dWRlICh2ZXJ0aWNhbCkgYXhpcy5cclxuXHJcblx0Ly8gd3JhcExuZzogW21pbiwgbWF4XSxcclxuXHQvLyB3cmFwTGF0OiBbbWluLCBtYXhdLFxyXG5cclxuXHQvLyBAcHJvcGVydHkgaW5maW5pdGU6IEJvb2xlYW5cclxuXHQvLyBJZiB0cnVlLCB0aGUgY29vcmRpbmF0ZSBzcGFjZSB3aWxsIGJlIHVuYm91bmRlZCAoaW5maW5pdGUgaW4gYm90aCBheGVzKVxyXG5cdGluZmluaXRlOiBmYWxzZSxcclxuXHJcblx0Ly8gQG1ldGhvZCB3cmFwTGF0TG5nKGxhdGxuZzogTGF0TG5nKTogTGF0TG5nXHJcblx0Ly8gUmV0dXJucyBhIGBMYXRMbmdgIHdoZXJlIGxhdCBhbmQgbG5nIGhhcyBiZWVuIHdyYXBwZWQgYWNjb3JkaW5nIHRvIHRoZVxyXG5cdC8vIENSUydzIGB3cmFwTGF0YCBhbmQgYHdyYXBMbmdgIHByb3BlcnRpZXMsIGlmIHRoZXkgYXJlIG91dHNpZGUgdGhlIENSUydzIGJvdW5kcy5cclxuXHR3cmFwTGF0TG5nOiBmdW5jdGlvbiAobGF0bG5nKSB7XHJcblx0XHR2YXIgbG5nID0gdGhpcy53cmFwTG5nID8gd3JhcE51bShsYXRsbmcubG5nLCB0aGlzLndyYXBMbmcsIHRydWUpIDogbGF0bG5nLmxuZyxcclxuXHRcdCAgICBsYXQgPSB0aGlzLndyYXBMYXQgPyB3cmFwTnVtKGxhdGxuZy5sYXQsIHRoaXMud3JhcExhdCwgdHJ1ZSkgOiBsYXRsbmcubGF0LFxyXG5cdFx0ICAgIGFsdCA9IGxhdGxuZy5hbHQ7XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBMYXRMbmcobGF0LCBsbmcsIGFsdCk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB3cmFwTGF0TG5nQm91bmRzKGJvdW5kczogTGF0TG5nQm91bmRzKTogTGF0TG5nQm91bmRzXHJcblx0Ly8gUmV0dXJucyBhIGBMYXRMbmdCb3VuZHNgIHdpdGggdGhlIHNhbWUgc2l6ZSBhcyB0aGUgZ2l2ZW4gb25lLCBlbnN1cmluZ1xyXG5cdC8vIHRoYXQgaXRzIGNlbnRlciBpcyB3aXRoaW4gdGhlIENSUydzIGJvdW5kcy5cclxuXHQvLyBPbmx5IGFjY2VwdHMgYWN0dWFsIGBMLkxhdExuZ0JvdW5kc2AgaW5zdGFuY2VzLCBub3QgYXJyYXlzLlxyXG5cdHdyYXBMYXRMbmdCb3VuZHM6IGZ1bmN0aW9uIChib3VuZHMpIHtcclxuXHRcdHZhciBjZW50ZXIgPSBib3VuZHMuZ2V0Q2VudGVyKCksXHJcblx0XHQgICAgbmV3Q2VudGVyID0gdGhpcy53cmFwTGF0TG5nKGNlbnRlciksXHJcblx0XHQgICAgbGF0U2hpZnQgPSBjZW50ZXIubGF0IC0gbmV3Q2VudGVyLmxhdCxcclxuXHRcdCAgICBsbmdTaGlmdCA9IGNlbnRlci5sbmcgLSBuZXdDZW50ZXIubG5nO1xyXG5cclxuXHRcdGlmIChsYXRTaGlmdCA9PT0gMCAmJiBsbmdTaGlmdCA9PT0gMCkge1xyXG5cdFx0XHRyZXR1cm4gYm91bmRzO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBzdyA9IGJvdW5kcy5nZXRTb3V0aFdlc3QoKSxcclxuXHRcdCAgICBuZSA9IGJvdW5kcy5nZXROb3J0aEVhc3QoKSxcclxuXHRcdCAgICBuZXdTdyA9IG5ldyBMYXRMbmcoc3cubGF0IC0gbGF0U2hpZnQsIHN3LmxuZyAtIGxuZ1NoaWZ0KSxcclxuXHRcdCAgICBuZXdOZSA9IG5ldyBMYXRMbmcobmUubGF0IC0gbGF0U2hpZnQsIG5lLmxuZyAtIGxuZ1NoaWZ0KTtcclxuXHJcblx0XHRyZXR1cm4gbmV3IExhdExuZ0JvdW5kcyhuZXdTdywgbmV3TmUpO1xyXG5cdH1cclxufTtcblxuLypcbiAqIEBuYW1lc3BhY2UgQ1JTXG4gKiBAY3JzIEwuQ1JTLkVhcnRoXG4gKlxuICogU2VydmVzIGFzIHRoZSBiYXNlIGZvciBDUlMgdGhhdCBhcmUgZ2xvYmFsIHN1Y2ggdGhhdCB0aGV5IGNvdmVyIHRoZSBlYXJ0aC5cbiAqIENhbiBvbmx5IGJlIHVzZWQgYXMgdGhlIGJhc2UgZm9yIG90aGVyIENSUyBhbmQgY2Fubm90IGJlIHVzZWQgZGlyZWN0bHksXG4gKiBzaW5jZSBpdCBkb2VzIG5vdCBoYXZlIGEgYGNvZGVgLCBgcHJvamVjdGlvbmAgb3IgYHRyYW5zZm9ybWF0aW9uYC4gYGRpc3RhbmNlKClgIHJldHVybnNcbiAqIG1ldGVycy5cbiAqL1xuXG52YXIgRWFydGggPSBleHRlbmQoe30sIENSUywge1xuXHR3cmFwTG5nOiBbLTE4MCwgMTgwXSxcblxuXHQvLyBNZWFuIEVhcnRoIFJhZGl1cywgYXMgcmVjb21tZW5kZWQgZm9yIHVzZSBieVxuXHQvLyB0aGUgSW50ZXJuYXRpb25hbCBVbmlvbiBvZiBHZW9kZXN5IGFuZCBHZW9waHlzaWNzLFxuXHQvLyBzZWUgaHR0cDovL3Jvc2V0dGFjb2RlLm9yZy93aWtpL0hhdmVyc2luZV9mb3JtdWxhXG5cdFI6IDYzNzEwMDAsXG5cblx0Ly8gZGlzdGFuY2UgYmV0d2VlbiB0d28gZ2VvZ3JhcGhpY2FsIHBvaW50cyB1c2luZyBzcGhlcmljYWwgbGF3IG9mIGNvc2luZXMgYXBwcm94aW1hdGlvblxuXHRkaXN0YW5jZTogZnVuY3Rpb24gKGxhdGxuZzEsIGxhdGxuZzIpIHtcblx0XHR2YXIgcmFkID0gTWF0aC5QSSAvIDE4MCxcblx0XHQgICAgbGF0MSA9IGxhdGxuZzEubGF0ICogcmFkLFxuXHRcdCAgICBsYXQyID0gbGF0bG5nMi5sYXQgKiByYWQsXG5cdFx0ICAgIHNpbkRMYXQgPSBNYXRoLnNpbigobGF0bG5nMi5sYXQgLSBsYXRsbmcxLmxhdCkgKiByYWQgLyAyKSxcblx0XHQgICAgc2luRExvbiA9IE1hdGguc2luKChsYXRsbmcyLmxuZyAtIGxhdGxuZzEubG5nKSAqIHJhZCAvIDIpLFxuXHRcdCAgICBhID0gc2luRExhdCAqIHNpbkRMYXQgKyBNYXRoLmNvcyhsYXQxKSAqIE1hdGguY29zKGxhdDIpICogc2luRExvbiAqIHNpbkRMb24sXG5cdFx0ICAgIGMgPSAyICogTWF0aC5hdGFuMihNYXRoLnNxcnQoYSksIE1hdGguc3FydCgxIC0gYSkpO1xuXHRcdHJldHVybiB0aGlzLlIgKiBjO1xuXHR9XG59KTtcblxuLypcclxuICogQG5hbWVzcGFjZSBQcm9qZWN0aW9uXHJcbiAqIEBwcm9qZWN0aW9uIEwuUHJvamVjdGlvbi5TcGhlcmljYWxNZXJjYXRvclxyXG4gKlxyXG4gKiBTcGhlcmljYWwgTWVyY2F0b3IgcHJvamVjdGlvbiDigJQgdGhlIG1vc3QgY29tbW9uIHByb2plY3Rpb24gZm9yIG9ubGluZSBtYXBzLFxyXG4gKiB1c2VkIGJ5IGFsbW9zdCBhbGwgZnJlZSBhbmQgY29tbWVyY2lhbCB0aWxlIHByb3ZpZGVycy4gQXNzdW1lcyB0aGF0IEVhcnRoIGlzXHJcbiAqIGEgc3BoZXJlLiBVc2VkIGJ5IHRoZSBgRVBTRzozODU3YCBDUlMuXHJcbiAqL1xyXG5cclxudmFyIFNwaGVyaWNhbE1lcmNhdG9yID0ge1xyXG5cclxuXHRSOiA2Mzc4MTM3LFxyXG5cdE1BWF9MQVRJVFVERTogODUuMDUxMTI4Nzc5OCxcclxuXHJcblx0cHJvamVjdDogZnVuY3Rpb24gKGxhdGxuZykge1xyXG5cdFx0dmFyIGQgPSBNYXRoLlBJIC8gMTgwLFxyXG5cdFx0ICAgIG1heCA9IHRoaXMuTUFYX0xBVElUVURFLFxyXG5cdFx0ICAgIGxhdCA9IE1hdGgubWF4KE1hdGgubWluKG1heCwgbGF0bG5nLmxhdCksIC1tYXgpLFxyXG5cdFx0ICAgIHNpbiA9IE1hdGguc2luKGxhdCAqIGQpO1xyXG5cclxuXHRcdHJldHVybiBuZXcgUG9pbnQoXHJcblx0XHRcdHRoaXMuUiAqIGxhdGxuZy5sbmcgKiBkLFxyXG5cdFx0XHR0aGlzLlIgKiBNYXRoLmxvZygoMSArIHNpbikgLyAoMSAtIHNpbikpIC8gMik7XHJcblx0fSxcclxuXHJcblx0dW5wcm9qZWN0OiBmdW5jdGlvbiAocG9pbnQpIHtcclxuXHRcdHZhciBkID0gMTgwIC8gTWF0aC5QSTtcclxuXHJcblx0XHRyZXR1cm4gbmV3IExhdExuZyhcclxuXHRcdFx0KDIgKiBNYXRoLmF0YW4oTWF0aC5leHAocG9pbnQueSAvIHRoaXMuUikpIC0gKE1hdGguUEkgLyAyKSkgKiBkLFxyXG5cdFx0XHRwb2ludC54ICogZCAvIHRoaXMuUik7XHJcblx0fSxcclxuXHJcblx0Ym91bmRzOiAoZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGQgPSA2Mzc4MTM3ICogTWF0aC5QSTtcclxuXHRcdHJldHVybiBuZXcgQm91bmRzKFstZCwgLWRdLCBbZCwgZF0pO1xyXG5cdH0pKClcclxufTtcblxuLypcclxuICogQGNsYXNzIFRyYW5zZm9ybWF0aW9uXHJcbiAqIEBha2EgTC5UcmFuc2Zvcm1hdGlvblxyXG4gKlxyXG4gKiBSZXByZXNlbnRzIGFuIGFmZmluZSB0cmFuc2Zvcm1hdGlvbjogYSBzZXQgb2YgY29lZmZpY2llbnRzIGBhYCwgYGJgLCBgY2AsIGBkYFxyXG4gKiBmb3IgdHJhbnNmb3JtaW5nIGEgcG9pbnQgb2YgYSBmb3JtIGAoeCwgeSlgIGludG8gYChhKnggKyBiLCBjKnkgKyBkKWAgYW5kIGRvaW5nXHJcbiAqIHRoZSByZXZlcnNlLiBVc2VkIGJ5IExlYWZsZXQgaW4gaXRzIHByb2plY3Rpb25zIGNvZGUuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHZhciB0cmFuc2Zvcm1hdGlvbiA9IEwudHJhbnNmb3JtYXRpb24oMiwgNSwgLTEsIDEwKSxcclxuICogXHRwID0gTC5wb2ludCgxLCAyKSxcclxuICogXHRwMiA9IHRyYW5zZm9ybWF0aW9uLnRyYW5zZm9ybShwKSwgLy8gIEwucG9pbnQoNywgOClcclxuICogXHRwMyA9IHRyYW5zZm9ybWF0aW9uLnVudHJhbnNmb3JtKHAyKTsgLy8gIEwucG9pbnQoMSwgMilcclxuICogYGBgXHJcbiAqL1xyXG5cclxuXHJcbi8vIGZhY3RvcnkgbmV3IEwuVHJhbnNmb3JtYXRpb24oYTogTnVtYmVyLCBiOiBOdW1iZXIsIGM6IE51bWJlciwgZDogTnVtYmVyKVxyXG4vLyBDcmVhdGVzIGEgYFRyYW5zZm9ybWF0aW9uYCBvYmplY3Qgd2l0aCB0aGUgZ2l2ZW4gY29lZmZpY2llbnRzLlxyXG5mdW5jdGlvbiBUcmFuc2Zvcm1hdGlvbihhLCBiLCBjLCBkKSB7XHJcblx0aWYgKGlzQXJyYXkoYSkpIHtcclxuXHRcdC8vIHVzZSBhcnJheSBwcm9wZXJ0aWVzXHJcblx0XHR0aGlzLl9hID0gYVswXTtcclxuXHRcdHRoaXMuX2IgPSBhWzFdO1xyXG5cdFx0dGhpcy5fYyA9IGFbMl07XHJcblx0XHR0aGlzLl9kID0gYVszXTtcclxuXHRcdHJldHVybjtcclxuXHR9XHJcblx0dGhpcy5fYSA9IGE7XHJcblx0dGhpcy5fYiA9IGI7XHJcblx0dGhpcy5fYyA9IGM7XHJcblx0dGhpcy5fZCA9IGQ7XHJcbn1cclxuXHJcblRyYW5zZm9ybWF0aW9uLnByb3RvdHlwZSA9IHtcclxuXHQvLyBAbWV0aG9kIHRyYW5zZm9ybShwb2ludDogUG9pbnQsIHNjYWxlPzogTnVtYmVyKTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIGEgdHJhbnNmb3JtZWQgcG9pbnQsIG9wdGlvbmFsbHkgbXVsdGlwbGllZCBieSB0aGUgZ2l2ZW4gc2NhbGUuXHJcblx0Ly8gT25seSBhY2NlcHRzIGFjdHVhbCBgTC5Qb2ludGAgaW5zdGFuY2VzLCBub3QgYXJyYXlzLlxyXG5cdHRyYW5zZm9ybTogZnVuY3Rpb24gKHBvaW50LCBzY2FsZSkgeyAvLyAoUG9pbnQsIE51bWJlcikgLT4gUG9pbnRcclxuXHRcdHJldHVybiB0aGlzLl90cmFuc2Zvcm0ocG9pbnQuY2xvbmUoKSwgc2NhbGUpO1xyXG5cdH0sXHJcblxyXG5cdC8vIGRlc3RydWN0aXZlIHRyYW5zZm9ybSAoZmFzdGVyKVxyXG5cdF90cmFuc2Zvcm06IGZ1bmN0aW9uIChwb2ludCwgc2NhbGUpIHtcclxuXHRcdHNjYWxlID0gc2NhbGUgfHwgMTtcclxuXHRcdHBvaW50LnggPSBzY2FsZSAqICh0aGlzLl9hICogcG9pbnQueCArIHRoaXMuX2IpO1xyXG5cdFx0cG9pbnQueSA9IHNjYWxlICogKHRoaXMuX2MgKiBwb2ludC55ICsgdGhpcy5fZCk7XHJcblx0XHRyZXR1cm4gcG9pbnQ7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB1bnRyYW5zZm9ybShwb2ludDogUG9pbnQsIHNjYWxlPzogTnVtYmVyKTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIHRoZSByZXZlcnNlIHRyYW5zZm9ybWF0aW9uIG9mIHRoZSBnaXZlbiBwb2ludCwgb3B0aW9uYWxseSBkaXZpZGVkXHJcblx0Ly8gYnkgdGhlIGdpdmVuIHNjYWxlLiBPbmx5IGFjY2VwdHMgYWN0dWFsIGBMLlBvaW50YCBpbnN0YW5jZXMsIG5vdCBhcnJheXMuXHJcblx0dW50cmFuc2Zvcm06IGZ1bmN0aW9uIChwb2ludCwgc2NhbGUpIHtcclxuXHRcdHNjYWxlID0gc2NhbGUgfHwgMTtcclxuXHRcdHJldHVybiBuZXcgUG9pbnQoXHJcblx0XHQgICAgICAgIChwb2ludC54IC8gc2NhbGUgLSB0aGlzLl9iKSAvIHRoaXMuX2EsXHJcblx0XHQgICAgICAgIChwb2ludC55IC8gc2NhbGUgLSB0aGlzLl9kKSAvIHRoaXMuX2MpO1xyXG5cdH1cclxufTtcclxuXHJcbi8vIGZhY3RvcnkgTC50cmFuc2Zvcm1hdGlvbihhOiBOdW1iZXIsIGI6IE51bWJlciwgYzogTnVtYmVyLCBkOiBOdW1iZXIpXHJcblxyXG4vLyBAZmFjdG9yeSBMLnRyYW5zZm9ybWF0aW9uKGE6IE51bWJlciwgYjogTnVtYmVyLCBjOiBOdW1iZXIsIGQ6IE51bWJlcilcclxuLy8gSW5zdGFudGlhdGVzIGEgVHJhbnNmb3JtYXRpb24gb2JqZWN0IHdpdGggdGhlIGdpdmVuIGNvZWZmaWNpZW50cy5cclxuXHJcbi8vIEBhbHRlcm5hdGl2ZVxyXG4vLyBAZmFjdG9yeSBMLnRyYW5zZm9ybWF0aW9uKGNvZWZmaWNpZW50czogQXJyYXkpOiBUcmFuc2Zvcm1hdGlvblxyXG4vLyBFeHBlY3RzIGFuIGNvZWZmaWNpZW50cyBhcnJheSBvZiB0aGUgZm9ybVxyXG4vLyBgW2E6IE51bWJlciwgYjogTnVtYmVyLCBjOiBOdW1iZXIsIGQ6IE51bWJlcl1gLlxyXG5cclxuZnVuY3Rpb24gdG9UcmFuc2Zvcm1hdGlvbihhLCBiLCBjLCBkKSB7XHJcblx0cmV0dXJuIG5ldyBUcmFuc2Zvcm1hdGlvbihhLCBiLCBjLCBkKTtcclxufVxuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIENSU1xyXG4gKiBAY3JzIEwuQ1JTLkVQU0czODU3XHJcbiAqXHJcbiAqIFRoZSBtb3N0IGNvbW1vbiBDUlMgZm9yIG9ubGluZSBtYXBzLCB1c2VkIGJ5IGFsbW9zdCBhbGwgZnJlZSBhbmQgY29tbWVyY2lhbFxyXG4gKiB0aWxlIHByb3ZpZGVycy4gVXNlcyBTcGhlcmljYWwgTWVyY2F0b3IgcHJvamVjdGlvbi4gU2V0IGluIGJ5IGRlZmF1bHQgaW5cclxuICogTWFwJ3MgYGNyc2Agb3B0aW9uLlxyXG4gKi9cclxuXHJcbnZhciBFUFNHMzg1NyA9IGV4dGVuZCh7fSwgRWFydGgsIHtcclxuXHRjb2RlOiAnRVBTRzozODU3JyxcclxuXHRwcm9qZWN0aW9uOiBTcGhlcmljYWxNZXJjYXRvcixcclxuXHJcblx0dHJhbnNmb3JtYXRpb246IChmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgc2NhbGUgPSAwLjUgLyAoTWF0aC5QSSAqIFNwaGVyaWNhbE1lcmNhdG9yLlIpO1xyXG5cdFx0cmV0dXJuIHRvVHJhbnNmb3JtYXRpb24oc2NhbGUsIDAuNSwgLXNjYWxlLCAwLjUpO1xyXG5cdH0oKSlcclxufSk7XHJcblxyXG52YXIgRVBTRzkwMDkxMyA9IGV4dGVuZCh7fSwgRVBTRzM4NTcsIHtcclxuXHRjb2RlOiAnRVBTRzo5MDA5MTMnXHJcbn0pO1xuXG4vLyBAbmFtZXNwYWNlIFNWRzsgQHNlY3Rpb25cbi8vIFRoZXJlIGFyZSBzZXZlcmFsIHN0YXRpYyBmdW5jdGlvbnMgd2hpY2ggY2FuIGJlIGNhbGxlZCB3aXRob3V0IGluc3RhbnRpYXRpbmcgTC5TVkc6XG5cbi8vIEBmdW5jdGlvbiBjcmVhdGUobmFtZTogU3RyaW5nKTogU1ZHRWxlbWVudFxuLy8gUmV0dXJucyBhIGluc3RhbmNlIG9mIFtTVkdFbGVtZW50XShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9BUEkvU1ZHRWxlbWVudCksXG4vLyBjb3JyZXNwb25kaW5nIHRvIHRoZSBjbGFzcyBuYW1lIHBhc3NlZC4gRm9yIGV4YW1wbGUsIHVzaW5nICdsaW5lJyB3aWxsIHJldHVyblxuLy8gYW4gaW5zdGFuY2Ugb2YgW1NWR0xpbmVFbGVtZW50XShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9BUEkvU1ZHTGluZUVsZW1lbnQpLlxuZnVuY3Rpb24gc3ZnQ3JlYXRlKG5hbWUpIHtcblx0cmV0dXJuIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUygnaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnLCBuYW1lKTtcbn1cblxuLy8gQGZ1bmN0aW9uIHBvaW50c1RvUGF0aChyaW5nczogUG9pbnRbXSwgY2xvc2VkOiBCb29sZWFuKTogU3RyaW5nXG4vLyBHZW5lcmF0ZXMgYSBTVkcgcGF0aCBzdHJpbmcgZm9yIG11bHRpcGxlIHJpbmdzLCB3aXRoIGVhY2ggcmluZyB0dXJuaW5nXG4vLyBpbnRvIFwiTS4uTC4uTC4uXCIgaW5zdHJ1Y3Rpb25zXG5mdW5jdGlvbiBwb2ludHNUb1BhdGgocmluZ3MsIGNsb3NlZCkge1xuXHR2YXIgc3RyID0gJycsXG5cdGksIGosIGxlbiwgbGVuMiwgcG9pbnRzLCBwO1xuXG5cdGZvciAoaSA9IDAsIGxlbiA9IHJpbmdzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0cG9pbnRzID0gcmluZ3NbaV07XG5cblx0XHRmb3IgKGogPSAwLCBsZW4yID0gcG9pbnRzLmxlbmd0aDsgaiA8IGxlbjI7IGorKykge1xuXHRcdFx0cCA9IHBvaW50c1tqXTtcblx0XHRcdHN0ciArPSAoaiA/ICdMJyA6ICdNJykgKyBwLnggKyAnICcgKyBwLnk7XG5cdFx0fVxuXG5cdFx0Ly8gY2xvc2VzIHRoZSByaW5nIGZvciBwb2x5Z29uczsgXCJ4XCIgaXMgVk1MIHN5bnRheFxuXHRcdHN0ciArPSBjbG9zZWQgPyAoc3ZnID8gJ3onIDogJ3gnKSA6ICcnO1xuXHR9XG5cblx0Ly8gU1ZHIGNvbXBsYWlucyBhYm91dCBlbXB0eSBwYXRoIHN0cmluZ3Ncblx0cmV0dXJuIHN0ciB8fCAnTTAgMCc7XG59XG5cbi8qXHJcbiAqIEBuYW1lc3BhY2UgQnJvd3NlclxyXG4gKiBAYWthIEwuQnJvd3NlclxyXG4gKlxyXG4gKiBBIG5hbWVzcGFjZSB3aXRoIHN0YXRpYyBwcm9wZXJ0aWVzIGZvciBicm93c2VyL2ZlYXR1cmUgZGV0ZWN0aW9uIHVzZWQgYnkgTGVhZmxldCBpbnRlcm5hbGx5LlxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiBpZiAoTC5Ccm93c2VyLmllbHQ5KSB7XHJcbiAqICAgYWxlcnQoJ1VwZ3JhZGUgeW91ciBicm93c2VyLCBkdWRlIScpO1xyXG4gKiB9XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcbnZhciBzdHlsZSQxID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlO1xyXG5cclxuLy8gQHByb3BlcnR5IGllOiBCb29sZWFuOyBgdHJ1ZWAgZm9yIGFsbCBJbnRlcm5ldCBFeHBsb3JlciB2ZXJzaW9ucyAobm90IEVkZ2UpLlxyXG52YXIgaWUgPSAnQWN0aXZlWE9iamVjdCcgaW4gd2luZG93O1xyXG5cclxuLy8gQHByb3BlcnR5IGllbHQ5OiBCb29sZWFuOyBgdHJ1ZWAgZm9yIEludGVybmV0IEV4cGxvcmVyIHZlcnNpb25zIGxlc3MgdGhhbiA5LlxyXG52YXIgaWVsdDkgPSBpZSAmJiAhZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcjtcclxuXHJcbi8vIEBwcm9wZXJ0eSBlZGdlOiBCb29sZWFuOyBgdHJ1ZWAgZm9yIHRoZSBFZGdlIHdlYiBicm93c2VyLlxyXG52YXIgZWRnZSA9ICdtc0xhdW5jaFVyaScgaW4gbmF2aWdhdG9yICYmICEoJ2RvY3VtZW50TW9kZScgaW4gZG9jdW1lbnQpO1xyXG5cclxuLy8gQHByb3BlcnR5IHdlYmtpdDogQm9vbGVhbjtcclxuLy8gYHRydWVgIGZvciB3ZWJraXQtYmFzZWQgYnJvd3NlcnMgbGlrZSBDaHJvbWUgYW5kIFNhZmFyaSAoaW5jbHVkaW5nIG1vYmlsZSB2ZXJzaW9ucykuXHJcbnZhciB3ZWJraXQgPSB1c2VyQWdlbnRDb250YWlucygnd2Via2l0Jyk7XHJcblxyXG4vLyBAcHJvcGVydHkgYW5kcm9pZDogQm9vbGVhblxyXG4vLyBgdHJ1ZWAgZm9yIGFueSBicm93c2VyIHJ1bm5pbmcgb24gYW4gQW5kcm9pZCBwbGF0Zm9ybS5cclxudmFyIGFuZHJvaWQgPSB1c2VyQWdlbnRDb250YWlucygnYW5kcm9pZCcpO1xyXG5cclxuLy8gQHByb3BlcnR5IGFuZHJvaWQyMzogQm9vbGVhbjsgYHRydWVgIGZvciBicm93c2VycyBydW5uaW5nIG9uIEFuZHJvaWQgMiBvciBBbmRyb2lkIDMuXHJcbnZhciBhbmRyb2lkMjMgPSB1c2VyQWdlbnRDb250YWlucygnYW5kcm9pZCAyJykgfHwgdXNlckFnZW50Q29udGFpbnMoJ2FuZHJvaWQgMycpO1xyXG5cclxuLyogU2VlIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8xNzk2MTI2NiBmb3IgZGV0YWlscyBvbiBkZXRlY3Rpbmcgc3RvY2sgQW5kcm9pZCAqL1xyXG52YXIgd2Via2l0VmVyID0gcGFyc2VJbnQoL1dlYktpdFxcLyhbMC05XSspfCQvLmV4ZWMobmF2aWdhdG9yLnVzZXJBZ2VudClbMV0sIDEwKTsgLy8gYWxzbyBtYXRjaGVzIEFwcGxlV2ViS2l0XHJcbi8vIEBwcm9wZXJ0eSBhbmRyb2lkU3RvY2s6IEJvb2xlYW47IGB0cnVlYCBmb3IgdGhlIEFuZHJvaWQgc3RvY2sgYnJvd3NlciAoaS5lLiBub3QgQ2hyb21lKVxyXG52YXIgYW5kcm9pZFN0b2NrID0gYW5kcm9pZCAmJiB1c2VyQWdlbnRDb250YWlucygnR29vZ2xlJykgJiYgd2Via2l0VmVyIDwgNTM3ICYmICEoJ0F1ZGlvTm9kZScgaW4gd2luZG93KTtcclxuXHJcbi8vIEBwcm9wZXJ0eSBvcGVyYTogQm9vbGVhbjsgYHRydWVgIGZvciB0aGUgT3BlcmEgYnJvd3NlclxyXG52YXIgb3BlcmEgPSAhIXdpbmRvdy5vcGVyYTtcclxuXHJcbi8vIEBwcm9wZXJ0eSBjaHJvbWU6IEJvb2xlYW47IGB0cnVlYCBmb3IgdGhlIENocm9tZSBicm93c2VyLlxyXG52YXIgY2hyb21lID0gdXNlckFnZW50Q29udGFpbnMoJ2Nocm9tZScpO1xyXG5cclxuLy8gQHByb3BlcnR5IGdlY2tvOiBCb29sZWFuOyBgdHJ1ZWAgZm9yIGdlY2tvLWJhc2VkIGJyb3dzZXJzIGxpa2UgRmlyZWZveC5cclxudmFyIGdlY2tvID0gdXNlckFnZW50Q29udGFpbnMoJ2dlY2tvJykgJiYgIXdlYmtpdCAmJiAhb3BlcmEgJiYgIWllO1xyXG5cclxuLy8gQHByb3BlcnR5IHNhZmFyaTogQm9vbGVhbjsgYHRydWVgIGZvciB0aGUgU2FmYXJpIGJyb3dzZXIuXHJcbnZhciBzYWZhcmkgPSAhY2hyb21lICYmIHVzZXJBZ2VudENvbnRhaW5zKCdzYWZhcmknKTtcclxuXHJcbnZhciBwaGFudG9tID0gdXNlckFnZW50Q29udGFpbnMoJ3BoYW50b20nKTtcclxuXHJcbi8vIEBwcm9wZXJ0eSBvcGVyYTEyOiBCb29sZWFuXHJcbi8vIGB0cnVlYCBmb3IgdGhlIE9wZXJhIGJyb3dzZXIgc3VwcG9ydGluZyBDU1MgdHJhbnNmb3JtcyAodmVyc2lvbiAxMiBvciBsYXRlcikuXHJcbnZhciBvcGVyYTEyID0gJ09UcmFuc2l0aW9uJyBpbiBzdHlsZSQxO1xyXG5cclxuLy8gQHByb3BlcnR5IHdpbjogQm9vbGVhbjsgYHRydWVgIHdoZW4gdGhlIGJyb3dzZXIgaXMgcnVubmluZyBpbiBhIFdpbmRvd3MgcGxhdGZvcm1cclxudmFyIHdpbiA9IG5hdmlnYXRvci5wbGF0Zm9ybS5pbmRleE9mKCdXaW4nKSA9PT0gMDtcclxuXHJcbi8vIEBwcm9wZXJ0eSBpZTNkOiBCb29sZWFuOyBgdHJ1ZWAgZm9yIGFsbCBJbnRlcm5ldCBFeHBsb3JlciB2ZXJzaW9ucyBzdXBwb3J0aW5nIENTUyB0cmFuc2Zvcm1zLlxyXG52YXIgaWUzZCA9IGllICYmICgndHJhbnNpdGlvbicgaW4gc3R5bGUkMSk7XHJcblxyXG4vLyBAcHJvcGVydHkgd2Via2l0M2Q6IEJvb2xlYW47IGB0cnVlYCBmb3Igd2Via2l0LWJhc2VkIGJyb3dzZXJzIHN1cHBvcnRpbmcgQ1NTIHRyYW5zZm9ybXMuXHJcbnZhciB3ZWJraXQzZCA9ICgnV2ViS2l0Q1NTTWF0cml4JyBpbiB3aW5kb3cpICYmICgnbTExJyBpbiBuZXcgd2luZG93LldlYktpdENTU01hdHJpeCgpKSAmJiAhYW5kcm9pZDIzO1xyXG5cclxuLy8gQHByb3BlcnR5IGdlY2tvM2Q6IEJvb2xlYW47IGB0cnVlYCBmb3IgZ2Vja28tYmFzZWQgYnJvd3NlcnMgc3VwcG9ydGluZyBDU1MgdHJhbnNmb3Jtcy5cclxudmFyIGdlY2tvM2QgPSAnTW96UGVyc3BlY3RpdmUnIGluIHN0eWxlJDE7XHJcblxyXG4vLyBAcHJvcGVydHkgYW55M2Q6IEJvb2xlYW5cclxuLy8gYHRydWVgIGZvciBhbGwgYnJvd3NlcnMgc3VwcG9ydGluZyBDU1MgdHJhbnNmb3Jtcy5cclxudmFyIGFueTNkID0gIXdpbmRvdy5MX0RJU0FCTEVfM0QgJiYgKGllM2QgfHwgd2Via2l0M2QgfHwgZ2Vja28zZCkgJiYgIW9wZXJhMTIgJiYgIXBoYW50b207XHJcblxyXG4vLyBAcHJvcGVydHkgbW9iaWxlOiBCb29sZWFuOyBgdHJ1ZWAgZm9yIGFsbCBicm93c2VycyBydW5uaW5nIGluIGEgbW9iaWxlIGRldmljZS5cclxudmFyIG1vYmlsZSA9IHR5cGVvZiBvcmllbnRhdGlvbiAhPT0gJ3VuZGVmaW5lZCcgfHwgdXNlckFnZW50Q29udGFpbnMoJ21vYmlsZScpO1xyXG5cclxuLy8gQHByb3BlcnR5IG1vYmlsZVdlYmtpdDogQm9vbGVhbjsgYHRydWVgIGZvciBhbGwgd2Via2l0LWJhc2VkIGJyb3dzZXJzIGluIGEgbW9iaWxlIGRldmljZS5cclxudmFyIG1vYmlsZVdlYmtpdCA9IG1vYmlsZSAmJiB3ZWJraXQ7XHJcblxyXG4vLyBAcHJvcGVydHkgbW9iaWxlV2Via2l0M2Q6IEJvb2xlYW5cclxuLy8gYHRydWVgIGZvciBhbGwgd2Via2l0LWJhc2VkIGJyb3dzZXJzIGluIGEgbW9iaWxlIGRldmljZSBzdXBwb3J0aW5nIENTUyB0cmFuc2Zvcm1zLlxyXG52YXIgbW9iaWxlV2Via2l0M2QgPSBtb2JpbGUgJiYgd2Via2l0M2Q7XHJcblxyXG4vLyBAcHJvcGVydHkgbXNQb2ludGVyOiBCb29sZWFuXHJcbi8vIGB0cnVlYCBmb3IgYnJvd3NlcnMgaW1wbGVtZW50aW5nIHRoZSBNaWNyb3NvZnQgdG91Y2ggZXZlbnRzIG1vZGVsIChub3RhYmx5IElFMTApLlxyXG52YXIgbXNQb2ludGVyID0gIXdpbmRvdy5Qb2ludGVyRXZlbnQgJiYgd2luZG93Lk1TUG9pbnRlckV2ZW50O1xyXG5cclxuLy8gQHByb3BlcnR5IHBvaW50ZXI6IEJvb2xlYW5cclxuLy8gYHRydWVgIGZvciBhbGwgYnJvd3NlcnMgc3VwcG9ydGluZyBbcG9pbnRlciBldmVudHNdKGh0dHBzOi8vbXNkbi5taWNyb3NvZnQuY29tL2VuLXVzL2xpYnJhcnkvZG40MzMyNDQlMjh2PXZzLjg1JTI5LmFzcHgpLlxyXG52YXIgcG9pbnRlciA9ICEhKHdpbmRvdy5Qb2ludGVyRXZlbnQgfHwgbXNQb2ludGVyKTtcclxuXHJcbi8vIEBwcm9wZXJ0eSB0b3VjaDogQm9vbGVhblxyXG4vLyBgdHJ1ZWAgZm9yIGFsbCBicm93c2VycyBzdXBwb3J0aW5nIFt0b3VjaCBldmVudHNdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL0FQSS9Ub3VjaF9ldmVudHMpLlxyXG4vLyBUaGlzIGRvZXMgbm90IG5lY2Vzc2FyaWx5IG1lYW4gdGhhdCB0aGUgYnJvd3NlciBpcyBydW5uaW5nIGluIGEgY29tcHV0ZXIgd2l0aFxyXG4vLyBhIHRvdWNoc2NyZWVuLCBpdCBvbmx5IG1lYW5zIHRoYXQgdGhlIGJyb3dzZXIgaXMgY2FwYWJsZSBvZiB1bmRlcnN0YW5kaW5nXHJcbi8vIHRvdWNoIGV2ZW50cy5cclxudmFyIHRvdWNoID0gIXdpbmRvdy5MX05PX1RPVUNIICYmIChwb2ludGVyIHx8ICdvbnRvdWNoc3RhcnQnIGluIHdpbmRvdyB8fFxyXG5cdFx0KHdpbmRvdy5Eb2N1bWVudFRvdWNoICYmIGRvY3VtZW50IGluc3RhbmNlb2Ygd2luZG93LkRvY3VtZW50VG91Y2gpKTtcclxuXHJcbi8vIEBwcm9wZXJ0eSBtb2JpbGVPcGVyYTogQm9vbGVhbjsgYHRydWVgIGZvciB0aGUgT3BlcmEgYnJvd3NlciBpbiBhIG1vYmlsZSBkZXZpY2UuXHJcbnZhciBtb2JpbGVPcGVyYSA9IG1vYmlsZSAmJiBvcGVyYTtcclxuXHJcbi8vIEBwcm9wZXJ0eSBtb2JpbGVHZWNrbzogQm9vbGVhblxyXG4vLyBgdHJ1ZWAgZm9yIGdlY2tvLWJhc2VkIGJyb3dzZXJzIHJ1bm5pbmcgaW4gYSBtb2JpbGUgZGV2aWNlLlxyXG52YXIgbW9iaWxlR2Vja28gPSBtb2JpbGUgJiYgZ2Vja287XHJcblxyXG4vLyBAcHJvcGVydHkgcmV0aW5hOiBCb29sZWFuXHJcbi8vIGB0cnVlYCBmb3IgYnJvd3NlcnMgb24gYSBoaWdoLXJlc29sdXRpb24gXCJyZXRpbmFcIiBzY3JlZW4uXHJcbnZhciByZXRpbmEgPSAod2luZG93LmRldmljZVBpeGVsUmF0aW8gfHwgKHdpbmRvdy5zY3JlZW4uZGV2aWNlWERQSSAvIHdpbmRvdy5zY3JlZW4ubG9naWNhbFhEUEkpKSA+IDE7XHJcblxyXG5cclxuLy8gQHByb3BlcnR5IGNhbnZhczogQm9vbGVhblxyXG4vLyBgdHJ1ZWAgd2hlbiB0aGUgYnJvd3NlciBzdXBwb3J0cyBbYDxjYW52YXM+YF0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvQVBJL0NhbnZhc19BUEkpLlxyXG52YXIgY2FudmFzID0gKGZ1bmN0aW9uICgpIHtcclxuXHRyZXR1cm4gISFkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKS5nZXRDb250ZXh0O1xyXG59KCkpO1xyXG5cclxuLy8gQHByb3BlcnR5IHN2ZzogQm9vbGVhblxyXG4vLyBgdHJ1ZWAgd2hlbiB0aGUgYnJvd3NlciBzdXBwb3J0cyBbU1ZHXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9TVkcpLlxyXG52YXIgc3ZnID0gISEoZG9jdW1lbnQuY3JlYXRlRWxlbWVudE5TICYmIHN2Z0NyZWF0ZSgnc3ZnJykuY3JlYXRlU1ZHUmVjdCk7XHJcblxyXG4vLyBAcHJvcGVydHkgdm1sOiBCb29sZWFuXHJcbi8vIGB0cnVlYCBpZiB0aGUgYnJvd3NlciBzdXBwb3J0cyBbVk1MXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9WZWN0b3JfTWFya3VwX0xhbmd1YWdlKS5cclxudmFyIHZtbCA9ICFzdmcgJiYgKGZ1bmN0aW9uICgpIHtcclxuXHR0cnkge1xyXG5cdFx0dmFyIGRpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG5cdFx0ZGl2LmlubmVySFRNTCA9ICc8djpzaGFwZSBhZGo9XCIxXCIvPic7XHJcblxyXG5cdFx0dmFyIHNoYXBlID0gZGl2LmZpcnN0Q2hpbGQ7XHJcblx0XHRzaGFwZS5zdHlsZS5iZWhhdmlvciA9ICd1cmwoI2RlZmF1bHQjVk1MKSc7XHJcblxyXG5cdFx0cmV0dXJuIHNoYXBlICYmICh0eXBlb2Ygc2hhcGUuYWRqID09PSAnb2JqZWN0Jyk7XHJcblxyXG5cdH0gY2F0Y2ggKGUpIHtcclxuXHRcdHJldHVybiBmYWxzZTtcclxuXHR9XHJcbn0oKSk7XHJcblxyXG5cclxuZnVuY3Rpb24gdXNlckFnZW50Q29udGFpbnMoc3RyKSB7XHJcblx0cmV0dXJuIG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5pbmRleE9mKHN0cikgPj0gMDtcclxufVxyXG5cblxudmFyIEJyb3dzZXIgPSAoT2JqZWN0LmZyZWV6ZSB8fCBPYmplY3QpKHtcblx0aWU6IGllLFxuXHRpZWx0OTogaWVsdDksXG5cdGVkZ2U6IGVkZ2UsXG5cdHdlYmtpdDogd2Via2l0LFxuXHRhbmRyb2lkOiBhbmRyb2lkLFxuXHRhbmRyb2lkMjM6IGFuZHJvaWQyMyxcblx0YW5kcm9pZFN0b2NrOiBhbmRyb2lkU3RvY2ssXG5cdG9wZXJhOiBvcGVyYSxcblx0Y2hyb21lOiBjaHJvbWUsXG5cdGdlY2tvOiBnZWNrbyxcblx0c2FmYXJpOiBzYWZhcmksXG5cdHBoYW50b206IHBoYW50b20sXG5cdG9wZXJhMTI6IG9wZXJhMTIsXG5cdHdpbjogd2luLFxuXHRpZTNkOiBpZTNkLFxuXHR3ZWJraXQzZDogd2Via2l0M2QsXG5cdGdlY2tvM2Q6IGdlY2tvM2QsXG5cdGFueTNkOiBhbnkzZCxcblx0bW9iaWxlOiBtb2JpbGUsXG5cdG1vYmlsZVdlYmtpdDogbW9iaWxlV2Via2l0LFxuXHRtb2JpbGVXZWJraXQzZDogbW9iaWxlV2Via2l0M2QsXG5cdG1zUG9pbnRlcjogbXNQb2ludGVyLFxuXHRwb2ludGVyOiBwb2ludGVyLFxuXHR0b3VjaDogdG91Y2gsXG5cdG1vYmlsZU9wZXJhOiBtb2JpbGVPcGVyYSxcblx0bW9iaWxlR2Vja286IG1vYmlsZUdlY2tvLFxuXHRyZXRpbmE6IHJldGluYSxcblx0Y2FudmFzOiBjYW52YXMsXG5cdHN2Zzogc3ZnLFxuXHR2bWw6IHZtbFxufSk7XG5cbi8qXG4gKiBFeHRlbmRzIEwuRG9tRXZlbnQgdG8gcHJvdmlkZSB0b3VjaCBzdXBwb3J0IGZvciBJbnRlcm5ldCBFeHBsb3JlciBhbmQgV2luZG93cy1iYXNlZCBkZXZpY2VzLlxuICovXG5cblxudmFyIFBPSU5URVJfRE9XTiA9ICAgbXNQb2ludGVyID8gJ01TUG9pbnRlckRvd24nICAgOiAncG9pbnRlcmRvd24nO1xudmFyIFBPSU5URVJfTU9WRSA9ICAgbXNQb2ludGVyID8gJ01TUG9pbnRlck1vdmUnICAgOiAncG9pbnRlcm1vdmUnO1xudmFyIFBPSU5URVJfVVAgPSAgICAgbXNQb2ludGVyID8gJ01TUG9pbnRlclVwJyAgICAgOiAncG9pbnRlcnVwJztcbnZhciBQT0lOVEVSX0NBTkNFTCA9IG1zUG9pbnRlciA/ICdNU1BvaW50ZXJDYW5jZWwnIDogJ3BvaW50ZXJjYW5jZWwnO1xudmFyIFRBR19XSElURV9MSVNUID0gWydJTlBVVCcsICdTRUxFQ1QnLCAnT1BUSU9OJ107XG5cbnZhciBfcG9pbnRlcnMgPSB7fTtcbnZhciBfcG9pbnRlckRvY0xpc3RlbmVyID0gZmFsc2U7XG5cbi8vIERvbUV2ZW50LkRvdWJsZVRhcCBuZWVkcyB0byBrbm93IGFib3V0IHRoaXNcbnZhciBfcG9pbnRlcnNDb3VudCA9IDA7XG5cbi8vIFByb3ZpZGVzIGEgdG91Y2ggZXZlbnRzIHdyYXBwZXIgZm9yIChtcylwb2ludGVyIGV2ZW50cy5cbi8vIHJlZiBodHRwOi8vd3d3LnczLm9yZy9UUi9wb2ludGVyZXZlbnRzLyBodHRwczovL3d3dy53My5vcmcvQnVncy9QdWJsaWMvc2hvd19idWcuY2dpP2lkPTIyODkwXG5cbmZ1bmN0aW9uIGFkZFBvaW50ZXJMaXN0ZW5lcihvYmosIHR5cGUsIGhhbmRsZXIsIGlkKSB7XG5cdGlmICh0eXBlID09PSAndG91Y2hzdGFydCcpIHtcblx0XHRfYWRkUG9pbnRlclN0YXJ0KG9iaiwgaGFuZGxlciwgaWQpO1xuXG5cdH0gZWxzZSBpZiAodHlwZSA9PT0gJ3RvdWNobW92ZScpIHtcblx0XHRfYWRkUG9pbnRlck1vdmUob2JqLCBoYW5kbGVyLCBpZCk7XG5cblx0fSBlbHNlIGlmICh0eXBlID09PSAndG91Y2hlbmQnKSB7XG5cdFx0X2FkZFBvaW50ZXJFbmQob2JqLCBoYW5kbGVyLCBpZCk7XG5cdH1cblxuXHRyZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gcmVtb3ZlUG9pbnRlckxpc3RlbmVyKG9iaiwgdHlwZSwgaWQpIHtcblx0dmFyIGhhbmRsZXIgPSBvYmpbJ19sZWFmbGV0XycgKyB0eXBlICsgaWRdO1xuXG5cdGlmICh0eXBlID09PSAndG91Y2hzdGFydCcpIHtcblx0XHRvYmoucmVtb3ZlRXZlbnRMaXN0ZW5lcihQT0lOVEVSX0RPV04sIGhhbmRsZXIsIGZhbHNlKTtcblxuXHR9IGVsc2UgaWYgKHR5cGUgPT09ICd0b3VjaG1vdmUnKSB7XG5cdFx0b2JqLnJlbW92ZUV2ZW50TGlzdGVuZXIoUE9JTlRFUl9NT1ZFLCBoYW5kbGVyLCBmYWxzZSk7XG5cblx0fSBlbHNlIGlmICh0eXBlID09PSAndG91Y2hlbmQnKSB7XG5cdFx0b2JqLnJlbW92ZUV2ZW50TGlzdGVuZXIoUE9JTlRFUl9VUCwgaGFuZGxlciwgZmFsc2UpO1xuXHRcdG9iai5yZW1vdmVFdmVudExpc3RlbmVyKFBPSU5URVJfQ0FOQ0VMLCBoYW5kbGVyLCBmYWxzZSk7XG5cdH1cblxuXHRyZXR1cm4gdGhpcztcbn1cblxuZnVuY3Rpb24gX2FkZFBvaW50ZXJTdGFydChvYmosIGhhbmRsZXIsIGlkKSB7XG5cdHZhciBvbkRvd24gPSBiaW5kKGZ1bmN0aW9uIChlKSB7XG5cdFx0aWYgKGUucG9pbnRlclR5cGUgIT09ICdtb3VzZScgJiYgZS5NU1BPSU5URVJfVFlQRV9NT1VTRSAmJiBlLnBvaW50ZXJUeXBlICE9PSBlLk1TUE9JTlRFUl9UWVBFX01PVVNFKSB7XG5cdFx0XHQvLyBJbiBJRTExLCBzb21lIHRvdWNoIGV2ZW50cyBuZWVkcyB0byBmaXJlIGZvciBmb3JtIGNvbnRyb2xzLCBvclxuXHRcdFx0Ly8gdGhlIGNvbnRyb2xzIHdpbGwgc3RvcCB3b3JraW5nLiBXZSBrZWVwIGEgd2hpdGVsaXN0IG9mIHRhZyBuYW1lcyB0aGF0XG5cdFx0XHQvLyBuZWVkIHRoZXNlIGV2ZW50cy4gRm9yIG90aGVyIHRhcmdldCB0YWdzLCB3ZSBwcmV2ZW50IGRlZmF1bHQgb24gdGhlIGV2ZW50LlxuXHRcdFx0aWYgKFRBR19XSElURV9MSVNULmluZGV4T2YoZS50YXJnZXQudGFnTmFtZSkgPCAwKSB7XG5cdFx0XHRcdHByZXZlbnREZWZhdWx0KGUpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdF9oYW5kbGVQb2ludGVyKGUsIGhhbmRsZXIpO1xuXHR9KTtcblxuXHRvYmpbJ19sZWFmbGV0X3RvdWNoc3RhcnQnICsgaWRdID0gb25Eb3duO1xuXHRvYmouYWRkRXZlbnRMaXN0ZW5lcihQT0lOVEVSX0RPV04sIG9uRG93biwgZmFsc2UpO1xuXG5cdC8vIG5lZWQgdG8ga2VlcCB0cmFjayBvZiB3aGF0IHBvaW50ZXJzIGFuZCBob3cgbWFueSBhcmUgYWN0aXZlIHRvIHByb3ZpZGUgZS50b3VjaGVzIGVtdWxhdGlvblxuXHRpZiAoIV9wb2ludGVyRG9jTGlzdGVuZXIpIHtcblx0XHQvLyB3ZSBsaXN0ZW4gZG9jdW1lbnRFbGVtZW50IGFzIGFueSBkcmFncyB0aGF0IGVuZCBieSBtb3ZpbmcgdGhlIHRvdWNoIG9mZiB0aGUgc2NyZWVuIGdldCBmaXJlZCB0aGVyZVxuXHRcdGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5hZGRFdmVudExpc3RlbmVyKFBPSU5URVJfRE9XTiwgX2dsb2JhbFBvaW50ZXJEb3duLCB0cnVlKTtcblx0XHRkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihQT0lOVEVSX01PVkUsIF9nbG9iYWxQb2ludGVyTW92ZSwgdHJ1ZSk7XG5cdFx0ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoUE9JTlRFUl9VUCwgX2dsb2JhbFBvaW50ZXJVcCwgdHJ1ZSk7XG5cdFx0ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoUE9JTlRFUl9DQU5DRUwsIF9nbG9iYWxQb2ludGVyVXAsIHRydWUpO1xuXG5cdFx0X3BvaW50ZXJEb2NMaXN0ZW5lciA9IHRydWU7XG5cdH1cbn1cblxuZnVuY3Rpb24gX2dsb2JhbFBvaW50ZXJEb3duKGUpIHtcblx0X3BvaW50ZXJzW2UucG9pbnRlcklkXSA9IGU7XG5cdF9wb2ludGVyc0NvdW50Kys7XG59XG5cbmZ1bmN0aW9uIF9nbG9iYWxQb2ludGVyTW92ZShlKSB7XG5cdGlmIChfcG9pbnRlcnNbZS5wb2ludGVySWRdKSB7XG5cdFx0X3BvaW50ZXJzW2UucG9pbnRlcklkXSA9IGU7XG5cdH1cbn1cblxuZnVuY3Rpb24gX2dsb2JhbFBvaW50ZXJVcChlKSB7XG5cdGRlbGV0ZSBfcG9pbnRlcnNbZS5wb2ludGVySWRdO1xuXHRfcG9pbnRlcnNDb3VudC0tO1xufVxuXG5mdW5jdGlvbiBfaGFuZGxlUG9pbnRlcihlLCBoYW5kbGVyKSB7XG5cdGUudG91Y2hlcyA9IFtdO1xuXHRmb3IgKHZhciBpIGluIF9wb2ludGVycykge1xuXHRcdGUudG91Y2hlcy5wdXNoKF9wb2ludGVyc1tpXSk7XG5cdH1cblx0ZS5jaGFuZ2VkVG91Y2hlcyA9IFtlXTtcblxuXHRoYW5kbGVyKGUpO1xufVxuXG5mdW5jdGlvbiBfYWRkUG9pbnRlck1vdmUob2JqLCBoYW5kbGVyLCBpZCkge1xuXHR2YXIgb25Nb3ZlID0gZnVuY3Rpb24gKGUpIHtcblx0XHQvLyBkb24ndCBmaXJlIHRvdWNoIG1vdmVzIHdoZW4gbW91c2UgaXNuJ3QgZG93blxuXHRcdGlmICgoZS5wb2ludGVyVHlwZSA9PT0gZS5NU1BPSU5URVJfVFlQRV9NT1VTRSB8fCBlLnBvaW50ZXJUeXBlID09PSAnbW91c2UnKSAmJiBlLmJ1dHRvbnMgPT09IDApIHsgcmV0dXJuOyB9XG5cblx0XHRfaGFuZGxlUG9pbnRlcihlLCBoYW5kbGVyKTtcblx0fTtcblxuXHRvYmpbJ19sZWFmbGV0X3RvdWNobW92ZScgKyBpZF0gPSBvbk1vdmU7XG5cdG9iai5hZGRFdmVudExpc3RlbmVyKFBPSU5URVJfTU9WRSwgb25Nb3ZlLCBmYWxzZSk7XG59XG5cbmZ1bmN0aW9uIF9hZGRQb2ludGVyRW5kKG9iaiwgaGFuZGxlciwgaWQpIHtcblx0dmFyIG9uVXAgPSBmdW5jdGlvbiAoZSkge1xuXHRcdF9oYW5kbGVQb2ludGVyKGUsIGhhbmRsZXIpO1xuXHR9O1xuXG5cdG9ialsnX2xlYWZsZXRfdG91Y2hlbmQnICsgaWRdID0gb25VcDtcblx0b2JqLmFkZEV2ZW50TGlzdGVuZXIoUE9JTlRFUl9VUCwgb25VcCwgZmFsc2UpO1xuXHRvYmouYWRkRXZlbnRMaXN0ZW5lcihQT0lOVEVSX0NBTkNFTCwgb25VcCwgZmFsc2UpO1xufVxuXG4vKlxyXG4gKiBFeHRlbmRzIHRoZSBldmVudCBoYW5kbGluZyBjb2RlIHdpdGggZG91YmxlIHRhcCBzdXBwb3J0IGZvciBtb2JpbGUgYnJvd3NlcnMuXHJcbiAqL1xyXG5cclxudmFyIF90b3VjaHN0YXJ0ID0gbXNQb2ludGVyID8gJ01TUG9pbnRlckRvd24nIDogcG9pbnRlciA/ICdwb2ludGVyZG93bicgOiAndG91Y2hzdGFydCc7XHJcbnZhciBfdG91Y2hlbmQgPSBtc1BvaW50ZXIgPyAnTVNQb2ludGVyVXAnIDogcG9pbnRlciA/ICdwb2ludGVydXAnIDogJ3RvdWNoZW5kJztcclxudmFyIF9wcmUgPSAnX2xlYWZsZXRfJztcclxuXHJcbi8vIGluc3BpcmVkIGJ5IFplcHRvIHRvdWNoIGNvZGUgYnkgVGhvbWFzIEZ1Y2hzXHJcbmZ1bmN0aW9uIGFkZERvdWJsZVRhcExpc3RlbmVyKG9iaiwgaGFuZGxlciwgaWQpIHtcclxuXHR2YXIgbGFzdCwgdG91Y2gkJDEsXHJcblx0ICAgIGRvdWJsZVRhcCA9IGZhbHNlLFxyXG5cdCAgICBkZWxheSA9IDI1MDtcclxuXHJcblx0ZnVuY3Rpb24gb25Ub3VjaFN0YXJ0KGUpIHtcclxuXHRcdHZhciBjb3VudDtcclxuXHJcblx0XHRpZiAocG9pbnRlcikge1xyXG5cdFx0XHRpZiAoKCFlZGdlKSB8fCBlLnBvaW50ZXJUeXBlID09PSAnbW91c2UnKSB7IHJldHVybjsgfVxyXG5cdFx0XHRjb3VudCA9IF9wb2ludGVyc0NvdW50O1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0Y291bnQgPSBlLnRvdWNoZXMubGVuZ3RoO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChjb3VudCA+IDEpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0dmFyIG5vdyA9IERhdGUubm93KCksXHJcblx0XHQgICAgZGVsdGEgPSBub3cgLSAobGFzdCB8fCBub3cpO1xyXG5cclxuXHRcdHRvdWNoJCQxID0gZS50b3VjaGVzID8gZS50b3VjaGVzWzBdIDogZTtcclxuXHRcdGRvdWJsZVRhcCA9IChkZWx0YSA+IDAgJiYgZGVsdGEgPD0gZGVsYXkpO1xyXG5cdFx0bGFzdCA9IG5vdztcclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIG9uVG91Y2hFbmQoZSkge1xyXG5cdFx0aWYgKGRvdWJsZVRhcCAmJiAhdG91Y2gkJDEuY2FuY2VsQnViYmxlKSB7XHJcblx0XHRcdGlmIChwb2ludGVyKSB7XHJcblx0XHRcdFx0aWYgKCghZWRnZSkgfHwgZS5wb2ludGVyVHlwZSA9PT0gJ21vdXNlJykgeyByZXR1cm47IH1cclxuXHRcdFx0XHQvLyB3b3JrIGFyb3VuZCAudHlwZSBiZWluZyByZWFkb25seSB3aXRoIE1TUG9pbnRlciogZXZlbnRzXHJcblx0XHRcdFx0dmFyIG5ld1RvdWNoID0ge30sXHJcblx0XHRcdFx0ICAgIHByb3AsIGk7XHJcblxyXG5cdFx0XHRcdGZvciAoaSBpbiB0b3VjaCQkMSkge1xyXG5cdFx0XHRcdFx0cHJvcCA9IHRvdWNoJCQxW2ldO1xyXG5cdFx0XHRcdFx0bmV3VG91Y2hbaV0gPSBwcm9wICYmIHByb3AuYmluZCA/IHByb3AuYmluZCh0b3VjaCQkMSkgOiBwcm9wO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHR0b3VjaCQkMSA9IG5ld1RvdWNoO1xyXG5cdFx0XHR9XHJcblx0XHRcdHRvdWNoJCQxLnR5cGUgPSAnZGJsY2xpY2snO1xyXG5cdFx0XHRoYW5kbGVyKHRvdWNoJCQxKTtcclxuXHRcdFx0bGFzdCA9IG51bGw7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRvYmpbX3ByZSArIF90b3VjaHN0YXJ0ICsgaWRdID0gb25Ub3VjaFN0YXJ0O1xyXG5cdG9ialtfcHJlICsgX3RvdWNoZW5kICsgaWRdID0gb25Ub3VjaEVuZDtcclxuXHRvYmpbX3ByZSArICdkYmxjbGljaycgKyBpZF0gPSBoYW5kbGVyO1xyXG5cclxuXHRvYmouYWRkRXZlbnRMaXN0ZW5lcihfdG91Y2hzdGFydCwgb25Ub3VjaFN0YXJ0LCBmYWxzZSk7XHJcblx0b2JqLmFkZEV2ZW50TGlzdGVuZXIoX3RvdWNoZW5kLCBvblRvdWNoRW5kLCBmYWxzZSk7XHJcblxyXG5cdC8vIE9uIHNvbWUgcGxhdGZvcm1zIChub3RhYmx5LCBjaHJvbWU8NTUgb24gd2luMTAgKyB0b3VjaHNjcmVlbiArIG1vdXNlKSxcclxuXHQvLyB0aGUgYnJvd3NlciBkb2Vzbid0IGZpcmUgdG91Y2hlbmQvcG9pbnRlcnVwIGV2ZW50cyBidXQgZG9lcyBmaXJlXHJcblx0Ly8gbmF0aXZlIGRibGNsaWNrcy4gU2VlICM0MTI3LlxyXG5cdC8vIEVkZ2UgMTQgYWxzbyBmaXJlcyBuYXRpdmUgZGJsY2xpY2tzLCBidXQgb25seSBmb3IgcG9pbnRlclR5cGUgbW91c2UsIHNlZSAjNTE4MC5cclxuXHRvYmouYWRkRXZlbnRMaXN0ZW5lcignZGJsY2xpY2snLCBoYW5kbGVyLCBmYWxzZSk7XHJcblxyXG5cdHJldHVybiB0aGlzO1xyXG59XHJcblxyXG5mdW5jdGlvbiByZW1vdmVEb3VibGVUYXBMaXN0ZW5lcihvYmosIGlkKSB7XHJcblx0dmFyIHRvdWNoc3RhcnQgPSBvYmpbX3ByZSArIF90b3VjaHN0YXJ0ICsgaWRdLFxyXG5cdCAgICB0b3VjaGVuZCA9IG9ialtfcHJlICsgX3RvdWNoZW5kICsgaWRdLFxyXG5cdCAgICBkYmxjbGljayA9IG9ialtfcHJlICsgJ2RibGNsaWNrJyArIGlkXTtcclxuXHJcblx0b2JqLnJlbW92ZUV2ZW50TGlzdGVuZXIoX3RvdWNoc3RhcnQsIHRvdWNoc3RhcnQsIGZhbHNlKTtcclxuXHRvYmoucmVtb3ZlRXZlbnRMaXN0ZW5lcihfdG91Y2hlbmQsIHRvdWNoZW5kLCBmYWxzZSk7XHJcblx0aWYgKCFlZGdlKSB7XHJcblx0XHRvYmoucmVtb3ZlRXZlbnRMaXN0ZW5lcignZGJsY2xpY2snLCBkYmxjbGljaywgZmFsc2UpO1xyXG5cdH1cclxuXHJcblx0cmV0dXJuIHRoaXM7XHJcbn1cblxuLypcclxuICogQG5hbWVzcGFjZSBEb21FdmVudFxyXG4gKiBVdGlsaXR5IGZ1bmN0aW9ucyB0byB3b3JrIHdpdGggdGhlIFtET00gZXZlbnRzXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9BUEkvRXZlbnQpLCB1c2VkIGJ5IExlYWZsZXQgaW50ZXJuYWxseS5cclxuICovXHJcblxyXG4vLyBJbnNwaXJlZCBieSBKb2huIFJlc2lnLCBEZWFuIEVkd2FyZHMgYW5kIFlVSSBhZGRFdmVudCBpbXBsZW1lbnRhdGlvbnMuXHJcblxyXG4vLyBAZnVuY3Rpb24gb24oZWw6IEhUTUxFbGVtZW50LCB0eXBlczogU3RyaW5nLCBmbjogRnVuY3Rpb24sIGNvbnRleHQ/OiBPYmplY3QpOiB0aGlzXHJcbi8vIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiAoYGZuYCkgdG8gYSBwYXJ0aWN1bGFyIERPTSBldmVudCB0eXBlIG9mIHRoZVxyXG4vLyBlbGVtZW50IGBlbGAuIFlvdSBjYW4gb3B0aW9uYWxseSBzcGVjaWZ5IHRoZSBjb250ZXh0IG9mIHRoZSBsaXN0ZW5lclxyXG4vLyAob2JqZWN0IHRoZSBgdGhpc2Aga2V5d29yZCB3aWxsIHBvaW50IHRvKS4gWW91IGNhbiBhbHNvIHBhc3Mgc2V2ZXJhbFxyXG4vLyBzcGFjZS1zZXBhcmF0ZWQgdHlwZXMgKGUuZy4gYCdjbGljayBkYmxjbGljaydgKS5cclxuXHJcbi8vIEBhbHRlcm5hdGl2ZVxyXG4vLyBAZnVuY3Rpb24gb24oZWw6IEhUTUxFbGVtZW50LCBldmVudE1hcDogT2JqZWN0LCBjb250ZXh0PzogT2JqZWN0KTogdGhpc1xyXG4vLyBBZGRzIGEgc2V0IG9mIHR5cGUvbGlzdGVuZXIgcGFpcnMsIGUuZy4gYHtjbGljazogb25DbGljaywgbW91c2Vtb3ZlOiBvbk1vdXNlTW92ZX1gXHJcbmZ1bmN0aW9uIG9uKG9iaiwgdHlwZXMsIGZuLCBjb250ZXh0KSB7XHJcblxyXG5cdGlmICh0eXBlb2YgdHlwZXMgPT09ICdvYmplY3QnKSB7XHJcblx0XHRmb3IgKHZhciB0eXBlIGluIHR5cGVzKSB7XHJcblx0XHRcdGFkZE9uZShvYmosIHR5cGUsIHR5cGVzW3R5cGVdLCBmbik7XHJcblx0XHR9XHJcblx0fSBlbHNlIHtcclxuXHRcdHR5cGVzID0gc3BsaXRXb3Jkcyh0eXBlcyk7XHJcblxyXG5cdFx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IHR5cGVzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdGFkZE9uZShvYmosIHR5cGVzW2ldLCBmbiwgY29udGV4dCk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRyZXR1cm4gdGhpcztcclxufVxyXG5cclxudmFyIGV2ZW50c0tleSA9ICdfbGVhZmxldF9ldmVudHMnO1xyXG5cclxuLy8gQGZ1bmN0aW9uIG9mZihlbDogSFRNTEVsZW1lbnQsIHR5cGVzOiBTdHJpbmcsIGZuOiBGdW5jdGlvbiwgY29udGV4dD86IE9iamVjdCk6IHRoaXNcclxuLy8gUmVtb3ZlcyBhIHByZXZpb3VzbHkgYWRkZWQgbGlzdGVuZXIgZnVuY3Rpb24uXHJcbi8vIE5vdGUgdGhhdCBpZiB5b3UgcGFzc2VkIGEgY3VzdG9tIGNvbnRleHQgdG8gb24sIHlvdSBtdXN0IHBhc3MgdGhlIHNhbWVcclxuLy8gY29udGV4dCB0byBgb2ZmYCBpbiBvcmRlciB0byByZW1vdmUgdGhlIGxpc3RlbmVyLlxyXG5cclxuLy8gQGFsdGVybmF0aXZlXHJcbi8vIEBmdW5jdGlvbiBvZmYoZWw6IEhUTUxFbGVtZW50LCBldmVudE1hcDogT2JqZWN0LCBjb250ZXh0PzogT2JqZWN0KTogdGhpc1xyXG4vLyBSZW1vdmVzIGEgc2V0IG9mIHR5cGUvbGlzdGVuZXIgcGFpcnMsIGUuZy4gYHtjbGljazogb25DbGljaywgbW91c2Vtb3ZlOiBvbk1vdXNlTW92ZX1gXHJcbmZ1bmN0aW9uIG9mZihvYmosIHR5cGVzLCBmbiwgY29udGV4dCkge1xyXG5cclxuXHRpZiAodHlwZW9mIHR5cGVzID09PSAnb2JqZWN0Jykge1xyXG5cdFx0Zm9yICh2YXIgdHlwZSBpbiB0eXBlcykge1xyXG5cdFx0XHRyZW1vdmVPbmUob2JqLCB0eXBlLCB0eXBlc1t0eXBlXSwgZm4pO1xyXG5cdFx0fVxyXG5cdH0gZWxzZSBpZiAodHlwZXMpIHtcclxuXHRcdHR5cGVzID0gc3BsaXRXb3Jkcyh0eXBlcyk7XHJcblxyXG5cdFx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IHR5cGVzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdHJlbW92ZU9uZShvYmosIHR5cGVzW2ldLCBmbiwgY29udGV4dCk7XHJcblx0XHR9XHJcblx0fSBlbHNlIHtcclxuXHRcdGZvciAodmFyIGogaW4gb2JqW2V2ZW50c0tleV0pIHtcclxuXHRcdFx0cmVtb3ZlT25lKG9iaiwgaiwgb2JqW2V2ZW50c0tleV1bal0pO1xyXG5cdFx0fVxyXG5cdFx0ZGVsZXRlIG9ialtldmVudHNLZXldO1xyXG5cdH1cclxuXHJcblx0cmV0dXJuIHRoaXM7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGFkZE9uZShvYmosIHR5cGUsIGZuLCBjb250ZXh0KSB7XHJcblx0dmFyIGlkID0gdHlwZSArIHN0YW1wKGZuKSArIChjb250ZXh0ID8gJ18nICsgc3RhbXAoY29udGV4dCkgOiAnJyk7XHJcblxyXG5cdGlmIChvYmpbZXZlbnRzS2V5XSAmJiBvYmpbZXZlbnRzS2V5XVtpZF0pIHsgcmV0dXJuIHRoaXM7IH1cclxuXHJcblx0dmFyIGhhbmRsZXIgPSBmdW5jdGlvbiAoZSkge1xyXG5cdFx0cmV0dXJuIGZuLmNhbGwoY29udGV4dCB8fCBvYmosIGUgfHwgd2luZG93LmV2ZW50KTtcclxuXHR9O1xyXG5cclxuXHR2YXIgb3JpZ2luYWxIYW5kbGVyID0gaGFuZGxlcjtcclxuXHJcblx0aWYgKHBvaW50ZXIgJiYgdHlwZS5pbmRleE9mKCd0b3VjaCcpID09PSAwKSB7XHJcblx0XHQvLyBOZWVkcyBEb21FdmVudC5Qb2ludGVyLmpzXHJcblx0XHRhZGRQb2ludGVyTGlzdGVuZXIob2JqLCB0eXBlLCBoYW5kbGVyLCBpZCk7XHJcblxyXG5cdH0gZWxzZSBpZiAodG91Y2ggJiYgKHR5cGUgPT09ICdkYmxjbGljaycpICYmIGFkZERvdWJsZVRhcExpc3RlbmVyICYmXHJcblx0ICAgICAgICAgICAhKHBvaW50ZXIgJiYgY2hyb21lKSkge1xyXG5cdFx0Ly8gQ2hyb21lID41NSBkb2VzIG5vdCBuZWVkIHRoZSBzeW50aGV0aWMgZGJsY2xpY2tzIGZyb20gYWRkRG91YmxlVGFwTGlzdGVuZXJcclxuXHRcdC8vIFNlZSAjNTE4MFxyXG5cdFx0YWRkRG91YmxlVGFwTGlzdGVuZXIob2JqLCBoYW5kbGVyLCBpZCk7XHJcblxyXG5cdH0gZWxzZSBpZiAoJ2FkZEV2ZW50TGlzdGVuZXInIGluIG9iaikge1xyXG5cclxuXHRcdGlmICh0eXBlID09PSAnbW91c2V3aGVlbCcpIHtcclxuXHRcdFx0b2JqLmFkZEV2ZW50TGlzdGVuZXIoJ29ud2hlZWwnIGluIG9iaiA/ICd3aGVlbCcgOiAnbW91c2V3aGVlbCcsIGhhbmRsZXIsIGZhbHNlKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKCh0eXBlID09PSAnbW91c2VlbnRlcicpIHx8ICh0eXBlID09PSAnbW91c2VsZWF2ZScpKSB7XHJcblx0XHRcdGhhbmRsZXIgPSBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHRcdGUgPSBlIHx8IHdpbmRvdy5ldmVudDtcclxuXHRcdFx0XHRpZiAoaXNFeHRlcm5hbFRhcmdldChvYmosIGUpKSB7XHJcblx0XHRcdFx0XHRvcmlnaW5hbEhhbmRsZXIoZSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9O1xyXG5cdFx0XHRvYmouYWRkRXZlbnRMaXN0ZW5lcih0eXBlID09PSAnbW91c2VlbnRlcicgPyAnbW91c2VvdmVyJyA6ICdtb3VzZW91dCcsIGhhbmRsZXIsIGZhbHNlKTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRpZiAodHlwZSA9PT0gJ2NsaWNrJyAmJiBhbmRyb2lkKSB7XHJcblx0XHRcdFx0aGFuZGxlciA9IGZ1bmN0aW9uIChlKSB7XHJcblx0XHRcdFx0XHRmaWx0ZXJDbGljayhlLCBvcmlnaW5hbEhhbmRsZXIpO1xyXG5cdFx0XHRcdH07XHJcblx0XHRcdH1cclxuXHRcdFx0b2JqLmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgaGFuZGxlciwgZmFsc2UpO1xyXG5cdFx0fVxyXG5cclxuXHR9IGVsc2UgaWYgKCdhdHRhY2hFdmVudCcgaW4gb2JqKSB7XHJcblx0XHRvYmouYXR0YWNoRXZlbnQoJ29uJyArIHR5cGUsIGhhbmRsZXIpO1xyXG5cdH1cclxuXHJcblx0b2JqW2V2ZW50c0tleV0gPSBvYmpbZXZlbnRzS2V5XSB8fCB7fTtcclxuXHRvYmpbZXZlbnRzS2V5XVtpZF0gPSBoYW5kbGVyO1xyXG59XHJcblxyXG5mdW5jdGlvbiByZW1vdmVPbmUob2JqLCB0eXBlLCBmbiwgY29udGV4dCkge1xyXG5cclxuXHR2YXIgaWQgPSB0eXBlICsgc3RhbXAoZm4pICsgKGNvbnRleHQgPyAnXycgKyBzdGFtcChjb250ZXh0KSA6ICcnKSxcclxuXHQgICAgaGFuZGxlciA9IG9ialtldmVudHNLZXldICYmIG9ialtldmVudHNLZXldW2lkXTtcclxuXHJcblx0aWYgKCFoYW5kbGVyKSB7IHJldHVybiB0aGlzOyB9XHJcblxyXG5cdGlmIChwb2ludGVyICYmIHR5cGUuaW5kZXhPZigndG91Y2gnKSA9PT0gMCkge1xyXG5cdFx0cmVtb3ZlUG9pbnRlckxpc3RlbmVyKG9iaiwgdHlwZSwgaWQpO1xyXG5cclxuXHR9IGVsc2UgaWYgKHRvdWNoICYmICh0eXBlID09PSAnZGJsY2xpY2snKSAmJiByZW1vdmVEb3VibGVUYXBMaXN0ZW5lciAmJlxyXG5cdCAgICAgICAgICAgIShwb2ludGVyICYmIGNocm9tZSkpIHtcclxuXHRcdHJlbW92ZURvdWJsZVRhcExpc3RlbmVyKG9iaiwgaWQpO1xyXG5cclxuXHR9IGVsc2UgaWYgKCdyZW1vdmVFdmVudExpc3RlbmVyJyBpbiBvYmopIHtcclxuXHJcblx0XHRpZiAodHlwZSA9PT0gJ21vdXNld2hlZWwnKSB7XHJcblx0XHRcdG9iai5yZW1vdmVFdmVudExpc3RlbmVyKCdvbndoZWVsJyBpbiBvYmogPyAnd2hlZWwnIDogJ21vdXNld2hlZWwnLCBoYW5kbGVyLCBmYWxzZSk7XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0b2JqLnJlbW92ZUV2ZW50TGlzdGVuZXIoXHJcblx0XHRcdFx0dHlwZSA9PT0gJ21vdXNlZW50ZXInID8gJ21vdXNlb3ZlcicgOlxyXG5cdFx0XHRcdHR5cGUgPT09ICdtb3VzZWxlYXZlJyA/ICdtb3VzZW91dCcgOiB0eXBlLCBoYW5kbGVyLCBmYWxzZSk7XHJcblx0XHR9XHJcblxyXG5cdH0gZWxzZSBpZiAoJ2RldGFjaEV2ZW50JyBpbiBvYmopIHtcclxuXHRcdG9iai5kZXRhY2hFdmVudCgnb24nICsgdHlwZSwgaGFuZGxlcik7XHJcblx0fVxyXG5cclxuXHRvYmpbZXZlbnRzS2V5XVtpZF0gPSBudWxsO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gc3RvcFByb3BhZ2F0aW9uKGV2OiBET01FdmVudCk6IHRoaXNcclxuLy8gU3RvcCB0aGUgZ2l2ZW4gZXZlbnQgZnJvbSBwcm9wYWdhdGlvbiB0byBwYXJlbnQgZWxlbWVudHMuIFVzZWQgaW5zaWRlIHRoZSBsaXN0ZW5lciBmdW5jdGlvbnM6XHJcbi8vIGBgYGpzXHJcbi8vIEwuRG9tRXZlbnQub24oZGl2LCAnY2xpY2snLCBmdW5jdGlvbiAoZXYpIHtcclxuLy8gXHRMLkRvbUV2ZW50LnN0b3BQcm9wYWdhdGlvbihldik7XHJcbi8vIH0pO1xyXG4vLyBgYGBcclxuZnVuY3Rpb24gc3RvcFByb3BhZ2F0aW9uKGUpIHtcclxuXHJcblx0aWYgKGUuc3RvcFByb3BhZ2F0aW9uKSB7XHJcblx0XHRlLnN0b3BQcm9wYWdhdGlvbigpO1xyXG5cdH0gZWxzZSBpZiAoZS5vcmlnaW5hbEV2ZW50KSB7ICAvLyBJbiBjYXNlIG9mIExlYWZsZXQgZXZlbnQuXHJcblx0XHRlLm9yaWdpbmFsRXZlbnQuX3N0b3BwZWQgPSB0cnVlO1xyXG5cdH0gZWxzZSB7XHJcblx0XHRlLmNhbmNlbEJ1YmJsZSA9IHRydWU7XHJcblx0fVxyXG5cdHNraXBwZWQoZSk7XHJcblxyXG5cdHJldHVybiB0aGlzO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gZGlzYWJsZVNjcm9sbFByb3BhZ2F0aW9uKGVsOiBIVE1MRWxlbWVudCk6IHRoaXNcclxuLy8gQWRkcyBgc3RvcFByb3BhZ2F0aW9uYCB0byB0aGUgZWxlbWVudCdzIGAnbW91c2V3aGVlbCdgIGV2ZW50cyAocGx1cyBicm93c2VyIHZhcmlhbnRzKS5cclxuZnVuY3Rpb24gZGlzYWJsZVNjcm9sbFByb3BhZ2F0aW9uKGVsKSB7XHJcblx0YWRkT25lKGVsLCAnbW91c2V3aGVlbCcsIHN0b3BQcm9wYWdhdGlvbik7XHJcblx0cmV0dXJuIHRoaXM7XHJcbn1cclxuXHJcbi8vIEBmdW5jdGlvbiBkaXNhYmxlQ2xpY2tQcm9wYWdhdGlvbihlbDogSFRNTEVsZW1lbnQpOiB0aGlzXHJcbi8vIEFkZHMgYHN0b3BQcm9wYWdhdGlvbmAgdG8gdGhlIGVsZW1lbnQncyBgJ2NsaWNrJ2AsIGAnZG91YmxlY2xpY2snYCxcclxuLy8gYCdtb3VzZWRvd24nYCBhbmQgYCd0b3VjaHN0YXJ0J2AgZXZlbnRzIChwbHVzIGJyb3dzZXIgdmFyaWFudHMpLlxyXG5mdW5jdGlvbiBkaXNhYmxlQ2xpY2tQcm9wYWdhdGlvbihlbCkge1xyXG5cdG9uKGVsLCAnbW91c2Vkb3duIHRvdWNoc3RhcnQgZGJsY2xpY2snLCBzdG9wUHJvcGFnYXRpb24pO1xyXG5cdGFkZE9uZShlbCwgJ2NsaWNrJywgZmFrZVN0b3ApO1xyXG5cdHJldHVybiB0aGlzO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gcHJldmVudERlZmF1bHQoZXY6IERPTUV2ZW50KTogdGhpc1xyXG4vLyBQcmV2ZW50cyB0aGUgZGVmYXVsdCBhY3Rpb24gb2YgdGhlIERPTSBFdmVudCBgZXZgIGZyb20gaGFwcGVuaW5nIChzdWNoIGFzXHJcbi8vIGZvbGxvd2luZyBhIGxpbmsgaW4gdGhlIGhyZWYgb2YgdGhlIGEgZWxlbWVudCwgb3IgZG9pbmcgYSBQT1NUIHJlcXVlc3RcclxuLy8gd2l0aCBwYWdlIHJlbG9hZCB3aGVuIGEgYDxmb3JtPmAgaXMgc3VibWl0dGVkKS5cclxuLy8gVXNlIGl0IGluc2lkZSBsaXN0ZW5lciBmdW5jdGlvbnMuXHJcbmZ1bmN0aW9uIHByZXZlbnREZWZhdWx0KGUpIHtcclxuXHRpZiAoZS5wcmV2ZW50RGVmYXVsdCkge1xyXG5cdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG5cdH0gZWxzZSB7XHJcblx0XHRlLnJldHVyblZhbHVlID0gZmFsc2U7XHJcblx0fVxyXG5cdHJldHVybiB0aGlzO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gc3RvcChldjogRE9NRXZlbnQpOiB0aGlzXHJcbi8vIERvZXMgYHN0b3BQcm9wYWdhdGlvbmAgYW5kIGBwcmV2ZW50RGVmYXVsdGAgYXQgdGhlIHNhbWUgdGltZS5cclxuZnVuY3Rpb24gc3RvcChlKSB7XHJcblx0cHJldmVudERlZmF1bHQoZSk7XHJcblx0c3RvcFByb3BhZ2F0aW9uKGUpO1xyXG5cdHJldHVybiB0aGlzO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gZ2V0TW91c2VQb3NpdGlvbihldjogRE9NRXZlbnQsIGNvbnRhaW5lcj86IEhUTUxFbGVtZW50KTogUG9pbnRcclxuLy8gR2V0cyBub3JtYWxpemVkIG1vdXNlIHBvc2l0aW9uIGZyb20gYSBET00gZXZlbnQgcmVsYXRpdmUgdG8gdGhlXHJcbi8vIGBjb250YWluZXJgIG9yIHRvIHRoZSB3aG9sZSBwYWdlIGlmIG5vdCBzcGVjaWZpZWQuXHJcbmZ1bmN0aW9uIGdldE1vdXNlUG9zaXRpb24oZSwgY29udGFpbmVyKSB7XHJcblx0aWYgKCFjb250YWluZXIpIHtcclxuXHRcdHJldHVybiBuZXcgUG9pbnQoZS5jbGllbnRYLCBlLmNsaWVudFkpO1xyXG5cdH1cclxuXHJcblx0dmFyIHJlY3QgPSBjb250YWluZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcblxyXG5cdHZhciBzY2FsZVggPSByZWN0LndpZHRoIC8gY29udGFpbmVyLm9mZnNldFdpZHRoIHx8IDE7XHJcblx0dmFyIHNjYWxlWSA9IHJlY3QuaGVpZ2h0IC8gY29udGFpbmVyLm9mZnNldEhlaWdodCB8fCAxO1xyXG5cdHJldHVybiBuZXcgUG9pbnQoXHJcblx0XHRlLmNsaWVudFggLyBzY2FsZVggLSByZWN0LmxlZnQgLSBjb250YWluZXIuY2xpZW50TGVmdCxcclxuXHRcdGUuY2xpZW50WSAvIHNjYWxlWSAtIHJlY3QudG9wIC0gY29udGFpbmVyLmNsaWVudFRvcCk7XHJcbn1cclxuXHJcbi8vIENocm9tZSBvbiBXaW4gc2Nyb2xscyBkb3VibGUgdGhlIHBpeGVscyBhcyBpbiBvdGhlciBwbGF0Zm9ybXMgKHNlZSAjNDUzOCksXHJcbi8vIGFuZCBGaXJlZm94IHNjcm9sbHMgZGV2aWNlIHBpeGVscywgbm90IENTUyBwaXhlbHNcclxudmFyIHdoZWVsUHhGYWN0b3IgPVxyXG5cdCh3aW4gJiYgY2hyb21lKSA/IDIgKiB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyA6XHJcblx0Z2Vja28gPyB3aW5kb3cuZGV2aWNlUGl4ZWxSYXRpbyA6IDE7XHJcblxyXG4vLyBAZnVuY3Rpb24gZ2V0V2hlZWxEZWx0YShldjogRE9NRXZlbnQpOiBOdW1iZXJcclxuLy8gR2V0cyBub3JtYWxpemVkIHdoZWVsIGRlbHRhIGZyb20gYSBtb3VzZXdoZWVsIERPTSBldmVudCwgaW4gdmVydGljYWxcclxuLy8gcGl4ZWxzIHNjcm9sbGVkIChuZWdhdGl2ZSBpZiBzY3JvbGxpbmcgZG93bikuXHJcbi8vIEV2ZW50cyBmcm9tIHBvaW50aW5nIGRldmljZXMgd2l0aG91dCBwcmVjaXNlIHNjcm9sbGluZyBhcmUgbWFwcGVkIHRvXHJcbi8vIGEgYmVzdCBndWVzcyBvZiA2MCBwaXhlbHMuXHJcbmZ1bmN0aW9uIGdldFdoZWVsRGVsdGEoZSkge1xyXG5cdHJldHVybiAoZWRnZSkgPyBlLndoZWVsRGVsdGFZIC8gMiA6IC8vIERvbid0IHRydXN0IHdpbmRvdy1nZW9tZXRyeS1iYXNlZCBkZWx0YVxyXG5cdCAgICAgICAoZS5kZWx0YVkgJiYgZS5kZWx0YU1vZGUgPT09IDApID8gLWUuZGVsdGFZIC8gd2hlZWxQeEZhY3RvciA6IC8vIFBpeGVsc1xyXG5cdCAgICAgICAoZS5kZWx0YVkgJiYgZS5kZWx0YU1vZGUgPT09IDEpID8gLWUuZGVsdGFZICogMjAgOiAvLyBMaW5lc1xyXG5cdCAgICAgICAoZS5kZWx0YVkgJiYgZS5kZWx0YU1vZGUgPT09IDIpID8gLWUuZGVsdGFZICogNjAgOiAvLyBQYWdlc1xyXG5cdCAgICAgICAoZS5kZWx0YVggfHwgZS5kZWx0YVopID8gMCA6XHQvLyBTa2lwIGhvcml6b250YWwvZGVwdGggd2hlZWwgZXZlbnRzXHJcblx0ICAgICAgIGUud2hlZWxEZWx0YSA/IChlLndoZWVsRGVsdGFZIHx8IGUud2hlZWxEZWx0YSkgLyAyIDogLy8gTGVnYWN5IElFIHBpeGVsc1xyXG5cdCAgICAgICAoZS5kZXRhaWwgJiYgTWF0aC5hYnMoZS5kZXRhaWwpIDwgMzI3NjUpID8gLWUuZGV0YWlsICogMjAgOiAvLyBMZWdhY3kgTW96IGxpbmVzXHJcblx0ICAgICAgIGUuZGV0YWlsID8gZS5kZXRhaWwgLyAtMzI3NjUgKiA2MCA6IC8vIExlZ2FjeSBNb3ogcGFnZXNcclxuXHQgICAgICAgMDtcclxufVxyXG5cclxudmFyIHNraXBFdmVudHMgPSB7fTtcclxuXHJcbmZ1bmN0aW9uIGZha2VTdG9wKGUpIHtcclxuXHQvLyBmYWtlcyBzdG9wUHJvcGFnYXRpb24gYnkgc2V0dGluZyBhIHNwZWNpYWwgZXZlbnQgZmxhZywgY2hlY2tlZC9yZXNldCB3aXRoIHNraXBwZWQoZSlcclxuXHRza2lwRXZlbnRzW2UudHlwZV0gPSB0cnVlO1xyXG59XHJcblxyXG5mdW5jdGlvbiBza2lwcGVkKGUpIHtcclxuXHR2YXIgZXZlbnRzID0gc2tpcEV2ZW50c1tlLnR5cGVdO1xyXG5cdC8vIHJlc2V0IHdoZW4gY2hlY2tpbmcsIGFzIGl0J3Mgb25seSB1c2VkIGluIG1hcCBjb250YWluZXIgYW5kIHByb3BhZ2F0ZXMgb3V0c2lkZSBvZiB0aGUgbWFwXHJcblx0c2tpcEV2ZW50c1tlLnR5cGVdID0gZmFsc2U7XHJcblx0cmV0dXJuIGV2ZW50cztcclxufVxyXG5cclxuLy8gY2hlY2sgaWYgZWxlbWVudCByZWFsbHkgbGVmdC9lbnRlcmVkIHRoZSBldmVudCB0YXJnZXQgKGZvciBtb3VzZWVudGVyL21vdXNlbGVhdmUpXHJcbmZ1bmN0aW9uIGlzRXh0ZXJuYWxUYXJnZXQoZWwsIGUpIHtcclxuXHJcblx0dmFyIHJlbGF0ZWQgPSBlLnJlbGF0ZWRUYXJnZXQ7XHJcblxyXG5cdGlmICghcmVsYXRlZCkgeyByZXR1cm4gdHJ1ZTsgfVxyXG5cclxuXHR0cnkge1xyXG5cdFx0d2hpbGUgKHJlbGF0ZWQgJiYgKHJlbGF0ZWQgIT09IGVsKSkge1xyXG5cdFx0XHRyZWxhdGVkID0gcmVsYXRlZC5wYXJlbnROb2RlO1xyXG5cdFx0fVxyXG5cdH0gY2F0Y2ggKGVycikge1xyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH1cclxuXHRyZXR1cm4gKHJlbGF0ZWQgIT09IGVsKTtcclxufVxyXG5cclxudmFyIGxhc3RDbGljaztcclxuXHJcbi8vIHRoaXMgaXMgYSBob3JyaWJsZSB3b3JrYXJvdW5kIGZvciBhIGJ1ZyBpbiBBbmRyb2lkIHdoZXJlIGEgc2luZ2xlIHRvdWNoIHRyaWdnZXJzIHR3byBjbGljayBldmVudHNcclxuZnVuY3Rpb24gZmlsdGVyQ2xpY2soZSwgaGFuZGxlcikge1xyXG5cdHZhciB0aW1lU3RhbXAgPSAoZS50aW1lU3RhbXAgfHwgKGUub3JpZ2luYWxFdmVudCAmJiBlLm9yaWdpbmFsRXZlbnQudGltZVN0YW1wKSksXHJcblx0ICAgIGVsYXBzZWQgPSBsYXN0Q2xpY2sgJiYgKHRpbWVTdGFtcCAtIGxhc3RDbGljayk7XHJcblxyXG5cdC8vIGFyZSB0aGV5IGNsb3NlciB0b2dldGhlciB0aGFuIDUwMG1zIHlldCBtb3JlIHRoYW4gMTAwbXM/XHJcblx0Ly8gQW5kcm9pZCB0eXBpY2FsbHkgdHJpZ2dlcnMgdGhlbSB+MzAwbXMgYXBhcnQgd2hpbGUgbXVsdGlwbGUgbGlzdGVuZXJzXHJcblx0Ly8gb24gdGhlIHNhbWUgZXZlbnQgc2hvdWxkIGJlIHRyaWdnZXJlZCBmYXIgZmFzdGVyO1xyXG5cdC8vIG9yIGNoZWNrIGlmIGNsaWNrIGlzIHNpbXVsYXRlZCBvbiB0aGUgZWxlbWVudCwgYW5kIGlmIGl0IGlzLCByZWplY3QgYW55IG5vbi1zaW11bGF0ZWQgZXZlbnRzXHJcblxyXG5cdGlmICgoZWxhcHNlZCAmJiBlbGFwc2VkID4gMTAwICYmIGVsYXBzZWQgPCA1MDApIHx8IChlLnRhcmdldC5fc2ltdWxhdGVkQ2xpY2sgJiYgIWUuX3NpbXVsYXRlZCkpIHtcclxuXHRcdHN0b3AoZSk7XHJcblx0XHRyZXR1cm47XHJcblx0fVxyXG5cdGxhc3RDbGljayA9IHRpbWVTdGFtcDtcclxuXHJcblx0aGFuZGxlcihlKTtcclxufVxyXG5cclxuXHJcblxuXG52YXIgRG9tRXZlbnQgPSAoT2JqZWN0LmZyZWV6ZSB8fCBPYmplY3QpKHtcblx0b246IG9uLFxuXHRvZmY6IG9mZixcblx0c3RvcFByb3BhZ2F0aW9uOiBzdG9wUHJvcGFnYXRpb24sXG5cdGRpc2FibGVTY3JvbGxQcm9wYWdhdGlvbjogZGlzYWJsZVNjcm9sbFByb3BhZ2F0aW9uLFxuXHRkaXNhYmxlQ2xpY2tQcm9wYWdhdGlvbjogZGlzYWJsZUNsaWNrUHJvcGFnYXRpb24sXG5cdHByZXZlbnREZWZhdWx0OiBwcmV2ZW50RGVmYXVsdCxcblx0c3RvcDogc3RvcCxcblx0Z2V0TW91c2VQb3NpdGlvbjogZ2V0TW91c2VQb3NpdGlvbixcblx0Z2V0V2hlZWxEZWx0YTogZ2V0V2hlZWxEZWx0YSxcblx0ZmFrZVN0b3A6IGZha2VTdG9wLFxuXHRza2lwcGVkOiBza2lwcGVkLFxuXHRpc0V4dGVybmFsVGFyZ2V0OiBpc0V4dGVybmFsVGFyZ2V0LFxuXHRhZGRMaXN0ZW5lcjogb24sXG5cdHJlbW92ZUxpc3RlbmVyOiBvZmZcbn0pO1xuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIERvbVV0aWxcclxuICpcclxuICogVXRpbGl0eSBmdW5jdGlvbnMgdG8gd29yayB3aXRoIHRoZSBbRE9NXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9BUEkvRG9jdW1lbnRfT2JqZWN0X01vZGVsKVxyXG4gKiB0cmVlLCB1c2VkIGJ5IExlYWZsZXQgaW50ZXJuYWxseS5cclxuICpcclxuICogTW9zdCBmdW5jdGlvbnMgZXhwZWN0aW5nIG9yIHJldHVybmluZyBhIGBIVE1MRWxlbWVudGAgYWxzbyB3b3JrIGZvclxyXG4gKiBTVkcgZWxlbWVudHMuIFRoZSBvbmx5IGRpZmZlcmVuY2UgaXMgdGhhdCBjbGFzc2VzIHJlZmVyIHRvIENTUyBjbGFzc2VzXHJcbiAqIGluIEhUTUwgYW5kIFNWRyBjbGFzc2VzIGluIFNWRy5cclxuICovXHJcblxyXG5cclxuLy8gQHByb3BlcnR5IFRSQU5TRk9STTogU3RyaW5nXHJcbi8vIFZlbmRvci1wcmVmaXhlZCB0cmFuc2Zvcm0gc3R5bGUgbmFtZSAoZS5nLiBgJ3dlYmtpdFRyYW5zZm9ybSdgIGZvciBXZWJLaXQpLlxyXG52YXIgVFJBTlNGT1JNID0gdGVzdFByb3AoXHJcblx0Wyd0cmFuc2Zvcm0nLCAnV2Via2l0VHJhbnNmb3JtJywgJ09UcmFuc2Zvcm0nLCAnTW96VHJhbnNmb3JtJywgJ21zVHJhbnNmb3JtJ10pO1xyXG5cclxuLy8gd2Via2l0VHJhbnNpdGlvbiBjb21lcyBmaXJzdCBiZWNhdXNlIHNvbWUgYnJvd3NlciB2ZXJzaW9ucyB0aGF0IGRyb3AgdmVuZG9yIHByZWZpeCBkb24ndCBkb1xyXG4vLyB0aGUgc2FtZSBmb3IgdGhlIHRyYW5zaXRpb25lbmQgZXZlbnQsIGluIHBhcnRpY3VsYXIgdGhlIEFuZHJvaWQgNC4xIHN0b2NrIGJyb3dzZXJcclxuXHJcbi8vIEBwcm9wZXJ0eSBUUkFOU0lUSU9OOiBTdHJpbmdcclxuLy8gVmVuZG9yLXByZWZpeGVkIHRyYW5zaXRpb24gc3R5bGUgbmFtZS5cclxudmFyIFRSQU5TSVRJT04gPSB0ZXN0UHJvcChcclxuXHRbJ3dlYmtpdFRyYW5zaXRpb24nLCAndHJhbnNpdGlvbicsICdPVHJhbnNpdGlvbicsICdNb3pUcmFuc2l0aW9uJywgJ21zVHJhbnNpdGlvbiddKTtcclxuXHJcbi8vIEBwcm9wZXJ0eSBUUkFOU0lUSU9OX0VORDogU3RyaW5nXHJcbi8vIFZlbmRvci1wcmVmaXhlZCB0cmFuc2l0aW9uZW5kIGV2ZW50IG5hbWUuXHJcbnZhciBUUkFOU0lUSU9OX0VORCA9XHJcblx0VFJBTlNJVElPTiA9PT0gJ3dlYmtpdFRyYW5zaXRpb24nIHx8IFRSQU5TSVRJT04gPT09ICdPVHJhbnNpdGlvbicgPyBUUkFOU0lUSU9OICsgJ0VuZCcgOiAndHJhbnNpdGlvbmVuZCc7XHJcblxyXG5cclxuLy8gQGZ1bmN0aW9uIGdldChpZDogU3RyaW5nfEhUTUxFbGVtZW50KTogSFRNTEVsZW1lbnRcclxuLy8gUmV0dXJucyBhbiBlbGVtZW50IGdpdmVuIGl0cyBET00gaWQsIG9yIHJldHVybnMgdGhlIGVsZW1lbnQgaXRzZWxmXHJcbi8vIGlmIGl0IHdhcyBwYXNzZWQgZGlyZWN0bHkuXHJcbmZ1bmN0aW9uIGdldChpZCkge1xyXG5cdHJldHVybiB0eXBlb2YgaWQgPT09ICdzdHJpbmcnID8gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoaWQpIDogaWQ7XHJcbn1cclxuXHJcbi8vIEBmdW5jdGlvbiBnZXRTdHlsZShlbDogSFRNTEVsZW1lbnQsIHN0eWxlQXR0cmliOiBTdHJpbmcpOiBTdHJpbmdcclxuLy8gUmV0dXJucyB0aGUgdmFsdWUgZm9yIGEgY2VydGFpbiBzdHlsZSBhdHRyaWJ1dGUgb24gYW4gZWxlbWVudCxcclxuLy8gaW5jbHVkaW5nIGNvbXB1dGVkIHZhbHVlcyBvciB2YWx1ZXMgc2V0IHRocm91Z2ggQ1NTLlxyXG5mdW5jdGlvbiBnZXRTdHlsZShlbCwgc3R5bGUpIHtcclxuXHR2YXIgdmFsdWUgPSBlbC5zdHlsZVtzdHlsZV0gfHwgKGVsLmN1cnJlbnRTdHlsZSAmJiBlbC5jdXJyZW50U3R5bGVbc3R5bGVdKTtcclxuXHJcblx0aWYgKCghdmFsdWUgfHwgdmFsdWUgPT09ICdhdXRvJykgJiYgZG9jdW1lbnQuZGVmYXVsdFZpZXcpIHtcclxuXHRcdHZhciBjc3MgPSBkb2N1bWVudC5kZWZhdWx0Vmlldy5nZXRDb21wdXRlZFN0eWxlKGVsLCBudWxsKTtcclxuXHRcdHZhbHVlID0gY3NzID8gY3NzW3N0eWxlXSA6IG51bGw7XHJcblx0fVxyXG5cdHJldHVybiB2YWx1ZSA9PT0gJ2F1dG8nID8gbnVsbCA6IHZhbHVlO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gY3JlYXRlKHRhZ05hbWU6IFN0cmluZywgY2xhc3NOYW1lPzogU3RyaW5nLCBjb250YWluZXI/OiBIVE1MRWxlbWVudCk6IEhUTUxFbGVtZW50XHJcbi8vIENyZWF0ZXMgYW4gSFRNTCBlbGVtZW50IHdpdGggYHRhZ05hbWVgLCBzZXRzIGl0cyBjbGFzcyB0byBgY2xhc3NOYW1lYCwgYW5kIG9wdGlvbmFsbHkgYXBwZW5kcyBpdCB0byBgY29udGFpbmVyYCBlbGVtZW50LlxyXG5mdW5jdGlvbiBjcmVhdGUkMSh0YWdOYW1lLCBjbGFzc05hbWUsIGNvbnRhaW5lcikge1xyXG5cdHZhciBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodGFnTmFtZSk7XHJcblx0ZWwuY2xhc3NOYW1lID0gY2xhc3NOYW1lIHx8ICcnO1xyXG5cclxuXHRpZiAoY29udGFpbmVyKSB7XHJcblx0XHRjb250YWluZXIuYXBwZW5kQ2hpbGQoZWwpO1xyXG5cdH1cclxuXHRyZXR1cm4gZWw7XHJcbn1cclxuXHJcbi8vIEBmdW5jdGlvbiByZW1vdmUoZWw6IEhUTUxFbGVtZW50KVxyXG4vLyBSZW1vdmVzIGBlbGAgZnJvbSBpdHMgcGFyZW50IGVsZW1lbnRcclxuZnVuY3Rpb24gcmVtb3ZlKGVsKSB7XHJcblx0dmFyIHBhcmVudCA9IGVsLnBhcmVudE5vZGU7XHJcblx0aWYgKHBhcmVudCkge1xyXG5cdFx0cGFyZW50LnJlbW92ZUNoaWxkKGVsKTtcclxuXHR9XHJcbn1cclxuXHJcbi8vIEBmdW5jdGlvbiBlbXB0eShlbDogSFRNTEVsZW1lbnQpXHJcbi8vIFJlbW92ZXMgYWxsIG9mIGBlbGAncyBjaGlsZHJlbiBlbGVtZW50cyBmcm9tIGBlbGBcclxuZnVuY3Rpb24gZW1wdHkoZWwpIHtcclxuXHR3aGlsZSAoZWwuZmlyc3RDaGlsZCkge1xyXG5cdFx0ZWwucmVtb3ZlQ2hpbGQoZWwuZmlyc3RDaGlsZCk7XHJcblx0fVxyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gdG9Gcm9udChlbDogSFRNTEVsZW1lbnQpXHJcbi8vIE1ha2VzIGBlbGAgdGhlIGxhc3QgY2hpbGQgb2YgaXRzIHBhcmVudCwgc28gaXQgcmVuZGVycyBpbiBmcm9udCBvZiB0aGUgb3RoZXIgY2hpbGRyZW4uXHJcbmZ1bmN0aW9uIHRvRnJvbnQoZWwpIHtcclxuXHR2YXIgcGFyZW50ID0gZWwucGFyZW50Tm9kZTtcclxuXHRpZiAocGFyZW50Lmxhc3RDaGlsZCAhPT0gZWwpIHtcclxuXHRcdHBhcmVudC5hcHBlbmRDaGlsZChlbCk7XHJcblx0fVxyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gdG9CYWNrKGVsOiBIVE1MRWxlbWVudClcclxuLy8gTWFrZXMgYGVsYCB0aGUgZmlyc3QgY2hpbGQgb2YgaXRzIHBhcmVudCwgc28gaXQgcmVuZGVycyBiZWhpbmQgdGhlIG90aGVyIGNoaWxkcmVuLlxyXG5mdW5jdGlvbiB0b0JhY2soZWwpIHtcclxuXHR2YXIgcGFyZW50ID0gZWwucGFyZW50Tm9kZTtcclxuXHRpZiAocGFyZW50LmZpcnN0Q2hpbGQgIT09IGVsKSB7XHJcblx0XHRwYXJlbnQuaW5zZXJ0QmVmb3JlKGVsLCBwYXJlbnQuZmlyc3RDaGlsZCk7XHJcblx0fVxyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gaGFzQ2xhc3MoZWw6IEhUTUxFbGVtZW50LCBuYW1lOiBTdHJpbmcpOiBCb29sZWFuXHJcbi8vIFJldHVybnMgYHRydWVgIGlmIHRoZSBlbGVtZW50J3MgY2xhc3MgYXR0cmlidXRlIGNvbnRhaW5zIGBuYW1lYC5cclxuZnVuY3Rpb24gaGFzQ2xhc3MoZWwsIG5hbWUpIHtcclxuXHRpZiAoZWwuY2xhc3NMaXN0ICE9PSB1bmRlZmluZWQpIHtcclxuXHRcdHJldHVybiBlbC5jbGFzc0xpc3QuY29udGFpbnMobmFtZSk7XHJcblx0fVxyXG5cdHZhciBjbGFzc05hbWUgPSBnZXRDbGFzcyhlbCk7XHJcblx0cmV0dXJuIGNsYXNzTmFtZS5sZW5ndGggPiAwICYmIG5ldyBSZWdFeHAoJyhefFxcXFxzKScgKyBuYW1lICsgJyhcXFxcc3wkKScpLnRlc3QoY2xhc3NOYW1lKTtcclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIGFkZENsYXNzKGVsOiBIVE1MRWxlbWVudCwgbmFtZTogU3RyaW5nKVxyXG4vLyBBZGRzIGBuYW1lYCB0byB0aGUgZWxlbWVudCdzIGNsYXNzIGF0dHJpYnV0ZS5cclxuZnVuY3Rpb24gYWRkQ2xhc3MoZWwsIG5hbWUpIHtcclxuXHRpZiAoZWwuY2xhc3NMaXN0ICE9PSB1bmRlZmluZWQpIHtcclxuXHRcdHZhciBjbGFzc2VzID0gc3BsaXRXb3JkcyhuYW1lKTtcclxuXHRcdGZvciAodmFyIGkgPSAwLCBsZW4gPSBjbGFzc2VzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdGVsLmNsYXNzTGlzdC5hZGQoY2xhc3Nlc1tpXSk7XHJcblx0XHR9XHJcblx0fSBlbHNlIGlmICghaGFzQ2xhc3MoZWwsIG5hbWUpKSB7XHJcblx0XHR2YXIgY2xhc3NOYW1lID0gZ2V0Q2xhc3MoZWwpO1xyXG5cdFx0c2V0Q2xhc3MoZWwsIChjbGFzc05hbWUgPyBjbGFzc05hbWUgKyAnICcgOiAnJykgKyBuYW1lKTtcclxuXHR9XHJcbn1cclxuXHJcbi8vIEBmdW5jdGlvbiByZW1vdmVDbGFzcyhlbDogSFRNTEVsZW1lbnQsIG5hbWU6IFN0cmluZylcclxuLy8gUmVtb3ZlcyBgbmFtZWAgZnJvbSB0aGUgZWxlbWVudCdzIGNsYXNzIGF0dHJpYnV0ZS5cclxuZnVuY3Rpb24gcmVtb3ZlQ2xhc3MoZWwsIG5hbWUpIHtcclxuXHRpZiAoZWwuY2xhc3NMaXN0ICE9PSB1bmRlZmluZWQpIHtcclxuXHRcdGVsLmNsYXNzTGlzdC5yZW1vdmUobmFtZSk7XHJcblx0fSBlbHNlIHtcclxuXHRcdHNldENsYXNzKGVsLCB0cmltKCgnICcgKyBnZXRDbGFzcyhlbCkgKyAnICcpLnJlcGxhY2UoJyAnICsgbmFtZSArICcgJywgJyAnKSkpO1xyXG5cdH1cclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIHNldENsYXNzKGVsOiBIVE1MRWxlbWVudCwgbmFtZTogU3RyaW5nKVxyXG4vLyBTZXRzIHRoZSBlbGVtZW50J3MgY2xhc3MuXHJcbmZ1bmN0aW9uIHNldENsYXNzKGVsLCBuYW1lKSB7XHJcblx0aWYgKGVsLmNsYXNzTmFtZS5iYXNlVmFsID09PSB1bmRlZmluZWQpIHtcclxuXHRcdGVsLmNsYXNzTmFtZSA9IG5hbWU7XHJcblx0fSBlbHNlIHtcclxuXHRcdC8vIGluIGNhc2Ugb2YgU1ZHIGVsZW1lbnRcclxuXHRcdGVsLmNsYXNzTmFtZS5iYXNlVmFsID0gbmFtZTtcclxuXHR9XHJcbn1cclxuXHJcbi8vIEBmdW5jdGlvbiBnZXRDbGFzcyhlbDogSFRNTEVsZW1lbnQpOiBTdHJpbmdcclxuLy8gUmV0dXJucyB0aGUgZWxlbWVudCdzIGNsYXNzLlxyXG5mdW5jdGlvbiBnZXRDbGFzcyhlbCkge1xyXG5cdHJldHVybiBlbC5jbGFzc05hbWUuYmFzZVZhbCA9PT0gdW5kZWZpbmVkID8gZWwuY2xhc3NOYW1lIDogZWwuY2xhc3NOYW1lLmJhc2VWYWw7XHJcbn1cclxuXHJcbi8vIEBmdW5jdGlvbiBzZXRPcGFjaXR5KGVsOiBIVE1MRWxlbWVudCwgb3BhY2l0eTogTnVtYmVyKVxyXG4vLyBTZXQgdGhlIG9wYWNpdHkgb2YgYW4gZWxlbWVudCAoaW5jbHVkaW5nIG9sZCBJRSBzdXBwb3J0KS5cclxuLy8gYG9wYWNpdHlgIG11c3QgYmUgYSBudW1iZXIgZnJvbSBgMGAgdG8gYDFgLlxyXG5mdW5jdGlvbiBzZXRPcGFjaXR5KGVsLCB2YWx1ZSkge1xyXG5cdGlmICgnb3BhY2l0eScgaW4gZWwuc3R5bGUpIHtcclxuXHRcdGVsLnN0eWxlLm9wYWNpdHkgPSB2YWx1ZTtcclxuXHR9IGVsc2UgaWYgKCdmaWx0ZXInIGluIGVsLnN0eWxlKSB7XHJcblx0XHRfc2V0T3BhY2l0eUlFKGVsLCB2YWx1ZSk7XHJcblx0fVxyXG59XHJcblxyXG5mdW5jdGlvbiBfc2V0T3BhY2l0eUlFKGVsLCB2YWx1ZSkge1xyXG5cdHZhciBmaWx0ZXIgPSBmYWxzZSxcclxuXHQgICAgZmlsdGVyTmFtZSA9ICdEWEltYWdlVHJhbnNmb3JtLk1pY3Jvc29mdC5BbHBoYSc7XHJcblxyXG5cdC8vIGZpbHRlcnMgY29sbGVjdGlvbiB0aHJvd3MgYW4gZXJyb3IgaWYgd2UgdHJ5IHRvIHJldHJpZXZlIGEgZmlsdGVyIHRoYXQgZG9lc24ndCBleGlzdFxyXG5cdHRyeSB7XHJcblx0XHRmaWx0ZXIgPSBlbC5maWx0ZXJzLml0ZW0oZmlsdGVyTmFtZSk7XHJcblx0fSBjYXRjaCAoZSkge1xyXG5cdFx0Ly8gZG9uJ3Qgc2V0IG9wYWNpdHkgdG8gMSBpZiB3ZSBoYXZlbid0IGFscmVhZHkgc2V0IGFuIG9wYWNpdHksXHJcblx0XHQvLyBpdCBpc24ndCBuZWVkZWQgYW5kIGJyZWFrcyB0cmFuc3BhcmVudCBwbmdzLlxyXG5cdFx0aWYgKHZhbHVlID09PSAxKSB7IHJldHVybjsgfVxyXG5cdH1cclxuXHJcblx0dmFsdWUgPSBNYXRoLnJvdW5kKHZhbHVlICogMTAwKTtcclxuXHJcblx0aWYgKGZpbHRlcikge1xyXG5cdFx0ZmlsdGVyLkVuYWJsZWQgPSAodmFsdWUgIT09IDEwMCk7XHJcblx0XHRmaWx0ZXIuT3BhY2l0eSA9IHZhbHVlO1xyXG5cdH0gZWxzZSB7XHJcblx0XHRlbC5zdHlsZS5maWx0ZXIgKz0gJyBwcm9naWQ6JyArIGZpbHRlck5hbWUgKyAnKG9wYWNpdHk9JyArIHZhbHVlICsgJyknO1xyXG5cdH1cclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIHRlc3RQcm9wKHByb3BzOiBTdHJpbmdbXSk6IFN0cmluZ3xmYWxzZVxyXG4vLyBHb2VzIHRocm91Z2ggdGhlIGFycmF5IG9mIHN0eWxlIG5hbWVzIGFuZCByZXR1cm5zIHRoZSBmaXJzdCBuYW1lXHJcbi8vIHRoYXQgaXMgYSB2YWxpZCBzdHlsZSBuYW1lIGZvciBhbiBlbGVtZW50LiBJZiBubyBzdWNoIG5hbWUgaXMgZm91bmQsXHJcbi8vIGl0IHJldHVybnMgZmFsc2UuIFVzZWZ1bCBmb3IgdmVuZG9yLXByZWZpeGVkIHN0eWxlcyBsaWtlIGB0cmFuc2Zvcm1gLlxyXG5mdW5jdGlvbiB0ZXN0UHJvcChwcm9wcykge1xyXG5cdHZhciBzdHlsZSA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZTtcclxuXHJcblx0Zm9yICh2YXIgaSA9IDA7IGkgPCBwcm9wcy5sZW5ndGg7IGkrKykge1xyXG5cdFx0aWYgKHByb3BzW2ldIGluIHN0eWxlKSB7XHJcblx0XHRcdHJldHVybiBwcm9wc1tpXTtcclxuXHRcdH1cclxuXHR9XHJcblx0cmV0dXJuIGZhbHNlO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gc2V0VHJhbnNmb3JtKGVsOiBIVE1MRWxlbWVudCwgb2Zmc2V0OiBQb2ludCwgc2NhbGU/OiBOdW1iZXIpXHJcbi8vIFJlc2V0cyB0aGUgM0QgQ1NTIHRyYW5zZm9ybSBvZiBgZWxgIHNvIGl0IGlzIHRyYW5zbGF0ZWQgYnkgYG9mZnNldGAgcGl4ZWxzXHJcbi8vIGFuZCBvcHRpb25hbGx5IHNjYWxlZCBieSBgc2NhbGVgLiBEb2VzIG5vdCBoYXZlIGFuIGVmZmVjdCBpZiB0aGVcclxuLy8gYnJvd3NlciBkb2Vzbid0IHN1cHBvcnQgM0QgQ1NTIHRyYW5zZm9ybXMuXHJcbmZ1bmN0aW9uIHNldFRyYW5zZm9ybShlbCwgb2Zmc2V0LCBzY2FsZSkge1xyXG5cdHZhciBwb3MgPSBvZmZzZXQgfHwgbmV3IFBvaW50KDAsIDApO1xyXG5cclxuXHRlbC5zdHlsZVtUUkFOU0ZPUk1dID1cclxuXHRcdChpZTNkID9cclxuXHRcdFx0J3RyYW5zbGF0ZSgnICsgcG9zLnggKyAncHgsJyArIHBvcy55ICsgJ3B4KScgOlxyXG5cdFx0XHQndHJhbnNsYXRlM2QoJyArIHBvcy54ICsgJ3B4LCcgKyBwb3MueSArICdweCwwKScpICtcclxuXHRcdChzY2FsZSA/ICcgc2NhbGUoJyArIHNjYWxlICsgJyknIDogJycpO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gc2V0UG9zaXRpb24oZWw6IEhUTUxFbGVtZW50LCBwb3NpdGlvbjogUG9pbnQpXHJcbi8vIFNldHMgdGhlIHBvc2l0aW9uIG9mIGBlbGAgdG8gY29vcmRpbmF0ZXMgc3BlY2lmaWVkIGJ5IGBwb3NpdGlvbmAsXHJcbi8vIHVzaW5nIENTUyB0cmFuc2xhdGUgb3IgdG9wL2xlZnQgcG9zaXRpb25pbmcgZGVwZW5kaW5nIG9uIHRoZSBicm93c2VyXHJcbi8vICh1c2VkIGJ5IExlYWZsZXQgaW50ZXJuYWxseSB0byBwb3NpdGlvbiBpdHMgbGF5ZXJzKS5cclxuZnVuY3Rpb24gc2V0UG9zaXRpb24oZWwsIHBvaW50KSB7XHJcblxyXG5cdC8qZXNsaW50LWRpc2FibGUgKi9cclxuXHRlbC5fbGVhZmxldF9wb3MgPSBwb2ludDtcclxuXHQvKiBlc2xpbnQtZW5hYmxlICovXHJcblxyXG5cdGlmIChhbnkzZCkge1xyXG5cdFx0c2V0VHJhbnNmb3JtKGVsLCBwb2ludCk7XHJcblx0fSBlbHNlIHtcclxuXHRcdGVsLnN0eWxlLmxlZnQgPSBwb2ludC54ICsgJ3B4JztcclxuXHRcdGVsLnN0eWxlLnRvcCA9IHBvaW50LnkgKyAncHgnO1xyXG5cdH1cclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIGdldFBvc2l0aW9uKGVsOiBIVE1MRWxlbWVudCk6IFBvaW50XHJcbi8vIFJldHVybnMgdGhlIGNvb3JkaW5hdGVzIG9mIGFuIGVsZW1lbnQgcHJldmlvdXNseSBwb3NpdGlvbmVkIHdpdGggc2V0UG9zaXRpb24uXHJcbmZ1bmN0aW9uIGdldFBvc2l0aW9uKGVsKSB7XHJcblx0Ly8gdGhpcyBtZXRob2QgaXMgb25seSB1c2VkIGZvciBlbGVtZW50cyBwcmV2aW91c2x5IHBvc2l0aW9uZWQgdXNpbmcgc2V0UG9zaXRpb24sXHJcblx0Ly8gc28gaXQncyBzYWZlIHRvIGNhY2hlIHRoZSBwb3NpdGlvbiBmb3IgcGVyZm9ybWFuY2VcclxuXHJcblx0cmV0dXJuIGVsLl9sZWFmbGV0X3BvcyB8fCBuZXcgUG9pbnQoMCwgMCk7XHJcbn1cclxuXHJcbi8vIEBmdW5jdGlvbiBkaXNhYmxlVGV4dFNlbGVjdGlvbigpXHJcbi8vIFByZXZlbnRzIHRoZSB1c2VyIGZyb20gZ2VuZXJhdGluZyBgc2VsZWN0c3RhcnRgIERPTSBldmVudHMsIHVzdWFsbHkgZ2VuZXJhdGVkXHJcbi8vIHdoZW4gdGhlIHVzZXIgZHJhZ3MgdGhlIG1vdXNlIHRocm91Z2ggYSBwYWdlIHdpdGggdGV4dC4gVXNlZCBpbnRlcm5hbGx5XHJcbi8vIGJ5IExlYWZsZXQgdG8gb3ZlcnJpZGUgdGhlIGJlaGF2aW91ciBvZiBhbnkgY2xpY2stYW5kLWRyYWcgaW50ZXJhY3Rpb24gb25cclxuLy8gdGhlIG1hcC4gQWZmZWN0cyBkcmFnIGludGVyYWN0aW9ucyBvbiB0aGUgd2hvbGUgZG9jdW1lbnQuXHJcblxyXG4vLyBAZnVuY3Rpb24gZW5hYmxlVGV4dFNlbGVjdGlvbigpXHJcbi8vIENhbmNlbHMgdGhlIGVmZmVjdHMgb2YgYSBwcmV2aW91cyBbYEwuRG9tVXRpbC5kaXNhYmxlVGV4dFNlbGVjdGlvbmBdKCNkb211dGlsLWRpc2FibGV0ZXh0c2VsZWN0aW9uKS5cclxudmFyIGRpc2FibGVUZXh0U2VsZWN0aW9uO1xyXG52YXIgZW5hYmxlVGV4dFNlbGVjdGlvbjtcclxudmFyIF91c2VyU2VsZWN0O1xyXG5pZiAoJ29uc2VsZWN0c3RhcnQnIGluIGRvY3VtZW50KSB7XHJcblx0ZGlzYWJsZVRleHRTZWxlY3Rpb24gPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRvbih3aW5kb3csICdzZWxlY3RzdGFydCcsIHByZXZlbnREZWZhdWx0KTtcclxuXHR9O1xyXG5cdGVuYWJsZVRleHRTZWxlY3Rpb24gPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRvZmYod2luZG93LCAnc2VsZWN0c3RhcnQnLCBwcmV2ZW50RGVmYXVsdCk7XHJcblx0fTtcclxufSBlbHNlIHtcclxuXHR2YXIgdXNlclNlbGVjdFByb3BlcnR5ID0gdGVzdFByb3AoXHJcblx0XHRbJ3VzZXJTZWxlY3QnLCAnV2Via2l0VXNlclNlbGVjdCcsICdPVXNlclNlbGVjdCcsICdNb3pVc2VyU2VsZWN0JywgJ21zVXNlclNlbGVjdCddKTtcclxuXHJcblx0ZGlzYWJsZVRleHRTZWxlY3Rpb24gPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAodXNlclNlbGVjdFByb3BlcnR5KSB7XHJcblx0XHRcdHZhciBzdHlsZSA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZTtcclxuXHRcdFx0X3VzZXJTZWxlY3QgPSBzdHlsZVt1c2VyU2VsZWN0UHJvcGVydHldO1xyXG5cdFx0XHRzdHlsZVt1c2VyU2VsZWN0UHJvcGVydHldID0gJ25vbmUnO1xyXG5cdFx0fVxyXG5cdH07XHJcblx0ZW5hYmxlVGV4dFNlbGVjdGlvbiA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICh1c2VyU2VsZWN0UHJvcGVydHkpIHtcclxuXHRcdFx0ZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlW3VzZXJTZWxlY3RQcm9wZXJ0eV0gPSBfdXNlclNlbGVjdDtcclxuXHRcdFx0X3VzZXJTZWxlY3QgPSB1bmRlZmluZWQ7XHJcblx0XHR9XHJcblx0fTtcclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIGRpc2FibGVJbWFnZURyYWcoKVxyXG4vLyBBcyBbYEwuRG9tVXRpbC5kaXNhYmxlVGV4dFNlbGVjdGlvbmBdKCNkb211dGlsLWRpc2FibGV0ZXh0c2VsZWN0aW9uKSwgYnV0XHJcbi8vIGZvciBgZHJhZ3N0YXJ0YCBET00gZXZlbnRzLCB1c3VhbGx5IGdlbmVyYXRlZCB3aGVuIHRoZSB1c2VyIGRyYWdzIGFuIGltYWdlLlxyXG5mdW5jdGlvbiBkaXNhYmxlSW1hZ2VEcmFnKCkge1xyXG5cdG9uKHdpbmRvdywgJ2RyYWdzdGFydCcsIHByZXZlbnREZWZhdWx0KTtcclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIGVuYWJsZUltYWdlRHJhZygpXHJcbi8vIENhbmNlbHMgdGhlIGVmZmVjdHMgb2YgYSBwcmV2aW91cyBbYEwuRG9tVXRpbC5kaXNhYmxlSW1hZ2VEcmFnYF0oI2RvbXV0aWwtZGlzYWJsZXRleHRzZWxlY3Rpb24pLlxyXG5mdW5jdGlvbiBlbmFibGVJbWFnZURyYWcoKSB7XHJcblx0b2ZmKHdpbmRvdywgJ2RyYWdzdGFydCcsIHByZXZlbnREZWZhdWx0KTtcclxufVxyXG5cclxudmFyIF9vdXRsaW5lRWxlbWVudDtcbnZhciBfb3V0bGluZVN0eWxlO1xyXG4vLyBAZnVuY3Rpb24gcHJldmVudE91dGxpbmUoZWw6IEhUTUxFbGVtZW50KVxyXG4vLyBNYWtlcyB0aGUgW291dGxpbmVdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL0NTUy9vdXRsaW5lKVxyXG4vLyBvZiB0aGUgZWxlbWVudCBgZWxgIGludmlzaWJsZS4gVXNlZCBpbnRlcm5hbGx5IGJ5IExlYWZsZXQgdG8gcHJldmVudFxyXG4vLyBmb2N1c2FibGUgZWxlbWVudHMgZnJvbSBkaXNwbGF5aW5nIGFuIG91dGxpbmUgd2hlbiB0aGUgdXNlciBwZXJmb3JtcyBhXHJcbi8vIGRyYWcgaW50ZXJhY3Rpb24gb24gdGhlbS5cclxuZnVuY3Rpb24gcHJldmVudE91dGxpbmUoZWxlbWVudCkge1xyXG5cdHdoaWxlIChlbGVtZW50LnRhYkluZGV4ID09PSAtMSkge1xyXG5cdFx0ZWxlbWVudCA9IGVsZW1lbnQucGFyZW50Tm9kZTtcclxuXHR9XHJcblx0aWYgKCFlbGVtZW50LnN0eWxlKSB7IHJldHVybjsgfVxyXG5cdHJlc3RvcmVPdXRsaW5lKCk7XHJcblx0X291dGxpbmVFbGVtZW50ID0gZWxlbWVudDtcclxuXHRfb3V0bGluZVN0eWxlID0gZWxlbWVudC5zdHlsZS5vdXRsaW5lO1xyXG5cdGVsZW1lbnQuc3R5bGUub3V0bGluZSA9ICdub25lJztcclxuXHRvbih3aW5kb3csICdrZXlkb3duJywgcmVzdG9yZU91dGxpbmUpO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gcmVzdG9yZU91dGxpbmUoKVxyXG4vLyBDYW5jZWxzIHRoZSBlZmZlY3RzIG9mIGEgcHJldmlvdXMgW2BMLkRvbVV0aWwucHJldmVudE91dGxpbmVgXSgpLlxyXG5mdW5jdGlvbiByZXN0b3JlT3V0bGluZSgpIHtcclxuXHRpZiAoIV9vdXRsaW5lRWxlbWVudCkgeyByZXR1cm47IH1cclxuXHRfb3V0bGluZUVsZW1lbnQuc3R5bGUub3V0bGluZSA9IF9vdXRsaW5lU3R5bGU7XHJcblx0X291dGxpbmVFbGVtZW50ID0gdW5kZWZpbmVkO1xyXG5cdF9vdXRsaW5lU3R5bGUgPSB1bmRlZmluZWQ7XHJcblx0b2ZmKHdpbmRvdywgJ2tleWRvd24nLCByZXN0b3JlT3V0bGluZSk7XHJcbn1cclxuXG5cbnZhciBEb21VdGlsID0gKE9iamVjdC5mcmVlemUgfHwgT2JqZWN0KSh7XG5cdFRSQU5TRk9STTogVFJBTlNGT1JNLFxuXHRUUkFOU0lUSU9OOiBUUkFOU0lUSU9OLFxuXHRUUkFOU0lUSU9OX0VORDogVFJBTlNJVElPTl9FTkQsXG5cdGdldDogZ2V0LFxuXHRnZXRTdHlsZTogZ2V0U3R5bGUsXG5cdGNyZWF0ZTogY3JlYXRlJDEsXG5cdHJlbW92ZTogcmVtb3ZlLFxuXHRlbXB0eTogZW1wdHksXG5cdHRvRnJvbnQ6IHRvRnJvbnQsXG5cdHRvQmFjazogdG9CYWNrLFxuXHRoYXNDbGFzczogaGFzQ2xhc3MsXG5cdGFkZENsYXNzOiBhZGRDbGFzcyxcblx0cmVtb3ZlQ2xhc3M6IHJlbW92ZUNsYXNzLFxuXHRzZXRDbGFzczogc2V0Q2xhc3MsXG5cdGdldENsYXNzOiBnZXRDbGFzcyxcblx0c2V0T3BhY2l0eTogc2V0T3BhY2l0eSxcblx0dGVzdFByb3A6IHRlc3RQcm9wLFxuXHRzZXRUcmFuc2Zvcm06IHNldFRyYW5zZm9ybSxcblx0c2V0UG9zaXRpb246IHNldFBvc2l0aW9uLFxuXHRnZXRQb3NpdGlvbjogZ2V0UG9zaXRpb24sXG5cdGRpc2FibGVUZXh0U2VsZWN0aW9uOiBkaXNhYmxlVGV4dFNlbGVjdGlvbixcblx0ZW5hYmxlVGV4dFNlbGVjdGlvbjogZW5hYmxlVGV4dFNlbGVjdGlvbixcblx0ZGlzYWJsZUltYWdlRHJhZzogZGlzYWJsZUltYWdlRHJhZyxcblx0ZW5hYmxlSW1hZ2VEcmFnOiBlbmFibGVJbWFnZURyYWcsXG5cdHByZXZlbnRPdXRsaW5lOiBwcmV2ZW50T3V0bGluZSxcblx0cmVzdG9yZU91dGxpbmU6IHJlc3RvcmVPdXRsaW5lXG59KTtcblxuLypcbiAqIEBjbGFzcyBQb3NBbmltYXRpb25cbiAqIEBha2EgTC5Qb3NBbmltYXRpb25cbiAqIEBpbmhlcml0cyBFdmVudGVkXG4gKiBVc2VkIGludGVybmFsbHkgZm9yIHBhbm5pbmcgYW5pbWF0aW9ucywgdXRpbGl6aW5nIENTUzMgVHJhbnNpdGlvbnMgZm9yIG1vZGVybiBicm93c2VycyBhbmQgYSB0aW1lciBmYWxsYmFjayBmb3IgSUU2LTkuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYGpzXG4gKiB2YXIgZnggPSBuZXcgTC5Qb3NBbmltYXRpb24oKTtcbiAqIGZ4LnJ1bihlbCwgWzMwMCwgNTAwXSwgMC41KTtcbiAqIGBgYFxuICpcbiAqIEBjb25zdHJ1Y3RvciBMLlBvc0FuaW1hdGlvbigpXG4gKiBDcmVhdGVzIGEgYFBvc0FuaW1hdGlvbmAgb2JqZWN0LlxuICpcbiAqL1xuXG52YXIgUG9zQW5pbWF0aW9uID0gRXZlbnRlZC5leHRlbmQoe1xuXG5cdC8vIEBtZXRob2QgcnVuKGVsOiBIVE1MRWxlbWVudCwgbmV3UG9zOiBQb2ludCwgZHVyYXRpb24/OiBOdW1iZXIsIGVhc2VMaW5lYXJpdHk/OiBOdW1iZXIpXG5cdC8vIFJ1biBhbiBhbmltYXRpb24gb2YgYSBnaXZlbiBlbGVtZW50IHRvIGEgbmV3IHBvc2l0aW9uLCBvcHRpb25hbGx5IHNldHRpbmdcblx0Ly8gZHVyYXRpb24gaW4gc2Vjb25kcyAoYDAuMjVgIGJ5IGRlZmF1bHQpIGFuZCBlYXNpbmcgbGluZWFyaXR5IGZhY3RvciAoM3JkXG5cdC8vIGFyZ3VtZW50IG9mIHRoZSBbY3ViaWMgYmV6aWVyIGN1cnZlXShodHRwOi8vY3ViaWMtYmV6aWVyLmNvbS8jMCwwLC41LDEpLFxuXHQvLyBgMC41YCBieSBkZWZhdWx0KS5cblx0cnVuOiBmdW5jdGlvbiAoZWwsIG5ld1BvcywgZHVyYXRpb24sIGVhc2VMaW5lYXJpdHkpIHtcblx0XHR0aGlzLnN0b3AoKTtcblxuXHRcdHRoaXMuX2VsID0gZWw7XG5cdFx0dGhpcy5faW5Qcm9ncmVzcyA9IHRydWU7XG5cdFx0dGhpcy5fZHVyYXRpb24gPSBkdXJhdGlvbiB8fCAwLjI1O1xuXHRcdHRoaXMuX2Vhc2VPdXRQb3dlciA9IDEgLyBNYXRoLm1heChlYXNlTGluZWFyaXR5IHx8IDAuNSwgMC4yKTtcblxuXHRcdHRoaXMuX3N0YXJ0UG9zID0gZ2V0UG9zaXRpb24oZWwpO1xuXHRcdHRoaXMuX29mZnNldCA9IG5ld1Bvcy5zdWJ0cmFjdCh0aGlzLl9zdGFydFBvcyk7XG5cdFx0dGhpcy5fc3RhcnRUaW1lID0gK25ldyBEYXRlKCk7XG5cblx0XHQvLyBAZXZlbnQgc3RhcnQ6IEV2ZW50XG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgYW5pbWF0aW9uIHN0YXJ0c1xuXHRcdHRoaXMuZmlyZSgnc3RhcnQnKTtcblxuXHRcdHRoaXMuX2FuaW1hdGUoKTtcblx0fSxcblxuXHQvLyBAbWV0aG9kIHN0b3AoKVxuXHQvLyBTdG9wcyB0aGUgYW5pbWF0aW9uIChpZiBjdXJyZW50bHkgcnVubmluZykuXG5cdHN0b3A6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAoIXRoaXMuX2luUHJvZ3Jlc3MpIHsgcmV0dXJuOyB9XG5cblx0XHR0aGlzLl9zdGVwKHRydWUpO1xuXHRcdHRoaXMuX2NvbXBsZXRlKCk7XG5cdH0sXG5cblx0X2FuaW1hdGU6IGZ1bmN0aW9uICgpIHtcblx0XHQvLyBhbmltYXRpb24gbG9vcFxuXHRcdHRoaXMuX2FuaW1JZCA9IHJlcXVlc3RBbmltRnJhbWUodGhpcy5fYW5pbWF0ZSwgdGhpcyk7XG5cdFx0dGhpcy5fc3RlcCgpO1xuXHR9LFxuXG5cdF9zdGVwOiBmdW5jdGlvbiAocm91bmQpIHtcblx0XHR2YXIgZWxhcHNlZCA9ICgrbmV3IERhdGUoKSkgLSB0aGlzLl9zdGFydFRpbWUsXG5cdFx0ICAgIGR1cmF0aW9uID0gdGhpcy5fZHVyYXRpb24gKiAxMDAwO1xuXG5cdFx0aWYgKGVsYXBzZWQgPCBkdXJhdGlvbikge1xuXHRcdFx0dGhpcy5fcnVuRnJhbWUodGhpcy5fZWFzZU91dChlbGFwc2VkIC8gZHVyYXRpb24pLCByb3VuZCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuX3J1bkZyYW1lKDEpO1xuXHRcdFx0dGhpcy5fY29tcGxldGUoKTtcblx0XHR9XG5cdH0sXG5cblx0X3J1bkZyYW1lOiBmdW5jdGlvbiAocHJvZ3Jlc3MsIHJvdW5kKSB7XG5cdFx0dmFyIHBvcyA9IHRoaXMuX3N0YXJ0UG9zLmFkZCh0aGlzLl9vZmZzZXQubXVsdGlwbHlCeShwcm9ncmVzcykpO1xuXHRcdGlmIChyb3VuZCkge1xuXHRcdFx0cG9zLl9yb3VuZCgpO1xuXHRcdH1cblx0XHRzZXRQb3NpdGlvbih0aGlzLl9lbCwgcG9zKTtcblxuXHRcdC8vIEBldmVudCBzdGVwOiBFdmVudFxuXHRcdC8vIEZpcmVkIGNvbnRpbnVvdXNseSBkdXJpbmcgdGhlIGFuaW1hdGlvbi5cblx0XHR0aGlzLmZpcmUoJ3N0ZXAnKTtcblx0fSxcblxuXHRfY29tcGxldGU6IGZ1bmN0aW9uICgpIHtcblx0XHRjYW5jZWxBbmltRnJhbWUodGhpcy5fYW5pbUlkKTtcblxuXHRcdHRoaXMuX2luUHJvZ3Jlc3MgPSBmYWxzZTtcblx0XHQvLyBAZXZlbnQgZW5kOiBFdmVudFxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIGFuaW1hdGlvbiBlbmRzLlxuXHRcdHRoaXMuZmlyZSgnZW5kJyk7XG5cdH0sXG5cblx0X2Vhc2VPdXQ6IGZ1bmN0aW9uICh0KSB7XG5cdFx0cmV0dXJuIDEgLSBNYXRoLnBvdygxIC0gdCwgdGhpcy5fZWFzZU91dFBvd2VyKTtcblx0fVxufSk7XG5cbi8qXHJcbiAqIEBjbGFzcyBNYXBcclxuICogQGFrYSBMLk1hcFxyXG4gKiBAaW5oZXJpdHMgRXZlbnRlZFxyXG4gKlxyXG4gKiBUaGUgY2VudHJhbCBjbGFzcyBvZiB0aGUgQVBJIOKAlCBpdCBpcyB1c2VkIHRvIGNyZWF0ZSBhIG1hcCBvbiBhIHBhZ2UgYW5kIG1hbmlwdWxhdGUgaXQuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIC8vIGluaXRpYWxpemUgdGhlIG1hcCBvbiB0aGUgXCJtYXBcIiBkaXYgd2l0aCBhIGdpdmVuIGNlbnRlciBhbmQgem9vbVxyXG4gKiB2YXIgbWFwID0gTC5tYXAoJ21hcCcsIHtcclxuICogXHRjZW50ZXI6IFs1MS41MDUsIC0wLjA5XSxcclxuICogXHR6b29tOiAxM1xyXG4gKiB9KTtcclxuICogYGBgXHJcbiAqXHJcbiAqL1xyXG5cclxudmFyIE1hcCA9IEV2ZW50ZWQuZXh0ZW5kKHtcclxuXHJcblx0b3B0aW9uczoge1xyXG5cdFx0Ly8gQHNlY3Rpb24gTWFwIFN0YXRlIE9wdGlvbnNcclxuXHRcdC8vIEBvcHRpb24gY3JzOiBDUlMgPSBMLkNSUy5FUFNHMzg1N1xyXG5cdFx0Ly8gVGhlIFtDb29yZGluYXRlIFJlZmVyZW5jZSBTeXN0ZW1dKCNjcnMpIHRvIHVzZS4gRG9uJ3QgY2hhbmdlIHRoaXMgaWYgeW91J3JlIG5vdFxyXG5cdFx0Ly8gc3VyZSB3aGF0IGl0IG1lYW5zLlxyXG5cdFx0Y3JzOiBFUFNHMzg1NyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGNlbnRlcjogTGF0TG5nID0gdW5kZWZpbmVkXHJcblx0XHQvLyBJbml0aWFsIGdlb2dyYXBoaWMgY2VudGVyIG9mIHRoZSBtYXBcclxuXHRcdGNlbnRlcjogdW5kZWZpbmVkLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gem9vbTogTnVtYmVyID0gdW5kZWZpbmVkXHJcblx0XHQvLyBJbml0aWFsIG1hcCB6b29tIGxldmVsXHJcblx0XHR6b29tOiB1bmRlZmluZWQsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBtaW5ab29tOiBOdW1iZXIgPSAqXHJcblx0XHQvLyBNaW5pbXVtIHpvb20gbGV2ZWwgb2YgdGhlIG1hcC5cclxuXHRcdC8vIElmIG5vdCBzcGVjaWZpZWQgYW5kIGF0IGxlYXN0IG9uZSBgR3JpZExheWVyYCBvciBgVGlsZUxheWVyYCBpcyBpbiB0aGUgbWFwLFxyXG5cdFx0Ly8gdGhlIGxvd2VzdCBvZiB0aGVpciBgbWluWm9vbWAgb3B0aW9ucyB3aWxsIGJlIHVzZWQgaW5zdGVhZC5cclxuXHRcdG1pblpvb206IHVuZGVmaW5lZCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIG1heFpvb206IE51bWJlciA9ICpcclxuXHRcdC8vIE1heGltdW0gem9vbSBsZXZlbCBvZiB0aGUgbWFwLlxyXG5cdFx0Ly8gSWYgbm90IHNwZWNpZmllZCBhbmQgYXQgbGVhc3Qgb25lIGBHcmlkTGF5ZXJgIG9yIGBUaWxlTGF5ZXJgIGlzIGluIHRoZSBtYXAsXHJcblx0XHQvLyB0aGUgaGlnaGVzdCBvZiB0aGVpciBgbWF4Wm9vbWAgb3B0aW9ucyB3aWxsIGJlIHVzZWQgaW5zdGVhZC5cclxuXHRcdG1heFpvb206IHVuZGVmaW5lZCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGxheWVyczogTGF5ZXJbXSA9IFtdXHJcblx0XHQvLyBBcnJheSBvZiBsYXllcnMgdGhhdCB3aWxsIGJlIGFkZGVkIHRvIHRoZSBtYXAgaW5pdGlhbGx5XHJcblx0XHRsYXllcnM6IFtdLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gbWF4Qm91bmRzOiBMYXRMbmdCb3VuZHMgPSBudWxsXHJcblx0XHQvLyBXaGVuIHRoaXMgb3B0aW9uIGlzIHNldCwgdGhlIG1hcCByZXN0cmljdHMgdGhlIHZpZXcgdG8gdGhlIGdpdmVuXHJcblx0XHQvLyBnZW9ncmFwaGljYWwgYm91bmRzLCBib3VuY2luZyB0aGUgdXNlciBiYWNrIGlmIHRoZSB1c2VyIHRyaWVzIHRvIHBhblxyXG5cdFx0Ly8gb3V0c2lkZSB0aGUgdmlldy4gVG8gc2V0IHRoZSByZXN0cmljdGlvbiBkeW5hbWljYWxseSwgdXNlXHJcblx0XHQvLyBbYHNldE1heEJvdW5kc2BdKCNtYXAtc2V0bWF4Ym91bmRzKSBtZXRob2QuXHJcblx0XHRtYXhCb3VuZHM6IHVuZGVmaW5lZCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHJlbmRlcmVyOiBSZW5kZXJlciA9ICpcclxuXHRcdC8vIFRoZSBkZWZhdWx0IG1ldGhvZCBmb3IgZHJhd2luZyB2ZWN0b3IgbGF5ZXJzIG9uIHRoZSBtYXAuIGBMLlNWR2BcclxuXHRcdC8vIG9yIGBMLkNhbnZhc2AgYnkgZGVmYXVsdCBkZXBlbmRpbmcgb24gYnJvd3NlciBzdXBwb3J0LlxyXG5cdFx0cmVuZGVyZXI6IHVuZGVmaW5lZCxcclxuXHJcblxyXG5cdFx0Ly8gQHNlY3Rpb24gQW5pbWF0aW9uIE9wdGlvbnNcclxuXHRcdC8vIEBvcHRpb24gem9vbUFuaW1hdGlvbjogQm9vbGVhbiA9IHRydWVcclxuXHRcdC8vIFdoZXRoZXIgdGhlIG1hcCB6b29tIGFuaW1hdGlvbiBpcyBlbmFibGVkLiBCeSBkZWZhdWx0IGl0J3MgZW5hYmxlZFxyXG5cdFx0Ly8gaW4gYWxsIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCBDU1MzIFRyYW5zaXRpb25zIGV4Y2VwdCBBbmRyb2lkLlxyXG5cdFx0em9vbUFuaW1hdGlvbjogdHJ1ZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHpvb21BbmltYXRpb25UaHJlc2hvbGQ6IE51bWJlciA9IDRcclxuXHRcdC8vIFdvbid0IGFuaW1hdGUgem9vbSBpZiB0aGUgem9vbSBkaWZmZXJlbmNlIGV4Y2VlZHMgdGhpcyB2YWx1ZS5cclxuXHRcdHpvb21BbmltYXRpb25UaHJlc2hvbGQ6IDQsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBmYWRlQW5pbWF0aW9uOiBCb29sZWFuID0gdHJ1ZVxyXG5cdFx0Ly8gV2hldGhlciB0aGUgdGlsZSBmYWRlIGFuaW1hdGlvbiBpcyBlbmFibGVkLiBCeSBkZWZhdWx0IGl0J3MgZW5hYmxlZFxyXG5cdFx0Ly8gaW4gYWxsIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCBDU1MzIFRyYW5zaXRpb25zIGV4Y2VwdCBBbmRyb2lkLlxyXG5cdFx0ZmFkZUFuaW1hdGlvbjogdHJ1ZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIG1hcmtlclpvb21BbmltYXRpb246IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBXaGV0aGVyIG1hcmtlcnMgYW5pbWF0ZSB0aGVpciB6b29tIHdpdGggdGhlIHpvb20gYW5pbWF0aW9uLCBpZiBkaXNhYmxlZFxyXG5cdFx0Ly8gdGhleSB3aWxsIGRpc2FwcGVhciBmb3IgdGhlIGxlbmd0aCBvZiB0aGUgYW5pbWF0aW9uLiBCeSBkZWZhdWx0IGl0J3NcclxuXHRcdC8vIGVuYWJsZWQgaW4gYWxsIGJyb3dzZXJzIHRoYXQgc3VwcG9ydCBDU1MzIFRyYW5zaXRpb25zIGV4Y2VwdCBBbmRyb2lkLlxyXG5cdFx0bWFya2VyWm9vbUFuaW1hdGlvbjogdHJ1ZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHRyYW5zZm9ybTNETGltaXQ6IE51bWJlciA9IDJeMjNcclxuXHRcdC8vIERlZmluZXMgdGhlIG1heGltdW0gc2l6ZSBvZiBhIENTUyB0cmFuc2xhdGlvbiB0cmFuc2Zvcm0uIFRoZSBkZWZhdWx0XHJcblx0XHQvLyB2YWx1ZSBzaG91bGQgbm90IGJlIGNoYW5nZWQgdW5sZXNzIGEgd2ViIGJyb3dzZXIgcG9zaXRpb25zIGxheWVycyBpblxyXG5cdFx0Ly8gdGhlIHdyb25nIHBsYWNlIGFmdGVyIGRvaW5nIGEgbGFyZ2UgYHBhbkJ5YC5cclxuXHRcdHRyYW5zZm9ybTNETGltaXQ6IDgzODg2MDgsIC8vIFByZWNpc2lvbiBsaW1pdCBvZiBhIDMyLWJpdCBmbG9hdFxyXG5cclxuXHRcdC8vIEBzZWN0aW9uIEludGVyYWN0aW9uIE9wdGlvbnNcclxuXHRcdC8vIEBvcHRpb24gem9vbVNuYXA6IE51bWJlciA9IDFcclxuXHRcdC8vIEZvcmNlcyB0aGUgbWFwJ3Mgem9vbSBsZXZlbCB0byBhbHdheXMgYmUgYSBtdWx0aXBsZSBvZiB0aGlzLCBwYXJ0aWN1bGFybHlcclxuXHRcdC8vIHJpZ2h0IGFmdGVyIGEgW2BmaXRCb3VuZHMoKWBdKCNtYXAtZml0Ym91bmRzKSBvciBhIHBpbmNoLXpvb20uXHJcblx0XHQvLyBCeSBkZWZhdWx0LCB0aGUgem9vbSBsZXZlbCBzbmFwcyB0byB0aGUgbmVhcmVzdCBpbnRlZ2VyOyBsb3dlciB2YWx1ZXNcclxuXHRcdC8vIChlLmcuIGAwLjVgIG9yIGAwLjFgKSBhbGxvdyBmb3IgZ3JlYXRlciBncmFudWxhcml0eS4gQSB2YWx1ZSBvZiBgMGBcclxuXHRcdC8vIG1lYW5zIHRoZSB6b29tIGxldmVsIHdpbGwgbm90IGJlIHNuYXBwZWQgYWZ0ZXIgYGZpdEJvdW5kc2Agb3IgYSBwaW5jaC16b29tLlxyXG5cdFx0em9vbVNuYXA6IDEsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiB6b29tRGVsdGE6IE51bWJlciA9IDFcclxuXHRcdC8vIENvbnRyb2xzIGhvdyBtdWNoIHRoZSBtYXAncyB6b29tIGxldmVsIHdpbGwgY2hhbmdlIGFmdGVyIGFcclxuXHRcdC8vIFtgem9vbUluKClgXSgjbWFwLXpvb21pbiksIFtgem9vbU91dCgpYF0oI21hcC16b29tb3V0KSwgcHJlc3NpbmcgYCtgXHJcblx0XHQvLyBvciBgLWAgb24gdGhlIGtleWJvYXJkLCBvciB1c2luZyB0aGUgW3pvb20gY29udHJvbHNdKCNjb250cm9sLXpvb20pLlxyXG5cdFx0Ly8gVmFsdWVzIHNtYWxsZXIgdGhhbiBgMWAgKGUuZy4gYDAuNWApIGFsbG93IGZvciBncmVhdGVyIGdyYW51bGFyaXR5LlxyXG5cdFx0em9vbURlbHRhOiAxLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gdHJhY2tSZXNpemU6IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBXaGV0aGVyIHRoZSBtYXAgYXV0b21hdGljYWxseSBoYW5kbGVzIGJyb3dzZXIgd2luZG93IHJlc2l6ZSB0byB1cGRhdGUgaXRzZWxmLlxyXG5cdFx0dHJhY2tSZXNpemU6IHRydWVcclxuXHR9LFxyXG5cclxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAoaWQsIG9wdGlvbnMpIHsgLy8gKEhUTUxFbGVtZW50IG9yIFN0cmluZywgT2JqZWN0KVxyXG5cdFx0b3B0aW9ucyA9IHNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XHJcblxyXG5cdFx0dGhpcy5faW5pdENvbnRhaW5lcihpZCk7XHJcblx0XHR0aGlzLl9pbml0TGF5b3V0KCk7XHJcblxyXG5cdFx0Ly8gaGFjayBmb3IgaHR0cHM6Ly9naXRodWIuY29tL0xlYWZsZXQvTGVhZmxldC9pc3N1ZXMvMTk4MFxyXG5cdFx0dGhpcy5fb25SZXNpemUgPSBiaW5kKHRoaXMuX29uUmVzaXplLCB0aGlzKTtcclxuXHJcblx0XHR0aGlzLl9pbml0RXZlbnRzKCk7XHJcblxyXG5cdFx0aWYgKG9wdGlvbnMubWF4Qm91bmRzKSB7XHJcblx0XHRcdHRoaXMuc2V0TWF4Qm91bmRzKG9wdGlvbnMubWF4Qm91bmRzKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAob3B0aW9ucy56b29tICE9PSB1bmRlZmluZWQpIHtcclxuXHRcdFx0dGhpcy5fem9vbSA9IHRoaXMuX2xpbWl0Wm9vbShvcHRpb25zLnpvb20pO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChvcHRpb25zLmNlbnRlciAmJiBvcHRpb25zLnpvb20gIT09IHVuZGVmaW5lZCkge1xyXG5cdFx0XHR0aGlzLnNldFZpZXcodG9MYXRMbmcob3B0aW9ucy5jZW50ZXIpLCBvcHRpb25zLnpvb20sIHtyZXNldDogdHJ1ZX0pO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2hhbmRsZXJzID0gW107XHJcblx0XHR0aGlzLl9sYXllcnMgPSB7fTtcclxuXHRcdHRoaXMuX3pvb21Cb3VuZExheWVycyA9IHt9O1xyXG5cdFx0dGhpcy5fc2l6ZUNoYW5nZWQgPSB0cnVlO1xyXG5cclxuXHRcdHRoaXMuY2FsbEluaXRIb29rcygpO1xyXG5cclxuXHRcdC8vIGRvbid0IGFuaW1hdGUgb24gYnJvd3NlcnMgd2l0aG91dCBoYXJkd2FyZS1hY2NlbGVyYXRlZCB0cmFuc2l0aW9ucyBvciBvbGQgQW5kcm9pZC9PcGVyYVxyXG5cdFx0dGhpcy5fem9vbUFuaW1hdGVkID0gVFJBTlNJVElPTiAmJiBhbnkzZCAmJiAhbW9iaWxlT3BlcmEgJiZcclxuXHRcdFx0XHR0aGlzLm9wdGlvbnMuem9vbUFuaW1hdGlvbjtcclxuXHJcblx0XHQvLyB6b29tIHRyYW5zaXRpb25zIHJ1biB3aXRoIHRoZSBzYW1lIGR1cmF0aW9uIGZvciBhbGwgbGF5ZXJzLCBzbyBpZiBvbmUgb2YgdHJhbnNpdGlvbmVuZCBldmVudHNcclxuXHRcdC8vIGhhcHBlbnMgYWZ0ZXIgc3RhcnRpbmcgem9vbSBhbmltYXRpb24gKHByb3BhZ2F0aW5nIHRvIHRoZSBtYXAgcGFuZSksIHdlIGtub3cgdGhhdCBpdCBlbmRlZCBnbG9iYWxseVxyXG5cdFx0aWYgKHRoaXMuX3pvb21BbmltYXRlZCkge1xyXG5cdFx0XHR0aGlzLl9jcmVhdGVBbmltUHJveHkoKTtcclxuXHRcdFx0b24odGhpcy5fcHJveHksIFRSQU5TSVRJT05fRU5ELCB0aGlzLl9jYXRjaFRyYW5zaXRpb25FbmQsIHRoaXMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2FkZExheWVycyh0aGlzLm9wdGlvbnMubGF5ZXJzKTtcclxuXHR9LFxyXG5cclxuXHJcblx0Ly8gQHNlY3Rpb24gTWV0aG9kcyBmb3IgbW9kaWZ5aW5nIG1hcCBzdGF0ZVxyXG5cclxuXHQvLyBAbWV0aG9kIHNldFZpZXcoY2VudGVyOiBMYXRMbmcsIHpvb206IE51bWJlciwgb3B0aW9ucz86IFpvb20vcGFuIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gU2V0cyB0aGUgdmlldyBvZiB0aGUgbWFwIChnZW9ncmFwaGljYWwgY2VudGVyIGFuZCB6b29tKSB3aXRoIHRoZSBnaXZlblxyXG5cdC8vIGFuaW1hdGlvbiBvcHRpb25zLlxyXG5cdHNldFZpZXc6IGZ1bmN0aW9uIChjZW50ZXIsIHpvb20sIG9wdGlvbnMpIHtcclxuXHJcblx0XHR6b29tID0gem9vbSA9PT0gdW5kZWZpbmVkID8gdGhpcy5fem9vbSA6IHRoaXMuX2xpbWl0Wm9vbSh6b29tKTtcclxuXHRcdGNlbnRlciA9IHRoaXMuX2xpbWl0Q2VudGVyKHRvTGF0TG5nKGNlbnRlciksIHpvb20sIHRoaXMub3B0aW9ucy5tYXhCb3VuZHMpO1xyXG5cdFx0b3B0aW9ucyA9IG9wdGlvbnMgfHwge307XHJcblxyXG5cdFx0dGhpcy5fc3RvcCgpO1xyXG5cclxuXHRcdGlmICh0aGlzLl9sb2FkZWQgJiYgIW9wdGlvbnMucmVzZXQgJiYgb3B0aW9ucyAhPT0gdHJ1ZSkge1xyXG5cclxuXHRcdFx0aWYgKG9wdGlvbnMuYW5pbWF0ZSAhPT0gdW5kZWZpbmVkKSB7XHJcblx0XHRcdFx0b3B0aW9ucy56b29tID0gZXh0ZW5kKHthbmltYXRlOiBvcHRpb25zLmFuaW1hdGV9LCBvcHRpb25zLnpvb20pO1xyXG5cdFx0XHRcdG9wdGlvbnMucGFuID0gZXh0ZW5kKHthbmltYXRlOiBvcHRpb25zLmFuaW1hdGUsIGR1cmF0aW9uOiBvcHRpb25zLmR1cmF0aW9ufSwgb3B0aW9ucy5wYW4pO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyB0cnkgYW5pbWF0aW5nIHBhbiBvciB6b29tXHJcblx0XHRcdHZhciBtb3ZlZCA9ICh0aGlzLl96b29tICE9PSB6b29tKSA/XHJcblx0XHRcdFx0dGhpcy5fdHJ5QW5pbWF0ZWRab29tICYmIHRoaXMuX3RyeUFuaW1hdGVkWm9vbShjZW50ZXIsIHpvb20sIG9wdGlvbnMuem9vbSkgOlxyXG5cdFx0XHRcdHRoaXMuX3RyeUFuaW1hdGVkUGFuKGNlbnRlciwgb3B0aW9ucy5wYW4pO1xyXG5cclxuXHRcdFx0aWYgKG1vdmVkKSB7XHJcblx0XHRcdFx0Ly8gcHJldmVudCByZXNpemUgaGFuZGxlciBjYWxsLCB0aGUgdmlldyB3aWxsIHJlZnJlc2ggYWZ0ZXIgYW5pbWF0aW9uIGFueXdheVxyXG5cdFx0XHRcdGNsZWFyVGltZW91dCh0aGlzLl9zaXplVGltZXIpO1xyXG5cdFx0XHRcdHJldHVybiB0aGlzO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYW5pbWF0aW9uIGRpZG4ndCBzdGFydCwganVzdCByZXNldCB0aGUgbWFwIHZpZXdcclxuXHRcdHRoaXMuX3Jlc2V0VmlldyhjZW50ZXIsIHpvb20pO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0Wm9vbSh6b29tOiBOdW1iZXIsIG9wdGlvbnM/OiBab29tL3BhbiBvcHRpb25zKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIHpvb20gb2YgdGhlIG1hcC5cclxuXHRzZXRab29tOiBmdW5jdGlvbiAoem9vbSwgb3B0aW9ucykge1xyXG5cdFx0aWYgKCF0aGlzLl9sb2FkZWQpIHtcclxuXHRcdFx0dGhpcy5fem9vbSA9IHpvb207XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXMuc2V0Vmlldyh0aGlzLmdldENlbnRlcigpLCB6b29tLCB7em9vbTogb3B0aW9uc30pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgem9vbUluKGRlbHRhPzogTnVtYmVyLCBvcHRpb25zPzogWm9vbSBvcHRpb25zKTogdGhpc1xyXG5cdC8vIEluY3JlYXNlcyB0aGUgem9vbSBvZiB0aGUgbWFwIGJ5IGBkZWx0YWAgKFtgem9vbURlbHRhYF0oI21hcC16b29tZGVsdGEpIGJ5IGRlZmF1bHQpLlxyXG5cdHpvb21JbjogZnVuY3Rpb24gKGRlbHRhLCBvcHRpb25zKSB7XHJcblx0XHRkZWx0YSA9IGRlbHRhIHx8IChhbnkzZCA/IHRoaXMub3B0aW9ucy56b29tRGVsdGEgOiAxKTtcclxuXHRcdHJldHVybiB0aGlzLnNldFpvb20odGhpcy5fem9vbSArIGRlbHRhLCBvcHRpb25zKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHpvb21PdXQoZGVsdGE/OiBOdW1iZXIsIG9wdGlvbnM/OiBab29tIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gRGVjcmVhc2VzIHRoZSB6b29tIG9mIHRoZSBtYXAgYnkgYGRlbHRhYCAoW2B6b29tRGVsdGFgXSgjbWFwLXpvb21kZWx0YSkgYnkgZGVmYXVsdCkuXHJcblx0em9vbU91dDogZnVuY3Rpb24gKGRlbHRhLCBvcHRpb25zKSB7XHJcblx0XHRkZWx0YSA9IGRlbHRhIHx8IChhbnkzZCA/IHRoaXMub3B0aW9ucy56b29tRGVsdGEgOiAxKTtcclxuXHRcdHJldHVybiB0aGlzLnNldFpvb20odGhpcy5fem9vbSAtIGRlbHRhLCBvcHRpb25zKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldFpvb21Bcm91bmQobGF0bG5nOiBMYXRMbmcsIHpvb206IE51bWJlciwgb3B0aW9uczogWm9vbSBvcHRpb25zKTogdGhpc1xyXG5cdC8vIFpvb21zIHRoZSBtYXAgd2hpbGUga2VlcGluZyBhIHNwZWNpZmllZCBnZW9ncmFwaGljYWwgcG9pbnQgb24gdGhlIG1hcFxyXG5cdC8vIHN0YXRpb25hcnkgKGUuZy4gdXNlZCBpbnRlcm5hbGx5IGZvciBzY3JvbGwgem9vbSBhbmQgZG91YmxlLWNsaWNrIHpvb20pLlxyXG5cdC8vIEBhbHRlcm5hdGl2ZVxyXG5cdC8vIEBtZXRob2Qgc2V0Wm9vbUFyb3VuZChvZmZzZXQ6IFBvaW50LCB6b29tOiBOdW1iZXIsIG9wdGlvbnM6IFpvb20gb3B0aW9ucyk6IHRoaXNcclxuXHQvLyBab29tcyB0aGUgbWFwIHdoaWxlIGtlZXBpbmcgYSBzcGVjaWZpZWQgcGl4ZWwgb24gdGhlIG1hcCAocmVsYXRpdmUgdG8gdGhlIHRvcC1sZWZ0IGNvcm5lcikgc3RhdGlvbmFyeS5cclxuXHRzZXRab29tQXJvdW5kOiBmdW5jdGlvbiAobGF0bG5nLCB6b29tLCBvcHRpb25zKSB7XHJcblx0XHR2YXIgc2NhbGUgPSB0aGlzLmdldFpvb21TY2FsZSh6b29tKSxcclxuXHRcdCAgICB2aWV3SGFsZiA9IHRoaXMuZ2V0U2l6ZSgpLmRpdmlkZUJ5KDIpLFxyXG5cdFx0ICAgIGNvbnRhaW5lclBvaW50ID0gbGF0bG5nIGluc3RhbmNlb2YgUG9pbnQgPyBsYXRsbmcgOiB0aGlzLmxhdExuZ1RvQ29udGFpbmVyUG9pbnQobGF0bG5nKSxcclxuXHJcblx0XHQgICAgY2VudGVyT2Zmc2V0ID0gY29udGFpbmVyUG9pbnQuc3VidHJhY3Qodmlld0hhbGYpLm11bHRpcGx5QnkoMSAtIDEgLyBzY2FsZSksXHJcblx0XHQgICAgbmV3Q2VudGVyID0gdGhpcy5jb250YWluZXJQb2ludFRvTGF0TG5nKHZpZXdIYWxmLmFkZChjZW50ZXJPZmZzZXQpKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXRWaWV3KG5ld0NlbnRlciwgem9vbSwge3pvb206IG9wdGlvbnN9KTtcclxuXHR9LFxyXG5cclxuXHRfZ2V0Qm91bmRzQ2VudGVyWm9vbTogZnVuY3Rpb24gKGJvdW5kcywgb3B0aW9ucykge1xyXG5cclxuXHRcdG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xyXG5cdFx0Ym91bmRzID0gYm91bmRzLmdldEJvdW5kcyA/IGJvdW5kcy5nZXRCb3VuZHMoKSA6IHRvTGF0TG5nQm91bmRzKGJvdW5kcyk7XHJcblxyXG5cdFx0dmFyIHBhZGRpbmdUTCA9IHRvUG9pbnQob3B0aW9ucy5wYWRkaW5nVG9wTGVmdCB8fCBvcHRpb25zLnBhZGRpbmcgfHwgWzAsIDBdKSxcclxuXHRcdCAgICBwYWRkaW5nQlIgPSB0b1BvaW50KG9wdGlvbnMucGFkZGluZ0JvdHRvbVJpZ2h0IHx8IG9wdGlvbnMucGFkZGluZyB8fCBbMCwgMF0pLFxyXG5cclxuXHRcdCAgICB6b29tID0gdGhpcy5nZXRCb3VuZHNab29tKGJvdW5kcywgZmFsc2UsIHBhZGRpbmdUTC5hZGQocGFkZGluZ0JSKSk7XHJcblxyXG5cdFx0em9vbSA9ICh0eXBlb2Ygb3B0aW9ucy5tYXhab29tID09PSAnbnVtYmVyJykgPyBNYXRoLm1pbihvcHRpb25zLm1heFpvb20sIHpvb20pIDogem9vbTtcclxuXHJcblx0XHRpZiAoem9vbSA9PT0gSW5maW5pdHkpIHtcclxuXHRcdFx0cmV0dXJuIHtcclxuXHRcdFx0XHRjZW50ZXI6IGJvdW5kcy5nZXRDZW50ZXIoKSxcclxuXHRcdFx0XHR6b29tOiB6b29tXHJcblx0XHRcdH07XHJcblx0XHR9XHJcblxyXG5cdFx0dmFyIHBhZGRpbmdPZmZzZXQgPSBwYWRkaW5nQlIuc3VidHJhY3QocGFkZGluZ1RMKS5kaXZpZGVCeSgyKSxcclxuXHJcblx0XHQgICAgc3dQb2ludCA9IHRoaXMucHJvamVjdChib3VuZHMuZ2V0U291dGhXZXN0KCksIHpvb20pLFxyXG5cdFx0ICAgIG5lUG9pbnQgPSB0aGlzLnByb2plY3QoYm91bmRzLmdldE5vcnRoRWFzdCgpLCB6b29tKSxcclxuXHRcdCAgICBjZW50ZXIgPSB0aGlzLnVucHJvamVjdChzd1BvaW50LmFkZChuZVBvaW50KS5kaXZpZGVCeSgyKS5hZGQocGFkZGluZ09mZnNldCksIHpvb20pO1xyXG5cclxuXHRcdHJldHVybiB7XHJcblx0XHRcdGNlbnRlcjogY2VudGVyLFxyXG5cdFx0XHR6b29tOiB6b29tXHJcblx0XHR9O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZml0Qm91bmRzKGJvdW5kczogTGF0TG5nQm91bmRzLCBvcHRpb25zPzogZml0Qm91bmRzIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gU2V0cyBhIG1hcCB2aWV3IHRoYXQgY29udGFpbnMgdGhlIGdpdmVuIGdlb2dyYXBoaWNhbCBib3VuZHMgd2l0aCB0aGVcclxuXHQvLyBtYXhpbXVtIHpvb20gbGV2ZWwgcG9zc2libGUuXHJcblx0Zml0Qm91bmRzOiBmdW5jdGlvbiAoYm91bmRzLCBvcHRpb25zKSB7XHJcblxyXG5cdFx0Ym91bmRzID0gdG9MYXRMbmdCb3VuZHMoYm91bmRzKTtcclxuXHJcblx0XHRpZiAoIWJvdW5kcy5pc1ZhbGlkKCkpIHtcclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdCb3VuZHMgYXJlIG5vdCB2YWxpZC4nKTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgdGFyZ2V0ID0gdGhpcy5fZ2V0Qm91bmRzQ2VudGVyWm9vbShib3VuZHMsIG9wdGlvbnMpO1xyXG5cdFx0cmV0dXJuIHRoaXMuc2V0Vmlldyh0YXJnZXQuY2VudGVyLCB0YXJnZXQuem9vbSwgb3B0aW9ucyk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBmaXRXb3JsZChvcHRpb25zPzogZml0Qm91bmRzIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gU2V0cyBhIG1hcCB2aWV3IHRoYXQgbW9zdGx5IGNvbnRhaW5zIHRoZSB3aG9sZSB3b3JsZCB3aXRoIHRoZSBtYXhpbXVtXHJcblx0Ly8gem9vbSBsZXZlbCBwb3NzaWJsZS5cclxuXHRmaXRXb3JsZDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcclxuXHRcdHJldHVybiB0aGlzLmZpdEJvdW5kcyhbWy05MCwgLTE4MF0sIFs5MCwgMTgwXV0sIG9wdGlvbnMpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgcGFuVG8obGF0bG5nOiBMYXRMbmcsIG9wdGlvbnM/OiBQYW4gb3B0aW9ucyk6IHRoaXNcclxuXHQvLyBQYW5zIHRoZSBtYXAgdG8gYSBnaXZlbiBjZW50ZXIuXHJcblx0cGFuVG86IGZ1bmN0aW9uIChjZW50ZXIsIG9wdGlvbnMpIHsgLy8gKExhdExuZylcclxuXHRcdHJldHVybiB0aGlzLnNldFZpZXcoY2VudGVyLCB0aGlzLl96b29tLCB7cGFuOiBvcHRpb25zfSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBwYW5CeShvZmZzZXQ6IFBvaW50LCBvcHRpb25zPzogUGFuIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gUGFucyB0aGUgbWFwIGJ5IGEgZ2l2ZW4gbnVtYmVyIG9mIHBpeGVscyAoYW5pbWF0ZWQpLlxyXG5cdHBhbkJ5OiBmdW5jdGlvbiAob2Zmc2V0LCBvcHRpb25zKSB7XHJcblx0XHRvZmZzZXQgPSB0b1BvaW50KG9mZnNldCkucm91bmQoKTtcclxuXHRcdG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xyXG5cclxuXHRcdGlmICghb2Zmc2V0LnggJiYgIW9mZnNldC55KSB7XHJcblx0XHRcdHJldHVybiB0aGlzLmZpcmUoJ21vdmVlbmQnKTtcclxuXHRcdH1cclxuXHRcdC8vIElmIHdlIHBhbiB0b28gZmFyLCBDaHJvbWUgZ2V0cyBpc3N1ZXMgd2l0aCB0aWxlc1xyXG5cdFx0Ly8gYW5kIG1ha2VzIHRoZW0gZGlzYXBwZWFyIG9yIGFwcGVhciBpbiB0aGUgd3JvbmcgcGxhY2UgKHNsaWdodGx5IG9mZnNldCkgIzI2MDJcclxuXHRcdGlmIChvcHRpb25zLmFuaW1hdGUgIT09IHRydWUgJiYgIXRoaXMuZ2V0U2l6ZSgpLmNvbnRhaW5zKG9mZnNldCkpIHtcclxuXHRcdFx0dGhpcy5fcmVzZXRWaWV3KHRoaXMudW5wcm9qZWN0KHRoaXMucHJvamVjdCh0aGlzLmdldENlbnRlcigpKS5hZGQob2Zmc2V0KSksIHRoaXMuZ2V0Wm9vbSgpKTtcclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCF0aGlzLl9wYW5BbmltKSB7XHJcblx0XHRcdHRoaXMuX3BhbkFuaW0gPSBuZXcgUG9zQW5pbWF0aW9uKCk7XHJcblxyXG5cdFx0XHR0aGlzLl9wYW5BbmltLm9uKHtcclxuXHRcdFx0XHQnc3RlcCc6IHRoaXMuX29uUGFuVHJhbnNpdGlvblN0ZXAsXHJcblx0XHRcdFx0J2VuZCc6IHRoaXMuX29uUGFuVHJhbnNpdGlvbkVuZFxyXG5cdFx0XHR9LCB0aGlzKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBkb24ndCBmaXJlIG1vdmVzdGFydCBpZiBhbmltYXRpbmcgaW5lcnRpYVxyXG5cdFx0aWYgKCFvcHRpb25zLm5vTW92ZVN0YXJ0KSB7XHJcblx0XHRcdHRoaXMuZmlyZSgnbW92ZXN0YXJ0Jyk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYW5pbWF0ZSBwYW4gdW5sZXNzIGFuaW1hdGU6IGZhbHNlIHNwZWNpZmllZFxyXG5cdFx0aWYgKG9wdGlvbnMuYW5pbWF0ZSAhPT0gZmFsc2UpIHtcclxuXHRcdFx0YWRkQ2xhc3ModGhpcy5fbWFwUGFuZSwgJ2xlYWZsZXQtcGFuLWFuaW0nKTtcclxuXHJcblx0XHRcdHZhciBuZXdQb3MgPSB0aGlzLl9nZXRNYXBQYW5lUG9zKCkuc3VidHJhY3Qob2Zmc2V0KS5yb3VuZCgpO1xyXG5cdFx0XHR0aGlzLl9wYW5BbmltLnJ1bih0aGlzLl9tYXBQYW5lLCBuZXdQb3MsIG9wdGlvbnMuZHVyYXRpb24gfHwgMC4yNSwgb3B0aW9ucy5lYXNlTGluZWFyaXR5KTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdHRoaXMuX3Jhd1BhbkJ5KG9mZnNldCk7XHJcblx0XHRcdHRoaXMuZmlyZSgnbW92ZScpLmZpcmUoJ21vdmVlbmQnKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGZseVRvKGxhdGxuZzogTGF0TG5nLCB6b29tPzogTnVtYmVyLCBvcHRpb25zPzogWm9vbS9wYW4gb3B0aW9ucyk6IHRoaXNcclxuXHQvLyBTZXRzIHRoZSB2aWV3IG9mIHRoZSBtYXAgKGdlb2dyYXBoaWNhbCBjZW50ZXIgYW5kIHpvb20pIHBlcmZvcm1pbmcgYSBzbW9vdGhcclxuXHQvLyBwYW4tem9vbSBhbmltYXRpb24uXHJcblx0Zmx5VG86IGZ1bmN0aW9uICh0YXJnZXRDZW50ZXIsIHRhcmdldFpvb20sIG9wdGlvbnMpIHtcclxuXHJcblx0XHRvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcclxuXHRcdGlmIChvcHRpb25zLmFuaW1hdGUgPT09IGZhbHNlIHx8ICFhbnkzZCkge1xyXG5cdFx0XHRyZXR1cm4gdGhpcy5zZXRWaWV3KHRhcmdldENlbnRlciwgdGFyZ2V0Wm9vbSwgb3B0aW9ucyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fc3RvcCgpO1xyXG5cclxuXHRcdHZhciBmcm9tID0gdGhpcy5wcm9qZWN0KHRoaXMuZ2V0Q2VudGVyKCkpLFxyXG5cdFx0ICAgIHRvID0gdGhpcy5wcm9qZWN0KHRhcmdldENlbnRlciksXHJcblx0XHQgICAgc2l6ZSA9IHRoaXMuZ2V0U2l6ZSgpLFxyXG5cdFx0ICAgIHN0YXJ0Wm9vbSA9IHRoaXMuX3pvb207XHJcblxyXG5cdFx0dGFyZ2V0Q2VudGVyID0gdG9MYXRMbmcodGFyZ2V0Q2VudGVyKTtcclxuXHRcdHRhcmdldFpvb20gPSB0YXJnZXRab29tID09PSB1bmRlZmluZWQgPyBzdGFydFpvb20gOiB0YXJnZXRab29tO1xyXG5cclxuXHRcdHZhciB3MCA9IE1hdGgubWF4KHNpemUueCwgc2l6ZS55KSxcclxuXHRcdCAgICB3MSA9IHcwICogdGhpcy5nZXRab29tU2NhbGUoc3RhcnRab29tLCB0YXJnZXRab29tKSxcclxuXHRcdCAgICB1MSA9ICh0by5kaXN0YW5jZVRvKGZyb20pKSB8fCAxLFxyXG5cdFx0ICAgIHJobyA9IDEuNDIsXHJcblx0XHQgICAgcmhvMiA9IHJobyAqIHJobztcclxuXHJcblx0XHRmdW5jdGlvbiByKGkpIHtcclxuXHRcdFx0dmFyIHMxID0gaSA/IC0xIDogMSxcclxuXHRcdFx0ICAgIHMyID0gaSA/IHcxIDogdzAsXHJcblx0XHRcdCAgICB0MSA9IHcxICogdzEgLSB3MCAqIHcwICsgczEgKiByaG8yICogcmhvMiAqIHUxICogdTEsXHJcblx0XHRcdCAgICBiMSA9IDIgKiBzMiAqIHJobzIgKiB1MSxcclxuXHRcdFx0ICAgIGIgPSB0MSAvIGIxLFxyXG5cdFx0XHQgICAgc3EgPSBNYXRoLnNxcnQoYiAqIGIgKyAxKSAtIGI7XHJcblxyXG5cdFx0XHQgICAgLy8gd29ya2Fyb3VuZCBmb3IgZmxvYXRpbmcgcG9pbnQgcHJlY2lzaW9uIGJ1ZyB3aGVuIHNxID0gMCwgbG9nID0gLUluZmluaXRlLFxyXG5cdFx0XHQgICAgLy8gdGh1cyB0cmlnZ2VyaW5nIGFuIGluZmluaXRlIGxvb3AgaW4gZmx5VG9cclxuXHRcdFx0ICAgIHZhciBsb2cgPSBzcSA8IDAuMDAwMDAwMDAxID8gLTE4IDogTWF0aC5sb2coc3EpO1xyXG5cclxuXHRcdFx0cmV0dXJuIGxvZztcclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBzaW5oKG4pIHsgcmV0dXJuIChNYXRoLmV4cChuKSAtIE1hdGguZXhwKC1uKSkgLyAyOyB9XHJcblx0XHRmdW5jdGlvbiBjb3NoKG4pIHsgcmV0dXJuIChNYXRoLmV4cChuKSArIE1hdGguZXhwKC1uKSkgLyAyOyB9XHJcblx0XHRmdW5jdGlvbiB0YW5oKG4pIHsgcmV0dXJuIHNpbmgobikgLyBjb3NoKG4pOyB9XHJcblxyXG5cdFx0dmFyIHIwID0gcigwKTtcclxuXHJcblx0XHRmdW5jdGlvbiB3KHMpIHsgcmV0dXJuIHcwICogKGNvc2gocjApIC8gY29zaChyMCArIHJobyAqIHMpKTsgfVxyXG5cdFx0ZnVuY3Rpb24gdShzKSB7IHJldHVybiB3MCAqIChjb3NoKHIwKSAqIHRhbmgocjAgKyByaG8gKiBzKSAtIHNpbmgocjApKSAvIHJobzI7IH1cclxuXHJcblx0XHRmdW5jdGlvbiBlYXNlT3V0KHQpIHsgcmV0dXJuIDEgLSBNYXRoLnBvdygxIC0gdCwgMS41KTsgfVxyXG5cclxuXHRcdHZhciBzdGFydCA9IERhdGUubm93KCksXHJcblx0XHQgICAgUyA9IChyKDEpIC0gcjApIC8gcmhvLFxyXG5cdFx0ICAgIGR1cmF0aW9uID0gb3B0aW9ucy5kdXJhdGlvbiA/IDEwMDAgKiBvcHRpb25zLmR1cmF0aW9uIDogMTAwMCAqIFMgKiAwLjg7XHJcblxyXG5cdFx0ZnVuY3Rpb24gZnJhbWUoKSB7XHJcblx0XHRcdHZhciB0ID0gKERhdGUubm93KCkgLSBzdGFydCkgLyBkdXJhdGlvbixcclxuXHRcdFx0ICAgIHMgPSBlYXNlT3V0KHQpICogUztcclxuXHJcblx0XHRcdGlmICh0IDw9IDEpIHtcclxuXHRcdFx0XHR0aGlzLl9mbHlUb0ZyYW1lID0gcmVxdWVzdEFuaW1GcmFtZShmcmFtZSwgdGhpcyk7XHJcblxyXG5cdFx0XHRcdHRoaXMuX21vdmUoXHJcblx0XHRcdFx0XHR0aGlzLnVucHJvamVjdChmcm9tLmFkZCh0by5zdWJ0cmFjdChmcm9tKS5tdWx0aXBseUJ5KHUocykgLyB1MSkpLCBzdGFydFpvb20pLFxyXG5cdFx0XHRcdFx0dGhpcy5nZXRTY2FsZVpvb20odzAgLyB3KHMpLCBzdGFydFpvb20pLFxyXG5cdFx0XHRcdFx0e2ZseVRvOiB0cnVlfSk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdHRoaXNcclxuXHRcdFx0XHRcdC5fbW92ZSh0YXJnZXRDZW50ZXIsIHRhcmdldFpvb20pXHJcblx0XHRcdFx0XHQuX21vdmVFbmQodHJ1ZSk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9tb3ZlU3RhcnQodHJ1ZSwgb3B0aW9ucy5ub01vdmVTdGFydCk7XHJcblxyXG5cdFx0ZnJhbWUuY2FsbCh0aGlzKTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZmx5VG9Cb3VuZHMoYm91bmRzOiBMYXRMbmdCb3VuZHMsIG9wdGlvbnM/OiBmaXRCb3VuZHMgb3B0aW9ucyk6IHRoaXNcclxuXHQvLyBTZXRzIHRoZSB2aWV3IG9mIHRoZSBtYXAgd2l0aCBhIHNtb290aCBhbmltYXRpb24gbGlrZSBbYGZseVRvYF0oI21hcC1mbHl0byksXHJcblx0Ly8gYnV0IHRha2VzIGEgYm91bmRzIHBhcmFtZXRlciBsaWtlIFtgZml0Qm91bmRzYF0oI21hcC1maXRib3VuZHMpLlxyXG5cdGZseVRvQm91bmRzOiBmdW5jdGlvbiAoYm91bmRzLCBvcHRpb25zKSB7XHJcblx0XHR2YXIgdGFyZ2V0ID0gdGhpcy5fZ2V0Qm91bmRzQ2VudGVyWm9vbShib3VuZHMsIG9wdGlvbnMpO1xyXG5cdFx0cmV0dXJuIHRoaXMuZmx5VG8odGFyZ2V0LmNlbnRlciwgdGFyZ2V0Lnpvb20sIG9wdGlvbnMpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0TWF4Qm91bmRzKGJvdW5kczogQm91bmRzKTogdGhpc1xyXG5cdC8vIFJlc3RyaWN0cyB0aGUgbWFwIHZpZXcgdG8gdGhlIGdpdmVuIGJvdW5kcyAoc2VlIHRoZSBbbWF4Qm91bmRzXSgjbWFwLW1heGJvdW5kcykgb3B0aW9uKS5cclxuXHRzZXRNYXhCb3VuZHM6IGZ1bmN0aW9uIChib3VuZHMpIHtcclxuXHRcdGJvdW5kcyA9IHRvTGF0TG5nQm91bmRzKGJvdW5kcyk7XHJcblxyXG5cdFx0aWYgKCFib3VuZHMuaXNWYWxpZCgpKSB7XHJcblx0XHRcdHRoaXMub3B0aW9ucy5tYXhCb3VuZHMgPSBudWxsO1xyXG5cdFx0XHRyZXR1cm4gdGhpcy5vZmYoJ21vdmVlbmQnLCB0aGlzLl9wYW5JbnNpZGVNYXhCb3VuZHMpO1xyXG5cdFx0fSBlbHNlIGlmICh0aGlzLm9wdGlvbnMubWF4Qm91bmRzKSB7XHJcblx0XHRcdHRoaXMub2ZmKCdtb3ZlZW5kJywgdGhpcy5fcGFuSW5zaWRlTWF4Qm91bmRzKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLm9wdGlvbnMubWF4Qm91bmRzID0gYm91bmRzO1xyXG5cclxuXHRcdGlmICh0aGlzLl9sb2FkZWQpIHtcclxuXHRcdFx0dGhpcy5fcGFuSW5zaWRlTWF4Qm91bmRzKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMub24oJ21vdmVlbmQnLCB0aGlzLl9wYW5JbnNpZGVNYXhCb3VuZHMpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0TWluWm9vbSh6b29tOiBOdW1iZXIpOiB0aGlzXHJcblx0Ly8gU2V0cyB0aGUgbG93ZXIgbGltaXQgZm9yIHRoZSBhdmFpbGFibGUgem9vbSBsZXZlbHMgKHNlZSB0aGUgW21pblpvb21dKCNtYXAtbWluem9vbSkgb3B0aW9uKS5cclxuXHRzZXRNaW5ab29tOiBmdW5jdGlvbiAoem9vbSkge1xyXG5cdFx0dmFyIG9sZFpvb20gPSB0aGlzLm9wdGlvbnMubWluWm9vbTtcclxuXHRcdHRoaXMub3B0aW9ucy5taW5ab29tID0gem9vbTtcclxuXHJcblx0XHRpZiAodGhpcy5fbG9hZGVkICYmIG9sZFpvb20gIT09IHpvb20pIHtcclxuXHRcdFx0dGhpcy5maXJlKCd6b29tbGV2ZWxzY2hhbmdlJyk7XHJcblxyXG5cdFx0XHRpZiAodGhpcy5nZXRab29tKCkgPCB0aGlzLm9wdGlvbnMubWluWm9vbSkge1xyXG5cdFx0XHRcdHJldHVybiB0aGlzLnNldFpvb20oem9vbSk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldE1heFpvb20oem9vbTogTnVtYmVyKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIHVwcGVyIGxpbWl0IGZvciB0aGUgYXZhaWxhYmxlIHpvb20gbGV2ZWxzIChzZWUgdGhlIFttYXhab29tXSgjbWFwLW1heHpvb20pIG9wdGlvbikuXHJcblx0c2V0TWF4Wm9vbTogZnVuY3Rpb24gKHpvb20pIHtcclxuXHRcdHZhciBvbGRab29tID0gdGhpcy5vcHRpb25zLm1heFpvb207XHJcblx0XHR0aGlzLm9wdGlvbnMubWF4Wm9vbSA9IHpvb207XHJcblxyXG5cdFx0aWYgKHRoaXMuX2xvYWRlZCAmJiBvbGRab29tICE9PSB6b29tKSB7XHJcblx0XHRcdHRoaXMuZmlyZSgnem9vbWxldmVsc2NoYW5nZScpO1xyXG5cclxuXHRcdFx0aWYgKHRoaXMuZ2V0Wm9vbSgpID4gdGhpcy5vcHRpb25zLm1heFpvb20pIHtcclxuXHRcdFx0XHRyZXR1cm4gdGhpcy5zZXRab29tKHpvb20pO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBwYW5JbnNpZGVCb3VuZHMoYm91bmRzOiBMYXRMbmdCb3VuZHMsIG9wdGlvbnM/OiBQYW4gb3B0aW9ucyk6IHRoaXNcclxuXHQvLyBQYW5zIHRoZSBtYXAgdG8gdGhlIGNsb3Nlc3QgdmlldyB0aGF0IHdvdWxkIGxpZSBpbnNpZGUgdGhlIGdpdmVuIGJvdW5kcyAoaWYgaXQncyBub3QgYWxyZWFkeSksIGNvbnRyb2xsaW5nIHRoZSBhbmltYXRpb24gdXNpbmcgdGhlIG9wdGlvbnMgc3BlY2lmaWMsIGlmIGFueS5cclxuXHRwYW5JbnNpZGVCb3VuZHM6IGZ1bmN0aW9uIChib3VuZHMsIG9wdGlvbnMpIHtcclxuXHRcdHRoaXMuX2VuZm9yY2luZ0JvdW5kcyA9IHRydWU7XHJcblx0XHR2YXIgY2VudGVyID0gdGhpcy5nZXRDZW50ZXIoKSxcclxuXHRcdCAgICBuZXdDZW50ZXIgPSB0aGlzLl9saW1pdENlbnRlcihjZW50ZXIsIHRoaXMuX3pvb20sIHRvTGF0TG5nQm91bmRzKGJvdW5kcykpO1xyXG5cclxuXHRcdGlmICghY2VudGVyLmVxdWFscyhuZXdDZW50ZXIpKSB7XHJcblx0XHRcdHRoaXMucGFuVG8obmV3Q2VudGVyLCBvcHRpb25zKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9lbmZvcmNpbmdCb3VuZHMgPSBmYWxzZTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgaW52YWxpZGF0ZVNpemUob3B0aW9uczogWm9vbS9wYW4gb3B0aW9ucyk6IHRoaXNcclxuXHQvLyBDaGVja3MgaWYgdGhlIG1hcCBjb250YWluZXIgc2l6ZSBjaGFuZ2VkIGFuZCB1cGRhdGVzIHRoZSBtYXAgaWYgc28g4oCUXHJcblx0Ly8gY2FsbCBpdCBhZnRlciB5b3UndmUgY2hhbmdlZCB0aGUgbWFwIHNpemUgZHluYW1pY2FsbHksIGFsc28gYW5pbWF0aW5nXHJcblx0Ly8gcGFuIGJ5IGRlZmF1bHQuIElmIGBvcHRpb25zLnBhbmAgaXMgYGZhbHNlYCwgcGFubmluZyB3aWxsIG5vdCBvY2N1ci5cclxuXHQvLyBJZiBgb3B0aW9ucy5kZWJvdW5jZU1vdmVlbmRgIGlzIGB0cnVlYCwgaXQgd2lsbCBkZWxheSBgbW92ZWVuZGAgZXZlbnQgc29cclxuXHQvLyB0aGF0IGl0IGRvZXNuJ3QgaGFwcGVuIG9mdGVuIGV2ZW4gaWYgdGhlIG1ldGhvZCBpcyBjYWxsZWQgbWFueVxyXG5cdC8vIHRpbWVzIGluIGEgcm93LlxyXG5cclxuXHQvLyBAYWx0ZXJuYXRpdmVcclxuXHQvLyBAbWV0aG9kIGludmFsaWRhdGVTaXplKGFuaW1hdGU6IEJvb2xlYW4pOiB0aGlzXHJcblx0Ly8gQ2hlY2tzIGlmIHRoZSBtYXAgY29udGFpbmVyIHNpemUgY2hhbmdlZCBhbmQgdXBkYXRlcyB0aGUgbWFwIGlmIHNvIOKAlFxyXG5cdC8vIGNhbGwgaXQgYWZ0ZXIgeW91J3ZlIGNoYW5nZWQgdGhlIG1hcCBzaXplIGR5bmFtaWNhbGx5LCBhbHNvIGFuaW1hdGluZ1xyXG5cdC8vIHBhbiBieSBkZWZhdWx0LlxyXG5cdGludmFsaWRhdGVTaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xyXG5cdFx0aWYgKCF0aGlzLl9sb2FkZWQpIHsgcmV0dXJuIHRoaXM7IH1cclxuXHJcblx0XHRvcHRpb25zID0gZXh0ZW5kKHtcclxuXHRcdFx0YW5pbWF0ZTogZmFsc2UsXHJcblx0XHRcdHBhbjogdHJ1ZVxyXG5cdFx0fSwgb3B0aW9ucyA9PT0gdHJ1ZSA/IHthbmltYXRlOiB0cnVlfSA6IG9wdGlvbnMpO1xyXG5cclxuXHRcdHZhciBvbGRTaXplID0gdGhpcy5nZXRTaXplKCk7XHJcblx0XHR0aGlzLl9zaXplQ2hhbmdlZCA9IHRydWU7XHJcblx0XHR0aGlzLl9sYXN0Q2VudGVyID0gbnVsbDtcclxuXHJcblx0XHR2YXIgbmV3U2l6ZSA9IHRoaXMuZ2V0U2l6ZSgpLFxyXG5cdFx0ICAgIG9sZENlbnRlciA9IG9sZFNpemUuZGl2aWRlQnkoMikucm91bmQoKSxcclxuXHRcdCAgICBuZXdDZW50ZXIgPSBuZXdTaXplLmRpdmlkZUJ5KDIpLnJvdW5kKCksXHJcblx0XHQgICAgb2Zmc2V0ID0gb2xkQ2VudGVyLnN1YnRyYWN0KG5ld0NlbnRlcik7XHJcblxyXG5cdFx0aWYgKCFvZmZzZXQueCAmJiAhb2Zmc2V0LnkpIHsgcmV0dXJuIHRoaXM7IH1cclxuXHJcblx0XHRpZiAob3B0aW9ucy5hbmltYXRlICYmIG9wdGlvbnMucGFuKSB7XHJcblx0XHRcdHRoaXMucGFuQnkob2Zmc2V0KTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRpZiAob3B0aW9ucy5wYW4pIHtcclxuXHRcdFx0XHR0aGlzLl9yYXdQYW5CeShvZmZzZXQpO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLmZpcmUoJ21vdmUnKTtcclxuXHJcblx0XHRcdGlmIChvcHRpb25zLmRlYm91bmNlTW92ZWVuZCkge1xyXG5cdFx0XHRcdGNsZWFyVGltZW91dCh0aGlzLl9zaXplVGltZXIpO1xyXG5cdFx0XHRcdHRoaXMuX3NpemVUaW1lciA9IHNldFRpbWVvdXQoYmluZCh0aGlzLmZpcmUsIHRoaXMsICdtb3ZlZW5kJyksIDIwMCk7XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0dGhpcy5maXJlKCdtb3ZlZW5kJyk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHQvLyBAc2VjdGlvbiBNYXAgc3RhdGUgY2hhbmdlIGV2ZW50c1xyXG5cdFx0Ly8gQGV2ZW50IHJlc2l6ZTogUmVzaXplRXZlbnRcclxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIG1hcCBpcyByZXNpemVkLlxyXG5cdFx0cmV0dXJuIHRoaXMuZmlyZSgncmVzaXplJywge1xyXG5cdFx0XHRvbGRTaXplOiBvbGRTaXplLFxyXG5cdFx0XHRuZXdTaXplOiBuZXdTaXplXHJcblx0XHR9KTtcclxuXHR9LFxyXG5cclxuXHQvLyBAc2VjdGlvbiBNZXRob2RzIGZvciBtb2RpZnlpbmcgbWFwIHN0YXRlXHJcblx0Ly8gQG1ldGhvZCBzdG9wKCk6IHRoaXNcclxuXHQvLyBTdG9wcyB0aGUgY3VycmVudGx5IHJ1bm5pbmcgYHBhblRvYCBvciBgZmx5VG9gIGFuaW1hdGlvbiwgaWYgYW55LlxyXG5cdHN0b3A6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHRoaXMuc2V0Wm9vbSh0aGlzLl9saW1pdFpvb20odGhpcy5fem9vbSkpO1xyXG5cdFx0aWYgKCF0aGlzLm9wdGlvbnMuem9vbVNuYXApIHtcclxuXHRcdFx0dGhpcy5maXJlKCd2aWV3cmVzZXQnKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzLl9zdG9wKCk7XHJcblx0fSxcclxuXHJcblx0Ly8gQHNlY3Rpb24gR2VvbG9jYXRpb24gbWV0aG9kc1xyXG5cdC8vIEBtZXRob2QgbG9jYXRlKG9wdGlvbnM/OiBMb2NhdGUgb3B0aW9ucyk6IHRoaXNcclxuXHQvLyBUcmllcyB0byBsb2NhdGUgdGhlIHVzZXIgdXNpbmcgdGhlIEdlb2xvY2F0aW9uIEFQSSwgZmlyaW5nIGEgW2Bsb2NhdGlvbmZvdW5kYF0oI21hcC1sb2NhdGlvbmZvdW5kKVxyXG5cdC8vIGV2ZW50IHdpdGggbG9jYXRpb24gZGF0YSBvbiBzdWNjZXNzIG9yIGEgW2Bsb2NhdGlvbmVycm9yYF0oI21hcC1sb2NhdGlvbmVycm9yKSBldmVudCBvbiBmYWlsdXJlLFxyXG5cdC8vIGFuZCBvcHRpb25hbGx5IHNldHMgdGhlIG1hcCB2aWV3IHRvIHRoZSB1c2VyJ3MgbG9jYXRpb24gd2l0aCByZXNwZWN0IHRvXHJcblx0Ly8gZGV0ZWN0aW9uIGFjY3VyYWN5IChvciB0byB0aGUgd29ybGQgdmlldyBpZiBnZW9sb2NhdGlvbiBmYWlsZWQpLlxyXG5cdC8vIE5vdGUgdGhhdCwgaWYgeW91ciBwYWdlIGRvZXNuJ3QgdXNlIEhUVFBTLCB0aGlzIG1ldGhvZCB3aWxsIGZhaWwgaW5cclxuXHQvLyBtb2Rlcm4gYnJvd3NlcnMgKFtDaHJvbWUgNTAgYW5kIG5ld2VyXShodHRwczovL3NpdGVzLmdvb2dsZS5jb20vYS9jaHJvbWl1bS5vcmcvZGV2L0hvbWUvY2hyb21pdW0tc2VjdXJpdHkvZGVwcmVjYXRpbmctcG93ZXJmdWwtZmVhdHVyZXMtb24taW5zZWN1cmUtb3JpZ2lucykpXHJcblx0Ly8gU2VlIGBMb2NhdGUgb3B0aW9uc2AgZm9yIG1vcmUgZGV0YWlscy5cclxuXHRsb2NhdGU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XHJcblxyXG5cdFx0b3B0aW9ucyA9IHRoaXMuX2xvY2F0ZU9wdGlvbnMgPSBleHRlbmQoe1xyXG5cdFx0XHR0aW1lb3V0OiAxMDAwMCxcclxuXHRcdFx0d2F0Y2g6IGZhbHNlXHJcblx0XHRcdC8vIHNldFZpZXc6IGZhbHNlXHJcblx0XHRcdC8vIG1heFpvb206IDxOdW1iZXI+XHJcblx0XHRcdC8vIG1heGltdW1BZ2U6IDBcclxuXHRcdFx0Ly8gZW5hYmxlSGlnaEFjY3VyYWN5OiBmYWxzZVxyXG5cdFx0fSwgb3B0aW9ucyk7XHJcblxyXG5cdFx0aWYgKCEoJ2dlb2xvY2F0aW9uJyBpbiBuYXZpZ2F0b3IpKSB7XHJcblx0XHRcdHRoaXMuX2hhbmRsZUdlb2xvY2F0aW9uRXJyb3Ioe1xyXG5cdFx0XHRcdGNvZGU6IDAsXHJcblx0XHRcdFx0bWVzc2FnZTogJ0dlb2xvY2F0aW9uIG5vdCBzdXBwb3J0ZWQuJ1xyXG5cdFx0XHR9KTtcclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblx0XHR9XHJcblxyXG5cdFx0dmFyIG9uUmVzcG9uc2UgPSBiaW5kKHRoaXMuX2hhbmRsZUdlb2xvY2F0aW9uUmVzcG9uc2UsIHRoaXMpLFxyXG5cdFx0ICAgIG9uRXJyb3IgPSBiaW5kKHRoaXMuX2hhbmRsZUdlb2xvY2F0aW9uRXJyb3IsIHRoaXMpO1xyXG5cclxuXHRcdGlmIChvcHRpb25zLndhdGNoKSB7XHJcblx0XHRcdHRoaXMuX2xvY2F0aW9uV2F0Y2hJZCA9XHJcblx0XHRcdCAgICAgICAgbmF2aWdhdG9yLmdlb2xvY2F0aW9uLndhdGNoUG9zaXRpb24ob25SZXNwb25zZSwgb25FcnJvciwgb3B0aW9ucyk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRuYXZpZ2F0b3IuZ2VvbG9jYXRpb24uZ2V0Q3VycmVudFBvc2l0aW9uKG9uUmVzcG9uc2UsIG9uRXJyb3IsIG9wdGlvbnMpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBzdG9wTG9jYXRlKCk6IHRoaXNcclxuXHQvLyBTdG9wcyB3YXRjaGluZyBsb2NhdGlvbiBwcmV2aW91c2x5IGluaXRpYXRlZCBieSBgbWFwLmxvY2F0ZSh7d2F0Y2g6IHRydWV9KWBcclxuXHQvLyBhbmQgYWJvcnRzIHJlc2V0dGluZyB0aGUgbWFwIHZpZXcgaWYgbWFwLmxvY2F0ZSB3YXMgY2FsbGVkIHdpdGhcclxuXHQvLyBge3NldFZpZXc6IHRydWV9YC5cclxuXHRzdG9wTG9jYXRlOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAobmF2aWdhdG9yLmdlb2xvY2F0aW9uICYmIG5hdmlnYXRvci5nZW9sb2NhdGlvbi5jbGVhcldhdGNoKSB7XHJcblx0XHRcdG5hdmlnYXRvci5nZW9sb2NhdGlvbi5jbGVhcldhdGNoKHRoaXMuX2xvY2F0aW9uV2F0Y2hJZCk7XHJcblx0XHR9XHJcblx0XHRpZiAodGhpcy5fbG9jYXRlT3B0aW9ucykge1xyXG5cdFx0XHR0aGlzLl9sb2NhdGVPcHRpb25zLnNldFZpZXcgPSBmYWxzZTtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdF9oYW5kbGVHZW9sb2NhdGlvbkVycm9yOiBmdW5jdGlvbiAoZXJyb3IpIHtcclxuXHRcdHZhciBjID0gZXJyb3IuY29kZSxcclxuXHRcdCAgICBtZXNzYWdlID0gZXJyb3IubWVzc2FnZSB8fFxyXG5cdFx0ICAgICAgICAgICAgKGMgPT09IDEgPyAncGVybWlzc2lvbiBkZW5pZWQnIDpcclxuXHRcdCAgICAgICAgICAgIChjID09PSAyID8gJ3Bvc2l0aW9uIHVuYXZhaWxhYmxlJyA6ICd0aW1lb3V0JykpO1xyXG5cclxuXHRcdGlmICh0aGlzLl9sb2NhdGVPcHRpb25zLnNldFZpZXcgJiYgIXRoaXMuX2xvYWRlZCkge1xyXG5cdFx0XHR0aGlzLmZpdFdvcmxkKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQHNlY3Rpb24gTG9jYXRpb24gZXZlbnRzXHJcblx0XHQvLyBAZXZlbnQgbG9jYXRpb25lcnJvcjogRXJyb3JFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiBnZW9sb2NhdGlvbiAodXNpbmcgdGhlIFtgbG9jYXRlYF0oI21hcC1sb2NhdGUpIG1ldGhvZCkgZmFpbGVkLlxyXG5cdFx0dGhpcy5maXJlKCdsb2NhdGlvbmVycm9yJywge1xyXG5cdFx0XHRjb2RlOiBjLFxyXG5cdFx0XHRtZXNzYWdlOiAnR2VvbG9jYXRpb24gZXJyb3I6ICcgKyBtZXNzYWdlICsgJy4nXHJcblx0XHR9KTtcclxuXHR9LFxyXG5cclxuXHRfaGFuZGxlR2VvbG9jYXRpb25SZXNwb25zZTogZnVuY3Rpb24gKHBvcykge1xyXG5cdFx0dmFyIGxhdCA9IHBvcy5jb29yZHMubGF0aXR1ZGUsXHJcblx0XHQgICAgbG5nID0gcG9zLmNvb3Jkcy5sb25naXR1ZGUsXHJcblx0XHQgICAgbGF0bG5nID0gbmV3IExhdExuZyhsYXQsIGxuZyksXHJcblx0XHQgICAgYm91bmRzID0gbGF0bG5nLnRvQm91bmRzKHBvcy5jb29yZHMuYWNjdXJhY3kpLFxyXG5cdFx0ICAgIG9wdGlvbnMgPSB0aGlzLl9sb2NhdGVPcHRpb25zO1xyXG5cclxuXHRcdGlmIChvcHRpb25zLnNldFZpZXcpIHtcclxuXHRcdFx0dmFyIHpvb20gPSB0aGlzLmdldEJvdW5kc1pvb20oYm91bmRzKTtcclxuXHRcdFx0dGhpcy5zZXRWaWV3KGxhdGxuZywgb3B0aW9ucy5tYXhab29tID8gTWF0aC5taW4oem9vbSwgb3B0aW9ucy5tYXhab29tKSA6IHpvb20pO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBkYXRhID0ge1xyXG5cdFx0XHRsYXRsbmc6IGxhdGxuZyxcclxuXHRcdFx0Ym91bmRzOiBib3VuZHMsXHJcblx0XHRcdHRpbWVzdGFtcDogcG9zLnRpbWVzdGFtcFxyXG5cdFx0fTtcclxuXHJcblx0XHRmb3IgKHZhciBpIGluIHBvcy5jb29yZHMpIHtcclxuXHRcdFx0aWYgKHR5cGVvZiBwb3MuY29vcmRzW2ldID09PSAnbnVtYmVyJykge1xyXG5cdFx0XHRcdGRhdGFbaV0gPSBwb3MuY29vcmRzW2ldO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQGV2ZW50IGxvY2F0aW9uZm91bmQ6IExvY2F0aW9uRXZlbnRcclxuXHRcdC8vIEZpcmVkIHdoZW4gZ2VvbG9jYXRpb24gKHVzaW5nIHRoZSBbYGxvY2F0ZWBdKCNtYXAtbG9jYXRlKSBtZXRob2QpXHJcblx0XHQvLyB3ZW50IHN1Y2Nlc3NmdWxseS5cclxuXHRcdHRoaXMuZmlyZSgnbG9jYXRpb25mb3VuZCcsIGRhdGEpO1xyXG5cdH0sXHJcblxyXG5cdC8vIFRPRE8gQXBwcm9wcmlhdGUgZG9jcyBzZWN0aW9uP1xyXG5cdC8vIEBzZWN0aW9uIE90aGVyIE1ldGhvZHNcclxuXHQvLyBAbWV0aG9kIGFkZEhhbmRsZXIobmFtZTogU3RyaW5nLCBIYW5kbGVyQ2xhc3M6IEZ1bmN0aW9uKTogdGhpc1xyXG5cdC8vIEFkZHMgYSBuZXcgYEhhbmRsZXJgIHRvIHRoZSBtYXAsIGdpdmVuIGl0cyBuYW1lIGFuZCBjb25zdHJ1Y3RvciBmdW5jdGlvbi5cclxuXHRhZGRIYW5kbGVyOiBmdW5jdGlvbiAobmFtZSwgSGFuZGxlckNsYXNzKSB7XHJcblx0XHRpZiAoIUhhbmRsZXJDbGFzcykgeyByZXR1cm4gdGhpczsgfVxyXG5cclxuXHRcdHZhciBoYW5kbGVyID0gdGhpc1tuYW1lXSA9IG5ldyBIYW5kbGVyQ2xhc3ModGhpcyk7XHJcblxyXG5cdFx0dGhpcy5faGFuZGxlcnMucHVzaChoYW5kbGVyKTtcclxuXHJcblx0XHRpZiAodGhpcy5vcHRpb25zW25hbWVdKSB7XHJcblx0XHRcdGhhbmRsZXIuZW5hYmxlKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCByZW1vdmUoKTogdGhpc1xyXG5cdC8vIERlc3Ryb3lzIHRoZSBtYXAgYW5kIGNsZWFycyBhbGwgcmVsYXRlZCBldmVudCBsaXN0ZW5lcnMuXHJcblx0cmVtb3ZlOiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0dGhpcy5faW5pdEV2ZW50cyh0cnVlKTtcclxuXHJcblx0XHRpZiAodGhpcy5fY29udGFpbmVySWQgIT09IHRoaXMuX2NvbnRhaW5lci5fbGVhZmxldF9pZCkge1xyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ01hcCBjb250YWluZXIgaXMgYmVpbmcgcmV1c2VkIGJ5IGFub3RoZXIgaW5zdGFuY2UnKTtcclxuXHRcdH1cclxuXHJcblx0XHR0cnkge1xyXG5cdFx0XHQvLyB0aHJvd3MgZXJyb3IgaW4gSUU2LThcclxuXHRcdFx0ZGVsZXRlIHRoaXMuX2NvbnRhaW5lci5fbGVhZmxldF9pZDtcclxuXHRcdFx0ZGVsZXRlIHRoaXMuX2NvbnRhaW5lcklkO1xyXG5cdFx0fSBjYXRjaCAoZSkge1xyXG5cdFx0XHQvKmVzbGludC1kaXNhYmxlICovXHJcblx0XHRcdHRoaXMuX2NvbnRhaW5lci5fbGVhZmxldF9pZCA9IHVuZGVmaW5lZDtcclxuXHRcdFx0LyogZXNsaW50LWVuYWJsZSAqL1xyXG5cdFx0XHR0aGlzLl9jb250YWluZXJJZCA9IHVuZGVmaW5lZDtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAodGhpcy5fbG9jYXRpb25XYXRjaElkICE9PSB1bmRlZmluZWQpIHtcclxuXHRcdFx0dGhpcy5zdG9wTG9jYXRlKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fc3RvcCgpO1xyXG5cclxuXHRcdHJlbW92ZSh0aGlzLl9tYXBQYW5lKTtcclxuXHJcblx0XHRpZiAodGhpcy5fY2xlYXJDb250cm9sUG9zKSB7XHJcblx0XHRcdHRoaXMuX2NsZWFyQ29udHJvbFBvcygpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2NsZWFySGFuZGxlcnMoKTtcclxuXHJcblx0XHRpZiAodGhpcy5fbG9hZGVkKSB7XHJcblx0XHRcdC8vIEBzZWN0aW9uIE1hcCBzdGF0ZSBjaGFuZ2UgZXZlbnRzXHJcblx0XHRcdC8vIEBldmVudCB1bmxvYWQ6IEV2ZW50XHJcblx0XHRcdC8vIEZpcmVkIHdoZW4gdGhlIG1hcCBpcyBkZXN0cm95ZWQgd2l0aCBbcmVtb3ZlXSgjbWFwLXJlbW92ZSkgbWV0aG9kLlxyXG5cdFx0XHR0aGlzLmZpcmUoJ3VubG9hZCcpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBpO1xyXG5cdFx0Zm9yIChpIGluIHRoaXMuX2xheWVycykge1xyXG5cdFx0XHR0aGlzLl9sYXllcnNbaV0ucmVtb3ZlKCk7XHJcblx0XHR9XHJcblx0XHRmb3IgKGkgaW4gdGhpcy5fcGFuZXMpIHtcclxuXHRcdFx0cmVtb3ZlKHRoaXMuX3BhbmVzW2ldKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9sYXllcnMgPSBbXTtcclxuXHRcdHRoaXMuX3BhbmVzID0gW107XHJcblx0XHRkZWxldGUgdGhpcy5fbWFwUGFuZTtcclxuXHRcdGRlbGV0ZSB0aGlzLl9yZW5kZXJlcjtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAc2VjdGlvbiBPdGhlciBNZXRob2RzXHJcblx0Ly8gQG1ldGhvZCBjcmVhdGVQYW5lKG5hbWU6IFN0cmluZywgY29udGFpbmVyPzogSFRNTEVsZW1lbnQpOiBIVE1MRWxlbWVudFxyXG5cdC8vIENyZWF0ZXMgYSBuZXcgW21hcCBwYW5lXSgjbWFwLXBhbmUpIHdpdGggdGhlIGdpdmVuIG5hbWUgaWYgaXQgZG9lc24ndCBleGlzdCBhbHJlYWR5LFxyXG5cdC8vIHRoZW4gcmV0dXJucyBpdC4gVGhlIHBhbmUgaXMgY3JlYXRlZCBhcyBhIGNoaWxkIG9mIGBjb250YWluZXJgLCBvclxyXG5cdC8vIGFzIGEgY2hpbGQgb2YgdGhlIG1haW4gbWFwIHBhbmUgaWYgbm90IHNldC5cclxuXHRjcmVhdGVQYW5lOiBmdW5jdGlvbiAobmFtZSwgY29udGFpbmVyKSB7XHJcblx0XHR2YXIgY2xhc3NOYW1lID0gJ2xlYWZsZXQtcGFuZScgKyAobmFtZSA/ICcgbGVhZmxldC0nICsgbmFtZS5yZXBsYWNlKCdQYW5lJywgJycpICsgJy1wYW5lJyA6ICcnKSxcclxuXHRcdCAgICBwYW5lID0gY3JlYXRlJDEoJ2RpdicsIGNsYXNzTmFtZSwgY29udGFpbmVyIHx8IHRoaXMuX21hcFBhbmUpO1xyXG5cclxuXHRcdGlmIChuYW1lKSB7XHJcblx0XHRcdHRoaXMuX3BhbmVzW25hbWVdID0gcGFuZTtcclxuXHRcdH1cclxuXHRcdHJldHVybiBwYW5lO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBzZWN0aW9uIE1ldGhvZHMgZm9yIEdldHRpbmcgTWFwIFN0YXRlXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0Q2VudGVyKCk6IExhdExuZ1xyXG5cdC8vIFJldHVybnMgdGhlIGdlb2dyYXBoaWNhbCBjZW50ZXIgb2YgdGhlIG1hcCB2aWV3XHJcblx0Z2V0Q2VudGVyOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR0aGlzLl9jaGVja0lmTG9hZGVkKCk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX2xhc3RDZW50ZXIgJiYgIXRoaXMuX21vdmVkKCkpIHtcclxuXHRcdFx0cmV0dXJuIHRoaXMuX2xhc3RDZW50ZXI7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcy5sYXllclBvaW50VG9MYXRMbmcodGhpcy5fZ2V0Q2VudGVyTGF5ZXJQb2ludCgpKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldFpvb20oKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgY3VycmVudCB6b29tIGxldmVsIG9mIHRoZSBtYXAgdmlld1xyXG5cdGdldFpvb206IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl96b29tO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0Qm91bmRzKCk6IExhdExuZ0JvdW5kc1xyXG5cdC8vIFJldHVybnMgdGhlIGdlb2dyYXBoaWNhbCBib3VuZHMgdmlzaWJsZSBpbiB0aGUgY3VycmVudCBtYXAgdmlld1xyXG5cdGdldEJvdW5kczogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGJvdW5kcyA9IHRoaXMuZ2V0UGl4ZWxCb3VuZHMoKSxcclxuXHRcdCAgICBzdyA9IHRoaXMudW5wcm9qZWN0KGJvdW5kcy5nZXRCb3R0b21MZWZ0KCkpLFxyXG5cdFx0ICAgIG5lID0gdGhpcy51bnByb2plY3QoYm91bmRzLmdldFRvcFJpZ2h0KCkpO1xyXG5cclxuXHRcdHJldHVybiBuZXcgTGF0TG5nQm91bmRzKHN3LCBuZSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRNaW5ab29tKCk6IE51bWJlclxyXG5cdC8vIFJldHVybnMgdGhlIG1pbmltdW0gem9vbSBsZXZlbCBvZiB0aGUgbWFwIChpZiBzZXQgaW4gdGhlIGBtaW5ab29tYCBvcHRpb24gb2YgdGhlIG1hcCBvciBvZiBhbnkgbGF5ZXJzKSwgb3IgYDBgIGJ5IGRlZmF1bHQuXHJcblx0Z2V0TWluWm9vbTogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMub3B0aW9ucy5taW5ab29tID09PSB1bmRlZmluZWQgPyB0aGlzLl9sYXllcnNNaW5ab29tIHx8IDAgOiB0aGlzLm9wdGlvbnMubWluWm9vbTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldE1heFpvb20oKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgbWF4aW11bSB6b29tIGxldmVsIG9mIHRoZSBtYXAgKGlmIHNldCBpbiB0aGUgYG1heFpvb21gIG9wdGlvbiBvZiB0aGUgbWFwIG9yIG9mIGFueSBsYXllcnMpLlxyXG5cdGdldE1heFpvb206IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMubWF4Wm9vbSA9PT0gdW5kZWZpbmVkID9cclxuXHRcdFx0KHRoaXMuX2xheWVyc01heFpvb20gPT09IHVuZGVmaW5lZCA/IEluZmluaXR5IDogdGhpcy5fbGF5ZXJzTWF4Wm9vbSkgOlxyXG5cdFx0XHR0aGlzLm9wdGlvbnMubWF4Wm9vbTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldEJvdW5kc1pvb20oYm91bmRzOiBMYXRMbmdCb3VuZHMsIGluc2lkZT86IEJvb2xlYW4pOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBtYXhpbXVtIHpvb20gbGV2ZWwgb24gd2hpY2ggdGhlIGdpdmVuIGJvdW5kcyBmaXQgdG8gdGhlIG1hcFxyXG5cdC8vIHZpZXcgaW4gaXRzIGVudGlyZXR5LiBJZiBgaW5zaWRlYCAob3B0aW9uYWwpIGlzIHNldCB0byBgdHJ1ZWAsIHRoZSBtZXRob2RcclxuXHQvLyBpbnN0ZWFkIHJldHVybnMgdGhlIG1pbmltdW0gem9vbSBsZXZlbCBvbiB3aGljaCB0aGUgbWFwIHZpZXcgZml0cyBpbnRvXHJcblx0Ly8gdGhlIGdpdmVuIGJvdW5kcyBpbiBpdHMgZW50aXJldHkuXHJcblx0Z2V0Qm91bmRzWm9vbTogZnVuY3Rpb24gKGJvdW5kcywgaW5zaWRlLCBwYWRkaW5nKSB7IC8vIChMYXRMbmdCb3VuZHNbLCBCb29sZWFuLCBQb2ludF0pIC0+IE51bWJlclxyXG5cdFx0Ym91bmRzID0gdG9MYXRMbmdCb3VuZHMoYm91bmRzKTtcclxuXHRcdHBhZGRpbmcgPSB0b1BvaW50KHBhZGRpbmcgfHwgWzAsIDBdKTtcclxuXHJcblx0XHR2YXIgem9vbSA9IHRoaXMuZ2V0Wm9vbSgpIHx8IDAsXHJcblx0XHQgICAgbWluID0gdGhpcy5nZXRNaW5ab29tKCksXHJcblx0XHQgICAgbWF4ID0gdGhpcy5nZXRNYXhab29tKCksXHJcblx0XHQgICAgbncgPSBib3VuZHMuZ2V0Tm9ydGhXZXN0KCksXHJcblx0XHQgICAgc2UgPSBib3VuZHMuZ2V0U291dGhFYXN0KCksXHJcblx0XHQgICAgc2l6ZSA9IHRoaXMuZ2V0U2l6ZSgpLnN1YnRyYWN0KHBhZGRpbmcpLFxyXG5cdFx0ICAgIGJvdW5kc1NpemUgPSB0b0JvdW5kcyh0aGlzLnByb2plY3Qoc2UsIHpvb20pLCB0aGlzLnByb2plY3QobncsIHpvb20pKS5nZXRTaXplKCksXHJcblx0XHQgICAgc25hcCA9IGFueTNkID8gdGhpcy5vcHRpb25zLnpvb21TbmFwIDogMSxcclxuXHRcdCAgICBzY2FsZXggPSBzaXplLnggLyBib3VuZHNTaXplLngsXHJcblx0XHQgICAgc2NhbGV5ID0gc2l6ZS55IC8gYm91bmRzU2l6ZS55LFxyXG5cdFx0ICAgIHNjYWxlID0gaW5zaWRlID8gTWF0aC5tYXgoc2NhbGV4LCBzY2FsZXkpIDogTWF0aC5taW4oc2NhbGV4LCBzY2FsZXkpO1xyXG5cclxuXHRcdHpvb20gPSB0aGlzLmdldFNjYWxlWm9vbShzY2FsZSwgem9vbSk7XHJcblxyXG5cdFx0aWYgKHNuYXApIHtcclxuXHRcdFx0em9vbSA9IE1hdGgucm91bmQoem9vbSAvIChzbmFwIC8gMTAwKSkgKiAoc25hcCAvIDEwMCk7IC8vIGRvbid0IGp1bXAgaWYgd2l0aGluIDElIG9mIGEgc25hcCBsZXZlbFxyXG5cdFx0XHR6b29tID0gaW5zaWRlID8gTWF0aC5jZWlsKHpvb20gLyBzbmFwKSAqIHNuYXAgOiBNYXRoLmZsb29yKHpvb20gLyBzbmFwKSAqIHNuYXA7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIE1hdGgubWF4KG1pbiwgTWF0aC5taW4obWF4LCB6b29tKSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRTaXplKCk6IFBvaW50XHJcblx0Ly8gUmV0dXJucyB0aGUgY3VycmVudCBzaXplIG9mIHRoZSBtYXAgY29udGFpbmVyIChpbiBwaXhlbHMpLlxyXG5cdGdldFNpemU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICghdGhpcy5fc2l6ZSB8fCB0aGlzLl9zaXplQ2hhbmdlZCkge1xyXG5cdFx0XHR0aGlzLl9zaXplID0gbmV3IFBvaW50KFxyXG5cdFx0XHRcdHRoaXMuX2NvbnRhaW5lci5jbGllbnRXaWR0aCB8fCAwLFxyXG5cdFx0XHRcdHRoaXMuX2NvbnRhaW5lci5jbGllbnRIZWlnaHQgfHwgMCk7XHJcblxyXG5cdFx0XHR0aGlzLl9zaXplQ2hhbmdlZCA9IGZhbHNlO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXMuX3NpemUuY2xvbmUoKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldFBpeGVsQm91bmRzKCk6IEJvdW5kc1xyXG5cdC8vIFJldHVybnMgdGhlIGJvdW5kcyBvZiB0aGUgY3VycmVudCBtYXAgdmlldyBpbiBwcm9qZWN0ZWQgcGl4ZWxcclxuXHQvLyBjb29yZGluYXRlcyAoc29tZXRpbWVzIHVzZWZ1bCBpbiBsYXllciBhbmQgb3ZlcmxheSBpbXBsZW1lbnRhdGlvbnMpLlxyXG5cdGdldFBpeGVsQm91bmRzOiBmdW5jdGlvbiAoY2VudGVyLCB6b29tKSB7XHJcblx0XHR2YXIgdG9wTGVmdFBvaW50ID0gdGhpcy5fZ2V0VG9wTGVmdFBvaW50KGNlbnRlciwgem9vbSk7XHJcblx0XHRyZXR1cm4gbmV3IEJvdW5kcyh0b3BMZWZ0UG9pbnQsIHRvcExlZnRQb2ludC5hZGQodGhpcy5nZXRTaXplKCkpKTtcclxuXHR9LFxyXG5cclxuXHQvLyBUT0RPOiBDaGVjayBzZW1hbnRpY3MgLSBpc24ndCB0aGUgcGl4ZWwgb3JpZ2luIHRoZSAwLDAgY29vcmQgcmVsYXRpdmUgdG9cclxuXHQvLyB0aGUgbWFwIHBhbmU/IFwibGVmdCBwb2ludCBvZiB0aGUgbWFwIGxheWVyXCIgY2FuIGJlIGNvbmZ1c2luZywgc3BlY2lhbGx5XHJcblx0Ly8gc2luY2UgdGhlcmUgY2FuIGJlIG5lZ2F0aXZlIG9mZnNldHMuXHJcblx0Ly8gQG1ldGhvZCBnZXRQaXhlbE9yaWdpbigpOiBQb2ludFxyXG5cdC8vIFJldHVybnMgdGhlIHByb2plY3RlZCBwaXhlbCBjb29yZGluYXRlcyBvZiB0aGUgdG9wIGxlZnQgcG9pbnQgb2ZcclxuXHQvLyB0aGUgbWFwIGxheWVyICh1c2VmdWwgaW4gY3VzdG9tIGxheWVyIGFuZCBvdmVybGF5IGltcGxlbWVudGF0aW9ucykuXHJcblx0Z2V0UGl4ZWxPcmlnaW46IGZ1bmN0aW9uICgpIHtcclxuXHRcdHRoaXMuX2NoZWNrSWZMb2FkZWQoKTtcclxuXHRcdHJldHVybiB0aGlzLl9waXhlbE9yaWdpbjtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldFBpeGVsV29ybGRCb3VuZHMoem9vbT86IE51bWJlcik6IEJvdW5kc1xyXG5cdC8vIFJldHVybnMgdGhlIHdvcmxkJ3MgYm91bmRzIGluIHBpeGVsIGNvb3JkaW5hdGVzIGZvciB6b29tIGxldmVsIGB6b29tYC5cclxuXHQvLyBJZiBgem9vbWAgaXMgb21pdHRlZCwgdGhlIG1hcCdzIGN1cnJlbnQgem9vbSBsZXZlbCBpcyB1c2VkLlxyXG5cdGdldFBpeGVsV29ybGRCb3VuZHM6IGZ1bmN0aW9uICh6b29tKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLmNycy5nZXRQcm9qZWN0ZWRCb3VuZHMoem9vbSA9PT0gdW5kZWZpbmVkID8gdGhpcy5nZXRab29tKCkgOiB6b29tKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAc2VjdGlvbiBPdGhlciBNZXRob2RzXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0UGFuZShwYW5lOiBTdHJpbmd8SFRNTEVsZW1lbnQpOiBIVE1MRWxlbWVudFxyXG5cdC8vIFJldHVybnMgYSBbbWFwIHBhbmVdKCNtYXAtcGFuZSksIGdpdmVuIGl0cyBuYW1lIG9yIGl0cyBIVE1MIGVsZW1lbnQgKGl0cyBpZGVudGl0eSkuXHJcblx0Z2V0UGFuZTogZnVuY3Rpb24gKHBhbmUpIHtcclxuXHRcdHJldHVybiB0eXBlb2YgcGFuZSA9PT0gJ3N0cmluZycgPyB0aGlzLl9wYW5lc1twYW5lXSA6IHBhbmU7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRQYW5lcygpOiBPYmplY3RcclxuXHQvLyBSZXR1cm5zIGEgcGxhaW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIG5hbWVzIG9mIGFsbCBbcGFuZXNdKCNtYXAtcGFuZSkgYXMga2V5cyBhbmRcclxuXHQvLyB0aGUgcGFuZXMgYXMgdmFsdWVzLlxyXG5cdGdldFBhbmVzOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5fcGFuZXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRDb250YWluZXI6IEhUTUxFbGVtZW50XHJcblx0Ly8gUmV0dXJucyB0aGUgSFRNTCBlbGVtZW50IHRoYXQgY29udGFpbnMgdGhlIG1hcC5cclxuXHRnZXRDb250YWluZXI6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9jb250YWluZXI7XHJcblx0fSxcclxuXHJcblxyXG5cdC8vIEBzZWN0aW9uIENvbnZlcnNpb24gTWV0aG9kc1xyXG5cclxuXHQvLyBAbWV0aG9kIGdldFpvb21TY2FsZSh0b1pvb206IE51bWJlciwgZnJvbVpvb206IE51bWJlcik6IE51bWJlclxyXG5cdC8vIFJldHVybnMgdGhlIHNjYWxlIGZhY3RvciB0byBiZSBhcHBsaWVkIHRvIGEgbWFwIHRyYW5zaXRpb24gZnJvbSB6b29tIGxldmVsXHJcblx0Ly8gYGZyb21ab29tYCB0byBgdG9ab29tYC4gVXNlZCBpbnRlcm5hbGx5IHRvIGhlbHAgd2l0aCB6b29tIGFuaW1hdGlvbnMuXHJcblx0Z2V0Wm9vbVNjYWxlOiBmdW5jdGlvbiAodG9ab29tLCBmcm9tWm9vbSkge1xyXG5cdFx0Ly8gVE9ETyByZXBsYWNlIHdpdGggdW5pdmVyc2FsIGltcGxlbWVudGF0aW9uIGFmdGVyIHJlZmFjdG9yaW5nIHByb2plY3Rpb25zXHJcblx0XHR2YXIgY3JzID0gdGhpcy5vcHRpb25zLmNycztcclxuXHRcdGZyb21ab29tID0gZnJvbVpvb20gPT09IHVuZGVmaW5lZCA/IHRoaXMuX3pvb20gOiBmcm9tWm9vbTtcclxuXHRcdHJldHVybiBjcnMuc2NhbGUodG9ab29tKSAvIGNycy5zY2FsZShmcm9tWm9vbSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRTY2FsZVpvb20oc2NhbGU6IE51bWJlciwgZnJvbVpvb206IE51bWJlcik6IE51bWJlclxyXG5cdC8vIFJldHVybnMgdGhlIHpvb20gbGV2ZWwgdGhhdCB0aGUgbWFwIHdvdWxkIGVuZCB1cCBhdCwgaWYgaXQgaXMgYXQgYGZyb21ab29tYFxyXG5cdC8vIGxldmVsIGFuZCBldmVyeXRoaW5nIGlzIHNjYWxlZCBieSBhIGZhY3RvciBvZiBgc2NhbGVgLiBJbnZlcnNlIG9mXHJcblx0Ly8gW2BnZXRab29tU2NhbGVgXSgjbWFwLWdldFpvb21TY2FsZSkuXHJcblx0Z2V0U2NhbGVab29tOiBmdW5jdGlvbiAoc2NhbGUsIGZyb21ab29tKSB7XHJcblx0XHR2YXIgY3JzID0gdGhpcy5vcHRpb25zLmNycztcclxuXHRcdGZyb21ab29tID0gZnJvbVpvb20gPT09IHVuZGVmaW5lZCA/IHRoaXMuX3pvb20gOiBmcm9tWm9vbTtcclxuXHRcdHZhciB6b29tID0gY3JzLnpvb20oc2NhbGUgKiBjcnMuc2NhbGUoZnJvbVpvb20pKTtcclxuXHRcdHJldHVybiBpc05hTih6b29tKSA/IEluZmluaXR5IDogem9vbTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHByb2plY3QobGF0bG5nOiBMYXRMbmcsIHpvb206IE51bWJlcik6IFBvaW50XHJcblx0Ly8gUHJvamVjdHMgYSBnZW9ncmFwaGljYWwgY29vcmRpbmF0ZSBgTGF0TG5nYCBhY2NvcmRpbmcgdG8gdGhlIHByb2plY3Rpb25cclxuXHQvLyBvZiB0aGUgbWFwJ3MgQ1JTLCB0aGVuIHNjYWxlcyBpdCBhY2NvcmRpbmcgdG8gYHpvb21gIGFuZCB0aGUgQ1JTJ3NcclxuXHQvLyBgVHJhbnNmb3JtYXRpb25gLiBUaGUgcmVzdWx0IGlzIHBpeGVsIGNvb3JkaW5hdGUgcmVsYXRpdmUgdG9cclxuXHQvLyB0aGUgQ1JTIG9yaWdpbi5cclxuXHRwcm9qZWN0OiBmdW5jdGlvbiAobGF0bG5nLCB6b29tKSB7XHJcblx0XHR6b29tID0gem9vbSA9PT0gdW5kZWZpbmVkID8gdGhpcy5fem9vbSA6IHpvb207XHJcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLmNycy5sYXRMbmdUb1BvaW50KHRvTGF0TG5nKGxhdGxuZyksIHpvb20pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgdW5wcm9qZWN0KHBvaW50OiBQb2ludCwgem9vbTogTnVtYmVyKTogTGF0TG5nXHJcblx0Ly8gSW52ZXJzZSBvZiBbYHByb2plY3RgXSgjbWFwLXByb2plY3QpLlxyXG5cdHVucHJvamVjdDogZnVuY3Rpb24gKHBvaW50LCB6b29tKSB7XHJcblx0XHR6b29tID0gem9vbSA9PT0gdW5kZWZpbmVkID8gdGhpcy5fem9vbSA6IHpvb207XHJcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLmNycy5wb2ludFRvTGF0TG5nKHRvUG9pbnQocG9pbnQpLCB6b29tKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGxheWVyUG9pbnRUb0xhdExuZyhwb2ludDogUG9pbnQpOiBMYXRMbmdcclxuXHQvLyBHaXZlbiBhIHBpeGVsIGNvb3JkaW5hdGUgcmVsYXRpdmUgdG8gdGhlIFtvcmlnaW4gcGl4ZWxdKCNtYXAtZ2V0cGl4ZWxvcmlnaW4pLFxyXG5cdC8vIHJldHVybnMgdGhlIGNvcnJlc3BvbmRpbmcgZ2VvZ3JhcGhpY2FsIGNvb3JkaW5hdGUgKGZvciB0aGUgY3VycmVudCB6b29tIGxldmVsKS5cclxuXHRsYXllclBvaW50VG9MYXRMbmc6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0dmFyIHByb2plY3RlZFBvaW50ID0gdG9Qb2ludChwb2ludCkuYWRkKHRoaXMuZ2V0UGl4ZWxPcmlnaW4oKSk7XHJcblx0XHRyZXR1cm4gdGhpcy51bnByb2plY3QocHJvamVjdGVkUG9pbnQpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgbGF0TG5nVG9MYXllclBvaW50KGxhdGxuZzogTGF0TG5nKTogUG9pbnRcclxuXHQvLyBHaXZlbiBhIGdlb2dyYXBoaWNhbCBjb29yZGluYXRlLCByZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIHBpeGVsIGNvb3JkaW5hdGVcclxuXHQvLyByZWxhdGl2ZSB0byB0aGUgW29yaWdpbiBwaXhlbF0oI21hcC1nZXRwaXhlbG9yaWdpbikuXHJcblx0bGF0TG5nVG9MYXllclBvaW50OiBmdW5jdGlvbiAobGF0bG5nKSB7XHJcblx0XHR2YXIgcHJvamVjdGVkUG9pbnQgPSB0aGlzLnByb2plY3QodG9MYXRMbmcobGF0bG5nKSkuX3JvdW5kKCk7XHJcblx0XHRyZXR1cm4gcHJvamVjdGVkUG9pbnQuX3N1YnRyYWN0KHRoaXMuZ2V0UGl4ZWxPcmlnaW4oKSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB3cmFwTGF0TG5nKGxhdGxuZzogTGF0TG5nKTogTGF0TG5nXHJcblx0Ly8gUmV0dXJucyBhIGBMYXRMbmdgIHdoZXJlIGBsYXRgIGFuZCBgbG5nYCBoYXMgYmVlbiB3cmFwcGVkIGFjY29yZGluZyB0byB0aGVcclxuXHQvLyBtYXAncyBDUlMncyBgd3JhcExhdGAgYW5kIGB3cmFwTG5nYCBwcm9wZXJ0aWVzLCBpZiB0aGV5IGFyZSBvdXRzaWRlIHRoZVxyXG5cdC8vIENSUydzIGJvdW5kcy5cclxuXHQvLyBCeSBkZWZhdWx0IHRoaXMgbWVhbnMgbG9uZ2l0dWRlIGlzIHdyYXBwZWQgYXJvdW5kIHRoZSBkYXRlbGluZSBzbyBpdHNcclxuXHQvLyB2YWx1ZSBpcyBiZXR3ZWVuIC0xODAgYW5kICsxODAgZGVncmVlcy5cclxuXHR3cmFwTGF0TG5nOiBmdW5jdGlvbiAobGF0bG5nKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLmNycy53cmFwTGF0TG5nKHRvTGF0TG5nKGxhdGxuZykpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgd3JhcExhdExuZ0JvdW5kcyhib3VuZHM6IExhdExuZ0JvdW5kcyk6IExhdExuZ0JvdW5kc1xyXG5cdC8vIFJldHVybnMgYSBgTGF0TG5nQm91bmRzYCB3aXRoIHRoZSBzYW1lIHNpemUgYXMgdGhlIGdpdmVuIG9uZSwgZW5zdXJpbmcgdGhhdFxyXG5cdC8vIGl0cyBjZW50ZXIgaXMgd2l0aGluIHRoZSBDUlMncyBib3VuZHMuXHJcblx0Ly8gQnkgZGVmYXVsdCB0aGlzIG1lYW5zIHRoZSBjZW50ZXIgbG9uZ2l0dWRlIGlzIHdyYXBwZWQgYXJvdW5kIHRoZSBkYXRlbGluZSBzbyBpdHNcclxuXHQvLyB2YWx1ZSBpcyBiZXR3ZWVuIC0xODAgYW5kICsxODAgZGVncmVlcywgYW5kIHRoZSBtYWpvcml0eSBvZiB0aGUgYm91bmRzXHJcblx0Ly8gb3ZlcmxhcHMgdGhlIENSUydzIGJvdW5kcy5cclxuXHR3cmFwTGF0TG5nQm91bmRzOiBmdW5jdGlvbiAobGF0bG5nKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLmNycy53cmFwTGF0TG5nQm91bmRzKHRvTGF0TG5nQm91bmRzKGxhdGxuZykpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZGlzdGFuY2UobGF0bG5nMTogTGF0TG5nLCBsYXRsbmcyOiBMYXRMbmcpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBkaXN0YW5jZSBiZXR3ZWVuIHR3byBnZW9ncmFwaGljYWwgY29vcmRpbmF0ZXMgYWNjb3JkaW5nIHRvXHJcblx0Ly8gdGhlIG1hcCdzIENSUy4gQnkgZGVmYXVsdCB0aGlzIG1lYXN1cmVzIGRpc3RhbmNlIGluIG1ldGVycy5cclxuXHRkaXN0YW5jZTogZnVuY3Rpb24gKGxhdGxuZzEsIGxhdGxuZzIpIHtcclxuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMuY3JzLmRpc3RhbmNlKHRvTGF0TG5nKGxhdGxuZzEpLCB0b0xhdExuZyhsYXRsbmcyKSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBjb250YWluZXJQb2ludFRvTGF5ZXJQb2ludChwb2ludDogUG9pbnQpOiBQb2ludFxyXG5cdC8vIEdpdmVuIGEgcGl4ZWwgY29vcmRpbmF0ZSByZWxhdGl2ZSB0byB0aGUgbWFwIGNvbnRhaW5lciwgcmV0dXJucyB0aGUgY29ycmVzcG9uZGluZ1xyXG5cdC8vIHBpeGVsIGNvb3JkaW5hdGUgcmVsYXRpdmUgdG8gdGhlIFtvcmlnaW4gcGl4ZWxdKCNtYXAtZ2V0cGl4ZWxvcmlnaW4pLlxyXG5cdGNvbnRhaW5lclBvaW50VG9MYXllclBvaW50OiBmdW5jdGlvbiAocG9pbnQpIHsgLy8gKFBvaW50KVxyXG5cdFx0cmV0dXJuIHRvUG9pbnQocG9pbnQpLnN1YnRyYWN0KHRoaXMuX2dldE1hcFBhbmVQb3MoKSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBsYXllclBvaW50VG9Db250YWluZXJQb2ludChwb2ludDogUG9pbnQpOiBQb2ludFxyXG5cdC8vIEdpdmVuIGEgcGl4ZWwgY29vcmRpbmF0ZSByZWxhdGl2ZSB0byB0aGUgW29yaWdpbiBwaXhlbF0oI21hcC1nZXRwaXhlbG9yaWdpbiksXHJcblx0Ly8gcmV0dXJucyB0aGUgY29ycmVzcG9uZGluZyBwaXhlbCBjb29yZGluYXRlIHJlbGF0aXZlIHRvIHRoZSBtYXAgY29udGFpbmVyLlxyXG5cdGxheWVyUG9pbnRUb0NvbnRhaW5lclBvaW50OiBmdW5jdGlvbiAocG9pbnQpIHsgLy8gKFBvaW50KVxyXG5cdFx0cmV0dXJuIHRvUG9pbnQocG9pbnQpLmFkZCh0aGlzLl9nZXRNYXBQYW5lUG9zKCkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgY29udGFpbmVyUG9pbnRUb0xhdExuZyhwb2ludDogUG9pbnQpOiBMYXRMbmdcclxuXHQvLyBHaXZlbiBhIHBpeGVsIGNvb3JkaW5hdGUgcmVsYXRpdmUgdG8gdGhlIG1hcCBjb250YWluZXIsIHJldHVybnNcclxuXHQvLyB0aGUgY29ycmVzcG9uZGluZyBnZW9ncmFwaGljYWwgY29vcmRpbmF0ZSAoZm9yIHRoZSBjdXJyZW50IHpvb20gbGV2ZWwpLlxyXG5cdGNvbnRhaW5lclBvaW50VG9MYXRMbmc6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0dmFyIGxheWVyUG9pbnQgPSB0aGlzLmNvbnRhaW5lclBvaW50VG9MYXllclBvaW50KHRvUG9pbnQocG9pbnQpKTtcclxuXHRcdHJldHVybiB0aGlzLmxheWVyUG9pbnRUb0xhdExuZyhsYXllclBvaW50KTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGxhdExuZ1RvQ29udGFpbmVyUG9pbnQobGF0bG5nOiBMYXRMbmcpOiBQb2ludFxyXG5cdC8vIEdpdmVuIGEgZ2VvZ3JhcGhpY2FsIGNvb3JkaW5hdGUsIHJldHVybnMgdGhlIGNvcnJlc3BvbmRpbmcgcGl4ZWwgY29vcmRpbmF0ZVxyXG5cdC8vIHJlbGF0aXZlIHRvIHRoZSBtYXAgY29udGFpbmVyLlxyXG5cdGxhdExuZ1RvQ29udGFpbmVyUG9pbnQ6IGZ1bmN0aW9uIChsYXRsbmcpIHtcclxuXHRcdHJldHVybiB0aGlzLmxheWVyUG9pbnRUb0NvbnRhaW5lclBvaW50KHRoaXMubGF0TG5nVG9MYXllclBvaW50KHRvTGF0TG5nKGxhdGxuZykpKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIG1vdXNlRXZlbnRUb0NvbnRhaW5lclBvaW50KGV2OiBNb3VzZUV2ZW50KTogUG9pbnRcclxuXHQvLyBHaXZlbiBhIE1vdXNlRXZlbnQgb2JqZWN0LCByZXR1cm5zIHRoZSBwaXhlbCBjb29yZGluYXRlIHJlbGF0aXZlIHRvIHRoZVxyXG5cdC8vIG1hcCBjb250YWluZXIgd2hlcmUgdGhlIGV2ZW50IHRvb2sgcGxhY2UuXHJcblx0bW91c2VFdmVudFRvQ29udGFpbmVyUG9pbnQ6IGZ1bmN0aW9uIChlKSB7XHJcblx0XHRyZXR1cm4gZ2V0TW91c2VQb3NpdGlvbihlLCB0aGlzLl9jb250YWluZXIpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgbW91c2VFdmVudFRvTGF5ZXJQb2ludChldjogTW91c2VFdmVudCk6IFBvaW50XHJcblx0Ly8gR2l2ZW4gYSBNb3VzZUV2ZW50IG9iamVjdCwgcmV0dXJucyB0aGUgcGl4ZWwgY29vcmRpbmF0ZSByZWxhdGl2ZSB0b1xyXG5cdC8vIHRoZSBbb3JpZ2luIHBpeGVsXSgjbWFwLWdldHBpeGVsb3JpZ2luKSB3aGVyZSB0aGUgZXZlbnQgdG9vayBwbGFjZS5cclxuXHRtb3VzZUV2ZW50VG9MYXllclBvaW50OiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0cmV0dXJuIHRoaXMuY29udGFpbmVyUG9pbnRUb0xheWVyUG9pbnQodGhpcy5tb3VzZUV2ZW50VG9Db250YWluZXJQb2ludChlKSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBtb3VzZUV2ZW50VG9MYXRMbmcoZXY6IE1vdXNlRXZlbnQpOiBMYXRMbmdcclxuXHQvLyBHaXZlbiBhIE1vdXNlRXZlbnQgb2JqZWN0LCByZXR1cm5zIGdlb2dyYXBoaWNhbCBjb29yZGluYXRlIHdoZXJlIHRoZVxyXG5cdC8vIGV2ZW50IHRvb2sgcGxhY2UuXHJcblx0bW91c2VFdmVudFRvTGF0TG5nOiBmdW5jdGlvbiAoZSkgeyAvLyAoTW91c2VFdmVudClcclxuXHRcdHJldHVybiB0aGlzLmxheWVyUG9pbnRUb0xhdExuZyh0aGlzLm1vdXNlRXZlbnRUb0xheWVyUG9pbnQoZSkpO1xyXG5cdH0sXHJcblxyXG5cclxuXHQvLyBtYXAgaW5pdGlhbGl6YXRpb24gbWV0aG9kc1xyXG5cclxuXHRfaW5pdENvbnRhaW5lcjogZnVuY3Rpb24gKGlkKSB7XHJcblx0XHR2YXIgY29udGFpbmVyID0gdGhpcy5fY29udGFpbmVyID0gZ2V0KGlkKTtcclxuXHJcblx0XHRpZiAoIWNvbnRhaW5lcikge1xyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ01hcCBjb250YWluZXIgbm90IGZvdW5kLicpO1xyXG5cdFx0fSBlbHNlIGlmIChjb250YWluZXIuX2xlYWZsZXRfaWQpIHtcclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdNYXAgY29udGFpbmVyIGlzIGFscmVhZHkgaW5pdGlhbGl6ZWQuJyk7XHJcblx0XHR9XHJcblxyXG5cdFx0b24oY29udGFpbmVyLCAnc2Nyb2xsJywgdGhpcy5fb25TY3JvbGwsIHRoaXMpO1xyXG5cdFx0dGhpcy5fY29udGFpbmVySWQgPSBzdGFtcChjb250YWluZXIpO1xyXG5cdH0sXHJcblxyXG5cdF9pbml0TGF5b3V0OiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgY29udGFpbmVyID0gdGhpcy5fY29udGFpbmVyO1xyXG5cclxuXHRcdHRoaXMuX2ZhZGVBbmltYXRlZCA9IHRoaXMub3B0aW9ucy5mYWRlQW5pbWF0aW9uICYmIGFueTNkO1xyXG5cclxuXHRcdGFkZENsYXNzKGNvbnRhaW5lciwgJ2xlYWZsZXQtY29udGFpbmVyJyArXHJcblx0XHRcdCh0b3VjaCA/ICcgbGVhZmxldC10b3VjaCcgOiAnJykgK1xyXG5cdFx0XHQocmV0aW5hID8gJyBsZWFmbGV0LXJldGluYScgOiAnJykgK1xyXG5cdFx0XHQoaWVsdDkgPyAnIGxlYWZsZXQtb2xkaWUnIDogJycpICtcclxuXHRcdFx0KHNhZmFyaSA/ICcgbGVhZmxldC1zYWZhcmknIDogJycpICtcclxuXHRcdFx0KHRoaXMuX2ZhZGVBbmltYXRlZCA/ICcgbGVhZmxldC1mYWRlLWFuaW0nIDogJycpKTtcclxuXHJcblx0XHR2YXIgcG9zaXRpb24gPSBnZXRTdHlsZShjb250YWluZXIsICdwb3NpdGlvbicpO1xyXG5cclxuXHRcdGlmIChwb3NpdGlvbiAhPT0gJ2Fic29sdXRlJyAmJiBwb3NpdGlvbiAhPT0gJ3JlbGF0aXZlJyAmJiBwb3NpdGlvbiAhPT0gJ2ZpeGVkJykge1xyXG5cdFx0XHRjb250YWluZXIuc3R5bGUucG9zaXRpb24gPSAncmVsYXRpdmUnO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2luaXRQYW5lcygpO1xyXG5cclxuXHRcdGlmICh0aGlzLl9pbml0Q29udHJvbFBvcykge1xyXG5cdFx0XHR0aGlzLl9pbml0Q29udHJvbFBvcygpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdF9pbml0UGFuZXM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBwYW5lcyA9IHRoaXMuX3BhbmVzID0ge307XHJcblx0XHR0aGlzLl9wYW5lUmVuZGVyZXJzID0ge307XHJcblxyXG5cdFx0Ly8gQHNlY3Rpb25cclxuXHRcdC8vXHJcblx0XHQvLyBQYW5lcyBhcmUgRE9NIGVsZW1lbnRzIHVzZWQgdG8gY29udHJvbCB0aGUgb3JkZXJpbmcgb2YgbGF5ZXJzIG9uIHRoZSBtYXAuIFlvdVxyXG5cdFx0Ly8gY2FuIGFjY2VzcyBwYW5lcyB3aXRoIFtgbWFwLmdldFBhbmVgXSgjbWFwLWdldHBhbmUpIG9yXHJcblx0XHQvLyBbYG1hcC5nZXRQYW5lc2BdKCNtYXAtZ2V0cGFuZXMpIG1ldGhvZHMuIE5ldyBwYW5lcyBjYW4gYmUgY3JlYXRlZCB3aXRoIHRoZVxyXG5cdFx0Ly8gW2BtYXAuY3JlYXRlUGFuZWBdKCNtYXAtY3JlYXRlcGFuZSkgbWV0aG9kLlxyXG5cdFx0Ly9cclxuXHRcdC8vIEV2ZXJ5IG1hcCBoYXMgdGhlIGZvbGxvd2luZyBkZWZhdWx0IHBhbmVzIHRoYXQgZGlmZmVyIG9ubHkgaW4gekluZGV4LlxyXG5cdFx0Ly9cclxuXHRcdC8vIEBwYW5lIG1hcFBhbmU6IEhUTUxFbGVtZW50ID0gJ2F1dG8nXHJcblx0XHQvLyBQYW5lIHRoYXQgY29udGFpbnMgYWxsIG90aGVyIG1hcCBwYW5lc1xyXG5cclxuXHRcdHRoaXMuX21hcFBhbmUgPSB0aGlzLmNyZWF0ZVBhbmUoJ21hcFBhbmUnLCB0aGlzLl9jb250YWluZXIpO1xyXG5cdFx0c2V0UG9zaXRpb24odGhpcy5fbWFwUGFuZSwgbmV3IFBvaW50KDAsIDApKTtcclxuXHJcblx0XHQvLyBAcGFuZSB0aWxlUGFuZTogSFRNTEVsZW1lbnQgPSAyMDBcclxuXHRcdC8vIFBhbmUgZm9yIGBHcmlkTGF5ZXJgcyBhbmQgYFRpbGVMYXllcmBzXHJcblx0XHR0aGlzLmNyZWF0ZVBhbmUoJ3RpbGVQYW5lJyk7XHJcblx0XHQvLyBAcGFuZSBvdmVybGF5UGFuZTogSFRNTEVsZW1lbnQgPSA0MDBcclxuXHRcdC8vIFBhbmUgZm9yIHZlY3RvcnMgKGBQYXRoYHMsIGxpa2UgYFBvbHlsaW5lYHMgYW5kIGBQb2x5Z29uYHMpLCBgSW1hZ2VPdmVybGF5YHMgYW5kIGBWaWRlb092ZXJsYXlgc1xyXG5cdFx0dGhpcy5jcmVhdGVQYW5lKCdzaGFkb3dQYW5lJyk7XHJcblx0XHQvLyBAcGFuZSBzaGFkb3dQYW5lOiBIVE1MRWxlbWVudCA9IDUwMFxyXG5cdFx0Ly8gUGFuZSBmb3Igb3ZlcmxheSBzaGFkb3dzIChlLmcuIGBNYXJrZXJgIHNoYWRvd3MpXHJcblx0XHR0aGlzLmNyZWF0ZVBhbmUoJ292ZXJsYXlQYW5lJyk7XHJcblx0XHQvLyBAcGFuZSBtYXJrZXJQYW5lOiBIVE1MRWxlbWVudCA9IDYwMFxyXG5cdFx0Ly8gUGFuZSBmb3IgYEljb25gcyBvZiBgTWFya2VyYHNcclxuXHRcdHRoaXMuY3JlYXRlUGFuZSgnbWFya2VyUGFuZScpO1xyXG5cdFx0Ly8gQHBhbmUgdG9vbHRpcFBhbmU6IEhUTUxFbGVtZW50ID0gNjUwXHJcblx0XHQvLyBQYW5lIGZvciBgVG9vbHRpcGBzLlxyXG5cdFx0dGhpcy5jcmVhdGVQYW5lKCd0b29sdGlwUGFuZScpO1xyXG5cdFx0Ly8gQHBhbmUgcG9wdXBQYW5lOiBIVE1MRWxlbWVudCA9IDcwMFxyXG5cdFx0Ly8gUGFuZSBmb3IgYFBvcHVwYHMuXHJcblx0XHR0aGlzLmNyZWF0ZVBhbmUoJ3BvcHVwUGFuZScpO1xyXG5cclxuXHRcdGlmICghdGhpcy5vcHRpb25zLm1hcmtlclpvb21BbmltYXRpb24pIHtcclxuXHRcdFx0YWRkQ2xhc3MocGFuZXMubWFya2VyUGFuZSwgJ2xlYWZsZXQtem9vbS1oaWRlJyk7XHJcblx0XHRcdGFkZENsYXNzKHBhbmVzLnNoYWRvd1BhbmUsICdsZWFmbGV0LXpvb20taGlkZScpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cclxuXHQvLyBwcml2YXRlIG1ldGhvZHMgdGhhdCBtb2RpZnkgbWFwIHN0YXRlXHJcblxyXG5cdC8vIEBzZWN0aW9uIE1hcCBzdGF0ZSBjaGFuZ2UgZXZlbnRzXHJcblx0X3Jlc2V0VmlldzogZnVuY3Rpb24gKGNlbnRlciwgem9vbSkge1xyXG5cdFx0c2V0UG9zaXRpb24odGhpcy5fbWFwUGFuZSwgbmV3IFBvaW50KDAsIDApKTtcclxuXHJcblx0XHR2YXIgbG9hZGluZyA9ICF0aGlzLl9sb2FkZWQ7XHJcblx0XHR0aGlzLl9sb2FkZWQgPSB0cnVlO1xyXG5cdFx0em9vbSA9IHRoaXMuX2xpbWl0Wm9vbSh6b29tKTtcclxuXHJcblx0XHR0aGlzLmZpcmUoJ3ZpZXdwcmVyZXNldCcpO1xyXG5cclxuXHRcdHZhciB6b29tQ2hhbmdlZCA9IHRoaXMuX3pvb20gIT09IHpvb207XHJcblx0XHR0aGlzXHJcblx0XHRcdC5fbW92ZVN0YXJ0KHpvb21DaGFuZ2VkLCBmYWxzZSlcclxuXHRcdFx0Ll9tb3ZlKGNlbnRlciwgem9vbSlcclxuXHRcdFx0Ll9tb3ZlRW5kKHpvb21DaGFuZ2VkKTtcclxuXHJcblx0XHQvLyBAZXZlbnQgdmlld3Jlc2V0OiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFwIG5lZWRzIHRvIHJlZHJhdyBpdHMgY29udGVudCAodGhpcyB1c3VhbGx5IGhhcHBlbnNcclxuXHRcdC8vIG9uIG1hcCB6b29tIG9yIGxvYWQpLiBWZXJ5IHVzZWZ1bCBmb3IgY3JlYXRpbmcgY3VzdG9tIG92ZXJsYXlzLlxyXG5cdFx0dGhpcy5maXJlKCd2aWV3cmVzZXQnKTtcclxuXHJcblx0XHQvLyBAZXZlbnQgbG9hZDogRXZlbnRcclxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIG1hcCBpcyBpbml0aWFsaXplZCAod2hlbiBpdHMgY2VudGVyIGFuZCB6b29tIGFyZSBzZXRcclxuXHRcdC8vIGZvciB0aGUgZmlyc3QgdGltZSkuXHJcblx0XHRpZiAobG9hZGluZykge1xyXG5cdFx0XHR0aGlzLmZpcmUoJ2xvYWQnKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfbW92ZVN0YXJ0OiBmdW5jdGlvbiAoem9vbUNoYW5nZWQsIG5vTW92ZVN0YXJ0KSB7XHJcblx0XHQvLyBAZXZlbnQgem9vbXN0YXJ0OiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFwIHpvb20gaXMgYWJvdXQgdG8gY2hhbmdlIChlLmcuIGJlZm9yZSB6b29tIGFuaW1hdGlvbikuXHJcblx0XHQvLyBAZXZlbnQgbW92ZXN0YXJ0OiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgdmlldyBvZiB0aGUgbWFwIHN0YXJ0cyBjaGFuZ2luZyAoZS5nLiB1c2VyIHN0YXJ0cyBkcmFnZ2luZyB0aGUgbWFwKS5cclxuXHRcdGlmICh6b29tQ2hhbmdlZCkge1xyXG5cdFx0XHR0aGlzLmZpcmUoJ3pvb21zdGFydCcpO1xyXG5cdFx0fVxyXG5cdFx0aWYgKCFub01vdmVTdGFydCkge1xyXG5cdFx0XHR0aGlzLmZpcmUoJ21vdmVzdGFydCcpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0X21vdmU6IGZ1bmN0aW9uIChjZW50ZXIsIHpvb20sIGRhdGEpIHtcclxuXHRcdGlmICh6b29tID09PSB1bmRlZmluZWQpIHtcclxuXHRcdFx0em9vbSA9IHRoaXMuX3pvb207XHJcblx0XHR9XHJcblx0XHR2YXIgem9vbUNoYW5nZWQgPSB0aGlzLl96b29tICE9PSB6b29tO1xyXG5cclxuXHRcdHRoaXMuX3pvb20gPSB6b29tO1xyXG5cdFx0dGhpcy5fbGFzdENlbnRlciA9IGNlbnRlcjtcclxuXHRcdHRoaXMuX3BpeGVsT3JpZ2luID0gdGhpcy5fZ2V0TmV3UGl4ZWxPcmlnaW4oY2VudGVyKTtcclxuXHJcblx0XHQvLyBAZXZlbnQgem9vbTogRXZlbnRcclxuXHRcdC8vIEZpcmVkIHJlcGVhdGVkbHkgZHVyaW5nIGFueSBjaGFuZ2UgaW4gem9vbSBsZXZlbCwgaW5jbHVkaW5nIHpvb21cclxuXHRcdC8vIGFuZCBmbHkgYW5pbWF0aW9ucy5cclxuXHRcdGlmICh6b29tQ2hhbmdlZCB8fCAoZGF0YSAmJiBkYXRhLnBpbmNoKSkge1x0Ly8gQWx3YXlzIGZpcmUgJ3pvb20nIGlmIHBpbmNoaW5nIGJlY2F1c2UgIzM1MzBcclxuXHRcdFx0dGhpcy5maXJlKCd6b29tJywgZGF0YSk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQGV2ZW50IG1vdmU6IEV2ZW50XHJcblx0XHQvLyBGaXJlZCByZXBlYXRlZGx5IGR1cmluZyBhbnkgbW92ZW1lbnQgb2YgdGhlIG1hcCwgaW5jbHVkaW5nIHBhbiBhbmRcclxuXHRcdC8vIGZseSBhbmltYXRpb25zLlxyXG5cdFx0cmV0dXJuIHRoaXMuZmlyZSgnbW92ZScsIGRhdGEpO1xyXG5cdH0sXHJcblxyXG5cdF9tb3ZlRW5kOiBmdW5jdGlvbiAoem9vbUNoYW5nZWQpIHtcclxuXHRcdC8vIEBldmVudCB6b29tZW5kOiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFwIGhhcyBjaGFuZ2VkLCBhZnRlciBhbnkgYW5pbWF0aW9ucy5cclxuXHRcdGlmICh6b29tQ2hhbmdlZCkge1xyXG5cdFx0XHR0aGlzLmZpcmUoJ3pvb21lbmQnKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBAZXZlbnQgbW92ZWVuZDogRXZlbnRcclxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIGNlbnRlciBvZiB0aGUgbWFwIHN0b3BzIGNoYW5naW5nIChlLmcuIHVzZXIgc3RvcHBlZFxyXG5cdFx0Ly8gZHJhZ2dpbmcgdGhlIG1hcCkuXHJcblx0XHRyZXR1cm4gdGhpcy5maXJlKCdtb3ZlZW5kJyk7XHJcblx0fSxcclxuXHJcblx0X3N0b3A6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGNhbmNlbEFuaW1GcmFtZSh0aGlzLl9mbHlUb0ZyYW1lKTtcclxuXHRcdGlmICh0aGlzLl9wYW5BbmltKSB7XHJcblx0XHRcdHRoaXMuX3BhbkFuaW0uc3RvcCgpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0X3Jhd1BhbkJ5OiBmdW5jdGlvbiAob2Zmc2V0KSB7XHJcblx0XHRzZXRQb3NpdGlvbih0aGlzLl9tYXBQYW5lLCB0aGlzLl9nZXRNYXBQYW5lUG9zKCkuc3VidHJhY3Qob2Zmc2V0KSk7XHJcblx0fSxcclxuXHJcblx0X2dldFpvb21TcGFuOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5nZXRNYXhab29tKCkgLSB0aGlzLmdldE1pblpvb20oKTtcclxuXHR9LFxyXG5cclxuXHRfcGFuSW5zaWRlTWF4Qm91bmRzOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAoIXRoaXMuX2VuZm9yY2luZ0JvdW5kcykge1xyXG5cdFx0XHR0aGlzLnBhbkluc2lkZUJvdW5kcyh0aGlzLm9wdGlvbnMubWF4Qm91bmRzKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfY2hlY2tJZkxvYWRlZDogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKCF0aGlzLl9sb2FkZWQpIHtcclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdTZXQgbWFwIGNlbnRlciBhbmQgem9vbSBmaXJzdC4nKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHQvLyBET00gZXZlbnQgaGFuZGxpbmdcclxuXHJcblx0Ly8gQHNlY3Rpb24gSW50ZXJhY3Rpb24gZXZlbnRzXHJcblx0X2luaXRFdmVudHM6IGZ1bmN0aW9uIChyZW1vdmUkJDEpIHtcclxuXHRcdHRoaXMuX3RhcmdldHMgPSB7fTtcclxuXHRcdHRoaXMuX3RhcmdldHNbc3RhbXAodGhpcy5fY29udGFpbmVyKV0gPSB0aGlzO1xyXG5cclxuXHRcdHZhciBvbk9mZiA9IHJlbW92ZSQkMSA/IG9mZiA6IG9uO1xyXG5cclxuXHRcdC8vIEBldmVudCBjbGljazogTW91c2VFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgdXNlciBjbGlja3MgKG9yIHRhcHMpIHRoZSBtYXAuXHJcblx0XHQvLyBAZXZlbnQgZGJsY2xpY2s6IE1vdXNlRXZlbnRcclxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIHVzZXIgZG91YmxlLWNsaWNrcyAob3IgZG91YmxlLXRhcHMpIHRoZSBtYXAuXHJcblx0XHQvLyBAZXZlbnQgbW91c2Vkb3duOiBNb3VzZUV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSB1c2VyIHB1c2hlcyB0aGUgbW91c2UgYnV0dG9uIG9uIHRoZSBtYXAuXHJcblx0XHQvLyBAZXZlbnQgbW91c2V1cDogTW91c2VFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgdXNlciByZWxlYXNlcyB0aGUgbW91c2UgYnV0dG9uIG9uIHRoZSBtYXAuXHJcblx0XHQvLyBAZXZlbnQgbW91c2VvdmVyOiBNb3VzZUV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSBtb3VzZSBlbnRlcnMgdGhlIG1hcC5cclxuXHRcdC8vIEBldmVudCBtb3VzZW91dDogTW91c2VFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbW91c2UgbGVhdmVzIHRoZSBtYXAuXHJcblx0XHQvLyBAZXZlbnQgbW91c2Vtb3ZlOiBNb3VzZUV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGlsZSB0aGUgbW91c2UgbW92ZXMgb3ZlciB0aGUgbWFwLlxyXG5cdFx0Ly8gQGV2ZW50IGNvbnRleHRtZW51OiBNb3VzZUV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSB1c2VyIHB1c2hlcyB0aGUgcmlnaHQgbW91c2UgYnV0dG9uIG9uIHRoZSBtYXAsIHByZXZlbnRzXHJcblx0XHQvLyBkZWZhdWx0IGJyb3dzZXIgY29udGV4dCBtZW51IGZyb20gc2hvd2luZyBpZiB0aGVyZSBhcmUgbGlzdGVuZXJzIG9uXHJcblx0XHQvLyB0aGlzIGV2ZW50LiBBbHNvIGZpcmVkIG9uIG1vYmlsZSB3aGVuIHRoZSB1c2VyIGhvbGRzIGEgc2luZ2xlIHRvdWNoXHJcblx0XHQvLyBmb3IgYSBzZWNvbmQgKGFsc28gY2FsbGVkIGxvbmcgcHJlc3MpLlxyXG5cdFx0Ly8gQGV2ZW50IGtleXByZXNzOiBLZXlib2FyZEV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSB1c2VyIHByZXNzZXMgYSBrZXkgZnJvbSB0aGUga2V5Ym9hcmQgd2hpbGUgdGhlIG1hcCBpcyBmb2N1c2VkLlxyXG5cdFx0b25PZmYodGhpcy5fY29udGFpbmVyLCAnY2xpY2sgZGJsY2xpY2sgbW91c2Vkb3duIG1vdXNldXAgJyArXHJcblx0XHRcdCdtb3VzZW92ZXIgbW91c2VvdXQgbW91c2Vtb3ZlIGNvbnRleHRtZW51IGtleXByZXNzJywgdGhpcy5faGFuZGxlRE9NRXZlbnQsIHRoaXMpO1xyXG5cclxuXHRcdGlmICh0aGlzLm9wdGlvbnMudHJhY2tSZXNpemUpIHtcclxuXHRcdFx0b25PZmYod2luZG93LCAncmVzaXplJywgdGhpcy5fb25SZXNpemUsIHRoaXMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChhbnkzZCAmJiB0aGlzLm9wdGlvbnMudHJhbnNmb3JtM0RMaW1pdCkge1xyXG5cdFx0XHQocmVtb3ZlJCQxID8gdGhpcy5vZmYgOiB0aGlzLm9uKS5jYWxsKHRoaXMsICdtb3ZlZW5kJywgdGhpcy5fb25Nb3ZlRW5kKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfb25SZXNpemU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGNhbmNlbEFuaW1GcmFtZSh0aGlzLl9yZXNpemVSZXF1ZXN0KTtcclxuXHRcdHRoaXMuX3Jlc2l6ZVJlcXVlc3QgPSByZXF1ZXN0QW5pbUZyYW1lKFxyXG5cdFx0ICAgICAgICBmdW5jdGlvbiAoKSB7IHRoaXMuaW52YWxpZGF0ZVNpemUoe2RlYm91bmNlTW92ZWVuZDogdHJ1ZX0pOyB9LCB0aGlzKTtcclxuXHR9LFxyXG5cclxuXHRfb25TY3JvbGw6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHRoaXMuX2NvbnRhaW5lci5zY3JvbGxUb3AgID0gMDtcclxuXHRcdHRoaXMuX2NvbnRhaW5lci5zY3JvbGxMZWZ0ID0gMDtcclxuXHR9LFxyXG5cclxuXHRfb25Nb3ZlRW5kOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgcG9zID0gdGhpcy5fZ2V0TWFwUGFuZVBvcygpO1xyXG5cdFx0aWYgKE1hdGgubWF4KE1hdGguYWJzKHBvcy54KSwgTWF0aC5hYnMocG9zLnkpKSA+PSB0aGlzLm9wdGlvbnMudHJhbnNmb3JtM0RMaW1pdCkge1xyXG5cdFx0XHQvLyBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD0xMjAzODczIGJ1dCBXZWJraXQgYWxzbyBoYXZlXHJcblx0XHRcdC8vIGEgcGl4ZWwgb2Zmc2V0IG9uIHZlcnkgaGlnaCB2YWx1ZXMsIHNlZTogaHR0cDovL2pzZmlkZGxlLm5ldC9kZzZyNWhoYi9cclxuXHRcdFx0dGhpcy5fcmVzZXRWaWV3KHRoaXMuZ2V0Q2VudGVyKCksIHRoaXMuZ2V0Wm9vbSgpKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfZmluZEV2ZW50VGFyZ2V0czogZnVuY3Rpb24gKGUsIHR5cGUpIHtcclxuXHRcdHZhciB0YXJnZXRzID0gW10sXHJcblx0XHQgICAgdGFyZ2V0LFxyXG5cdFx0ICAgIGlzSG92ZXIgPSB0eXBlID09PSAnbW91c2VvdXQnIHx8IHR5cGUgPT09ICdtb3VzZW92ZXInLFxyXG5cdFx0ICAgIHNyYyA9IGUudGFyZ2V0IHx8IGUuc3JjRWxlbWVudCxcclxuXHRcdCAgICBkcmFnZ2luZyA9IGZhbHNlO1xyXG5cclxuXHRcdHdoaWxlIChzcmMpIHtcclxuXHRcdFx0dGFyZ2V0ID0gdGhpcy5fdGFyZ2V0c1tzdGFtcChzcmMpXTtcclxuXHRcdFx0aWYgKHRhcmdldCAmJiAodHlwZSA9PT0gJ2NsaWNrJyB8fCB0eXBlID09PSAncHJlY2xpY2snKSAmJiAhZS5fc2ltdWxhdGVkICYmIHRoaXMuX2RyYWdnYWJsZU1vdmVkKHRhcmdldCkpIHtcclxuXHRcdFx0XHQvLyBQcmV2ZW50IGZpcmluZyBjbGljayBhZnRlciB5b3UganVzdCBkcmFnZ2VkIGFuIG9iamVjdC5cclxuXHRcdFx0XHRkcmFnZ2luZyA9IHRydWU7XHJcblx0XHRcdFx0YnJlYWs7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKHRhcmdldCAmJiB0YXJnZXQubGlzdGVucyh0eXBlLCB0cnVlKSkge1xyXG5cdFx0XHRcdGlmIChpc0hvdmVyICYmICFpc0V4dGVybmFsVGFyZ2V0KHNyYywgZSkpIHsgYnJlYWs7IH1cclxuXHRcdFx0XHR0YXJnZXRzLnB1c2godGFyZ2V0KTtcclxuXHRcdFx0XHRpZiAoaXNIb3ZlcikgeyBicmVhazsgfVxyXG5cdFx0XHR9XHJcblx0XHRcdGlmIChzcmMgPT09IHRoaXMuX2NvbnRhaW5lcikgeyBicmVhazsgfVxyXG5cdFx0XHRzcmMgPSBzcmMucGFyZW50Tm9kZTtcclxuXHRcdH1cclxuXHRcdGlmICghdGFyZ2V0cy5sZW5ndGggJiYgIWRyYWdnaW5nICYmICFpc0hvdmVyICYmIGlzRXh0ZXJuYWxUYXJnZXQoc3JjLCBlKSkge1xyXG5cdFx0XHR0YXJnZXRzID0gW3RoaXNdO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRhcmdldHM7XHJcblx0fSxcclxuXHJcblx0X2hhbmRsZURPTUV2ZW50OiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0aWYgKCF0aGlzLl9sb2FkZWQgfHwgc2tpcHBlZChlKSkgeyByZXR1cm47IH1cclxuXHJcblx0XHR2YXIgdHlwZSA9IGUudHlwZTtcclxuXHJcblx0XHRpZiAodHlwZSA9PT0gJ21vdXNlZG93bicgfHwgdHlwZSA9PT0gJ2tleXByZXNzJykge1xyXG5cdFx0XHQvLyBwcmV2ZW50cyBvdXRsaW5lIHdoZW4gY2xpY2tpbmcgb24ga2V5Ym9hcmQtZm9jdXNhYmxlIGVsZW1lbnRcclxuXHRcdFx0cHJldmVudE91dGxpbmUoZS50YXJnZXQgfHwgZS5zcmNFbGVtZW50KTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9maXJlRE9NRXZlbnQoZSwgdHlwZSk7XHJcblx0fSxcclxuXHJcblx0X21vdXNlRXZlbnRzOiBbJ2NsaWNrJywgJ2RibGNsaWNrJywgJ21vdXNlb3ZlcicsICdtb3VzZW91dCcsICdjb250ZXh0bWVudSddLFxyXG5cclxuXHRfZmlyZURPTUV2ZW50OiBmdW5jdGlvbiAoZSwgdHlwZSwgdGFyZ2V0cykge1xyXG5cclxuXHRcdGlmIChlLnR5cGUgPT09ICdjbGljaycpIHtcclxuXHRcdFx0Ly8gRmlyZSBhIHN5bnRoZXRpYyAncHJlY2xpY2snIGV2ZW50IHdoaWNoIHByb3BhZ2F0ZXMgdXAgKG1haW5seSBmb3IgY2xvc2luZyBwb3B1cHMpLlxyXG5cdFx0XHQvLyBAZXZlbnQgcHJlY2xpY2s6IE1vdXNlRXZlbnRcclxuXHRcdFx0Ly8gRmlyZWQgYmVmb3JlIG1vdXNlIGNsaWNrIG9uIHRoZSBtYXAgKHNvbWV0aW1lcyB1c2VmdWwgd2hlbiB5b3VcclxuXHRcdFx0Ly8gd2FudCBzb21ldGhpbmcgdG8gaGFwcGVuIG9uIGNsaWNrIGJlZm9yZSBhbnkgZXhpc3RpbmcgY2xpY2tcclxuXHRcdFx0Ly8gaGFuZGxlcnMgc3RhcnQgcnVubmluZykuXHJcblx0XHRcdHZhciBzeW50aCA9IGV4dGVuZCh7fSwgZSk7XHJcblx0XHRcdHN5bnRoLnR5cGUgPSAncHJlY2xpY2snO1xyXG5cdFx0XHR0aGlzLl9maXJlRE9NRXZlbnQoc3ludGgsIHN5bnRoLnR5cGUsIHRhcmdldHMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChlLl9zdG9wcGVkKSB7IHJldHVybjsgfVxyXG5cclxuXHRcdC8vIEZpbmQgdGhlIGxheWVyIHRoZSBldmVudCBpcyBwcm9wYWdhdGluZyBmcm9tIGFuZCBpdHMgcGFyZW50cy5cclxuXHRcdHRhcmdldHMgPSAodGFyZ2V0cyB8fCBbXSkuY29uY2F0KHRoaXMuX2ZpbmRFdmVudFRhcmdldHMoZSwgdHlwZSkpO1xyXG5cclxuXHRcdGlmICghdGFyZ2V0cy5sZW5ndGgpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0dmFyIHRhcmdldCA9IHRhcmdldHNbMF07XHJcblx0XHRpZiAodHlwZSA9PT0gJ2NvbnRleHRtZW51JyAmJiB0YXJnZXQubGlzdGVucyh0eXBlLCB0cnVlKSkge1xyXG5cdFx0XHRwcmV2ZW50RGVmYXVsdChlKTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgZGF0YSA9IHtcclxuXHRcdFx0b3JpZ2luYWxFdmVudDogZVxyXG5cdFx0fTtcclxuXHJcblx0XHRpZiAoZS50eXBlICE9PSAna2V5cHJlc3MnKSB7XHJcblx0XHRcdHZhciBpc01hcmtlciA9IHRhcmdldC5nZXRMYXRMbmcgJiYgKCF0YXJnZXQuX3JhZGl1cyB8fCB0YXJnZXQuX3JhZGl1cyA8PSAxMCk7XHJcblx0XHRcdGRhdGEuY29udGFpbmVyUG9pbnQgPSBpc01hcmtlciA/XHJcblx0XHRcdFx0dGhpcy5sYXRMbmdUb0NvbnRhaW5lclBvaW50KHRhcmdldC5nZXRMYXRMbmcoKSkgOiB0aGlzLm1vdXNlRXZlbnRUb0NvbnRhaW5lclBvaW50KGUpO1xyXG5cdFx0XHRkYXRhLmxheWVyUG9pbnQgPSB0aGlzLmNvbnRhaW5lclBvaW50VG9MYXllclBvaW50KGRhdGEuY29udGFpbmVyUG9pbnQpO1xyXG5cdFx0XHRkYXRhLmxhdGxuZyA9IGlzTWFya2VyID8gdGFyZ2V0LmdldExhdExuZygpIDogdGhpcy5sYXllclBvaW50VG9MYXRMbmcoZGF0YS5sYXllclBvaW50KTtcclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHRhcmdldHMubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0dGFyZ2V0c1tpXS5maXJlKHR5cGUsIGRhdGEsIHRydWUpO1xyXG5cdFx0XHRpZiAoZGF0YS5vcmlnaW5hbEV2ZW50Ll9zdG9wcGVkIHx8XHJcblx0XHRcdFx0KHRhcmdldHNbaV0ub3B0aW9ucy5idWJibGluZ01vdXNlRXZlbnRzID09PSBmYWxzZSAmJiBpbmRleE9mKHRoaXMuX21vdXNlRXZlbnRzLCB0eXBlKSAhPT0gLTEpKSB7IHJldHVybjsgfVxyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdF9kcmFnZ2FibGVNb3ZlZDogZnVuY3Rpb24gKG9iaikge1xyXG5cdFx0b2JqID0gb2JqLmRyYWdnaW5nICYmIG9iai5kcmFnZ2luZy5lbmFibGVkKCkgPyBvYmogOiB0aGlzO1xyXG5cdFx0cmV0dXJuIChvYmouZHJhZ2dpbmcgJiYgb2JqLmRyYWdnaW5nLm1vdmVkKCkpIHx8ICh0aGlzLmJveFpvb20gJiYgdGhpcy5ib3hab29tLm1vdmVkKCkpO1xyXG5cdH0sXHJcblxyXG5cdF9jbGVhckhhbmRsZXJzOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRmb3IgKHZhciBpID0gMCwgbGVuID0gdGhpcy5faGFuZGxlcnMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdFx0dGhpcy5faGFuZGxlcnNbaV0uZGlzYWJsZSgpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBzZWN0aW9uIE90aGVyIE1ldGhvZHNcclxuXHJcblx0Ly8gQG1ldGhvZCB3aGVuUmVhZHkoZm46IEZ1bmN0aW9uLCBjb250ZXh0PzogT2JqZWN0KTogdGhpc1xyXG5cdC8vIFJ1bnMgdGhlIGdpdmVuIGZ1bmN0aW9uIGBmbmAgd2hlbiB0aGUgbWFwIGdldHMgaW5pdGlhbGl6ZWQgd2l0aFxyXG5cdC8vIGEgdmlldyAoY2VudGVyIGFuZCB6b29tKSBhbmQgYXQgbGVhc3Qgb25lIGxheWVyLCBvciBpbW1lZGlhdGVseVxyXG5cdC8vIGlmIGl0J3MgYWxyZWFkeSBpbml0aWFsaXplZCwgb3B0aW9uYWxseSBwYXNzaW5nIGEgZnVuY3Rpb24gY29udGV4dC5cclxuXHR3aGVuUmVhZHk6IGZ1bmN0aW9uIChjYWxsYmFjaywgY29udGV4dCkge1xyXG5cdFx0aWYgKHRoaXMuX2xvYWRlZCkge1xyXG5cdFx0XHRjYWxsYmFjay5jYWxsKGNvbnRleHQgfHwgdGhpcywge3RhcmdldDogdGhpc30pO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0dGhpcy5vbignbG9hZCcsIGNhbGxiYWNrLCBjb250ZXh0KTtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cclxuXHQvLyBwcml2YXRlIG1ldGhvZHMgZm9yIGdldHRpbmcgbWFwIHN0YXRlXHJcblxyXG5cdF9nZXRNYXBQYW5lUG9zOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gZ2V0UG9zaXRpb24odGhpcy5fbWFwUGFuZSkgfHwgbmV3IFBvaW50KDAsIDApO1xyXG5cdH0sXHJcblxyXG5cdF9tb3ZlZDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIHBvcyA9IHRoaXMuX2dldE1hcFBhbmVQb3MoKTtcclxuXHRcdHJldHVybiBwb3MgJiYgIXBvcy5lcXVhbHMoWzAsIDBdKTtcclxuXHR9LFxyXG5cclxuXHRfZ2V0VG9wTGVmdFBvaW50OiBmdW5jdGlvbiAoY2VudGVyLCB6b29tKSB7XHJcblx0XHR2YXIgcGl4ZWxPcmlnaW4gPSBjZW50ZXIgJiYgem9vbSAhPT0gdW5kZWZpbmVkID9cclxuXHRcdFx0dGhpcy5fZ2V0TmV3UGl4ZWxPcmlnaW4oY2VudGVyLCB6b29tKSA6XHJcblx0XHRcdHRoaXMuZ2V0UGl4ZWxPcmlnaW4oKTtcclxuXHRcdHJldHVybiBwaXhlbE9yaWdpbi5zdWJ0cmFjdCh0aGlzLl9nZXRNYXBQYW5lUG9zKCkpO1xyXG5cdH0sXHJcblxyXG5cdF9nZXROZXdQaXhlbE9yaWdpbjogZnVuY3Rpb24gKGNlbnRlciwgem9vbSkge1xyXG5cdFx0dmFyIHZpZXdIYWxmID0gdGhpcy5nZXRTaXplKCkuX2RpdmlkZUJ5KDIpO1xyXG5cdFx0cmV0dXJuIHRoaXMucHJvamVjdChjZW50ZXIsIHpvb20pLl9zdWJ0cmFjdCh2aWV3SGFsZikuX2FkZCh0aGlzLl9nZXRNYXBQYW5lUG9zKCkpLl9yb3VuZCgpO1xyXG5cdH0sXHJcblxyXG5cdF9sYXRMbmdUb05ld0xheWVyUG9pbnQ6IGZ1bmN0aW9uIChsYXRsbmcsIHpvb20sIGNlbnRlcikge1xyXG5cdFx0dmFyIHRvcExlZnQgPSB0aGlzLl9nZXROZXdQaXhlbE9yaWdpbihjZW50ZXIsIHpvb20pO1xyXG5cdFx0cmV0dXJuIHRoaXMucHJvamVjdChsYXRsbmcsIHpvb20pLl9zdWJ0cmFjdCh0b3BMZWZ0KTtcclxuXHR9LFxyXG5cclxuXHRfbGF0TG5nQm91bmRzVG9OZXdMYXllckJvdW5kczogZnVuY3Rpb24gKGxhdExuZ0JvdW5kcywgem9vbSwgY2VudGVyKSB7XHJcblx0XHR2YXIgdG9wTGVmdCA9IHRoaXMuX2dldE5ld1BpeGVsT3JpZ2luKGNlbnRlciwgem9vbSk7XHJcblx0XHRyZXR1cm4gdG9Cb3VuZHMoW1xyXG5cdFx0XHR0aGlzLnByb2plY3QobGF0TG5nQm91bmRzLmdldFNvdXRoV2VzdCgpLCB6b29tKS5fc3VidHJhY3QodG9wTGVmdCksXHJcblx0XHRcdHRoaXMucHJvamVjdChsYXRMbmdCb3VuZHMuZ2V0Tm9ydGhXZXN0KCksIHpvb20pLl9zdWJ0cmFjdCh0b3BMZWZ0KSxcclxuXHRcdFx0dGhpcy5wcm9qZWN0KGxhdExuZ0JvdW5kcy5nZXRTb3V0aEVhc3QoKSwgem9vbSkuX3N1YnRyYWN0KHRvcExlZnQpLFxyXG5cdFx0XHR0aGlzLnByb2plY3QobGF0TG5nQm91bmRzLmdldE5vcnRoRWFzdCgpLCB6b29tKS5fc3VidHJhY3QodG9wTGVmdClcclxuXHRcdF0pO1xyXG5cdH0sXHJcblxyXG5cdC8vIGxheWVyIHBvaW50IG9mIHRoZSBjdXJyZW50IGNlbnRlclxyXG5cdF9nZXRDZW50ZXJMYXllclBvaW50OiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5jb250YWluZXJQb2ludFRvTGF5ZXJQb2ludCh0aGlzLmdldFNpemUoKS5fZGl2aWRlQnkoMikpO1xyXG5cdH0sXHJcblxyXG5cdC8vIG9mZnNldCBvZiB0aGUgc3BlY2lmaWVkIHBsYWNlIHRvIHRoZSBjdXJyZW50IGNlbnRlciBpbiBwaXhlbHNcclxuXHRfZ2V0Q2VudGVyT2Zmc2V0OiBmdW5jdGlvbiAobGF0bG5nKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5sYXRMbmdUb0xheWVyUG9pbnQobGF0bG5nKS5zdWJ0cmFjdCh0aGlzLl9nZXRDZW50ZXJMYXllclBvaW50KCkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIGFkanVzdCBjZW50ZXIgZm9yIHZpZXcgdG8gZ2V0IGluc2lkZSBib3VuZHNcclxuXHRfbGltaXRDZW50ZXI6IGZ1bmN0aW9uIChjZW50ZXIsIHpvb20sIGJvdW5kcykge1xyXG5cclxuXHRcdGlmICghYm91bmRzKSB7IHJldHVybiBjZW50ZXI7IH1cclxuXHJcblx0XHR2YXIgY2VudGVyUG9pbnQgPSB0aGlzLnByb2plY3QoY2VudGVyLCB6b29tKSxcclxuXHRcdCAgICB2aWV3SGFsZiA9IHRoaXMuZ2V0U2l6ZSgpLmRpdmlkZUJ5KDIpLFxyXG5cdFx0ICAgIHZpZXdCb3VuZHMgPSBuZXcgQm91bmRzKGNlbnRlclBvaW50LnN1YnRyYWN0KHZpZXdIYWxmKSwgY2VudGVyUG9pbnQuYWRkKHZpZXdIYWxmKSksXHJcblx0XHQgICAgb2Zmc2V0ID0gdGhpcy5fZ2V0Qm91bmRzT2Zmc2V0KHZpZXdCb3VuZHMsIGJvdW5kcywgem9vbSk7XHJcblxyXG5cdFx0Ly8gSWYgb2Zmc2V0IGlzIGxlc3MgdGhhbiBhIHBpeGVsLCBpZ25vcmUuXHJcblx0XHQvLyBUaGlzIHByZXZlbnRzIHVuc3RhYmxlIHByb2plY3Rpb25zIGZyb20gZ2V0dGluZyBpbnRvXHJcblx0XHQvLyBhbiBpbmZpbml0ZSBsb29wIG9mIHRpbnkgb2Zmc2V0cy5cclxuXHRcdGlmIChvZmZzZXQucm91bmQoKS5lcXVhbHMoWzAsIDBdKSkge1xyXG5cdFx0XHRyZXR1cm4gY2VudGVyO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzLnVucHJvamVjdChjZW50ZXJQb2ludC5hZGQob2Zmc2V0KSwgem9vbSk7XHJcblx0fSxcclxuXHJcblx0Ly8gYWRqdXN0IG9mZnNldCBmb3IgdmlldyB0byBnZXQgaW5zaWRlIGJvdW5kc1xyXG5cdF9saW1pdE9mZnNldDogZnVuY3Rpb24gKG9mZnNldCwgYm91bmRzKSB7XHJcblx0XHRpZiAoIWJvdW5kcykgeyByZXR1cm4gb2Zmc2V0OyB9XHJcblxyXG5cdFx0dmFyIHZpZXdCb3VuZHMgPSB0aGlzLmdldFBpeGVsQm91bmRzKCksXHJcblx0XHQgICAgbmV3Qm91bmRzID0gbmV3IEJvdW5kcyh2aWV3Qm91bmRzLm1pbi5hZGQob2Zmc2V0KSwgdmlld0JvdW5kcy5tYXguYWRkKG9mZnNldCkpO1xyXG5cclxuXHRcdHJldHVybiBvZmZzZXQuYWRkKHRoaXMuX2dldEJvdW5kc09mZnNldChuZXdCb3VuZHMsIGJvdW5kcykpO1xyXG5cdH0sXHJcblxyXG5cdC8vIHJldHVybnMgb2Zmc2V0IG5lZWRlZCBmb3IgcHhCb3VuZHMgdG8gZ2V0IGluc2lkZSBtYXhCb3VuZHMgYXQgYSBzcGVjaWZpZWQgem9vbVxyXG5cdF9nZXRCb3VuZHNPZmZzZXQ6IGZ1bmN0aW9uIChweEJvdW5kcywgbWF4Qm91bmRzLCB6b29tKSB7XHJcblx0XHR2YXIgcHJvamVjdGVkTWF4Qm91bmRzID0gdG9Cb3VuZHMoXHJcblx0XHQgICAgICAgIHRoaXMucHJvamVjdChtYXhCb3VuZHMuZ2V0Tm9ydGhFYXN0KCksIHpvb20pLFxyXG5cdFx0ICAgICAgICB0aGlzLnByb2plY3QobWF4Qm91bmRzLmdldFNvdXRoV2VzdCgpLCB6b29tKVxyXG5cdFx0ICAgICksXHJcblx0XHQgICAgbWluT2Zmc2V0ID0gcHJvamVjdGVkTWF4Qm91bmRzLm1pbi5zdWJ0cmFjdChweEJvdW5kcy5taW4pLFxyXG5cdFx0ICAgIG1heE9mZnNldCA9IHByb2plY3RlZE1heEJvdW5kcy5tYXguc3VidHJhY3QocHhCb3VuZHMubWF4KSxcclxuXHJcblx0XHQgICAgZHggPSB0aGlzLl9yZWJvdW5kKG1pbk9mZnNldC54LCAtbWF4T2Zmc2V0LngpLFxyXG5cdFx0ICAgIGR5ID0gdGhpcy5fcmVib3VuZChtaW5PZmZzZXQueSwgLW1heE9mZnNldC55KTtcclxuXHJcblx0XHRyZXR1cm4gbmV3IFBvaW50KGR4LCBkeSk7XHJcblx0fSxcclxuXHJcblx0X3JlYm91bmQ6IGZ1bmN0aW9uIChsZWZ0LCByaWdodCkge1xyXG5cdFx0cmV0dXJuIGxlZnQgKyByaWdodCA+IDAgP1xyXG5cdFx0XHRNYXRoLnJvdW5kKGxlZnQgLSByaWdodCkgLyAyIDpcclxuXHRcdFx0TWF0aC5tYXgoMCwgTWF0aC5jZWlsKGxlZnQpKSAtIE1hdGgubWF4KDAsIE1hdGguZmxvb3IocmlnaHQpKTtcclxuXHR9LFxyXG5cclxuXHRfbGltaXRab29tOiBmdW5jdGlvbiAoem9vbSkge1xyXG5cdFx0dmFyIG1pbiA9IHRoaXMuZ2V0TWluWm9vbSgpLFxyXG5cdFx0ICAgIG1heCA9IHRoaXMuZ2V0TWF4Wm9vbSgpLFxyXG5cdFx0ICAgIHNuYXAgPSBhbnkzZCA/IHRoaXMub3B0aW9ucy56b29tU25hcCA6IDE7XHJcblx0XHRpZiAoc25hcCkge1xyXG5cdFx0XHR6b29tID0gTWF0aC5yb3VuZCh6b29tIC8gc25hcCkgKiBzbmFwO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIE1hdGgubWF4KG1pbiwgTWF0aC5taW4obWF4LCB6b29tKSk7XHJcblx0fSxcclxuXHJcblx0X29uUGFuVHJhbnNpdGlvblN0ZXA6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHRoaXMuZmlyZSgnbW92ZScpO1xyXG5cdH0sXHJcblxyXG5cdF9vblBhblRyYW5zaXRpb25FbmQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJlbW92ZUNsYXNzKHRoaXMuX21hcFBhbmUsICdsZWFmbGV0LXBhbi1hbmltJyk7XHJcblx0XHR0aGlzLmZpcmUoJ21vdmVlbmQnKTtcclxuXHR9LFxyXG5cclxuXHRfdHJ5QW5pbWF0ZWRQYW46IGZ1bmN0aW9uIChjZW50ZXIsIG9wdGlvbnMpIHtcclxuXHRcdC8vIGRpZmZlcmVuY2UgYmV0d2VlbiB0aGUgbmV3IGFuZCBjdXJyZW50IGNlbnRlcnMgaW4gcGl4ZWxzXHJcblx0XHR2YXIgb2Zmc2V0ID0gdGhpcy5fZ2V0Q2VudGVyT2Zmc2V0KGNlbnRlcikuX3RydW5jKCk7XHJcblxyXG5cdFx0Ly8gZG9uJ3QgYW5pbWF0ZSB0b28gZmFyIHVubGVzcyBhbmltYXRlOiB0cnVlIHNwZWNpZmllZCBpbiBvcHRpb25zXHJcblx0XHRpZiAoKG9wdGlvbnMgJiYgb3B0aW9ucy5hbmltYXRlKSAhPT0gdHJ1ZSAmJiAhdGhpcy5nZXRTaXplKCkuY29udGFpbnMob2Zmc2V0KSkgeyByZXR1cm4gZmFsc2U7IH1cclxuXHJcblx0XHR0aGlzLnBhbkJ5KG9mZnNldCwgb3B0aW9ucyk7XHJcblxyXG5cdFx0cmV0dXJuIHRydWU7XHJcblx0fSxcclxuXHJcblx0X2NyZWF0ZUFuaW1Qcm94eTogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdHZhciBwcm94eSA9IHRoaXMuX3Byb3h5ID0gY3JlYXRlJDEoJ2RpdicsICdsZWFmbGV0LXByb3h5IGxlYWZsZXQtem9vbS1hbmltYXRlZCcpO1xyXG5cdFx0dGhpcy5fcGFuZXMubWFwUGFuZS5hcHBlbmRDaGlsZChwcm94eSk7XHJcblxyXG5cdFx0dGhpcy5vbignem9vbWFuaW0nLCBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHR2YXIgcHJvcCA9IFRSQU5TRk9STSxcclxuXHRcdFx0ICAgIHRyYW5zZm9ybSA9IHRoaXMuX3Byb3h5LnN0eWxlW3Byb3BdO1xyXG5cclxuXHRcdFx0c2V0VHJhbnNmb3JtKHRoaXMuX3Byb3h5LCB0aGlzLnByb2plY3QoZS5jZW50ZXIsIGUuem9vbSksIHRoaXMuZ2V0Wm9vbVNjYWxlKGUuem9vbSwgMSkpO1xyXG5cclxuXHRcdFx0Ly8gd29ya2Fyb3VuZCBmb3IgY2FzZSB3aGVuIHRyYW5zZm9ybSBpcyB0aGUgc2FtZSBhbmQgc28gdHJhbnNpdGlvbmVuZCBldmVudCBpcyBub3QgZmlyZWRcclxuXHRcdFx0aWYgKHRyYW5zZm9ybSA9PT0gdGhpcy5fcHJveHkuc3R5bGVbcHJvcF0gJiYgdGhpcy5fYW5pbWF0aW5nWm9vbSkge1xyXG5cdFx0XHRcdHRoaXMuX29uWm9vbVRyYW5zaXRpb25FbmQoKTtcclxuXHRcdFx0fVxyXG5cdFx0fSwgdGhpcyk7XHJcblxyXG5cdFx0dGhpcy5vbignbG9hZCBtb3ZlZW5kJywgZnVuY3Rpb24gKCkge1xyXG5cdFx0XHR2YXIgYyA9IHRoaXMuZ2V0Q2VudGVyKCksXHJcblx0XHRcdCAgICB6ID0gdGhpcy5nZXRab29tKCk7XHJcblx0XHRcdHNldFRyYW5zZm9ybSh0aGlzLl9wcm94eSwgdGhpcy5wcm9qZWN0KGMsIHopLCB0aGlzLmdldFpvb21TY2FsZSh6LCAxKSk7XHJcblx0XHR9LCB0aGlzKTtcclxuXHJcblx0XHR0aGlzLl9vbigndW5sb2FkJywgdGhpcy5fZGVzdHJveUFuaW1Qcm94eSwgdGhpcyk7XHJcblx0fSxcclxuXHJcblx0X2Rlc3Ryb3lBbmltUHJveHk6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJlbW92ZSh0aGlzLl9wcm94eSk7XHJcblx0XHRkZWxldGUgdGhpcy5fcHJveHk7XHJcblx0fSxcclxuXHJcblx0X2NhdGNoVHJhbnNpdGlvbkVuZDogZnVuY3Rpb24gKGUpIHtcclxuXHRcdGlmICh0aGlzLl9hbmltYXRpbmdab29tICYmIGUucHJvcGVydHlOYW1lLmluZGV4T2YoJ3RyYW5zZm9ybScpID49IDApIHtcclxuXHRcdFx0dGhpcy5fb25ab29tVHJhbnNpdGlvbkVuZCgpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdF9ub3RoaW5nVG9BbmltYXRlOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gIXRoaXMuX2NvbnRhaW5lci5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCdsZWFmbGV0LXpvb20tYW5pbWF0ZWQnKS5sZW5ndGg7XHJcblx0fSxcclxuXHJcblx0X3RyeUFuaW1hdGVkWm9vbTogZnVuY3Rpb24gKGNlbnRlciwgem9vbSwgb3B0aW9ucykge1xyXG5cclxuXHRcdGlmICh0aGlzLl9hbmltYXRpbmdab29tKSB7IHJldHVybiB0cnVlOyB9XHJcblxyXG5cdFx0b3B0aW9ucyA9IG9wdGlvbnMgfHwge307XHJcblxyXG5cdFx0Ly8gZG9uJ3QgYW5pbWF0ZSBpZiBkaXNhYmxlZCwgbm90IHN1cHBvcnRlZCBvciB6b29tIGRpZmZlcmVuY2UgaXMgdG9vIGxhcmdlXHJcblx0XHRpZiAoIXRoaXMuX3pvb21BbmltYXRlZCB8fCBvcHRpb25zLmFuaW1hdGUgPT09IGZhbHNlIHx8IHRoaXMuX25vdGhpbmdUb0FuaW1hdGUoKSB8fFxyXG5cdFx0ICAgICAgICBNYXRoLmFicyh6b29tIC0gdGhpcy5fem9vbSkgPiB0aGlzLm9wdGlvbnMuem9vbUFuaW1hdGlvblRocmVzaG9sZCkgeyByZXR1cm4gZmFsc2U7IH1cclxuXHJcblx0XHQvLyBvZmZzZXQgaXMgdGhlIHBpeGVsIGNvb3JkcyBvZiB0aGUgem9vbSBvcmlnaW4gcmVsYXRpdmUgdG8gdGhlIGN1cnJlbnQgY2VudGVyXHJcblx0XHR2YXIgc2NhbGUgPSB0aGlzLmdldFpvb21TY2FsZSh6b29tKSxcclxuXHRcdCAgICBvZmZzZXQgPSB0aGlzLl9nZXRDZW50ZXJPZmZzZXQoY2VudGVyKS5fZGl2aWRlQnkoMSAtIDEgLyBzY2FsZSk7XHJcblxyXG5cdFx0Ly8gZG9uJ3QgYW5pbWF0ZSBpZiB0aGUgem9vbSBvcmlnaW4gaXNuJ3Qgd2l0aGluIG9uZSBzY3JlZW4gZnJvbSB0aGUgY3VycmVudCBjZW50ZXIsIHVubGVzcyBmb3JjZWRcclxuXHRcdGlmIChvcHRpb25zLmFuaW1hdGUgIT09IHRydWUgJiYgIXRoaXMuZ2V0U2l6ZSgpLmNvbnRhaW5zKG9mZnNldCkpIHsgcmV0dXJuIGZhbHNlOyB9XHJcblxyXG5cdFx0cmVxdWVzdEFuaW1GcmFtZShmdW5jdGlvbiAoKSB7XHJcblx0XHRcdHRoaXNcclxuXHRcdFx0ICAgIC5fbW92ZVN0YXJ0KHRydWUsIGZhbHNlKVxyXG5cdFx0XHQgICAgLl9hbmltYXRlWm9vbShjZW50ZXIsIHpvb20sIHRydWUpO1xyXG5cdFx0fSwgdGhpcyk7XHJcblxyXG5cdFx0cmV0dXJuIHRydWU7XHJcblx0fSxcclxuXHJcblx0X2FuaW1hdGVab29tOiBmdW5jdGlvbiAoY2VudGVyLCB6b29tLCBzdGFydEFuaW0sIG5vVXBkYXRlKSB7XHJcblx0XHRpZiAoIXRoaXMuX21hcFBhbmUpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0aWYgKHN0YXJ0QW5pbSkge1xyXG5cdFx0XHR0aGlzLl9hbmltYXRpbmdab29tID0gdHJ1ZTtcclxuXHJcblx0XHRcdC8vIHJlbWVtYmVyIHdoYXQgY2VudGVyL3pvb20gdG8gc2V0IGFmdGVyIGFuaW1hdGlvblxyXG5cdFx0XHR0aGlzLl9hbmltYXRlVG9DZW50ZXIgPSBjZW50ZXI7XHJcblx0XHRcdHRoaXMuX2FuaW1hdGVUb1pvb20gPSB6b29tO1xyXG5cclxuXHRcdFx0YWRkQ2xhc3ModGhpcy5fbWFwUGFuZSwgJ2xlYWZsZXQtem9vbS1hbmltJyk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQGV2ZW50IHpvb21hbmltOiBab29tQW5pbUV2ZW50XHJcblx0XHQvLyBGaXJlZCBvbiBldmVyeSBmcmFtZSBvZiBhIHpvb20gYW5pbWF0aW9uXHJcblx0XHR0aGlzLmZpcmUoJ3pvb21hbmltJywge1xyXG5cdFx0XHRjZW50ZXI6IGNlbnRlcixcclxuXHRcdFx0em9vbTogem9vbSxcclxuXHRcdFx0bm9VcGRhdGU6IG5vVXBkYXRlXHJcblx0XHR9KTtcclxuXHJcblx0XHQvLyBXb3JrIGFyb3VuZCB3ZWJraXQgbm90IGZpcmluZyAndHJhbnNpdGlvbmVuZCcsIHNlZSBodHRwczovL2dpdGh1Yi5jb20vTGVhZmxldC9MZWFmbGV0L2lzc3Vlcy8zNjg5LCAyNjkzXHJcblx0XHRzZXRUaW1lb3V0KGJpbmQodGhpcy5fb25ab29tVHJhbnNpdGlvbkVuZCwgdGhpcyksIDI1MCk7XHJcblx0fSxcclxuXHJcblx0X29uWm9vbVRyYW5zaXRpb25FbmQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICghdGhpcy5fYW5pbWF0aW5nWm9vbSkgeyByZXR1cm47IH1cclxuXHJcblx0XHRpZiAodGhpcy5fbWFwUGFuZSkge1xyXG5cdFx0XHRyZW1vdmVDbGFzcyh0aGlzLl9tYXBQYW5lLCAnbGVhZmxldC16b29tLWFuaW0nKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9hbmltYXRpbmdab29tID0gZmFsc2U7XHJcblxyXG5cdFx0dGhpcy5fbW92ZSh0aGlzLl9hbmltYXRlVG9DZW50ZXIsIHRoaXMuX2FuaW1hdGVUb1pvb20pO1xyXG5cclxuXHRcdC8vIFRoaXMgYW5pbSBmcmFtZSBzaG91bGQgcHJldmVudCBhbiBvYnNjdXJlIGlPUyB3ZWJraXQgdGlsZSBsb2FkaW5nIHJhY2UgY29uZGl0aW9uLlxyXG5cdFx0cmVxdWVzdEFuaW1GcmFtZShmdW5jdGlvbiAoKSB7XHJcblx0XHRcdHRoaXMuX21vdmVFbmQodHJ1ZSk7XHJcblx0XHR9LCB0aGlzKTtcclxuXHR9XHJcbn0pO1xyXG5cclxuLy8gQHNlY3Rpb25cclxuXHJcbi8vIEBmYWN0b3J5IEwubWFwKGlkOiBTdHJpbmcsIG9wdGlvbnM/OiBNYXAgb3B0aW9ucylcclxuLy8gSW5zdGFudGlhdGVzIGEgbWFwIG9iamVjdCBnaXZlbiB0aGUgRE9NIElEIG9mIGEgYDxkaXY+YCBlbGVtZW50XHJcbi8vIGFuZCBvcHRpb25hbGx5IGFuIG9iamVjdCBsaXRlcmFsIHdpdGggYE1hcCBvcHRpb25zYC5cclxuLy9cclxuLy8gQGFsdGVybmF0aXZlXHJcbi8vIEBmYWN0b3J5IEwubWFwKGVsOiBIVE1MRWxlbWVudCwgb3B0aW9ucz86IE1hcCBvcHRpb25zKVxyXG4vLyBJbnN0YW50aWF0ZXMgYSBtYXAgb2JqZWN0IGdpdmVuIGFuIGluc3RhbmNlIG9mIGEgYDxkaXY+YCBIVE1MIGVsZW1lbnRcclxuLy8gYW5kIG9wdGlvbmFsbHkgYW4gb2JqZWN0IGxpdGVyYWwgd2l0aCBgTWFwIG9wdGlvbnNgLlxyXG5mdW5jdGlvbiBjcmVhdGVNYXAoaWQsIG9wdGlvbnMpIHtcclxuXHRyZXR1cm4gbmV3IE1hcChpZCwgb3B0aW9ucyk7XHJcbn1cblxuLypcclxuICogQGNsYXNzIENvbnRyb2xcclxuICogQGFrYSBMLkNvbnRyb2xcclxuICogQGluaGVyaXRzIENsYXNzXHJcbiAqXHJcbiAqIEwuQ29udHJvbCBpcyBhIGJhc2UgY2xhc3MgZm9yIGltcGxlbWVudGluZyBtYXAgY29udHJvbHMuIEhhbmRsZXMgcG9zaXRpb25pbmcuXHJcbiAqIEFsbCBvdGhlciBjb250cm9scyBleHRlbmQgZnJvbSB0aGlzIGNsYXNzLlxyXG4gKi9cclxuXHJcbnZhciBDb250cm9sID0gQ2xhc3MuZXh0ZW5kKHtcclxuXHQvLyBAc2VjdGlvblxyXG5cdC8vIEBha2EgQ29udHJvbCBvcHRpb25zXHJcblx0b3B0aW9uczoge1xyXG5cdFx0Ly8gQG9wdGlvbiBwb3NpdGlvbjogU3RyaW5nID0gJ3RvcHJpZ2h0J1xyXG5cdFx0Ly8gVGhlIHBvc2l0aW9uIG9mIHRoZSBjb250cm9sIChvbmUgb2YgdGhlIG1hcCBjb3JuZXJzKS4gUG9zc2libGUgdmFsdWVzIGFyZSBgJ3RvcGxlZnQnYCxcclxuXHRcdC8vIGAndG9wcmlnaHQnYCwgYCdib3R0b21sZWZ0J2Agb3IgYCdib3R0b21yaWdodCdgXHJcblx0XHRwb3NpdGlvbjogJ3RvcHJpZ2h0J1xyXG5cdH0sXHJcblxyXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XHJcblx0XHRzZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xyXG5cdH0sXHJcblxyXG5cdC8qIEBzZWN0aW9uXHJcblx0ICogQ2xhc3NlcyBleHRlbmRpbmcgTC5Db250cm9sIHdpbGwgaW5oZXJpdCB0aGUgZm9sbG93aW5nIG1ldGhvZHM6XHJcblx0ICpcclxuXHQgKiBAbWV0aG9kIGdldFBvc2l0aW9uOiBzdHJpbmdcclxuXHQgKiBSZXR1cm5zIHRoZSBwb3NpdGlvbiBvZiB0aGUgY29udHJvbC5cclxuXHQgKi9cclxuXHRnZXRQb3NpdGlvbjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMub3B0aW9ucy5wb3NpdGlvbjtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldFBvc2l0aW9uKHBvc2l0aW9uOiBzdHJpbmcpOiB0aGlzXHJcblx0Ly8gU2V0cyB0aGUgcG9zaXRpb24gb2YgdGhlIGNvbnRyb2wuXHJcblx0c2V0UG9zaXRpb246IGZ1bmN0aW9uIChwb3NpdGlvbikge1xyXG5cdFx0dmFyIG1hcCA9IHRoaXMuX21hcDtcclxuXHJcblx0XHRpZiAobWFwKSB7XHJcblx0XHRcdG1hcC5yZW1vdmVDb250cm9sKHRoaXMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMub3B0aW9ucy5wb3NpdGlvbiA9IHBvc2l0aW9uO1xyXG5cclxuXHRcdGlmIChtYXApIHtcclxuXHRcdFx0bWFwLmFkZENvbnRyb2wodGhpcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRDb250YWluZXI6IEhUTUxFbGVtZW50XHJcblx0Ly8gUmV0dXJucyB0aGUgSFRNTEVsZW1lbnQgdGhhdCBjb250YWlucyB0aGUgY29udHJvbC5cclxuXHRnZXRDb250YWluZXI6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9jb250YWluZXI7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBhZGRUbyhtYXA6IE1hcCk6IHRoaXNcclxuXHQvLyBBZGRzIHRoZSBjb250cm9sIHRvIHRoZSBnaXZlbiBtYXAuXHJcblx0YWRkVG86IGZ1bmN0aW9uIChtYXApIHtcclxuXHRcdHRoaXMucmVtb3ZlKCk7XHJcblx0XHR0aGlzLl9tYXAgPSBtYXA7XHJcblxyXG5cdFx0dmFyIGNvbnRhaW5lciA9IHRoaXMuX2NvbnRhaW5lciA9IHRoaXMub25BZGQobWFwKSxcclxuXHRcdCAgICBwb3MgPSB0aGlzLmdldFBvc2l0aW9uKCksXHJcblx0XHQgICAgY29ybmVyID0gbWFwLl9jb250cm9sQ29ybmVyc1twb3NdO1xyXG5cclxuXHRcdGFkZENsYXNzKGNvbnRhaW5lciwgJ2xlYWZsZXQtY29udHJvbCcpO1xyXG5cclxuXHRcdGlmIChwb3MuaW5kZXhPZignYm90dG9tJykgIT09IC0xKSB7XHJcblx0XHRcdGNvcm5lci5pbnNlcnRCZWZvcmUoY29udGFpbmVyLCBjb3JuZXIuZmlyc3RDaGlsZCk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRjb3JuZXIuYXBwZW5kQ2hpbGQoY29udGFpbmVyKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHJlbW92ZTogdGhpc1xyXG5cdC8vIFJlbW92ZXMgdGhlIGNvbnRyb2wgZnJvbSB0aGUgbWFwIGl0IGlzIGN1cnJlbnRseSBhY3RpdmUgb24uXHJcblx0cmVtb3ZlOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAoIXRoaXMuX21hcCkge1xyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHRcdH1cclxuXHJcblx0XHRyZW1vdmUodGhpcy5fY29udGFpbmVyKTtcclxuXHJcblx0XHRpZiAodGhpcy5vblJlbW92ZSkge1xyXG5cdFx0XHR0aGlzLm9uUmVtb3ZlKHRoaXMuX21hcCk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fbWFwID0gbnVsbDtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfcmVmb2N1c09uTWFwOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0Ly8gaWYgbWFwIGV4aXN0cyBhbmQgZXZlbnQgaXMgbm90IGEga2V5Ym9hcmQgZXZlbnRcclxuXHRcdGlmICh0aGlzLl9tYXAgJiYgZSAmJiBlLnNjcmVlblggPiAwICYmIGUuc2NyZWVuWSA+IDApIHtcclxuXHRcdFx0dGhpcy5fbWFwLmdldENvbnRhaW5lcigpLmZvY3VzKCk7XHJcblx0XHR9XHJcblx0fVxyXG59KTtcclxuXHJcbnZhciBjb250cm9sID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcclxuXHRyZXR1cm4gbmV3IENvbnRyb2wob3B0aW9ucyk7XHJcbn07XHJcblxyXG4vKiBAc2VjdGlvbiBFeHRlbnNpb24gbWV0aG9kc1xyXG4gKiBAdW5pbmhlcml0YWJsZVxyXG4gKlxyXG4gKiBFdmVyeSBjb250cm9sIHNob3VsZCBleHRlbmQgZnJvbSBgTC5Db250cm9sYCBhbmQgKHJlLSlpbXBsZW1lbnQgdGhlIGZvbGxvd2luZyBtZXRob2RzLlxyXG4gKlxyXG4gKiBAbWV0aG9kIG9uQWRkKG1hcDogTWFwKTogSFRNTEVsZW1lbnRcclxuICogU2hvdWxkIHJldHVybiB0aGUgY29udGFpbmVyIERPTSBlbGVtZW50IGZvciB0aGUgY29udHJvbCBhbmQgYWRkIGxpc3RlbmVycyBvbiByZWxldmFudCBtYXAgZXZlbnRzLiBDYWxsZWQgb24gW2Bjb250cm9sLmFkZFRvKG1hcClgXSgjY29udHJvbC1hZGRUbykuXHJcbiAqXHJcbiAqIEBtZXRob2Qgb25SZW1vdmUobWFwOiBNYXApXHJcbiAqIE9wdGlvbmFsIG1ldGhvZC4gU2hvdWxkIGNvbnRhaW4gYWxsIGNsZWFuIHVwIGNvZGUgdGhhdCByZW1vdmVzIHRoZSBsaXN0ZW5lcnMgcHJldmlvdXNseSBhZGRlZCBpbiBbYG9uQWRkYF0oI2NvbnRyb2wtb25hZGQpLiBDYWxsZWQgb24gW2Bjb250cm9sLnJlbW92ZSgpYF0oI2NvbnRyb2wtcmVtb3ZlKS5cclxuICovXHJcblxyXG4vKiBAbmFtZXNwYWNlIE1hcFxyXG4gKiBAc2VjdGlvbiBNZXRob2RzIGZvciBMYXllcnMgYW5kIENvbnRyb2xzXHJcbiAqL1xyXG5NYXAuaW5jbHVkZSh7XHJcblx0Ly8gQG1ldGhvZCBhZGRDb250cm9sKGNvbnRyb2w6IENvbnRyb2wpOiB0aGlzXHJcblx0Ly8gQWRkcyB0aGUgZ2l2ZW4gY29udHJvbCB0byB0aGUgbWFwXHJcblx0YWRkQ29udHJvbDogZnVuY3Rpb24gKGNvbnRyb2wpIHtcclxuXHRcdGNvbnRyb2wuYWRkVG8odGhpcyk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHJlbW92ZUNvbnRyb2woY29udHJvbDogQ29udHJvbCk6IHRoaXNcclxuXHQvLyBSZW1vdmVzIHRoZSBnaXZlbiBjb250cm9sIGZyb20gdGhlIG1hcFxyXG5cdHJlbW92ZUNvbnRyb2w6IGZ1bmN0aW9uIChjb250cm9sKSB7XHJcblx0XHRjb250cm9sLnJlbW92ZSgpO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0X2luaXRDb250cm9sUG9zOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgY29ybmVycyA9IHRoaXMuX2NvbnRyb2xDb3JuZXJzID0ge30sXHJcblx0XHQgICAgbCA9ICdsZWFmbGV0LScsXHJcblx0XHQgICAgY29udGFpbmVyID0gdGhpcy5fY29udHJvbENvbnRhaW5lciA9XHJcblx0XHQgICAgICAgICAgICBjcmVhdGUkMSgnZGl2JywgbCArICdjb250cm9sLWNvbnRhaW5lcicsIHRoaXMuX2NvbnRhaW5lcik7XHJcblxyXG5cdFx0ZnVuY3Rpb24gY3JlYXRlQ29ybmVyKHZTaWRlLCBoU2lkZSkge1xyXG5cdFx0XHR2YXIgY2xhc3NOYW1lID0gbCArIHZTaWRlICsgJyAnICsgbCArIGhTaWRlO1xyXG5cclxuXHRcdFx0Y29ybmVyc1t2U2lkZSArIGhTaWRlXSA9IGNyZWF0ZSQxKCdkaXYnLCBjbGFzc05hbWUsIGNvbnRhaW5lcik7XHJcblx0XHR9XHJcblxyXG5cdFx0Y3JlYXRlQ29ybmVyKCd0b3AnLCAnbGVmdCcpO1xyXG5cdFx0Y3JlYXRlQ29ybmVyKCd0b3AnLCAncmlnaHQnKTtcclxuXHRcdGNyZWF0ZUNvcm5lcignYm90dG9tJywgJ2xlZnQnKTtcclxuXHRcdGNyZWF0ZUNvcm5lcignYm90dG9tJywgJ3JpZ2h0Jyk7XHJcblx0fSxcclxuXHJcblx0X2NsZWFyQ29udHJvbFBvczogZnVuY3Rpb24gKCkge1xyXG5cdFx0Zm9yICh2YXIgaSBpbiB0aGlzLl9jb250cm9sQ29ybmVycykge1xyXG5cdFx0XHRyZW1vdmUodGhpcy5fY29udHJvbENvcm5lcnNbaV0pO1xyXG5cdFx0fVxyXG5cdFx0cmVtb3ZlKHRoaXMuX2NvbnRyb2xDb250YWluZXIpO1xyXG5cdFx0ZGVsZXRlIHRoaXMuX2NvbnRyb2xDb3JuZXJzO1xyXG5cdFx0ZGVsZXRlIHRoaXMuX2NvbnRyb2xDb250YWluZXI7XHJcblx0fVxyXG59KTtcblxuLypcclxuICogQGNsYXNzIENvbnRyb2wuTGF5ZXJzXHJcbiAqIEBha2EgTC5Db250cm9sLkxheWVyc1xyXG4gKiBAaW5oZXJpdHMgQ29udHJvbFxyXG4gKlxyXG4gKiBUaGUgbGF5ZXJzIGNvbnRyb2wgZ2l2ZXMgdXNlcnMgdGhlIGFiaWxpdHkgdG8gc3dpdGNoIGJldHdlZW4gZGlmZmVyZW50IGJhc2UgbGF5ZXJzIGFuZCBzd2l0Y2ggb3ZlcmxheXMgb24vb2ZmIChjaGVjayBvdXQgdGhlIFtkZXRhaWxlZCBleGFtcGxlXShodHRwOi8vbGVhZmxldGpzLmNvbS9leGFtcGxlcy9sYXllcnMtY29udHJvbC8pKS4gRXh0ZW5kcyBgQ29udHJvbGAuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHZhciBiYXNlTGF5ZXJzID0ge1xyXG4gKiBcdFwiTWFwYm94XCI6IG1hcGJveCxcclxuICogXHRcIk9wZW5TdHJlZXRNYXBcIjogb3NtXHJcbiAqIH07XHJcbiAqXHJcbiAqIHZhciBvdmVybGF5cyA9IHtcclxuICogXHRcIk1hcmtlclwiOiBtYXJrZXIsXHJcbiAqIFx0XCJSb2Fkc1wiOiByb2Fkc0xheWVyXHJcbiAqIH07XHJcbiAqXHJcbiAqIEwuY29udHJvbC5sYXllcnMoYmFzZUxheWVycywgb3ZlcmxheXMpLmFkZFRvKG1hcCk7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBUaGUgYGJhc2VMYXllcnNgIGFuZCBgb3ZlcmxheXNgIHBhcmFtZXRlcnMgYXJlIG9iamVjdCBsaXRlcmFscyB3aXRoIGxheWVyIG5hbWVzIGFzIGtleXMgYW5kIGBMYXllcmAgb2JqZWN0cyBhcyB2YWx1ZXM6XHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHtcclxuICogICAgIFwiPHNvbWVOYW1lMT5cIjogbGF5ZXIxLFxyXG4gKiAgICAgXCI8c29tZU5hbWUyPlwiOiBsYXllcjJcclxuICogfVxyXG4gKiBgYGBcclxuICpcclxuICogVGhlIGxheWVyIG5hbWVzIGNhbiBjb250YWluIEhUTUwsIHdoaWNoIGFsbG93cyB5b3UgdG8gYWRkIGFkZGl0aW9uYWwgc3R5bGluZyB0byB0aGUgaXRlbXM6XHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHtcIjxpbWcgc3JjPSdteS1sYXllci1pY29uJyAvPiA8c3BhbiBjbGFzcz0nbXktbGF5ZXItaXRlbSc+TXkgTGF5ZXI8L3NwYW4+XCI6IG15TGF5ZXJ9XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcbnZhciBMYXllcnMgPSBDb250cm9sLmV4dGVuZCh7XHJcblx0Ly8gQHNlY3Rpb25cclxuXHQvLyBAYWthIENvbnRyb2wuTGF5ZXJzIG9wdGlvbnNcclxuXHRvcHRpb25zOiB7XHJcblx0XHQvLyBAb3B0aW9uIGNvbGxhcHNlZDogQm9vbGVhbiA9IHRydWVcclxuXHRcdC8vIElmIGB0cnVlYCwgdGhlIGNvbnRyb2wgd2lsbCBiZSBjb2xsYXBzZWQgaW50byBhbiBpY29uIGFuZCBleHBhbmRlZCBvbiBtb3VzZSBob3ZlciBvciB0b3VjaC5cclxuXHRcdGNvbGxhcHNlZDogdHJ1ZSxcclxuXHRcdHBvc2l0aW9uOiAndG9wcmlnaHQnLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gYXV0b1pJbmRleDogQm9vbGVhbiA9IHRydWVcclxuXHRcdC8vIElmIGB0cnVlYCwgdGhlIGNvbnRyb2wgd2lsbCBhc3NpZ24gekluZGV4ZXMgaW4gaW5jcmVhc2luZyBvcmRlciB0byBhbGwgb2YgaXRzIGxheWVycyBzbyB0aGF0IHRoZSBvcmRlciBpcyBwcmVzZXJ2ZWQgd2hlbiBzd2l0Y2hpbmcgdGhlbSBvbi9vZmYuXHJcblx0XHRhdXRvWkluZGV4OiB0cnVlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gaGlkZVNpbmdsZUJhc2U6IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gSWYgYHRydWVgLCB0aGUgYmFzZSBsYXllcnMgaW4gdGhlIGNvbnRyb2wgd2lsbCBiZSBoaWRkZW4gd2hlbiB0aGVyZSBpcyBvbmx5IG9uZS5cclxuXHRcdGhpZGVTaW5nbGVCYXNlOiBmYWxzZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHNvcnRMYXllcnM6IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gV2hldGhlciB0byBzb3J0IHRoZSBsYXllcnMuIFdoZW4gYGZhbHNlYCwgbGF5ZXJzIHdpbGwga2VlcCB0aGUgb3JkZXJcclxuXHRcdC8vIGluIHdoaWNoIHRoZXkgd2VyZSBhZGRlZCB0byB0aGUgY29udHJvbC5cclxuXHRcdHNvcnRMYXllcnM6IGZhbHNlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gc29ydEZ1bmN0aW9uOiBGdW5jdGlvbiA9ICpcclxuXHRcdC8vIEEgW2NvbXBhcmUgZnVuY3Rpb25dKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL0phdmFTY3JpcHQvUmVmZXJlbmNlL0dsb2JhbF9PYmplY3RzL0FycmF5L3NvcnQpXHJcblx0XHQvLyB0aGF0IHdpbGwgYmUgdXNlZCBmb3Igc29ydGluZyB0aGUgbGF5ZXJzLCB3aGVuIGBzb3J0TGF5ZXJzYCBpcyBgdHJ1ZWAuXHJcblx0XHQvLyBUaGUgZnVuY3Rpb24gcmVjZWl2ZXMgYm90aCB0aGUgYEwuTGF5ZXJgIGluc3RhbmNlcyBhbmQgdGhlaXIgbmFtZXMsIGFzIGluXHJcblx0XHQvLyBgc29ydEZ1bmN0aW9uKGxheWVyQSwgbGF5ZXJCLCBuYW1lQSwgbmFtZUIpYC5cclxuXHRcdC8vIEJ5IGRlZmF1bHQsIGl0IHNvcnRzIGxheWVycyBhbHBoYWJldGljYWxseSBieSB0aGVpciBuYW1lLlxyXG5cdFx0c29ydEZ1bmN0aW9uOiBmdW5jdGlvbiAobGF5ZXJBLCBsYXllckIsIG5hbWVBLCBuYW1lQikge1xyXG5cdFx0XHRyZXR1cm4gbmFtZUEgPCBuYW1lQiA/IC0xIDogKG5hbWVCIDwgbmFtZUEgPyAxIDogMCk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKGJhc2VMYXllcnMsIG92ZXJsYXlzLCBvcHRpb25zKSB7XHJcblx0XHRzZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xyXG5cclxuXHRcdHRoaXMuX2xheWVyQ29udHJvbElucHV0cyA9IFtdO1xyXG5cdFx0dGhpcy5fbGF5ZXJzID0gW107XHJcblx0XHR0aGlzLl9sYXN0WkluZGV4ID0gMDtcclxuXHRcdHRoaXMuX2hhbmRsaW5nQ2xpY2sgPSBmYWxzZTtcclxuXHJcblx0XHRmb3IgKHZhciBpIGluIGJhc2VMYXllcnMpIHtcclxuXHRcdFx0dGhpcy5fYWRkTGF5ZXIoYmFzZUxheWVyc1tpXSwgaSk7XHJcblx0XHR9XHJcblxyXG5cdFx0Zm9yIChpIGluIG92ZXJsYXlzKSB7XHJcblx0XHRcdHRoaXMuX2FkZExheWVyKG92ZXJsYXlzW2ldLCBpLCB0cnVlKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRvbkFkZDogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0dGhpcy5faW5pdExheW91dCgpO1xyXG5cdFx0dGhpcy5fdXBkYXRlKCk7XHJcblxyXG5cdFx0dGhpcy5fbWFwID0gbWFwO1xyXG5cdFx0bWFwLm9uKCd6b29tZW5kJywgdGhpcy5fY2hlY2tEaXNhYmxlZExheWVycywgdGhpcyk7XHJcblxyXG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLl9sYXllcnMubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0dGhpcy5fbGF5ZXJzW2ldLmxheWVyLm9uKCdhZGQgcmVtb3ZlJywgdGhpcy5fb25MYXllckNoYW5nZSwgdGhpcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX2NvbnRhaW5lcjtcclxuXHR9LFxyXG5cclxuXHRhZGRUbzogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0Q29udHJvbC5wcm90b3R5cGUuYWRkVG8uY2FsbCh0aGlzLCBtYXApO1xyXG5cdFx0Ly8gVHJpZ2dlciBleHBhbmQgYWZ0ZXIgTGF5ZXJzIENvbnRyb2wgaGFzIGJlZW4gaW5zZXJ0ZWQgaW50byBET00gc28gdGhhdCBpcyBub3cgaGFzIGFuIGFjdHVhbCBoZWlnaHQuXHJcblx0XHRyZXR1cm4gdGhpcy5fZXhwYW5kSWZOb3RDb2xsYXBzZWQoKTtcclxuXHR9LFxyXG5cclxuXHRvblJlbW92ZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0dGhpcy5fbWFwLm9mZignem9vbWVuZCcsIHRoaXMuX2NoZWNrRGlzYWJsZWRMYXllcnMsIHRoaXMpO1xyXG5cclxuXHRcdGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5fbGF5ZXJzLmxlbmd0aDsgaSsrKSB7XHJcblx0XHRcdHRoaXMuX2xheWVyc1tpXS5sYXllci5vZmYoJ2FkZCByZW1vdmUnLCB0aGlzLl9vbkxheWVyQ2hhbmdlLCB0aGlzKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGFkZEJhc2VMYXllcihsYXllcjogTGF5ZXIsIG5hbWU6IFN0cmluZyk6IHRoaXNcclxuXHQvLyBBZGRzIGEgYmFzZSBsYXllciAocmFkaW8gYnV0dG9uIGVudHJ5KSB3aXRoIHRoZSBnaXZlbiBuYW1lIHRvIHRoZSBjb250cm9sLlxyXG5cdGFkZEJhc2VMYXllcjogZnVuY3Rpb24gKGxheWVyLCBuYW1lKSB7XHJcblx0XHR0aGlzLl9hZGRMYXllcihsYXllciwgbmFtZSk7XHJcblx0XHRyZXR1cm4gKHRoaXMuX21hcCkgPyB0aGlzLl91cGRhdGUoKSA6IHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBhZGRPdmVybGF5KGxheWVyOiBMYXllciwgbmFtZTogU3RyaW5nKTogdGhpc1xyXG5cdC8vIEFkZHMgYW4gb3ZlcmxheSAoY2hlY2tib3ggZW50cnkpIHdpdGggdGhlIGdpdmVuIG5hbWUgdG8gdGhlIGNvbnRyb2wuXHJcblx0YWRkT3ZlcmxheTogZnVuY3Rpb24gKGxheWVyLCBuYW1lKSB7XHJcblx0XHR0aGlzLl9hZGRMYXllcihsYXllciwgbmFtZSwgdHJ1ZSk7XHJcblx0XHRyZXR1cm4gKHRoaXMuX21hcCkgPyB0aGlzLl91cGRhdGUoKSA6IHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCByZW1vdmVMYXllcihsYXllcjogTGF5ZXIpOiB0aGlzXHJcblx0Ly8gUmVtb3ZlIHRoZSBnaXZlbiBsYXllciBmcm9tIHRoZSBjb250cm9sLlxyXG5cdHJlbW92ZUxheWVyOiBmdW5jdGlvbiAobGF5ZXIpIHtcclxuXHRcdGxheWVyLm9mZignYWRkIHJlbW92ZScsIHRoaXMuX29uTGF5ZXJDaGFuZ2UsIHRoaXMpO1xyXG5cclxuXHRcdHZhciBvYmogPSB0aGlzLl9nZXRMYXllcihzdGFtcChsYXllcikpO1xyXG5cdFx0aWYgKG9iaikge1xyXG5cdFx0XHR0aGlzLl9sYXllcnMuc3BsaWNlKHRoaXMuX2xheWVycy5pbmRleE9mKG9iaiksIDEpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuICh0aGlzLl9tYXApID8gdGhpcy5fdXBkYXRlKCkgOiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZXhwYW5kKCk6IHRoaXNcclxuXHQvLyBFeHBhbmQgdGhlIGNvbnRyb2wgY29udGFpbmVyIGlmIGNvbGxhcHNlZC5cclxuXHRleHBhbmQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGFkZENsYXNzKHRoaXMuX2NvbnRhaW5lciwgJ2xlYWZsZXQtY29udHJvbC1sYXllcnMtZXhwYW5kZWQnKTtcclxuXHRcdHRoaXMuX2Zvcm0uc3R5bGUuaGVpZ2h0ID0gbnVsbDtcclxuXHRcdHZhciBhY2NlcHRhYmxlSGVpZ2h0ID0gdGhpcy5fbWFwLmdldFNpemUoKS55IC0gKHRoaXMuX2NvbnRhaW5lci5vZmZzZXRUb3AgKyA1MCk7XHJcblx0XHRpZiAoYWNjZXB0YWJsZUhlaWdodCA8IHRoaXMuX2Zvcm0uY2xpZW50SGVpZ2h0KSB7XHJcblx0XHRcdGFkZENsYXNzKHRoaXMuX2Zvcm0sICdsZWFmbGV0LWNvbnRyb2wtbGF5ZXJzLXNjcm9sbGJhcicpO1xyXG5cdFx0XHR0aGlzLl9mb3JtLnN0eWxlLmhlaWdodCA9IGFjY2VwdGFibGVIZWlnaHQgKyAncHgnO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0cmVtb3ZlQ2xhc3ModGhpcy5fZm9ybSwgJ2xlYWZsZXQtY29udHJvbC1sYXllcnMtc2Nyb2xsYmFyJyk7XHJcblx0XHR9XHJcblx0XHR0aGlzLl9jaGVja0Rpc2FibGVkTGF5ZXJzKCk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGNvbGxhcHNlKCk6IHRoaXNcclxuXHQvLyBDb2xsYXBzZSB0aGUgY29udHJvbCBjb250YWluZXIgaWYgZXhwYW5kZWQuXHJcblx0Y29sbGFwc2U6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJlbW92ZUNsYXNzKHRoaXMuX2NvbnRhaW5lciwgJ2xlYWZsZXQtY29udHJvbC1sYXllcnMtZXhwYW5kZWQnKTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdF9pbml0TGF5b3V0OiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgY2xhc3NOYW1lID0gJ2xlYWZsZXQtY29udHJvbC1sYXllcnMnLFxyXG5cdFx0ICAgIGNvbnRhaW5lciA9IHRoaXMuX2NvbnRhaW5lciA9IGNyZWF0ZSQxKCdkaXYnLCBjbGFzc05hbWUpLFxyXG5cdFx0ICAgIGNvbGxhcHNlZCA9IHRoaXMub3B0aW9ucy5jb2xsYXBzZWQ7XHJcblxyXG5cdFx0Ly8gbWFrZXMgdGhpcyB3b3JrIG9uIElFIHRvdWNoIGRldmljZXMgYnkgc3RvcHBpbmcgaXQgZnJvbSBmaXJpbmcgYSBtb3VzZW91dCBldmVudCB3aGVuIHRoZSB0b3VjaCBpcyByZWxlYXNlZFxyXG5cdFx0Y29udGFpbmVyLnNldEF0dHJpYnV0ZSgnYXJpYS1oYXNwb3B1cCcsIHRydWUpO1xyXG5cclxuXHRcdGRpc2FibGVDbGlja1Byb3BhZ2F0aW9uKGNvbnRhaW5lcik7XHJcblx0XHRkaXNhYmxlU2Nyb2xsUHJvcGFnYXRpb24oY29udGFpbmVyKTtcclxuXHJcblx0XHR2YXIgZm9ybSA9IHRoaXMuX2Zvcm0gPSBjcmVhdGUkMSgnZm9ybScsIGNsYXNzTmFtZSArICctbGlzdCcpO1xyXG5cclxuXHRcdGlmIChjb2xsYXBzZWQpIHtcclxuXHRcdFx0dGhpcy5fbWFwLm9uKCdjbGljaycsIHRoaXMuY29sbGFwc2UsIHRoaXMpO1xyXG5cclxuXHRcdFx0aWYgKCFhbmRyb2lkKSB7XHJcblx0XHRcdFx0b24oY29udGFpbmVyLCB7XHJcblx0XHRcdFx0XHRtb3VzZWVudGVyOiB0aGlzLmV4cGFuZCxcclxuXHRcdFx0XHRcdG1vdXNlbGVhdmU6IHRoaXMuY29sbGFwc2VcclxuXHRcdFx0XHR9LCB0aGlzKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBsaW5rID0gdGhpcy5fbGF5ZXJzTGluayA9IGNyZWF0ZSQxKCdhJywgY2xhc3NOYW1lICsgJy10b2dnbGUnLCBjb250YWluZXIpO1xyXG5cdFx0bGluay5ocmVmID0gJyMnO1xyXG5cdFx0bGluay50aXRsZSA9ICdMYXllcnMnO1xyXG5cclxuXHRcdGlmICh0b3VjaCkge1xyXG5cdFx0XHRvbihsaW5rLCAnY2xpY2snLCBzdG9wKTtcclxuXHRcdFx0b24obGluaywgJ2NsaWNrJywgdGhpcy5leHBhbmQsIHRoaXMpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0b24obGluaywgJ2ZvY3VzJywgdGhpcy5leHBhbmQsIHRoaXMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICghY29sbGFwc2VkKSB7XHJcblx0XHRcdHRoaXMuZXhwYW5kKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fYmFzZUxheWVyc0xpc3QgPSBjcmVhdGUkMSgnZGl2JywgY2xhc3NOYW1lICsgJy1iYXNlJywgZm9ybSk7XHJcblx0XHR0aGlzLl9zZXBhcmF0b3IgPSBjcmVhdGUkMSgnZGl2JywgY2xhc3NOYW1lICsgJy1zZXBhcmF0b3InLCBmb3JtKTtcclxuXHRcdHRoaXMuX292ZXJsYXlzTGlzdCA9IGNyZWF0ZSQxKCdkaXYnLCBjbGFzc05hbWUgKyAnLW92ZXJsYXlzJywgZm9ybSk7XHJcblxyXG5cdFx0Y29udGFpbmVyLmFwcGVuZENoaWxkKGZvcm0pO1xyXG5cdH0sXHJcblxyXG5cdF9nZXRMYXllcjogZnVuY3Rpb24gKGlkKSB7XHJcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuX2xheWVycy5sZW5ndGg7IGkrKykge1xyXG5cclxuXHRcdFx0aWYgKHRoaXMuX2xheWVyc1tpXSAmJiBzdGFtcCh0aGlzLl9sYXllcnNbaV0ubGF5ZXIpID09PSBpZCkge1xyXG5cdFx0XHRcdHJldHVybiB0aGlzLl9sYXllcnNbaV07XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfYWRkTGF5ZXI6IGZ1bmN0aW9uIChsYXllciwgbmFtZSwgb3ZlcmxheSkge1xyXG5cdFx0aWYgKHRoaXMuX21hcCkge1xyXG5cdFx0XHRsYXllci5vbignYWRkIHJlbW92ZScsIHRoaXMuX29uTGF5ZXJDaGFuZ2UsIHRoaXMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2xheWVycy5wdXNoKHtcclxuXHRcdFx0bGF5ZXI6IGxheWVyLFxyXG5cdFx0XHRuYW1lOiBuYW1lLFxyXG5cdFx0XHRvdmVybGF5OiBvdmVybGF5XHJcblx0XHR9KTtcclxuXHJcblx0XHRpZiAodGhpcy5vcHRpb25zLnNvcnRMYXllcnMpIHtcclxuXHRcdFx0dGhpcy5fbGF5ZXJzLnNvcnQoYmluZChmdW5jdGlvbiAoYSwgYikge1xyXG5cdFx0XHRcdHJldHVybiB0aGlzLm9wdGlvbnMuc29ydEZ1bmN0aW9uKGEubGF5ZXIsIGIubGF5ZXIsIGEubmFtZSwgYi5uYW1lKTtcclxuXHRcdFx0fSwgdGhpcykpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICh0aGlzLm9wdGlvbnMuYXV0b1pJbmRleCAmJiBsYXllci5zZXRaSW5kZXgpIHtcclxuXHRcdFx0dGhpcy5fbGFzdFpJbmRleCsrO1xyXG5cdFx0XHRsYXllci5zZXRaSW5kZXgodGhpcy5fbGFzdFpJbmRleCk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fZXhwYW5kSWZOb3RDb2xsYXBzZWQoKTtcclxuXHR9LFxyXG5cclxuXHRfdXBkYXRlOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAoIXRoaXMuX2NvbnRhaW5lcikgeyByZXR1cm4gdGhpczsgfVxyXG5cclxuXHRcdGVtcHR5KHRoaXMuX2Jhc2VMYXllcnNMaXN0KTtcclxuXHRcdGVtcHR5KHRoaXMuX292ZXJsYXlzTGlzdCk7XHJcblxyXG5cdFx0dGhpcy5fbGF5ZXJDb250cm9sSW5wdXRzID0gW107XHJcblx0XHR2YXIgYmFzZUxheWVyc1ByZXNlbnQsIG92ZXJsYXlzUHJlc2VudCwgaSwgb2JqLCBiYXNlTGF5ZXJzQ291bnQgPSAwO1xyXG5cclxuXHRcdGZvciAoaSA9IDA7IGkgPCB0aGlzLl9sYXllcnMubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0b2JqID0gdGhpcy5fbGF5ZXJzW2ldO1xyXG5cdFx0XHR0aGlzLl9hZGRJdGVtKG9iaik7XHJcblx0XHRcdG92ZXJsYXlzUHJlc2VudCA9IG92ZXJsYXlzUHJlc2VudCB8fCBvYmoub3ZlcmxheTtcclxuXHRcdFx0YmFzZUxheWVyc1ByZXNlbnQgPSBiYXNlTGF5ZXJzUHJlc2VudCB8fCAhb2JqLm92ZXJsYXk7XHJcblx0XHRcdGJhc2VMYXllcnNDb3VudCArPSAhb2JqLm92ZXJsYXkgPyAxIDogMDtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBIaWRlIGJhc2UgbGF5ZXJzIHNlY3Rpb24gaWYgdGhlcmUncyBvbmx5IG9uZSBsYXllci5cclxuXHRcdGlmICh0aGlzLm9wdGlvbnMuaGlkZVNpbmdsZUJhc2UpIHtcclxuXHRcdFx0YmFzZUxheWVyc1ByZXNlbnQgPSBiYXNlTGF5ZXJzUHJlc2VudCAmJiBiYXNlTGF5ZXJzQ291bnQgPiAxO1xyXG5cdFx0XHR0aGlzLl9iYXNlTGF5ZXJzTGlzdC5zdHlsZS5kaXNwbGF5ID0gYmFzZUxheWVyc1ByZXNlbnQgPyAnJyA6ICdub25lJztcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9zZXBhcmF0b3Iuc3R5bGUuZGlzcGxheSA9IG92ZXJsYXlzUHJlc2VudCAmJiBiYXNlTGF5ZXJzUHJlc2VudCA/ICcnIDogJ25vbmUnO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdF9vbkxheWVyQ2hhbmdlOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0aWYgKCF0aGlzLl9oYW5kbGluZ0NsaWNrKSB7XHJcblx0XHRcdHRoaXMuX3VwZGF0ZSgpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBvYmogPSB0aGlzLl9nZXRMYXllcihzdGFtcChlLnRhcmdldCkpO1xyXG5cclxuXHRcdC8vIEBuYW1lc3BhY2UgTWFwXHJcblx0XHQvLyBAc2VjdGlvbiBMYXllciBldmVudHNcclxuXHRcdC8vIEBldmVudCBiYXNlbGF5ZXJjaGFuZ2U6IExheWVyc0NvbnRyb2xFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgYmFzZSBsYXllciBpcyBjaGFuZ2VkIHRocm91Z2ggdGhlIFtsYXllciBjb250cm9sXSgjY29udHJvbC1sYXllcnMpLlxyXG5cdFx0Ly8gQGV2ZW50IG92ZXJsYXlhZGQ6IExheWVyc0NvbnRyb2xFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiBhbiBvdmVybGF5IGlzIHNlbGVjdGVkIHRocm91Z2ggdGhlIFtsYXllciBjb250cm9sXSgjY29udHJvbC1sYXllcnMpLlxyXG5cdFx0Ly8gQGV2ZW50IG92ZXJsYXlyZW1vdmU6IExheWVyc0NvbnRyb2xFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiBhbiBvdmVybGF5IGlzIGRlc2VsZWN0ZWQgdGhyb3VnaCB0aGUgW2xheWVyIGNvbnRyb2xdKCNjb250cm9sLWxheWVycykuXHJcblx0XHQvLyBAbmFtZXNwYWNlIENvbnRyb2wuTGF5ZXJzXHJcblx0XHR2YXIgdHlwZSA9IG9iai5vdmVybGF5ID9cclxuXHRcdFx0KGUudHlwZSA9PT0gJ2FkZCcgPyAnb3ZlcmxheWFkZCcgOiAnb3ZlcmxheXJlbW92ZScpIDpcclxuXHRcdFx0KGUudHlwZSA9PT0gJ2FkZCcgPyAnYmFzZWxheWVyY2hhbmdlJyA6IG51bGwpO1xyXG5cclxuXHRcdGlmICh0eXBlKSB7XHJcblx0XHRcdHRoaXMuX21hcC5maXJlKHR5cGUsIG9iaik7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gSUU3IGJ1Z3Mgb3V0IGlmIHlvdSBjcmVhdGUgYSByYWRpbyBkeW5hbWljYWxseSwgc28geW91IGhhdmUgdG8gZG8gaXQgdGhpcyBoYWNreSB3YXkgKHNlZSBodHRwOi8vYml0Lmx5L1BxWUxCZSlcclxuXHRfY3JlYXRlUmFkaW9FbGVtZW50OiBmdW5jdGlvbiAobmFtZSwgY2hlY2tlZCkge1xyXG5cclxuXHRcdHZhciByYWRpb0h0bWwgPSAnPGlucHV0IHR5cGU9XCJyYWRpb1wiIGNsYXNzPVwibGVhZmxldC1jb250cm9sLWxheWVycy1zZWxlY3RvclwiIG5hbWU9XCInICtcclxuXHRcdFx0XHRuYW1lICsgJ1wiJyArIChjaGVja2VkID8gJyBjaGVja2VkPVwiY2hlY2tlZFwiJyA6ICcnKSArICcvPic7XHJcblxyXG5cdFx0dmFyIHJhZGlvRnJhZ21lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuXHRcdHJhZGlvRnJhZ21lbnQuaW5uZXJIVE1MID0gcmFkaW9IdG1sO1xyXG5cclxuXHRcdHJldHVybiByYWRpb0ZyYWdtZW50LmZpcnN0Q2hpbGQ7XHJcblx0fSxcclxuXHJcblx0X2FkZEl0ZW06IGZ1bmN0aW9uIChvYmopIHtcclxuXHRcdHZhciBsYWJlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xhYmVsJyksXHJcblx0XHQgICAgY2hlY2tlZCA9IHRoaXMuX21hcC5oYXNMYXllcihvYmoubGF5ZXIpLFxyXG5cdFx0ICAgIGlucHV0O1xyXG5cclxuXHRcdGlmIChvYmoub3ZlcmxheSkge1xyXG5cdFx0XHRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lucHV0Jyk7XHJcblx0XHRcdGlucHV0LnR5cGUgPSAnY2hlY2tib3gnO1xyXG5cdFx0XHRpbnB1dC5jbGFzc05hbWUgPSAnbGVhZmxldC1jb250cm9sLWxheWVycy1zZWxlY3Rvcic7XHJcblx0XHRcdGlucHV0LmRlZmF1bHRDaGVja2VkID0gY2hlY2tlZDtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGlucHV0ID0gdGhpcy5fY3JlYXRlUmFkaW9FbGVtZW50KCdsZWFmbGV0LWJhc2UtbGF5ZXJzJywgY2hlY2tlZCk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fbGF5ZXJDb250cm9sSW5wdXRzLnB1c2goaW5wdXQpO1xyXG5cdFx0aW5wdXQubGF5ZXJJZCA9IHN0YW1wKG9iai5sYXllcik7XHJcblxyXG5cdFx0b24oaW5wdXQsICdjbGljaycsIHRoaXMuX29uSW5wdXRDbGljaywgdGhpcyk7XHJcblxyXG5cdFx0dmFyIG5hbWUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XHJcblx0XHRuYW1lLmlubmVySFRNTCA9ICcgJyArIG9iai5uYW1lO1xyXG5cclxuXHRcdC8vIEhlbHBzIGZyb20gcHJldmVudGluZyBsYXllciBjb250cm9sIGZsaWNrZXIgd2hlbiBjaGVja2JveGVzIGFyZSBkaXNhYmxlZFxyXG5cdFx0Ly8gaHR0cHM6Ly9naXRodWIuY29tL0xlYWZsZXQvTGVhZmxldC9pc3N1ZXMvMjc3MVxyXG5cdFx0dmFyIGhvbGRlciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xyXG5cclxuXHRcdGxhYmVsLmFwcGVuZENoaWxkKGhvbGRlcik7XHJcblx0XHRob2xkZXIuYXBwZW5kQ2hpbGQoaW5wdXQpO1xyXG5cdFx0aG9sZGVyLmFwcGVuZENoaWxkKG5hbWUpO1xyXG5cclxuXHRcdHZhciBjb250YWluZXIgPSBvYmoub3ZlcmxheSA/IHRoaXMuX292ZXJsYXlzTGlzdCA6IHRoaXMuX2Jhc2VMYXllcnNMaXN0O1xyXG5cdFx0Y29udGFpbmVyLmFwcGVuZENoaWxkKGxhYmVsKTtcclxuXHJcblx0XHR0aGlzLl9jaGVja0Rpc2FibGVkTGF5ZXJzKCk7XHJcblx0XHRyZXR1cm4gbGFiZWw7XHJcblx0fSxcclxuXHJcblx0X29uSW5wdXRDbGljazogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGlucHV0cyA9IHRoaXMuX2xheWVyQ29udHJvbElucHV0cyxcclxuXHRcdCAgICBpbnB1dCwgbGF5ZXI7XHJcblx0XHR2YXIgYWRkZWRMYXllcnMgPSBbXSxcclxuXHRcdCAgICByZW1vdmVkTGF5ZXJzID0gW107XHJcblxyXG5cdFx0dGhpcy5faGFuZGxpbmdDbGljayA9IHRydWU7XHJcblxyXG5cdFx0Zm9yICh2YXIgaSA9IGlucHV0cy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xyXG5cdFx0XHRpbnB1dCA9IGlucHV0c1tpXTtcclxuXHRcdFx0bGF5ZXIgPSB0aGlzLl9nZXRMYXllcihpbnB1dC5sYXllcklkKS5sYXllcjtcclxuXHJcblx0XHRcdGlmIChpbnB1dC5jaGVja2VkKSB7XHJcblx0XHRcdFx0YWRkZWRMYXllcnMucHVzaChsYXllcik7XHJcblx0XHRcdH0gZWxzZSBpZiAoIWlucHV0LmNoZWNrZWQpIHtcclxuXHRcdFx0XHRyZW1vdmVkTGF5ZXJzLnB1c2gobGF5ZXIpO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQnVnZml4IGlzc3VlIDIzMTg6IFNob3VsZCByZW1vdmUgYWxsIG9sZCBsYXllcnMgYmVmb3JlIHJlYWRkaW5nIG5ldyBvbmVzXHJcblx0XHRmb3IgKGkgPSAwOyBpIDwgcmVtb3ZlZExheWVycy5sZW5ndGg7IGkrKykge1xyXG5cdFx0XHRpZiAodGhpcy5fbWFwLmhhc0xheWVyKHJlbW92ZWRMYXllcnNbaV0pKSB7XHJcblx0XHRcdFx0dGhpcy5fbWFwLnJlbW92ZUxheWVyKHJlbW92ZWRMYXllcnNbaV0pO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRmb3IgKGkgPSAwOyBpIDwgYWRkZWRMYXllcnMubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0aWYgKCF0aGlzLl9tYXAuaGFzTGF5ZXIoYWRkZWRMYXllcnNbaV0pKSB7XHJcblx0XHRcdFx0dGhpcy5fbWFwLmFkZExheWVyKGFkZGVkTGF5ZXJzW2ldKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2hhbmRsaW5nQ2xpY2sgPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLl9yZWZvY3VzT25NYXAoKTtcclxuXHR9LFxyXG5cclxuXHRfY2hlY2tEaXNhYmxlZExheWVyczogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGlucHV0cyA9IHRoaXMuX2xheWVyQ29udHJvbElucHV0cyxcclxuXHRcdCAgICBpbnB1dCxcclxuXHRcdCAgICBsYXllcixcclxuXHRcdCAgICB6b29tID0gdGhpcy5fbWFwLmdldFpvb20oKTtcclxuXHJcblx0XHRmb3IgKHZhciBpID0gaW5wdXRzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XHJcblx0XHRcdGlucHV0ID0gaW5wdXRzW2ldO1xyXG5cdFx0XHRsYXllciA9IHRoaXMuX2dldExheWVyKGlucHV0LmxheWVySWQpLmxheWVyO1xyXG5cdFx0XHRpbnB1dC5kaXNhYmxlZCA9IChsYXllci5vcHRpb25zLm1pblpvb20gIT09IHVuZGVmaW5lZCAmJiB6b29tIDwgbGF5ZXIub3B0aW9ucy5taW5ab29tKSB8fFxyXG5cdFx0XHQgICAgICAgICAgICAgICAgIChsYXllci5vcHRpb25zLm1heFpvb20gIT09IHVuZGVmaW5lZCAmJiB6b29tID4gbGF5ZXIub3B0aW9ucy5tYXhab29tKTtcclxuXHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X2V4cGFuZElmTm90Q29sbGFwc2VkOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAodGhpcy5fbWFwICYmICF0aGlzLm9wdGlvbnMuY29sbGFwc2VkKSB7XHJcblx0XHRcdHRoaXMuZXhwYW5kKCk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfZXhwYW5kOiBmdW5jdGlvbiAoKSB7XHJcblx0XHQvLyBCYWNrd2FyZCBjb21wYXRpYmlsaXR5LCByZW1vdmUgbWUgaW4gMS4xLlxyXG5cdFx0cmV0dXJuIHRoaXMuZXhwYW5kKCk7XHJcblx0fSxcclxuXHJcblx0X2NvbGxhcHNlOiBmdW5jdGlvbiAoKSB7XHJcblx0XHQvLyBCYWNrd2FyZCBjb21wYXRpYmlsaXR5LCByZW1vdmUgbWUgaW4gMS4xLlxyXG5cdFx0cmV0dXJuIHRoaXMuY29sbGFwc2UoKTtcclxuXHR9XHJcblxyXG59KTtcclxuXHJcblxyXG4vLyBAZmFjdG9yeSBMLmNvbnRyb2wubGF5ZXJzKGJhc2VsYXllcnM/OiBPYmplY3QsIG92ZXJsYXlzPzogT2JqZWN0LCBvcHRpb25zPzogQ29udHJvbC5MYXllcnMgb3B0aW9ucylcclxuLy8gQ3JlYXRlcyBhbiBhdHRyaWJ1dGlvbiBjb250cm9sIHdpdGggdGhlIGdpdmVuIGxheWVycy4gQmFzZSBsYXllcnMgd2lsbCBiZSBzd2l0Y2hlZCB3aXRoIHJhZGlvIGJ1dHRvbnMsIHdoaWxlIG92ZXJsYXlzIHdpbGwgYmUgc3dpdGNoZWQgd2l0aCBjaGVja2JveGVzLiBOb3RlIHRoYXQgYWxsIGJhc2UgbGF5ZXJzIHNob3VsZCBiZSBwYXNzZWQgaW4gdGhlIGJhc2UgbGF5ZXJzIG9iamVjdCwgYnV0IG9ubHkgb25lIHNob3VsZCBiZSBhZGRlZCB0byB0aGUgbWFwIGR1cmluZyBtYXAgaW5zdGFudGlhdGlvbi5cclxudmFyIGxheWVycyA9IGZ1bmN0aW9uIChiYXNlTGF5ZXJzLCBvdmVybGF5cywgb3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgTGF5ZXJzKGJhc2VMYXllcnMsIG92ZXJsYXlzLCBvcHRpb25zKTtcclxufTtcblxuLypcclxuICogQGNsYXNzIENvbnRyb2wuWm9vbVxyXG4gKiBAYWthIEwuQ29udHJvbC5ab29tXHJcbiAqIEBpbmhlcml0cyBDb250cm9sXHJcbiAqXHJcbiAqIEEgYmFzaWMgem9vbSBjb250cm9sIHdpdGggdHdvIGJ1dHRvbnMgKHpvb20gaW4gYW5kIHpvb20gb3V0KS4gSXQgaXMgcHV0IG9uIHRoZSBtYXAgYnkgZGVmYXVsdCB1bmxlc3MgeW91IHNldCBpdHMgW2B6b29tQ29udHJvbGAgb3B0aW9uXSgjbWFwLXpvb21jb250cm9sKSB0byBgZmFsc2VgLiBFeHRlbmRzIGBDb250cm9sYC5cclxuICovXHJcblxyXG52YXIgWm9vbSA9IENvbnRyb2wuZXh0ZW5kKHtcclxuXHQvLyBAc2VjdGlvblxyXG5cdC8vIEBha2EgQ29udHJvbC5ab29tIG9wdGlvbnNcclxuXHRvcHRpb25zOiB7XHJcblx0XHRwb3NpdGlvbjogJ3RvcGxlZnQnLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gem9vbUluVGV4dDogU3RyaW5nID0gJysnXHJcblx0XHQvLyBUaGUgdGV4dCBzZXQgb24gdGhlICd6b29tIGluJyBidXR0b24uXHJcblx0XHR6b29tSW5UZXh0OiAnKycsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiB6b29tSW5UaXRsZTogU3RyaW5nID0gJ1pvb20gaW4nXHJcblx0XHQvLyBUaGUgdGl0bGUgc2V0IG9uIHRoZSAnem9vbSBpbicgYnV0dG9uLlxyXG5cdFx0em9vbUluVGl0bGU6ICdab29tIGluJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHpvb21PdXRUZXh0OiBTdHJpbmcgPSAnJiN4MjIxMjsnXHJcblx0XHQvLyBUaGUgdGV4dCBzZXQgb24gdGhlICd6b29tIG91dCcgYnV0dG9uLlxyXG5cdFx0em9vbU91dFRleHQ6ICcmI3gyMjEyOycsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiB6b29tT3V0VGl0bGU6IFN0cmluZyA9ICdab29tIG91dCdcclxuXHRcdC8vIFRoZSB0aXRsZSBzZXQgb24gdGhlICd6b29tIG91dCcgYnV0dG9uLlxyXG5cdFx0em9vbU91dFRpdGxlOiAnWm9vbSBvdXQnXHJcblx0fSxcclxuXHJcblx0b25BZGQ6IGZ1bmN0aW9uIChtYXApIHtcclxuXHRcdHZhciB6b29tTmFtZSA9ICdsZWFmbGV0LWNvbnRyb2wtem9vbScsXHJcblx0XHQgICAgY29udGFpbmVyID0gY3JlYXRlJDEoJ2RpdicsIHpvb21OYW1lICsgJyBsZWFmbGV0LWJhcicpLFxyXG5cdFx0ICAgIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XHJcblxyXG5cdFx0dGhpcy5fem9vbUluQnV0dG9uICA9IHRoaXMuX2NyZWF0ZUJ1dHRvbihvcHRpb25zLnpvb21JblRleHQsIG9wdGlvbnMuem9vbUluVGl0bGUsXHJcblx0XHQgICAgICAgIHpvb21OYW1lICsgJy1pbicsICBjb250YWluZXIsIHRoaXMuX3pvb21Jbik7XHJcblx0XHR0aGlzLl96b29tT3V0QnV0dG9uID0gdGhpcy5fY3JlYXRlQnV0dG9uKG9wdGlvbnMuem9vbU91dFRleHQsIG9wdGlvbnMuem9vbU91dFRpdGxlLFxyXG5cdFx0ICAgICAgICB6b29tTmFtZSArICctb3V0JywgY29udGFpbmVyLCB0aGlzLl96b29tT3V0KTtcclxuXHJcblx0XHR0aGlzLl91cGRhdGVEaXNhYmxlZCgpO1xyXG5cdFx0bWFwLm9uKCd6b29tZW5kIHpvb21sZXZlbHNjaGFuZ2UnLCB0aGlzLl91cGRhdGVEaXNhYmxlZCwgdGhpcyk7XHJcblxyXG5cdFx0cmV0dXJuIGNvbnRhaW5lcjtcclxuXHR9LFxyXG5cclxuXHRvblJlbW92ZTogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0bWFwLm9mZignem9vbWVuZCB6b29tbGV2ZWxzY2hhbmdlJywgdGhpcy5fdXBkYXRlRGlzYWJsZWQsIHRoaXMpO1xyXG5cdH0sXHJcblxyXG5cdGRpc2FibGU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHRoaXMuX2Rpc2FibGVkID0gdHJ1ZTtcclxuXHRcdHRoaXMuX3VwZGF0ZURpc2FibGVkKCk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRlbmFibGU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHRoaXMuX2Rpc2FibGVkID0gZmFsc2U7XHJcblx0XHR0aGlzLl91cGRhdGVEaXNhYmxlZCgpO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0X3pvb21JbjogZnVuY3Rpb24gKGUpIHtcclxuXHRcdGlmICghdGhpcy5fZGlzYWJsZWQgJiYgdGhpcy5fbWFwLl96b29tIDwgdGhpcy5fbWFwLmdldE1heFpvb20oKSkge1xyXG5cdFx0XHR0aGlzLl9tYXAuem9vbUluKHRoaXMuX21hcC5vcHRpb25zLnpvb21EZWx0YSAqIChlLnNoaWZ0S2V5ID8gMyA6IDEpKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfem9vbU91dDogZnVuY3Rpb24gKGUpIHtcclxuXHRcdGlmICghdGhpcy5fZGlzYWJsZWQgJiYgdGhpcy5fbWFwLl96b29tID4gdGhpcy5fbWFwLmdldE1pblpvb20oKSkge1xyXG5cdFx0XHR0aGlzLl9tYXAuem9vbU91dCh0aGlzLl9tYXAub3B0aW9ucy56b29tRGVsdGEgKiAoZS5zaGlmdEtleSA/IDMgOiAxKSk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X2NyZWF0ZUJ1dHRvbjogZnVuY3Rpb24gKGh0bWwsIHRpdGxlLCBjbGFzc05hbWUsIGNvbnRhaW5lciwgZm4pIHtcclxuXHRcdHZhciBsaW5rID0gY3JlYXRlJDEoJ2EnLCBjbGFzc05hbWUsIGNvbnRhaW5lcik7XHJcblx0XHRsaW5rLmlubmVySFRNTCA9IGh0bWw7XHJcblx0XHRsaW5rLmhyZWYgPSAnIyc7XHJcblx0XHRsaW5rLnRpdGxlID0gdGl0bGU7XHJcblxyXG5cdFx0LypcclxuXHRcdCAqIFdpbGwgZm9yY2Ugc2NyZWVuIHJlYWRlcnMgbGlrZSBWb2ljZU92ZXIgdG8gcmVhZCB0aGlzIGFzIFwiWm9vbSBpbiAtIGJ1dHRvblwiXHJcblx0XHQgKi9cclxuXHRcdGxpbmsuc2V0QXR0cmlidXRlKCdyb2xlJywgJ2J1dHRvbicpO1xyXG5cdFx0bGluay5zZXRBdHRyaWJ1dGUoJ2FyaWEtbGFiZWwnLCB0aXRsZSk7XHJcblxyXG5cdFx0ZGlzYWJsZUNsaWNrUHJvcGFnYXRpb24obGluayk7XHJcblx0XHRvbihsaW5rLCAnY2xpY2snLCBzdG9wKTtcclxuXHRcdG9uKGxpbmssICdjbGljaycsIGZuLCB0aGlzKTtcclxuXHRcdG9uKGxpbmssICdjbGljaycsIHRoaXMuX3JlZm9jdXNPbk1hcCwgdGhpcyk7XHJcblxyXG5cdFx0cmV0dXJuIGxpbms7XHJcblx0fSxcclxuXHJcblx0X3VwZGF0ZURpc2FibGVkOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxyXG5cdFx0ICAgIGNsYXNzTmFtZSA9ICdsZWFmbGV0LWRpc2FibGVkJztcclxuXHJcblx0XHRyZW1vdmVDbGFzcyh0aGlzLl96b29tSW5CdXR0b24sIGNsYXNzTmFtZSk7XHJcblx0XHRyZW1vdmVDbGFzcyh0aGlzLl96b29tT3V0QnV0dG9uLCBjbGFzc05hbWUpO1xyXG5cclxuXHRcdGlmICh0aGlzLl9kaXNhYmxlZCB8fCBtYXAuX3pvb20gPT09IG1hcC5nZXRNaW5ab29tKCkpIHtcclxuXHRcdFx0YWRkQ2xhc3ModGhpcy5fem9vbU91dEJ1dHRvbiwgY2xhc3NOYW1lKTtcclxuXHRcdH1cclxuXHRcdGlmICh0aGlzLl9kaXNhYmxlZCB8fCBtYXAuX3pvb20gPT09IG1hcC5nZXRNYXhab29tKCkpIHtcclxuXHRcdFx0YWRkQ2xhc3ModGhpcy5fem9vbUluQnV0dG9uLCBjbGFzc05hbWUpO1xyXG5cdFx0fVxyXG5cdH1cclxufSk7XHJcblxyXG4vLyBAbmFtZXNwYWNlIE1hcFxyXG4vLyBAc2VjdGlvbiBDb250cm9sIG9wdGlvbnNcclxuLy8gQG9wdGlvbiB6b29tQ29udHJvbDogQm9vbGVhbiA9IHRydWVcclxuLy8gV2hldGhlciBhIFt6b29tIGNvbnRyb2xdKCNjb250cm9sLXpvb20pIGlzIGFkZGVkIHRvIHRoZSBtYXAgYnkgZGVmYXVsdC5cclxuTWFwLm1lcmdlT3B0aW9ucyh7XHJcblx0em9vbUNvbnRyb2w6IHRydWVcclxufSk7XHJcblxyXG5NYXAuYWRkSW5pdEhvb2soZnVuY3Rpb24gKCkge1xyXG5cdGlmICh0aGlzLm9wdGlvbnMuem9vbUNvbnRyb2wpIHtcclxuXHRcdHRoaXMuem9vbUNvbnRyb2wgPSBuZXcgWm9vbSgpO1xyXG5cdFx0dGhpcy5hZGRDb250cm9sKHRoaXMuem9vbUNvbnRyb2wpO1xyXG5cdH1cclxufSk7XHJcblxyXG4vLyBAbmFtZXNwYWNlIENvbnRyb2wuWm9vbVxyXG4vLyBAZmFjdG9yeSBMLmNvbnRyb2wuem9vbShvcHRpb25zOiBDb250cm9sLlpvb20gb3B0aW9ucylcclxuLy8gQ3JlYXRlcyBhIHpvb20gY29udHJvbFxyXG52YXIgem9vbSA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XHJcblx0cmV0dXJuIG5ldyBab29tKG9wdGlvbnMpO1xyXG59O1xuXG4vKlxuICogQGNsYXNzIENvbnRyb2wuU2NhbGVcbiAqIEBha2EgTC5Db250cm9sLlNjYWxlXG4gKiBAaW5oZXJpdHMgQ29udHJvbFxuICpcbiAqIEEgc2ltcGxlIHNjYWxlIGNvbnRyb2wgdGhhdCBzaG93cyB0aGUgc2NhbGUgb2YgdGhlIGN1cnJlbnQgY2VudGVyIG9mIHNjcmVlbiBpbiBtZXRyaWMgKG0va20pIGFuZCBpbXBlcmlhbCAobWkvZnQpIHN5c3RlbXMuIEV4dGVuZHMgYENvbnRyb2xgLlxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogYGBganNcbiAqIEwuY29udHJvbC5zY2FsZSgpLmFkZFRvKG1hcCk7XG4gKiBgYGBcbiAqL1xuXG52YXIgU2NhbGUgPSBDb250cm9sLmV4dGVuZCh7XG5cdC8vIEBzZWN0aW9uXG5cdC8vIEBha2EgQ29udHJvbC5TY2FsZSBvcHRpb25zXG5cdG9wdGlvbnM6IHtcblx0XHRwb3NpdGlvbjogJ2JvdHRvbWxlZnQnLFxuXG5cdFx0Ly8gQG9wdGlvbiBtYXhXaWR0aDogTnVtYmVyID0gMTAwXG5cdFx0Ly8gTWF4aW11bSB3aWR0aCBvZiB0aGUgY29udHJvbCBpbiBwaXhlbHMuIFRoZSB3aWR0aCBpcyBzZXQgZHluYW1pY2FsbHkgdG8gc2hvdyByb3VuZCB2YWx1ZXMgKGUuZy4gMTAwLCAyMDAsIDUwMCkuXG5cdFx0bWF4V2lkdGg6IDEwMCxcblxuXHRcdC8vIEBvcHRpb24gbWV0cmljOiBCb29sZWFuID0gVHJ1ZVxuXHRcdC8vIFdoZXRoZXIgdG8gc2hvdyB0aGUgbWV0cmljIHNjYWxlIGxpbmUgKG0va20pLlxuXHRcdG1ldHJpYzogdHJ1ZSxcblxuXHRcdC8vIEBvcHRpb24gaW1wZXJpYWw6IEJvb2xlYW4gPSBUcnVlXG5cdFx0Ly8gV2hldGhlciB0byBzaG93IHRoZSBpbXBlcmlhbCBzY2FsZSBsaW5lIChtaS9mdCkuXG5cdFx0aW1wZXJpYWw6IHRydWVcblxuXHRcdC8vIEBvcHRpb24gdXBkYXRlV2hlbklkbGU6IEJvb2xlYW4gPSBmYWxzZVxuXHRcdC8vIElmIGB0cnVlYCwgdGhlIGNvbnRyb2wgaXMgdXBkYXRlZCBvbiBbYG1vdmVlbmRgXSgjbWFwLW1vdmVlbmQpLCBvdGhlcndpc2UgaXQncyBhbHdheXMgdXAtdG8tZGF0ZSAodXBkYXRlZCBvbiBbYG1vdmVgXSgjbWFwLW1vdmUpKS5cblx0fSxcblxuXHRvbkFkZDogZnVuY3Rpb24gKG1hcCkge1xuXHRcdHZhciBjbGFzc05hbWUgPSAnbGVhZmxldC1jb250cm9sLXNjYWxlJyxcblx0XHQgICAgY29udGFpbmVyID0gY3JlYXRlJDEoJ2RpdicsIGNsYXNzTmFtZSksXG5cdFx0ICAgIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHR0aGlzLl9hZGRTY2FsZXMob3B0aW9ucywgY2xhc3NOYW1lICsgJy1saW5lJywgY29udGFpbmVyKTtcblxuXHRcdG1hcC5vbihvcHRpb25zLnVwZGF0ZVdoZW5JZGxlID8gJ21vdmVlbmQnIDogJ21vdmUnLCB0aGlzLl91cGRhdGUsIHRoaXMpO1xuXHRcdG1hcC53aGVuUmVhZHkodGhpcy5fdXBkYXRlLCB0aGlzKTtcblxuXHRcdHJldHVybiBjb250YWluZXI7XG5cdH0sXG5cblx0b25SZW1vdmU6IGZ1bmN0aW9uIChtYXApIHtcblx0XHRtYXAub2ZmKHRoaXMub3B0aW9ucy51cGRhdGVXaGVuSWRsZSA/ICdtb3ZlZW5kJyA6ICdtb3ZlJywgdGhpcy5fdXBkYXRlLCB0aGlzKTtcblx0fSxcblxuXHRfYWRkU2NhbGVzOiBmdW5jdGlvbiAob3B0aW9ucywgY2xhc3NOYW1lLCBjb250YWluZXIpIHtcblx0XHRpZiAob3B0aW9ucy5tZXRyaWMpIHtcblx0XHRcdHRoaXMuX21TY2FsZSA9IGNyZWF0ZSQxKCdkaXYnLCBjbGFzc05hbWUsIGNvbnRhaW5lcik7XG5cdFx0fVxuXHRcdGlmIChvcHRpb25zLmltcGVyaWFsKSB7XG5cdFx0XHR0aGlzLl9pU2NhbGUgPSBjcmVhdGUkMSgnZGl2JywgY2xhc3NOYW1lLCBjb250YWluZXIpO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIG1hcCA9IHRoaXMuX21hcCxcblx0XHQgICAgeSA9IG1hcC5nZXRTaXplKCkueSAvIDI7XG5cblx0XHR2YXIgbWF4TWV0ZXJzID0gbWFwLmRpc3RhbmNlKFxuXHRcdFx0bWFwLmNvbnRhaW5lclBvaW50VG9MYXRMbmcoWzAsIHldKSxcblx0XHRcdG1hcC5jb250YWluZXJQb2ludFRvTGF0TG5nKFt0aGlzLm9wdGlvbnMubWF4V2lkdGgsIHldKSk7XG5cblx0XHR0aGlzLl91cGRhdGVTY2FsZXMobWF4TWV0ZXJzKTtcblx0fSxcblxuXHRfdXBkYXRlU2NhbGVzOiBmdW5jdGlvbiAobWF4TWV0ZXJzKSB7XG5cdFx0aWYgKHRoaXMub3B0aW9ucy5tZXRyaWMgJiYgbWF4TWV0ZXJzKSB7XG5cdFx0XHR0aGlzLl91cGRhdGVNZXRyaWMobWF4TWV0ZXJzKTtcblx0XHR9XG5cdFx0aWYgKHRoaXMub3B0aW9ucy5pbXBlcmlhbCAmJiBtYXhNZXRlcnMpIHtcblx0XHRcdHRoaXMuX3VwZGF0ZUltcGVyaWFsKG1heE1ldGVycyk7XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGVNZXRyaWM6IGZ1bmN0aW9uIChtYXhNZXRlcnMpIHtcblx0XHR2YXIgbWV0ZXJzID0gdGhpcy5fZ2V0Um91bmROdW0obWF4TWV0ZXJzKSxcblx0XHQgICAgbGFiZWwgPSBtZXRlcnMgPCAxMDAwID8gbWV0ZXJzICsgJyBtJyA6IChtZXRlcnMgLyAxMDAwKSArICcga20nO1xuXG5cdFx0dGhpcy5fdXBkYXRlU2NhbGUodGhpcy5fbVNjYWxlLCBsYWJlbCwgbWV0ZXJzIC8gbWF4TWV0ZXJzKTtcblx0fSxcblxuXHRfdXBkYXRlSW1wZXJpYWw6IGZ1bmN0aW9uIChtYXhNZXRlcnMpIHtcblx0XHR2YXIgbWF4RmVldCA9IG1heE1ldGVycyAqIDMuMjgwODM5OSxcblx0XHQgICAgbWF4TWlsZXMsIG1pbGVzLCBmZWV0O1xuXG5cdFx0aWYgKG1heEZlZXQgPiA1MjgwKSB7XG5cdFx0XHRtYXhNaWxlcyA9IG1heEZlZXQgLyA1MjgwO1xuXHRcdFx0bWlsZXMgPSB0aGlzLl9nZXRSb3VuZE51bShtYXhNaWxlcyk7XG5cdFx0XHR0aGlzLl91cGRhdGVTY2FsZSh0aGlzLl9pU2NhbGUsIG1pbGVzICsgJyBtaScsIG1pbGVzIC8gbWF4TWlsZXMpO1xuXG5cdFx0fSBlbHNlIHtcblx0XHRcdGZlZXQgPSB0aGlzLl9nZXRSb3VuZE51bShtYXhGZWV0KTtcblx0XHRcdHRoaXMuX3VwZGF0ZVNjYWxlKHRoaXMuX2lTY2FsZSwgZmVldCArICcgZnQnLCBmZWV0IC8gbWF4RmVldCk7XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGVTY2FsZTogZnVuY3Rpb24gKHNjYWxlLCB0ZXh0LCByYXRpbykge1xuXHRcdHNjYWxlLnN0eWxlLndpZHRoID0gTWF0aC5yb3VuZCh0aGlzLm9wdGlvbnMubWF4V2lkdGggKiByYXRpbykgKyAncHgnO1xuXHRcdHNjYWxlLmlubmVySFRNTCA9IHRleHQ7XG5cdH0sXG5cblx0X2dldFJvdW5kTnVtOiBmdW5jdGlvbiAobnVtKSB7XG5cdFx0dmFyIHBvdzEwID0gTWF0aC5wb3coMTAsIChNYXRoLmZsb29yKG51bSkgKyAnJykubGVuZ3RoIC0gMSksXG5cdFx0ICAgIGQgPSBudW0gLyBwb3cxMDtcblxuXHRcdGQgPSBkID49IDEwID8gMTAgOlxuXHRcdCAgICBkID49IDUgPyA1IDpcblx0XHQgICAgZCA+PSAzID8gMyA6XG5cdFx0ICAgIGQgPj0gMiA/IDIgOiAxO1xuXG5cdFx0cmV0dXJuIHBvdzEwICogZDtcblx0fVxufSk7XG5cblxuLy8gQGZhY3RvcnkgTC5jb250cm9sLnNjYWxlKG9wdGlvbnM/OiBDb250cm9sLlNjYWxlIG9wdGlvbnMpXG4vLyBDcmVhdGVzIGFuIHNjYWxlIGNvbnRyb2wgd2l0aCB0aGUgZ2l2ZW4gb3B0aW9ucy5cbnZhciBzY2FsZSA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG5cdHJldHVybiBuZXcgU2NhbGUob3B0aW9ucyk7XG59O1xuXG4vKlxyXG4gKiBAY2xhc3MgQ29udHJvbC5BdHRyaWJ1dGlvblxyXG4gKiBAYWthIEwuQ29udHJvbC5BdHRyaWJ1dGlvblxyXG4gKiBAaW5oZXJpdHMgQ29udHJvbFxyXG4gKlxyXG4gKiBUaGUgYXR0cmlidXRpb24gY29udHJvbCBhbGxvd3MgeW91IHRvIGRpc3BsYXkgYXR0cmlidXRpb24gZGF0YSBpbiBhIHNtYWxsIHRleHQgYm94IG9uIGEgbWFwLiBJdCBpcyBwdXQgb24gdGhlIG1hcCBieSBkZWZhdWx0IHVubGVzcyB5b3Ugc2V0IGl0cyBbYGF0dHJpYnV0aW9uQ29udHJvbGAgb3B0aW9uXSgjbWFwLWF0dHJpYnV0aW9uY29udHJvbCkgdG8gYGZhbHNlYCwgYW5kIGl0IGZldGNoZXMgYXR0cmlidXRpb24gdGV4dHMgZnJvbSBsYXllcnMgd2l0aCB0aGUgW2BnZXRBdHRyaWJ1dGlvbmAgbWV0aG9kXSgjbGF5ZXItZ2V0YXR0cmlidXRpb24pIGF1dG9tYXRpY2FsbHkuIEV4dGVuZHMgQ29udHJvbC5cclxuICovXHJcblxyXG52YXIgQXR0cmlidXRpb24gPSBDb250cm9sLmV4dGVuZCh7XHJcblx0Ly8gQHNlY3Rpb25cclxuXHQvLyBAYWthIENvbnRyb2wuQXR0cmlidXRpb24gb3B0aW9uc1xyXG5cdG9wdGlvbnM6IHtcclxuXHRcdHBvc2l0aW9uOiAnYm90dG9tcmlnaHQnLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gcHJlZml4OiBTdHJpbmcgPSAnTGVhZmxldCdcclxuXHRcdC8vIFRoZSBIVE1MIHRleHQgc2hvd24gYmVmb3JlIHRoZSBhdHRyaWJ1dGlvbnMuIFBhc3MgYGZhbHNlYCB0byBkaXNhYmxlLlxyXG5cdFx0cHJlZml4OiAnPGEgaHJlZj1cImh0dHA6Ly9sZWFmbGV0anMuY29tXCIgdGl0bGU9XCJBIEpTIGxpYnJhcnkgZm9yIGludGVyYWN0aXZlIG1hcHNcIj5MZWFmbGV0PC9hPidcclxuXHR9LFxyXG5cclxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xyXG5cdFx0c2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcclxuXHJcblx0XHR0aGlzLl9hdHRyaWJ1dGlvbnMgPSB7fTtcclxuXHR9LFxyXG5cclxuXHRvbkFkZDogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0bWFwLmF0dHJpYnV0aW9uQ29udHJvbCA9IHRoaXM7XHJcblx0XHR0aGlzLl9jb250YWluZXIgPSBjcmVhdGUkMSgnZGl2JywgJ2xlYWZsZXQtY29udHJvbC1hdHRyaWJ1dGlvbicpO1xyXG5cdFx0ZGlzYWJsZUNsaWNrUHJvcGFnYXRpb24odGhpcy5fY29udGFpbmVyKTtcclxuXHJcblx0XHQvLyBUT0RPIHVnbHksIHJlZmFjdG9yXHJcblx0XHRmb3IgKHZhciBpIGluIG1hcC5fbGF5ZXJzKSB7XHJcblx0XHRcdGlmIChtYXAuX2xheWVyc1tpXS5nZXRBdHRyaWJ1dGlvbikge1xyXG5cdFx0XHRcdHRoaXMuYWRkQXR0cmlidXRpb24obWFwLl9sYXllcnNbaV0uZ2V0QXR0cmlidXRpb24oKSk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl91cGRhdGUoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fY29udGFpbmVyO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0UHJlZml4KHByZWZpeDogU3RyaW5nKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIHRleHQgYmVmb3JlIHRoZSBhdHRyaWJ1dGlvbnMuXHJcblx0c2V0UHJlZml4OiBmdW5jdGlvbiAocHJlZml4KSB7XHJcblx0XHR0aGlzLm9wdGlvbnMucHJlZml4ID0gcHJlZml4O1xyXG5cdFx0dGhpcy5fdXBkYXRlKCk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGFkZEF0dHJpYnV0aW9uKHRleHQ6IFN0cmluZyk6IHRoaXNcclxuXHQvLyBBZGRzIGFuIGF0dHJpYnV0aW9uIHRleHQgKGUuZy4gYCdWZWN0b3IgZGF0YSAmY29weTsgTWFwYm94J2ApLlxyXG5cdGFkZEF0dHJpYnV0aW9uOiBmdW5jdGlvbiAodGV4dCkge1xyXG5cdFx0aWYgKCF0ZXh0KSB7IHJldHVybiB0aGlzOyB9XHJcblxyXG5cdFx0aWYgKCF0aGlzLl9hdHRyaWJ1dGlvbnNbdGV4dF0pIHtcclxuXHRcdFx0dGhpcy5fYXR0cmlidXRpb25zW3RleHRdID0gMDtcclxuXHRcdH1cclxuXHRcdHRoaXMuX2F0dHJpYnV0aW9uc1t0ZXh0XSsrO1xyXG5cclxuXHRcdHRoaXMuX3VwZGF0ZSgpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgcmVtb3ZlQXR0cmlidXRpb24odGV4dDogU3RyaW5nKTogdGhpc1xyXG5cdC8vIFJlbW92ZXMgYW4gYXR0cmlidXRpb24gdGV4dC5cclxuXHRyZW1vdmVBdHRyaWJ1dGlvbjogZnVuY3Rpb24gKHRleHQpIHtcclxuXHRcdGlmICghdGV4dCkgeyByZXR1cm4gdGhpczsgfVxyXG5cclxuXHRcdGlmICh0aGlzLl9hdHRyaWJ1dGlvbnNbdGV4dF0pIHtcclxuXHRcdFx0dGhpcy5fYXR0cmlidXRpb25zW3RleHRdLS07XHJcblx0XHRcdHRoaXMuX3VwZGF0ZSgpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdF91cGRhdGU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICghdGhpcy5fbWFwKSB7IHJldHVybjsgfVxyXG5cclxuXHRcdHZhciBhdHRyaWJzID0gW107XHJcblxyXG5cdFx0Zm9yICh2YXIgaSBpbiB0aGlzLl9hdHRyaWJ1dGlvbnMpIHtcclxuXHRcdFx0aWYgKHRoaXMuX2F0dHJpYnV0aW9uc1tpXSkge1xyXG5cdFx0XHRcdGF0dHJpYnMucHVzaChpKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBwcmVmaXhBbmRBdHRyaWJzID0gW107XHJcblxyXG5cdFx0aWYgKHRoaXMub3B0aW9ucy5wcmVmaXgpIHtcclxuXHRcdFx0cHJlZml4QW5kQXR0cmlicy5wdXNoKHRoaXMub3B0aW9ucy5wcmVmaXgpO1xyXG5cdFx0fVxyXG5cdFx0aWYgKGF0dHJpYnMubGVuZ3RoKSB7XHJcblx0XHRcdHByZWZpeEFuZEF0dHJpYnMucHVzaChhdHRyaWJzLmpvaW4oJywgJykpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2NvbnRhaW5lci5pbm5lckhUTUwgPSBwcmVmaXhBbmRBdHRyaWJzLmpvaW4oJyB8ICcpO1xyXG5cdH1cclxufSk7XHJcblxyXG4vLyBAbmFtZXNwYWNlIE1hcFxyXG4vLyBAc2VjdGlvbiBDb250cm9sIG9wdGlvbnNcclxuLy8gQG9wdGlvbiBhdHRyaWJ1dGlvbkNvbnRyb2w6IEJvb2xlYW4gPSB0cnVlXHJcbi8vIFdoZXRoZXIgYSBbYXR0cmlidXRpb24gY29udHJvbF0oI2NvbnRyb2wtYXR0cmlidXRpb24pIGlzIGFkZGVkIHRvIHRoZSBtYXAgYnkgZGVmYXVsdC5cclxuTWFwLm1lcmdlT3B0aW9ucyh7XHJcblx0YXR0cmlidXRpb25Db250cm9sOiB0cnVlXHJcbn0pO1xyXG5cclxuTWFwLmFkZEluaXRIb29rKGZ1bmN0aW9uICgpIHtcclxuXHRpZiAodGhpcy5vcHRpb25zLmF0dHJpYnV0aW9uQ29udHJvbCkge1xyXG5cdFx0bmV3IEF0dHJpYnV0aW9uKCkuYWRkVG8odGhpcyk7XHJcblx0fVxyXG59KTtcclxuXHJcbi8vIEBuYW1lc3BhY2UgQ29udHJvbC5BdHRyaWJ1dGlvblxyXG4vLyBAZmFjdG9yeSBMLmNvbnRyb2wuYXR0cmlidXRpb24ob3B0aW9uczogQ29udHJvbC5BdHRyaWJ1dGlvbiBvcHRpb25zKVxyXG4vLyBDcmVhdGVzIGFuIGF0dHJpYnV0aW9uIGNvbnRyb2wuXHJcbnZhciBhdHRyaWJ1dGlvbiA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XHJcblx0cmV0dXJuIG5ldyBBdHRyaWJ1dGlvbihvcHRpb25zKTtcclxufTtcblxuQ29udHJvbC5MYXllcnMgPSBMYXllcnM7XG5Db250cm9sLlpvb20gPSBab29tO1xuQ29udHJvbC5TY2FsZSA9IFNjYWxlO1xuQ29udHJvbC5BdHRyaWJ1dGlvbiA9IEF0dHJpYnV0aW9uO1xuXG5jb250cm9sLmxheWVycyA9IGxheWVycztcbmNvbnRyb2wuem9vbSA9IHpvb207XG5jb250cm9sLnNjYWxlID0gc2NhbGU7XG5jb250cm9sLmF0dHJpYnV0aW9uID0gYXR0cmlidXRpb247XG5cbi8qXG5cdEwuSGFuZGxlciBpcyBhIGJhc2UgY2xhc3MgZm9yIGhhbmRsZXIgY2xhc3NlcyB0aGF0IGFyZSB1c2VkIGludGVybmFsbHkgdG8gaW5qZWN0XG5cdGludGVyYWN0aW9uIGZlYXR1cmVzIGxpa2UgZHJhZ2dpbmcgdG8gY2xhc3NlcyBsaWtlIE1hcCBhbmQgTWFya2VyLlxuKi9cblxuLy8gQGNsYXNzIEhhbmRsZXJcbi8vIEBha2EgTC5IYW5kbGVyXG4vLyBBYnN0cmFjdCBjbGFzcyBmb3IgbWFwIGludGVyYWN0aW9uIGhhbmRsZXJzXG5cbnZhciBIYW5kbGVyID0gQ2xhc3MuZXh0ZW5kKHtcblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKG1hcCkge1xuXHRcdHRoaXMuX21hcCA9IG1hcDtcblx0fSxcblxuXHQvLyBAbWV0aG9kIGVuYWJsZSgpOiB0aGlzXG5cdC8vIEVuYWJsZXMgdGhlIGhhbmRsZXJcblx0ZW5hYmxlOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX2VuYWJsZWQpIHsgcmV0dXJuIHRoaXM7IH1cblxuXHRcdHRoaXMuX2VuYWJsZWQgPSB0cnVlO1xuXHRcdHRoaXMuYWRkSG9va3MoKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIGRpc2FibGUoKTogdGhpc1xuXHQvLyBEaXNhYmxlcyB0aGUgaGFuZGxlclxuXHRkaXNhYmxlOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKCF0aGlzLl9lbmFibGVkKSB7IHJldHVybiB0aGlzOyB9XG5cblx0XHR0aGlzLl9lbmFibGVkID0gZmFsc2U7XG5cdFx0dGhpcy5yZW1vdmVIb29rcygpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgZW5hYmxlZCgpOiBCb29sZWFuXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSBoYW5kbGVyIGlzIGVuYWJsZWRcblx0ZW5hYmxlZDogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiAhIXRoaXMuX2VuYWJsZWQ7XG5cdH1cblxuXHQvLyBAc2VjdGlvbiBFeHRlbnNpb24gbWV0aG9kc1xuXHQvLyBDbGFzc2VzIGluaGVyaXRpbmcgZnJvbSBgSGFuZGxlcmAgbXVzdCBpbXBsZW1lbnQgdGhlIHR3byBmb2xsb3dpbmcgbWV0aG9kczpcblx0Ly8gQG1ldGhvZCBhZGRIb29rcygpXG5cdC8vIENhbGxlZCB3aGVuIHRoZSBoYW5kbGVyIGlzIGVuYWJsZWQsIHNob3VsZCBhZGQgZXZlbnQgaG9va3MuXG5cdC8vIEBtZXRob2QgcmVtb3ZlSG9va3MoKVxuXHQvLyBDYWxsZWQgd2hlbiB0aGUgaGFuZGxlciBpcyBkaXNhYmxlZCwgc2hvdWxkIHJlbW92ZSB0aGUgZXZlbnQgaG9va3MgYWRkZWQgcHJldmlvdXNseS5cbn0pO1xuXG4vLyBAc2VjdGlvbiBUaGVyZSBpcyBzdGF0aWMgZnVuY3Rpb24gd2hpY2ggY2FuIGJlIGNhbGxlZCB3aXRob3V0IGluc3RhbnRpYXRpbmcgTC5IYW5kbGVyOlxuLy8gQGZ1bmN0aW9uIGFkZFRvKG1hcDogTWFwLCBuYW1lOiBTdHJpbmcpOiB0aGlzXG4vLyBBZGRzIGEgbmV3IEhhbmRsZXIgdG8gdGhlIGdpdmVuIG1hcCB3aXRoIHRoZSBnaXZlbiBuYW1lLlxuSGFuZGxlci5hZGRUbyA9IGZ1bmN0aW9uIChtYXAsIG5hbWUpIHtcblx0bWFwLmFkZEhhbmRsZXIobmFtZSwgdGhpcyk7XG5cdHJldHVybiB0aGlzO1xufTtcblxudmFyIE1peGluID0ge0V2ZW50czogRXZlbnRzfTtcblxuLypcclxuICogQGNsYXNzIERyYWdnYWJsZVxyXG4gKiBAYWthIEwuRHJhZ2dhYmxlXHJcbiAqIEBpbmhlcml0cyBFdmVudGVkXHJcbiAqXHJcbiAqIEEgY2xhc3MgZm9yIG1ha2luZyBET00gZWxlbWVudHMgZHJhZ2dhYmxlIChpbmNsdWRpbmcgdG91Y2ggc3VwcG9ydCkuXHJcbiAqIFVzZWQgaW50ZXJuYWxseSBmb3IgbWFwIGFuZCBtYXJrZXIgZHJhZ2dpbmcuIE9ubHkgd29ya3MgZm9yIGVsZW1lbnRzXHJcbiAqIHRoYXQgd2VyZSBwb3NpdGlvbmVkIHdpdGggW2BMLkRvbVV0aWwuc2V0UG9zaXRpb25gXSgjZG9tdXRpbC1zZXRwb3NpdGlvbikuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIGBgYGpzXHJcbiAqIHZhciBkcmFnZ2FibGUgPSBuZXcgTC5EcmFnZ2FibGUoZWxlbWVudFRvRHJhZyk7XHJcbiAqIGRyYWdnYWJsZS5lbmFibGUoKTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxudmFyIFNUQVJUID0gdG91Y2ggPyAndG91Y2hzdGFydCBtb3VzZWRvd24nIDogJ21vdXNlZG93bic7XHJcbnZhciBFTkQgPSB7XHJcblx0bW91c2Vkb3duOiAnbW91c2V1cCcsXHJcblx0dG91Y2hzdGFydDogJ3RvdWNoZW5kJyxcclxuXHRwb2ludGVyZG93bjogJ3RvdWNoZW5kJyxcclxuXHRNU1BvaW50ZXJEb3duOiAndG91Y2hlbmQnXHJcbn07XHJcbnZhciBNT1ZFID0ge1xyXG5cdG1vdXNlZG93bjogJ21vdXNlbW92ZScsXHJcblx0dG91Y2hzdGFydDogJ3RvdWNobW92ZScsXHJcblx0cG9pbnRlcmRvd246ICd0b3VjaG1vdmUnLFxyXG5cdE1TUG9pbnRlckRvd246ICd0b3VjaG1vdmUnXHJcbn07XHJcblxyXG5cclxudmFyIERyYWdnYWJsZSA9IEV2ZW50ZWQuZXh0ZW5kKHtcclxuXHJcblx0b3B0aW9uczoge1xyXG5cdFx0Ly8gQHNlY3Rpb25cclxuXHRcdC8vIEBha2EgRHJhZ2dhYmxlIG9wdGlvbnNcclxuXHRcdC8vIEBvcHRpb24gY2xpY2tUb2xlcmFuY2U6IE51bWJlciA9IDNcclxuXHRcdC8vIFRoZSBtYXggbnVtYmVyIG9mIHBpeGVscyBhIHVzZXIgY2FuIHNoaWZ0IHRoZSBtb3VzZSBwb2ludGVyIGR1cmluZyBhIGNsaWNrXHJcblx0XHQvLyBmb3IgaXQgdG8gYmUgY29uc2lkZXJlZCBhIHZhbGlkIGNsaWNrIChhcyBvcHBvc2VkIHRvIGEgbW91c2UgZHJhZykuXHJcblx0XHRjbGlja1RvbGVyYW5jZTogM1xyXG5cdH0sXHJcblxyXG5cdC8vIEBjb25zdHJ1Y3RvciBMLkRyYWdnYWJsZShlbDogSFRNTEVsZW1lbnQsIGRyYWdIYW5kbGU/OiBIVE1MRWxlbWVudCwgcHJldmVudE91dGxpbmU/OiBCb29sZWFuLCBvcHRpb25zPzogRHJhZ2dhYmxlIG9wdGlvbnMpXHJcblx0Ly8gQ3JlYXRlcyBhIGBEcmFnZ2FibGVgIG9iamVjdCBmb3IgbW92aW5nIGBlbGAgd2hlbiB5b3Ugc3RhcnQgZHJhZ2dpbmcgdGhlIGBkcmFnSGFuZGxlYCBlbGVtZW50IChlcXVhbHMgYGVsYCBpdHNlbGYgYnkgZGVmYXVsdCkuXHJcblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKGVsZW1lbnQsIGRyYWdTdGFydFRhcmdldCwgcHJldmVudE91dGxpbmUkJDEsIG9wdGlvbnMpIHtcclxuXHRcdHNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XHJcblxyXG5cdFx0dGhpcy5fZWxlbWVudCA9IGVsZW1lbnQ7XHJcblx0XHR0aGlzLl9kcmFnU3RhcnRUYXJnZXQgPSBkcmFnU3RhcnRUYXJnZXQgfHwgZWxlbWVudDtcclxuXHRcdHRoaXMuX3ByZXZlbnRPdXRsaW5lID0gcHJldmVudE91dGxpbmUkJDE7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBlbmFibGUoKVxyXG5cdC8vIEVuYWJsZXMgdGhlIGRyYWdnaW5nIGFiaWxpdHlcclxuXHRlbmFibGU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICh0aGlzLl9lbmFibGVkKSB7IHJldHVybjsgfVxyXG5cclxuXHRcdG9uKHRoaXMuX2RyYWdTdGFydFRhcmdldCwgU1RBUlQsIHRoaXMuX29uRG93biwgdGhpcyk7XHJcblxyXG5cdFx0dGhpcy5fZW5hYmxlZCA9IHRydWU7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBkaXNhYmxlKClcclxuXHQvLyBEaXNhYmxlcyB0aGUgZHJhZ2dpbmcgYWJpbGl0eVxyXG5cdGRpc2FibGU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICghdGhpcy5fZW5hYmxlZCkgeyByZXR1cm47IH1cclxuXHJcblx0XHQvLyBJZiB3ZSdyZSBjdXJyZW50bHkgZHJhZ2dpbmcgdGhpcyBkcmFnZ2FibGUsXHJcblx0XHQvLyBkaXNhYmxpbmcgaXQgY291bnRzIGFzIGZpcnN0IGVuZGluZyB0aGUgZHJhZy5cclxuXHRcdGlmIChEcmFnZ2FibGUuX2RyYWdnaW5nID09PSB0aGlzKSB7XHJcblx0XHRcdHRoaXMuZmluaXNoRHJhZygpO1xyXG5cdFx0fVxyXG5cclxuXHRcdG9mZih0aGlzLl9kcmFnU3RhcnRUYXJnZXQsIFNUQVJULCB0aGlzLl9vbkRvd24sIHRoaXMpO1xyXG5cclxuXHRcdHRoaXMuX2VuYWJsZWQgPSBmYWxzZTtcclxuXHRcdHRoaXMuX21vdmVkID0gZmFsc2U7XHJcblx0fSxcclxuXHJcblx0X29uRG93bjogZnVuY3Rpb24gKGUpIHtcclxuXHRcdC8vIElnbm9yZSBzaW11bGF0ZWQgZXZlbnRzLCBzaW5jZSB3ZSBoYW5kbGUgYm90aCB0b3VjaCBhbmRcclxuXHRcdC8vIG1vdXNlIGV4cGxpY2l0bHk7IG90aGVyd2lzZSB3ZSByaXNrIGdldHRpbmcgZHVwbGljYXRlcyBvZlxyXG5cdFx0Ly8gdG91Y2ggZXZlbnRzLCBzZWUgIzQzMTUuXHJcblx0XHQvLyBBbHNvIGlnbm9yZSB0aGUgZXZlbnQgaWYgZGlzYWJsZWQ7IHRoaXMgaGFwcGVucyBpbiBJRTExXHJcblx0XHQvLyB1bmRlciBzb21lIGNpcmN1bXN0YW5jZXMsIHNlZSAjMzY2Ni5cclxuXHRcdGlmIChlLl9zaW11bGF0ZWQgfHwgIXRoaXMuX2VuYWJsZWQpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0dGhpcy5fbW92ZWQgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAoaGFzQ2xhc3ModGhpcy5fZWxlbWVudCwgJ2xlYWZsZXQtem9vbS1hbmltJykpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0aWYgKERyYWdnYWJsZS5fZHJhZ2dpbmcgfHwgZS5zaGlmdEtleSB8fCAoKGUud2hpY2ggIT09IDEpICYmIChlLmJ1dHRvbiAhPT0gMSkgJiYgIWUudG91Y2hlcykpIHsgcmV0dXJuOyB9XHJcblx0XHREcmFnZ2FibGUuX2RyYWdnaW5nID0gdGhpczsgIC8vIFByZXZlbnQgZHJhZ2dpbmcgbXVsdGlwbGUgb2JqZWN0cyBhdCBvbmNlLlxyXG5cclxuXHRcdGlmICh0aGlzLl9wcmV2ZW50T3V0bGluZSkge1xyXG5cdFx0XHRwcmV2ZW50T3V0bGluZSh0aGlzLl9lbGVtZW50KTtcclxuXHRcdH1cclxuXHJcblx0XHRkaXNhYmxlSW1hZ2VEcmFnKCk7XHJcblx0XHRkaXNhYmxlVGV4dFNlbGVjdGlvbigpO1xyXG5cclxuXHRcdGlmICh0aGlzLl9tb3ZpbmcpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0Ly8gQGV2ZW50IGRvd246IEV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIGEgZHJhZyBpcyBhYm91dCB0byBzdGFydC5cclxuXHRcdHRoaXMuZmlyZSgnZG93bicpO1xyXG5cclxuXHRcdHZhciBmaXJzdCA9IGUudG91Y2hlcyA/IGUudG91Y2hlc1swXSA6IGU7XHJcblxyXG5cdFx0dGhpcy5fc3RhcnRQb2ludCA9IG5ldyBQb2ludChmaXJzdC5jbGllbnRYLCBmaXJzdC5jbGllbnRZKTtcclxuXHJcblx0XHRvbihkb2N1bWVudCwgTU9WRVtlLnR5cGVdLCB0aGlzLl9vbk1vdmUsIHRoaXMpO1xyXG5cdFx0b24oZG9jdW1lbnQsIEVORFtlLnR5cGVdLCB0aGlzLl9vblVwLCB0aGlzKTtcclxuXHR9LFxyXG5cclxuXHRfb25Nb3ZlOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0Ly8gSWdub3JlIHNpbXVsYXRlZCBldmVudHMsIHNpbmNlIHdlIGhhbmRsZSBib3RoIHRvdWNoIGFuZFxyXG5cdFx0Ly8gbW91c2UgZXhwbGljaXRseTsgb3RoZXJ3aXNlIHdlIHJpc2sgZ2V0dGluZyBkdXBsaWNhdGVzIG9mXHJcblx0XHQvLyB0b3VjaCBldmVudHMsIHNlZSAjNDMxNS5cclxuXHRcdC8vIEFsc28gaWdub3JlIHRoZSBldmVudCBpZiBkaXNhYmxlZDsgdGhpcyBoYXBwZW5zIGluIElFMTFcclxuXHRcdC8vIHVuZGVyIHNvbWUgY2lyY3Vtc3RhbmNlcywgc2VlICMzNjY2LlxyXG5cdFx0aWYgKGUuX3NpbXVsYXRlZCB8fCAhdGhpcy5fZW5hYmxlZCkgeyByZXR1cm47IH1cclxuXHJcblx0XHRpZiAoZS50b3VjaGVzICYmIGUudG91Y2hlcy5sZW5ndGggPiAxKSB7XHJcblx0XHRcdHRoaXMuX21vdmVkID0gdHJ1ZTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBmaXJzdCA9IChlLnRvdWNoZXMgJiYgZS50b3VjaGVzLmxlbmd0aCA9PT0gMSA/IGUudG91Y2hlc1swXSA6IGUpLFxyXG5cdFx0ICAgIG5ld1BvaW50ID0gbmV3IFBvaW50KGZpcnN0LmNsaWVudFgsIGZpcnN0LmNsaWVudFkpLFxyXG5cdFx0ICAgIG9mZnNldCA9IG5ld1BvaW50LnN1YnRyYWN0KHRoaXMuX3N0YXJ0UG9pbnQpO1xyXG5cclxuXHRcdGlmICghb2Zmc2V0LnggJiYgIW9mZnNldC55KSB7IHJldHVybjsgfVxyXG5cdFx0aWYgKE1hdGguYWJzKG9mZnNldC54KSArIE1hdGguYWJzKG9mZnNldC55KSA8IHRoaXMub3B0aW9ucy5jbGlja1RvbGVyYW5jZSkgeyByZXR1cm47IH1cclxuXHJcblx0XHRwcmV2ZW50RGVmYXVsdChlKTtcclxuXHJcblx0XHRpZiAoIXRoaXMuX21vdmVkKSB7XHJcblx0XHRcdC8vIEBldmVudCBkcmFnc3RhcnQ6IEV2ZW50XHJcblx0XHRcdC8vIEZpcmVkIHdoZW4gYSBkcmFnIHN0YXJ0c1xyXG5cdFx0XHR0aGlzLmZpcmUoJ2RyYWdzdGFydCcpO1xyXG5cclxuXHRcdFx0dGhpcy5fbW92ZWQgPSB0cnVlO1xyXG5cdFx0XHR0aGlzLl9zdGFydFBvcyA9IGdldFBvc2l0aW9uKHRoaXMuX2VsZW1lbnQpLnN1YnRyYWN0KG9mZnNldCk7XHJcblxyXG5cdFx0XHRhZGRDbGFzcyhkb2N1bWVudC5ib2R5LCAnbGVhZmxldC1kcmFnZ2luZycpO1xyXG5cclxuXHRcdFx0dGhpcy5fbGFzdFRhcmdldCA9IGUudGFyZ2V0IHx8IGUuc3JjRWxlbWVudDtcclxuXHRcdFx0Ly8gSUUgYW5kIEVkZ2UgZG8gbm90IGdpdmUgdGhlIDx1c2U+IGVsZW1lbnQsIHNvIGZldGNoIGl0XHJcblx0XHRcdC8vIGlmIG5lY2Vzc2FyeVxyXG5cdFx0XHRpZiAoKHdpbmRvdy5TVkdFbGVtZW50SW5zdGFuY2UpICYmICh0aGlzLl9sYXN0VGFyZ2V0IGluc3RhbmNlb2YgU1ZHRWxlbWVudEluc3RhbmNlKSkge1xyXG5cdFx0XHRcdHRoaXMuX2xhc3RUYXJnZXQgPSB0aGlzLl9sYXN0VGFyZ2V0LmNvcnJlc3BvbmRpbmdVc2VFbGVtZW50O1xyXG5cdFx0XHR9XHJcblx0XHRcdGFkZENsYXNzKHRoaXMuX2xhc3RUYXJnZXQsICdsZWFmbGV0LWRyYWctdGFyZ2V0Jyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fbmV3UG9zID0gdGhpcy5fc3RhcnRQb3MuYWRkKG9mZnNldCk7XHJcblx0XHR0aGlzLl9tb3ZpbmcgPSB0cnVlO1xyXG5cclxuXHRcdGNhbmNlbEFuaW1GcmFtZSh0aGlzLl9hbmltUmVxdWVzdCk7XHJcblx0XHR0aGlzLl9sYXN0RXZlbnQgPSBlO1xyXG5cdFx0dGhpcy5fYW5pbVJlcXVlc3QgPSByZXF1ZXN0QW5pbUZyYW1lKHRoaXMuX3VwZGF0ZVBvc2l0aW9uLCB0aGlzLCB0cnVlKTtcclxuXHR9LFxyXG5cclxuXHRfdXBkYXRlUG9zaXRpb246IGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBlID0ge29yaWdpbmFsRXZlbnQ6IHRoaXMuX2xhc3RFdmVudH07XHJcblxyXG5cdFx0Ly8gQGV2ZW50IHByZWRyYWc6IEV2ZW50XHJcblx0XHQvLyBGaXJlZCBjb250aW51b3VzbHkgZHVyaW5nIGRyYWdnaW5nICpiZWZvcmUqIGVhY2ggY29ycmVzcG9uZGluZ1xyXG5cdFx0Ly8gdXBkYXRlIG9mIHRoZSBlbGVtZW50J3MgcG9zaXRpb24uXHJcblx0XHR0aGlzLmZpcmUoJ3ByZWRyYWcnLCBlKTtcclxuXHRcdHNldFBvc2l0aW9uKHRoaXMuX2VsZW1lbnQsIHRoaXMuX25ld1Bvcyk7XHJcblxyXG5cdFx0Ly8gQGV2ZW50IGRyYWc6IEV2ZW50XHJcblx0XHQvLyBGaXJlZCBjb250aW51b3VzbHkgZHVyaW5nIGRyYWdnaW5nLlxyXG5cdFx0dGhpcy5maXJlKCdkcmFnJywgZSk7XHJcblx0fSxcclxuXHJcblx0X29uVXA6IGZ1bmN0aW9uIChlKSB7XHJcblx0XHQvLyBJZ25vcmUgc2ltdWxhdGVkIGV2ZW50cywgc2luY2Ugd2UgaGFuZGxlIGJvdGggdG91Y2ggYW5kXHJcblx0XHQvLyBtb3VzZSBleHBsaWNpdGx5OyBvdGhlcndpc2Ugd2UgcmlzayBnZXR0aW5nIGR1cGxpY2F0ZXMgb2ZcclxuXHRcdC8vIHRvdWNoIGV2ZW50cywgc2VlICM0MzE1LlxyXG5cdFx0Ly8gQWxzbyBpZ25vcmUgdGhlIGV2ZW50IGlmIGRpc2FibGVkOyB0aGlzIGhhcHBlbnMgaW4gSUUxMVxyXG5cdFx0Ly8gdW5kZXIgc29tZSBjaXJjdW1zdGFuY2VzLCBzZWUgIzM2NjYuXHJcblx0XHRpZiAoZS5fc2ltdWxhdGVkIHx8ICF0aGlzLl9lbmFibGVkKSB7IHJldHVybjsgfVxyXG5cdFx0dGhpcy5maW5pc2hEcmFnKCk7XHJcblx0fSxcclxuXHJcblx0ZmluaXNoRHJhZzogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmVtb3ZlQ2xhc3MoZG9jdW1lbnQuYm9keSwgJ2xlYWZsZXQtZHJhZ2dpbmcnKTtcclxuXHJcblx0XHRpZiAodGhpcy5fbGFzdFRhcmdldCkge1xyXG5cdFx0XHRyZW1vdmVDbGFzcyh0aGlzLl9sYXN0VGFyZ2V0LCAnbGVhZmxldC1kcmFnLXRhcmdldCcpO1xyXG5cdFx0XHR0aGlzLl9sYXN0VGFyZ2V0ID0gbnVsbDtcclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKHZhciBpIGluIE1PVkUpIHtcclxuXHRcdFx0b2ZmKGRvY3VtZW50LCBNT1ZFW2ldLCB0aGlzLl9vbk1vdmUsIHRoaXMpO1xyXG5cdFx0XHRvZmYoZG9jdW1lbnQsIEVORFtpXSwgdGhpcy5fb25VcCwgdGhpcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0ZW5hYmxlSW1hZ2VEcmFnKCk7XHJcblx0XHRlbmFibGVUZXh0U2VsZWN0aW9uKCk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX21vdmVkICYmIHRoaXMuX21vdmluZykge1xyXG5cdFx0XHQvLyBlbnN1cmUgZHJhZyBpcyBub3QgZmlyZWQgYWZ0ZXIgZHJhZ2VuZFxyXG5cdFx0XHRjYW5jZWxBbmltRnJhbWUodGhpcy5fYW5pbVJlcXVlc3QpO1xyXG5cclxuXHRcdFx0Ly8gQGV2ZW50IGRyYWdlbmQ6IERyYWdFbmRFdmVudFxyXG5cdFx0XHQvLyBGaXJlZCB3aGVuIHRoZSBkcmFnIGVuZHMuXHJcblx0XHRcdHRoaXMuZmlyZSgnZHJhZ2VuZCcsIHtcclxuXHRcdFx0XHRkaXN0YW5jZTogdGhpcy5fbmV3UG9zLmRpc3RhbmNlVG8odGhpcy5fc3RhcnRQb3MpXHJcblx0XHRcdH0pO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX21vdmluZyA9IGZhbHNlO1xyXG5cdFx0RHJhZ2dhYmxlLl9kcmFnZ2luZyA9IGZhbHNlO1xyXG5cdH1cclxuXHJcbn0pO1xuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIExpbmVVdGlsXHJcbiAqXHJcbiAqIFZhcmlvdXMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIHBvbHlsaW5lIHBvaW50cyBwcm9jZXNzaW5nLCB1c2VkIGJ5IExlYWZsZXQgaW50ZXJuYWxseSB0byBtYWtlIHBvbHlsaW5lcyBsaWdodG5pbmctZmFzdC5cclxuICovXHJcblxyXG4vLyBTaW1wbGlmeSBwb2x5bGluZSB3aXRoIHZlcnRleCByZWR1Y3Rpb24gYW5kIERvdWdsYXMtUGV1Y2tlciBzaW1wbGlmaWNhdGlvbi5cclxuLy8gSW1wcm92ZXMgcmVuZGVyaW5nIHBlcmZvcm1hbmNlIGRyYW1hdGljYWxseSBieSBsZXNzZW5pbmcgdGhlIG51bWJlciBvZiBwb2ludHMgdG8gZHJhdy5cclxuXHJcbi8vIEBmdW5jdGlvbiBzaW1wbGlmeShwb2ludHM6IFBvaW50W10sIHRvbGVyYW5jZTogTnVtYmVyKTogUG9pbnRbXVxyXG4vLyBEcmFtYXRpY2FsbHkgcmVkdWNlcyB0aGUgbnVtYmVyIG9mIHBvaW50cyBpbiBhIHBvbHlsaW5lIHdoaWxlIHJldGFpbmluZ1xyXG4vLyBpdHMgc2hhcGUgYW5kIHJldHVybnMgYSBuZXcgYXJyYXkgb2Ygc2ltcGxpZmllZCBwb2ludHMsIHVzaW5nIHRoZVxyXG4vLyBbRG91Z2xhcy1QZXVja2VyIGFsZ29yaXRobV0oaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Eb3VnbGFzLVBldWNrZXJfYWxnb3JpdGhtKS5cclxuLy8gVXNlZCBmb3IgYSBodWdlIHBlcmZvcm1hbmNlIGJvb3N0IHdoZW4gcHJvY2Vzc2luZy9kaXNwbGF5aW5nIExlYWZsZXQgcG9seWxpbmVzIGZvclxyXG4vLyBlYWNoIHpvb20gbGV2ZWwgYW5kIGFsc28gcmVkdWNpbmcgdmlzdWFsIG5vaXNlLiB0b2xlcmFuY2UgYWZmZWN0cyB0aGUgYW1vdW50IG9mXHJcbi8vIHNpbXBsaWZpY2F0aW9uIChsZXNzZXIgdmFsdWUgbWVhbnMgaGlnaGVyIHF1YWxpdHkgYnV0IHNsb3dlciBhbmQgd2l0aCBtb3JlIHBvaW50cykuXHJcbi8vIEFsc28gcmVsZWFzZWQgYXMgYSBzZXBhcmF0ZWQgbWljcm8tbGlicmFyeSBbU2ltcGxpZnkuanNdKGh0dHA6Ly9tb3VybmVyLmdpdGh1Yi5jb20vc2ltcGxpZnktanMvKS5cclxuZnVuY3Rpb24gc2ltcGxpZnkocG9pbnRzLCB0b2xlcmFuY2UpIHtcclxuXHRpZiAoIXRvbGVyYW5jZSB8fCAhcG9pbnRzLmxlbmd0aCkge1xyXG5cdFx0cmV0dXJuIHBvaW50cy5zbGljZSgpO1xyXG5cdH1cclxuXHJcblx0dmFyIHNxVG9sZXJhbmNlID0gdG9sZXJhbmNlICogdG9sZXJhbmNlO1xyXG5cclxuXHQgICAgLy8gc3RhZ2UgMTogdmVydGV4IHJlZHVjdGlvblxyXG5cdCAgICBwb2ludHMgPSBfcmVkdWNlUG9pbnRzKHBvaW50cywgc3FUb2xlcmFuY2UpO1xyXG5cclxuXHQgICAgLy8gc3RhZ2UgMjogRG91Z2xhcy1QZXVja2VyIHNpbXBsaWZpY2F0aW9uXHJcblx0ICAgIHBvaW50cyA9IF9zaW1wbGlmeURQKHBvaW50cywgc3FUb2xlcmFuY2UpO1xyXG5cclxuXHRyZXR1cm4gcG9pbnRzO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gcG9pbnRUb1NlZ21lbnREaXN0YW5jZShwOiBQb2ludCwgcDE6IFBvaW50LCBwMjogUG9pbnQpOiBOdW1iZXJcclxuLy8gUmV0dXJucyB0aGUgZGlzdGFuY2UgYmV0d2VlbiBwb2ludCBgcGAgYW5kIHNlZ21lbnQgYHAxYCB0byBgcDJgLlxyXG5mdW5jdGlvbiBwb2ludFRvU2VnbWVudERpc3RhbmNlKHAsIHAxLCBwMikge1xyXG5cdHJldHVybiBNYXRoLnNxcnQoX3NxQ2xvc2VzdFBvaW50T25TZWdtZW50KHAsIHAxLCBwMiwgdHJ1ZSkpO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gY2xvc2VzdFBvaW50T25TZWdtZW50KHA6IFBvaW50LCBwMTogUG9pbnQsIHAyOiBQb2ludCk6IE51bWJlclxyXG4vLyBSZXR1cm5zIHRoZSBjbG9zZXN0IHBvaW50IGZyb20gYSBwb2ludCBgcGAgb24gYSBzZWdtZW50IGBwMWAgdG8gYHAyYC5cclxuZnVuY3Rpb24gY2xvc2VzdFBvaW50T25TZWdtZW50KHAsIHAxLCBwMikge1xyXG5cdHJldHVybiBfc3FDbG9zZXN0UG9pbnRPblNlZ21lbnQocCwgcDEsIHAyKTtcclxufVxyXG5cclxuLy8gRG91Z2xhcy1QZXVja2VyIHNpbXBsaWZpY2F0aW9uLCBzZWUgaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Eb3VnbGFzLVBldWNrZXJfYWxnb3JpdGhtXHJcbmZ1bmN0aW9uIF9zaW1wbGlmeURQKHBvaW50cywgc3FUb2xlcmFuY2UpIHtcclxuXHJcblx0dmFyIGxlbiA9IHBvaW50cy5sZW5ndGgsXHJcblx0ICAgIEFycmF5Q29uc3RydWN0b3IgPSB0eXBlb2YgVWludDhBcnJheSAhPT0gdW5kZWZpbmVkICsgJycgPyBVaW50OEFycmF5IDogQXJyYXksXHJcblx0ICAgIG1hcmtlcnMgPSBuZXcgQXJyYXlDb25zdHJ1Y3RvcihsZW4pO1xyXG5cclxuXHQgICAgbWFya2Vyc1swXSA9IG1hcmtlcnNbbGVuIC0gMV0gPSAxO1xyXG5cclxuXHRfc2ltcGxpZnlEUFN0ZXAocG9pbnRzLCBtYXJrZXJzLCBzcVRvbGVyYW5jZSwgMCwgbGVuIC0gMSk7XHJcblxyXG5cdHZhciBpLFxyXG5cdCAgICBuZXdQb2ludHMgPSBbXTtcclxuXHJcblx0Zm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRpZiAobWFya2Vyc1tpXSkge1xyXG5cdFx0XHRuZXdQb2ludHMucHVzaChwb2ludHNbaV0pO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0cmV0dXJuIG5ld1BvaW50cztcclxufVxyXG5cclxuZnVuY3Rpb24gX3NpbXBsaWZ5RFBTdGVwKHBvaW50cywgbWFya2Vycywgc3FUb2xlcmFuY2UsIGZpcnN0LCBsYXN0KSB7XHJcblxyXG5cdHZhciBtYXhTcURpc3QgPSAwLFxyXG5cdGluZGV4LCBpLCBzcURpc3Q7XHJcblxyXG5cdGZvciAoaSA9IGZpcnN0ICsgMTsgaSA8PSBsYXN0IC0gMTsgaSsrKSB7XHJcblx0XHRzcURpc3QgPSBfc3FDbG9zZXN0UG9pbnRPblNlZ21lbnQocG9pbnRzW2ldLCBwb2ludHNbZmlyc3RdLCBwb2ludHNbbGFzdF0sIHRydWUpO1xyXG5cclxuXHRcdGlmIChzcURpc3QgPiBtYXhTcURpc3QpIHtcclxuXHRcdFx0aW5kZXggPSBpO1xyXG5cdFx0XHRtYXhTcURpc3QgPSBzcURpc3Q7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHRpZiAobWF4U3FEaXN0ID4gc3FUb2xlcmFuY2UpIHtcclxuXHRcdG1hcmtlcnNbaW5kZXhdID0gMTtcclxuXHJcblx0XHRfc2ltcGxpZnlEUFN0ZXAocG9pbnRzLCBtYXJrZXJzLCBzcVRvbGVyYW5jZSwgZmlyc3QsIGluZGV4KTtcclxuXHRcdF9zaW1wbGlmeURQU3RlcChwb2ludHMsIG1hcmtlcnMsIHNxVG9sZXJhbmNlLCBpbmRleCwgbGFzdCk7XHJcblx0fVxyXG59XHJcblxyXG4vLyByZWR1Y2UgcG9pbnRzIHRoYXQgYXJlIHRvbyBjbG9zZSB0byBlYWNoIG90aGVyIHRvIGEgc2luZ2xlIHBvaW50XHJcbmZ1bmN0aW9uIF9yZWR1Y2VQb2ludHMocG9pbnRzLCBzcVRvbGVyYW5jZSkge1xyXG5cdHZhciByZWR1Y2VkUG9pbnRzID0gW3BvaW50c1swXV07XHJcblxyXG5cdGZvciAodmFyIGkgPSAxLCBwcmV2ID0gMCwgbGVuID0gcG9pbnRzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRpZiAoX3NxRGlzdChwb2ludHNbaV0sIHBvaW50c1twcmV2XSkgPiBzcVRvbGVyYW5jZSkge1xyXG5cdFx0XHRyZWR1Y2VkUG9pbnRzLnB1c2gocG9pbnRzW2ldKTtcclxuXHRcdFx0cHJldiA9IGk7XHJcblx0XHR9XHJcblx0fVxyXG5cdGlmIChwcmV2IDwgbGVuIC0gMSkge1xyXG5cdFx0cmVkdWNlZFBvaW50cy5wdXNoKHBvaW50c1tsZW4gLSAxXSk7XHJcblx0fVxyXG5cdHJldHVybiByZWR1Y2VkUG9pbnRzO1xyXG59XHJcblxyXG52YXIgX2xhc3RDb2RlO1xyXG5cclxuLy8gQGZ1bmN0aW9uIGNsaXBTZWdtZW50KGE6IFBvaW50LCBiOiBQb2ludCwgYm91bmRzOiBCb3VuZHMsIHVzZUxhc3RDb2RlPzogQm9vbGVhbiwgcm91bmQ/OiBCb29sZWFuKTogUG9pbnRbXXxCb29sZWFuXHJcbi8vIENsaXBzIHRoZSBzZWdtZW50IGEgdG8gYiBieSByZWN0YW5ndWxhciBib3VuZHMgd2l0aCB0aGVcclxuLy8gW0NvaGVuLVN1dGhlcmxhbmQgYWxnb3JpdGhtXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Db2hlbiVFMiU4MCU5M1N1dGhlcmxhbmRfYWxnb3JpdGhtKVxyXG4vLyAobW9kaWZ5aW5nIHRoZSBzZWdtZW50IHBvaW50cyBkaXJlY3RseSEpLiBVc2VkIGJ5IExlYWZsZXQgdG8gb25seSBzaG93IHBvbHlsaW5lXHJcbi8vIHBvaW50cyB0aGF0IGFyZSBvbiB0aGUgc2NyZWVuIG9yIG5lYXIsIGluY3JlYXNpbmcgcGVyZm9ybWFuY2UuXHJcbmZ1bmN0aW9uIGNsaXBTZWdtZW50KGEsIGIsIGJvdW5kcywgdXNlTGFzdENvZGUsIHJvdW5kKSB7XHJcblx0dmFyIGNvZGVBID0gdXNlTGFzdENvZGUgPyBfbGFzdENvZGUgOiBfZ2V0Qml0Q29kZShhLCBib3VuZHMpLFxyXG5cdCAgICBjb2RlQiA9IF9nZXRCaXRDb2RlKGIsIGJvdW5kcyksXHJcblxyXG5cdCAgICBjb2RlT3V0LCBwLCBuZXdDb2RlO1xyXG5cclxuXHQgICAgLy8gc2F2ZSAybmQgY29kZSB0byBhdm9pZCBjYWxjdWxhdGluZyBpdCBvbiB0aGUgbmV4dCBzZWdtZW50XHJcblx0ICAgIF9sYXN0Q29kZSA9IGNvZGVCO1xyXG5cclxuXHR3aGlsZSAodHJ1ZSkge1xyXG5cdFx0Ly8gaWYgYSxiIGlzIGluc2lkZSB0aGUgY2xpcCB3aW5kb3cgKHRyaXZpYWwgYWNjZXB0KVxyXG5cdFx0aWYgKCEoY29kZUEgfCBjb2RlQikpIHtcclxuXHRcdFx0cmV0dXJuIFthLCBiXTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBpZiBhLGIgaXMgb3V0c2lkZSB0aGUgY2xpcCB3aW5kb3cgKHRyaXZpYWwgcmVqZWN0KVxyXG5cdFx0aWYgKGNvZGVBICYgY29kZUIpIHtcclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIG90aGVyIGNhc2VzXHJcblx0XHRjb2RlT3V0ID0gY29kZUEgfHwgY29kZUI7XHJcblx0XHRwID0gX2dldEVkZ2VJbnRlcnNlY3Rpb24oYSwgYiwgY29kZU91dCwgYm91bmRzLCByb3VuZCk7XHJcblx0XHRuZXdDb2RlID0gX2dldEJpdENvZGUocCwgYm91bmRzKTtcclxuXHJcblx0XHRpZiAoY29kZU91dCA9PT0gY29kZUEpIHtcclxuXHRcdFx0YSA9IHA7XHJcblx0XHRcdGNvZGVBID0gbmV3Q29kZTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGIgPSBwO1xyXG5cdFx0XHRjb2RlQiA9IG5ld0NvZGU7XHJcblx0XHR9XHJcblx0fVxyXG59XHJcblxyXG5mdW5jdGlvbiBfZ2V0RWRnZUludGVyc2VjdGlvbihhLCBiLCBjb2RlLCBib3VuZHMsIHJvdW5kKSB7XHJcblx0dmFyIGR4ID0gYi54IC0gYS54LFxyXG5cdCAgICBkeSA9IGIueSAtIGEueSxcclxuXHQgICAgbWluID0gYm91bmRzLm1pbixcclxuXHQgICAgbWF4ID0gYm91bmRzLm1heCxcclxuXHQgICAgeCwgeTtcclxuXHJcblx0aWYgKGNvZGUgJiA4KSB7IC8vIHRvcFxyXG5cdFx0eCA9IGEueCArIGR4ICogKG1heC55IC0gYS55KSAvIGR5O1xyXG5cdFx0eSA9IG1heC55O1xyXG5cclxuXHR9IGVsc2UgaWYgKGNvZGUgJiA0KSB7IC8vIGJvdHRvbVxyXG5cdFx0eCA9IGEueCArIGR4ICogKG1pbi55IC0gYS55KSAvIGR5O1xyXG5cdFx0eSA9IG1pbi55O1xyXG5cclxuXHR9IGVsc2UgaWYgKGNvZGUgJiAyKSB7IC8vIHJpZ2h0XHJcblx0XHR4ID0gbWF4Lng7XHJcblx0XHR5ID0gYS55ICsgZHkgKiAobWF4LnggLSBhLngpIC8gZHg7XHJcblxyXG5cdH0gZWxzZSBpZiAoY29kZSAmIDEpIHsgLy8gbGVmdFxyXG5cdFx0eCA9IG1pbi54O1xyXG5cdFx0eSA9IGEueSArIGR5ICogKG1pbi54IC0gYS54KSAvIGR4O1xyXG5cdH1cclxuXHJcblx0cmV0dXJuIG5ldyBQb2ludCh4LCB5LCByb3VuZCk7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIF9nZXRCaXRDb2RlKHAsIGJvdW5kcykge1xyXG5cdHZhciBjb2RlID0gMDtcclxuXHJcblx0aWYgKHAueCA8IGJvdW5kcy5taW4ueCkgeyAvLyBsZWZ0XHJcblx0XHRjb2RlIHw9IDE7XHJcblx0fSBlbHNlIGlmIChwLnggPiBib3VuZHMubWF4LngpIHsgLy8gcmlnaHRcclxuXHRcdGNvZGUgfD0gMjtcclxuXHR9XHJcblxyXG5cdGlmIChwLnkgPCBib3VuZHMubWluLnkpIHsgLy8gYm90dG9tXHJcblx0XHRjb2RlIHw9IDQ7XHJcblx0fSBlbHNlIGlmIChwLnkgPiBib3VuZHMubWF4LnkpIHsgLy8gdG9wXHJcblx0XHRjb2RlIHw9IDg7XHJcblx0fVxyXG5cclxuXHRyZXR1cm4gY29kZTtcclxufVxyXG5cclxuLy8gc3F1YXJlIGRpc3RhbmNlICh0byBhdm9pZCB1bm5lY2Vzc2FyeSBNYXRoLnNxcnQgY2FsbHMpXHJcbmZ1bmN0aW9uIF9zcURpc3QocDEsIHAyKSB7XHJcblx0dmFyIGR4ID0gcDIueCAtIHAxLngsXHJcblx0ICAgIGR5ID0gcDIueSAtIHAxLnk7XHJcblx0cmV0dXJuIGR4ICogZHggKyBkeSAqIGR5O1xyXG59XHJcblxyXG4vLyByZXR1cm4gY2xvc2VzdCBwb2ludCBvbiBzZWdtZW50IG9yIGRpc3RhbmNlIHRvIHRoYXQgcG9pbnRcclxuZnVuY3Rpb24gX3NxQ2xvc2VzdFBvaW50T25TZWdtZW50KHAsIHAxLCBwMiwgc3FEaXN0KSB7XHJcblx0dmFyIHggPSBwMS54LFxyXG5cdCAgICB5ID0gcDEueSxcclxuXHQgICAgZHggPSBwMi54IC0geCxcclxuXHQgICAgZHkgPSBwMi55IC0geSxcclxuXHQgICAgZG90ID0gZHggKiBkeCArIGR5ICogZHksXHJcblx0ICAgIHQ7XHJcblxyXG5cdGlmIChkb3QgPiAwKSB7XHJcblx0XHR0ID0gKChwLnggLSB4KSAqIGR4ICsgKHAueSAtIHkpICogZHkpIC8gZG90O1xyXG5cclxuXHRcdGlmICh0ID4gMSkge1xyXG5cdFx0XHR4ID0gcDIueDtcclxuXHRcdFx0eSA9IHAyLnk7XHJcblx0XHR9IGVsc2UgaWYgKHQgPiAwKSB7XHJcblx0XHRcdHggKz0gZHggKiB0O1xyXG5cdFx0XHR5ICs9IGR5ICogdDtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdGR4ID0gcC54IC0geDtcclxuXHRkeSA9IHAueSAtIHk7XHJcblxyXG5cdHJldHVybiBzcURpc3QgPyBkeCAqIGR4ICsgZHkgKiBkeSA6IG5ldyBQb2ludCh4LCB5KTtcclxufVxyXG5cclxuXHJcbi8vIEBmdW5jdGlvbiBpc0ZsYXQobGF0bG5nczogTGF0TG5nW10pOiBCb29sZWFuXHJcbi8vIFJldHVybnMgdHJ1ZSBpZiBgbGF0bG5nc2AgaXMgYSBmbGF0IGFycmF5LCBmYWxzZSBpcyBuZXN0ZWQuXHJcbmZ1bmN0aW9uIGlzRmxhdChsYXRsbmdzKSB7XHJcblx0cmV0dXJuICFpc0FycmF5KGxhdGxuZ3NbMF0pIHx8ICh0eXBlb2YgbGF0bG5nc1swXVswXSAhPT0gJ29iamVjdCcgJiYgdHlwZW9mIGxhdGxuZ3NbMF1bMF0gIT09ICd1bmRlZmluZWQnKTtcclxufVxyXG5cclxuZnVuY3Rpb24gX2ZsYXQobGF0bG5ncykge1xyXG5cdGNvbnNvbGUud2FybignRGVwcmVjYXRlZCB1c2Ugb2YgX2ZsYXQsIHBsZWFzZSB1c2UgTC5MaW5lVXRpbC5pc0ZsYXQgaW5zdGVhZC4nKTtcclxuXHRyZXR1cm4gaXNGbGF0KGxhdGxuZ3MpO1xyXG59XHJcblxuXG52YXIgTGluZVV0aWwgPSAoT2JqZWN0LmZyZWV6ZSB8fCBPYmplY3QpKHtcblx0c2ltcGxpZnk6IHNpbXBsaWZ5LFxuXHRwb2ludFRvU2VnbWVudERpc3RhbmNlOiBwb2ludFRvU2VnbWVudERpc3RhbmNlLFxuXHRjbG9zZXN0UG9pbnRPblNlZ21lbnQ6IGNsb3Nlc3RQb2ludE9uU2VnbWVudCxcblx0Y2xpcFNlZ21lbnQ6IGNsaXBTZWdtZW50LFxuXHRfZ2V0RWRnZUludGVyc2VjdGlvbjogX2dldEVkZ2VJbnRlcnNlY3Rpb24sXG5cdF9nZXRCaXRDb2RlOiBfZ2V0Qml0Q29kZSxcblx0X3NxQ2xvc2VzdFBvaW50T25TZWdtZW50OiBfc3FDbG9zZXN0UG9pbnRPblNlZ21lbnQsXG5cdGlzRmxhdDogaXNGbGF0LFxuXHRfZmxhdDogX2ZsYXRcbn0pO1xuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIFBvbHlVdGlsXHJcbiAqIFZhcmlvdXMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIHBvbHlnb24gZ2VvbWV0cmllcy5cclxuICovXHJcblxyXG4vKiBAZnVuY3Rpb24gY2xpcFBvbHlnb24ocG9pbnRzOiBQb2ludFtdLCBib3VuZHM6IEJvdW5kcywgcm91bmQ/OiBCb29sZWFuKTogUG9pbnRbXVxyXG4gKiBDbGlwcyB0aGUgcG9seWdvbiBnZW9tZXRyeSBkZWZpbmVkIGJ5IHRoZSBnaXZlbiBgcG9pbnRzYCBieSB0aGUgZ2l2ZW4gYm91bmRzICh1c2luZyB0aGUgW1N1dGhlcmxhbmQtSG9kZ21hbiBhbGdvcml0aG1dKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1N1dGhlcmxhbmQlRTIlODAlOTNIb2RnbWFuX2FsZ29yaXRobSkpLlxyXG4gKiBVc2VkIGJ5IExlYWZsZXQgdG8gb25seSBzaG93IHBvbHlnb24gcG9pbnRzIHRoYXQgYXJlIG9uIHRoZSBzY3JlZW4gb3IgbmVhciwgaW5jcmVhc2luZ1xyXG4gKiBwZXJmb3JtYW5jZS4gTm90ZSB0aGF0IHBvbHlnb24gcG9pbnRzIG5lZWRzIGRpZmZlcmVudCBhbGdvcml0aG0gZm9yIGNsaXBwaW5nXHJcbiAqIHRoYW4gcG9seWxpbmUsIHNvIHRoZXJlJ3MgYSBzZXBhcmF0ZSBtZXRob2QgZm9yIGl0LlxyXG4gKi9cclxuZnVuY3Rpb24gY2xpcFBvbHlnb24ocG9pbnRzLCBib3VuZHMsIHJvdW5kKSB7XHJcblx0dmFyIGNsaXBwZWRQb2ludHMsXHJcblx0ICAgIGVkZ2VzID0gWzEsIDQsIDIsIDhdLFxyXG5cdCAgICBpLCBqLCBrLFxyXG5cdCAgICBhLCBiLFxyXG5cdCAgICBsZW4sIGVkZ2UsIHA7XHJcblxyXG5cdGZvciAoaSA9IDAsIGxlbiA9IHBvaW50cy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG5cdFx0cG9pbnRzW2ldLl9jb2RlID0gX2dldEJpdENvZGUocG9pbnRzW2ldLCBib3VuZHMpO1xyXG5cdH1cclxuXHJcblx0Ly8gZm9yIGVhY2ggZWRnZSAobGVmdCwgYm90dG9tLCByaWdodCwgdG9wKVxyXG5cdGZvciAoayA9IDA7IGsgPCA0OyBrKyspIHtcclxuXHRcdGVkZ2UgPSBlZGdlc1trXTtcclxuXHRcdGNsaXBwZWRQb2ludHMgPSBbXTtcclxuXHJcblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBwb2ludHMubGVuZ3RoLCBqID0gbGVuIC0gMTsgaSA8IGxlbjsgaiA9IGkrKykge1xyXG5cdFx0XHRhID0gcG9pbnRzW2ldO1xyXG5cdFx0XHRiID0gcG9pbnRzW2pdO1xyXG5cclxuXHRcdFx0Ly8gaWYgYSBpcyBpbnNpZGUgdGhlIGNsaXAgd2luZG93XHJcblx0XHRcdGlmICghKGEuX2NvZGUgJiBlZGdlKSkge1xyXG5cdFx0XHRcdC8vIGlmIGIgaXMgb3V0c2lkZSB0aGUgY2xpcCB3aW5kb3cgKGEtPmIgZ29lcyBvdXQgb2Ygc2NyZWVuKVxyXG5cdFx0XHRcdGlmIChiLl9jb2RlICYgZWRnZSkge1xyXG5cdFx0XHRcdFx0cCA9IF9nZXRFZGdlSW50ZXJzZWN0aW9uKGIsIGEsIGVkZ2UsIGJvdW5kcywgcm91bmQpO1xyXG5cdFx0XHRcdFx0cC5fY29kZSA9IF9nZXRCaXRDb2RlKHAsIGJvdW5kcyk7XHJcblx0XHRcdFx0XHRjbGlwcGVkUG9pbnRzLnB1c2gocCk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGNsaXBwZWRQb2ludHMucHVzaChhKTtcclxuXHJcblx0XHRcdC8vIGVsc2UgaWYgYiBpcyBpbnNpZGUgdGhlIGNsaXAgd2luZG93IChhLT5iIGVudGVycyB0aGUgc2NyZWVuKVxyXG5cdFx0XHR9IGVsc2UgaWYgKCEoYi5fY29kZSAmIGVkZ2UpKSB7XHJcblx0XHRcdFx0cCA9IF9nZXRFZGdlSW50ZXJzZWN0aW9uKGIsIGEsIGVkZ2UsIGJvdW5kcywgcm91bmQpO1xyXG5cdFx0XHRcdHAuX2NvZGUgPSBfZ2V0Qml0Q29kZShwLCBib3VuZHMpO1xyXG5cdFx0XHRcdGNsaXBwZWRQb2ludHMucHVzaChwKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdFx0cG9pbnRzID0gY2xpcHBlZFBvaW50cztcclxuXHR9XHJcblxyXG5cdHJldHVybiBwb2ludHM7XHJcbn1cclxuXG5cbnZhciBQb2x5VXRpbCA9IChPYmplY3QuZnJlZXplIHx8IE9iamVjdCkoe1xuXHRjbGlwUG9seWdvbjogY2xpcFBvbHlnb25cbn0pO1xuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIFByb2plY3Rpb25cclxuICogQHNlY3Rpb25cclxuICogTGVhZmxldCBjb21lcyB3aXRoIGEgc2V0IG9mIGFscmVhZHkgZGVmaW5lZCBQcm9qZWN0aW9ucyBvdXQgb2YgdGhlIGJveDpcclxuICpcclxuICogQHByb2plY3Rpb24gTC5Qcm9qZWN0aW9uLkxvbkxhdFxyXG4gKlxyXG4gKiBFcXVpcmVjdGFuZ3VsYXIsIG9yIFBsYXRlIENhcnJlZSBwcm9qZWN0aW9uIOKAlCB0aGUgbW9zdCBzaW1wbGUgcHJvamVjdGlvbixcclxuICogbW9zdGx5IHVzZWQgYnkgR0lTIGVudGh1c2lhc3RzLiBEaXJlY3RseSBtYXBzIGB4YCBhcyBsb25naXR1ZGUsIGFuZCBgeWAgYXNcclxuICogbGF0aXR1ZGUuIEFsc28gc3VpdGFibGUgZm9yIGZsYXQgd29ybGRzLCBlLmcuIGdhbWUgbWFwcy4gVXNlZCBieSB0aGVcclxuICogYEVQU0c6NDMyNmAgYW5kIGBTaW1wbGVgIENSUy5cclxuICovXHJcblxyXG52YXIgTG9uTGF0ID0ge1xyXG5cdHByb2plY3Q6IGZ1bmN0aW9uIChsYXRsbmcpIHtcclxuXHRcdHJldHVybiBuZXcgUG9pbnQobGF0bG5nLmxuZywgbGF0bG5nLmxhdCk7XHJcblx0fSxcclxuXHJcblx0dW5wcm9qZWN0OiBmdW5jdGlvbiAocG9pbnQpIHtcclxuXHRcdHJldHVybiBuZXcgTGF0TG5nKHBvaW50LnksIHBvaW50LngpO1xyXG5cdH0sXHJcblxyXG5cdGJvdW5kczogbmV3IEJvdW5kcyhbLTE4MCwgLTkwXSwgWzE4MCwgOTBdKVxyXG59O1xuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIFByb2plY3Rpb25cclxuICogQHByb2plY3Rpb24gTC5Qcm9qZWN0aW9uLk1lcmNhdG9yXHJcbiAqXHJcbiAqIEVsbGlwdGljYWwgTWVyY2F0b3IgcHJvamVjdGlvbiDigJQgbW9yZSBjb21wbGV4IHRoYW4gU3BoZXJpY2FsIE1lcmNhdG9yLiBUYWtlcyBpbnRvIGFjY291bnQgdGhhdCBFYXJ0aCBpcyBhIGdlb2lkLCBub3QgYSBwZXJmZWN0IHNwaGVyZS4gVXNlZCBieSB0aGUgRVBTRzozMzk1IENSUy5cclxuICovXHJcblxyXG52YXIgTWVyY2F0b3IgPSB7XHJcblx0UjogNjM3ODEzNyxcclxuXHRSX01JTk9SOiA2MzU2NzUyLjMxNDI0NTE3OSxcclxuXHJcblx0Ym91bmRzOiBuZXcgQm91bmRzKFstMjAwMzc1MDguMzQyNzksIC0xNTQ5NjU3MC43Mzk3Ml0sIFsyMDAzNzUwOC4zNDI3OSwgMTg3NjQ2NTYuMjMxMzhdKSxcclxuXHJcblx0cHJvamVjdDogZnVuY3Rpb24gKGxhdGxuZykge1xyXG5cdFx0dmFyIGQgPSBNYXRoLlBJIC8gMTgwLFxyXG5cdFx0ICAgIHIgPSB0aGlzLlIsXHJcblx0XHQgICAgeSA9IGxhdGxuZy5sYXQgKiBkLFxyXG5cdFx0ICAgIHRtcCA9IHRoaXMuUl9NSU5PUiAvIHIsXHJcblx0XHQgICAgZSA9IE1hdGguc3FydCgxIC0gdG1wICogdG1wKSxcclxuXHRcdCAgICBjb24gPSBlICogTWF0aC5zaW4oeSk7XHJcblxyXG5cdFx0dmFyIHRzID0gTWF0aC50YW4oTWF0aC5QSSAvIDQgLSB5IC8gMikgLyBNYXRoLnBvdygoMSAtIGNvbikgLyAoMSArIGNvbiksIGUgLyAyKTtcclxuXHRcdHkgPSAtciAqIE1hdGgubG9nKE1hdGgubWF4KHRzLCAxRS0xMCkpO1xyXG5cclxuXHRcdHJldHVybiBuZXcgUG9pbnQobGF0bG5nLmxuZyAqIGQgKiByLCB5KTtcclxuXHR9LFxyXG5cclxuXHR1bnByb2plY3Q6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0dmFyIGQgPSAxODAgLyBNYXRoLlBJLFxyXG5cdFx0ICAgIHIgPSB0aGlzLlIsXHJcblx0XHQgICAgdG1wID0gdGhpcy5SX01JTk9SIC8gcixcclxuXHRcdCAgICBlID0gTWF0aC5zcXJ0KDEgLSB0bXAgKiB0bXApLFxyXG5cdFx0ICAgIHRzID0gTWF0aC5leHAoLXBvaW50LnkgLyByKSxcclxuXHRcdCAgICBwaGkgPSBNYXRoLlBJIC8gMiAtIDIgKiBNYXRoLmF0YW4odHMpO1xyXG5cclxuXHRcdGZvciAodmFyIGkgPSAwLCBkcGhpID0gMC4xLCBjb247IGkgPCAxNSAmJiBNYXRoLmFicyhkcGhpKSA+IDFlLTc7IGkrKykge1xyXG5cdFx0XHRjb24gPSBlICogTWF0aC5zaW4ocGhpKTtcclxuXHRcdFx0Y29uID0gTWF0aC5wb3coKDEgLSBjb24pIC8gKDEgKyBjb24pLCBlIC8gMik7XHJcblx0XHRcdGRwaGkgPSBNYXRoLlBJIC8gMiAtIDIgKiBNYXRoLmF0YW4odHMgKiBjb24pIC0gcGhpO1xyXG5cdFx0XHRwaGkgKz0gZHBoaTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbmV3IExhdExuZyhwaGkgKiBkLCBwb2ludC54ICogZCAvIHIpO1xyXG5cdH1cclxufTtcblxuLypcbiAqIEBjbGFzcyBQcm9qZWN0aW9uXG5cbiAqIEFuIG9iamVjdCB3aXRoIG1ldGhvZHMgZm9yIHByb2plY3RpbmcgZ2VvZ3JhcGhpY2FsIGNvb3JkaW5hdGVzIG9mIHRoZSB3b3JsZCBvbnRvXG4gKiBhIGZsYXQgc3VyZmFjZSAoYW5kIGJhY2spLiBTZWUgW01hcCBwcm9qZWN0aW9uXShodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL01hcF9wcm9qZWN0aW9uKS5cblxuICogQHByb3BlcnR5IGJvdW5kczogQm91bmRzXG4gKiBUaGUgYm91bmRzIChzcGVjaWZpZWQgaW4gQ1JTIHVuaXRzKSB3aGVyZSB0aGUgcHJvamVjdGlvbiBpcyB2YWxpZFxuXG4gKiBAbWV0aG9kIHByb2plY3QobGF0bG5nOiBMYXRMbmcpOiBQb2ludFxuICogUHJvamVjdHMgZ2VvZ3JhcGhpY2FsIGNvb3JkaW5hdGVzIGludG8gYSAyRCBwb2ludC5cbiAqIE9ubHkgYWNjZXB0cyBhY3R1YWwgYEwuTGF0TG5nYCBpbnN0YW5jZXMsIG5vdCBhcnJheXMuXG5cbiAqIEBtZXRob2QgdW5wcm9qZWN0KHBvaW50OiBQb2ludCk6IExhdExuZ1xuICogVGhlIGludmVyc2Ugb2YgYHByb2plY3RgLiBQcm9qZWN0cyBhIDJEIHBvaW50IGludG8gYSBnZW9ncmFwaGljYWwgbG9jYXRpb24uXG4gKiBPbmx5IGFjY2VwdHMgYWN0dWFsIGBMLlBvaW50YCBpbnN0YW5jZXMsIG5vdCBhcnJheXMuXG5cbiAqIE5vdGUgdGhhdCB0aGUgcHJvamVjdGlvbiBpbnN0YW5jZXMgZG8gbm90IGluaGVyaXQgZnJvbSBMZWFmZXQncyBgQ2xhc3NgIG9iamVjdCxcbiAqIGFuZCBjYW4ndCBiZSBpbnN0YW50aWF0ZWQuIEFsc28sIG5ldyBjbGFzc2VzIGNhbid0IGluaGVyaXQgZnJvbSB0aGVtLFxuICogYW5kIG1ldGhvZHMgY2FuJ3QgYmUgYWRkZWQgdG8gdGhlbSB3aXRoIHRoZSBgaW5jbHVkZWAgZnVuY3Rpb24uXG5cbiAqL1xuXG5cblxuXG52YXIgaW5kZXggPSAoT2JqZWN0LmZyZWV6ZSB8fCBPYmplY3QpKHtcblx0TG9uTGF0OiBMb25MYXQsXG5cdE1lcmNhdG9yOiBNZXJjYXRvcixcblx0U3BoZXJpY2FsTWVyY2F0b3I6IFNwaGVyaWNhbE1lcmNhdG9yXG59KTtcblxuLypcclxuICogQG5hbWVzcGFjZSBDUlNcclxuICogQGNycyBMLkNSUy5FUFNHMzM5NVxyXG4gKlxyXG4gKiBSYXJlbHkgdXNlZCBieSBzb21lIGNvbW1lcmNpYWwgdGlsZSBwcm92aWRlcnMuIFVzZXMgRWxsaXB0aWNhbCBNZXJjYXRvciBwcm9qZWN0aW9uLlxyXG4gKi9cclxudmFyIEVQU0czMzk1ID0gZXh0ZW5kKHt9LCBFYXJ0aCwge1xyXG5cdGNvZGU6ICdFUFNHOjMzOTUnLFxyXG5cdHByb2plY3Rpb246IE1lcmNhdG9yLFxyXG5cclxuXHR0cmFuc2Zvcm1hdGlvbjogKGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBzY2FsZSA9IDAuNSAvIChNYXRoLlBJICogTWVyY2F0b3IuUik7XHJcblx0XHRyZXR1cm4gdG9UcmFuc2Zvcm1hdGlvbihzY2FsZSwgMC41LCAtc2NhbGUsIDAuNSk7XHJcblx0fSgpKVxyXG59KTtcblxuLypcclxuICogQG5hbWVzcGFjZSBDUlNcclxuICogQGNycyBMLkNSUy5FUFNHNDMyNlxyXG4gKlxyXG4gKiBBIGNvbW1vbiBDUlMgYW1vbmcgR0lTIGVudGh1c2lhc3RzLiBVc2VzIHNpbXBsZSBFcXVpcmVjdGFuZ3VsYXIgcHJvamVjdGlvbi5cclxuICpcclxuICogTGVhZmxldCAxLjAueCBjb21wbGllcyB3aXRoIHRoZSBbVE1TIGNvb3JkaW5hdGUgc2NoZW1lIGZvciBFUFNHOjQzMjZdKGh0dHBzOi8vd2lraS5vc2dlby5vcmcvd2lraS9UaWxlX01hcF9TZXJ2aWNlX1NwZWNpZmljYXRpb24jZ2xvYmFsLWdlb2RldGljKSxcclxuICogd2hpY2ggaXMgYSBicmVha2luZyBjaGFuZ2UgZnJvbSAwLjcueCBiZWhhdmlvdXIuICBJZiB5b3UgYXJlIHVzaW5nIGEgYFRpbGVMYXllcmBcclxuICogd2l0aCB0aGlzIENSUywgZW5zdXJlIHRoYXQgdGhlcmUgYXJlIHR3byAyNTZ4MjU2IHBpeGVsIHRpbGVzIGNvdmVyaW5nIHRoZVxyXG4gKiB3aG9sZSBlYXJ0aCBhdCB6b29tIGxldmVsIHplcm8sIGFuZCB0aGF0IHRoZSB0aWxlIGNvb3JkaW5hdGUgb3JpZ2luIGlzICgtMTgwLCs5MCksXHJcbiAqIG9yICgtMTgwLC05MCkgZm9yIGBUaWxlTGF5ZXJgcyB3aXRoIFt0aGUgYHRtc2Agb3B0aW9uXSgjdGlsZWxheWVyLXRtcykgc2V0LlxyXG4gKi9cclxuXHJcbnZhciBFUFNHNDMyNiA9IGV4dGVuZCh7fSwgRWFydGgsIHtcclxuXHRjb2RlOiAnRVBTRzo0MzI2JyxcclxuXHRwcm9qZWN0aW9uOiBMb25MYXQsXHJcblx0dHJhbnNmb3JtYXRpb246IHRvVHJhbnNmb3JtYXRpb24oMSAvIDE4MCwgMSwgLTEgLyAxODAsIDAuNSlcclxufSk7XG5cbi8qXG4gKiBAbmFtZXNwYWNlIENSU1xuICogQGNycyBMLkNSUy5TaW1wbGVcbiAqXG4gKiBBIHNpbXBsZSBDUlMgdGhhdCBtYXBzIGxvbmdpdHVkZSBhbmQgbGF0aXR1ZGUgaW50byBgeGAgYW5kIGB5YCBkaXJlY3RseS5cbiAqIE1heSBiZSB1c2VkIGZvciBtYXBzIG9mIGZsYXQgc3VyZmFjZXMgKGUuZy4gZ2FtZSBtYXBzKS4gTm90ZSB0aGF0IHRoZSBgeWBcbiAqIGF4aXMgc2hvdWxkIHN0aWxsIGJlIGludmVydGVkIChnb2luZyBmcm9tIGJvdHRvbSB0byB0b3ApLiBgZGlzdGFuY2UoKWAgcmV0dXJuc1xuICogc2ltcGxlIGV1Y2xpZGVhbiBkaXN0YW5jZS5cbiAqL1xuXG52YXIgU2ltcGxlID0gZXh0ZW5kKHt9LCBDUlMsIHtcblx0cHJvamVjdGlvbjogTG9uTGF0LFxuXHR0cmFuc2Zvcm1hdGlvbjogdG9UcmFuc2Zvcm1hdGlvbigxLCAwLCAtMSwgMCksXG5cblx0c2NhbGU6IGZ1bmN0aW9uICh6b29tKSB7XG5cdFx0cmV0dXJuIE1hdGgucG93KDIsIHpvb20pO1xuXHR9LFxuXG5cdHpvb206IGZ1bmN0aW9uIChzY2FsZSkge1xuXHRcdHJldHVybiBNYXRoLmxvZyhzY2FsZSkgLyBNYXRoLkxOMjtcblx0fSxcblxuXHRkaXN0YW5jZTogZnVuY3Rpb24gKGxhdGxuZzEsIGxhdGxuZzIpIHtcblx0XHR2YXIgZHggPSBsYXRsbmcyLmxuZyAtIGxhdGxuZzEubG5nLFxuXHRcdCAgICBkeSA9IGxhdGxuZzIubGF0IC0gbGF0bG5nMS5sYXQ7XG5cblx0XHRyZXR1cm4gTWF0aC5zcXJ0KGR4ICogZHggKyBkeSAqIGR5KTtcblx0fSxcblxuXHRpbmZpbml0ZTogdHJ1ZVxufSk7XG5cbkNSUy5FYXJ0aCA9IEVhcnRoO1xuQ1JTLkVQU0czMzk1ID0gRVBTRzMzOTU7XG5DUlMuRVBTRzM4NTcgPSBFUFNHMzg1NztcbkNSUy5FUFNHOTAwOTEzID0gRVBTRzkwMDkxMztcbkNSUy5FUFNHNDMyNiA9IEVQU0c0MzI2O1xuQ1JTLlNpbXBsZSA9IFNpbXBsZTtcblxuLypcbiAqIEBjbGFzcyBMYXllclxuICogQGluaGVyaXRzIEV2ZW50ZWRcbiAqIEBha2EgTC5MYXllclxuICogQGFrYSBJTGF5ZXJcbiAqXG4gKiBBIHNldCBvZiBtZXRob2RzIGZyb20gdGhlIExheWVyIGJhc2UgY2xhc3MgdGhhdCBhbGwgTGVhZmxldCBsYXllcnMgdXNlLlxuICogSW5oZXJpdHMgYWxsIG1ldGhvZHMsIG9wdGlvbnMgYW5kIGV2ZW50cyBmcm9tIGBMLkV2ZW50ZWRgLlxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogYGBganNcbiAqIHZhciBsYXllciA9IEwuTWFya2VyKGxhdGxuZykuYWRkVG8obWFwKTtcbiAqIGxheWVyLmFkZFRvKG1hcCk7XG4gKiBsYXllci5yZW1vdmUoKTtcbiAqIGBgYFxuICpcbiAqIEBldmVudCBhZGQ6IEV2ZW50XG4gKiBGaXJlZCBhZnRlciB0aGUgbGF5ZXIgaXMgYWRkZWQgdG8gYSBtYXBcbiAqXG4gKiBAZXZlbnQgcmVtb3ZlOiBFdmVudFxuICogRmlyZWQgYWZ0ZXIgdGhlIGxheWVyIGlzIHJlbW92ZWQgZnJvbSBhIG1hcFxuICovXG5cblxudmFyIExheWVyID0gRXZlbnRlZC5leHRlbmQoe1xuXG5cdC8vIENsYXNzZXMgZXh0ZW5kaW5nIGBMLkxheWVyYCB3aWxsIGluaGVyaXQgdGhlIGZvbGxvd2luZyBvcHRpb25zOlxuXHRvcHRpb25zOiB7XG5cdFx0Ly8gQG9wdGlvbiBwYW5lOiBTdHJpbmcgPSAnb3ZlcmxheVBhbmUnXG5cdFx0Ly8gQnkgZGVmYXVsdCB0aGUgbGF5ZXIgd2lsbCBiZSBhZGRlZCB0byB0aGUgbWFwJ3MgW292ZXJsYXkgcGFuZV0oI21hcC1vdmVybGF5cGFuZSkuIE92ZXJyaWRpbmcgdGhpcyBvcHRpb24gd2lsbCBjYXVzZSB0aGUgbGF5ZXIgdG8gYmUgcGxhY2VkIG9uIGFub3RoZXIgcGFuZSBieSBkZWZhdWx0LlxuXHRcdHBhbmU6ICdvdmVybGF5UGFuZScsXG5cblx0XHQvLyBAb3B0aW9uIGF0dHJpYnV0aW9uOiBTdHJpbmcgPSBudWxsXG5cdFx0Ly8gU3RyaW5nIHRvIGJlIHNob3duIGluIHRoZSBhdHRyaWJ1dGlvbiBjb250cm9sLCBkZXNjcmliZXMgdGhlIGxheWVyIGRhdGEsIGUuZy4gXCLCqSBNYXBib3hcIi5cblx0XHRhdHRyaWJ1dGlvbjogbnVsbCxcblxuXHRcdGJ1YmJsaW5nTW91c2VFdmVudHM6IHRydWVcblx0fSxcblxuXHQvKiBAc2VjdGlvblxuXHQgKiBDbGFzc2VzIGV4dGVuZGluZyBgTC5MYXllcmAgd2lsbCBpbmhlcml0IHRoZSBmb2xsb3dpbmcgbWV0aG9kczpcblx0ICpcblx0ICogQG1ldGhvZCBhZGRUbyhtYXA6IE1hcHxMYXllckdyb3VwKTogdGhpc1xuXHQgKiBBZGRzIHRoZSBsYXllciB0byB0aGUgZ2l2ZW4gbWFwIG9yIGxheWVyIGdyb3VwLlxuXHQgKi9cblx0YWRkVG86IGZ1bmN0aW9uIChtYXApIHtcblx0XHRtYXAuYWRkTGF5ZXIodGhpcyk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCByZW1vdmU6IHRoaXNcblx0Ly8gUmVtb3ZlcyB0aGUgbGF5ZXIgZnJvbSB0aGUgbWFwIGl0IGlzIGN1cnJlbnRseSBhY3RpdmUgb24uXG5cdHJlbW92ZTogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLnJlbW92ZUZyb20odGhpcy5fbWFwIHx8IHRoaXMuX21hcFRvQWRkKTtcblx0fSxcblxuXHQvLyBAbWV0aG9kIHJlbW92ZUZyb20obWFwOiBNYXApOiB0aGlzXG5cdC8vIFJlbW92ZXMgdGhlIGxheWVyIGZyb20gdGhlIGdpdmVuIG1hcFxuXHRyZW1vdmVGcm9tOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0aWYgKG9iaikge1xuXHRcdFx0b2JqLnJlbW92ZUxheWVyKHRoaXMpO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIGdldFBhbmUobmFtZT8gOiBTdHJpbmcpOiBIVE1MRWxlbWVudFxuXHQvLyBSZXR1cm5zIHRoZSBgSFRNTEVsZW1lbnRgIHJlcHJlc2VudGluZyB0aGUgbmFtZWQgcGFuZSBvbiB0aGUgbWFwLiBJZiBgbmFtZWAgaXMgb21pdHRlZCwgcmV0dXJucyB0aGUgcGFuZSBmb3IgdGhpcyBsYXllci5cblx0Z2V0UGFuZTogZnVuY3Rpb24gKG5hbWUpIHtcblx0XHRyZXR1cm4gdGhpcy5fbWFwLmdldFBhbmUobmFtZSA/ICh0aGlzLm9wdGlvbnNbbmFtZV0gfHwgbmFtZSkgOiB0aGlzLm9wdGlvbnMucGFuZSk7XG5cdH0sXG5cblx0YWRkSW50ZXJhY3RpdmVUYXJnZXQ6IGZ1bmN0aW9uICh0YXJnZXRFbCkge1xuXHRcdHRoaXMuX21hcC5fdGFyZ2V0c1tzdGFtcCh0YXJnZXRFbCldID0gdGhpcztcblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRyZW1vdmVJbnRlcmFjdGl2ZVRhcmdldDogZnVuY3Rpb24gKHRhcmdldEVsKSB7XG5cdFx0ZGVsZXRlIHRoaXMuX21hcC5fdGFyZ2V0c1tzdGFtcCh0YXJnZXRFbCldO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgZ2V0QXR0cmlidXRpb246IFN0cmluZ1xuXHQvLyBVc2VkIGJ5IHRoZSBgYXR0cmlidXRpb24gY29udHJvbGAsIHJldHVybnMgdGhlIFthdHRyaWJ1dGlvbiBvcHRpb25dKCNncmlkbGF5ZXItYXR0cmlidXRpb24pLlxuXHRnZXRBdHRyaWJ1dGlvbjogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMuYXR0cmlidXRpb247XG5cdH0sXG5cblx0X2xheWVyQWRkOiBmdW5jdGlvbiAoZSkge1xuXHRcdHZhciBtYXAgPSBlLnRhcmdldDtcblxuXHRcdC8vIGNoZWNrIGluIGNhc2UgbGF5ZXIgZ2V0cyBhZGRlZCBhbmQgdGhlbiByZW1vdmVkIGJlZm9yZSB0aGUgbWFwIGlzIHJlYWR5XG5cdFx0aWYgKCFtYXAuaGFzTGF5ZXIodGhpcykpIHsgcmV0dXJuOyB9XG5cblx0XHR0aGlzLl9tYXAgPSBtYXA7XG5cdFx0dGhpcy5fem9vbUFuaW1hdGVkID0gbWFwLl96b29tQW5pbWF0ZWQ7XG5cblx0XHRpZiAodGhpcy5nZXRFdmVudHMpIHtcblx0XHRcdHZhciBldmVudHMgPSB0aGlzLmdldEV2ZW50cygpO1xuXHRcdFx0bWFwLm9uKGV2ZW50cywgdGhpcyk7XG5cdFx0XHR0aGlzLm9uY2UoJ3JlbW92ZScsIGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0bWFwLm9mZihldmVudHMsIHRoaXMpO1xuXHRcdFx0fSwgdGhpcyk7XG5cdFx0fVxuXG5cdFx0dGhpcy5vbkFkZChtYXApO1xuXG5cdFx0aWYgKHRoaXMuZ2V0QXR0cmlidXRpb24gJiYgbWFwLmF0dHJpYnV0aW9uQ29udHJvbCkge1xuXHRcdFx0bWFwLmF0dHJpYnV0aW9uQ29udHJvbC5hZGRBdHRyaWJ1dGlvbih0aGlzLmdldEF0dHJpYnV0aW9uKCkpO1xuXHRcdH1cblxuXHRcdHRoaXMuZmlyZSgnYWRkJyk7XG5cdFx0bWFwLmZpcmUoJ2xheWVyYWRkJywge2xheWVyOiB0aGlzfSk7XG5cdH1cbn0pO1xuXG4vKiBAc2VjdGlvbiBFeHRlbnNpb24gbWV0aG9kc1xuICogQHVuaW5oZXJpdGFibGVcbiAqXG4gKiBFdmVyeSBsYXllciBzaG91bGQgZXh0ZW5kIGZyb20gYEwuTGF5ZXJgIGFuZCAocmUtKWltcGxlbWVudCB0aGUgZm9sbG93aW5nIG1ldGhvZHMuXG4gKlxuICogQG1ldGhvZCBvbkFkZChtYXA6IE1hcCk6IHRoaXNcbiAqIFNob3VsZCBjb250YWluIGNvZGUgdGhhdCBjcmVhdGVzIERPTSBlbGVtZW50cyBmb3IgdGhlIGxheWVyLCBhZGRzIHRoZW0gdG8gYG1hcCBwYW5lc2Agd2hlcmUgdGhleSBzaG91bGQgYmVsb25nIGFuZCBwdXRzIGxpc3RlbmVycyBvbiByZWxldmFudCBtYXAgZXZlbnRzLiBDYWxsZWQgb24gW2BtYXAuYWRkTGF5ZXIobGF5ZXIpYF0oI21hcC1hZGRsYXllcikuXG4gKlxuICogQG1ldGhvZCBvblJlbW92ZShtYXA6IE1hcCk6IHRoaXNcbiAqIFNob3VsZCBjb250YWluIGFsbCBjbGVhbiB1cCBjb2RlIHRoYXQgcmVtb3ZlcyB0aGUgbGF5ZXIncyBlbGVtZW50cyBmcm9tIHRoZSBET00gYW5kIHJlbW92ZXMgbGlzdGVuZXJzIHByZXZpb3VzbHkgYWRkZWQgaW4gW2BvbkFkZGBdKCNsYXllci1vbmFkZCkuIENhbGxlZCBvbiBbYG1hcC5yZW1vdmVMYXllcihsYXllcilgXSgjbWFwLXJlbW92ZWxheWVyKS5cbiAqXG4gKiBAbWV0aG9kIGdldEV2ZW50cygpOiBPYmplY3RcbiAqIFRoaXMgb3B0aW9uYWwgbWV0aG9kIHNob3VsZCByZXR1cm4gYW4gb2JqZWN0IGxpa2UgYHsgdmlld3Jlc2V0OiB0aGlzLl9yZXNldCB9YCBmb3IgW2BhZGRFdmVudExpc3RlbmVyYF0oI2V2ZW50ZWQtYWRkZXZlbnRsaXN0ZW5lcikuIFRoZSBldmVudCBoYW5kbGVycyBpbiB0aGlzIG9iamVjdCB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgYWRkZWQgYW5kIHJlbW92ZWQgZnJvbSB0aGUgbWFwIHdpdGggeW91ciBsYXllci5cbiAqXG4gKiBAbWV0aG9kIGdldEF0dHJpYnV0aW9uKCk6IFN0cmluZ1xuICogVGhpcyBvcHRpb25hbCBtZXRob2Qgc2hvdWxkIHJldHVybiBhIHN0cmluZyBjb250YWluaW5nIEhUTUwgdG8gYmUgc2hvd24gb24gdGhlIGBBdHRyaWJ1dGlvbiBjb250cm9sYCB3aGVuZXZlciB0aGUgbGF5ZXIgaXMgdmlzaWJsZS5cbiAqXG4gKiBAbWV0aG9kIGJlZm9yZUFkZChtYXA6IE1hcCk6IHRoaXNcbiAqIE9wdGlvbmFsIG1ldGhvZC4gQ2FsbGVkIG9uIFtgbWFwLmFkZExheWVyKGxheWVyKWBdKCNtYXAtYWRkbGF5ZXIpLCBiZWZvcmUgdGhlIGxheWVyIGlzIGFkZGVkIHRvIHRoZSBtYXAsIGJlZm9yZSBldmVudHMgYXJlIGluaXRpYWxpemVkLCB3aXRob3V0IHdhaXRpbmcgdW50aWwgdGhlIG1hcCBpcyBpbiBhIHVzYWJsZSBzdGF0ZS4gVXNlIGZvciBlYXJseSBpbml0aWFsaXphdGlvbiBvbmx5LlxuICovXG5cblxuLyogQG5hbWVzcGFjZSBNYXBcbiAqIEBzZWN0aW9uIExheWVyIGV2ZW50c1xuICpcbiAqIEBldmVudCBsYXllcmFkZDogTGF5ZXJFdmVudFxuICogRmlyZWQgd2hlbiBhIG5ldyBsYXllciBpcyBhZGRlZCB0byB0aGUgbWFwLlxuICpcbiAqIEBldmVudCBsYXllcnJlbW92ZTogTGF5ZXJFdmVudFxuICogRmlyZWQgd2hlbiBzb21lIGxheWVyIGlzIHJlbW92ZWQgZnJvbSB0aGUgbWFwXG4gKlxuICogQHNlY3Rpb24gTWV0aG9kcyBmb3IgTGF5ZXJzIGFuZCBDb250cm9sc1xuICovXG5NYXAuaW5jbHVkZSh7XG5cdC8vIEBtZXRob2QgYWRkTGF5ZXIobGF5ZXI6IExheWVyKTogdGhpc1xuXHQvLyBBZGRzIHRoZSBnaXZlbiBsYXllciB0byB0aGUgbWFwXG5cdGFkZExheWVyOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHRpZiAoIWxheWVyLl9sYXllckFkZCkge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdUaGUgcHJvdmlkZWQgb2JqZWN0IGlzIG5vdCBhIExheWVyLicpO1xuXHRcdH1cblxuXHRcdHZhciBpZCA9IHN0YW1wKGxheWVyKTtcblx0XHRpZiAodGhpcy5fbGF5ZXJzW2lkXSkgeyByZXR1cm4gdGhpczsgfVxuXHRcdHRoaXMuX2xheWVyc1tpZF0gPSBsYXllcjtcblxuXHRcdGxheWVyLl9tYXBUb0FkZCA9IHRoaXM7XG5cblx0XHRpZiAobGF5ZXIuYmVmb3JlQWRkKSB7XG5cdFx0XHRsYXllci5iZWZvcmVBZGQodGhpcyk7XG5cdFx0fVxuXG5cdFx0dGhpcy53aGVuUmVhZHkobGF5ZXIuX2xheWVyQWRkLCBsYXllcik7XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIHJlbW92ZUxheWVyKGxheWVyOiBMYXllcik6IHRoaXNcblx0Ly8gUmVtb3ZlcyB0aGUgZ2l2ZW4gbGF5ZXIgZnJvbSB0aGUgbWFwLlxuXHRyZW1vdmVMYXllcjogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dmFyIGlkID0gc3RhbXAobGF5ZXIpO1xuXG5cdFx0aWYgKCF0aGlzLl9sYXllcnNbaWRdKSB7IHJldHVybiB0aGlzOyB9XG5cblx0XHRpZiAodGhpcy5fbG9hZGVkKSB7XG5cdFx0XHRsYXllci5vblJlbW92ZSh0aGlzKTtcblx0XHR9XG5cblx0XHRpZiAobGF5ZXIuZ2V0QXR0cmlidXRpb24gJiYgdGhpcy5hdHRyaWJ1dGlvbkNvbnRyb2wpIHtcblx0XHRcdHRoaXMuYXR0cmlidXRpb25Db250cm9sLnJlbW92ZUF0dHJpYnV0aW9uKGxheWVyLmdldEF0dHJpYnV0aW9uKCkpO1xuXHRcdH1cblxuXHRcdGRlbGV0ZSB0aGlzLl9sYXllcnNbaWRdO1xuXG5cdFx0aWYgKHRoaXMuX2xvYWRlZCkge1xuXHRcdFx0dGhpcy5maXJlKCdsYXllcnJlbW92ZScsIHtsYXllcjogbGF5ZXJ9KTtcblx0XHRcdGxheWVyLmZpcmUoJ3JlbW92ZScpO1xuXHRcdH1cblxuXHRcdGxheWVyLl9tYXAgPSBsYXllci5fbWFwVG9BZGQgPSBudWxsO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBoYXNMYXllcihsYXllcjogTGF5ZXIpOiBCb29sZWFuXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSBnaXZlbiBsYXllciBpcyBjdXJyZW50bHkgYWRkZWQgdG8gdGhlIG1hcFxuXHRoYXNMYXllcjogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0cmV0dXJuICEhbGF5ZXIgJiYgKHN0YW1wKGxheWVyKSBpbiB0aGlzLl9sYXllcnMpO1xuXHR9LFxuXG5cdC8qIEBtZXRob2QgZWFjaExheWVyKGZuOiBGdW5jdGlvbiwgY29udGV4dD86IE9iamVjdCk6IHRoaXNcblx0ICogSXRlcmF0ZXMgb3ZlciB0aGUgbGF5ZXJzIG9mIHRoZSBtYXAsIG9wdGlvbmFsbHkgc3BlY2lmeWluZyBjb250ZXh0IG9mIHRoZSBpdGVyYXRvciBmdW5jdGlvbi5cblx0ICogYGBgXG5cdCAqIG1hcC5lYWNoTGF5ZXIoZnVuY3Rpb24obGF5ZXIpe1xuXHQgKiAgICAgbGF5ZXIuYmluZFBvcHVwKCdIZWxsbycpO1xuXHQgKiB9KTtcblx0ICogYGBgXG5cdCAqL1xuXHRlYWNoTGF5ZXI6IGZ1bmN0aW9uIChtZXRob2QsIGNvbnRleHQpIHtcblx0XHRmb3IgKHZhciBpIGluIHRoaXMuX2xheWVycykge1xuXHRcdFx0bWV0aG9kLmNhbGwoY29udGV4dCwgdGhpcy5fbGF5ZXJzW2ldKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X2FkZExheWVyczogZnVuY3Rpb24gKGxheWVycykge1xuXHRcdGxheWVycyA9IGxheWVycyA/IChpc0FycmF5KGxheWVycykgPyBsYXllcnMgOiBbbGF5ZXJzXSkgOiBbXTtcblxuXHRcdGZvciAodmFyIGkgPSAwLCBsZW4gPSBsYXllcnMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdHRoaXMuYWRkTGF5ZXIobGF5ZXJzW2ldKTtcblx0XHR9XG5cdH0sXG5cblx0X2FkZFpvb21MaW1pdDogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0aWYgKGlzTmFOKGxheWVyLm9wdGlvbnMubWF4Wm9vbSkgfHwgIWlzTmFOKGxheWVyLm9wdGlvbnMubWluWm9vbSkpIHtcblx0XHRcdHRoaXMuX3pvb21Cb3VuZExheWVyc1tzdGFtcChsYXllcildID0gbGF5ZXI7XG5cdFx0XHR0aGlzLl91cGRhdGVab29tTGV2ZWxzKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZW1vdmVab29tTGltaXQ6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHZhciBpZCA9IHN0YW1wKGxheWVyKTtcblxuXHRcdGlmICh0aGlzLl96b29tQm91bmRMYXllcnNbaWRdKSB7XG5cdFx0XHRkZWxldGUgdGhpcy5fem9vbUJvdW5kTGF5ZXJzW2lkXTtcblx0XHRcdHRoaXMuX3VwZGF0ZVpvb21MZXZlbHMoKTtcblx0XHR9XG5cdH0sXG5cblx0X3VwZGF0ZVpvb21MZXZlbHM6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgbWluWm9vbSA9IEluZmluaXR5LFxuXHRcdCAgICBtYXhab29tID0gLUluZmluaXR5LFxuXHRcdCAgICBvbGRab29tU3BhbiA9IHRoaXMuX2dldFpvb21TcGFuKCk7XG5cblx0XHRmb3IgKHZhciBpIGluIHRoaXMuX3pvb21Cb3VuZExheWVycykge1xuXHRcdFx0dmFyIG9wdGlvbnMgPSB0aGlzLl96b29tQm91bmRMYXllcnNbaV0ub3B0aW9ucztcblxuXHRcdFx0bWluWm9vbSA9IG9wdGlvbnMubWluWm9vbSA9PT0gdW5kZWZpbmVkID8gbWluWm9vbSA6IE1hdGgubWluKG1pblpvb20sIG9wdGlvbnMubWluWm9vbSk7XG5cdFx0XHRtYXhab29tID0gb3B0aW9ucy5tYXhab29tID09PSB1bmRlZmluZWQgPyBtYXhab29tIDogTWF0aC5tYXgobWF4Wm9vbSwgb3B0aW9ucy5tYXhab29tKTtcblx0XHR9XG5cblx0XHR0aGlzLl9sYXllcnNNYXhab29tID0gbWF4Wm9vbSA9PT0gLUluZmluaXR5ID8gdW5kZWZpbmVkIDogbWF4Wm9vbTtcblx0XHR0aGlzLl9sYXllcnNNaW5ab29tID0gbWluWm9vbSA9PT0gSW5maW5pdHkgPyB1bmRlZmluZWQgOiBtaW5ab29tO1xuXG5cdFx0Ly8gQHNlY3Rpb24gTWFwIHN0YXRlIGNoYW5nZSBldmVudHNcblx0XHQvLyBAZXZlbnQgem9vbWxldmVsc2NoYW5nZTogRXZlbnRcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSBudW1iZXIgb2Ygem9vbWxldmVscyBvbiB0aGUgbWFwIGlzIGNoYW5nZWQgZHVlXG5cdFx0Ly8gdG8gYWRkaW5nIG9yIHJlbW92aW5nIGEgbGF5ZXIuXG5cdFx0aWYgKG9sZFpvb21TcGFuICE9PSB0aGlzLl9nZXRab29tU3BhbigpKSB7XG5cdFx0XHR0aGlzLmZpcmUoJ3pvb21sZXZlbHNjaGFuZ2UnKTtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5vcHRpb25zLm1heFpvb20gPT09IHVuZGVmaW5lZCAmJiB0aGlzLl9sYXllcnNNYXhab29tICYmIHRoaXMuZ2V0Wm9vbSgpID4gdGhpcy5fbGF5ZXJzTWF4Wm9vbSkge1xuXHRcdFx0dGhpcy5zZXRab29tKHRoaXMuX2xheWVyc01heFpvb20pO1xuXHRcdH1cblx0XHRpZiAodGhpcy5vcHRpb25zLm1pblpvb20gPT09IHVuZGVmaW5lZCAmJiB0aGlzLl9sYXllcnNNaW5ab29tICYmIHRoaXMuZ2V0Wm9vbSgpIDwgdGhpcy5fbGF5ZXJzTWluWm9vbSkge1xuXHRcdFx0dGhpcy5zZXRab29tKHRoaXMuX2xheWVyc01pblpvb20pO1xuXHRcdH1cblx0fVxufSk7XG5cbi8qXHJcbiAqIEBjbGFzcyBMYXllckdyb3VwXHJcbiAqIEBha2EgTC5MYXllckdyb3VwXHJcbiAqIEBpbmhlcml0cyBMYXllclxyXG4gKlxyXG4gKiBVc2VkIHRvIGdyb3VwIHNldmVyYWwgbGF5ZXJzIGFuZCBoYW5kbGUgdGhlbSBhcyBvbmUuIElmIHlvdSBhZGQgaXQgdG8gdGhlIG1hcCxcclxuICogYW55IGxheWVycyBhZGRlZCBvciByZW1vdmVkIGZyb20gdGhlIGdyb3VwIHdpbGwgYmUgYWRkZWQvcmVtb3ZlZCBvbiB0aGUgbWFwIGFzXHJcbiAqIHdlbGwuIEV4dGVuZHMgYExheWVyYC5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogYGBganNcclxuICogTC5sYXllckdyb3VwKFttYXJrZXIxLCBtYXJrZXIyXSlcclxuICogXHQuYWRkTGF5ZXIocG9seWxpbmUpXHJcbiAqIFx0LmFkZFRvKG1hcCk7XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcbnZhciBMYXllckdyb3VwID0gTGF5ZXIuZXh0ZW5kKHtcclxuXHJcblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKGxheWVycywgb3B0aW9ucykge1xyXG5cdFx0c2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcclxuXHJcblx0XHR0aGlzLl9sYXllcnMgPSB7fTtcclxuXHJcblx0XHR2YXIgaSwgbGVuO1xyXG5cclxuXHRcdGlmIChsYXllcnMpIHtcclxuXHRcdFx0Zm9yIChpID0gMCwgbGVuID0gbGF5ZXJzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdFx0dGhpcy5hZGRMYXllcihsYXllcnNbaV0pO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBhZGRMYXllcihsYXllcjogTGF5ZXIpOiB0aGlzXHJcblx0Ly8gQWRkcyB0aGUgZ2l2ZW4gbGF5ZXIgdG8gdGhlIGdyb3VwLlxyXG5cdGFkZExheWVyOiBmdW5jdGlvbiAobGF5ZXIpIHtcclxuXHRcdHZhciBpZCA9IHRoaXMuZ2V0TGF5ZXJJZChsYXllcik7XHJcblxyXG5cdFx0dGhpcy5fbGF5ZXJzW2lkXSA9IGxheWVyO1xyXG5cclxuXHRcdGlmICh0aGlzLl9tYXApIHtcclxuXHRcdFx0dGhpcy5fbWFwLmFkZExheWVyKGxheWVyKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHJlbW92ZUxheWVyKGxheWVyOiBMYXllcik6IHRoaXNcclxuXHQvLyBSZW1vdmVzIHRoZSBnaXZlbiBsYXllciBmcm9tIHRoZSBncm91cC5cclxuXHQvLyBAYWx0ZXJuYXRpdmVcclxuXHQvLyBAbWV0aG9kIHJlbW92ZUxheWVyKGlkOiBOdW1iZXIpOiB0aGlzXHJcblx0Ly8gUmVtb3ZlcyB0aGUgbGF5ZXIgd2l0aCB0aGUgZ2l2ZW4gaW50ZXJuYWwgSUQgZnJvbSB0aGUgZ3JvdXAuXHJcblx0cmVtb3ZlTGF5ZXI6IGZ1bmN0aW9uIChsYXllcikge1xyXG5cdFx0dmFyIGlkID0gbGF5ZXIgaW4gdGhpcy5fbGF5ZXJzID8gbGF5ZXIgOiB0aGlzLmdldExheWVySWQobGF5ZXIpO1xyXG5cclxuXHRcdGlmICh0aGlzLl9tYXAgJiYgdGhpcy5fbGF5ZXJzW2lkXSkge1xyXG5cdFx0XHR0aGlzLl9tYXAucmVtb3ZlTGF5ZXIodGhpcy5fbGF5ZXJzW2lkXSk7XHJcblx0XHR9XHJcblxyXG5cdFx0ZGVsZXRlIHRoaXMuX2xheWVyc1tpZF07XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBoYXNMYXllcihsYXllcjogTGF5ZXIpOiBCb29sZWFuXHJcblx0Ly8gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGdpdmVuIGxheWVyIGlzIGN1cnJlbnRseSBhZGRlZCB0byB0aGUgZ3JvdXAuXHJcblx0Ly8gQGFsdGVybmF0aXZlXHJcblx0Ly8gQG1ldGhvZCBoYXNMYXllcihpZDogTnVtYmVyKTogQm9vbGVhblxyXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSBnaXZlbiBpbnRlcm5hbCBJRCBpcyBjdXJyZW50bHkgYWRkZWQgdG8gdGhlIGdyb3VwLlxyXG5cdGhhc0xheWVyOiBmdW5jdGlvbiAobGF5ZXIpIHtcclxuXHRcdHJldHVybiAhIWxheWVyICYmIChsYXllciBpbiB0aGlzLl9sYXllcnMgfHwgdGhpcy5nZXRMYXllcklkKGxheWVyKSBpbiB0aGlzLl9sYXllcnMpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgY2xlYXJMYXllcnMoKTogdGhpc1xyXG5cdC8vIFJlbW92ZXMgYWxsIHRoZSBsYXllcnMgZnJvbSB0aGUgZ3JvdXAuXHJcblx0Y2xlYXJMYXllcnM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLmVhY2hMYXllcih0aGlzLnJlbW92ZUxheWVyLCB0aGlzKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGludm9rZShtZXRob2ROYW1lOiBTdHJpbmcsIOKApik6IHRoaXNcclxuXHQvLyBDYWxscyBgbWV0aG9kTmFtZWAgb24gZXZlcnkgbGF5ZXIgY29udGFpbmVkIGluIHRoaXMgZ3JvdXAsIHBhc3NpbmcgYW55XHJcblx0Ly8gYWRkaXRpb25hbCBwYXJhbWV0ZXJzLiBIYXMgbm8gZWZmZWN0IGlmIHRoZSBsYXllcnMgY29udGFpbmVkIGRvIG5vdFxyXG5cdC8vIGltcGxlbWVudCBgbWV0aG9kTmFtZWAuXHJcblx0aW52b2tlOiBmdW5jdGlvbiAobWV0aG9kTmFtZSkge1xyXG5cdFx0dmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpLFxyXG5cdFx0ICAgIGksIGxheWVyO1xyXG5cclxuXHRcdGZvciAoaSBpbiB0aGlzLl9sYXllcnMpIHtcclxuXHRcdFx0bGF5ZXIgPSB0aGlzLl9sYXllcnNbaV07XHJcblxyXG5cdFx0XHRpZiAobGF5ZXJbbWV0aG9kTmFtZV0pIHtcclxuXHRcdFx0XHRsYXllclttZXRob2ROYW1lXS5hcHBseShsYXllciwgYXJncyk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRvbkFkZDogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0dGhpcy5lYWNoTGF5ZXIobWFwLmFkZExheWVyLCBtYXApO1xyXG5cdH0sXHJcblxyXG5cdG9uUmVtb3ZlOiBmdW5jdGlvbiAobWFwKSB7XHJcblx0XHR0aGlzLmVhY2hMYXllcihtYXAucmVtb3ZlTGF5ZXIsIG1hcCk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBlYWNoTGF5ZXIoZm46IEZ1bmN0aW9uLCBjb250ZXh0PzogT2JqZWN0KTogdGhpc1xyXG5cdC8vIEl0ZXJhdGVzIG92ZXIgdGhlIGxheWVycyBvZiB0aGUgZ3JvdXAsIG9wdGlvbmFsbHkgc3BlY2lmeWluZyBjb250ZXh0IG9mIHRoZSBpdGVyYXRvciBmdW5jdGlvbi5cclxuXHQvLyBgYGBqc1xyXG5cdC8vIGdyb3VwLmVhY2hMYXllcihmdW5jdGlvbiAobGF5ZXIpIHtcclxuXHQvLyBcdGxheWVyLmJpbmRQb3B1cCgnSGVsbG8nKTtcclxuXHQvLyB9KTtcclxuXHQvLyBgYGBcclxuXHRlYWNoTGF5ZXI6IGZ1bmN0aW9uIChtZXRob2QsIGNvbnRleHQpIHtcclxuXHRcdGZvciAodmFyIGkgaW4gdGhpcy5fbGF5ZXJzKSB7XHJcblx0XHRcdG1ldGhvZC5jYWxsKGNvbnRleHQsIHRoaXMuX2xheWVyc1tpXSk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldExheWVyKGlkOiBOdW1iZXIpOiBMYXllclxyXG5cdC8vIFJldHVybnMgdGhlIGxheWVyIHdpdGggdGhlIGdpdmVuIGludGVybmFsIElELlxyXG5cdGdldExheWVyOiBmdW5jdGlvbiAoaWQpIHtcclxuXHRcdHJldHVybiB0aGlzLl9sYXllcnNbaWRdO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0TGF5ZXJzKCk6IExheWVyW11cclxuXHQvLyBSZXR1cm5zIGFuIGFycmF5IG9mIGFsbCB0aGUgbGF5ZXJzIGFkZGVkIHRvIHRoZSBncm91cC5cclxuXHRnZXRMYXllcnM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBsYXllcnMgPSBbXTtcclxuXHRcdHRoaXMuZWFjaExheWVyKGxheWVycy5wdXNoLCBsYXllcnMpO1xyXG5cdFx0cmV0dXJuIGxheWVycztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldFpJbmRleCh6SW5kZXg6IE51bWJlcik6IHRoaXNcclxuXHQvLyBDYWxscyBgc2V0WkluZGV4YCBvbiBldmVyeSBsYXllciBjb250YWluZWQgaW4gdGhpcyBncm91cCwgcGFzc2luZyB0aGUgei1pbmRleC5cclxuXHRzZXRaSW5kZXg6IGZ1bmN0aW9uICh6SW5kZXgpIHtcclxuXHRcdHJldHVybiB0aGlzLmludm9rZSgnc2V0WkluZGV4JywgekluZGV4KTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldExheWVySWQobGF5ZXI6IExheWVyKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgaW50ZXJuYWwgSUQgZm9yIGEgbGF5ZXJcclxuXHRnZXRMYXllcklkOiBmdW5jdGlvbiAobGF5ZXIpIHtcclxuXHRcdHJldHVybiBzdGFtcChsYXllcik7XHJcblx0fVxyXG59KTtcclxuXHJcblxyXG4vLyBAZmFjdG9yeSBMLmxheWVyR3JvdXAobGF5ZXJzPzogTGF5ZXJbXSwgb3B0aW9ucz86IE9iamVjdClcclxuLy8gQ3JlYXRlIGEgbGF5ZXIgZ3JvdXAsIG9wdGlvbmFsbHkgZ2l2ZW4gYW4gaW5pdGlhbCBzZXQgb2YgbGF5ZXJzIGFuZCBhbiBgb3B0aW9uc2Agb2JqZWN0LlxyXG52YXIgbGF5ZXJHcm91cCA9IGZ1bmN0aW9uIChsYXllcnMsIG9wdGlvbnMpIHtcclxuXHRyZXR1cm4gbmV3IExheWVyR3JvdXAobGF5ZXJzLCBvcHRpb25zKTtcclxufTtcblxuLypcclxuICogQGNsYXNzIEZlYXR1cmVHcm91cFxyXG4gKiBAYWthIEwuRmVhdHVyZUdyb3VwXHJcbiAqIEBpbmhlcml0cyBMYXllckdyb3VwXHJcbiAqXHJcbiAqIEV4dGVuZGVkIGBMYXllckdyb3VwYCB0aGF0IG1ha2VzIGl0IGVhc2llciB0byBkbyB0aGUgc2FtZSB0aGluZyB0byBhbGwgaXRzIG1lbWJlciBsYXllcnM6XHJcbiAqICAqIFtgYmluZFBvcHVwYF0oI2xheWVyLWJpbmRwb3B1cCkgYmluZHMgYSBwb3B1cCB0byBhbGwgb2YgdGhlIGxheWVycyBhdCBvbmNlIChsaWtld2lzZSB3aXRoIFtgYmluZFRvb2x0aXBgXSgjbGF5ZXItYmluZHRvb2x0aXApKVxyXG4gKiAgKiBFdmVudHMgYXJlIHByb3BhZ2F0ZWQgdG8gdGhlIGBGZWF0dXJlR3JvdXBgLCBzbyBpZiB0aGUgZ3JvdXAgaGFzIGFuIGV2ZW50XHJcbiAqIGhhbmRsZXIsIGl0IHdpbGwgaGFuZGxlIGV2ZW50cyBmcm9tIGFueSBvZiB0aGUgbGF5ZXJzLiBUaGlzIGluY2x1ZGVzIG1vdXNlIGV2ZW50c1xyXG4gKiBhbmQgY3VzdG9tIGV2ZW50cy5cclxuICogICogSGFzIGBsYXllcmFkZGAgYW5kIGBsYXllcnJlbW92ZWAgZXZlbnRzXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIEwuZmVhdHVyZUdyb3VwKFttYXJrZXIxLCBtYXJrZXIyLCBwb2x5bGluZV0pXHJcbiAqIFx0LmJpbmRQb3B1cCgnSGVsbG8gd29ybGQhJylcclxuICogXHQub24oJ2NsaWNrJywgZnVuY3Rpb24oKSB7IGFsZXJ0KCdDbGlja2VkIG9uIGEgbWVtYmVyIG9mIHRoZSBncm91cCEnKTsgfSlcclxuICogXHQuYWRkVG8obWFwKTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxudmFyIEZlYXR1cmVHcm91cCA9IExheWVyR3JvdXAuZXh0ZW5kKHtcclxuXHJcblx0YWRkTGF5ZXI6IGZ1bmN0aW9uIChsYXllcikge1xyXG5cdFx0aWYgKHRoaXMuaGFzTGF5ZXIobGF5ZXIpKSB7XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cdFx0fVxyXG5cclxuXHRcdGxheWVyLmFkZEV2ZW50UGFyZW50KHRoaXMpO1xyXG5cclxuXHRcdExheWVyR3JvdXAucHJvdG90eXBlLmFkZExheWVyLmNhbGwodGhpcywgbGF5ZXIpO1xyXG5cclxuXHRcdC8vIEBldmVudCBsYXllcmFkZDogTGF5ZXJFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiBhIGxheWVyIGlzIGFkZGVkIHRvIHRoaXMgYEZlYXR1cmVHcm91cGBcclxuXHRcdHJldHVybiB0aGlzLmZpcmUoJ2xheWVyYWRkJywge2xheWVyOiBsYXllcn0pO1xyXG5cdH0sXHJcblxyXG5cdHJlbW92ZUxheWVyOiBmdW5jdGlvbiAobGF5ZXIpIHtcclxuXHRcdGlmICghdGhpcy5oYXNMYXllcihsYXllcikpIHtcclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblx0XHR9XHJcblx0XHRpZiAobGF5ZXIgaW4gdGhpcy5fbGF5ZXJzKSB7XHJcblx0XHRcdGxheWVyID0gdGhpcy5fbGF5ZXJzW2xheWVyXTtcclxuXHRcdH1cclxuXHJcblx0XHRsYXllci5yZW1vdmVFdmVudFBhcmVudCh0aGlzKTtcclxuXHJcblx0XHRMYXllckdyb3VwLnByb3RvdHlwZS5yZW1vdmVMYXllci5jYWxsKHRoaXMsIGxheWVyKTtcclxuXHJcblx0XHQvLyBAZXZlbnQgbGF5ZXJyZW1vdmU6IExheWVyRXZlbnRcclxuXHRcdC8vIEZpcmVkIHdoZW4gYSBsYXllciBpcyByZW1vdmVkIGZyb20gdGhpcyBgRmVhdHVyZUdyb3VwYFxyXG5cdFx0cmV0dXJuIHRoaXMuZmlyZSgnbGF5ZXJyZW1vdmUnLCB7bGF5ZXI6IGxheWVyfSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBzZXRTdHlsZShzdHlsZTogUGF0aCBvcHRpb25zKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIGdpdmVuIHBhdGggb3B0aW9ucyB0byBlYWNoIGxheWVyIG9mIHRoZSBncm91cCB0aGF0IGhhcyBhIGBzZXRTdHlsZWAgbWV0aG9kLlxyXG5cdHNldFN0eWxlOiBmdW5jdGlvbiAoc3R5bGUpIHtcclxuXHRcdHJldHVybiB0aGlzLmludm9rZSgnc2V0U3R5bGUnLCBzdHlsZSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBicmluZ1RvRnJvbnQoKTogdGhpc1xyXG5cdC8vIEJyaW5ncyB0aGUgbGF5ZXIgZ3JvdXAgdG8gdGhlIHRvcCBvZiBhbGwgb3RoZXIgbGF5ZXJzXHJcblx0YnJpbmdUb0Zyb250OiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5pbnZva2UoJ2JyaW5nVG9Gcm9udCcpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgYnJpbmdUb0JhY2soKTogdGhpc1xyXG5cdC8vIEJyaW5ncyB0aGUgbGF5ZXIgZ3JvdXAgdG8gdGhlIGJhY2sgb2YgYWxsIG90aGVyIGxheWVyc1xyXG5cdGJyaW5nVG9CYWNrOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5pbnZva2UoJ2JyaW5nVG9CYWNrJyk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRCb3VuZHMoKTogTGF0TG5nQm91bmRzXHJcblx0Ly8gUmV0dXJucyB0aGUgTGF0TG5nQm91bmRzIG9mIHRoZSBGZWF0dXJlIEdyb3VwIChjcmVhdGVkIGZyb20gYm91bmRzIGFuZCBjb29yZGluYXRlcyBvZiBpdHMgY2hpbGRyZW4pLlxyXG5cdGdldEJvdW5kczogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGJvdW5kcyA9IG5ldyBMYXRMbmdCb3VuZHMoKTtcclxuXHJcblx0XHRmb3IgKHZhciBpZCBpbiB0aGlzLl9sYXllcnMpIHtcclxuXHRcdFx0dmFyIGxheWVyID0gdGhpcy5fbGF5ZXJzW2lkXTtcclxuXHRcdFx0Ym91bmRzLmV4dGVuZChsYXllci5nZXRCb3VuZHMgPyBsYXllci5nZXRCb3VuZHMoKSA6IGxheWVyLmdldExhdExuZygpKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiBib3VuZHM7XHJcblx0fVxyXG59KTtcclxuXHJcbi8vIEBmYWN0b3J5IEwuZmVhdHVyZUdyb3VwKGxheWVyczogTGF5ZXJbXSlcclxuLy8gQ3JlYXRlIGEgZmVhdHVyZSBncm91cCwgb3B0aW9uYWxseSBnaXZlbiBhbiBpbml0aWFsIHNldCBvZiBsYXllcnMuXHJcbnZhciBmZWF0dXJlR3JvdXAgPSBmdW5jdGlvbiAobGF5ZXJzKSB7XHJcblx0cmV0dXJuIG5ldyBGZWF0dXJlR3JvdXAobGF5ZXJzKTtcclxufTtcblxuLypcclxuICogQGNsYXNzIEljb25cclxuICogQGFrYSBMLkljb25cclxuICpcclxuICogUmVwcmVzZW50cyBhbiBpY29uIHRvIHByb3ZpZGUgd2hlbiBjcmVhdGluZyBhIG1hcmtlci5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogYGBganNcclxuICogdmFyIG15SWNvbiA9IEwuaWNvbih7XHJcbiAqICAgICBpY29uVXJsOiAnbXktaWNvbi5wbmcnLFxyXG4gKiAgICAgaWNvblJldGluYVVybDogJ215LWljb25AMngucG5nJyxcclxuICogICAgIGljb25TaXplOiBbMzgsIDk1XSxcclxuICogICAgIGljb25BbmNob3I6IFsyMiwgOTRdLFxyXG4gKiAgICAgcG9wdXBBbmNob3I6IFstMywgLTc2XSxcclxuICogICAgIHNoYWRvd1VybDogJ215LWljb24tc2hhZG93LnBuZycsXHJcbiAqICAgICBzaGFkb3dSZXRpbmFVcmw6ICdteS1pY29uLXNoYWRvd0AyeC5wbmcnLFxyXG4gKiAgICAgc2hhZG93U2l6ZTogWzY4LCA5NV0sXHJcbiAqICAgICBzaGFkb3dBbmNob3I6IFsyMiwgOTRdXHJcbiAqIH0pO1xyXG4gKlxyXG4gKiBMLm1hcmtlcihbNTAuNTA1LCAzMC41N10sIHtpY29uOiBteUljb259KS5hZGRUbyhtYXApO1xyXG4gKiBgYGBcclxuICpcclxuICogYEwuSWNvbi5EZWZhdWx0YCBleHRlbmRzIGBMLkljb25gIGFuZCBpcyB0aGUgYmx1ZSBpY29uIExlYWZsZXQgdXNlcyBmb3IgbWFya2VycyBieSBkZWZhdWx0LlxyXG4gKlxyXG4gKi9cclxuXHJcbnZhciBJY29uID0gQ2xhc3MuZXh0ZW5kKHtcclxuXHJcblx0LyogQHNlY3Rpb25cclxuXHQgKiBAYWthIEljb24gb3B0aW9uc1xyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBpY29uVXJsOiBTdHJpbmcgPSBudWxsXHJcblx0ICogKioocmVxdWlyZWQpKiogVGhlIFVSTCB0byB0aGUgaWNvbiBpbWFnZSAoYWJzb2x1dGUgb3IgcmVsYXRpdmUgdG8geW91ciBzY3JpcHQgcGF0aCkuXHJcblx0ICpcclxuXHQgKiBAb3B0aW9uIGljb25SZXRpbmFVcmw6IFN0cmluZyA9IG51bGxcclxuXHQgKiBUaGUgVVJMIHRvIGEgcmV0aW5hIHNpemVkIHZlcnNpb24gb2YgdGhlIGljb24gaW1hZ2UgKGFic29sdXRlIG9yIHJlbGF0aXZlIHRvIHlvdXJcclxuXHQgKiBzY3JpcHQgcGF0aCkuIFVzZWQgZm9yIFJldGluYSBzY3JlZW4gZGV2aWNlcy5cclxuXHQgKlxyXG5cdCAqIEBvcHRpb24gaWNvblNpemU6IFBvaW50ID0gbnVsbFxyXG5cdCAqIFNpemUgb2YgdGhlIGljb24gaW1hZ2UgaW4gcGl4ZWxzLlxyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBpY29uQW5jaG9yOiBQb2ludCA9IG51bGxcclxuXHQgKiBUaGUgY29vcmRpbmF0ZXMgb2YgdGhlIFwidGlwXCIgb2YgdGhlIGljb24gKHJlbGF0aXZlIHRvIGl0cyB0b3AgbGVmdCBjb3JuZXIpLiBUaGUgaWNvblxyXG5cdCAqIHdpbGwgYmUgYWxpZ25lZCBzbyB0aGF0IHRoaXMgcG9pbnQgaXMgYXQgdGhlIG1hcmtlcidzIGdlb2dyYXBoaWNhbCBsb2NhdGlvbi4gQ2VudGVyZWRcclxuXHQgKiBieSBkZWZhdWx0IGlmIHNpemUgaXMgc3BlY2lmaWVkLCBhbHNvIGNhbiBiZSBzZXQgaW4gQ1NTIHdpdGggbmVnYXRpdmUgbWFyZ2lucy5cclxuXHQgKlxyXG5cdCAqIEBvcHRpb24gcG9wdXBBbmNob3I6IFBvaW50ID0gWzAsIDBdXHJcblx0ICogVGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBwb2ludCBmcm9tIHdoaWNoIHBvcHVwcyB3aWxsIFwib3BlblwiLCByZWxhdGl2ZSB0byB0aGUgaWNvbiBhbmNob3IuXHJcblx0ICpcclxuXHQgKiBAb3B0aW9uIHRvb2x0aXBBbmNob3I6IFBvaW50ID0gWzAsIDBdXHJcblx0ICogVGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBwb2ludCBmcm9tIHdoaWNoIHRvb2x0aXBzIHdpbGwgXCJvcGVuXCIsIHJlbGF0aXZlIHRvIHRoZSBpY29uIGFuY2hvci5cclxuXHQgKlxyXG5cdCAqIEBvcHRpb24gc2hhZG93VXJsOiBTdHJpbmcgPSBudWxsXHJcblx0ICogVGhlIFVSTCB0byB0aGUgaWNvbiBzaGFkb3cgaW1hZ2UuIElmIG5vdCBzcGVjaWZpZWQsIG5vIHNoYWRvdyBpbWFnZSB3aWxsIGJlIGNyZWF0ZWQuXHJcblx0ICpcclxuXHQgKiBAb3B0aW9uIHNoYWRvd1JldGluYVVybDogU3RyaW5nID0gbnVsbFxyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBzaGFkb3dTaXplOiBQb2ludCA9IG51bGxcclxuXHQgKiBTaXplIG9mIHRoZSBzaGFkb3cgaW1hZ2UgaW4gcGl4ZWxzLlxyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBzaGFkb3dBbmNob3I6IFBvaW50ID0gbnVsbFxyXG5cdCAqIFRoZSBjb29yZGluYXRlcyBvZiB0aGUgXCJ0aXBcIiBvZiB0aGUgc2hhZG93IChyZWxhdGl2ZSB0byBpdHMgdG9wIGxlZnQgY29ybmVyKSAodGhlIHNhbWVcclxuXHQgKiBhcyBpY29uQW5jaG9yIGlmIG5vdCBzcGVjaWZpZWQpLlxyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBjbGFzc05hbWU6IFN0cmluZyA9ICcnXHJcblx0ICogQSBjdXN0b20gY2xhc3MgbmFtZSB0byBhc3NpZ24gdG8gYm90aCBpY29uIGFuZCBzaGFkb3cgaW1hZ2VzLiBFbXB0eSBieSBkZWZhdWx0LlxyXG5cdCAqL1xyXG5cclxuXHRvcHRpb25zOiB7XHJcblx0XHRwb3B1cEFuY2hvcjogWzAsIDBdLFxyXG5cdFx0dG9vbHRpcEFuY2hvcjogWzAsIDBdLFxyXG5cdH0sXHJcblxyXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XHJcblx0XHRzZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgY3JlYXRlSWNvbihvbGRJY29uPzogSFRNTEVsZW1lbnQpOiBIVE1MRWxlbWVudFxyXG5cdC8vIENhbGxlZCBpbnRlcm5hbGx5IHdoZW4gdGhlIGljb24gaGFzIHRvIGJlIHNob3duLCByZXR1cm5zIGEgYDxpbWc+YCBIVE1MIGVsZW1lbnRcclxuXHQvLyBzdHlsZWQgYWNjb3JkaW5nIHRvIHRoZSBvcHRpb25zLlxyXG5cdGNyZWF0ZUljb246IGZ1bmN0aW9uIChvbGRJY29uKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5fY3JlYXRlSWNvbignaWNvbicsIG9sZEljb24pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgY3JlYXRlU2hhZG93KG9sZEljb24/OiBIVE1MRWxlbWVudCk6IEhUTUxFbGVtZW50XHJcblx0Ly8gQXMgYGNyZWF0ZUljb25gLCBidXQgZm9yIHRoZSBzaGFkb3cgYmVuZWF0aCBpdC5cclxuXHRjcmVhdGVTaGFkb3c6IGZ1bmN0aW9uIChvbGRJY29uKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5fY3JlYXRlSWNvbignc2hhZG93Jywgb2xkSWNvbik7XHJcblx0fSxcclxuXHJcblx0X2NyZWF0ZUljb246IGZ1bmN0aW9uIChuYW1lLCBvbGRJY29uKSB7XHJcblx0XHR2YXIgc3JjID0gdGhpcy5fZ2V0SWNvblVybChuYW1lKTtcclxuXHJcblx0XHRpZiAoIXNyYykge1xyXG5cdFx0XHRpZiAobmFtZSA9PT0gJ2ljb24nKSB7XHJcblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCdpY29uVXJsIG5vdCBzZXQgaW4gSWNvbiBvcHRpb25zIChzZWUgdGhlIGRvY3MpLicpO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBpbWcgPSB0aGlzLl9jcmVhdGVJbWcoc3JjLCBvbGRJY29uICYmIG9sZEljb24udGFnTmFtZSA9PT0gJ0lNRycgPyBvbGRJY29uIDogbnVsbCk7XHJcblx0XHR0aGlzLl9zZXRJY29uU3R5bGVzKGltZywgbmFtZSk7XHJcblxyXG5cdFx0cmV0dXJuIGltZztcclxuXHR9LFxyXG5cclxuXHRfc2V0SWNvblN0eWxlczogZnVuY3Rpb24gKGltZywgbmFtZSkge1xyXG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XHJcblx0XHR2YXIgc2l6ZU9wdGlvbiA9IG9wdGlvbnNbbmFtZSArICdTaXplJ107XHJcblxyXG5cdFx0aWYgKHR5cGVvZiBzaXplT3B0aW9uID09PSAnbnVtYmVyJykge1xyXG5cdFx0XHRzaXplT3B0aW9uID0gW3NpemVPcHRpb24sIHNpemVPcHRpb25dO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBzaXplID0gdG9Qb2ludChzaXplT3B0aW9uKSxcclxuXHRcdCAgICBhbmNob3IgPSB0b1BvaW50KG5hbWUgPT09ICdzaGFkb3cnICYmIG9wdGlvbnMuc2hhZG93QW5jaG9yIHx8IG9wdGlvbnMuaWNvbkFuY2hvciB8fFxyXG5cdFx0ICAgICAgICAgICAgc2l6ZSAmJiBzaXplLmRpdmlkZUJ5KDIsIHRydWUpKTtcclxuXHJcblx0XHRpbWcuY2xhc3NOYW1lID0gJ2xlYWZsZXQtbWFya2VyLScgKyBuYW1lICsgJyAnICsgKG9wdGlvbnMuY2xhc3NOYW1lIHx8ICcnKTtcclxuXHJcblx0XHRpZiAoYW5jaG9yKSB7XHJcblx0XHRcdGltZy5zdHlsZS5tYXJnaW5MZWZ0ID0gKC1hbmNob3IueCkgKyAncHgnO1xyXG5cdFx0XHRpbWcuc3R5bGUubWFyZ2luVG9wICA9ICgtYW5jaG9yLnkpICsgJ3B4JztcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoc2l6ZSkge1xyXG5cdFx0XHRpbWcuc3R5bGUud2lkdGggID0gc2l6ZS54ICsgJ3B4JztcclxuXHRcdFx0aW1nLnN0eWxlLmhlaWdodCA9IHNpemUueSArICdweCc7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X2NyZWF0ZUltZzogZnVuY3Rpb24gKHNyYywgZWwpIHtcclxuXHRcdGVsID0gZWwgfHwgZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW1nJyk7XHJcblx0XHRlbC5zcmMgPSBzcmM7XHJcblx0XHRyZXR1cm4gZWw7XHJcblx0fSxcclxuXHJcblx0X2dldEljb25Vcmw6IGZ1bmN0aW9uIChuYW1lKSB7XHJcblx0XHRyZXR1cm4gcmV0aW5hICYmIHRoaXMub3B0aW9uc1tuYW1lICsgJ1JldGluYVVybCddIHx8IHRoaXMub3B0aW9uc1tuYW1lICsgJ1VybCddO1xyXG5cdH1cclxufSk7XHJcblxyXG5cclxuLy8gQGZhY3RvcnkgTC5pY29uKG9wdGlvbnM6IEljb24gb3B0aW9ucylcclxuLy8gQ3JlYXRlcyBhbiBpY29uIGluc3RhbmNlIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXHJcbmZ1bmN0aW9uIGljb24ob3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgSWNvbihvcHRpb25zKTtcclxufVxuXG4vKlxuICogQG1pbmljbGFzcyBJY29uLkRlZmF1bHQgKEljb24pXG4gKiBAYWthIEwuSWNvbi5EZWZhdWx0XG4gKiBAc2VjdGlvblxuICpcbiAqIEEgdHJpdmlhbCBzdWJjbGFzcyBvZiBgSWNvbmAsIHJlcHJlc2VudHMgdGhlIGljb24gdG8gdXNlIGluIGBNYXJrZXJgcyB3aGVuXG4gKiBubyBpY29uIGlzIHNwZWNpZmllZC4gUG9pbnRzIHRvIHRoZSBibHVlIG1hcmtlciBpbWFnZSBkaXN0cmlidXRlZCB3aXRoIExlYWZsZXRcbiAqIHJlbGVhc2VzLlxuICpcbiAqIEluIG9yZGVyIHRvIGN1c3RvbWl6ZSB0aGUgZGVmYXVsdCBpY29uLCBqdXN0IGNoYW5nZSB0aGUgcHJvcGVydGllcyBvZiBgTC5JY29uLkRlZmF1bHQucHJvdG90eXBlLm9wdGlvbnNgXG4gKiAod2hpY2ggaXMgYSBzZXQgb2YgYEljb24gb3B0aW9uc2ApLlxuICpcbiAqIElmIHlvdSB3YW50IHRvIF9jb21wbGV0ZWx5XyByZXBsYWNlIHRoZSBkZWZhdWx0IGljb24sIG92ZXJyaWRlIHRoZVxuICogYEwuTWFya2VyLnByb3RvdHlwZS5vcHRpb25zLmljb25gIHdpdGggeW91ciBvd24gaWNvbiBpbnN0ZWFkLlxuICovXG5cbnZhciBJY29uRGVmYXVsdCA9IEljb24uZXh0ZW5kKHtcblxuXHRvcHRpb25zOiB7XG5cdFx0aWNvblVybDogICAgICAgJ21hcmtlci1pY29uLnBuZycsXG5cdFx0aWNvblJldGluYVVybDogJ21hcmtlci1pY29uLTJ4LnBuZycsXG5cdFx0c2hhZG93VXJsOiAgICAgJ21hcmtlci1zaGFkb3cucG5nJyxcblx0XHRpY29uU2l6ZTogICAgWzI1LCA0MV0sXG5cdFx0aWNvbkFuY2hvcjogIFsxMiwgNDFdLFxuXHRcdHBvcHVwQW5jaG9yOiBbMSwgLTM0XSxcblx0XHR0b29sdGlwQW5jaG9yOiBbMTYsIC0yOF0sXG5cdFx0c2hhZG93U2l6ZTogIFs0MSwgNDFdXG5cdH0sXG5cblx0X2dldEljb25Vcmw6IGZ1bmN0aW9uIChuYW1lKSB7XG5cdFx0aWYgKCFJY29uRGVmYXVsdC5pbWFnZVBhdGgpIHtcdC8vIERlcHJlY2F0ZWQsIGJhY2t3YXJkcy1jb21wYXRpYmlsaXR5IG9ubHlcblx0XHRcdEljb25EZWZhdWx0LmltYWdlUGF0aCA9IHRoaXMuX2RldGVjdEljb25QYXRoKCk7XG5cdFx0fVxuXG5cdFx0Ly8gQG9wdGlvbiBpbWFnZVBhdGg6IFN0cmluZ1xuXHRcdC8vIGBJY29uLkRlZmF1bHRgIHdpbGwgdHJ5IHRvIGF1dG8tZGV0ZWN0IHRoZSBsb2NhdGlvbiBvZiB0aGVcblx0XHQvLyBibHVlIGljb24gaW1hZ2VzLiBJZiB5b3UgYXJlIHBsYWNpbmcgdGhlc2UgaW1hZ2VzIGluIGEgbm9uLXN0YW5kYXJkXG5cdFx0Ly8gd2F5LCBzZXQgdGhpcyBvcHRpb24gdG8gcG9pbnQgdG8gdGhlIHJpZ2h0IHBhdGguXG5cdFx0cmV0dXJuICh0aGlzLm9wdGlvbnMuaW1hZ2VQYXRoIHx8IEljb25EZWZhdWx0LmltYWdlUGF0aCkgKyBJY29uLnByb3RvdHlwZS5fZ2V0SWNvblVybC5jYWxsKHRoaXMsIG5hbWUpO1xuXHR9LFxuXG5cdF9kZXRlY3RJY29uUGF0aDogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBlbCA9IGNyZWF0ZSQxKCdkaXYnLCAgJ2xlYWZsZXQtZGVmYXVsdC1pY29uLXBhdGgnLCBkb2N1bWVudC5ib2R5KTtcblx0XHR2YXIgcGF0aCA9IGdldFN0eWxlKGVsLCAnYmFja2dyb3VuZC1pbWFnZScpIHx8XG5cdFx0ICAgICAgICAgICBnZXRTdHlsZShlbCwgJ2JhY2tncm91bmRJbWFnZScpO1x0Ly8gSUU4XG5cblx0XHRkb2N1bWVudC5ib2R5LnJlbW92ZUNoaWxkKGVsKTtcblxuXHRcdGlmIChwYXRoID09PSBudWxsIHx8IHBhdGguaW5kZXhPZigndXJsJykgIT09IDApIHtcblx0XHRcdHBhdGggPSAnJztcblx0XHR9IGVsc2Uge1xuXHRcdFx0cGF0aCA9IHBhdGgucmVwbGFjZSgvXnVybFxcKFtcIiddPy8sICcnKS5yZXBsYWNlKC9tYXJrZXItaWNvblxcLnBuZ1tcIiddP1xcKSQvLCAnJyk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHBhdGg7XG5cdH1cbn0pO1xuXG4vKlxuICogTC5IYW5kbGVyLk1hcmtlckRyYWcgaXMgdXNlZCBpbnRlcm5hbGx5IGJ5IEwuTWFya2VyIHRvIG1ha2UgdGhlIG1hcmtlcnMgZHJhZ2dhYmxlLlxuICovXG5cblxuLyogQG5hbWVzcGFjZSBNYXJrZXJcbiAqIEBzZWN0aW9uIEludGVyYWN0aW9uIGhhbmRsZXJzXG4gKlxuICogSW50ZXJhY3Rpb24gaGFuZGxlcnMgYXJlIHByb3BlcnRpZXMgb2YgYSBtYXJrZXIgaW5zdGFuY2UgdGhhdCBhbGxvdyB5b3UgdG8gY29udHJvbCBpbnRlcmFjdGlvbiBiZWhhdmlvciBpbiBydW50aW1lLCBlbmFibGluZyBvciBkaXNhYmxpbmcgY2VydGFpbiBmZWF0dXJlcyBzdWNoIGFzIGRyYWdnaW5nIChzZWUgYEhhbmRsZXJgIG1ldGhvZHMpLiBFeGFtcGxlOlxuICpcbiAqIGBgYGpzXG4gKiBtYXJrZXIuZHJhZ2dpbmcuZGlzYWJsZSgpO1xuICogYGBgXG4gKlxuICogQHByb3BlcnR5IGRyYWdnaW5nOiBIYW5kbGVyXG4gKiBNYXJrZXIgZHJhZ2dpbmcgaGFuZGxlciAoYnkgYm90aCBtb3VzZSBhbmQgdG91Y2gpLiBPbmx5IHZhbGlkIHdoZW4gdGhlIG1hcmtlciBpcyBvbiB0aGUgbWFwIChPdGhlcndpc2Ugc2V0IFtgbWFya2VyLm9wdGlvbnMuZHJhZ2dhYmxlYF0oI21hcmtlci1kcmFnZ2FibGUpKS5cbiAqL1xuXG52YXIgTWFya2VyRHJhZyA9IEhhbmRsZXIuZXh0ZW5kKHtcblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKG1hcmtlcikge1xuXHRcdHRoaXMuX21hcmtlciA9IG1hcmtlcjtcblx0fSxcblxuXHRhZGRIb29rczogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBpY29uID0gdGhpcy5fbWFya2VyLl9pY29uO1xuXG5cdFx0aWYgKCF0aGlzLl9kcmFnZ2FibGUpIHtcblx0XHRcdHRoaXMuX2RyYWdnYWJsZSA9IG5ldyBEcmFnZ2FibGUoaWNvbiwgaWNvbiwgdHJ1ZSk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fZHJhZ2dhYmxlLm9uKHtcblx0XHRcdGRyYWdzdGFydDogdGhpcy5fb25EcmFnU3RhcnQsXG5cdFx0XHRwcmVkcmFnOiB0aGlzLl9vblByZURyYWcsXG5cdFx0XHRkcmFnOiB0aGlzLl9vbkRyYWcsXG5cdFx0XHRkcmFnZW5kOiB0aGlzLl9vbkRyYWdFbmRcblx0XHR9LCB0aGlzKS5lbmFibGUoKTtcblxuXHRcdGFkZENsYXNzKGljb24sICdsZWFmbGV0LW1hcmtlci1kcmFnZ2FibGUnKTtcblx0fSxcblxuXHRyZW1vdmVIb29rczogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX2RyYWdnYWJsZS5vZmYoe1xuXHRcdFx0ZHJhZ3N0YXJ0OiB0aGlzLl9vbkRyYWdTdGFydCxcblx0XHRcdHByZWRyYWc6IHRoaXMuX29uUHJlRHJhZyxcblx0XHRcdGRyYWc6IHRoaXMuX29uRHJhZyxcblx0XHRcdGRyYWdlbmQ6IHRoaXMuX29uRHJhZ0VuZFxuXHRcdH0sIHRoaXMpLmRpc2FibGUoKTtcblxuXHRcdGlmICh0aGlzLl9tYXJrZXIuX2ljb24pIHtcblx0XHRcdHJlbW92ZUNsYXNzKHRoaXMuX21hcmtlci5faWNvbiwgJ2xlYWZsZXQtbWFya2VyLWRyYWdnYWJsZScpO1xuXHRcdH1cblx0fSxcblxuXHRtb3ZlZDogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLl9kcmFnZ2FibGUgJiYgdGhpcy5fZHJhZ2dhYmxlLl9tb3ZlZDtcblx0fSxcblxuXHRfYWRqdXN0UGFuOiBmdW5jdGlvbiAoZSkge1xuXHRcdHZhciBtYXJrZXIgPSB0aGlzLl9tYXJrZXIsXG5cdFx0ICAgIG1hcCA9IG1hcmtlci5fbWFwLFxuXHRcdCAgICBzcGVlZCA9IHRoaXMuX21hcmtlci5vcHRpb25zLmF1dG9QYW5TcGVlZCxcblx0XHQgICAgcGFkZGluZyA9IHRoaXMuX21hcmtlci5vcHRpb25zLmF1dG9QYW5QYWRkaW5nLFxuXHRcdCAgICBpY29uUG9zID0gTC5Eb21VdGlsLmdldFBvc2l0aW9uKG1hcmtlci5faWNvbiksXG5cdFx0ICAgIGJvdW5kcyA9IG1hcC5nZXRQaXhlbEJvdW5kcygpLFxuXHRcdCAgICBvcmlnaW4gPSBtYXAuZ2V0UGl4ZWxPcmlnaW4oKTtcblxuXHRcdHZhciBwYW5Cb3VuZHMgPSB0b0JvdW5kcyhcblx0XHRcdGJvdW5kcy5taW4uX3N1YnRyYWN0KG9yaWdpbikuYWRkKHBhZGRpbmcpLFxuXHRcdFx0Ym91bmRzLm1heC5fc3VidHJhY3Qob3JpZ2luKS5zdWJ0cmFjdChwYWRkaW5nKVxuXHRcdCk7XG5cblx0XHRpZiAoIXBhbkJvdW5kcy5jb250YWlucyhpY29uUG9zKSkge1xuXHRcdFx0Ly8gQ29tcHV0ZSBpbmNyZW1lbnRhbCBtb3ZlbWVudFxuXHRcdFx0dmFyIG1vdmVtZW50ID0gdG9Qb2ludChcblx0XHRcdFx0KE1hdGgubWF4KHBhbkJvdW5kcy5tYXgueCwgaWNvblBvcy54KSAtIHBhbkJvdW5kcy5tYXgueCkgLyAoYm91bmRzLm1heC54IC0gcGFuQm91bmRzLm1heC54KSAtXG5cdFx0XHRcdChNYXRoLm1pbihwYW5Cb3VuZHMubWluLngsIGljb25Qb3MueCkgLSBwYW5Cb3VuZHMubWluLngpIC8gKGJvdW5kcy5taW4ueCAtIHBhbkJvdW5kcy5taW4ueCksXG5cblx0XHRcdFx0KE1hdGgubWF4KHBhbkJvdW5kcy5tYXgueSwgaWNvblBvcy55KSAtIHBhbkJvdW5kcy5tYXgueSkgLyAoYm91bmRzLm1heC55IC0gcGFuQm91bmRzLm1heC55KSAtXG5cdFx0XHRcdChNYXRoLm1pbihwYW5Cb3VuZHMubWluLnksIGljb25Qb3MueSkgLSBwYW5Cb3VuZHMubWluLnkpIC8gKGJvdW5kcy5taW4ueSAtIHBhbkJvdW5kcy5taW4ueSlcblx0XHRcdCkubXVsdGlwbHlCeShzcGVlZCk7XG5cblx0XHRcdG1hcC5wYW5CeShtb3ZlbWVudCwge2FuaW1hdGU6IGZhbHNlfSk7XG5cblx0XHRcdHRoaXMuX2RyYWdnYWJsZS5fbmV3UG9zLl9hZGQobW92ZW1lbnQpO1xuXHRcdFx0dGhpcy5fZHJhZ2dhYmxlLl9zdGFydFBvcy5fYWRkKG1vdmVtZW50KTtcblxuXHRcdFx0TC5Eb21VdGlsLnNldFBvc2l0aW9uKG1hcmtlci5faWNvbiwgdGhpcy5fZHJhZ2dhYmxlLl9uZXdQb3MpO1xuXHRcdFx0dGhpcy5fb25EcmFnKGUpO1xuXG5cdFx0XHR0aGlzLl9wYW5SZXF1ZXN0ID0gcmVxdWVzdEFuaW1GcmFtZSh0aGlzLl9hZGp1c3RQYW4uYmluZCh0aGlzLCBlKSk7XG5cdFx0fVxuXHR9LFxuXG5cdF9vbkRyYWdTdGFydDogZnVuY3Rpb24gKCkge1xuXHRcdC8vIEBzZWN0aW9uIERyYWdnaW5nIGV2ZW50c1xuXHRcdC8vIEBldmVudCBkcmFnc3RhcnQ6IEV2ZW50XG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgdXNlciBzdGFydHMgZHJhZ2dpbmcgdGhlIG1hcmtlci5cblxuXHRcdC8vIEBldmVudCBtb3Zlc3RhcnQ6IEV2ZW50XG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFya2VyIHN0YXJ0cyBtb3ZpbmcgKGJlY2F1c2Ugb2YgZHJhZ2dpbmcpLlxuXG5cdFx0dGhpcy5fb2xkTGF0TG5nID0gdGhpcy5fbWFya2VyLmdldExhdExuZygpO1xuXHRcdHRoaXMuX21hcmtlclxuXHRcdCAgICAuY2xvc2VQb3B1cCgpXG5cdFx0ICAgIC5maXJlKCdtb3Zlc3RhcnQnKVxuXHRcdCAgICAuZmlyZSgnZHJhZ3N0YXJ0Jyk7XG5cdH0sXG5cblx0X29uUHJlRHJhZzogZnVuY3Rpb24gKGUpIHtcblx0XHRpZiAodGhpcy5fbWFya2VyLm9wdGlvbnMuYXV0b1Bhbikge1xuXHRcdFx0Y2FuY2VsQW5pbUZyYW1lKHRoaXMuX3BhblJlcXVlc3QpO1xuXHRcdFx0dGhpcy5fcGFuUmVxdWVzdCA9IHJlcXVlc3RBbmltRnJhbWUodGhpcy5fYWRqdXN0UGFuLmJpbmQodGhpcywgZSkpO1xuXHRcdH1cblx0fSxcblxuXHRfb25EcmFnOiBmdW5jdGlvbiAoZSkge1xuXHRcdHZhciBtYXJrZXIgPSB0aGlzLl9tYXJrZXIsXG5cdFx0ICAgIHNoYWRvdyA9IG1hcmtlci5fc2hhZG93LFxuXHRcdGljb25Qb3MgPSBnZXRQb3NpdGlvbihtYXJrZXIuX2ljb24pLFxuXHRcdCAgICBsYXRsbmcgPSBtYXJrZXIuX21hcC5sYXllclBvaW50VG9MYXRMbmcoaWNvblBvcyk7XG5cblx0XHQvLyB1cGRhdGUgc2hhZG93IHBvc2l0aW9uXG5cdFx0aWYgKHNoYWRvdykge1xuXHRcdFx0c2V0UG9zaXRpb24oc2hhZG93LCBpY29uUG9zKTtcblx0XHR9XG5cblx0XHRtYXJrZXIuX2xhdGxuZyA9IGxhdGxuZztcblx0XHRlLmxhdGxuZyA9IGxhdGxuZztcblx0XHRlLm9sZExhdExuZyA9IHRoaXMuX29sZExhdExuZztcblxuXHRcdC8vIEBldmVudCBkcmFnOiBFdmVudFxuXHRcdC8vIEZpcmVkIHJlcGVhdGVkbHkgd2hpbGUgdGhlIHVzZXIgZHJhZ3MgdGhlIG1hcmtlci5cblx0XHRtYXJrZXJcblx0XHQgICAgLmZpcmUoJ21vdmUnLCBlKVxuXHRcdCAgICAuZmlyZSgnZHJhZycsIGUpO1xuXHR9LFxuXG5cdF9vbkRyYWdFbmQ6IGZ1bmN0aW9uIChlKSB7XG5cdFx0Ly8gQGV2ZW50IGRyYWdlbmQ6IERyYWdFbmRFdmVudFxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIHVzZXIgc3RvcHMgZHJhZ2dpbmcgdGhlIG1hcmtlci5cblxuXHRcdCBjYW5jZWxBbmltRnJhbWUodGhpcy5fcGFuUmVxdWVzdCk7XG5cblx0XHQvLyBAZXZlbnQgbW92ZWVuZDogRXZlbnRcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSBtYXJrZXIgc3RvcHMgbW92aW5nIChiZWNhdXNlIG9mIGRyYWdnaW5nKS5cblx0XHRkZWxldGUgdGhpcy5fb2xkTGF0TG5nO1xuXHRcdHRoaXMuX21hcmtlclxuXHRcdCAgICAuZmlyZSgnbW92ZWVuZCcpXG5cdFx0ICAgIC5maXJlKCdkcmFnZW5kJywgZSk7XG5cdH1cbn0pO1xuXG4vKlxyXG4gKiBAY2xhc3MgTWFya2VyXHJcbiAqIEBpbmhlcml0cyBJbnRlcmFjdGl2ZSBsYXllclxyXG4gKiBAYWthIEwuTWFya2VyXHJcbiAqIEwuTWFya2VyIGlzIHVzZWQgdG8gZGlzcGxheSBjbGlja2FibGUvZHJhZ2dhYmxlIGljb25zIG9uIHRoZSBtYXAuIEV4dGVuZHMgYExheWVyYC5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogYGBganNcclxuICogTC5tYXJrZXIoWzUwLjUsIDMwLjVdKS5hZGRUbyhtYXApO1xyXG4gKiBgYGBcclxuICovXHJcblxyXG52YXIgTWFya2VyID0gTGF5ZXIuZXh0ZW5kKHtcclxuXHJcblx0Ly8gQHNlY3Rpb25cclxuXHQvLyBAYWthIE1hcmtlciBvcHRpb25zXHJcblx0b3B0aW9uczoge1xyXG5cdFx0Ly8gQG9wdGlvbiBpY29uOiBJY29uID0gKlxyXG5cdFx0Ly8gSWNvbiBpbnN0YW5jZSB0byB1c2UgZm9yIHJlbmRlcmluZyB0aGUgbWFya2VyLlxyXG5cdFx0Ly8gU2VlIFtJY29uIGRvY3VtZW50YXRpb25dKCNMLkljb24pIGZvciBkZXRhaWxzIG9uIGhvdyB0byBjdXN0b21pemUgdGhlIG1hcmtlciBpY29uLlxyXG5cdFx0Ly8gSWYgbm90IHNwZWNpZmllZCwgYSBjb21tb24gaW5zdGFuY2Ugb2YgYEwuSWNvbi5EZWZhdWx0YCBpcyB1c2VkLlxyXG5cdFx0aWNvbjogbmV3IEljb25EZWZhdWx0KCksXHJcblxyXG5cdFx0Ly8gT3B0aW9uIGluaGVyaXRlZCBmcm9tIFwiSW50ZXJhY3RpdmUgbGF5ZXJcIiBhYnN0cmFjdCBjbGFzc1xyXG5cdFx0aW50ZXJhY3RpdmU6IHRydWUsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBkcmFnZ2FibGU6IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gV2hldGhlciB0aGUgbWFya2VyIGlzIGRyYWdnYWJsZSB3aXRoIG1vdXNlL3RvdWNoIG9yIG5vdC5cclxuXHRcdGRyYWdnYWJsZTogZmFsc2UsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhdXRvUGFuOiBCb29sZWFuID0gZmFsc2VcclxuXHRcdC8vIFNldCBpdCB0byBgdHJ1ZWAgaWYgeW91IHdhbnQgdGhlIG1hcCB0byBkbyBwYW5uaW5nIGFuaW1hdGlvbiB3aGVuIG1hcmtlciBoaXRzIHRoZSBlZGdlcy5cclxuXHRcdGF1dG9QYW46IGZhbHNlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gYXV0b1BhblBhZGRpbmc6IFBvaW50ID0gUG9pbnQoNTAsIDUwKVxyXG5cdFx0Ly8gRXF1aXZhbGVudCBvZiBzZXR0aW5nIGJvdGggdG9wIGxlZnQgYW5kIGJvdHRvbSByaWdodCBhdXRvcGFuIHBhZGRpbmcgdG8gdGhlIHNhbWUgdmFsdWUuXHJcblx0XHRhdXRvUGFuUGFkZGluZzogWzUwLCA1MF0sXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhdXRvUGFuU3BlZWQ6IE51bWJlciA9IDEwXHJcblx0XHQvLyBOdW1iZXIgb2YgcGl4ZWxzIHRoZSBtYXAgc2hvdWxkIG1vdmUgYnkuXHJcblx0XHRhdXRvUGFuU3BlZWQ6IDEwLFxyXG5cclxuXHRcdC8vIEBvcHRpb24ga2V5Ym9hcmQ6IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBXaGV0aGVyIHRoZSBtYXJrZXIgY2FuIGJlIHRhYmJlZCB0byB3aXRoIGEga2V5Ym9hcmQgYW5kIGNsaWNrZWQgYnkgcHJlc3NpbmcgZW50ZXIuXHJcblx0XHRrZXlib2FyZDogdHJ1ZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHRpdGxlOiBTdHJpbmcgPSAnJ1xyXG5cdFx0Ly8gVGV4dCBmb3IgdGhlIGJyb3dzZXIgdG9vbHRpcCB0aGF0IGFwcGVhciBvbiBtYXJrZXIgaG92ZXIgKG5vIHRvb2x0aXAgYnkgZGVmYXVsdCkuXHJcblx0XHR0aXRsZTogJycsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhbHQ6IFN0cmluZyA9ICcnXHJcblx0XHQvLyBUZXh0IGZvciB0aGUgYGFsdGAgYXR0cmlidXRlIG9mIHRoZSBpY29uIGltYWdlICh1c2VmdWwgZm9yIGFjY2Vzc2liaWxpdHkpLlxyXG5cdFx0YWx0OiAnJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHpJbmRleE9mZnNldDogTnVtYmVyID0gMFxyXG5cdFx0Ly8gQnkgZGVmYXVsdCwgbWFya2VyIGltYWdlcyB6SW5kZXggaXMgc2V0IGF1dG9tYXRpY2FsbHkgYmFzZWQgb24gaXRzIGxhdGl0dWRlLiBVc2UgdGhpcyBvcHRpb24gaWYgeW91IHdhbnQgdG8gcHV0IHRoZSBtYXJrZXIgb24gdG9wIG9mIGFsbCBvdGhlcnMgKG9yIGJlbG93KSwgc3BlY2lmeWluZyBhIGhpZ2ggdmFsdWUgbGlrZSBgMTAwMGAgKG9yIGhpZ2ggbmVnYXRpdmUgdmFsdWUsIHJlc3BlY3RpdmVseSkuXHJcblx0XHR6SW5kZXhPZmZzZXQ6IDAsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBvcGFjaXR5OiBOdW1iZXIgPSAxLjBcclxuXHRcdC8vIFRoZSBvcGFjaXR5IG9mIHRoZSBtYXJrZXIuXHJcblx0XHRvcGFjaXR5OiAxLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gcmlzZU9uSG92ZXI6IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gSWYgYHRydWVgLCB0aGUgbWFya2VyIHdpbGwgZ2V0IG9uIHRvcCBvZiBvdGhlcnMgd2hlbiB5b3UgaG92ZXIgdGhlIG1vdXNlIG92ZXIgaXQuXHJcblx0XHRyaXNlT25Ib3ZlcjogZmFsc2UsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiByaXNlT2Zmc2V0OiBOdW1iZXIgPSAyNTBcclxuXHRcdC8vIFRoZSB6LWluZGV4IG9mZnNldCB1c2VkIGZvciB0aGUgYHJpc2VPbkhvdmVyYCBmZWF0dXJlLlxyXG5cdFx0cmlzZU9mZnNldDogMjUwLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gcGFuZTogU3RyaW5nID0gJ21hcmtlclBhbmUnXHJcblx0XHQvLyBgTWFwIHBhbmVgIHdoZXJlIHRoZSBtYXJrZXJzIGljb24gd2lsbCBiZSBhZGRlZC5cclxuXHRcdHBhbmU6ICdtYXJrZXJQYW5lJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGJ1YmJsaW5nTW91c2VFdmVudHM6IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gV2hlbiBgdHJ1ZWAsIGEgbW91c2UgZXZlbnQgb24gdGhpcyBtYXJrZXIgd2lsbCB0cmlnZ2VyIHRoZSBzYW1lIGV2ZW50IG9uIHRoZSBtYXBcclxuXHRcdC8vICh1bmxlc3MgW2BMLkRvbUV2ZW50LnN0b3BQcm9wYWdhdGlvbmBdKCNkb21ldmVudC1zdG9wcHJvcGFnYXRpb24pIGlzIHVzZWQpLlxyXG5cdFx0YnViYmxpbmdNb3VzZUV2ZW50czogZmFsc2VcclxuXHR9LFxyXG5cclxuXHQvKiBAc2VjdGlvblxyXG5cdCAqXHJcblx0ICogSW4gYWRkaXRpb24gdG8gW3NoYXJlZCBsYXllciBtZXRob2RzXSgjTGF5ZXIpIGxpa2UgYGFkZFRvKClgIGFuZCBgcmVtb3ZlKClgIGFuZCBbcG9wdXAgbWV0aG9kc10oI1BvcHVwKSBsaWtlIGJpbmRQb3B1cCgpIHlvdSBjYW4gYWxzbyB1c2UgdGhlIGZvbGxvd2luZyBtZXRob2RzOlxyXG5cdCAqL1xyXG5cclxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAobGF0bG5nLCBvcHRpb25zKSB7XHJcblx0XHRzZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xyXG5cdFx0dGhpcy5fbGF0bG5nID0gdG9MYXRMbmcobGF0bG5nKTtcclxuXHR9LFxyXG5cclxuXHRvbkFkZDogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0dGhpcy5fem9vbUFuaW1hdGVkID0gdGhpcy5fem9vbUFuaW1hdGVkICYmIG1hcC5vcHRpb25zLm1hcmtlclpvb21BbmltYXRpb247XHJcblxyXG5cdFx0aWYgKHRoaXMuX3pvb21BbmltYXRlZCkge1xyXG5cdFx0XHRtYXAub24oJ3pvb21hbmltJywgdGhpcy5fYW5pbWF0ZVpvb20sIHRoaXMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2luaXRJY29uKCk7XHJcblx0XHR0aGlzLnVwZGF0ZSgpO1xyXG5cdH0sXHJcblxyXG5cdG9uUmVtb3ZlOiBmdW5jdGlvbiAobWFwKSB7XHJcblx0XHRpZiAodGhpcy5kcmFnZ2luZyAmJiB0aGlzLmRyYWdnaW5nLmVuYWJsZWQoKSkge1xyXG5cdFx0XHR0aGlzLm9wdGlvbnMuZHJhZ2dhYmxlID0gdHJ1ZTtcclxuXHRcdFx0dGhpcy5kcmFnZ2luZy5yZW1vdmVIb29rcygpO1xyXG5cdFx0fVxyXG5cdFx0ZGVsZXRlIHRoaXMuZHJhZ2dpbmc7XHJcblxyXG5cdFx0aWYgKHRoaXMuX3pvb21BbmltYXRlZCkge1xyXG5cdFx0XHRtYXAub2ZmKCd6b29tYW5pbScsIHRoaXMuX2FuaW1hdGVab29tLCB0aGlzKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9yZW1vdmVJY29uKCk7XHJcblx0XHR0aGlzLl9yZW1vdmVTaGFkb3coKTtcclxuXHR9LFxyXG5cclxuXHRnZXRFdmVudHM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB7XHJcblx0XHRcdHpvb206IHRoaXMudXBkYXRlLFxyXG5cdFx0XHR2aWV3cmVzZXQ6IHRoaXMudXBkYXRlXHJcblx0XHR9O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0TGF0TG5nOiBMYXRMbmdcclxuXHQvLyBSZXR1cm5zIHRoZSBjdXJyZW50IGdlb2dyYXBoaWNhbCBwb3NpdGlvbiBvZiB0aGUgbWFya2VyLlxyXG5cdGdldExhdExuZzogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX2xhdGxuZztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldExhdExuZyhsYXRsbmc6IExhdExuZyk6IHRoaXNcclxuXHQvLyBDaGFuZ2VzIHRoZSBtYXJrZXIgcG9zaXRpb24gdG8gdGhlIGdpdmVuIHBvaW50LlxyXG5cdHNldExhdExuZzogZnVuY3Rpb24gKGxhdGxuZykge1xyXG5cdFx0dmFyIG9sZExhdExuZyA9IHRoaXMuX2xhdGxuZztcclxuXHRcdHRoaXMuX2xhdGxuZyA9IHRvTGF0TG5nKGxhdGxuZyk7XHJcblx0XHR0aGlzLnVwZGF0ZSgpO1xyXG5cclxuXHRcdC8vIEBldmVudCBtb3ZlOiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFya2VyIGlzIG1vdmVkIHZpYSBbYHNldExhdExuZ2BdKCNtYXJrZXItc2V0bGF0bG5nKSBvciBieSBbZHJhZ2dpbmddKCNtYXJrZXItZHJhZ2dpbmcpLiBPbGQgYW5kIG5ldyBjb29yZGluYXRlcyBhcmUgaW5jbHVkZWQgaW4gZXZlbnQgYXJndW1lbnRzIGFzIGBvbGRMYXRMbmdgLCBgbGF0bG5nYC5cclxuXHRcdHJldHVybiB0aGlzLmZpcmUoJ21vdmUnLCB7b2xkTGF0TG5nOiBvbGRMYXRMbmcsIGxhdGxuZzogdGhpcy5fbGF0bG5nfSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBzZXRaSW5kZXhPZmZzZXQob2Zmc2V0OiBOdW1iZXIpOiB0aGlzXHJcblx0Ly8gQ2hhbmdlcyB0aGUgW3pJbmRleCBvZmZzZXRdKCNtYXJrZXItemluZGV4b2Zmc2V0KSBvZiB0aGUgbWFya2VyLlxyXG5cdHNldFpJbmRleE9mZnNldDogZnVuY3Rpb24gKG9mZnNldCkge1xyXG5cdFx0dGhpcy5vcHRpb25zLnpJbmRleE9mZnNldCA9IG9mZnNldDtcclxuXHRcdHJldHVybiB0aGlzLnVwZGF0ZSgpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0SWNvbihpY29uOiBJY29uKTogdGhpc1xyXG5cdC8vIENoYW5nZXMgdGhlIG1hcmtlciBpY29uLlxyXG5cdHNldEljb246IGZ1bmN0aW9uIChpY29uKSB7XHJcblxyXG5cdFx0dGhpcy5vcHRpb25zLmljb24gPSBpY29uO1xyXG5cclxuXHRcdGlmICh0aGlzLl9tYXApIHtcclxuXHRcdFx0dGhpcy5faW5pdEljb24oKTtcclxuXHRcdFx0dGhpcy51cGRhdGUoKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAodGhpcy5fcG9wdXApIHtcclxuXHRcdFx0dGhpcy5iaW5kUG9wdXAodGhpcy5fcG9wdXAsIHRoaXMuX3BvcHVwLm9wdGlvbnMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdGdldEVsZW1lbnQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9pY29uO1xyXG5cdH0sXHJcblxyXG5cdHVwZGF0ZTogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdGlmICh0aGlzLl9pY29uICYmIHRoaXMuX21hcCkge1xyXG5cdFx0XHR2YXIgcG9zID0gdGhpcy5fbWFwLmxhdExuZ1RvTGF5ZXJQb2ludCh0aGlzLl9sYXRsbmcpLnJvdW5kKCk7XHJcblx0XHRcdHRoaXMuX3NldFBvcyhwb3MpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdF9pbml0SWNvbjogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnMsXHJcblx0XHQgICAgY2xhc3NUb0FkZCA9ICdsZWFmbGV0LXpvb20tJyArICh0aGlzLl96b29tQW5pbWF0ZWQgPyAnYW5pbWF0ZWQnIDogJ2hpZGUnKTtcclxuXHJcblx0XHR2YXIgaWNvbiA9IG9wdGlvbnMuaWNvbi5jcmVhdGVJY29uKHRoaXMuX2ljb24pLFxyXG5cdFx0ICAgIGFkZEljb24gPSBmYWxzZTtcclxuXHJcblx0XHQvLyBpZiB3ZSdyZSBub3QgcmV1c2luZyB0aGUgaWNvbiwgcmVtb3ZlIHRoZSBvbGQgb25lIGFuZCBpbml0IG5ldyBvbmVcclxuXHRcdGlmIChpY29uICE9PSB0aGlzLl9pY29uKSB7XHJcblx0XHRcdGlmICh0aGlzLl9pY29uKSB7XHJcblx0XHRcdFx0dGhpcy5fcmVtb3ZlSWNvbigpO1xyXG5cdFx0XHR9XHJcblx0XHRcdGFkZEljb24gPSB0cnVlO1xyXG5cclxuXHRcdFx0aWYgKG9wdGlvbnMudGl0bGUpIHtcclxuXHRcdFx0XHRpY29uLnRpdGxlID0gb3B0aW9ucy50aXRsZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKGljb24udGFnTmFtZSA9PT0gJ0lNRycpIHtcclxuXHRcdFx0XHRpY29uLmFsdCA9IG9wdGlvbnMuYWx0IHx8ICcnO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0YWRkQ2xhc3MoaWNvbiwgY2xhc3NUb0FkZCk7XHJcblxyXG5cdFx0aWYgKG9wdGlvbnMua2V5Ym9hcmQpIHtcclxuXHRcdFx0aWNvbi50YWJJbmRleCA9ICcwJztcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9pY29uID0gaWNvbjtcclxuXHJcblx0XHRpZiAob3B0aW9ucy5yaXNlT25Ib3Zlcikge1xyXG5cdFx0XHR0aGlzLm9uKHtcclxuXHRcdFx0XHRtb3VzZW92ZXI6IHRoaXMuX2JyaW5nVG9Gcm9udCxcclxuXHRcdFx0XHRtb3VzZW91dDogdGhpcy5fcmVzZXRaSW5kZXhcclxuXHRcdFx0fSk7XHJcblx0XHR9XHJcblxyXG5cdFx0dmFyIG5ld1NoYWRvdyA9IG9wdGlvbnMuaWNvbi5jcmVhdGVTaGFkb3codGhpcy5fc2hhZG93KSxcclxuXHRcdCAgICBhZGRTaGFkb3cgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAobmV3U2hhZG93ICE9PSB0aGlzLl9zaGFkb3cpIHtcclxuXHRcdFx0dGhpcy5fcmVtb3ZlU2hhZG93KCk7XHJcblx0XHRcdGFkZFNoYWRvdyA9IHRydWU7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKG5ld1NoYWRvdykge1xyXG5cdFx0XHRhZGRDbGFzcyhuZXdTaGFkb3csIGNsYXNzVG9BZGQpO1xyXG5cdFx0XHRuZXdTaGFkb3cuYWx0ID0gJyc7XHJcblx0XHR9XHJcblx0XHR0aGlzLl9zaGFkb3cgPSBuZXdTaGFkb3c7XHJcblxyXG5cclxuXHRcdGlmIChvcHRpb25zLm9wYWNpdHkgPCAxKSB7XHJcblx0XHRcdHRoaXMuX3VwZGF0ZU9wYWNpdHkoKTtcclxuXHRcdH1cclxuXHJcblxyXG5cdFx0aWYgKGFkZEljb24pIHtcclxuXHRcdFx0dGhpcy5nZXRQYW5lKCkuYXBwZW5kQ2hpbGQodGhpcy5faWNvbik7XHJcblx0XHR9XHJcblx0XHR0aGlzLl9pbml0SW50ZXJhY3Rpb24oKTtcclxuXHRcdGlmIChuZXdTaGFkb3cgJiYgYWRkU2hhZG93KSB7XHJcblx0XHRcdHRoaXMuZ2V0UGFuZSgnc2hhZG93UGFuZScpLmFwcGVuZENoaWxkKHRoaXMuX3NoYWRvdyk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X3JlbW92ZUljb246IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICh0aGlzLm9wdGlvbnMucmlzZU9uSG92ZXIpIHtcclxuXHRcdFx0dGhpcy5vZmYoe1xyXG5cdFx0XHRcdG1vdXNlb3ZlcjogdGhpcy5fYnJpbmdUb0Zyb250LFxyXG5cdFx0XHRcdG1vdXNlb3V0OiB0aGlzLl9yZXNldFpJbmRleFxyXG5cdFx0XHR9KTtcclxuXHRcdH1cclxuXHJcblx0XHRyZW1vdmUodGhpcy5faWNvbik7XHJcblx0XHR0aGlzLnJlbW92ZUludGVyYWN0aXZlVGFyZ2V0KHRoaXMuX2ljb24pO1xyXG5cclxuXHRcdHRoaXMuX2ljb24gPSBudWxsO1xyXG5cdH0sXHJcblxyXG5cdF9yZW1vdmVTaGFkb3c6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICh0aGlzLl9zaGFkb3cpIHtcclxuXHRcdFx0cmVtb3ZlKHRoaXMuX3NoYWRvdyk7XHJcblx0XHR9XHJcblx0XHR0aGlzLl9zaGFkb3cgPSBudWxsO1xyXG5cdH0sXHJcblxyXG5cdF9zZXRQb3M6IGZ1bmN0aW9uIChwb3MpIHtcclxuXHRcdHNldFBvc2l0aW9uKHRoaXMuX2ljb24sIHBvcyk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX3NoYWRvdykge1xyXG5cdFx0XHRzZXRQb3NpdGlvbih0aGlzLl9zaGFkb3csIHBvcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fekluZGV4ID0gcG9zLnkgKyB0aGlzLm9wdGlvbnMuekluZGV4T2Zmc2V0O1xyXG5cclxuXHRcdHRoaXMuX3Jlc2V0WkluZGV4KCk7XHJcblx0fSxcclxuXHJcblx0X3VwZGF0ZVpJbmRleDogZnVuY3Rpb24gKG9mZnNldCkge1xyXG5cdFx0dGhpcy5faWNvbi5zdHlsZS56SW5kZXggPSB0aGlzLl96SW5kZXggKyBvZmZzZXQ7XHJcblx0fSxcclxuXHJcblx0X2FuaW1hdGVab29tOiBmdW5jdGlvbiAob3B0KSB7XHJcblx0XHR2YXIgcG9zID0gdGhpcy5fbWFwLl9sYXRMbmdUb05ld0xheWVyUG9pbnQodGhpcy5fbGF0bG5nLCBvcHQuem9vbSwgb3B0LmNlbnRlcikucm91bmQoKTtcclxuXHJcblx0XHR0aGlzLl9zZXRQb3MocG9zKTtcclxuXHR9LFxyXG5cclxuXHRfaW5pdEludGVyYWN0aW9uOiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0aWYgKCF0aGlzLm9wdGlvbnMuaW50ZXJhY3RpdmUpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0YWRkQ2xhc3ModGhpcy5faWNvbiwgJ2xlYWZsZXQtaW50ZXJhY3RpdmUnKTtcclxuXHJcblx0XHR0aGlzLmFkZEludGVyYWN0aXZlVGFyZ2V0KHRoaXMuX2ljb24pO1xyXG5cclxuXHRcdGlmIChNYXJrZXJEcmFnKSB7XHJcblx0XHRcdHZhciBkcmFnZ2FibGUgPSB0aGlzLm9wdGlvbnMuZHJhZ2dhYmxlO1xyXG5cdFx0XHRpZiAodGhpcy5kcmFnZ2luZykge1xyXG5cdFx0XHRcdGRyYWdnYWJsZSA9IHRoaXMuZHJhZ2dpbmcuZW5hYmxlZCgpO1xyXG5cdFx0XHRcdHRoaXMuZHJhZ2dpbmcuZGlzYWJsZSgpO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLmRyYWdnaW5nID0gbmV3IE1hcmtlckRyYWcodGhpcyk7XHJcblxyXG5cdFx0XHRpZiAoZHJhZ2dhYmxlKSB7XHJcblx0XHRcdFx0dGhpcy5kcmFnZ2luZy5lbmFibGUoKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0T3BhY2l0eShvcGFjaXR5OiBOdW1iZXIpOiB0aGlzXHJcblx0Ly8gQ2hhbmdlcyB0aGUgb3BhY2l0eSBvZiB0aGUgbWFya2VyLlxyXG5cdHNldE9wYWNpdHk6IGZ1bmN0aW9uIChvcGFjaXR5KSB7XHJcblx0XHR0aGlzLm9wdGlvbnMub3BhY2l0eSA9IG9wYWNpdHk7XHJcblx0XHRpZiAodGhpcy5fbWFwKSB7XHJcblx0XHRcdHRoaXMuX3VwZGF0ZU9wYWNpdHkoKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfdXBkYXRlT3BhY2l0eTogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIG9wYWNpdHkgPSB0aGlzLm9wdGlvbnMub3BhY2l0eTtcclxuXHJcblx0XHRzZXRPcGFjaXR5KHRoaXMuX2ljb24sIG9wYWNpdHkpO1xyXG5cclxuXHRcdGlmICh0aGlzLl9zaGFkb3cpIHtcclxuXHRcdFx0c2V0T3BhY2l0eSh0aGlzLl9zaGFkb3csIG9wYWNpdHkpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdF9icmluZ1RvRnJvbnQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHRoaXMuX3VwZGF0ZVpJbmRleCh0aGlzLm9wdGlvbnMucmlzZU9mZnNldCk7XHJcblx0fSxcclxuXHJcblx0X3Jlc2V0WkluZGV4OiBmdW5jdGlvbiAoKSB7XHJcblx0XHR0aGlzLl91cGRhdGVaSW5kZXgoMCk7XHJcblx0fSxcclxuXHJcblx0X2dldFBvcHVwQW5jaG9yOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLmljb24ub3B0aW9ucy5wb3B1cEFuY2hvcjtcclxuXHR9LFxyXG5cclxuXHRfZ2V0VG9vbHRpcEFuY2hvcjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMub3B0aW9ucy5pY29uLm9wdGlvbnMudG9vbHRpcEFuY2hvcjtcclxuXHR9XHJcbn0pO1xyXG5cclxuXHJcbi8vIGZhY3RvcnkgTC5tYXJrZXIobGF0bG5nOiBMYXRMbmcsIG9wdGlvbnM/IDogTWFya2VyIG9wdGlvbnMpXHJcblxyXG4vLyBAZmFjdG9yeSBMLm1hcmtlcihsYXRsbmc6IExhdExuZywgb3B0aW9ucz8gOiBNYXJrZXIgb3B0aW9ucylcclxuLy8gSW5zdGFudGlhdGVzIGEgTWFya2VyIG9iamVjdCBnaXZlbiBhIGdlb2dyYXBoaWNhbCBwb2ludCBhbmQgb3B0aW9uYWxseSBhbiBvcHRpb25zIG9iamVjdC5cclxuZnVuY3Rpb24gbWFya2VyKGxhdGxuZywgb3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgTWFya2VyKGxhdGxuZywgb3B0aW9ucyk7XHJcbn1cblxuLypcbiAqIEBjbGFzcyBQYXRoXG4gKiBAYWthIEwuUGF0aFxuICogQGluaGVyaXRzIEludGVyYWN0aXZlIGxheWVyXG4gKlxuICogQW4gYWJzdHJhY3QgY2xhc3MgdGhhdCBjb250YWlucyBvcHRpb25zIGFuZCBjb25zdGFudHMgc2hhcmVkIGJldHdlZW4gdmVjdG9yXG4gKiBvdmVybGF5cyAoUG9seWdvbiwgUG9seWxpbmUsIENpcmNsZSkuIERvIG5vdCB1c2UgaXQgZGlyZWN0bHkuIEV4dGVuZHMgYExheWVyYC5cbiAqL1xuXG52YXIgUGF0aCA9IExheWVyLmV4dGVuZCh7XG5cblx0Ly8gQHNlY3Rpb25cblx0Ly8gQGFrYSBQYXRoIG9wdGlvbnNcblx0b3B0aW9uczoge1xuXHRcdC8vIEBvcHRpb24gc3Ryb2tlOiBCb29sZWFuID0gdHJ1ZVxuXHRcdC8vIFdoZXRoZXIgdG8gZHJhdyBzdHJva2UgYWxvbmcgdGhlIHBhdGguIFNldCBpdCB0byBgZmFsc2VgIHRvIGRpc2FibGUgYm9yZGVycyBvbiBwb2x5Z29ucyBvciBjaXJjbGVzLlxuXHRcdHN0cm9rZTogdHJ1ZSxcblxuXHRcdC8vIEBvcHRpb24gY29sb3I6IFN0cmluZyA9ICcjMzM4OGZmJ1xuXHRcdC8vIFN0cm9rZSBjb2xvclxuXHRcdGNvbG9yOiAnIzMzODhmZicsXG5cblx0XHQvLyBAb3B0aW9uIHdlaWdodDogTnVtYmVyID0gM1xuXHRcdC8vIFN0cm9rZSB3aWR0aCBpbiBwaXhlbHNcblx0XHR3ZWlnaHQ6IDMsXG5cblx0XHQvLyBAb3B0aW9uIG9wYWNpdHk6IE51bWJlciA9IDEuMFxuXHRcdC8vIFN0cm9rZSBvcGFjaXR5XG5cdFx0b3BhY2l0eTogMSxcblxuXHRcdC8vIEBvcHRpb24gbGluZUNhcDogU3RyaW5nPSAncm91bmQnXG5cdFx0Ly8gQSBzdHJpbmcgdGhhdCBkZWZpbmVzIFtzaGFwZSB0byBiZSB1c2VkIGF0IHRoZSBlbmRdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL1NWRy9BdHRyaWJ1dGUvc3Ryb2tlLWxpbmVjYXApIG9mIHRoZSBzdHJva2UuXG5cdFx0bGluZUNhcDogJ3JvdW5kJyxcblxuXHRcdC8vIEBvcHRpb24gbGluZUpvaW46IFN0cmluZyA9ICdyb3VuZCdcblx0XHQvLyBBIHN0cmluZyB0aGF0IGRlZmluZXMgW3NoYXBlIHRvIGJlIHVzZWQgYXQgdGhlIGNvcm5lcnNdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL1NWRy9BdHRyaWJ1dGUvc3Ryb2tlLWxpbmVqb2luKSBvZiB0aGUgc3Ryb2tlLlxuXHRcdGxpbmVKb2luOiAncm91bmQnLFxuXG5cdFx0Ly8gQG9wdGlvbiBkYXNoQXJyYXk6IFN0cmluZyA9IG51bGxcblx0XHQvLyBBIHN0cmluZyB0aGF0IGRlZmluZXMgdGhlIHN0cm9rZSBbZGFzaCBwYXR0ZXJuXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9TVkcvQXR0cmlidXRlL3N0cm9rZS1kYXNoYXJyYXkpLiBEb2Vzbid0IHdvcmsgb24gYENhbnZhc2AtcG93ZXJlZCBsYXllcnMgaW4gW3NvbWUgb2xkIGJyb3dzZXJzXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9BUEkvQ2FudmFzUmVuZGVyaW5nQ29udGV4dDJEL3NldExpbmVEYXNoI0Jyb3dzZXJfY29tcGF0aWJpbGl0eSkuXG5cdFx0ZGFzaEFycmF5OiBudWxsLFxuXG5cdFx0Ly8gQG9wdGlvbiBkYXNoT2Zmc2V0OiBTdHJpbmcgPSBudWxsXG5cdFx0Ly8gQSBzdHJpbmcgdGhhdCBkZWZpbmVzIHRoZSBbZGlzdGFuY2UgaW50byB0aGUgZGFzaCBwYXR0ZXJuIHRvIHN0YXJ0IHRoZSBkYXNoXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9TVkcvQXR0cmlidXRlL3N0cm9rZS1kYXNob2Zmc2V0KS4gRG9lc24ndCB3b3JrIG9uIGBDYW52YXNgLXBvd2VyZWQgbGF5ZXJzIGluIFtzb21lIG9sZCBicm93c2Vyc10oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvQVBJL0NhbnZhc1JlbmRlcmluZ0NvbnRleHQyRC9zZXRMaW5lRGFzaCNCcm93c2VyX2NvbXBhdGliaWxpdHkpLlxuXHRcdGRhc2hPZmZzZXQ6IG51bGwsXG5cblx0XHQvLyBAb3B0aW9uIGZpbGw6IEJvb2xlYW4gPSBkZXBlbmRzXG5cdFx0Ly8gV2hldGhlciB0byBmaWxsIHRoZSBwYXRoIHdpdGggY29sb3IuIFNldCBpdCB0byBgZmFsc2VgIHRvIGRpc2FibGUgZmlsbGluZyBvbiBwb2x5Z29ucyBvciBjaXJjbGVzLlxuXHRcdGZpbGw6IGZhbHNlLFxuXG5cdFx0Ly8gQG9wdGlvbiBmaWxsQ29sb3I6IFN0cmluZyA9ICpcblx0XHQvLyBGaWxsIGNvbG9yLiBEZWZhdWx0cyB0byB0aGUgdmFsdWUgb2YgdGhlIFtgY29sb3JgXSgjcGF0aC1jb2xvcikgb3B0aW9uXG5cdFx0ZmlsbENvbG9yOiBudWxsLFxuXG5cdFx0Ly8gQG9wdGlvbiBmaWxsT3BhY2l0eTogTnVtYmVyID0gMC4yXG5cdFx0Ly8gRmlsbCBvcGFjaXR5LlxuXHRcdGZpbGxPcGFjaXR5OiAwLjIsXG5cblx0XHQvLyBAb3B0aW9uIGZpbGxSdWxlOiBTdHJpbmcgPSAnZXZlbm9kZCdcblx0XHQvLyBBIHN0cmluZyB0aGF0IGRlZmluZXMgW2hvdyB0aGUgaW5zaWRlIG9mIGEgc2hhcGVdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL1NWRy9BdHRyaWJ1dGUvZmlsbC1ydWxlKSBpcyBkZXRlcm1pbmVkLlxuXHRcdGZpbGxSdWxlOiAnZXZlbm9kZCcsXG5cblx0XHQvLyBjbGFzc05hbWU6ICcnLFxuXG5cdFx0Ly8gT3B0aW9uIGluaGVyaXRlZCBmcm9tIFwiSW50ZXJhY3RpdmUgbGF5ZXJcIiBhYnN0cmFjdCBjbGFzc1xuXHRcdGludGVyYWN0aXZlOiB0cnVlLFxuXG5cdFx0Ly8gQG9wdGlvbiBidWJibGluZ01vdXNlRXZlbnRzOiBCb29sZWFuID0gdHJ1ZVxuXHRcdC8vIFdoZW4gYHRydWVgLCBhIG1vdXNlIGV2ZW50IG9uIHRoaXMgcGF0aCB3aWxsIHRyaWdnZXIgdGhlIHNhbWUgZXZlbnQgb24gdGhlIG1hcFxuXHRcdC8vICh1bmxlc3MgW2BMLkRvbUV2ZW50LnN0b3BQcm9wYWdhdGlvbmBdKCNkb21ldmVudC1zdG9wcHJvcGFnYXRpb24pIGlzIHVzZWQpLlxuXHRcdGJ1YmJsaW5nTW91c2VFdmVudHM6IHRydWVcblx0fSxcblxuXHRiZWZvcmVBZGQ6IGZ1bmN0aW9uIChtYXApIHtcblx0XHQvLyBSZW5kZXJlciBpcyBzZXQgaGVyZSBiZWNhdXNlIHdlIG5lZWQgdG8gY2FsbCByZW5kZXJlci5nZXRFdmVudHNcblx0XHQvLyBiZWZvcmUgdGhpcy5nZXRFdmVudHMuXG5cdFx0dGhpcy5fcmVuZGVyZXIgPSBtYXAuZ2V0UmVuZGVyZXIodGhpcyk7XG5cdH0sXG5cblx0b25BZGQ6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9yZW5kZXJlci5faW5pdFBhdGgodGhpcyk7XG5cdFx0dGhpcy5fcmVzZXQoKTtcblx0XHR0aGlzLl9yZW5kZXJlci5fYWRkUGF0aCh0aGlzKTtcblx0fSxcblxuXHRvblJlbW92ZTogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3JlbmRlcmVyLl9yZW1vdmVQYXRoKHRoaXMpO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgcmVkcmF3KCk6IHRoaXNcblx0Ly8gUmVkcmF3cyB0aGUgbGF5ZXIuIFNvbWV0aW1lcyB1c2VmdWwgYWZ0ZXIgeW91IGNoYW5nZWQgdGhlIGNvb3JkaW5hdGVzIHRoYXQgdGhlIHBhdGggdXNlcy5cblx0cmVkcmF3OiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX21hcCkge1xuXHRcdFx0dGhpcy5fcmVuZGVyZXIuX3VwZGF0ZVBhdGgodGhpcyk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2Qgc2V0U3R5bGUoc3R5bGU6IFBhdGggb3B0aW9ucyk6IHRoaXNcblx0Ly8gQ2hhbmdlcyB0aGUgYXBwZWFyYW5jZSBvZiBhIFBhdGggYmFzZWQgb24gdGhlIG9wdGlvbnMgaW4gdGhlIGBQYXRoIG9wdGlvbnNgIG9iamVjdC5cblx0c2V0U3R5bGU6IGZ1bmN0aW9uIChzdHlsZSkge1xuXHRcdHNldE9wdGlvbnModGhpcywgc3R5bGUpO1xuXHRcdGlmICh0aGlzLl9yZW5kZXJlcikge1xuXHRcdFx0dGhpcy5fcmVuZGVyZXIuX3VwZGF0ZVN0eWxlKHRoaXMpO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIGJyaW5nVG9Gcm9udCgpOiB0aGlzXG5cdC8vIEJyaW5ncyB0aGUgbGF5ZXIgdG8gdGhlIHRvcCBvZiBhbGwgcGF0aCBsYXllcnMuXG5cdGJyaW5nVG9Gcm9udDogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9yZW5kZXJlcikge1xuXHRcdFx0dGhpcy5fcmVuZGVyZXIuX2JyaW5nVG9Gcm9udCh0aGlzKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBicmluZ1RvQmFjaygpOiB0aGlzXG5cdC8vIEJyaW5ncyB0aGUgbGF5ZXIgdG8gdGhlIGJvdHRvbSBvZiBhbGwgcGF0aCBsYXllcnMuXG5cdGJyaW5nVG9CYWNrOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX3JlbmRlcmVyKSB7XG5cdFx0XHR0aGlzLl9yZW5kZXJlci5fYnJpbmdUb0JhY2sodGhpcyk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdGdldEVsZW1lbnQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fcGF0aDtcblx0fSxcblxuXHRfcmVzZXQ6IGZ1bmN0aW9uICgpIHtcblx0XHQvLyBkZWZpbmVkIGluIGNoaWxkIGNsYXNzZXNcblx0XHR0aGlzLl9wcm9qZWN0KCk7XG5cdFx0dGhpcy5fdXBkYXRlKCk7XG5cdH0sXG5cblx0X2NsaWNrVG9sZXJhbmNlOiBmdW5jdGlvbiAoKSB7XG5cdFx0Ly8gdXNlZCB3aGVuIGRvaW5nIGhpdCBkZXRlY3Rpb24gZm9yIENhbnZhcyBsYXllcnNcblx0XHRyZXR1cm4gKHRoaXMub3B0aW9ucy5zdHJva2UgPyB0aGlzLm9wdGlvbnMud2VpZ2h0IC8gMiA6IDApICsgdGhpcy5fcmVuZGVyZXIub3B0aW9ucy50b2xlcmFuY2U7XG5cdH1cbn0pO1xuXG4vKlxuICogQGNsYXNzIENpcmNsZU1hcmtlclxuICogQGFrYSBMLkNpcmNsZU1hcmtlclxuICogQGluaGVyaXRzIFBhdGhcbiAqXG4gKiBBIGNpcmNsZSBvZiBhIGZpeGVkIHNpemUgd2l0aCByYWRpdXMgc3BlY2lmaWVkIGluIHBpeGVscy4gRXh0ZW5kcyBgUGF0aGAuXG4gKi9cblxudmFyIENpcmNsZU1hcmtlciA9IFBhdGguZXh0ZW5kKHtcblxuXHQvLyBAc2VjdGlvblxuXHQvLyBAYWthIENpcmNsZU1hcmtlciBvcHRpb25zXG5cdG9wdGlvbnM6IHtcblx0XHRmaWxsOiB0cnVlLFxuXG5cdFx0Ly8gQG9wdGlvbiByYWRpdXM6IE51bWJlciA9IDEwXG5cdFx0Ly8gUmFkaXVzIG9mIHRoZSBjaXJjbGUgbWFya2VyLCBpbiBwaXhlbHNcblx0XHRyYWRpdXM6IDEwXG5cdH0sXG5cblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKGxhdGxuZywgb3B0aW9ucykge1xuXHRcdHNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XG5cdFx0dGhpcy5fbGF0bG5nID0gdG9MYXRMbmcobGF0bG5nKTtcblx0XHR0aGlzLl9yYWRpdXMgPSB0aGlzLm9wdGlvbnMucmFkaXVzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2Qgc2V0TGF0TG5nKGxhdExuZzogTGF0TG5nKTogdGhpc1xuXHQvLyBTZXRzIHRoZSBwb3NpdGlvbiBvZiBhIGNpcmNsZSBtYXJrZXIgdG8gYSBuZXcgbG9jYXRpb24uXG5cdHNldExhdExuZzogZnVuY3Rpb24gKGxhdGxuZykge1xuXHRcdHRoaXMuX2xhdGxuZyA9IHRvTGF0TG5nKGxhdGxuZyk7XG5cdFx0dGhpcy5yZWRyYXcoKTtcblx0XHRyZXR1cm4gdGhpcy5maXJlKCdtb3ZlJywge2xhdGxuZzogdGhpcy5fbGF0bG5nfSk7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBnZXRMYXRMbmcoKTogTGF0TG5nXG5cdC8vIFJldHVybnMgdGhlIGN1cnJlbnQgZ2VvZ3JhcGhpY2FsIHBvc2l0aW9uIG9mIHRoZSBjaXJjbGUgbWFya2VyXG5cdGdldExhdExuZzogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLl9sYXRsbmc7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBzZXRSYWRpdXMocmFkaXVzOiBOdW1iZXIpOiB0aGlzXG5cdC8vIFNldHMgdGhlIHJhZGl1cyBvZiBhIGNpcmNsZSBtYXJrZXIuIFVuaXRzIGFyZSBpbiBwaXhlbHMuXG5cdHNldFJhZGl1czogZnVuY3Rpb24gKHJhZGl1cykge1xuXHRcdHRoaXMub3B0aW9ucy5yYWRpdXMgPSB0aGlzLl9yYWRpdXMgPSByYWRpdXM7XG5cdFx0cmV0dXJuIHRoaXMucmVkcmF3KCk7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBnZXRSYWRpdXMoKTogTnVtYmVyXG5cdC8vIFJldHVybnMgdGhlIGN1cnJlbnQgcmFkaXVzIG9mIHRoZSBjaXJjbGVcblx0Z2V0UmFkaXVzOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3JhZGl1cztcblx0fSxcblxuXHRzZXRTdHlsZSA6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG5cdFx0dmFyIHJhZGl1cyA9IG9wdGlvbnMgJiYgb3B0aW9ucy5yYWRpdXMgfHwgdGhpcy5fcmFkaXVzO1xuXHRcdFBhdGgucHJvdG90eXBlLnNldFN0eWxlLmNhbGwodGhpcywgb3B0aW9ucyk7XG5cdFx0dGhpcy5zZXRSYWRpdXMocmFkaXVzKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRfcHJvamVjdDogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3BvaW50ID0gdGhpcy5fbWFwLmxhdExuZ1RvTGF5ZXJQb2ludCh0aGlzLl9sYXRsbmcpO1xuXHRcdHRoaXMuX3VwZGF0ZUJvdW5kcygpO1xuXHR9LFxuXG5cdF91cGRhdGVCb3VuZHM6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgciA9IHRoaXMuX3JhZGl1cyxcblx0XHQgICAgcjIgPSB0aGlzLl9yYWRpdXNZIHx8IHIsXG5cdFx0ICAgIHcgPSB0aGlzLl9jbGlja1RvbGVyYW5jZSgpLFxuXHRcdCAgICBwID0gW3IgKyB3LCByMiArIHddO1xuXHRcdHRoaXMuX3B4Qm91bmRzID0gbmV3IEJvdW5kcyh0aGlzLl9wb2ludC5zdWJ0cmFjdChwKSwgdGhpcy5fcG9pbnQuYWRkKHApKTtcblx0fSxcblxuXHRfdXBkYXRlOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX21hcCkge1xuXHRcdFx0dGhpcy5fdXBkYXRlUGF0aCgpO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlUGF0aDogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3JlbmRlcmVyLl91cGRhdGVDaXJjbGUodGhpcyk7XG5cdH0sXG5cblx0X2VtcHR5OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3JhZGl1cyAmJiAhdGhpcy5fcmVuZGVyZXIuX2JvdW5kcy5pbnRlcnNlY3RzKHRoaXMuX3B4Qm91bmRzKTtcblx0fSxcblxuXHQvLyBOZWVkZWQgYnkgdGhlIGBDYW52YXNgIHJlbmRlcmVyIGZvciBpbnRlcmFjdGl2aXR5XG5cdF9jb250YWluc1BvaW50OiBmdW5jdGlvbiAocCkge1xuXHRcdHJldHVybiBwLmRpc3RhbmNlVG8odGhpcy5fcG9pbnQpIDw9IHRoaXMuX3JhZGl1cyArIHRoaXMuX2NsaWNrVG9sZXJhbmNlKCk7XG5cdH1cbn0pO1xuXG5cbi8vIEBmYWN0b3J5IEwuY2lyY2xlTWFya2VyKGxhdGxuZzogTGF0TG5nLCBvcHRpb25zPzogQ2lyY2xlTWFya2VyIG9wdGlvbnMpXG4vLyBJbnN0YW50aWF0ZXMgYSBjaXJjbGUgbWFya2VyIG9iamVjdCBnaXZlbiBhIGdlb2dyYXBoaWNhbCBwb2ludCwgYW5kIGFuIG9wdGlvbmFsIG9wdGlvbnMgb2JqZWN0LlxuZnVuY3Rpb24gY2lyY2xlTWFya2VyKGxhdGxuZywgb3B0aW9ucykge1xuXHRyZXR1cm4gbmV3IENpcmNsZU1hcmtlcihsYXRsbmcsIG9wdGlvbnMpO1xufVxuXG4vKlxuICogQGNsYXNzIENpcmNsZVxuICogQGFrYSBMLkNpcmNsZVxuICogQGluaGVyaXRzIENpcmNsZU1hcmtlclxuICpcbiAqIEEgY2xhc3MgZm9yIGRyYXdpbmcgY2lyY2xlIG92ZXJsYXlzIG9uIGEgbWFwLiBFeHRlbmRzIGBDaXJjbGVNYXJrZXJgLlxuICpcbiAqIEl0J3MgYW4gYXBwcm94aW1hdGlvbiBhbmQgc3RhcnRzIHRvIGRpdmVyZ2UgZnJvbSBhIHJlYWwgY2lyY2xlIGNsb3NlciB0byBwb2xlcyAoZHVlIHRvIHByb2plY3Rpb24gZGlzdG9ydGlvbikuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiBgYGBqc1xuICogTC5jaXJjbGUoWzUwLjUsIDMwLjVdLCB7cmFkaXVzOiAyMDB9KS5hZGRUbyhtYXApO1xuICogYGBgXG4gKi9cblxudmFyIENpcmNsZSA9IENpcmNsZU1hcmtlci5leHRlbmQoe1xuXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChsYXRsbmcsIG9wdGlvbnMsIGxlZ2FjeU9wdGlvbnMpIHtcblx0XHRpZiAodHlwZW9mIG9wdGlvbnMgPT09ICdudW1iZXInKSB7XG5cdFx0XHQvLyBCYWNrd2FyZHMgY29tcGF0aWJpbGl0eSB3aXRoIDAuNy54IGZhY3RvcnkgKGxhdGxuZywgcmFkaXVzLCBvcHRpb25zPylcblx0XHRcdG9wdGlvbnMgPSBleHRlbmQoe30sIGxlZ2FjeU9wdGlvbnMsIHtyYWRpdXM6IG9wdGlvbnN9KTtcblx0XHR9XG5cdFx0c2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcblx0XHR0aGlzLl9sYXRsbmcgPSB0b0xhdExuZyhsYXRsbmcpO1xuXG5cdFx0aWYgKGlzTmFOKHRoaXMub3B0aW9ucy5yYWRpdXMpKSB7IHRocm93IG5ldyBFcnJvcignQ2lyY2xlIHJhZGl1cyBjYW5ub3QgYmUgTmFOJyk7IH1cblxuXHRcdC8vIEBzZWN0aW9uXG5cdFx0Ly8gQGFrYSBDaXJjbGUgb3B0aW9uc1xuXHRcdC8vIEBvcHRpb24gcmFkaXVzOiBOdW1iZXI7IFJhZGl1cyBvZiB0aGUgY2lyY2xlLCBpbiBtZXRlcnMuXG5cdFx0dGhpcy5fbVJhZGl1cyA9IHRoaXMub3B0aW9ucy5yYWRpdXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBzZXRSYWRpdXMocmFkaXVzOiBOdW1iZXIpOiB0aGlzXG5cdC8vIFNldHMgdGhlIHJhZGl1cyBvZiBhIGNpcmNsZS4gVW5pdHMgYXJlIGluIG1ldGVycy5cblx0c2V0UmFkaXVzOiBmdW5jdGlvbiAocmFkaXVzKSB7XG5cdFx0dGhpcy5fbVJhZGl1cyA9IHJhZGl1cztcblx0XHRyZXR1cm4gdGhpcy5yZWRyYXcoKTtcblx0fSxcblxuXHQvLyBAbWV0aG9kIGdldFJhZGl1cygpOiBOdW1iZXJcblx0Ly8gUmV0dXJucyB0aGUgY3VycmVudCByYWRpdXMgb2YgYSBjaXJjbGUuIFVuaXRzIGFyZSBpbiBtZXRlcnMuXG5cdGdldFJhZGl1czogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLl9tUmFkaXVzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgZ2V0Qm91bmRzKCk6IExhdExuZ0JvdW5kc1xuXHQvLyBSZXR1cm5zIHRoZSBgTGF0TG5nQm91bmRzYCBvZiB0aGUgcGF0aC5cblx0Z2V0Qm91bmRzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGhhbGYgPSBbdGhpcy5fcmFkaXVzLCB0aGlzLl9yYWRpdXNZIHx8IHRoaXMuX3JhZGl1c107XG5cblx0XHRyZXR1cm4gbmV3IExhdExuZ0JvdW5kcyhcblx0XHRcdHRoaXMuX21hcC5sYXllclBvaW50VG9MYXRMbmcodGhpcy5fcG9pbnQuc3VidHJhY3QoaGFsZikpLFxuXHRcdFx0dGhpcy5fbWFwLmxheWVyUG9pbnRUb0xhdExuZyh0aGlzLl9wb2ludC5hZGQoaGFsZikpKTtcblx0fSxcblxuXHRzZXRTdHlsZTogUGF0aC5wcm90b3R5cGUuc2V0U3R5bGUsXG5cblx0X3Byb2plY3Q6IGZ1bmN0aW9uICgpIHtcblxuXHRcdHZhciBsbmcgPSB0aGlzLl9sYXRsbmcubG5nLFxuXHRcdCAgICBsYXQgPSB0aGlzLl9sYXRsbmcubGF0LFxuXHRcdCAgICBtYXAgPSB0aGlzLl9tYXAsXG5cdFx0ICAgIGNycyA9IG1hcC5vcHRpb25zLmNycztcblxuXHRcdGlmIChjcnMuZGlzdGFuY2UgPT09IEVhcnRoLmRpc3RhbmNlKSB7XG5cdFx0XHR2YXIgZCA9IE1hdGguUEkgLyAxODAsXG5cdFx0XHQgICAgbGF0UiA9ICh0aGlzLl9tUmFkaXVzIC8gRWFydGguUikgLyBkLFxuXHRcdFx0ICAgIHRvcCA9IG1hcC5wcm9qZWN0KFtsYXQgKyBsYXRSLCBsbmddKSxcblx0XHRcdCAgICBib3R0b20gPSBtYXAucHJvamVjdChbbGF0IC0gbGF0UiwgbG5nXSksXG5cdFx0XHQgICAgcCA9IHRvcC5hZGQoYm90dG9tKS5kaXZpZGVCeSgyKSxcblx0XHRcdCAgICBsYXQyID0gbWFwLnVucHJvamVjdChwKS5sYXQsXG5cdFx0XHQgICAgbG5nUiA9IE1hdGguYWNvcygoTWF0aC5jb3MobGF0UiAqIGQpIC0gTWF0aC5zaW4obGF0ICogZCkgKiBNYXRoLnNpbihsYXQyICogZCkpIC9cblx0XHRcdCAgICAgICAgICAgIChNYXRoLmNvcyhsYXQgKiBkKSAqIE1hdGguY29zKGxhdDIgKiBkKSkpIC8gZDtcblxuXHRcdFx0aWYgKGlzTmFOKGxuZ1IpIHx8IGxuZ1IgPT09IDApIHtcblx0XHRcdFx0bG5nUiA9IGxhdFIgLyBNYXRoLmNvcyhNYXRoLlBJIC8gMTgwICogbGF0KTsgLy8gRmFsbGJhY2sgZm9yIGVkZ2UgY2FzZSwgIzI0MjVcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fcG9pbnQgPSBwLnN1YnRyYWN0KG1hcC5nZXRQaXhlbE9yaWdpbigpKTtcblx0XHRcdHRoaXMuX3JhZGl1cyA9IGlzTmFOKGxuZ1IpID8gMCA6IHAueCAtIG1hcC5wcm9qZWN0KFtsYXQyLCBsbmcgLSBsbmdSXSkueDtcblx0XHRcdHRoaXMuX3JhZGl1c1kgPSBwLnkgLSB0b3AueTtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHR2YXIgbGF0bG5nMiA9IGNycy51bnByb2plY3QoY3JzLnByb2plY3QodGhpcy5fbGF0bG5nKS5zdWJ0cmFjdChbdGhpcy5fbVJhZGl1cywgMF0pKTtcblxuXHRcdFx0dGhpcy5fcG9pbnQgPSBtYXAubGF0TG5nVG9MYXllclBvaW50KHRoaXMuX2xhdGxuZyk7XG5cdFx0XHR0aGlzLl9yYWRpdXMgPSB0aGlzLl9wb2ludC54IC0gbWFwLmxhdExuZ1RvTGF5ZXJQb2ludChsYXRsbmcyKS54O1xuXHRcdH1cblxuXHRcdHRoaXMuX3VwZGF0ZUJvdW5kcygpO1xuXHR9XG59KTtcblxuLy8gQGZhY3RvcnkgTC5jaXJjbGUobGF0bG5nOiBMYXRMbmcsIG9wdGlvbnM/OiBDaXJjbGUgb3B0aW9ucylcbi8vIEluc3RhbnRpYXRlcyBhIGNpcmNsZSBvYmplY3QgZ2l2ZW4gYSBnZW9ncmFwaGljYWwgcG9pbnQsIGFuZCBhbiBvcHRpb25zIG9iamVjdFxuLy8gd2hpY2ggY29udGFpbnMgdGhlIGNpcmNsZSByYWRpdXMuXG4vLyBAYWx0ZXJuYXRpdmVcbi8vIEBmYWN0b3J5IEwuY2lyY2xlKGxhdGxuZzogTGF0TG5nLCByYWRpdXM6IE51bWJlciwgb3B0aW9ucz86IENpcmNsZSBvcHRpb25zKVxuLy8gT2Jzb2xldGUgd2F5IG9mIGluc3RhbnRpYXRpbmcgYSBjaXJjbGUsIGZvciBjb21wYXRpYmlsaXR5IHdpdGggMC43LnggY29kZS5cbi8vIERvIG5vdCB1c2UgaW4gbmV3IGFwcGxpY2F0aW9ucyBvciBwbHVnaW5zLlxuZnVuY3Rpb24gY2lyY2xlKGxhdGxuZywgb3B0aW9ucywgbGVnYWN5T3B0aW9ucykge1xuXHRyZXR1cm4gbmV3IENpcmNsZShsYXRsbmcsIG9wdGlvbnMsIGxlZ2FjeU9wdGlvbnMpO1xufVxuXG4vKlxuICogQGNsYXNzIFBvbHlsaW5lXG4gKiBAYWthIEwuUG9seWxpbmVcbiAqIEBpbmhlcml0cyBQYXRoXG4gKlxuICogQSBjbGFzcyBmb3IgZHJhd2luZyBwb2x5bGluZSBvdmVybGF5cyBvbiBhIG1hcC4gRXh0ZW5kcyBgUGF0aGAuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiBgYGBqc1xuICogLy8gY3JlYXRlIGEgcmVkIHBvbHlsaW5lIGZyb20gYW4gYXJyYXkgb2YgTGF0TG5nIHBvaW50c1xuICogdmFyIGxhdGxuZ3MgPSBbXG4gKiBcdFs0NS41MSwgLTEyMi42OF0sXG4gKiBcdFszNy43NywgLTEyMi40M10sXG4gKiBcdFszNC4wNCwgLTExOC4yXVxuICogXTtcbiAqXG4gKiB2YXIgcG9seWxpbmUgPSBMLnBvbHlsaW5lKGxhdGxuZ3MsIHtjb2xvcjogJ3JlZCd9KS5hZGRUbyhtYXApO1xuICpcbiAqIC8vIHpvb20gdGhlIG1hcCB0byB0aGUgcG9seWxpbmVcbiAqIG1hcC5maXRCb3VuZHMocG9seWxpbmUuZ2V0Qm91bmRzKCkpO1xuICogYGBgXG4gKlxuICogWW91IGNhbiBhbHNvIHBhc3MgYSBtdWx0aS1kaW1lbnNpb25hbCBhcnJheSB0byByZXByZXNlbnQgYSBgTXVsdGlQb2x5bGluZWAgc2hhcGU6XG4gKlxuICogYGBganNcbiAqIC8vIGNyZWF0ZSBhIHJlZCBwb2x5bGluZSBmcm9tIGFuIGFycmF5IG9mIGFycmF5cyBvZiBMYXRMbmcgcG9pbnRzXG4gKiB2YXIgbGF0bG5ncyA9IFtcbiAqIFx0W1s0NS41MSwgLTEyMi42OF0sXG4gKiBcdCBbMzcuNzcsIC0xMjIuNDNdLFxuICogXHQgWzM0LjA0LCAtMTE4LjJdXSxcbiAqIFx0W1s0MC43OCwgLTczLjkxXSxcbiAqIFx0IFs0MS44MywgLTg3LjYyXSxcbiAqIFx0IFszMi43NiwgLTk2LjcyXV1cbiAqIF07XG4gKiBgYGBcbiAqL1xuXG5cbnZhciBQb2x5bGluZSA9IFBhdGguZXh0ZW5kKHtcblxuXHQvLyBAc2VjdGlvblxuXHQvLyBAYWthIFBvbHlsaW5lIG9wdGlvbnNcblx0b3B0aW9uczoge1xuXHRcdC8vIEBvcHRpb24gc21vb3RoRmFjdG9yOiBOdW1iZXIgPSAxLjBcblx0XHQvLyBIb3cgbXVjaCB0byBzaW1wbGlmeSB0aGUgcG9seWxpbmUgb24gZWFjaCB6b29tIGxldmVsLiBNb3JlIG1lYW5zXG5cdFx0Ly8gYmV0dGVyIHBlcmZvcm1hbmNlIGFuZCBzbW9vdGhlciBsb29rLCBhbmQgbGVzcyBtZWFucyBtb3JlIGFjY3VyYXRlIHJlcHJlc2VudGF0aW9uLlxuXHRcdHNtb290aEZhY3RvcjogMS4wLFxuXG5cdFx0Ly8gQG9wdGlvbiBub0NsaXA6IEJvb2xlYW4gPSBmYWxzZVxuXHRcdC8vIERpc2FibGUgcG9seWxpbmUgY2xpcHBpbmcuXG5cdFx0bm9DbGlwOiBmYWxzZVxuXHR9LFxuXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChsYXRsbmdzLCBvcHRpb25zKSB7XG5cdFx0c2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcblx0XHR0aGlzLl9zZXRMYXRMbmdzKGxhdGxuZ3MpO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgZ2V0TGF0TG5ncygpOiBMYXRMbmdbXVxuXHQvLyBSZXR1cm5zIGFuIGFycmF5IG9mIHRoZSBwb2ludHMgaW4gdGhlIHBhdGgsIG9yIG5lc3RlZCBhcnJheXMgb2YgcG9pbnRzIGluIGNhc2Ugb2YgbXVsdGktcG9seWxpbmUuXG5cdGdldExhdExuZ3M6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fbGF0bG5ncztcblx0fSxcblxuXHQvLyBAbWV0aG9kIHNldExhdExuZ3MobGF0bG5nczogTGF0TG5nW10pOiB0aGlzXG5cdC8vIFJlcGxhY2VzIGFsbCB0aGUgcG9pbnRzIGluIHRoZSBwb2x5bGluZSB3aXRoIHRoZSBnaXZlbiBhcnJheSBvZiBnZW9ncmFwaGljYWwgcG9pbnRzLlxuXHRzZXRMYXRMbmdzOiBmdW5jdGlvbiAobGF0bG5ncykge1xuXHRcdHRoaXMuX3NldExhdExuZ3MobGF0bG5ncyk7XG5cdFx0cmV0dXJuIHRoaXMucmVkcmF3KCk7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBpc0VtcHR5KCk6IEJvb2xlYW5cblx0Ly8gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIFBvbHlsaW5lIGhhcyBubyBMYXRMbmdzLlxuXHRpc0VtcHR5OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuICF0aGlzLl9sYXRsbmdzLmxlbmd0aDtcblx0fSxcblxuXHQvLyBAbWV0aG9kIGNsb3Nlc3RMYXllclBvaW50OiBQb2ludFxuXHQvLyBSZXR1cm5zIHRoZSBwb2ludCBjbG9zZXN0IHRvIGBwYCBvbiB0aGUgUG9seWxpbmUuXG5cdGNsb3Nlc3RMYXllclBvaW50OiBmdW5jdGlvbiAocCkge1xuXHRcdHZhciBtaW5EaXN0YW5jZSA9IEluZmluaXR5LFxuXHRcdCAgICBtaW5Qb2ludCA9IG51bGwsXG5cdFx0ICAgIGNsb3Nlc3QgPSBfc3FDbG9zZXN0UG9pbnRPblNlZ21lbnQsXG5cdFx0ICAgIHAxLCBwMjtcblxuXHRcdGZvciAodmFyIGogPSAwLCBqTGVuID0gdGhpcy5fcGFydHMubGVuZ3RoOyBqIDwgakxlbjsgaisrKSB7XG5cdFx0XHR2YXIgcG9pbnRzID0gdGhpcy5fcGFydHNbal07XG5cblx0XHRcdGZvciAodmFyIGkgPSAxLCBsZW4gPSBwb2ludHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdFx0cDEgPSBwb2ludHNbaSAtIDFdO1xuXHRcdFx0XHRwMiA9IHBvaW50c1tpXTtcblxuXHRcdFx0XHR2YXIgc3FEaXN0ID0gY2xvc2VzdChwLCBwMSwgcDIsIHRydWUpO1xuXG5cdFx0XHRcdGlmIChzcURpc3QgPCBtaW5EaXN0YW5jZSkge1xuXHRcdFx0XHRcdG1pbkRpc3RhbmNlID0gc3FEaXN0O1xuXHRcdFx0XHRcdG1pblBvaW50ID0gY2xvc2VzdChwLCBwMSwgcDIpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGlmIChtaW5Qb2ludCkge1xuXHRcdFx0bWluUG9pbnQuZGlzdGFuY2UgPSBNYXRoLnNxcnQobWluRGlzdGFuY2UpO1xuXHRcdH1cblx0XHRyZXR1cm4gbWluUG9pbnQ7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBnZXRDZW50ZXIoKTogTGF0TG5nXG5cdC8vIFJldHVybnMgdGhlIGNlbnRlciAoW2NlbnRyb2lkXShodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0NlbnRyb2lkKSkgb2YgdGhlIHBvbHlsaW5lLlxuXHRnZXRDZW50ZXI6IGZ1bmN0aW9uICgpIHtcblx0XHQvLyB0aHJvd3MgZXJyb3Igd2hlbiBub3QgeWV0IGFkZGVkIHRvIG1hcCBhcyB0aGlzIGNlbnRlciBjYWxjdWxhdGlvbiByZXF1aXJlcyBwcm9qZWN0ZWQgY29vcmRpbmF0ZXNcblx0XHRpZiAoIXRoaXMuX21hcCkge1xuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdNdXN0IGFkZCBsYXllciB0byBtYXAgYmVmb3JlIHVzaW5nIGdldENlbnRlcigpJyk7XG5cdFx0fVxuXG5cdFx0dmFyIGksIGhhbGZEaXN0LCBzZWdEaXN0LCBkaXN0LCBwMSwgcDIsIHJhdGlvLFxuXHRcdCAgICBwb2ludHMgPSB0aGlzLl9yaW5nc1swXSxcblx0XHQgICAgbGVuID0gcG9pbnRzLmxlbmd0aDtcblxuXHRcdGlmICghbGVuKSB7IHJldHVybiBudWxsOyB9XG5cblx0XHQvLyBwb2x5bGluZSBjZW50cm9pZCBhbGdvcml0aG07IG9ubHkgdXNlcyB0aGUgZmlyc3QgcmluZyBpZiB0aGVyZSBhcmUgbXVsdGlwbGVcblxuXHRcdGZvciAoaSA9IDAsIGhhbGZEaXN0ID0gMDsgaSA8IGxlbiAtIDE7IGkrKykge1xuXHRcdFx0aGFsZkRpc3QgKz0gcG9pbnRzW2ldLmRpc3RhbmNlVG8ocG9pbnRzW2kgKyAxXSkgLyAyO1xuXHRcdH1cblxuXHRcdC8vIFRoZSBsaW5lIGlzIHNvIHNtYWxsIGluIHRoZSBjdXJyZW50IHZpZXcgdGhhdCBhbGwgcG9pbnRzIGFyZSBvbiB0aGUgc2FtZSBwaXhlbC5cblx0XHRpZiAoaGFsZkRpc3QgPT09IDApIHtcblx0XHRcdHJldHVybiB0aGlzLl9tYXAubGF5ZXJQb2ludFRvTGF0TG5nKHBvaW50c1swXSk7XG5cdFx0fVxuXG5cdFx0Zm9yIChpID0gMCwgZGlzdCA9IDA7IGkgPCBsZW4gLSAxOyBpKyspIHtcblx0XHRcdHAxID0gcG9pbnRzW2ldO1xuXHRcdFx0cDIgPSBwb2ludHNbaSArIDFdO1xuXHRcdFx0c2VnRGlzdCA9IHAxLmRpc3RhbmNlVG8ocDIpO1xuXHRcdFx0ZGlzdCArPSBzZWdEaXN0O1xuXG5cdFx0XHRpZiAoZGlzdCA+IGhhbGZEaXN0KSB7XG5cdFx0XHRcdHJhdGlvID0gKGRpc3QgLSBoYWxmRGlzdCkgLyBzZWdEaXN0O1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5fbWFwLmxheWVyUG9pbnRUb0xhdExuZyhbXG5cdFx0XHRcdFx0cDIueCAtIHJhdGlvICogKHAyLnggLSBwMS54KSxcblx0XHRcdFx0XHRwMi55IC0gcmF0aW8gKiAocDIueSAtIHAxLnkpXG5cdFx0XHRcdF0pO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHQvLyBAbWV0aG9kIGdldEJvdW5kcygpOiBMYXRMbmdCb3VuZHNcblx0Ly8gUmV0dXJucyB0aGUgYExhdExuZ0JvdW5kc2Agb2YgdGhlIHBhdGguXG5cdGdldEJvdW5kczogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLl9ib3VuZHM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBhZGRMYXRMbmcobGF0bG5nOiBMYXRMbmcsIGxhdGxuZ3M/IExhdExuZ1tdKTogdGhpc1xuXHQvLyBBZGRzIGEgZ2l2ZW4gcG9pbnQgdG8gdGhlIHBvbHlsaW5lLiBCeSBkZWZhdWx0LCBhZGRzIHRvIHRoZSBmaXJzdCByaW5nIG9mXG5cdC8vIHRoZSBwb2x5bGluZSBpbiBjYXNlIG9mIGEgbXVsdGktcG9seWxpbmUsIGJ1dCBjYW4gYmUgb3ZlcnJpZGRlbiBieSBwYXNzaW5nXG5cdC8vIGEgc3BlY2lmaWMgcmluZyBhcyBhIExhdExuZyBhcnJheSAodGhhdCB5b3UgY2FuIGVhcmxpZXIgYWNjZXNzIHdpdGggW2BnZXRMYXRMbmdzYF0oI3BvbHlsaW5lLWdldGxhdGxuZ3MpKS5cblx0YWRkTGF0TG5nOiBmdW5jdGlvbiAobGF0bG5nLCBsYXRsbmdzKSB7XG5cdFx0bGF0bG5ncyA9IGxhdGxuZ3MgfHwgdGhpcy5fZGVmYXVsdFNoYXBlKCk7XG5cdFx0bGF0bG5nID0gdG9MYXRMbmcobGF0bG5nKTtcblx0XHRsYXRsbmdzLnB1c2gobGF0bG5nKTtcblx0XHR0aGlzLl9ib3VuZHMuZXh0ZW5kKGxhdGxuZyk7XG5cdFx0cmV0dXJuIHRoaXMucmVkcmF3KCk7XG5cdH0sXG5cblx0X3NldExhdExuZ3M6IGZ1bmN0aW9uIChsYXRsbmdzKSB7XG5cdFx0dGhpcy5fYm91bmRzID0gbmV3IExhdExuZ0JvdW5kcygpO1xuXHRcdHRoaXMuX2xhdGxuZ3MgPSB0aGlzLl9jb252ZXJ0TGF0TG5ncyhsYXRsbmdzKTtcblx0fSxcblxuXHRfZGVmYXVsdFNoYXBlOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIGlzRmxhdCh0aGlzLl9sYXRsbmdzKSA/IHRoaXMuX2xhdGxuZ3MgOiB0aGlzLl9sYXRsbmdzWzBdO1xuXHR9LFxuXG5cdC8vIHJlY3Vyc2l2ZWx5IGNvbnZlcnQgbGF0bG5ncyBpbnB1dCBpbnRvIGFjdHVhbCBMYXRMbmcgaW5zdGFuY2VzOyBjYWxjdWxhdGUgYm91bmRzIGFsb25nIHRoZSB3YXlcblx0X2NvbnZlcnRMYXRMbmdzOiBmdW5jdGlvbiAobGF0bG5ncykge1xuXHRcdHZhciByZXN1bHQgPSBbXSxcblx0XHQgICAgZmxhdCA9IGlzRmxhdChsYXRsbmdzKTtcblxuXHRcdGZvciAodmFyIGkgPSAwLCBsZW4gPSBsYXRsbmdzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRpZiAoZmxhdCkge1xuXHRcdFx0XHRyZXN1bHRbaV0gPSB0b0xhdExuZyhsYXRsbmdzW2ldKTtcblx0XHRcdFx0dGhpcy5fYm91bmRzLmV4dGVuZChyZXN1bHRbaV0pO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmVzdWx0W2ldID0gdGhpcy5fY29udmVydExhdExuZ3MobGF0bG5nc1tpXSk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJlc3VsdDtcblx0fSxcblxuXHRfcHJvamVjdDogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBweEJvdW5kcyA9IG5ldyBCb3VuZHMoKTtcblx0XHR0aGlzLl9yaW5ncyA9IFtdO1xuXHRcdHRoaXMuX3Byb2plY3RMYXRsbmdzKHRoaXMuX2xhdGxuZ3MsIHRoaXMuX3JpbmdzLCBweEJvdW5kcyk7XG5cblx0XHR2YXIgdyA9IHRoaXMuX2NsaWNrVG9sZXJhbmNlKCksXG5cdFx0ICAgIHAgPSBuZXcgUG9pbnQodywgdyk7XG5cblx0XHRpZiAodGhpcy5fYm91bmRzLmlzVmFsaWQoKSAmJiBweEJvdW5kcy5pc1ZhbGlkKCkpIHtcblx0XHRcdHB4Qm91bmRzLm1pbi5fc3VidHJhY3QocCk7XG5cdFx0XHRweEJvdW5kcy5tYXguX2FkZChwKTtcblx0XHRcdHRoaXMuX3B4Qm91bmRzID0gcHhCb3VuZHM7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIHJlY3Vyc2l2ZWx5IHR1cm5zIGxhdGxuZ3MgaW50byBhIHNldCBvZiByaW5ncyB3aXRoIHByb2plY3RlZCBjb29yZGluYXRlc1xuXHRfcHJvamVjdExhdGxuZ3M6IGZ1bmN0aW9uIChsYXRsbmdzLCByZXN1bHQsIHByb2plY3RlZEJvdW5kcykge1xuXHRcdHZhciBmbGF0ID0gbGF0bG5nc1swXSBpbnN0YW5jZW9mIExhdExuZyxcblx0XHQgICAgbGVuID0gbGF0bG5ncy5sZW5ndGgsXG5cdFx0ICAgIGksIHJpbmc7XG5cblx0XHRpZiAoZmxhdCkge1xuXHRcdFx0cmluZyA9IFtdO1xuXHRcdFx0Zm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRcdHJpbmdbaV0gPSB0aGlzLl9tYXAubGF0TG5nVG9MYXllclBvaW50KGxhdGxuZ3NbaV0pO1xuXHRcdFx0XHRwcm9qZWN0ZWRCb3VuZHMuZXh0ZW5kKHJpbmdbaV0pO1xuXHRcdFx0fVxuXHRcdFx0cmVzdWx0LnB1c2gocmluZyk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAoaSA9IDA7IGkgPCBsZW47IGkrKykge1xuXHRcdFx0XHR0aGlzLl9wcm9qZWN0TGF0bG5ncyhsYXRsbmdzW2ldLCByZXN1bHQsIHByb2plY3RlZEJvdW5kcyk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdC8vIGNsaXAgcG9seWxpbmUgYnkgcmVuZGVyZXIgYm91bmRzIHNvIHRoYXQgd2UgaGF2ZSBsZXNzIHRvIHJlbmRlciBmb3IgcGVyZm9ybWFuY2Vcblx0X2NsaXBQb2ludHM6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgYm91bmRzID0gdGhpcy5fcmVuZGVyZXIuX2JvdW5kcztcblxuXHRcdHRoaXMuX3BhcnRzID0gW107XG5cdFx0aWYgKCF0aGlzLl9weEJvdW5kcyB8fCAhdGhpcy5fcHhCb3VuZHMuaW50ZXJzZWN0cyhib3VuZHMpKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMub3B0aW9ucy5ub0NsaXApIHtcblx0XHRcdHRoaXMuX3BhcnRzID0gdGhpcy5fcmluZ3M7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIHBhcnRzID0gdGhpcy5fcGFydHMsXG5cdFx0ICAgIGksIGosIGssIGxlbiwgbGVuMiwgc2VnbWVudCwgcG9pbnRzO1xuXG5cdFx0Zm9yIChpID0gMCwgayA9IDAsIGxlbiA9IHRoaXMuX3JpbmdzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRwb2ludHMgPSB0aGlzLl9yaW5nc1tpXTtcblxuXHRcdFx0Zm9yIChqID0gMCwgbGVuMiA9IHBvaW50cy5sZW5ndGg7IGogPCBsZW4yIC0gMTsgaisrKSB7XG5cdFx0XHRcdHNlZ21lbnQgPSBjbGlwU2VnbWVudChwb2ludHNbal0sIHBvaW50c1tqICsgMV0sIGJvdW5kcywgaiwgdHJ1ZSk7XG5cblx0XHRcdFx0aWYgKCFzZWdtZW50KSB7IGNvbnRpbnVlOyB9XG5cblx0XHRcdFx0cGFydHNba10gPSBwYXJ0c1trXSB8fCBbXTtcblx0XHRcdFx0cGFydHNba10ucHVzaChzZWdtZW50WzBdKTtcblxuXHRcdFx0XHQvLyBpZiBzZWdtZW50IGdvZXMgb3V0IG9mIHNjcmVlbiwgb3IgaXQncyB0aGUgbGFzdCBvbmUsIGl0J3MgdGhlIGVuZCBvZiB0aGUgbGluZSBwYXJ0XG5cdFx0XHRcdGlmICgoc2VnbWVudFsxXSAhPT0gcG9pbnRzW2ogKyAxXSkgfHwgKGogPT09IGxlbjIgLSAyKSkge1xuXHRcdFx0XHRcdHBhcnRzW2tdLnB1c2goc2VnbWVudFsxXSk7XG5cdFx0XHRcdFx0aysrO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdC8vIHNpbXBsaWZ5IGVhY2ggY2xpcHBlZCBwYXJ0IG9mIHRoZSBwb2x5bGluZSBmb3IgcGVyZm9ybWFuY2Vcblx0X3NpbXBsaWZ5UG9pbnRzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHBhcnRzID0gdGhpcy5fcGFydHMsXG5cdFx0ICAgIHRvbGVyYW5jZSA9IHRoaXMub3B0aW9ucy5zbW9vdGhGYWN0b3I7XG5cblx0XHRmb3IgKHZhciBpID0gMCwgbGVuID0gcGFydHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdHBhcnRzW2ldID0gc2ltcGxpZnkocGFydHNbaV0sIHRvbGVyYW5jZSk7XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGU6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAoIXRoaXMuX21hcCkgeyByZXR1cm47IH1cblxuXHRcdHRoaXMuX2NsaXBQb2ludHMoKTtcblx0XHR0aGlzLl9zaW1wbGlmeVBvaW50cygpO1xuXHRcdHRoaXMuX3VwZGF0ZVBhdGgoKTtcblx0fSxcblxuXHRfdXBkYXRlUGF0aDogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3JlbmRlcmVyLl91cGRhdGVQb2x5KHRoaXMpO1xuXHR9LFxuXG5cdC8vIE5lZWRlZCBieSB0aGUgYENhbnZhc2AgcmVuZGVyZXIgZm9yIGludGVyYWN0aXZpdHlcblx0X2NvbnRhaW5zUG9pbnQ6IGZ1bmN0aW9uIChwLCBjbG9zZWQpIHtcblx0XHR2YXIgaSwgaiwgaywgbGVuLCBsZW4yLCBwYXJ0LFxuXHRcdCAgICB3ID0gdGhpcy5fY2xpY2tUb2xlcmFuY2UoKTtcblxuXHRcdGlmICghdGhpcy5fcHhCb3VuZHMgfHwgIXRoaXMuX3B4Qm91bmRzLmNvbnRhaW5zKHApKSB7IHJldHVybiBmYWxzZTsgfVxuXG5cdFx0Ly8gaGl0IGRldGVjdGlvbiBmb3IgcG9seWxpbmVzXG5cdFx0Zm9yIChpID0gMCwgbGVuID0gdGhpcy5fcGFydHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdHBhcnQgPSB0aGlzLl9wYXJ0c1tpXTtcblxuXHRcdFx0Zm9yIChqID0gMCwgbGVuMiA9IHBhcnQubGVuZ3RoLCBrID0gbGVuMiAtIDE7IGogPCBsZW4yOyBrID0gaisrKSB7XG5cdFx0XHRcdGlmICghY2xvc2VkICYmIChqID09PSAwKSkgeyBjb250aW51ZTsgfVxuXG5cdFx0XHRcdGlmIChwb2ludFRvU2VnbWVudERpc3RhbmNlKHAsIHBhcnRba10sIHBhcnRbal0pIDw9IHcpIHtcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cbn0pO1xuXG4vLyBAZmFjdG9yeSBMLnBvbHlsaW5lKGxhdGxuZ3M6IExhdExuZ1tdLCBvcHRpb25zPzogUG9seWxpbmUgb3B0aW9ucylcbi8vIEluc3RhbnRpYXRlcyBhIHBvbHlsaW5lIG9iamVjdCBnaXZlbiBhbiBhcnJheSBvZiBnZW9ncmFwaGljYWwgcG9pbnRzIGFuZFxuLy8gb3B0aW9uYWxseSBhbiBvcHRpb25zIG9iamVjdC4gWW91IGNhbiBjcmVhdGUgYSBgUG9seWxpbmVgIG9iamVjdCB3aXRoXG4vLyBtdWx0aXBsZSBzZXBhcmF0ZSBsaW5lcyAoYE11bHRpUG9seWxpbmVgKSBieSBwYXNzaW5nIGFuIGFycmF5IG9mIGFycmF5c1xuLy8gb2YgZ2VvZ3JhcGhpYyBwb2ludHMuXG5mdW5jdGlvbiBwb2x5bGluZShsYXRsbmdzLCBvcHRpb25zKSB7XG5cdHJldHVybiBuZXcgUG9seWxpbmUobGF0bG5ncywgb3B0aW9ucyk7XG59XG5cbi8vIFJldHJvY29tcGF0LiBBbGxvdyBwbHVnaW5zIHRvIHN1cHBvcnQgTGVhZmxldCB2ZXJzaW9ucyBiZWZvcmUgYW5kIGFmdGVyIDEuMS5cblBvbHlsaW5lLl9mbGF0ID0gX2ZsYXQ7XG5cbi8qXG4gKiBAY2xhc3MgUG9seWdvblxuICogQGFrYSBMLlBvbHlnb25cbiAqIEBpbmhlcml0cyBQb2x5bGluZVxuICpcbiAqIEEgY2xhc3MgZm9yIGRyYXdpbmcgcG9seWdvbiBvdmVybGF5cyBvbiBhIG1hcC4gRXh0ZW5kcyBgUG9seWxpbmVgLlxuICpcbiAqIE5vdGUgdGhhdCBwb2ludHMgeW91IHBhc3Mgd2hlbiBjcmVhdGluZyBhIHBvbHlnb24gc2hvdWxkbid0IGhhdmUgYW4gYWRkaXRpb25hbCBsYXN0IHBvaW50IGVxdWFsIHRvIHRoZSBmaXJzdCBvbmUg4oCUIGl0J3MgYmV0dGVyIHRvIGZpbHRlciBvdXQgc3VjaCBwb2ludHMuXG4gKlxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogYGBganNcbiAqIC8vIGNyZWF0ZSBhIHJlZCBwb2x5Z29uIGZyb20gYW4gYXJyYXkgb2YgTGF0TG5nIHBvaW50c1xuICogdmFyIGxhdGxuZ3MgPSBbWzM3LCAtMTA5LjA1XSxbNDEsIC0xMDkuMDNdLFs0MSwgLTEwMi4wNV0sWzM3LCAtMTAyLjA0XV07XG4gKlxuICogdmFyIHBvbHlnb24gPSBMLnBvbHlnb24obGF0bG5ncywge2NvbG9yOiAncmVkJ30pLmFkZFRvKG1hcCk7XG4gKlxuICogLy8gem9vbSB0aGUgbWFwIHRvIHRoZSBwb2x5Z29uXG4gKiBtYXAuZml0Qm91bmRzKHBvbHlnb24uZ2V0Qm91bmRzKCkpO1xuICogYGBgXG4gKlxuICogWW91IGNhbiBhbHNvIHBhc3MgYW4gYXJyYXkgb2YgYXJyYXlzIG9mIGxhdGxuZ3MsIHdpdGggdGhlIGZpcnN0IGFycmF5IHJlcHJlc2VudGluZyB0aGUgb3V0ZXIgc2hhcGUgYW5kIHRoZSBvdGhlciBhcnJheXMgcmVwcmVzZW50aW5nIGhvbGVzIGluIHRoZSBvdXRlciBzaGFwZTpcbiAqXG4gKiBgYGBqc1xuICogdmFyIGxhdGxuZ3MgPSBbXG4gKiAgIFtbMzcsIC0xMDkuMDVdLFs0MSwgLTEwOS4wM10sWzQxLCAtMTAyLjA1XSxbMzcsIC0xMDIuMDRdXSwgLy8gb3V0ZXIgcmluZ1xuICogICBbWzM3LjI5LCAtMTA4LjU4XSxbNDAuNzEsIC0xMDguNThdLFs0MC43MSwgLTEwMi41MF0sWzM3LjI5LCAtMTAyLjUwXV0gLy8gaG9sZVxuICogXTtcbiAqIGBgYFxuICpcbiAqIEFkZGl0aW9uYWxseSwgeW91IGNhbiBwYXNzIGEgbXVsdGktZGltZW5zaW9uYWwgYXJyYXkgdG8gcmVwcmVzZW50IGEgTXVsdGlQb2x5Z29uIHNoYXBlLlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgbGF0bG5ncyA9IFtcbiAqICAgWyAvLyBmaXJzdCBwb2x5Z29uXG4gKiAgICAgW1szNywgLTEwOS4wNV0sWzQxLCAtMTA5LjAzXSxbNDEsIC0xMDIuMDVdLFszNywgLTEwMi4wNF1dLCAvLyBvdXRlciByaW5nXG4gKiAgICAgW1szNy4yOSwgLTEwOC41OF0sWzQwLjcxLCAtMTA4LjU4XSxbNDAuNzEsIC0xMDIuNTBdLFszNy4yOSwgLTEwMi41MF1dIC8vIGhvbGVcbiAqICAgXSxcbiAqICAgWyAvLyBzZWNvbmQgcG9seWdvblxuICogICAgIFtbNDEsIC0xMTEuMDNdLFs0NSwgLTExMS4wNF0sWzQ1LCAtMTA0LjA1XSxbNDEsIC0xMDQuMDVdXVxuICogICBdXG4gKiBdO1xuICogYGBgXG4gKi9cblxudmFyIFBvbHlnb24gPSBQb2x5bGluZS5leHRlbmQoe1xuXG5cdG9wdGlvbnM6IHtcblx0XHRmaWxsOiB0cnVlXG5cdH0sXG5cblx0aXNFbXB0eTogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiAhdGhpcy5fbGF0bG5ncy5sZW5ndGggfHwgIXRoaXMuX2xhdGxuZ3NbMF0ubGVuZ3RoO1xuXHR9LFxuXG5cdGdldENlbnRlcjogZnVuY3Rpb24gKCkge1xuXHRcdC8vIHRocm93cyBlcnJvciB3aGVuIG5vdCB5ZXQgYWRkZWQgdG8gbWFwIGFzIHRoaXMgY2VudGVyIGNhbGN1bGF0aW9uIHJlcXVpcmVzIHByb2plY3RlZCBjb29yZGluYXRlc1xuXHRcdGlmICghdGhpcy5fbWFwKSB7XG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ011c3QgYWRkIGxheWVyIHRvIG1hcCBiZWZvcmUgdXNpbmcgZ2V0Q2VudGVyKCknKTtcblx0XHR9XG5cblx0XHR2YXIgaSwgaiwgcDEsIHAyLCBmLCBhcmVhLCB4LCB5LCBjZW50ZXIsXG5cdFx0ICAgIHBvaW50cyA9IHRoaXMuX3JpbmdzWzBdLFxuXHRcdCAgICBsZW4gPSBwb2ludHMubGVuZ3RoO1xuXG5cdFx0aWYgKCFsZW4pIHsgcmV0dXJuIG51bGw7IH1cblxuXHRcdC8vIHBvbHlnb24gY2VudHJvaWQgYWxnb3JpdGhtOyBvbmx5IHVzZXMgdGhlIGZpcnN0IHJpbmcgaWYgdGhlcmUgYXJlIG11bHRpcGxlXG5cblx0XHRhcmVhID0geCA9IHkgPSAwO1xuXG5cdFx0Zm9yIChpID0gMCwgaiA9IGxlbiAtIDE7IGkgPCBsZW47IGogPSBpKyspIHtcblx0XHRcdHAxID0gcG9pbnRzW2ldO1xuXHRcdFx0cDIgPSBwb2ludHNbal07XG5cblx0XHRcdGYgPSBwMS55ICogcDIueCAtIHAyLnkgKiBwMS54O1xuXHRcdFx0eCArPSAocDEueCArIHAyLngpICogZjtcblx0XHRcdHkgKz0gKHAxLnkgKyBwMi55KSAqIGY7XG5cdFx0XHRhcmVhICs9IGYgKiAzO1xuXHRcdH1cblxuXHRcdGlmIChhcmVhID09PSAwKSB7XG5cdFx0XHQvLyBQb2x5Z29uIGlzIHNvIHNtYWxsIHRoYXQgYWxsIHBvaW50cyBhcmUgb24gc2FtZSBwaXhlbC5cblx0XHRcdGNlbnRlciA9IHBvaW50c1swXTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Y2VudGVyID0gW3ggLyBhcmVhLCB5IC8gYXJlYV07XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzLl9tYXAubGF5ZXJQb2ludFRvTGF0TG5nKGNlbnRlcik7XG5cdH0sXG5cblx0X2NvbnZlcnRMYXRMbmdzOiBmdW5jdGlvbiAobGF0bG5ncykge1xuXHRcdHZhciByZXN1bHQgPSBQb2x5bGluZS5wcm90b3R5cGUuX2NvbnZlcnRMYXRMbmdzLmNhbGwodGhpcywgbGF0bG5ncyksXG5cdFx0ICAgIGxlbiA9IHJlc3VsdC5sZW5ndGg7XG5cblx0XHQvLyByZW1vdmUgbGFzdCBwb2ludCBpZiBpdCBlcXVhbHMgZmlyc3Qgb25lXG5cdFx0aWYgKGxlbiA+PSAyICYmIHJlc3VsdFswXSBpbnN0YW5jZW9mIExhdExuZyAmJiByZXN1bHRbMF0uZXF1YWxzKHJlc3VsdFtsZW4gLSAxXSkpIHtcblx0XHRcdHJlc3VsdC5wb3AoKTtcblx0XHR9XG5cdFx0cmV0dXJuIHJlc3VsdDtcblx0fSxcblxuXHRfc2V0TGF0TG5nczogZnVuY3Rpb24gKGxhdGxuZ3MpIHtcblx0XHRQb2x5bGluZS5wcm90b3R5cGUuX3NldExhdExuZ3MuY2FsbCh0aGlzLCBsYXRsbmdzKTtcblx0XHRpZiAoaXNGbGF0KHRoaXMuX2xhdGxuZ3MpKSB7XG5cdFx0XHR0aGlzLl9sYXRsbmdzID0gW3RoaXMuX2xhdGxuZ3NdO1xuXHRcdH1cblx0fSxcblxuXHRfZGVmYXVsdFNoYXBlOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIGlzRmxhdCh0aGlzLl9sYXRsbmdzWzBdKSA/IHRoaXMuX2xhdGxuZ3NbMF0gOiB0aGlzLl9sYXRsbmdzWzBdWzBdO1xuXHR9LFxuXG5cdF9jbGlwUG9pbnRzOiBmdW5jdGlvbiAoKSB7XG5cdFx0Ly8gcG9seWdvbnMgbmVlZCBhIGRpZmZlcmVudCBjbGlwcGluZyBhbGdvcml0aG0gc28gd2UgcmVkZWZpbmUgdGhhdFxuXG5cdFx0dmFyIGJvdW5kcyA9IHRoaXMuX3JlbmRlcmVyLl9ib3VuZHMsXG5cdFx0ICAgIHcgPSB0aGlzLm9wdGlvbnMud2VpZ2h0LFxuXHRcdCAgICBwID0gbmV3IFBvaW50KHcsIHcpO1xuXG5cdFx0Ly8gaW5jcmVhc2UgY2xpcCBwYWRkaW5nIGJ5IHN0cm9rZSB3aWR0aCB0byBhdm9pZCBzdHJva2Ugb24gY2xpcCBlZGdlc1xuXHRcdGJvdW5kcyA9IG5ldyBCb3VuZHMoYm91bmRzLm1pbi5zdWJ0cmFjdChwKSwgYm91bmRzLm1heC5hZGQocCkpO1xuXG5cdFx0dGhpcy5fcGFydHMgPSBbXTtcblx0XHRpZiAoIXRoaXMuX3B4Qm91bmRzIHx8ICF0aGlzLl9weEJvdW5kcy5pbnRlcnNlY3RzKGJvdW5kcykpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5vcHRpb25zLm5vQ2xpcCkge1xuXHRcdFx0dGhpcy5fcGFydHMgPSB0aGlzLl9yaW5ncztcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRmb3IgKHZhciBpID0gMCwgbGVuID0gdGhpcy5fcmluZ3MubGVuZ3RoLCBjbGlwcGVkOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdGNsaXBwZWQgPSBjbGlwUG9seWdvbih0aGlzLl9yaW5nc1tpXSwgYm91bmRzLCB0cnVlKTtcblx0XHRcdGlmIChjbGlwcGVkLmxlbmd0aCkge1xuXHRcdFx0XHR0aGlzLl9wYXJ0cy5wdXNoKGNsaXBwZWQpO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlUGF0aDogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3JlbmRlcmVyLl91cGRhdGVQb2x5KHRoaXMsIHRydWUpO1xuXHR9LFxuXG5cdC8vIE5lZWRlZCBieSB0aGUgYENhbnZhc2AgcmVuZGVyZXIgZm9yIGludGVyYWN0aXZpdHlcblx0X2NvbnRhaW5zUG9pbnQ6IGZ1bmN0aW9uIChwKSB7XG5cdFx0dmFyIGluc2lkZSA9IGZhbHNlLFxuXHRcdCAgICBwYXJ0LCBwMSwgcDIsIGksIGosIGssIGxlbiwgbGVuMjtcblxuXHRcdGlmICghdGhpcy5fcHhCb3VuZHMuY29udGFpbnMocCkpIHsgcmV0dXJuIGZhbHNlOyB9XG5cblx0XHQvLyByYXkgY2FzdGluZyBhbGdvcml0aG0gZm9yIGRldGVjdGluZyBpZiBwb2ludCBpcyBpbiBwb2x5Z29uXG5cdFx0Zm9yIChpID0gMCwgbGVuID0gdGhpcy5fcGFydHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdHBhcnQgPSB0aGlzLl9wYXJ0c1tpXTtcblxuXHRcdFx0Zm9yIChqID0gMCwgbGVuMiA9IHBhcnQubGVuZ3RoLCBrID0gbGVuMiAtIDE7IGogPCBsZW4yOyBrID0gaisrKSB7XG5cdFx0XHRcdHAxID0gcGFydFtqXTtcblx0XHRcdFx0cDIgPSBwYXJ0W2tdO1xuXG5cdFx0XHRcdGlmICgoKHAxLnkgPiBwLnkpICE9PSAocDIueSA+IHAueSkpICYmIChwLnggPCAocDIueCAtIHAxLngpICogKHAueSAtIHAxLnkpIC8gKHAyLnkgLSBwMS55KSArIHAxLngpKSB7XG5cdFx0XHRcdFx0aW5zaWRlID0gIWluc2lkZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIGFsc28gY2hlY2sgaWYgaXQncyBvbiBwb2x5Z29uIHN0cm9rZVxuXHRcdHJldHVybiBpbnNpZGUgfHwgUG9seWxpbmUucHJvdG90eXBlLl9jb250YWluc1BvaW50LmNhbGwodGhpcywgcCwgdHJ1ZSk7XG5cdH1cblxufSk7XG5cblxuLy8gQGZhY3RvcnkgTC5wb2x5Z29uKGxhdGxuZ3M6IExhdExuZ1tdLCBvcHRpb25zPzogUG9seWxpbmUgb3B0aW9ucylcbmZ1bmN0aW9uIHBvbHlnb24obGF0bG5ncywgb3B0aW9ucykge1xuXHRyZXR1cm4gbmV3IFBvbHlnb24obGF0bG5ncywgb3B0aW9ucyk7XG59XG5cbi8qXHJcbiAqIEBjbGFzcyBHZW9KU09OXHJcbiAqIEBha2EgTC5HZW9KU09OXHJcbiAqIEBpbmhlcml0cyBGZWF0dXJlR3JvdXBcclxuICpcclxuICogUmVwcmVzZW50cyBhIEdlb0pTT04gb2JqZWN0IG9yIGFuIGFycmF5IG9mIEdlb0pTT04gb2JqZWN0cy4gQWxsb3dzIHlvdSB0byBwYXJzZVxyXG4gKiBHZW9KU09OIGRhdGEgYW5kIGRpc3BsYXkgaXQgb24gdGhlIG1hcC4gRXh0ZW5kcyBgRmVhdHVyZUdyb3VwYC5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogYGBganNcclxuICogTC5nZW9KU09OKGRhdGEsIHtcclxuICogXHRzdHlsZTogZnVuY3Rpb24gKGZlYXR1cmUpIHtcclxuICogXHRcdHJldHVybiB7Y29sb3I6IGZlYXR1cmUucHJvcGVydGllcy5jb2xvcn07XHJcbiAqIFx0fVxyXG4gKiB9KS5iaW5kUG9wdXAoZnVuY3Rpb24gKGxheWVyKSB7XHJcbiAqIFx0cmV0dXJuIGxheWVyLmZlYXR1cmUucHJvcGVydGllcy5kZXNjcmlwdGlvbjtcclxuICogfSkuYWRkVG8obWFwKTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxudmFyIEdlb0pTT04gPSBGZWF0dXJlR3JvdXAuZXh0ZW5kKHtcclxuXHJcblx0LyogQHNlY3Rpb25cclxuXHQgKiBAYWthIEdlb0pTT04gb3B0aW9uc1xyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBwb2ludFRvTGF5ZXI6IEZ1bmN0aW9uID0gKlxyXG5cdCAqIEEgYEZ1bmN0aW9uYCBkZWZpbmluZyBob3cgR2VvSlNPTiBwb2ludHMgc3Bhd24gTGVhZmxldCBsYXllcnMuIEl0IGlzIGludGVybmFsbHlcclxuXHQgKiBjYWxsZWQgd2hlbiBkYXRhIGlzIGFkZGVkLCBwYXNzaW5nIHRoZSBHZW9KU09OIHBvaW50IGZlYXR1cmUgYW5kIGl0cyBgTGF0TG5nYC5cclxuXHQgKiBUaGUgZGVmYXVsdCBpcyB0byBzcGF3biBhIGRlZmF1bHQgYE1hcmtlcmA6XHJcblx0ICogYGBganNcclxuXHQgKiBmdW5jdGlvbihnZW9Kc29uUG9pbnQsIGxhdGxuZykge1xyXG5cdCAqIFx0cmV0dXJuIEwubWFya2VyKGxhdGxuZyk7XHJcblx0ICogfVxyXG5cdCAqIGBgYFxyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBzdHlsZTogRnVuY3Rpb24gPSAqXHJcblx0ICogQSBgRnVuY3Rpb25gIGRlZmluaW5nIHRoZSBgUGF0aCBvcHRpb25zYCBmb3Igc3R5bGluZyBHZW9KU09OIGxpbmVzIGFuZCBwb2x5Z29ucyxcclxuXHQgKiBjYWxsZWQgaW50ZXJuYWxseSB3aGVuIGRhdGEgaXMgYWRkZWQuXHJcblx0ICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgdG8gbm90IG92ZXJyaWRlIGFueSBkZWZhdWx0czpcclxuXHQgKiBgYGBqc1xyXG5cdCAqIGZ1bmN0aW9uIChnZW9Kc29uRmVhdHVyZSkge1xyXG5cdCAqIFx0cmV0dXJuIHt9XHJcblx0ICogfVxyXG5cdCAqIGBgYFxyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBvbkVhY2hGZWF0dXJlOiBGdW5jdGlvbiA9ICpcclxuXHQgKiBBIGBGdW5jdGlvbmAgdGhhdCB3aWxsIGJlIGNhbGxlZCBvbmNlIGZvciBlYWNoIGNyZWF0ZWQgYEZlYXR1cmVgLCBhZnRlciBpdCBoYXNcclxuXHQgKiBiZWVuIGNyZWF0ZWQgYW5kIHN0eWxlZC4gVXNlZnVsIGZvciBhdHRhY2hpbmcgZXZlbnRzIGFuZCBwb3B1cHMgdG8gZmVhdHVyZXMuXHJcblx0ICogVGhlIGRlZmF1bHQgaXMgdG8gZG8gbm90aGluZyB3aXRoIHRoZSBuZXdseSBjcmVhdGVkIGxheWVyczpcclxuXHQgKiBgYGBqc1xyXG5cdCAqIGZ1bmN0aW9uIChmZWF0dXJlLCBsYXllcikge31cclxuXHQgKiBgYGBcclxuXHQgKlxyXG5cdCAqIEBvcHRpb24gZmlsdGVyOiBGdW5jdGlvbiA9ICpcclxuXHQgKiBBIGBGdW5jdGlvbmAgdGhhdCB3aWxsIGJlIHVzZWQgdG8gZGVjaWRlIHdoZXRoZXIgdG8gaW5jbHVkZSBhIGZlYXR1cmUgb3Igbm90LlxyXG5cdCAqIFRoZSBkZWZhdWx0IGlzIHRvIGluY2x1ZGUgYWxsIGZlYXR1cmVzOlxyXG5cdCAqIGBgYGpzXHJcblx0ICogZnVuY3Rpb24gKGdlb0pzb25GZWF0dXJlKSB7XHJcblx0ICogXHRyZXR1cm4gdHJ1ZTtcclxuXHQgKiB9XHJcblx0ICogYGBgXHJcblx0ICogTm90ZTogZHluYW1pY2FsbHkgY2hhbmdpbmcgdGhlIGBmaWx0ZXJgIG9wdGlvbiB3aWxsIGhhdmUgZWZmZWN0IG9ubHkgb24gbmV3bHlcclxuXHQgKiBhZGRlZCBkYXRhLiBJdCB3aWxsIF9ub3RfIHJlLWV2YWx1YXRlIGFscmVhZHkgaW5jbHVkZWQgZmVhdHVyZXMuXHJcblx0ICpcclxuXHQgKiBAb3B0aW9uIGNvb3Jkc1RvTGF0TG5nOiBGdW5jdGlvbiA9ICpcclxuXHQgKiBBIGBGdW5jdGlvbmAgdGhhdCB3aWxsIGJlIHVzZWQgZm9yIGNvbnZlcnRpbmcgR2VvSlNPTiBjb29yZGluYXRlcyB0byBgTGF0TG5nYHMuXHJcblx0ICogVGhlIGRlZmF1bHQgaXMgdGhlIGBjb29yZHNUb0xhdExuZ2Agc3RhdGljIG1ldGhvZC5cclxuXHQgKi9cclxuXHJcblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKGdlb2pzb24sIG9wdGlvbnMpIHtcclxuXHRcdHNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XHJcblxyXG5cdFx0dGhpcy5fbGF5ZXJzID0ge307XHJcblxyXG5cdFx0aWYgKGdlb2pzb24pIHtcclxuXHRcdFx0dGhpcy5hZGREYXRhKGdlb2pzb24pO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgYWRkRGF0YSggPEdlb0pTT04+IGRhdGEgKTogdGhpc1xyXG5cdC8vIEFkZHMgYSBHZW9KU09OIG9iamVjdCB0byB0aGUgbGF5ZXIuXHJcblx0YWRkRGF0YTogZnVuY3Rpb24gKGdlb2pzb24pIHtcclxuXHRcdHZhciBmZWF0dXJlcyA9IGlzQXJyYXkoZ2VvanNvbikgPyBnZW9qc29uIDogZ2VvanNvbi5mZWF0dXJlcyxcclxuXHRcdCAgICBpLCBsZW4sIGZlYXR1cmU7XHJcblxyXG5cdFx0aWYgKGZlYXR1cmVzKSB7XHJcblx0XHRcdGZvciAoaSA9IDAsIGxlbiA9IGZlYXR1cmVzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdFx0Ly8gb25seSBhZGQgdGhpcyBpZiBnZW9tZXRyeSBvciBnZW9tZXRyaWVzIGFyZSBzZXQgYW5kIG5vdCBudWxsXHJcblx0XHRcdFx0ZmVhdHVyZSA9IGZlYXR1cmVzW2ldO1xyXG5cdFx0XHRcdGlmIChmZWF0dXJlLmdlb21ldHJpZXMgfHwgZmVhdHVyZS5nZW9tZXRyeSB8fCBmZWF0dXJlLmZlYXR1cmVzIHx8IGZlYXR1cmUuY29vcmRpbmF0ZXMpIHtcclxuXHRcdFx0XHRcdHRoaXMuYWRkRGF0YShmZWF0dXJlKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblx0XHR9XHJcblxyXG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XHJcblxyXG5cdFx0aWYgKG9wdGlvbnMuZmlsdGVyICYmICFvcHRpb25zLmZpbHRlcihnZW9qc29uKSkgeyByZXR1cm4gdGhpczsgfVxyXG5cclxuXHRcdHZhciBsYXllciA9IGdlb21ldHJ5VG9MYXllcihnZW9qc29uLCBvcHRpb25zKTtcclxuXHRcdGlmICghbGF5ZXIpIHtcclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblx0XHR9XHJcblx0XHRsYXllci5mZWF0dXJlID0gYXNGZWF0dXJlKGdlb2pzb24pO1xyXG5cclxuXHRcdGxheWVyLmRlZmF1bHRPcHRpb25zID0gbGF5ZXIub3B0aW9ucztcclxuXHRcdHRoaXMucmVzZXRTdHlsZShsYXllcik7XHJcblxyXG5cdFx0aWYgKG9wdGlvbnMub25FYWNoRmVhdHVyZSkge1xyXG5cdFx0XHRvcHRpb25zLm9uRWFjaEZlYXR1cmUoZ2VvanNvbiwgbGF5ZXIpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzLmFkZExheWVyKGxheWVyKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHJlc2V0U3R5bGUoIDxQYXRoPiBsYXllciApOiB0aGlzXHJcblx0Ly8gUmVzZXRzIHRoZSBnaXZlbiB2ZWN0b3IgbGF5ZXIncyBzdHlsZSB0byB0aGUgb3JpZ2luYWwgR2VvSlNPTiBzdHlsZSwgdXNlZnVsIGZvciByZXNldHRpbmcgc3R5bGUgYWZ0ZXIgaG92ZXIgZXZlbnRzLlxyXG5cdHJlc2V0U3R5bGU6IGZ1bmN0aW9uIChsYXllcikge1xyXG5cdFx0Ly8gcmVzZXQgYW55IGN1c3RvbSBzdHlsZXNcclxuXHRcdGxheWVyLm9wdGlvbnMgPSBleHRlbmQoe30sIGxheWVyLmRlZmF1bHRPcHRpb25zKTtcclxuXHRcdHRoaXMuX3NldExheWVyU3R5bGUobGF5ZXIsIHRoaXMub3B0aW9ucy5zdHlsZSk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldFN0eWxlKCA8RnVuY3Rpb24+IHN0eWxlICk6IHRoaXNcclxuXHQvLyBDaGFuZ2VzIHN0eWxlcyBvZiBHZW9KU09OIHZlY3RvciBsYXllcnMgd2l0aCB0aGUgZ2l2ZW4gc3R5bGUgZnVuY3Rpb24uXHJcblx0c2V0U3R5bGU6IGZ1bmN0aW9uIChzdHlsZSkge1xyXG5cdFx0cmV0dXJuIHRoaXMuZWFjaExheWVyKGZ1bmN0aW9uIChsYXllcikge1xyXG5cdFx0XHR0aGlzLl9zZXRMYXllclN0eWxlKGxheWVyLCBzdHlsZSk7XHJcblx0XHR9LCB0aGlzKTtcclxuXHR9LFxyXG5cclxuXHRfc2V0TGF5ZXJTdHlsZTogZnVuY3Rpb24gKGxheWVyLCBzdHlsZSkge1xyXG5cdFx0aWYgKHR5cGVvZiBzdHlsZSA9PT0gJ2Z1bmN0aW9uJykge1xyXG5cdFx0XHRzdHlsZSA9IHN0eWxlKGxheWVyLmZlYXR1cmUpO1xyXG5cdFx0fVxyXG5cdFx0aWYgKGxheWVyLnNldFN0eWxlKSB7XHJcblx0XHRcdGxheWVyLnNldFN0eWxlKHN0eWxlKTtcclxuXHRcdH1cclxuXHR9XHJcbn0pO1xyXG5cclxuLy8gQHNlY3Rpb25cclxuLy8gVGhlcmUgYXJlIHNldmVyYWwgc3RhdGljIGZ1bmN0aW9ucyB3aGljaCBjYW4gYmUgY2FsbGVkIHdpdGhvdXQgaW5zdGFudGlhdGluZyBMLkdlb0pTT046XHJcblxyXG4vLyBAZnVuY3Rpb24gZ2VvbWV0cnlUb0xheWVyKGZlYXR1cmVEYXRhOiBPYmplY3QsIG9wdGlvbnM/OiBHZW9KU09OIG9wdGlvbnMpOiBMYXllclxyXG4vLyBDcmVhdGVzIGEgYExheWVyYCBmcm9tIGEgZ2l2ZW4gR2VvSlNPTiBmZWF0dXJlLiBDYW4gdXNlIGEgY3VzdG9tXHJcbi8vIFtgcG9pbnRUb0xheWVyYF0oI2dlb2pzb24tcG9pbnR0b2xheWVyKSBhbmQvb3IgW2Bjb29yZHNUb0xhdExuZ2BdKCNnZW9qc29uLWNvb3Jkc3RvbGF0bG5nKVxyXG4vLyBmdW5jdGlvbnMgaWYgcHJvdmlkZWQgYXMgb3B0aW9ucy5cclxuZnVuY3Rpb24gZ2VvbWV0cnlUb0xheWVyKGdlb2pzb24sIG9wdGlvbnMpIHtcclxuXHJcblx0dmFyIGdlb21ldHJ5ID0gZ2VvanNvbi50eXBlID09PSAnRmVhdHVyZScgPyBnZW9qc29uLmdlb21ldHJ5IDogZ2VvanNvbixcclxuXHQgICAgY29vcmRzID0gZ2VvbWV0cnkgPyBnZW9tZXRyeS5jb29yZGluYXRlcyA6IG51bGwsXHJcblx0ICAgIGxheWVycyA9IFtdLFxyXG5cdCAgICBwb2ludFRvTGF5ZXIgPSBvcHRpb25zICYmIG9wdGlvbnMucG9pbnRUb0xheWVyLFxyXG5cdCAgICBfY29vcmRzVG9MYXRMbmcgPSBvcHRpb25zICYmIG9wdGlvbnMuY29vcmRzVG9MYXRMbmcgfHwgY29vcmRzVG9MYXRMbmcsXHJcblx0ICAgIGxhdGxuZywgbGF0bG5ncywgaSwgbGVuO1xyXG5cclxuXHRpZiAoIWNvb3JkcyAmJiAhZ2VvbWV0cnkpIHtcclxuXHRcdHJldHVybiBudWxsO1xyXG5cdH1cclxuXHJcblx0c3dpdGNoIChnZW9tZXRyeS50eXBlKSB7XHJcblx0Y2FzZSAnUG9pbnQnOlxyXG5cdFx0bGF0bG5nID0gX2Nvb3Jkc1RvTGF0TG5nKGNvb3Jkcyk7XHJcblx0XHRyZXR1cm4gcG9pbnRUb0xheWVyID8gcG9pbnRUb0xheWVyKGdlb2pzb24sIGxhdGxuZykgOiBuZXcgTWFya2VyKGxhdGxuZyk7XHJcblxyXG5cdGNhc2UgJ011bHRpUG9pbnQnOlxyXG5cdFx0Zm9yIChpID0gMCwgbGVuID0gY29vcmRzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdGxhdGxuZyA9IF9jb29yZHNUb0xhdExuZyhjb29yZHNbaV0pO1xyXG5cdFx0XHRsYXllcnMucHVzaChwb2ludFRvTGF5ZXIgPyBwb2ludFRvTGF5ZXIoZ2VvanNvbiwgbGF0bG5nKSA6IG5ldyBNYXJrZXIobGF0bG5nKSk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gbmV3IEZlYXR1cmVHcm91cChsYXllcnMpO1xyXG5cclxuXHRjYXNlICdMaW5lU3RyaW5nJzpcclxuXHRjYXNlICdNdWx0aUxpbmVTdHJpbmcnOlxyXG5cdFx0bGF0bG5ncyA9IGNvb3Jkc1RvTGF0TG5ncyhjb29yZHMsIGdlb21ldHJ5LnR5cGUgPT09ICdMaW5lU3RyaW5nJyA/IDAgOiAxLCBfY29vcmRzVG9MYXRMbmcpO1xyXG5cdFx0cmV0dXJuIG5ldyBQb2x5bGluZShsYXRsbmdzLCBvcHRpb25zKTtcclxuXHJcblx0Y2FzZSAnUG9seWdvbic6XHJcblx0Y2FzZSAnTXVsdGlQb2x5Z29uJzpcclxuXHRcdGxhdGxuZ3MgPSBjb29yZHNUb0xhdExuZ3MoY29vcmRzLCBnZW9tZXRyeS50eXBlID09PSAnUG9seWdvbicgPyAxIDogMiwgX2Nvb3Jkc1RvTGF0TG5nKTtcclxuXHRcdHJldHVybiBuZXcgUG9seWdvbihsYXRsbmdzLCBvcHRpb25zKTtcclxuXHJcblx0Y2FzZSAnR2VvbWV0cnlDb2xsZWN0aW9uJzpcclxuXHRcdGZvciAoaSA9IDAsIGxlbiA9IGdlb21ldHJ5Lmdlb21ldHJpZXMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdFx0dmFyIGxheWVyID0gZ2VvbWV0cnlUb0xheWVyKHtcclxuXHRcdFx0XHRnZW9tZXRyeTogZ2VvbWV0cnkuZ2VvbWV0cmllc1tpXSxcclxuXHRcdFx0XHR0eXBlOiAnRmVhdHVyZScsXHJcblx0XHRcdFx0cHJvcGVydGllczogZ2VvanNvbi5wcm9wZXJ0aWVzXHJcblx0XHRcdH0sIG9wdGlvbnMpO1xyXG5cclxuXHRcdFx0aWYgKGxheWVyKSB7XHJcblx0XHRcdFx0bGF5ZXJzLnB1c2gobGF5ZXIpO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gbmV3IEZlYXR1cmVHcm91cChsYXllcnMpO1xyXG5cclxuXHRkZWZhdWx0OlxyXG5cdFx0dGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIEdlb0pTT04gb2JqZWN0LicpO1xyXG5cdH1cclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIGNvb3Jkc1RvTGF0TG5nKGNvb3JkczogQXJyYXkpOiBMYXRMbmdcclxuLy8gQ3JlYXRlcyBhIGBMYXRMbmdgIG9iamVjdCBmcm9tIGFuIGFycmF5IG9mIDIgbnVtYmVycyAobG9uZ2l0dWRlLCBsYXRpdHVkZSlcclxuLy8gb3IgMyBudW1iZXJzIChsb25naXR1ZGUsIGxhdGl0dWRlLCBhbHRpdHVkZSkgdXNlZCBpbiBHZW9KU09OIGZvciBwb2ludHMuXHJcbmZ1bmN0aW9uIGNvb3Jkc1RvTGF0TG5nKGNvb3Jkcykge1xyXG5cdHJldHVybiBuZXcgTGF0TG5nKGNvb3Jkc1sxXSwgY29vcmRzWzBdLCBjb29yZHNbMl0pO1xyXG59XHJcblxyXG4vLyBAZnVuY3Rpb24gY29vcmRzVG9MYXRMbmdzKGNvb3JkczogQXJyYXksIGxldmVsc0RlZXA/OiBOdW1iZXIsIGNvb3Jkc1RvTGF0TG5nPzogRnVuY3Rpb24pOiBBcnJheVxyXG4vLyBDcmVhdGVzIGEgbXVsdGlkaW1lbnNpb25hbCBhcnJheSBvZiBgTGF0TG5nYHMgZnJvbSBhIEdlb0pTT04gY29vcmRpbmF0ZXMgYXJyYXkuXHJcbi8vIGBsZXZlbHNEZWVwYCBzcGVjaWZpZXMgdGhlIG5lc3RpbmcgbGV2ZWwgKDAgaXMgZm9yIGFuIGFycmF5IG9mIHBvaW50cywgMSBmb3IgYW4gYXJyYXkgb2YgYXJyYXlzIG9mIHBvaW50cywgZXRjLiwgMCBieSBkZWZhdWx0KS5cclxuLy8gQ2FuIHVzZSBhIGN1c3RvbSBbYGNvb3Jkc1RvTGF0TG5nYF0oI2dlb2pzb24tY29vcmRzdG9sYXRsbmcpIGZ1bmN0aW9uLlxyXG5mdW5jdGlvbiBjb29yZHNUb0xhdExuZ3MoY29vcmRzLCBsZXZlbHNEZWVwLCBfY29vcmRzVG9MYXRMbmcpIHtcclxuXHR2YXIgbGF0bG5ncyA9IFtdO1xyXG5cclxuXHRmb3IgKHZhciBpID0gMCwgbGVuID0gY29vcmRzLmxlbmd0aCwgbGF0bG5nOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdGxhdGxuZyA9IGxldmVsc0RlZXAgP1xyXG5cdFx0XHRjb29yZHNUb0xhdExuZ3MoY29vcmRzW2ldLCBsZXZlbHNEZWVwIC0gMSwgX2Nvb3Jkc1RvTGF0TG5nKSA6XHJcblx0XHRcdChfY29vcmRzVG9MYXRMbmcgfHwgY29vcmRzVG9MYXRMbmcpKGNvb3Jkc1tpXSk7XHJcblxyXG5cdFx0bGF0bG5ncy5wdXNoKGxhdGxuZyk7XHJcblx0fVxyXG5cclxuXHRyZXR1cm4gbGF0bG5ncztcclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIGxhdExuZ1RvQ29vcmRzKGxhdGxuZzogTGF0TG5nLCBwcmVjaXNpb24/OiBOdW1iZXIpOiBBcnJheVxyXG4vLyBSZXZlcnNlIG9mIFtgY29vcmRzVG9MYXRMbmdgXSgjZ2VvanNvbi1jb29yZHN0b2xhdGxuZylcclxuZnVuY3Rpb24gbGF0TG5nVG9Db29yZHMobGF0bG5nLCBwcmVjaXNpb24pIHtcclxuXHRwcmVjaXNpb24gPSB0eXBlb2YgcHJlY2lzaW9uID09PSAnbnVtYmVyJyA/IHByZWNpc2lvbiA6IDY7XHJcblx0cmV0dXJuIGxhdGxuZy5hbHQgIT09IHVuZGVmaW5lZCA/XHJcblx0XHRbZm9ybWF0TnVtKGxhdGxuZy5sbmcsIHByZWNpc2lvbiksIGZvcm1hdE51bShsYXRsbmcubGF0LCBwcmVjaXNpb24pLCBmb3JtYXROdW0obGF0bG5nLmFsdCwgcHJlY2lzaW9uKV0gOlxyXG5cdFx0W2Zvcm1hdE51bShsYXRsbmcubG5nLCBwcmVjaXNpb24pLCBmb3JtYXROdW0obGF0bG5nLmxhdCwgcHJlY2lzaW9uKV07XHJcbn1cclxuXHJcbi8vIEBmdW5jdGlvbiBsYXRMbmdzVG9Db29yZHMobGF0bG5nczogQXJyYXksIGxldmVsc0RlZXA/OiBOdW1iZXIsIGNsb3NlZD86IEJvb2xlYW4pOiBBcnJheVxyXG4vLyBSZXZlcnNlIG9mIFtgY29vcmRzVG9MYXRMbmdzYF0oI2dlb2pzb24tY29vcmRzdG9sYXRsbmdzKVxyXG4vLyBgY2xvc2VkYCBkZXRlcm1pbmVzIHdoZXRoZXIgdGhlIGZpcnN0IHBvaW50IHNob3VsZCBiZSBhcHBlbmRlZCB0byB0aGUgZW5kIG9mIHRoZSBhcnJheSB0byBjbG9zZSB0aGUgZmVhdHVyZSwgb25seSB1c2VkIHdoZW4gYGxldmVsc0RlZXBgIGlzIDAuIEZhbHNlIGJ5IGRlZmF1bHQuXHJcbmZ1bmN0aW9uIGxhdExuZ3NUb0Nvb3JkcyhsYXRsbmdzLCBsZXZlbHNEZWVwLCBjbG9zZWQsIHByZWNpc2lvbikge1xyXG5cdHZhciBjb29yZHMgPSBbXTtcclxuXHJcblx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IGxhdGxuZ3MubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdGNvb3Jkcy5wdXNoKGxldmVsc0RlZXAgP1xyXG5cdFx0XHRsYXRMbmdzVG9Db29yZHMobGF0bG5nc1tpXSwgbGV2ZWxzRGVlcCAtIDEsIGNsb3NlZCwgcHJlY2lzaW9uKSA6XHJcblx0XHRcdGxhdExuZ1RvQ29vcmRzKGxhdGxuZ3NbaV0sIHByZWNpc2lvbikpO1xyXG5cdH1cclxuXHJcblx0aWYgKCFsZXZlbHNEZWVwICYmIGNsb3NlZCkge1xyXG5cdFx0Y29vcmRzLnB1c2goY29vcmRzWzBdKTtcclxuXHR9XHJcblxyXG5cdHJldHVybiBjb29yZHM7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGdldEZlYXR1cmUobGF5ZXIsIG5ld0dlb21ldHJ5KSB7XHJcblx0cmV0dXJuIGxheWVyLmZlYXR1cmUgP1xyXG5cdFx0ZXh0ZW5kKHt9LCBsYXllci5mZWF0dXJlLCB7Z2VvbWV0cnk6IG5ld0dlb21ldHJ5fSkgOlxyXG5cdFx0YXNGZWF0dXJlKG5ld0dlb21ldHJ5KTtcclxufVxyXG5cclxuLy8gQGZ1bmN0aW9uIGFzRmVhdHVyZShnZW9qc29uOiBPYmplY3QpOiBPYmplY3RcclxuLy8gTm9ybWFsaXplIEdlb0pTT04gZ2VvbWV0cmllcy9mZWF0dXJlcyBpbnRvIEdlb0pTT04gZmVhdHVyZXMuXHJcbmZ1bmN0aW9uIGFzRmVhdHVyZShnZW9qc29uKSB7XHJcblx0aWYgKGdlb2pzb24udHlwZSA9PT0gJ0ZlYXR1cmUnIHx8IGdlb2pzb24udHlwZSA9PT0gJ0ZlYXR1cmVDb2xsZWN0aW9uJykge1xyXG5cdFx0cmV0dXJuIGdlb2pzb247XHJcblx0fVxyXG5cclxuXHRyZXR1cm4ge1xyXG5cdFx0dHlwZTogJ0ZlYXR1cmUnLFxyXG5cdFx0cHJvcGVydGllczoge30sXHJcblx0XHRnZW9tZXRyeTogZ2VvanNvblxyXG5cdH07XHJcbn1cclxuXHJcbnZhciBQb2ludFRvR2VvSlNPTiA9IHtcclxuXHR0b0dlb0pTT046IGZ1bmN0aW9uIChwcmVjaXNpb24pIHtcclxuXHRcdHJldHVybiBnZXRGZWF0dXJlKHRoaXMsIHtcclxuXHRcdFx0dHlwZTogJ1BvaW50JyxcclxuXHRcdFx0Y29vcmRpbmF0ZXM6IGxhdExuZ1RvQ29vcmRzKHRoaXMuZ2V0TGF0TG5nKCksIHByZWNpc2lvbilcclxuXHRcdH0pO1xyXG5cdH1cclxufTtcclxuXHJcbi8vIEBuYW1lc3BhY2UgTWFya2VyXHJcbi8vIEBtZXRob2QgdG9HZW9KU09OKCk6IE9iamVjdFxyXG4vLyBSZXR1cm5zIGEgW2BHZW9KU09OYF0oaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9HZW9KU09OKSByZXByZXNlbnRhdGlvbiBvZiB0aGUgbWFya2VyIChhcyBhIEdlb0pTT04gYFBvaW50YCBGZWF0dXJlKS5cclxuTWFya2VyLmluY2x1ZGUoUG9pbnRUb0dlb0pTT04pO1xyXG5cclxuLy8gQG5hbWVzcGFjZSBDaXJjbGVNYXJrZXJcclxuLy8gQG1ldGhvZCB0b0dlb0pTT04oKTogT2JqZWN0XHJcbi8vIFJldHVybnMgYSBbYEdlb0pTT05gXShodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0dlb0pTT04pIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaXJjbGUgbWFya2VyIChhcyBhIEdlb0pTT04gYFBvaW50YCBGZWF0dXJlKS5cclxuQ2lyY2xlLmluY2x1ZGUoUG9pbnRUb0dlb0pTT04pO1xyXG5DaXJjbGVNYXJrZXIuaW5jbHVkZShQb2ludFRvR2VvSlNPTik7XHJcblxyXG5cclxuLy8gQG5hbWVzcGFjZSBQb2x5bGluZVxyXG4vLyBAbWV0aG9kIHRvR2VvSlNPTigpOiBPYmplY3RcclxuLy8gUmV0dXJucyBhIFtgR2VvSlNPTmBdKGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvR2VvSlNPTikgcmVwcmVzZW50YXRpb24gb2YgdGhlIHBvbHlsaW5lIChhcyBhIEdlb0pTT04gYExpbmVTdHJpbmdgIG9yIGBNdWx0aUxpbmVTdHJpbmdgIEZlYXR1cmUpLlxyXG5Qb2x5bGluZS5pbmNsdWRlKHtcclxuXHR0b0dlb0pTT046IGZ1bmN0aW9uIChwcmVjaXNpb24pIHtcclxuXHRcdHZhciBtdWx0aSA9ICFpc0ZsYXQodGhpcy5fbGF0bG5ncyk7XHJcblxyXG5cdFx0dmFyIGNvb3JkcyA9IGxhdExuZ3NUb0Nvb3Jkcyh0aGlzLl9sYXRsbmdzLCBtdWx0aSA/IDEgOiAwLCBmYWxzZSwgcHJlY2lzaW9uKTtcclxuXHJcblx0XHRyZXR1cm4gZ2V0RmVhdHVyZSh0aGlzLCB7XHJcblx0XHRcdHR5cGU6IChtdWx0aSA/ICdNdWx0aScgOiAnJykgKyAnTGluZVN0cmluZycsXHJcblx0XHRcdGNvb3JkaW5hdGVzOiBjb29yZHNcclxuXHRcdH0pO1xyXG5cdH1cclxufSk7XHJcblxyXG4vLyBAbmFtZXNwYWNlIFBvbHlnb25cclxuLy8gQG1ldGhvZCB0b0dlb0pTT04oKTogT2JqZWN0XHJcbi8vIFJldHVybnMgYSBbYEdlb0pTT05gXShodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0dlb0pTT04pIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwb2x5Z29uIChhcyBhIEdlb0pTT04gYFBvbHlnb25gIG9yIGBNdWx0aVBvbHlnb25gIEZlYXR1cmUpLlxyXG5Qb2x5Z29uLmluY2x1ZGUoe1xyXG5cdHRvR2VvSlNPTjogZnVuY3Rpb24gKHByZWNpc2lvbikge1xyXG5cdFx0dmFyIGhvbGVzID0gIWlzRmxhdCh0aGlzLl9sYXRsbmdzKSxcclxuXHRcdCAgICBtdWx0aSA9IGhvbGVzICYmICFpc0ZsYXQodGhpcy5fbGF0bG5nc1swXSk7XHJcblxyXG5cdFx0dmFyIGNvb3JkcyA9IGxhdExuZ3NUb0Nvb3Jkcyh0aGlzLl9sYXRsbmdzLCBtdWx0aSA/IDIgOiBob2xlcyA/IDEgOiAwLCB0cnVlLCBwcmVjaXNpb24pO1xyXG5cclxuXHRcdGlmICghaG9sZXMpIHtcclxuXHRcdFx0Y29vcmRzID0gW2Nvb3Jkc107XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGdldEZlYXR1cmUodGhpcywge1xyXG5cdFx0XHR0eXBlOiAobXVsdGkgPyAnTXVsdGknIDogJycpICsgJ1BvbHlnb24nLFxyXG5cdFx0XHRjb29yZGluYXRlczogY29vcmRzXHJcblx0XHR9KTtcclxuXHR9XHJcbn0pO1xyXG5cclxuXHJcbi8vIEBuYW1lc3BhY2UgTGF5ZXJHcm91cFxyXG5MYXllckdyb3VwLmluY2x1ZGUoe1xyXG5cdHRvTXVsdGlQb2ludDogZnVuY3Rpb24gKHByZWNpc2lvbikge1xyXG5cdFx0dmFyIGNvb3JkcyA9IFtdO1xyXG5cclxuXHRcdHRoaXMuZWFjaExheWVyKGZ1bmN0aW9uIChsYXllcikge1xyXG5cdFx0XHRjb29yZHMucHVzaChsYXllci50b0dlb0pTT04ocHJlY2lzaW9uKS5nZW9tZXRyeS5jb29yZGluYXRlcyk7XHJcblx0XHR9KTtcclxuXHJcblx0XHRyZXR1cm4gZ2V0RmVhdHVyZSh0aGlzLCB7XHJcblx0XHRcdHR5cGU6ICdNdWx0aVBvaW50JyxcclxuXHRcdFx0Y29vcmRpbmF0ZXM6IGNvb3Jkc1xyXG5cdFx0fSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB0b0dlb0pTT04oKTogT2JqZWN0XHJcblx0Ly8gUmV0dXJucyBhIFtgR2VvSlNPTmBdKGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvR2VvSlNPTikgcmVwcmVzZW50YXRpb24gb2YgdGhlIGxheWVyIGdyb3VwIChhcyBhIEdlb0pTT04gYEZlYXR1cmVDb2xsZWN0aW9uYCwgYEdlb21ldHJ5Q29sbGVjdGlvbmAsIG9yIGBNdWx0aVBvaW50YCkuXHJcblx0dG9HZW9KU09OOiBmdW5jdGlvbiAocHJlY2lzaW9uKSB7XHJcblxyXG5cdFx0dmFyIHR5cGUgPSB0aGlzLmZlYXR1cmUgJiYgdGhpcy5mZWF0dXJlLmdlb21ldHJ5ICYmIHRoaXMuZmVhdHVyZS5nZW9tZXRyeS50eXBlO1xyXG5cclxuXHRcdGlmICh0eXBlID09PSAnTXVsdGlQb2ludCcpIHtcclxuXHRcdFx0cmV0dXJuIHRoaXMudG9NdWx0aVBvaW50KHByZWNpc2lvbik7XHJcblx0XHR9XHJcblxyXG5cdFx0dmFyIGlzR2VvbWV0cnlDb2xsZWN0aW9uID0gdHlwZSA9PT0gJ0dlb21ldHJ5Q29sbGVjdGlvbicsXHJcblx0XHQgICAganNvbnMgPSBbXTtcclxuXHJcblx0XHR0aGlzLmVhY2hMYXllcihmdW5jdGlvbiAobGF5ZXIpIHtcclxuXHRcdFx0aWYgKGxheWVyLnRvR2VvSlNPTikge1xyXG5cdFx0XHRcdHZhciBqc29uID0gbGF5ZXIudG9HZW9KU09OKHByZWNpc2lvbik7XHJcblx0XHRcdFx0aWYgKGlzR2VvbWV0cnlDb2xsZWN0aW9uKSB7XHJcblx0XHRcdFx0XHRqc29ucy5wdXNoKGpzb24uZ2VvbWV0cnkpO1xyXG5cdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHR2YXIgZmVhdHVyZSA9IGFzRmVhdHVyZShqc29uKTtcclxuXHRcdFx0XHRcdC8vIFNxdWFzaCBuZXN0ZWQgZmVhdHVyZSBjb2xsZWN0aW9uc1xyXG5cdFx0XHRcdFx0aWYgKGZlYXR1cmUudHlwZSA9PT0gJ0ZlYXR1cmVDb2xsZWN0aW9uJykge1xyXG5cdFx0XHRcdFx0XHRqc29ucy5wdXNoLmFwcGx5KGpzb25zLCBmZWF0dXJlLmZlYXR1cmVzKTtcclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRcdGpzb25zLnB1c2goZmVhdHVyZSk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9KTtcclxuXHJcblx0XHRpZiAoaXNHZW9tZXRyeUNvbGxlY3Rpb24pIHtcclxuXHRcdFx0cmV0dXJuIGdldEZlYXR1cmUodGhpcywge1xyXG5cdFx0XHRcdGdlb21ldHJpZXM6IGpzb25zLFxyXG5cdFx0XHRcdHR5cGU6ICdHZW9tZXRyeUNvbGxlY3Rpb24nXHJcblx0XHRcdH0pO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB7XHJcblx0XHRcdHR5cGU6ICdGZWF0dXJlQ29sbGVjdGlvbicsXHJcblx0XHRcdGZlYXR1cmVzOiBqc29uc1xyXG5cdFx0fTtcclxuXHR9XHJcbn0pO1xyXG5cclxuLy8gQG5hbWVzcGFjZSBHZW9KU09OXHJcbi8vIEBmYWN0b3J5IEwuZ2VvSlNPTihnZW9qc29uPzogT2JqZWN0LCBvcHRpb25zPzogR2VvSlNPTiBvcHRpb25zKVxyXG4vLyBDcmVhdGVzIGEgR2VvSlNPTiBsYXllci4gT3B0aW9uYWxseSBhY2NlcHRzIGFuIG9iamVjdCBpblxyXG4vLyBbR2VvSlNPTiBmb3JtYXRdKGh0dHA6Ly9nZW9qc29uLm9yZy9nZW9qc29uLXNwZWMuaHRtbCkgdG8gZGlzcGxheSBvbiB0aGUgbWFwXHJcbi8vICh5b3UgY2FuIGFsdGVybmF0aXZlbHkgYWRkIGl0IGxhdGVyIHdpdGggYGFkZERhdGFgIG1ldGhvZCkgYW5kIGFuIGBvcHRpb25zYCBvYmplY3QuXHJcbmZ1bmN0aW9uIGdlb0pTT04oZ2VvanNvbiwgb3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgR2VvSlNPTihnZW9qc29uLCBvcHRpb25zKTtcclxufVxyXG5cclxuLy8gQmFja3dhcmQgY29tcGF0aWJpbGl0eS5cclxudmFyIGdlb0pzb24gPSBnZW9KU09OO1xuXG4vKlxyXG4gKiBAY2xhc3MgSW1hZ2VPdmVybGF5XHJcbiAqIEBha2EgTC5JbWFnZU92ZXJsYXlcclxuICogQGluaGVyaXRzIEludGVyYWN0aXZlIGxheWVyXHJcbiAqXHJcbiAqIFVzZWQgdG8gbG9hZCBhbmQgZGlzcGxheSBhIHNpbmdsZSBpbWFnZSBvdmVyIHNwZWNpZmljIGJvdW5kcyBvZiB0aGUgbWFwLiBFeHRlbmRzIGBMYXllcmAuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHZhciBpbWFnZVVybCA9ICdodHRwOi8vd3d3LmxpYi51dGV4YXMuZWR1L21hcHMvaGlzdG9yaWNhbC9uZXdhcmtfbmpfMTkyMi5qcGcnLFxyXG4gKiBcdGltYWdlQm91bmRzID0gW1s0MC43MTIyMTYsIC03NC4yMjY1NV0sIFs0MC43NzM5NDEsIC03NC4xMjU0NF1dO1xyXG4gKiBMLmltYWdlT3ZlcmxheShpbWFnZVVybCwgaW1hZ2VCb3VuZHMpLmFkZFRvKG1hcCk7XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcbnZhciBJbWFnZU92ZXJsYXkgPSBMYXllci5leHRlbmQoe1xyXG5cclxuXHQvLyBAc2VjdGlvblxyXG5cdC8vIEBha2EgSW1hZ2VPdmVybGF5IG9wdGlvbnNcclxuXHRvcHRpb25zOiB7XHJcblx0XHQvLyBAb3B0aW9uIG9wYWNpdHk6IE51bWJlciA9IDEuMFxyXG5cdFx0Ly8gVGhlIG9wYWNpdHkgb2YgdGhlIGltYWdlIG92ZXJsYXkuXHJcblx0XHRvcGFjaXR5OiAxLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gYWx0OiBTdHJpbmcgPSAnJ1xyXG5cdFx0Ly8gVGV4dCBmb3IgdGhlIGBhbHRgIGF0dHJpYnV0ZSBvZiB0aGUgaW1hZ2UgKHVzZWZ1bCBmb3IgYWNjZXNzaWJpbGl0eSkuXHJcblx0XHRhbHQ6ICcnLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gaW50ZXJhY3RpdmU6IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gSWYgYHRydWVgLCB0aGUgaW1hZ2Ugb3ZlcmxheSB3aWxsIGVtaXQgW21vdXNlIGV2ZW50c10oI2ludGVyYWN0aXZlLWxheWVyKSB3aGVuIGNsaWNrZWQgb3IgaG92ZXJlZC5cclxuXHRcdGludGVyYWN0aXZlOiBmYWxzZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGNyb3NzT3JpZ2luOiBCb29sZWFuID0gZmFsc2VcclxuXHRcdC8vIElmIHRydWUsIHRoZSBpbWFnZSB3aWxsIGhhdmUgaXRzIGNyb3NzT3JpZ2luIGF0dHJpYnV0ZSBzZXQgdG8gJycuIFRoaXMgaXMgbmVlZGVkIGlmIHlvdSB3YW50IHRvIGFjY2VzcyBpbWFnZSBwaXhlbCBkYXRhLlxyXG5cdFx0Y3Jvc3NPcmlnaW46IGZhbHNlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gZXJyb3JPdmVybGF5VXJsOiBTdHJpbmcgPSAnJ1xyXG5cdFx0Ly8gVVJMIHRvIHRoZSBvdmVybGF5IGltYWdlIHRvIHNob3cgaW4gcGxhY2Ugb2YgdGhlIG92ZXJsYXkgdGhhdCBmYWlsZWQgdG8gbG9hZC5cclxuXHRcdGVycm9yT3ZlcmxheVVybDogJycsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiB6SW5kZXg6IE51bWJlciA9IDFcclxuXHRcdC8vIFRoZSBleHBsaWNpdCBbekluZGV4XShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9DU1MvQ1NTX1Bvc2l0aW9uaW5nL1VuZGVyc3RhbmRpbmdfel9pbmRleCkgb2YgdGhlIHRpbGUgbGF5ZXIuXHJcblx0XHR6SW5kZXg6IDEsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBjbGFzc05hbWU6IFN0cmluZyA9ICcnXHJcblx0XHQvLyBBIGN1c3RvbSBjbGFzcyBuYW1lIHRvIGFzc2lnbiB0byB0aGUgaW1hZ2UuIEVtcHR5IGJ5IGRlZmF1bHQuXHJcblx0XHRjbGFzc05hbWU6ICcnLFxyXG5cdH0sXHJcblxyXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uICh1cmwsIGJvdW5kcywgb3B0aW9ucykgeyAvLyAoU3RyaW5nLCBMYXRMbmdCb3VuZHMsIE9iamVjdClcclxuXHRcdHRoaXMuX3VybCA9IHVybDtcclxuXHRcdHRoaXMuX2JvdW5kcyA9IHRvTGF0TG5nQm91bmRzKGJvdW5kcyk7XHJcblxyXG5cdFx0c2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcclxuXHR9LFxyXG5cclxuXHRvbkFkZDogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKCF0aGlzLl9pbWFnZSkge1xyXG5cdFx0XHR0aGlzLl9pbml0SW1hZ2UoKTtcclxuXHJcblx0XHRcdGlmICh0aGlzLm9wdGlvbnMub3BhY2l0eSA8IDEpIHtcclxuXHRcdFx0XHR0aGlzLl91cGRhdGVPcGFjaXR5KCk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRpZiAodGhpcy5vcHRpb25zLmludGVyYWN0aXZlKSB7XHJcblx0XHRcdGFkZENsYXNzKHRoaXMuX2ltYWdlLCAnbGVhZmxldC1pbnRlcmFjdGl2ZScpO1xyXG5cdFx0XHR0aGlzLmFkZEludGVyYWN0aXZlVGFyZ2V0KHRoaXMuX2ltYWdlKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmdldFBhbmUoKS5hcHBlbmRDaGlsZCh0aGlzLl9pbWFnZSk7XHJcblx0XHR0aGlzLl9yZXNldCgpO1xyXG5cdH0sXHJcblxyXG5cdG9uUmVtb3ZlOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZW1vdmUodGhpcy5faW1hZ2UpO1xyXG5cdFx0aWYgKHRoaXMub3B0aW9ucy5pbnRlcmFjdGl2ZSkge1xyXG5cdFx0XHR0aGlzLnJlbW92ZUludGVyYWN0aXZlVGFyZ2V0KHRoaXMuX2ltYWdlKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldE9wYWNpdHkob3BhY2l0eTogTnVtYmVyKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIG9wYWNpdHkgb2YgdGhlIG92ZXJsYXkuXHJcblx0c2V0T3BhY2l0eTogZnVuY3Rpb24gKG9wYWNpdHkpIHtcclxuXHRcdHRoaXMub3B0aW9ucy5vcGFjaXR5ID0gb3BhY2l0eTtcclxuXHJcblx0XHRpZiAodGhpcy5faW1hZ2UpIHtcclxuXHRcdFx0dGhpcy5fdXBkYXRlT3BhY2l0eSgpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0c2V0U3R5bGU6IGZ1bmN0aW9uIChzdHlsZU9wdHMpIHtcclxuXHRcdGlmIChzdHlsZU9wdHMub3BhY2l0eSkge1xyXG5cdFx0XHR0aGlzLnNldE9wYWNpdHkoc3R5bGVPcHRzLm9wYWNpdHkpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBicmluZ1RvRnJvbnQoKTogdGhpc1xyXG5cdC8vIEJyaW5ncyB0aGUgbGF5ZXIgdG8gdGhlIHRvcCBvZiBhbGwgb3ZlcmxheXMuXHJcblx0YnJpbmdUb0Zyb250OiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAodGhpcy5fbWFwKSB7XHJcblx0XHRcdHRvRnJvbnQodGhpcy5faW1hZ2UpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBicmluZ1RvQmFjaygpOiB0aGlzXHJcblx0Ly8gQnJpbmdzIHRoZSBsYXllciB0byB0aGUgYm90dG9tIG9mIGFsbCBvdmVybGF5cy5cclxuXHRicmluZ1RvQmFjazogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKHRoaXMuX21hcCkge1xyXG5cdFx0XHR0b0JhY2sodGhpcy5faW1hZ2UpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBzZXRVcmwodXJsOiBTdHJpbmcpOiB0aGlzXHJcblx0Ly8gQ2hhbmdlcyB0aGUgVVJMIG9mIHRoZSBpbWFnZS5cclxuXHRzZXRVcmw6IGZ1bmN0aW9uICh1cmwpIHtcclxuXHRcdHRoaXMuX3VybCA9IHVybDtcclxuXHJcblx0XHRpZiAodGhpcy5faW1hZ2UpIHtcclxuXHRcdFx0dGhpcy5faW1hZ2Uuc3JjID0gdXJsO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBzZXRCb3VuZHMoYm91bmRzOiBMYXRMbmdCb3VuZHMpOiB0aGlzXHJcblx0Ly8gVXBkYXRlIHRoZSBib3VuZHMgdGhhdCB0aGlzIEltYWdlT3ZlcmxheSBjb3ZlcnNcclxuXHRzZXRCb3VuZHM6IGZ1bmN0aW9uIChib3VuZHMpIHtcclxuXHRcdHRoaXMuX2JvdW5kcyA9IHRvTGF0TG5nQm91bmRzKGJvdW5kcyk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX21hcCkge1xyXG5cdFx0XHR0aGlzLl9yZXNldCgpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Z2V0RXZlbnRzOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgZXZlbnRzID0ge1xyXG5cdFx0XHR6b29tOiB0aGlzLl9yZXNldCxcclxuXHRcdFx0dmlld3Jlc2V0OiB0aGlzLl9yZXNldFxyXG5cdFx0fTtcclxuXHJcblx0XHRpZiAodGhpcy5fem9vbUFuaW1hdGVkKSB7XHJcblx0XHRcdGV2ZW50cy56b29tYW5pbSA9IHRoaXMuX2FuaW1hdGVab29tO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBldmVudHM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZDogc2V0WkluZGV4KHZhbHVlOiBOdW1iZXIpIDogdGhpc1xyXG5cdC8vIENoYW5nZXMgdGhlIFt6SW5kZXhdKCNpbWFnZW92ZXJsYXktemluZGV4KSBvZiB0aGUgaW1hZ2Ugb3ZlcmxheS5cclxuXHRzZXRaSW5kZXg6IGZ1bmN0aW9uICh2YWx1ZSkge1xyXG5cdFx0dGhpcy5vcHRpb25zLnpJbmRleCA9IHZhbHVlO1xyXG5cdFx0dGhpcy5fdXBkYXRlWkluZGV4KCk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldEJvdW5kcygpOiBMYXRMbmdCb3VuZHNcclxuXHQvLyBHZXQgdGhlIGJvdW5kcyB0aGF0IHRoaXMgSW1hZ2VPdmVybGF5IGNvdmVyc1xyXG5cdGdldEJvdW5kczogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX2JvdW5kcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldEVsZW1lbnQoKTogSFRNTEVsZW1lbnRcclxuXHQvLyBSZXR1cm5zIHRoZSBpbnN0YW5jZSBvZiBbYEhUTUxJbWFnZUVsZW1lbnRgXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9BUEkvSFRNTEltYWdlRWxlbWVudClcclxuXHQvLyB1c2VkIGJ5IHRoaXMgb3ZlcmxheS5cclxuXHRnZXRFbGVtZW50OiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5faW1hZ2U7XHJcblx0fSxcclxuXHJcblx0X2luaXRJbWFnZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIHdhc0VsZW1lbnRTdXBwbGllZCA9IHRoaXMuX3VybC50YWdOYW1lID09PSAnSU1HJztcclxuXHRcdHZhciBpbWcgPSB0aGlzLl9pbWFnZSA9IHdhc0VsZW1lbnRTdXBwbGllZCA/IHRoaXMuX3VybCA6IGNyZWF0ZSQxKCdpbWcnKTtcclxuXHJcblx0XHRhZGRDbGFzcyhpbWcsICdsZWFmbGV0LWltYWdlLWxheWVyJyk7XHJcblx0XHRpZiAodGhpcy5fem9vbUFuaW1hdGVkKSB7IGFkZENsYXNzKGltZywgJ2xlYWZsZXQtem9vbS1hbmltYXRlZCcpOyB9XHJcblx0XHRpZiAodGhpcy5vcHRpb25zLmNsYXNzTmFtZSkgeyBhZGRDbGFzcyhpbWcsIHRoaXMub3B0aW9ucy5jbGFzc05hbWUpOyB9XHJcblxyXG5cdFx0aW1nLm9uc2VsZWN0c3RhcnQgPSBmYWxzZUZuO1xyXG5cdFx0aW1nLm9ubW91c2Vtb3ZlID0gZmFsc2VGbjtcclxuXHJcblx0XHQvLyBAZXZlbnQgbG9hZDogRXZlbnRcclxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIEltYWdlT3ZlcmxheSBsYXllciBoYXMgbG9hZGVkIGl0cyBpbWFnZVxyXG5cdFx0aW1nLm9ubG9hZCA9IGJpbmQodGhpcy5maXJlLCB0aGlzLCAnbG9hZCcpO1xyXG5cdFx0aW1nLm9uZXJyb3IgPSBiaW5kKHRoaXMuX292ZXJsYXlPbkVycm9yLCB0aGlzLCAnZXJyb3InKTtcclxuXHJcblx0XHRpZiAodGhpcy5vcHRpb25zLmNyb3NzT3JpZ2luKSB7XHJcblx0XHRcdGltZy5jcm9zc09yaWdpbiA9ICcnO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICh0aGlzLm9wdGlvbnMuekluZGV4KSB7XHJcblx0XHRcdHRoaXMuX3VwZGF0ZVpJbmRleCgpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICh3YXNFbGVtZW50U3VwcGxpZWQpIHtcclxuXHRcdFx0dGhpcy5fdXJsID0gaW1nLnNyYztcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdGltZy5zcmMgPSB0aGlzLl91cmw7XHJcblx0XHRpbWcuYWx0ID0gdGhpcy5vcHRpb25zLmFsdDtcclxuXHR9LFxyXG5cclxuXHRfYW5pbWF0ZVpvb206IGZ1bmN0aW9uIChlKSB7XHJcblx0XHR2YXIgc2NhbGUgPSB0aGlzLl9tYXAuZ2V0Wm9vbVNjYWxlKGUuem9vbSksXHJcblx0XHQgICAgb2Zmc2V0ID0gdGhpcy5fbWFwLl9sYXRMbmdCb3VuZHNUb05ld0xheWVyQm91bmRzKHRoaXMuX2JvdW5kcywgZS56b29tLCBlLmNlbnRlcikubWluO1xyXG5cclxuXHRcdHNldFRyYW5zZm9ybSh0aGlzLl9pbWFnZSwgb2Zmc2V0LCBzY2FsZSk7XHJcblx0fSxcclxuXHJcblx0X3Jlc2V0OiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgaW1hZ2UgPSB0aGlzLl9pbWFnZSxcclxuXHRcdCAgICBib3VuZHMgPSBuZXcgQm91bmRzKFxyXG5cdFx0ICAgICAgICB0aGlzLl9tYXAubGF0TG5nVG9MYXllclBvaW50KHRoaXMuX2JvdW5kcy5nZXROb3J0aFdlc3QoKSksXHJcblx0XHQgICAgICAgIHRoaXMuX21hcC5sYXRMbmdUb0xheWVyUG9pbnQodGhpcy5fYm91bmRzLmdldFNvdXRoRWFzdCgpKSksXHJcblx0XHQgICAgc2l6ZSA9IGJvdW5kcy5nZXRTaXplKCk7XHJcblxyXG5cdFx0c2V0UG9zaXRpb24oaW1hZ2UsIGJvdW5kcy5taW4pO1xyXG5cclxuXHRcdGltYWdlLnN0eWxlLndpZHRoICA9IHNpemUueCArICdweCc7XHJcblx0XHRpbWFnZS5zdHlsZS5oZWlnaHQgPSBzaXplLnkgKyAncHgnO1xyXG5cdH0sXHJcblxyXG5cdF91cGRhdGVPcGFjaXR5OiBmdW5jdGlvbiAoKSB7XHJcblx0XHRzZXRPcGFjaXR5KHRoaXMuX2ltYWdlLCB0aGlzLm9wdGlvbnMub3BhY2l0eSk7XHJcblx0fSxcclxuXHJcblx0X3VwZGF0ZVpJbmRleDogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKHRoaXMuX2ltYWdlICYmIHRoaXMub3B0aW9ucy56SW5kZXggIT09IHVuZGVmaW5lZCAmJiB0aGlzLm9wdGlvbnMuekluZGV4ICE9PSBudWxsKSB7XHJcblx0XHRcdHRoaXMuX2ltYWdlLnN0eWxlLnpJbmRleCA9IHRoaXMub3B0aW9ucy56SW5kZXg7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X292ZXJsYXlPbkVycm9yOiBmdW5jdGlvbiAoKSB7XHJcblx0XHQvLyBAZXZlbnQgZXJyb3I6IEV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSBJbWFnZU92ZXJsYXkgbGF5ZXIgaGFzIGxvYWRlZCBpdHMgaW1hZ2VcclxuXHRcdHRoaXMuZmlyZSgnZXJyb3InKTtcclxuXHJcblx0XHR2YXIgZXJyb3JVcmwgPSB0aGlzLm9wdGlvbnMuZXJyb3JPdmVybGF5VXJsO1xyXG5cdFx0aWYgKGVycm9yVXJsICYmIHRoaXMuX3VybCAhPT0gZXJyb3JVcmwpIHtcclxuXHRcdFx0dGhpcy5fdXJsID0gZXJyb3JVcmw7XHJcblx0XHRcdHRoaXMuX2ltYWdlLnNyYyA9IGVycm9yVXJsO1xyXG5cdFx0fVxyXG5cdH1cclxufSk7XHJcblxyXG4vLyBAZmFjdG9yeSBMLmltYWdlT3ZlcmxheShpbWFnZVVybDogU3RyaW5nLCBib3VuZHM6IExhdExuZ0JvdW5kcywgb3B0aW9ucz86IEltYWdlT3ZlcmxheSBvcHRpb25zKVxyXG4vLyBJbnN0YW50aWF0ZXMgYW4gaW1hZ2Ugb3ZlcmxheSBvYmplY3QgZ2l2ZW4gdGhlIFVSTCBvZiB0aGUgaW1hZ2UgYW5kIHRoZVxyXG4vLyBnZW9ncmFwaGljYWwgYm91bmRzIGl0IGlzIHRpZWQgdG8uXHJcbnZhciBpbWFnZU92ZXJsYXkgPSBmdW5jdGlvbiAodXJsLCBib3VuZHMsIG9wdGlvbnMpIHtcclxuXHRyZXR1cm4gbmV3IEltYWdlT3ZlcmxheSh1cmwsIGJvdW5kcywgb3B0aW9ucyk7XHJcbn07XG5cbi8qXHJcbiAqIEBjbGFzcyBWaWRlb092ZXJsYXlcclxuICogQGFrYSBMLlZpZGVvT3ZlcmxheVxyXG4gKiBAaW5oZXJpdHMgSW1hZ2VPdmVybGF5XHJcbiAqXHJcbiAqIFVzZWQgdG8gbG9hZCBhbmQgZGlzcGxheSBhIHZpZGVvIHBsYXllciBvdmVyIHNwZWNpZmljIGJvdW5kcyBvZiB0aGUgbWFwLiBFeHRlbmRzIGBJbWFnZU92ZXJsYXlgLlxyXG4gKlxyXG4gKiBBIHZpZGVvIG92ZXJsYXkgdXNlcyB0aGUgW2A8dmlkZW8+YF0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvSFRNTC9FbGVtZW50L3ZpZGVvKVxyXG4gKiBIVE1MNSBlbGVtZW50LlxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiB2YXIgdmlkZW9VcmwgPSAnaHR0cHM6Ly93d3cubWFwYm94LmNvbS9iaXRlcy8wMDE4OC9wYXRyaWNpYV9uYXNhLndlYm0nLFxyXG4gKiBcdHZpZGVvQm91bmRzID0gW1sgMzIsIC0xMzBdLCBbIDEzLCAtMTAwXV07XHJcbiAqIEwuVmlkZW9PdmVybGF5KHZpZGVvVXJsLCB2aWRlb0JvdW5kcyApLmFkZFRvKG1hcCk7XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcbnZhciBWaWRlb092ZXJsYXkgPSBJbWFnZU92ZXJsYXkuZXh0ZW5kKHtcclxuXHJcblx0Ly8gQHNlY3Rpb25cclxuXHQvLyBAYWthIFZpZGVvT3ZlcmxheSBvcHRpb25zXHJcblx0b3B0aW9uczoge1xyXG5cdFx0Ly8gQG9wdGlvbiBhdXRvcGxheTogQm9vbGVhbiA9IHRydWVcclxuXHRcdC8vIFdoZXRoZXIgdGhlIHZpZGVvIHN0YXJ0cyBwbGF5aW5nIGF1dG9tYXRpY2FsbHkgd2hlbiBsb2FkZWQuXHJcblx0XHRhdXRvcGxheTogdHJ1ZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGxvb3A6IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBXaGV0aGVyIHRoZSB2aWRlbyB3aWxsIGxvb3AgYmFjayB0byB0aGUgYmVnaW5uaW5nIHdoZW4gcGxheWVkLlxyXG5cdFx0bG9vcDogdHJ1ZVxyXG5cdH0sXHJcblxyXG5cdF9pbml0SW1hZ2U6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciB3YXNFbGVtZW50U3VwcGxpZWQgPSB0aGlzLl91cmwudGFnTmFtZSA9PT0gJ1ZJREVPJztcclxuXHRcdHZhciB2aWQgPSB0aGlzLl9pbWFnZSA9IHdhc0VsZW1lbnRTdXBwbGllZCA/IHRoaXMuX3VybCA6IGNyZWF0ZSQxKCd2aWRlbycpO1xyXG5cclxuXHRcdGFkZENsYXNzKHZpZCwgJ2xlYWZsZXQtaW1hZ2UtbGF5ZXInKTtcclxuXHRcdGlmICh0aGlzLl96b29tQW5pbWF0ZWQpIHsgYWRkQ2xhc3ModmlkLCAnbGVhZmxldC16b29tLWFuaW1hdGVkJyk7IH1cclxuXHJcblx0XHR2aWQub25zZWxlY3RzdGFydCA9IGZhbHNlRm47XHJcblx0XHR2aWQub25tb3VzZW1vdmUgPSBmYWxzZUZuO1xyXG5cclxuXHRcdC8vIEBldmVudCBsb2FkOiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgdmlkZW8gaGFzIGZpbmlzaGVkIGxvYWRpbmcgdGhlIGZpcnN0IGZyYW1lXHJcblx0XHR2aWQub25sb2FkZWRkYXRhID0gYmluZCh0aGlzLmZpcmUsIHRoaXMsICdsb2FkJyk7XHJcblxyXG5cdFx0aWYgKHdhc0VsZW1lbnRTdXBwbGllZCkge1xyXG5cdFx0XHR2YXIgc291cmNlRWxlbWVudHMgPSB2aWQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3NvdXJjZScpO1xyXG5cdFx0XHR2YXIgc291cmNlcyA9IFtdO1xyXG5cdFx0XHRmb3IgKHZhciBqID0gMDsgaiA8IHNvdXJjZUVsZW1lbnRzLmxlbmd0aDsgaisrKSB7XHJcblx0XHRcdFx0c291cmNlcy5wdXNoKHNvdXJjZUVsZW1lbnRzW2pdLnNyYyk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuX3VybCA9IChzb3VyY2VFbGVtZW50cy5sZW5ndGggPiAwKSA/IHNvdXJjZXMgOiBbdmlkLnNyY107XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIWlzQXJyYXkodGhpcy5fdXJsKSkgeyB0aGlzLl91cmwgPSBbdGhpcy5fdXJsXTsgfVxyXG5cclxuXHRcdHZpZC5hdXRvcGxheSA9ICEhdGhpcy5vcHRpb25zLmF1dG9wbGF5O1xyXG5cdFx0dmlkLmxvb3AgPSAhIXRoaXMub3B0aW9ucy5sb29wO1xyXG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLl91cmwubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0dmFyIHNvdXJjZSA9IGNyZWF0ZSQxKCdzb3VyY2UnKTtcclxuXHRcdFx0c291cmNlLnNyYyA9IHRoaXMuX3VybFtpXTtcclxuXHRcdFx0dmlkLmFwcGVuZENoaWxkKHNvdXJjZSk7XHJcblx0XHR9XHJcblx0fVxyXG5cclxuXHQvLyBAbWV0aG9kIGdldEVsZW1lbnQoKTogSFRNTFZpZGVvRWxlbWVudFxyXG5cdC8vIFJldHVybnMgdGhlIGluc3RhbmNlIG9mIFtgSFRNTFZpZGVvRWxlbWVudGBdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL0FQSS9IVE1MVmlkZW9FbGVtZW50KVxyXG5cdC8vIHVzZWQgYnkgdGhpcyBvdmVybGF5LlxyXG59KTtcclxuXHJcblxyXG4vLyBAZmFjdG9yeSBMLnZpZGVvT3ZlcmxheSh2aWRlbzogU3RyaW5nfEFycmF5fEhUTUxWaWRlb0VsZW1lbnQsIGJvdW5kczogTGF0TG5nQm91bmRzLCBvcHRpb25zPzogVmlkZW9PdmVybGF5IG9wdGlvbnMpXHJcbi8vIEluc3RhbnRpYXRlcyBhbiBpbWFnZSBvdmVybGF5IG9iamVjdCBnaXZlbiB0aGUgVVJMIG9mIHRoZSB2aWRlbyAob3IgYXJyYXkgb2YgVVJMcywgb3IgZXZlbiBhIHZpZGVvIGVsZW1lbnQpIGFuZCB0aGVcclxuLy8gZ2VvZ3JhcGhpY2FsIGJvdW5kcyBpdCBpcyB0aWVkIHRvLlxyXG5cclxuZnVuY3Rpb24gdmlkZW9PdmVybGF5KHZpZGVvLCBib3VuZHMsIG9wdGlvbnMpIHtcclxuXHRyZXR1cm4gbmV3IFZpZGVvT3ZlcmxheSh2aWRlbywgYm91bmRzLCBvcHRpb25zKTtcclxufVxuXG4vKlxyXG4gKiBAY2xhc3MgRGl2T3ZlcmxheVxyXG4gKiBAaW5oZXJpdHMgTGF5ZXJcclxuICogQGFrYSBMLkRpdk92ZXJsYXlcclxuICogQmFzZSBtb2RlbCBmb3IgTC5Qb3B1cCBhbmQgTC5Ub29sdGlwLiBJbmhlcml0IGZyb20gaXQgZm9yIGN1c3RvbSBwb3B1cCBsaWtlIHBsdWdpbnMuXHJcbiAqL1xyXG5cclxuLy8gQG5hbWVzcGFjZSBEaXZPdmVybGF5XHJcbnZhciBEaXZPdmVybGF5ID0gTGF5ZXIuZXh0ZW5kKHtcclxuXHJcblx0Ly8gQHNlY3Rpb25cclxuXHQvLyBAYWthIERpdk92ZXJsYXkgb3B0aW9uc1xyXG5cdG9wdGlvbnM6IHtcclxuXHRcdC8vIEBvcHRpb24gb2Zmc2V0OiBQb2ludCA9IFBvaW50KDAsIDcpXHJcblx0XHQvLyBUaGUgb2Zmc2V0IG9mIHRoZSBwb3B1cCBwb3NpdGlvbi4gVXNlZnVsIHRvIGNvbnRyb2wgdGhlIGFuY2hvclxyXG5cdFx0Ly8gb2YgdGhlIHBvcHVwIHdoZW4gb3BlbmluZyBpdCBvbiBzb21lIG92ZXJsYXlzLlxyXG5cdFx0b2Zmc2V0OiBbMCwgN10sXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBjbGFzc05hbWU6IFN0cmluZyA9ICcnXHJcblx0XHQvLyBBIGN1c3RvbSBDU1MgY2xhc3MgbmFtZSB0byBhc3NpZ24gdG8gdGhlIHBvcHVwLlxyXG5cdFx0Y2xhc3NOYW1lOiAnJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHBhbmU6IFN0cmluZyA9ICdwb3B1cFBhbmUnXHJcblx0XHQvLyBgTWFwIHBhbmVgIHdoZXJlIHRoZSBwb3B1cCB3aWxsIGJlIGFkZGVkLlxyXG5cdFx0cGFuZTogJ3BvcHVwUGFuZSdcclxuXHR9LFxyXG5cclxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucywgc291cmNlKSB7XHJcblx0XHRzZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xyXG5cclxuXHRcdHRoaXMuX3NvdXJjZSA9IHNvdXJjZTtcclxuXHR9LFxyXG5cclxuXHRvbkFkZDogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0dGhpcy5fem9vbUFuaW1hdGVkID0gbWFwLl96b29tQW5pbWF0ZWQ7XHJcblxyXG5cdFx0aWYgKCF0aGlzLl9jb250YWluZXIpIHtcclxuXHRcdFx0dGhpcy5faW5pdExheW91dCgpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChtYXAuX2ZhZGVBbmltYXRlZCkge1xyXG5cdFx0XHRzZXRPcGFjaXR5KHRoaXMuX2NvbnRhaW5lciwgMCk7XHJcblx0XHR9XHJcblxyXG5cdFx0Y2xlYXJUaW1lb3V0KHRoaXMuX3JlbW92ZVRpbWVvdXQpO1xyXG5cdFx0dGhpcy5nZXRQYW5lKCkuYXBwZW5kQ2hpbGQodGhpcy5fY29udGFpbmVyKTtcclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cdFx0aWYgKG1hcC5fZmFkZUFuaW1hdGVkKSB7XHJcblx0XHRcdHNldE9wYWNpdHkodGhpcy5fY29udGFpbmVyLCAxKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLmJyaW5nVG9Gcm9udCgpO1xyXG5cdH0sXHJcblxyXG5cdG9uUmVtb3ZlOiBmdW5jdGlvbiAobWFwKSB7XHJcblx0XHRpZiAobWFwLl9mYWRlQW5pbWF0ZWQpIHtcclxuXHRcdFx0c2V0T3BhY2l0eSh0aGlzLl9jb250YWluZXIsIDApO1xyXG5cdFx0XHR0aGlzLl9yZW1vdmVUaW1lb3V0ID0gc2V0VGltZW91dChiaW5kKHJlbW92ZSwgdW5kZWZpbmVkLCB0aGlzLl9jb250YWluZXIpLCAyMDApO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0cmVtb3ZlKHRoaXMuX2NvbnRhaW5lcik7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gQG5hbWVzcGFjZSBQb3B1cFxyXG5cdC8vIEBtZXRob2QgZ2V0TGF0TG5nOiBMYXRMbmdcclxuXHQvLyBSZXR1cm5zIHRoZSBnZW9ncmFwaGljYWwgcG9pbnQgb2YgcG9wdXAuXHJcblx0Z2V0TGF0TG5nOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5fbGF0bG5nO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0TGF0TG5nKGxhdGxuZzogTGF0TG5nKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIGdlb2dyYXBoaWNhbCBwb2ludCB3aGVyZSB0aGUgcG9wdXAgd2lsbCBvcGVuLlxyXG5cdHNldExhdExuZzogZnVuY3Rpb24gKGxhdGxuZykge1xyXG5cdFx0dGhpcy5fbGF0bG5nID0gdG9MYXRMbmcobGF0bG5nKTtcclxuXHRcdGlmICh0aGlzLl9tYXApIHtcclxuXHRcdFx0dGhpcy5fdXBkYXRlUG9zaXRpb24oKTtcclxuXHRcdFx0dGhpcy5fYWRqdXN0UGFuKCk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldENvbnRlbnQ6IFN0cmluZ3xIVE1MRWxlbWVudFxyXG5cdC8vIFJldHVybnMgdGhlIGNvbnRlbnQgb2YgdGhlIHBvcHVwLlxyXG5cdGdldENvbnRlbnQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9jb250ZW50O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0Q29udGVudChodG1sQ29udGVudDogU3RyaW5nfEhUTUxFbGVtZW50fEZ1bmN0aW9uKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIEhUTUwgY29udGVudCBvZiB0aGUgcG9wdXAuIElmIGEgZnVuY3Rpb24gaXMgcGFzc2VkIHRoZSBzb3VyY2UgbGF5ZXIgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLiBUaGUgZnVuY3Rpb24gc2hvdWxkIHJldHVybiBhIGBTdHJpbmdgIG9yIGBIVE1MRWxlbWVudGAgdG8gYmUgdXNlZCBpbiB0aGUgcG9wdXAuXHJcblx0c2V0Q29udGVudDogZnVuY3Rpb24gKGNvbnRlbnQpIHtcclxuXHRcdHRoaXMuX2NvbnRlbnQgPSBjb250ZW50O1xyXG5cdFx0dGhpcy51cGRhdGUoKTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0RWxlbWVudDogU3RyaW5nfEhUTUxFbGVtZW50XHJcblx0Ly8gQWxpYXMgZm9yIFtnZXRDb250ZW50KCldKCNwb3B1cC1nZXRjb250ZW50KVxyXG5cdGdldEVsZW1lbnQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9jb250YWluZXI7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB1cGRhdGU6IG51bGxcclxuXHQvLyBVcGRhdGVzIHRoZSBwb3B1cCBjb250ZW50LCBsYXlvdXQgYW5kIHBvc2l0aW9uLiBVc2VmdWwgZm9yIHVwZGF0aW5nIHRoZSBwb3B1cCBhZnRlciBzb21ldGhpbmcgaW5zaWRlIGNoYW5nZWQsIGUuZy4gaW1hZ2UgbG9hZGVkLlxyXG5cdHVwZGF0ZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKCF0aGlzLl9tYXApIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0dGhpcy5fY29udGFpbmVyLnN0eWxlLnZpc2liaWxpdHkgPSAnaGlkZGVuJztcclxuXHJcblx0XHR0aGlzLl91cGRhdGVDb250ZW50KCk7XHJcblx0XHR0aGlzLl91cGRhdGVMYXlvdXQoKTtcclxuXHRcdHRoaXMuX3VwZGF0ZVBvc2l0aW9uKCk7XHJcblxyXG5cdFx0dGhpcy5fY29udGFpbmVyLnN0eWxlLnZpc2liaWxpdHkgPSAnJztcclxuXHJcblx0XHR0aGlzLl9hZGp1c3RQYW4oKTtcclxuXHR9LFxyXG5cclxuXHRnZXRFdmVudHM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBldmVudHMgPSB7XHJcblx0XHRcdHpvb206IHRoaXMuX3VwZGF0ZVBvc2l0aW9uLFxyXG5cdFx0XHR2aWV3cmVzZXQ6IHRoaXMuX3VwZGF0ZVBvc2l0aW9uXHJcblx0XHR9O1xyXG5cclxuXHRcdGlmICh0aGlzLl96b29tQW5pbWF0ZWQpIHtcclxuXHRcdFx0ZXZlbnRzLnpvb21hbmltID0gdGhpcy5fYW5pbWF0ZVpvb207XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gZXZlbnRzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgaXNPcGVuOiBCb29sZWFuXHJcblx0Ly8gUmV0dXJucyBgdHJ1ZWAgd2hlbiB0aGUgcG9wdXAgaXMgdmlzaWJsZSBvbiB0aGUgbWFwLlxyXG5cdGlzT3BlbjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuICEhdGhpcy5fbWFwICYmIHRoaXMuX21hcC5oYXNMYXllcih0aGlzKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGJyaW5nVG9Gcm9udDogdGhpc1xyXG5cdC8vIEJyaW5ncyB0aGlzIHBvcHVwIGluIGZyb250IG9mIG90aGVyIHBvcHVwcyAoaW4gdGhlIHNhbWUgbWFwIHBhbmUpLlxyXG5cdGJyaW5nVG9Gcm9udDogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKHRoaXMuX21hcCkge1xyXG5cdFx0XHR0b0Zyb250KHRoaXMuX2NvbnRhaW5lcik7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGJyaW5nVG9CYWNrOiB0aGlzXHJcblx0Ly8gQnJpbmdzIHRoaXMgcG9wdXAgdG8gdGhlIGJhY2sgb2Ygb3RoZXIgcG9wdXBzIChpbiB0aGUgc2FtZSBtYXAgcGFuZSkuXHJcblx0YnJpbmdUb0JhY2s6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICh0aGlzLl9tYXApIHtcclxuXHRcdFx0dG9CYWNrKHRoaXMuX2NvbnRhaW5lcik7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfdXBkYXRlQ29udGVudDogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKCF0aGlzLl9jb250ZW50KSB7IHJldHVybjsgfVxyXG5cclxuXHRcdHZhciBub2RlID0gdGhpcy5fY29udGVudE5vZGU7XHJcblx0XHR2YXIgY29udGVudCA9ICh0eXBlb2YgdGhpcy5fY29udGVudCA9PT0gJ2Z1bmN0aW9uJykgPyB0aGlzLl9jb250ZW50KHRoaXMuX3NvdXJjZSB8fCB0aGlzKSA6IHRoaXMuX2NvbnRlbnQ7XHJcblxyXG5cdFx0aWYgKHR5cGVvZiBjb250ZW50ID09PSAnc3RyaW5nJykge1xyXG5cdFx0XHRub2RlLmlubmVySFRNTCA9IGNvbnRlbnQ7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR3aGlsZSAobm9kZS5oYXNDaGlsZE5vZGVzKCkpIHtcclxuXHRcdFx0XHRub2RlLnJlbW92ZUNoaWxkKG5vZGUuZmlyc3RDaGlsZCk7XHJcblx0XHRcdH1cclxuXHRcdFx0bm9kZS5hcHBlbmRDaGlsZChjb250ZW50KTtcclxuXHRcdH1cclxuXHRcdHRoaXMuZmlyZSgnY29udGVudHVwZGF0ZScpO1xyXG5cdH0sXHJcblxyXG5cdF91cGRhdGVQb3NpdGlvbjogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKCF0aGlzLl9tYXApIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0dmFyIHBvcyA9IHRoaXMuX21hcC5sYXRMbmdUb0xheWVyUG9pbnQodGhpcy5fbGF0bG5nKSxcclxuXHRcdCAgICBvZmZzZXQgPSB0b1BvaW50KHRoaXMub3B0aW9ucy5vZmZzZXQpLFxyXG5cdFx0ICAgIGFuY2hvciA9IHRoaXMuX2dldEFuY2hvcigpO1xyXG5cclxuXHRcdGlmICh0aGlzLl96b29tQW5pbWF0ZWQpIHtcclxuXHRcdFx0c2V0UG9zaXRpb24odGhpcy5fY29udGFpbmVyLCBwb3MuYWRkKGFuY2hvcikpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0b2Zmc2V0ID0gb2Zmc2V0LmFkZChwb3MpLmFkZChhbmNob3IpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBib3R0b20gPSB0aGlzLl9jb250YWluZXJCb3R0b20gPSAtb2Zmc2V0LnksXHJcblx0XHQgICAgbGVmdCA9IHRoaXMuX2NvbnRhaW5lckxlZnQgPSAtTWF0aC5yb3VuZCh0aGlzLl9jb250YWluZXJXaWR0aCAvIDIpICsgb2Zmc2V0Lng7XHJcblxyXG5cdFx0Ly8gYm90dG9tIHBvc2l0aW9uIHRoZSBwb3B1cCBpbiBjYXNlIHRoZSBoZWlnaHQgb2YgdGhlIHBvcHVwIGNoYW5nZXMgKGltYWdlcyBsb2FkaW5nIGV0YylcclxuXHRcdHRoaXMuX2NvbnRhaW5lci5zdHlsZS5ib3R0b20gPSBib3R0b20gKyAncHgnO1xyXG5cdFx0dGhpcy5fY29udGFpbmVyLnN0eWxlLmxlZnQgPSBsZWZ0ICsgJ3B4JztcclxuXHR9LFxyXG5cclxuXHRfZ2V0QW5jaG9yOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gWzAsIDBdO1xyXG5cdH1cclxuXHJcbn0pO1xuXG4vKlxyXG4gKiBAY2xhc3MgUG9wdXBcclxuICogQGluaGVyaXRzIERpdk92ZXJsYXlcclxuICogQGFrYSBMLlBvcHVwXHJcbiAqIFVzZWQgdG8gb3BlbiBwb3B1cHMgaW4gY2VydGFpbiBwbGFjZXMgb2YgdGhlIG1hcC4gVXNlIFtNYXAub3BlblBvcHVwXSgjbWFwLW9wZW5wb3B1cCkgdG9cclxuICogb3BlbiBwb3B1cHMgd2hpbGUgbWFraW5nIHN1cmUgdGhhdCBvbmx5IG9uZSBwb3B1cCBpcyBvcGVuIGF0IG9uZSB0aW1lXHJcbiAqIChyZWNvbW1lbmRlZCBmb3IgdXNhYmlsaXR5KSwgb3IgdXNlIFtNYXAuYWRkTGF5ZXJdKCNtYXAtYWRkbGF5ZXIpIHRvIG9wZW4gYXMgbWFueSBhcyB5b3Ugd2FudC5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogSWYgeW91IHdhbnQgdG8ganVzdCBiaW5kIGEgcG9wdXAgdG8gbWFya2VyIGNsaWNrIGFuZCB0aGVuIG9wZW4gaXQsIGl0J3MgcmVhbGx5IGVhc3k6XHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIG1hcmtlci5iaW5kUG9wdXAocG9wdXBDb250ZW50KS5vcGVuUG9wdXAoKTtcclxuICogYGBgXHJcbiAqIFBhdGggb3ZlcmxheXMgbGlrZSBwb2x5bGluZXMgYWxzbyBoYXZlIGEgYGJpbmRQb3B1cGAgbWV0aG9kLlxyXG4gKiBIZXJlJ3MgYSBtb3JlIGNvbXBsaWNhdGVkIHdheSB0byBvcGVuIGEgcG9wdXAgb24gYSBtYXA6XHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHZhciBwb3B1cCA9IEwucG9wdXAoKVxyXG4gKiBcdC5zZXRMYXRMbmcobGF0bG5nKVxyXG4gKiBcdC5zZXRDb250ZW50KCc8cD5IZWxsbyB3b3JsZCE8YnIgLz5UaGlzIGlzIGEgbmljZSBwb3B1cC48L3A+JylcclxuICogXHQub3Blbk9uKG1hcCk7XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcblxyXG4vLyBAbmFtZXNwYWNlIFBvcHVwXHJcbnZhciBQb3B1cCA9IERpdk92ZXJsYXkuZXh0ZW5kKHtcclxuXHJcblx0Ly8gQHNlY3Rpb25cclxuXHQvLyBAYWthIFBvcHVwIG9wdGlvbnNcclxuXHRvcHRpb25zOiB7XHJcblx0XHQvLyBAb3B0aW9uIG1heFdpZHRoOiBOdW1iZXIgPSAzMDBcclxuXHRcdC8vIE1heCB3aWR0aCBvZiB0aGUgcG9wdXAsIGluIHBpeGVscy5cclxuXHRcdG1heFdpZHRoOiAzMDAsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBtaW5XaWR0aDogTnVtYmVyID0gNTBcclxuXHRcdC8vIE1pbiB3aWR0aCBvZiB0aGUgcG9wdXAsIGluIHBpeGVscy5cclxuXHRcdG1pbldpZHRoOiA1MCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIG1heEhlaWdodDogTnVtYmVyID0gbnVsbFxyXG5cdFx0Ly8gSWYgc2V0LCBjcmVhdGVzIGEgc2Nyb2xsYWJsZSBjb250YWluZXIgb2YgdGhlIGdpdmVuIGhlaWdodFxyXG5cdFx0Ly8gaW5zaWRlIGEgcG9wdXAgaWYgaXRzIGNvbnRlbnQgZXhjZWVkcyBpdC5cclxuXHRcdG1heEhlaWdodDogbnVsbCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGF1dG9QYW46IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBTZXQgaXQgdG8gYGZhbHNlYCBpZiB5b3UgZG9uJ3Qgd2FudCB0aGUgbWFwIHRvIGRvIHBhbm5pbmcgYW5pbWF0aW9uXHJcblx0XHQvLyB0byBmaXQgdGhlIG9wZW5lZCBwb3B1cC5cclxuXHRcdGF1dG9QYW46IHRydWUsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhdXRvUGFuUGFkZGluZ1RvcExlZnQ6IFBvaW50ID0gbnVsbFxyXG5cdFx0Ly8gVGhlIG1hcmdpbiBiZXR3ZWVuIHRoZSBwb3B1cCBhbmQgdGhlIHRvcCBsZWZ0IGNvcm5lciBvZiB0aGUgbWFwXHJcblx0XHQvLyB2aWV3IGFmdGVyIGF1dG9wYW5uaW5nIHdhcyBwZXJmb3JtZWQuXHJcblx0XHRhdXRvUGFuUGFkZGluZ1RvcExlZnQ6IG51bGwsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhdXRvUGFuUGFkZGluZ0JvdHRvbVJpZ2h0OiBQb2ludCA9IG51bGxcclxuXHRcdC8vIFRoZSBtYXJnaW4gYmV0d2VlbiB0aGUgcG9wdXAgYW5kIHRoZSBib3R0b20gcmlnaHQgY29ybmVyIG9mIHRoZSBtYXBcclxuXHRcdC8vIHZpZXcgYWZ0ZXIgYXV0b3Bhbm5pbmcgd2FzIHBlcmZvcm1lZC5cclxuXHRcdGF1dG9QYW5QYWRkaW5nQm90dG9tUmlnaHQ6IG51bGwsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhdXRvUGFuUGFkZGluZzogUG9pbnQgPSBQb2ludCg1LCA1KVxyXG5cdFx0Ly8gRXF1aXZhbGVudCBvZiBzZXR0aW5nIGJvdGggdG9wIGxlZnQgYW5kIGJvdHRvbSByaWdodCBhdXRvcGFuIHBhZGRpbmcgdG8gdGhlIHNhbWUgdmFsdWUuXHJcblx0XHRhdXRvUGFuUGFkZGluZzogWzUsIDVdLFxyXG5cclxuXHRcdC8vIEBvcHRpb24ga2VlcEluVmlldzogQm9vbGVhbiA9IGZhbHNlXHJcblx0XHQvLyBTZXQgaXQgdG8gYHRydWVgIGlmIHlvdSB3YW50IHRvIHByZXZlbnQgdXNlcnMgZnJvbSBwYW5uaW5nIHRoZSBwb3B1cFxyXG5cdFx0Ly8gb2ZmIG9mIHRoZSBzY3JlZW4gd2hpbGUgaXQgaXMgb3Blbi5cclxuXHRcdGtlZXBJblZpZXc6IGZhbHNlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gY2xvc2VCdXR0b246IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBDb250cm9scyB0aGUgcHJlc2VuY2Ugb2YgYSBjbG9zZSBidXR0b24gaW4gdGhlIHBvcHVwLlxyXG5cdFx0Y2xvc2VCdXR0b246IHRydWUsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhdXRvQ2xvc2U6IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBTZXQgaXQgdG8gYGZhbHNlYCBpZiB5b3Ugd2FudCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdCBiZWhhdmlvciBvZlxyXG5cdFx0Ly8gdGhlIHBvcHVwIGNsb3Npbmcgd2hlbiBhbm90aGVyIHBvcHVwIGlzIG9wZW5lZC5cclxuXHRcdGF1dG9DbG9zZTogdHJ1ZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGNsb3NlT25Fc2NhcGVLZXk6IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBTZXQgaXQgdG8gYGZhbHNlYCBpZiB5b3Ugd2FudCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdCBiZWhhdmlvciBvZlxyXG5cdFx0Ly8gdGhlIEVTQyBrZXkgZm9yIGNsb3Npbmcgb2YgdGhlIHBvcHVwLlxyXG5cdFx0Y2xvc2VPbkVzY2FwZUtleTogdHJ1ZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGNsb3NlT25DbGljazogQm9vbGVhbiA9ICpcclxuXHRcdC8vIFNldCBpdCBpZiB5b3Ugd2FudCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdCBiZWhhdmlvciBvZiB0aGUgcG9wdXAgY2xvc2luZyB3aGVuIHVzZXIgY2xpY2tzXHJcblx0XHQvLyBvbiB0aGUgbWFwLiBEZWZhdWx0cyB0byB0aGUgbWFwJ3MgW2BjbG9zZVBvcHVwT25DbGlja2BdKCNtYXAtY2xvc2Vwb3B1cG9uY2xpY2spIG9wdGlvbi5cclxuXHJcblx0XHQvLyBAb3B0aW9uIGNsYXNzTmFtZTogU3RyaW5nID0gJydcclxuXHRcdC8vIEEgY3VzdG9tIENTUyBjbGFzcyBuYW1lIHRvIGFzc2lnbiB0byB0aGUgcG9wdXAuXHJcblx0XHRjbGFzc05hbWU6ICcnXHJcblx0fSxcclxuXHJcblx0Ly8gQG5hbWVzcGFjZSBQb3B1cFxyXG5cdC8vIEBtZXRob2Qgb3Blbk9uKG1hcDogTWFwKTogdGhpc1xyXG5cdC8vIEFkZHMgdGhlIHBvcHVwIHRvIHRoZSBtYXAgYW5kIGNsb3NlcyB0aGUgcHJldmlvdXMgb25lLiBUaGUgc2FtZSBhcyBgbWFwLm9wZW5Qb3B1cChwb3B1cClgLlxyXG5cdG9wZW5PbjogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0bWFwLm9wZW5Qb3B1cCh0aGlzKTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdG9uQWRkOiBmdW5jdGlvbiAobWFwKSB7XHJcblx0XHREaXZPdmVybGF5LnByb3RvdHlwZS5vbkFkZC5jYWxsKHRoaXMsIG1hcCk7XHJcblxyXG5cdFx0Ly8gQG5hbWVzcGFjZSBNYXBcclxuXHRcdC8vIEBzZWN0aW9uIFBvcHVwIGV2ZW50c1xyXG5cdFx0Ly8gQGV2ZW50IHBvcHVwb3BlbjogUG9wdXBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiBhIHBvcHVwIGlzIG9wZW5lZCBpbiB0aGUgbWFwXHJcblx0XHRtYXAuZmlyZSgncG9wdXBvcGVuJywge3BvcHVwOiB0aGlzfSk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX3NvdXJjZSkge1xyXG5cdFx0XHQvLyBAbmFtZXNwYWNlIExheWVyXHJcblx0XHRcdC8vIEBzZWN0aW9uIFBvcHVwIGV2ZW50c1xyXG5cdFx0XHQvLyBAZXZlbnQgcG9wdXBvcGVuOiBQb3B1cEV2ZW50XHJcblx0XHRcdC8vIEZpcmVkIHdoZW4gYSBwb3B1cCBib3VuZCB0byB0aGlzIGxheWVyIGlzIG9wZW5lZFxyXG5cdFx0XHR0aGlzLl9zb3VyY2UuZmlyZSgncG9wdXBvcGVuJywge3BvcHVwOiB0aGlzfSwgdHJ1ZSk7XHJcblx0XHRcdC8vIEZvciBub24tcGF0aCBsYXllcnMsIHdlIHRvZ2dsZSB0aGUgcG9wdXAgd2hlbiBjbGlja2luZ1xyXG5cdFx0XHQvLyBhZ2FpbiB0aGUgbGF5ZXIsIHNvIHByZXZlbnQgdGhlIG1hcCB0byByZW9wZW4gaXQuXHJcblx0XHRcdGlmICghKHRoaXMuX3NvdXJjZSBpbnN0YW5jZW9mIFBhdGgpKSB7XHJcblx0XHRcdFx0dGhpcy5fc291cmNlLm9uKCdwcmVjbGljaycsIHN0b3BQcm9wYWdhdGlvbik7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRvblJlbW92ZTogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0RGl2T3ZlcmxheS5wcm90b3R5cGUub25SZW1vdmUuY2FsbCh0aGlzLCBtYXApO1xyXG5cclxuXHRcdC8vIEBuYW1lc3BhY2UgTWFwXHJcblx0XHQvLyBAc2VjdGlvbiBQb3B1cCBldmVudHNcclxuXHRcdC8vIEBldmVudCBwb3B1cGNsb3NlOiBQb3B1cEV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIGEgcG9wdXAgaW4gdGhlIG1hcCBpcyBjbG9zZWRcclxuXHRcdG1hcC5maXJlKCdwb3B1cGNsb3NlJywge3BvcHVwOiB0aGlzfSk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX3NvdXJjZSkge1xyXG5cdFx0XHQvLyBAbmFtZXNwYWNlIExheWVyXHJcblx0XHRcdC8vIEBzZWN0aW9uIFBvcHVwIGV2ZW50c1xyXG5cdFx0XHQvLyBAZXZlbnQgcG9wdXBjbG9zZTogUG9wdXBFdmVudFxyXG5cdFx0XHQvLyBGaXJlZCB3aGVuIGEgcG9wdXAgYm91bmQgdG8gdGhpcyBsYXllciBpcyBjbG9zZWRcclxuXHRcdFx0dGhpcy5fc291cmNlLmZpcmUoJ3BvcHVwY2xvc2UnLCB7cG9wdXA6IHRoaXN9LCB0cnVlKTtcclxuXHRcdFx0aWYgKCEodGhpcy5fc291cmNlIGluc3RhbmNlb2YgUGF0aCkpIHtcclxuXHRcdFx0XHR0aGlzLl9zb3VyY2Uub2ZmKCdwcmVjbGljaycsIHN0b3BQcm9wYWdhdGlvbik7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRnZXRFdmVudHM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBldmVudHMgPSBEaXZPdmVybGF5LnByb3RvdHlwZS5nZXRFdmVudHMuY2FsbCh0aGlzKTtcclxuXHJcblx0XHRpZiAodGhpcy5vcHRpb25zLmNsb3NlT25DbGljayAhPT0gdW5kZWZpbmVkID8gdGhpcy5vcHRpb25zLmNsb3NlT25DbGljayA6IHRoaXMuX21hcC5vcHRpb25zLmNsb3NlUG9wdXBPbkNsaWNrKSB7XHJcblx0XHRcdGV2ZW50cy5wcmVjbGljayA9IHRoaXMuX2Nsb3NlO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICh0aGlzLm9wdGlvbnMua2VlcEluVmlldykge1xyXG5cdFx0XHRldmVudHMubW92ZWVuZCA9IHRoaXMuX2FkanVzdFBhbjtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZXZlbnRzO1xyXG5cdH0sXHJcblxyXG5cdF9jbG9zZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKHRoaXMuX21hcCkge1xyXG5cdFx0XHR0aGlzLl9tYXAuY2xvc2VQb3B1cCh0aGlzKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfaW5pdExheW91dDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIHByZWZpeCA9ICdsZWFmbGV0LXBvcHVwJyxcclxuXHRcdCAgICBjb250YWluZXIgPSB0aGlzLl9jb250YWluZXIgPSBjcmVhdGUkMSgnZGl2JyxcclxuXHRcdFx0cHJlZml4ICsgJyAnICsgKHRoaXMub3B0aW9ucy5jbGFzc05hbWUgfHwgJycpICtcclxuXHRcdFx0JyBsZWFmbGV0LXpvb20tYW5pbWF0ZWQnKTtcclxuXHJcblx0XHR2YXIgd3JhcHBlciA9IHRoaXMuX3dyYXBwZXIgPSBjcmVhdGUkMSgnZGl2JywgcHJlZml4ICsgJy1jb250ZW50LXdyYXBwZXInLCBjb250YWluZXIpO1xyXG5cdFx0dGhpcy5fY29udGVudE5vZGUgPSBjcmVhdGUkMSgnZGl2JywgcHJlZml4ICsgJy1jb250ZW50Jywgd3JhcHBlcik7XHJcblxyXG5cdFx0ZGlzYWJsZUNsaWNrUHJvcGFnYXRpb24od3JhcHBlcik7XHJcblx0XHRkaXNhYmxlU2Nyb2xsUHJvcGFnYXRpb24odGhpcy5fY29udGVudE5vZGUpO1xyXG5cdFx0b24od3JhcHBlciwgJ2NvbnRleHRtZW51Jywgc3RvcFByb3BhZ2F0aW9uKTtcclxuXHJcblx0XHR0aGlzLl90aXBDb250YWluZXIgPSBjcmVhdGUkMSgnZGl2JywgcHJlZml4ICsgJy10aXAtY29udGFpbmVyJywgY29udGFpbmVyKTtcclxuXHRcdHRoaXMuX3RpcCA9IGNyZWF0ZSQxKCdkaXYnLCBwcmVmaXggKyAnLXRpcCcsIHRoaXMuX3RpcENvbnRhaW5lcik7XHJcblxyXG5cdFx0aWYgKHRoaXMub3B0aW9ucy5jbG9zZUJ1dHRvbikge1xyXG5cdFx0XHR2YXIgY2xvc2VCdXR0b24gPSB0aGlzLl9jbG9zZUJ1dHRvbiA9IGNyZWF0ZSQxKCdhJywgcHJlZml4ICsgJy1jbG9zZS1idXR0b24nLCBjb250YWluZXIpO1xyXG5cdFx0XHRjbG9zZUJ1dHRvbi5ocmVmID0gJyNjbG9zZSc7XHJcblx0XHRcdGNsb3NlQnV0dG9uLmlubmVySFRNTCA9ICcmIzIxNTsnO1xyXG5cclxuXHRcdFx0b24oY2xvc2VCdXR0b24sICdjbGljaycsIHRoaXMuX29uQ2xvc2VCdXR0b25DbGljaywgdGhpcyk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X3VwZGF0ZUxheW91dDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGNvbnRhaW5lciA9IHRoaXMuX2NvbnRlbnROb2RlLFxyXG5cdFx0ICAgIHN0eWxlID0gY29udGFpbmVyLnN0eWxlO1xyXG5cclxuXHRcdHN0eWxlLndpZHRoID0gJyc7XHJcblx0XHRzdHlsZS53aGl0ZVNwYWNlID0gJ25vd3JhcCc7XHJcblxyXG5cdFx0dmFyIHdpZHRoID0gY29udGFpbmVyLm9mZnNldFdpZHRoO1xyXG5cdFx0d2lkdGggPSBNYXRoLm1pbih3aWR0aCwgdGhpcy5vcHRpb25zLm1heFdpZHRoKTtcclxuXHRcdHdpZHRoID0gTWF0aC5tYXgod2lkdGgsIHRoaXMub3B0aW9ucy5taW5XaWR0aCk7XHJcblxyXG5cdFx0c3R5bGUud2lkdGggPSAod2lkdGggKyAxKSArICdweCc7XHJcblx0XHRzdHlsZS53aGl0ZVNwYWNlID0gJyc7XHJcblxyXG5cdFx0c3R5bGUuaGVpZ2h0ID0gJyc7XHJcblxyXG5cdFx0dmFyIGhlaWdodCA9IGNvbnRhaW5lci5vZmZzZXRIZWlnaHQsXHJcblx0XHQgICAgbWF4SGVpZ2h0ID0gdGhpcy5vcHRpb25zLm1heEhlaWdodCxcclxuXHRcdCAgICBzY3JvbGxlZENsYXNzID0gJ2xlYWZsZXQtcG9wdXAtc2Nyb2xsZWQnO1xyXG5cclxuXHRcdGlmIChtYXhIZWlnaHQgJiYgaGVpZ2h0ID4gbWF4SGVpZ2h0KSB7XHJcblx0XHRcdHN0eWxlLmhlaWdodCA9IG1heEhlaWdodCArICdweCc7XHJcblx0XHRcdGFkZENsYXNzKGNvbnRhaW5lciwgc2Nyb2xsZWRDbGFzcyk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRyZW1vdmVDbGFzcyhjb250YWluZXIsIHNjcm9sbGVkQ2xhc3MpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2NvbnRhaW5lcldpZHRoID0gdGhpcy5fY29udGFpbmVyLm9mZnNldFdpZHRoO1xyXG5cdH0sXHJcblxyXG5cdF9hbmltYXRlWm9vbTogZnVuY3Rpb24gKGUpIHtcclxuXHRcdHZhciBwb3MgPSB0aGlzLl9tYXAuX2xhdExuZ1RvTmV3TGF5ZXJQb2ludCh0aGlzLl9sYXRsbmcsIGUuem9vbSwgZS5jZW50ZXIpLFxyXG5cdFx0ICAgIGFuY2hvciA9IHRoaXMuX2dldEFuY2hvcigpO1xyXG5cdFx0c2V0UG9zaXRpb24odGhpcy5fY29udGFpbmVyLCBwb3MuYWRkKGFuY2hvcikpO1xyXG5cdH0sXHJcblxyXG5cdF9hZGp1c3RQYW46IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICghdGhpcy5vcHRpb25zLmF1dG9QYW4gfHwgKHRoaXMuX21hcC5fcGFuQW5pbSAmJiB0aGlzLl9tYXAuX3BhbkFuaW0uX2luUHJvZ3Jlc3MpKSB7IHJldHVybjsgfVxyXG5cclxuXHRcdHZhciBtYXAgPSB0aGlzLl9tYXAsXHJcblx0XHQgICAgbWFyZ2luQm90dG9tID0gcGFyc2VJbnQoZ2V0U3R5bGUodGhpcy5fY29udGFpbmVyLCAnbWFyZ2luQm90dG9tJyksIDEwKSB8fCAwLFxyXG5cdFx0ICAgIGNvbnRhaW5lckhlaWdodCA9IHRoaXMuX2NvbnRhaW5lci5vZmZzZXRIZWlnaHQgKyBtYXJnaW5Cb3R0b20sXHJcblx0XHQgICAgY29udGFpbmVyV2lkdGggPSB0aGlzLl9jb250YWluZXJXaWR0aCxcclxuXHRcdCAgICBsYXllclBvcyA9IG5ldyBQb2ludCh0aGlzLl9jb250YWluZXJMZWZ0LCAtY29udGFpbmVySGVpZ2h0IC0gdGhpcy5fY29udGFpbmVyQm90dG9tKTtcclxuXHJcblx0XHRsYXllclBvcy5fYWRkKGdldFBvc2l0aW9uKHRoaXMuX2NvbnRhaW5lcikpO1xyXG5cclxuXHRcdHZhciBjb250YWluZXJQb3MgPSBtYXAubGF5ZXJQb2ludFRvQ29udGFpbmVyUG9pbnQobGF5ZXJQb3MpLFxyXG5cdFx0ICAgIHBhZGRpbmcgPSB0b1BvaW50KHRoaXMub3B0aW9ucy5hdXRvUGFuUGFkZGluZyksXHJcblx0XHQgICAgcGFkZGluZ1RMID0gdG9Qb2ludCh0aGlzLm9wdGlvbnMuYXV0b1BhblBhZGRpbmdUb3BMZWZ0IHx8IHBhZGRpbmcpLFxyXG5cdFx0ICAgIHBhZGRpbmdCUiA9IHRvUG9pbnQodGhpcy5vcHRpb25zLmF1dG9QYW5QYWRkaW5nQm90dG9tUmlnaHQgfHwgcGFkZGluZyksXHJcblx0XHQgICAgc2l6ZSA9IG1hcC5nZXRTaXplKCksXHJcblx0XHQgICAgZHggPSAwLFxyXG5cdFx0ICAgIGR5ID0gMDtcclxuXHJcblx0XHRpZiAoY29udGFpbmVyUG9zLnggKyBjb250YWluZXJXaWR0aCArIHBhZGRpbmdCUi54ID4gc2l6ZS54KSB7IC8vIHJpZ2h0XHJcblx0XHRcdGR4ID0gY29udGFpbmVyUG9zLnggKyBjb250YWluZXJXaWR0aCAtIHNpemUueCArIHBhZGRpbmdCUi54O1xyXG5cdFx0fVxyXG5cdFx0aWYgKGNvbnRhaW5lclBvcy54IC0gZHggLSBwYWRkaW5nVEwueCA8IDApIHsgLy8gbGVmdFxyXG5cdFx0XHRkeCA9IGNvbnRhaW5lclBvcy54IC0gcGFkZGluZ1RMLng7XHJcblx0XHR9XHJcblx0XHRpZiAoY29udGFpbmVyUG9zLnkgKyBjb250YWluZXJIZWlnaHQgKyBwYWRkaW5nQlIueSA+IHNpemUueSkgeyAvLyBib3R0b21cclxuXHRcdFx0ZHkgPSBjb250YWluZXJQb3MueSArIGNvbnRhaW5lckhlaWdodCAtIHNpemUueSArIHBhZGRpbmdCUi55O1xyXG5cdFx0fVxyXG5cdFx0aWYgKGNvbnRhaW5lclBvcy55IC0gZHkgLSBwYWRkaW5nVEwueSA8IDApIHsgLy8gdG9wXHJcblx0XHRcdGR5ID0gY29udGFpbmVyUG9zLnkgLSBwYWRkaW5nVEwueTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBAbmFtZXNwYWNlIE1hcFxyXG5cdFx0Ly8gQHNlY3Rpb24gUG9wdXAgZXZlbnRzXHJcblx0XHQvLyBAZXZlbnQgYXV0b3BhbnN0YXJ0OiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFwIHN0YXJ0cyBhdXRvcGFubmluZyB3aGVuIG9wZW5pbmcgYSBwb3B1cC5cclxuXHRcdGlmIChkeCB8fCBkeSkge1xyXG5cdFx0XHRtYXBcclxuXHRcdFx0ICAgIC5maXJlKCdhdXRvcGFuc3RhcnQnKVxyXG5cdFx0XHQgICAgLnBhbkJ5KFtkeCwgZHldKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfb25DbG9zZUJ1dHRvbkNsaWNrOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0dGhpcy5fY2xvc2UoKTtcclxuXHRcdHN0b3AoZSk7XHJcblx0fSxcclxuXHJcblx0X2dldEFuY2hvcjogZnVuY3Rpb24gKCkge1xyXG5cdFx0Ly8gV2hlcmUgc2hvdWxkIHdlIGFuY2hvciB0aGUgcG9wdXAgb24gdGhlIHNvdXJjZSBsYXllcj9cclxuXHRcdHJldHVybiB0b1BvaW50KHRoaXMuX3NvdXJjZSAmJiB0aGlzLl9zb3VyY2UuX2dldFBvcHVwQW5jaG9yID8gdGhpcy5fc291cmNlLl9nZXRQb3B1cEFuY2hvcigpIDogWzAsIDBdKTtcclxuXHR9XHJcblxyXG59KTtcclxuXHJcbi8vIEBuYW1lc3BhY2UgUG9wdXBcclxuLy8gQGZhY3RvcnkgTC5wb3B1cChvcHRpb25zPzogUG9wdXAgb3B0aW9ucywgc291cmNlPzogTGF5ZXIpXHJcbi8vIEluc3RhbnRpYXRlcyBhIGBQb3B1cGAgb2JqZWN0IGdpdmVuIGFuIG9wdGlvbmFsIGBvcHRpb25zYCBvYmplY3QgdGhhdCBkZXNjcmliZXMgaXRzIGFwcGVhcmFuY2UgYW5kIGxvY2F0aW9uIGFuZCBhbiBvcHRpb25hbCBgc291cmNlYCBvYmplY3QgdGhhdCBpcyB1c2VkIHRvIHRhZyB0aGUgcG9wdXAgd2l0aCBhIHJlZmVyZW5jZSB0byB0aGUgTGF5ZXIgdG8gd2hpY2ggaXQgcmVmZXJzLlxyXG52YXIgcG9wdXAgPSBmdW5jdGlvbiAob3B0aW9ucywgc291cmNlKSB7XHJcblx0cmV0dXJuIG5ldyBQb3B1cChvcHRpb25zLCBzb3VyY2UpO1xyXG59O1xyXG5cclxuXHJcbi8qIEBuYW1lc3BhY2UgTWFwXHJcbiAqIEBzZWN0aW9uIEludGVyYWN0aW9uIE9wdGlvbnNcclxuICogQG9wdGlvbiBjbG9zZVBvcHVwT25DbGljazogQm9vbGVhbiA9IHRydWVcclxuICogU2V0IGl0IHRvIGBmYWxzZWAgaWYgeW91IGRvbid0IHdhbnQgcG9wdXBzIHRvIGNsb3NlIHdoZW4gdXNlciBjbGlja3MgdGhlIG1hcC5cclxuICovXHJcbk1hcC5tZXJnZU9wdGlvbnMoe1xyXG5cdGNsb3NlUG9wdXBPbkNsaWNrOiB0cnVlXHJcbn0pO1xyXG5cclxuXHJcbi8vIEBuYW1lc3BhY2UgTWFwXHJcbi8vIEBzZWN0aW9uIE1ldGhvZHMgZm9yIExheWVycyBhbmQgQ29udHJvbHNcclxuTWFwLmluY2x1ZGUoe1xyXG5cdC8vIEBtZXRob2Qgb3BlblBvcHVwKHBvcHVwOiBQb3B1cCk6IHRoaXNcclxuXHQvLyBPcGVucyB0aGUgc3BlY2lmaWVkIHBvcHVwIHdoaWxlIGNsb3NpbmcgdGhlIHByZXZpb3VzbHkgb3BlbmVkICh0byBtYWtlIHN1cmUgb25seSBvbmUgaXMgb3BlbmVkIGF0IG9uZSB0aW1lIGZvciB1c2FiaWxpdHkpLlxyXG5cdC8vIEBhbHRlcm5hdGl2ZVxyXG5cdC8vIEBtZXRob2Qgb3BlblBvcHVwKGNvbnRlbnQ6IFN0cmluZ3xIVE1MRWxlbWVudCwgbGF0bG5nOiBMYXRMbmcsIG9wdGlvbnM/OiBQb3B1cCBvcHRpb25zKTogdGhpc1xyXG5cdC8vIENyZWF0ZXMgYSBwb3B1cCB3aXRoIHRoZSBzcGVjaWZpZWQgY29udGVudCBhbmQgb3B0aW9ucyBhbmQgb3BlbnMgaXQgaW4gdGhlIGdpdmVuIHBvaW50IG9uIGEgbWFwLlxyXG5cdG9wZW5Qb3B1cDogZnVuY3Rpb24gKHBvcHVwLCBsYXRsbmcsIG9wdGlvbnMpIHtcclxuXHRcdGlmICghKHBvcHVwIGluc3RhbmNlb2YgUG9wdXApKSB7XHJcblx0XHRcdHBvcHVwID0gbmV3IFBvcHVwKG9wdGlvbnMpLnNldENvbnRlbnQocG9wdXApO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChsYXRsbmcpIHtcclxuXHRcdFx0cG9wdXAuc2V0TGF0TG5nKGxhdGxuZyk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKHRoaXMuaGFzTGF5ZXIocG9wdXApKSB7XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICh0aGlzLl9wb3B1cCAmJiB0aGlzLl9wb3B1cC5vcHRpb25zLmF1dG9DbG9zZSkge1xyXG5cdFx0XHR0aGlzLmNsb3NlUG9wdXAoKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9wb3B1cCA9IHBvcHVwO1xyXG5cdFx0cmV0dXJuIHRoaXMuYWRkTGF5ZXIocG9wdXApO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgY2xvc2VQb3B1cChwb3B1cD86IFBvcHVwKTogdGhpc1xyXG5cdC8vIENsb3NlcyB0aGUgcG9wdXAgcHJldmlvdXNseSBvcGVuZWQgd2l0aCBbb3BlblBvcHVwXSgjbWFwLW9wZW5wb3B1cCkgKG9yIHRoZSBnaXZlbiBvbmUpLlxyXG5cdGNsb3NlUG9wdXA6IGZ1bmN0aW9uIChwb3B1cCkge1xyXG5cdFx0aWYgKCFwb3B1cCB8fCBwb3B1cCA9PT0gdGhpcy5fcG9wdXApIHtcclxuXHRcdFx0cG9wdXAgPSB0aGlzLl9wb3B1cDtcclxuXHRcdFx0dGhpcy5fcG9wdXAgPSBudWxsO1xyXG5cdFx0fVxyXG5cdFx0aWYgKHBvcHVwKSB7XHJcblx0XHRcdHRoaXMucmVtb3ZlTGF5ZXIocG9wdXApO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fVxyXG59KTtcclxuXHJcbi8qXHJcbiAqIEBuYW1lc3BhY2UgTGF5ZXJcclxuICogQHNlY3Rpb24gUG9wdXAgbWV0aG9kcyBleGFtcGxlXHJcbiAqXHJcbiAqIEFsbCBsYXllcnMgc2hhcmUgYSBzZXQgb2YgbWV0aG9kcyBjb252ZW5pZW50IGZvciBiaW5kaW5nIHBvcHVwcyB0byBpdC5cclxuICpcclxuICogYGBganNcclxuICogdmFyIGxheWVyID0gTC5Qb2x5Z29uKGxhdGxuZ3MpLmJpbmRQb3B1cCgnSGkgVGhlcmUhJykuYWRkVG8obWFwKTtcclxuICogbGF5ZXIub3BlblBvcHVwKCk7XHJcbiAqIGxheWVyLmNsb3NlUG9wdXAoKTtcclxuICogYGBgXHJcbiAqXHJcbiAqIFBvcHVwcyB3aWxsIGFsc28gYmUgYXV0b21hdGljYWxseSBvcGVuZWQgd2hlbiB0aGUgbGF5ZXIgaXMgY2xpY2tlZCBvbiBhbmQgY2xvc2VkIHdoZW4gdGhlIGxheWVyIGlzIHJlbW92ZWQgZnJvbSB0aGUgbWFwIG9yIGFub3RoZXIgcG9wdXAgaXMgb3BlbmVkLlxyXG4gKi9cclxuXHJcbi8vIEBzZWN0aW9uIFBvcHVwIG1ldGhvZHNcclxuTGF5ZXIuaW5jbHVkZSh7XHJcblxyXG5cdC8vIEBtZXRob2QgYmluZFBvcHVwKGNvbnRlbnQ6IFN0cmluZ3xIVE1MRWxlbWVudHxGdW5jdGlvbnxQb3B1cCwgb3B0aW9ucz86IFBvcHVwIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gQmluZHMgYSBwb3B1cCB0byB0aGUgbGF5ZXIgd2l0aCB0aGUgcGFzc2VkIGBjb250ZW50YCBhbmQgc2V0cyB1cCB0aGVcclxuXHQvLyBuZWNlc3NhcnkgZXZlbnQgbGlzdGVuZXJzLiBJZiBhIGBGdW5jdGlvbmAgaXMgcGFzc2VkIGl0IHdpbGwgcmVjZWl2ZVxyXG5cdC8vIHRoZSBsYXllciBhcyB0aGUgZmlyc3QgYXJndW1lbnQgYW5kIHNob3VsZCByZXR1cm4gYSBgU3RyaW5nYCBvciBgSFRNTEVsZW1lbnRgLlxyXG5cdGJpbmRQb3B1cDogZnVuY3Rpb24gKGNvbnRlbnQsIG9wdGlvbnMpIHtcclxuXHJcblx0XHRpZiAoY29udGVudCBpbnN0YW5jZW9mIFBvcHVwKSB7XHJcblx0XHRcdHNldE9wdGlvbnMoY29udGVudCwgb3B0aW9ucyk7XHJcblx0XHRcdHRoaXMuX3BvcHVwID0gY29udGVudDtcclxuXHRcdFx0Y29udGVudC5fc291cmNlID0gdGhpcztcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGlmICghdGhpcy5fcG9wdXAgfHwgb3B0aW9ucykge1xyXG5cdFx0XHRcdHRoaXMuX3BvcHVwID0gbmV3IFBvcHVwKG9wdGlvbnMsIHRoaXMpO1xyXG5cdFx0XHR9XHJcblx0XHRcdHRoaXMuX3BvcHVwLnNldENvbnRlbnQoY29udGVudCk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCF0aGlzLl9wb3B1cEhhbmRsZXJzQWRkZWQpIHtcclxuXHRcdFx0dGhpcy5vbih7XHJcblx0XHRcdFx0Y2xpY2s6IHRoaXMuX29wZW5Qb3B1cCxcclxuXHRcdFx0XHRrZXlwcmVzczogdGhpcy5fb25LZXlQcmVzcyxcclxuXHRcdFx0XHRyZW1vdmU6IHRoaXMuY2xvc2VQb3B1cCxcclxuXHRcdFx0XHRtb3ZlOiB0aGlzLl9tb3ZlUG9wdXBcclxuXHRcdFx0fSk7XHJcblx0XHRcdHRoaXMuX3BvcHVwSGFuZGxlcnNBZGRlZCA9IHRydWU7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB1bmJpbmRQb3B1cCgpOiB0aGlzXHJcblx0Ly8gUmVtb3ZlcyB0aGUgcG9wdXAgcHJldmlvdXNseSBib3VuZCB3aXRoIGBiaW5kUG9wdXBgLlxyXG5cdHVuYmluZFBvcHVwOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAodGhpcy5fcG9wdXApIHtcclxuXHRcdFx0dGhpcy5vZmYoe1xyXG5cdFx0XHRcdGNsaWNrOiB0aGlzLl9vcGVuUG9wdXAsXHJcblx0XHRcdFx0a2V5cHJlc3M6IHRoaXMuX29uS2V5UHJlc3MsXHJcblx0XHRcdFx0cmVtb3ZlOiB0aGlzLmNsb3NlUG9wdXAsXHJcblx0XHRcdFx0bW92ZTogdGhpcy5fbW92ZVBvcHVwXHJcblx0XHRcdH0pO1xyXG5cdFx0XHR0aGlzLl9wb3B1cEhhbmRsZXJzQWRkZWQgPSBmYWxzZTtcclxuXHRcdFx0dGhpcy5fcG9wdXAgPSBudWxsO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBvcGVuUG9wdXAobGF0bG5nPzogTGF0TG5nKTogdGhpc1xyXG5cdC8vIE9wZW5zIHRoZSBib3VuZCBwb3B1cCBhdCB0aGUgc3BlY2lmaWVkIGBsYXRsbmdgIG9yIGF0IHRoZSBkZWZhdWx0IHBvcHVwIGFuY2hvciBpZiBubyBgbGF0bG5nYCBpcyBwYXNzZWQuXHJcblx0b3BlblBvcHVwOiBmdW5jdGlvbiAobGF5ZXIsIGxhdGxuZykge1xyXG5cdFx0aWYgKCEobGF5ZXIgaW5zdGFuY2VvZiBMYXllcikpIHtcclxuXHRcdFx0bGF0bG5nID0gbGF5ZXI7XHJcblx0XHRcdGxheWVyID0gdGhpcztcclxuXHRcdH1cclxuXHJcblx0XHRpZiAobGF5ZXIgaW5zdGFuY2VvZiBGZWF0dXJlR3JvdXApIHtcclxuXHRcdFx0Zm9yICh2YXIgaWQgaW4gdGhpcy5fbGF5ZXJzKSB7XHJcblx0XHRcdFx0bGF5ZXIgPSB0aGlzLl9sYXllcnNbaWRdO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCFsYXRsbmcpIHtcclxuXHRcdFx0bGF0bG5nID0gbGF5ZXIuZ2V0Q2VudGVyID8gbGF5ZXIuZ2V0Q2VudGVyKCkgOiBsYXllci5nZXRMYXRMbmcoKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAodGhpcy5fcG9wdXAgJiYgdGhpcy5fbWFwKSB7XHJcblx0XHRcdC8vIHNldCBwb3B1cCBzb3VyY2UgdG8gdGhpcyBsYXllclxyXG5cdFx0XHR0aGlzLl9wb3B1cC5fc291cmNlID0gbGF5ZXI7XHJcblxyXG5cdFx0XHQvLyB1cGRhdGUgdGhlIHBvcHVwIChjb250ZW50LCBsYXlvdXQsIGVjdC4uLilcclxuXHRcdFx0dGhpcy5fcG9wdXAudXBkYXRlKCk7XHJcblxyXG5cdFx0XHQvLyBvcGVuIHRoZSBwb3B1cCBvbiB0aGUgbWFwXHJcblx0XHRcdHRoaXMuX21hcC5vcGVuUG9wdXAodGhpcy5fcG9wdXAsIGxhdGxuZyk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBjbG9zZVBvcHVwKCk6IHRoaXNcclxuXHQvLyBDbG9zZXMgdGhlIHBvcHVwIGJvdW5kIHRvIHRoaXMgbGF5ZXIgaWYgaXQgaXMgb3Blbi5cclxuXHRjbG9zZVBvcHVwOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAodGhpcy5fcG9wdXApIHtcclxuXHRcdFx0dGhpcy5fcG9wdXAuX2Nsb3NlKCk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHRvZ2dsZVBvcHVwKCk6IHRoaXNcclxuXHQvLyBPcGVucyBvciBjbG9zZXMgdGhlIHBvcHVwIGJvdW5kIHRvIHRoaXMgbGF5ZXIgZGVwZW5kaW5nIG9uIGl0cyBjdXJyZW50IHN0YXRlLlxyXG5cdHRvZ2dsZVBvcHVwOiBmdW5jdGlvbiAodGFyZ2V0KSB7XHJcblx0XHRpZiAodGhpcy5fcG9wdXApIHtcclxuXHRcdFx0aWYgKHRoaXMuX3BvcHVwLl9tYXApIHtcclxuXHRcdFx0XHR0aGlzLmNsb3NlUG9wdXAoKTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHR0aGlzLm9wZW5Qb3B1cCh0YXJnZXQpO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGlzUG9wdXBPcGVuKCk6IGJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgcG9wdXAgYm91bmQgdG8gdGhpcyBsYXllciBpcyBjdXJyZW50bHkgb3Blbi5cclxuXHRpc1BvcHVwT3BlbjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuICh0aGlzLl9wb3B1cCA/IHRoaXMuX3BvcHVwLmlzT3BlbigpIDogZmFsc2UpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0UG9wdXBDb250ZW50KGNvbnRlbnQ6IFN0cmluZ3xIVE1MRWxlbWVudHxQb3B1cCk6IHRoaXNcclxuXHQvLyBTZXRzIHRoZSBjb250ZW50IG9mIHRoZSBwb3B1cCBib3VuZCB0byB0aGlzIGxheWVyLlxyXG5cdHNldFBvcHVwQ29udGVudDogZnVuY3Rpb24gKGNvbnRlbnQpIHtcclxuXHRcdGlmICh0aGlzLl9wb3B1cCkge1xyXG5cdFx0XHR0aGlzLl9wb3B1cC5zZXRDb250ZW50KGNvbnRlbnQpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRQb3B1cCgpOiBQb3B1cFxyXG5cdC8vIFJldHVybnMgdGhlIHBvcHVwIGJvdW5kIHRvIHRoaXMgbGF5ZXIuXHJcblx0Z2V0UG9wdXA6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9wb3B1cDtcclxuXHR9LFxyXG5cclxuXHRfb3BlblBvcHVwOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0dmFyIGxheWVyID0gZS5sYXllciB8fCBlLnRhcmdldDtcclxuXHJcblx0XHRpZiAoIXRoaXMuX3BvcHVwKSB7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIXRoaXMuX21hcCkge1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gcHJldmVudCBtYXAgY2xpY2tcclxuXHRcdHN0b3AoZSk7XHJcblxyXG5cdFx0Ly8gaWYgdGhpcyBpbmhlcml0cyBmcm9tIFBhdGggaXRzIGEgdmVjdG9yIGFuZCB3ZSBjYW4ganVzdFxyXG5cdFx0Ly8gb3BlbiB0aGUgcG9wdXAgYXQgdGhlIG5ldyBsb2NhdGlvblxyXG5cdFx0aWYgKGxheWVyIGluc3RhbmNlb2YgUGF0aCkge1xyXG5cdFx0XHR0aGlzLm9wZW5Qb3B1cChlLmxheWVyIHx8IGUudGFyZ2V0LCBlLmxhdGxuZyk7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBvdGhlcndpc2UgdHJlYXQgaXQgbGlrZSBhIG1hcmtlciBhbmQgZmlndXJlIG91dFxyXG5cdFx0Ly8gaWYgd2Ugc2hvdWxkIHRvZ2dsZSBpdCBvcGVuL2Nsb3NlZFxyXG5cdFx0aWYgKHRoaXMuX21hcC5oYXNMYXllcih0aGlzLl9wb3B1cCkgJiYgdGhpcy5fcG9wdXAuX3NvdXJjZSA9PT0gbGF5ZXIpIHtcclxuXHRcdFx0dGhpcy5jbG9zZVBvcHVwKCk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR0aGlzLm9wZW5Qb3B1cChsYXllciwgZS5sYXRsbmcpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdF9tb3ZlUG9wdXA6IGZ1bmN0aW9uIChlKSB7XHJcblx0XHR0aGlzLl9wb3B1cC5zZXRMYXRMbmcoZS5sYXRsbmcpO1xyXG5cdH0sXHJcblxyXG5cdF9vbktleVByZXNzOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0aWYgKGUub3JpZ2luYWxFdmVudC5rZXlDb2RlID09PSAxMykge1xyXG5cdFx0XHR0aGlzLl9vcGVuUG9wdXAoZSk7XHJcblx0XHR9XHJcblx0fVxyXG59KTtcblxuLypcbiAqIEBjbGFzcyBUb29sdGlwXG4gKiBAaW5oZXJpdHMgRGl2T3ZlcmxheVxuICogQGFrYSBMLlRvb2x0aXBcbiAqIFVzZWQgdG8gZGlzcGxheSBzbWFsbCB0ZXh0cyBvbiB0b3Agb2YgbWFwIGxheWVycy5cbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIGBgYGpzXG4gKiBtYXJrZXIuYmluZFRvb2x0aXAoXCJteSB0b29sdGlwIHRleHRcIikub3BlblRvb2x0aXAoKTtcbiAqIGBgYFxuICogTm90ZSBhYm91dCB0b29sdGlwIG9mZnNldC4gTGVhZmxldCB0YWtlcyB0d28gb3B0aW9ucyBpbiBjb25zaWRlcmF0aW9uXG4gKiBmb3IgY29tcHV0aW5nIHRvb2x0aXAgb2Zmc2V0dGluZzpcbiAqIC0gdGhlIGBvZmZzZXRgIFRvb2x0aXAgb3B0aW9uOiBpdCBkZWZhdWx0cyB0byBbMCwgMF0sIGFuZCBpdCdzIHNwZWNpZmljIHRvIG9uZSB0b29sdGlwLlxuICogICBBZGQgYSBwb3NpdGl2ZSB4IG9mZnNldCB0byBtb3ZlIHRoZSB0b29sdGlwIHRvIHRoZSByaWdodCwgYW5kIGEgcG9zaXRpdmUgeSBvZmZzZXQgdG9cbiAqICAgbW92ZSBpdCB0byB0aGUgYm90dG9tLiBOZWdhdGl2ZXMgd2lsbCBtb3ZlIHRvIHRoZSBsZWZ0IGFuZCB0b3AuXG4gKiAtIHRoZSBgdG9vbHRpcEFuY2hvcmAgSWNvbiBvcHRpb246IHRoaXMgd2lsbCBvbmx5IGJlIGNvbnNpZGVyZWQgZm9yIE1hcmtlci4gWW91XG4gKiAgIHNob3VsZCBhZGFwdCB0aGlzIHZhbHVlIGlmIHlvdSB1c2UgYSBjdXN0b20gaWNvbi5cbiAqL1xuXG5cbi8vIEBuYW1lc3BhY2UgVG9vbHRpcFxudmFyIFRvb2x0aXAgPSBEaXZPdmVybGF5LmV4dGVuZCh7XG5cblx0Ly8gQHNlY3Rpb25cblx0Ly8gQGFrYSBUb29sdGlwIG9wdGlvbnNcblx0b3B0aW9uczoge1xuXHRcdC8vIEBvcHRpb24gcGFuZTogU3RyaW5nID0gJ3Rvb2x0aXBQYW5lJ1xuXHRcdC8vIGBNYXAgcGFuZWAgd2hlcmUgdGhlIHRvb2x0aXAgd2lsbCBiZSBhZGRlZC5cblx0XHRwYW5lOiAndG9vbHRpcFBhbmUnLFxuXG5cdFx0Ly8gQG9wdGlvbiBvZmZzZXQ6IFBvaW50ID0gUG9pbnQoMCwgMClcblx0XHQvLyBPcHRpb25hbCBvZmZzZXQgb2YgdGhlIHRvb2x0aXAgcG9zaXRpb24uXG5cdFx0b2Zmc2V0OiBbMCwgMF0sXG5cblx0XHQvLyBAb3B0aW9uIGRpcmVjdGlvbjogU3RyaW5nID0gJ2F1dG8nXG5cdFx0Ly8gRGlyZWN0aW9uIHdoZXJlIHRvIG9wZW4gdGhlIHRvb2x0aXAuIFBvc3NpYmxlIHZhbHVlcyBhcmU6IGByaWdodGAsIGBsZWZ0YCxcblx0XHQvLyBgdG9wYCwgYGJvdHRvbWAsIGBjZW50ZXJgLCBgYXV0b2AuXG5cdFx0Ly8gYGF1dG9gIHdpbGwgZHluYW1pY2FsbHkgc3dpdGNoIGJldHdlZW4gYHJpZ2h0YCBhbmQgYGxlZnRgIGFjY29yZGluZyB0byB0aGUgdG9vbHRpcFxuXHRcdC8vIHBvc2l0aW9uIG9uIHRoZSBtYXAuXG5cdFx0ZGlyZWN0aW9uOiAnYXV0bycsXG5cblx0XHQvLyBAb3B0aW9uIHBlcm1hbmVudDogQm9vbGVhbiA9IGZhbHNlXG5cdFx0Ly8gV2hldGhlciB0byBvcGVuIHRoZSB0b29sdGlwIHBlcm1hbmVudGx5IG9yIG9ubHkgb24gbW91c2VvdmVyLlxuXHRcdHBlcm1hbmVudDogZmFsc2UsXG5cblx0XHQvLyBAb3B0aW9uIHN0aWNreTogQm9vbGVhbiA9IGZhbHNlXG5cdFx0Ly8gSWYgdHJ1ZSwgdGhlIHRvb2x0aXAgd2lsbCBmb2xsb3cgdGhlIG1vdXNlIGluc3RlYWQgb2YgYmVpbmcgZml4ZWQgYXQgdGhlIGZlYXR1cmUgY2VudGVyLlxuXHRcdHN0aWNreTogZmFsc2UsXG5cblx0XHQvLyBAb3B0aW9uIGludGVyYWN0aXZlOiBCb29sZWFuID0gZmFsc2Vcblx0XHQvLyBJZiB0cnVlLCB0aGUgdG9vbHRpcCB3aWxsIGxpc3RlbiB0byB0aGUgZmVhdHVyZSBldmVudHMuXG5cdFx0aW50ZXJhY3RpdmU6IGZhbHNlLFxuXG5cdFx0Ly8gQG9wdGlvbiBvcGFjaXR5OiBOdW1iZXIgPSAwLjlcblx0XHQvLyBUb29sdGlwIGNvbnRhaW5lciBvcGFjaXR5LlxuXHRcdG9wYWNpdHk6IDAuOVxuXHR9LFxuXG5cdG9uQWRkOiBmdW5jdGlvbiAobWFwKSB7XG5cdFx0RGl2T3ZlcmxheS5wcm90b3R5cGUub25BZGQuY2FsbCh0aGlzLCBtYXApO1xuXHRcdHRoaXMuc2V0T3BhY2l0eSh0aGlzLm9wdGlvbnMub3BhY2l0eSk7XG5cblx0XHQvLyBAbmFtZXNwYWNlIE1hcFxuXHRcdC8vIEBzZWN0aW9uIFRvb2x0aXAgZXZlbnRzXG5cdFx0Ly8gQGV2ZW50IHRvb2x0aXBvcGVuOiBUb29sdGlwRXZlbnRcblx0XHQvLyBGaXJlZCB3aGVuIGEgdG9vbHRpcCBpcyBvcGVuZWQgaW4gdGhlIG1hcC5cblx0XHRtYXAuZmlyZSgndG9vbHRpcG9wZW4nLCB7dG9vbHRpcDogdGhpc30pO1xuXG5cdFx0aWYgKHRoaXMuX3NvdXJjZSkge1xuXHRcdFx0Ly8gQG5hbWVzcGFjZSBMYXllclxuXHRcdFx0Ly8gQHNlY3Rpb24gVG9vbHRpcCBldmVudHNcblx0XHRcdC8vIEBldmVudCB0b29sdGlwb3BlbjogVG9vbHRpcEV2ZW50XG5cdFx0XHQvLyBGaXJlZCB3aGVuIGEgdG9vbHRpcCBib3VuZCB0byB0aGlzIGxheWVyIGlzIG9wZW5lZC5cblx0XHRcdHRoaXMuX3NvdXJjZS5maXJlKCd0b29sdGlwb3BlbicsIHt0b29sdGlwOiB0aGlzfSwgdHJ1ZSk7XG5cdFx0fVxuXHR9LFxuXG5cdG9uUmVtb3ZlOiBmdW5jdGlvbiAobWFwKSB7XG5cdFx0RGl2T3ZlcmxheS5wcm90b3R5cGUub25SZW1vdmUuY2FsbCh0aGlzLCBtYXApO1xuXG5cdFx0Ly8gQG5hbWVzcGFjZSBNYXBcblx0XHQvLyBAc2VjdGlvbiBUb29sdGlwIGV2ZW50c1xuXHRcdC8vIEBldmVudCB0b29sdGlwY2xvc2U6IFRvb2x0aXBFdmVudFxuXHRcdC8vIEZpcmVkIHdoZW4gYSB0b29sdGlwIGluIHRoZSBtYXAgaXMgY2xvc2VkLlxuXHRcdG1hcC5maXJlKCd0b29sdGlwY2xvc2UnLCB7dG9vbHRpcDogdGhpc30pO1xuXG5cdFx0aWYgKHRoaXMuX3NvdXJjZSkge1xuXHRcdFx0Ly8gQG5hbWVzcGFjZSBMYXllclxuXHRcdFx0Ly8gQHNlY3Rpb24gVG9vbHRpcCBldmVudHNcblx0XHRcdC8vIEBldmVudCB0b29sdGlwY2xvc2U6IFRvb2x0aXBFdmVudFxuXHRcdFx0Ly8gRmlyZWQgd2hlbiBhIHRvb2x0aXAgYm91bmQgdG8gdGhpcyBsYXllciBpcyBjbG9zZWQuXG5cdFx0XHR0aGlzLl9zb3VyY2UuZmlyZSgndG9vbHRpcGNsb3NlJywge3Rvb2x0aXA6IHRoaXN9LCB0cnVlKTtcblx0XHR9XG5cdH0sXG5cblx0Z2V0RXZlbnRzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGV2ZW50cyA9IERpdk92ZXJsYXkucHJvdG90eXBlLmdldEV2ZW50cy5jYWxsKHRoaXMpO1xuXG5cdFx0aWYgKHRvdWNoICYmICF0aGlzLm9wdGlvbnMucGVybWFuZW50KSB7XG5cdFx0XHRldmVudHMucHJlY2xpY2sgPSB0aGlzLl9jbG9zZTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZXZlbnRzO1xuXHR9LFxuXG5cdF9jbG9zZTogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9tYXApIHtcblx0XHRcdHRoaXMuX21hcC5jbG9zZVRvb2x0aXAodGhpcyk7XG5cdFx0fVxuXHR9LFxuXG5cdF9pbml0TGF5b3V0OiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHByZWZpeCA9ICdsZWFmbGV0LXRvb2x0aXAnLFxuXHRcdCAgICBjbGFzc05hbWUgPSBwcmVmaXggKyAnICcgKyAodGhpcy5vcHRpb25zLmNsYXNzTmFtZSB8fCAnJykgKyAnIGxlYWZsZXQtem9vbS0nICsgKHRoaXMuX3pvb21BbmltYXRlZCA/ICdhbmltYXRlZCcgOiAnaGlkZScpO1xuXG5cdFx0dGhpcy5fY29udGVudE5vZGUgPSB0aGlzLl9jb250YWluZXIgPSBjcmVhdGUkMSgnZGl2JywgY2xhc3NOYW1lKTtcblx0fSxcblxuXHRfdXBkYXRlTGF5b3V0OiBmdW5jdGlvbiAoKSB7fSxcblxuXHRfYWRqdXN0UGFuOiBmdW5jdGlvbiAoKSB7fSxcblxuXHRfc2V0UG9zaXRpb246IGZ1bmN0aW9uIChwb3MpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBjb250YWluZXIgPSB0aGlzLl9jb250YWluZXIsXG5cdFx0ICAgIGNlbnRlclBvaW50ID0gbWFwLmxhdExuZ1RvQ29udGFpbmVyUG9pbnQobWFwLmdldENlbnRlcigpKSxcblx0XHQgICAgdG9vbHRpcFBvaW50ID0gbWFwLmxheWVyUG9pbnRUb0NvbnRhaW5lclBvaW50KHBvcyksXG5cdFx0ICAgIGRpcmVjdGlvbiA9IHRoaXMub3B0aW9ucy5kaXJlY3Rpb24sXG5cdFx0ICAgIHRvb2x0aXBXaWR0aCA9IGNvbnRhaW5lci5vZmZzZXRXaWR0aCxcblx0XHQgICAgdG9vbHRpcEhlaWdodCA9IGNvbnRhaW5lci5vZmZzZXRIZWlnaHQsXG5cdFx0ICAgIG9mZnNldCA9IHRvUG9pbnQodGhpcy5vcHRpb25zLm9mZnNldCksXG5cdFx0ICAgIGFuY2hvciA9IHRoaXMuX2dldEFuY2hvcigpO1xuXG5cdFx0aWYgKGRpcmVjdGlvbiA9PT0gJ3RvcCcpIHtcblx0XHRcdHBvcyA9IHBvcy5hZGQodG9Qb2ludCgtdG9vbHRpcFdpZHRoIC8gMiArIG9mZnNldC54LCAtdG9vbHRpcEhlaWdodCArIG9mZnNldC55ICsgYW5jaG9yLnksIHRydWUpKTtcblx0XHR9IGVsc2UgaWYgKGRpcmVjdGlvbiA9PT0gJ2JvdHRvbScpIHtcblx0XHRcdHBvcyA9IHBvcy5zdWJ0cmFjdCh0b1BvaW50KHRvb2x0aXBXaWR0aCAvIDIgLSBvZmZzZXQueCwgLW9mZnNldC55LCB0cnVlKSk7XG5cdFx0fSBlbHNlIGlmIChkaXJlY3Rpb24gPT09ICdjZW50ZXInKSB7XG5cdFx0XHRwb3MgPSBwb3Muc3VidHJhY3QodG9Qb2ludCh0b29sdGlwV2lkdGggLyAyICsgb2Zmc2V0LngsIHRvb2x0aXBIZWlnaHQgLyAyIC0gYW5jaG9yLnkgKyBvZmZzZXQueSwgdHJ1ZSkpO1xuXHRcdH0gZWxzZSBpZiAoZGlyZWN0aW9uID09PSAncmlnaHQnIHx8IGRpcmVjdGlvbiA9PT0gJ2F1dG8nICYmIHRvb2x0aXBQb2ludC54IDwgY2VudGVyUG9pbnQueCkge1xuXHRcdFx0ZGlyZWN0aW9uID0gJ3JpZ2h0Jztcblx0XHRcdHBvcyA9IHBvcy5hZGQodG9Qb2ludChvZmZzZXQueCArIGFuY2hvci54LCBhbmNob3IueSAtIHRvb2x0aXBIZWlnaHQgLyAyICsgb2Zmc2V0LnksIHRydWUpKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZGlyZWN0aW9uID0gJ2xlZnQnO1xuXHRcdFx0cG9zID0gcG9zLnN1YnRyYWN0KHRvUG9pbnQodG9vbHRpcFdpZHRoICsgYW5jaG9yLnggLSBvZmZzZXQueCwgdG9vbHRpcEhlaWdodCAvIDIgLSBhbmNob3IueSAtIG9mZnNldC55LCB0cnVlKSk7XG5cdFx0fVxuXG5cdFx0cmVtb3ZlQ2xhc3MoY29udGFpbmVyLCAnbGVhZmxldC10b29sdGlwLXJpZ2h0Jyk7XG5cdFx0cmVtb3ZlQ2xhc3MoY29udGFpbmVyLCAnbGVhZmxldC10b29sdGlwLWxlZnQnKTtcblx0XHRyZW1vdmVDbGFzcyhjb250YWluZXIsICdsZWFmbGV0LXRvb2x0aXAtdG9wJyk7XG5cdFx0cmVtb3ZlQ2xhc3MoY29udGFpbmVyLCAnbGVhZmxldC10b29sdGlwLWJvdHRvbScpO1xuXHRcdGFkZENsYXNzKGNvbnRhaW5lciwgJ2xlYWZsZXQtdG9vbHRpcC0nICsgZGlyZWN0aW9uKTtcblx0XHRzZXRQb3NpdGlvbihjb250YWluZXIsIHBvcyk7XG5cdH0sXG5cblx0X3VwZGF0ZVBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHBvcyA9IHRoaXMuX21hcC5sYXRMbmdUb0xheWVyUG9pbnQodGhpcy5fbGF0bG5nKTtcblx0XHR0aGlzLl9zZXRQb3NpdGlvbihwb3MpO1xuXHR9LFxuXG5cdHNldE9wYWNpdHk6IGZ1bmN0aW9uIChvcGFjaXR5KSB7XG5cdFx0dGhpcy5vcHRpb25zLm9wYWNpdHkgPSBvcGFjaXR5O1xuXG5cdFx0aWYgKHRoaXMuX2NvbnRhaW5lcikge1xuXHRcdFx0c2V0T3BhY2l0eSh0aGlzLl9jb250YWluZXIsIG9wYWNpdHkpO1xuXHRcdH1cblx0fSxcblxuXHRfYW5pbWF0ZVpvb206IGZ1bmN0aW9uIChlKSB7XG5cdFx0dmFyIHBvcyA9IHRoaXMuX21hcC5fbGF0TG5nVG9OZXdMYXllclBvaW50KHRoaXMuX2xhdGxuZywgZS56b29tLCBlLmNlbnRlcik7XG5cdFx0dGhpcy5fc2V0UG9zaXRpb24ocG9zKTtcblx0fSxcblxuXHRfZ2V0QW5jaG9yOiBmdW5jdGlvbiAoKSB7XG5cdFx0Ly8gV2hlcmUgc2hvdWxkIHdlIGFuY2hvciB0aGUgdG9vbHRpcCBvbiB0aGUgc291cmNlIGxheWVyP1xuXHRcdHJldHVybiB0b1BvaW50KHRoaXMuX3NvdXJjZSAmJiB0aGlzLl9zb3VyY2UuX2dldFRvb2x0aXBBbmNob3IgJiYgIXRoaXMub3B0aW9ucy5zdGlja3kgPyB0aGlzLl9zb3VyY2UuX2dldFRvb2x0aXBBbmNob3IoKSA6IFswLCAwXSk7XG5cdH1cblxufSk7XG5cbi8vIEBuYW1lc3BhY2UgVG9vbHRpcFxuLy8gQGZhY3RvcnkgTC50b29sdGlwKG9wdGlvbnM/OiBUb29sdGlwIG9wdGlvbnMsIHNvdXJjZT86IExheWVyKVxuLy8gSW5zdGFudGlhdGVzIGEgVG9vbHRpcCBvYmplY3QgZ2l2ZW4gYW4gb3B0aW9uYWwgYG9wdGlvbnNgIG9iamVjdCB0aGF0IGRlc2NyaWJlcyBpdHMgYXBwZWFyYW5jZSBhbmQgbG9jYXRpb24gYW5kIGFuIG9wdGlvbmFsIGBzb3VyY2VgIG9iamVjdCB0aGF0IGlzIHVzZWQgdG8gdGFnIHRoZSB0b29sdGlwIHdpdGggYSByZWZlcmVuY2UgdG8gdGhlIExheWVyIHRvIHdoaWNoIGl0IHJlZmVycy5cbnZhciB0b29sdGlwID0gZnVuY3Rpb24gKG9wdGlvbnMsIHNvdXJjZSkge1xuXHRyZXR1cm4gbmV3IFRvb2x0aXAob3B0aW9ucywgc291cmNlKTtcbn07XG5cbi8vIEBuYW1lc3BhY2UgTWFwXG4vLyBAc2VjdGlvbiBNZXRob2RzIGZvciBMYXllcnMgYW5kIENvbnRyb2xzXG5NYXAuaW5jbHVkZSh7XG5cblx0Ly8gQG1ldGhvZCBvcGVuVG9vbHRpcCh0b29sdGlwOiBUb29sdGlwKTogdGhpc1xuXHQvLyBPcGVucyB0aGUgc3BlY2lmaWVkIHRvb2x0aXAuXG5cdC8vIEBhbHRlcm5hdGl2ZVxuXHQvLyBAbWV0aG9kIG9wZW5Ub29sdGlwKGNvbnRlbnQ6IFN0cmluZ3xIVE1MRWxlbWVudCwgbGF0bG5nOiBMYXRMbmcsIG9wdGlvbnM/OiBUb29sdGlwIG9wdGlvbnMpOiB0aGlzXG5cdC8vIENyZWF0ZXMgYSB0b29sdGlwIHdpdGggdGhlIHNwZWNpZmllZCBjb250ZW50IGFuZCBvcHRpb25zIGFuZCBvcGVuIGl0LlxuXHRvcGVuVG9vbHRpcDogZnVuY3Rpb24gKHRvb2x0aXAsIGxhdGxuZywgb3B0aW9ucykge1xuXHRcdGlmICghKHRvb2x0aXAgaW5zdGFuY2VvZiBUb29sdGlwKSkge1xuXHRcdFx0dG9vbHRpcCA9IG5ldyBUb29sdGlwKG9wdGlvbnMpLnNldENvbnRlbnQodG9vbHRpcCk7XG5cdFx0fVxuXG5cdFx0aWYgKGxhdGxuZykge1xuXHRcdFx0dG9vbHRpcC5zZXRMYXRMbmcobGF0bG5nKTtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5oYXNMYXllcih0b29sdGlwKSkge1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuYWRkTGF5ZXIodG9vbHRpcCk7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBjbG9zZVRvb2x0aXAodG9vbHRpcD86IFRvb2x0aXApOiB0aGlzXG5cdC8vIENsb3NlcyB0aGUgdG9vbHRpcCBnaXZlbiBhcyBwYXJhbWV0ZXIuXG5cdGNsb3NlVG9vbHRpcDogZnVuY3Rpb24gKHRvb2x0aXApIHtcblx0XHRpZiAodG9vbHRpcCkge1xuXHRcdFx0dGhpcy5yZW1vdmVMYXllcih0b29sdGlwKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxufSk7XG5cbi8qXG4gKiBAbmFtZXNwYWNlIExheWVyXG4gKiBAc2VjdGlvbiBUb29sdGlwIG1ldGhvZHMgZXhhbXBsZVxuICpcbiAqIEFsbCBsYXllcnMgc2hhcmUgYSBzZXQgb2YgbWV0aG9kcyBjb252ZW5pZW50IGZvciBiaW5kaW5nIHRvb2x0aXBzIHRvIGl0LlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgbGF5ZXIgPSBMLlBvbHlnb24obGF0bG5ncykuYmluZFRvb2x0aXAoJ0hpIFRoZXJlIScpLmFkZFRvKG1hcCk7XG4gKiBsYXllci5vcGVuVG9vbHRpcCgpO1xuICogbGF5ZXIuY2xvc2VUb29sdGlwKCk7XG4gKiBgYGBcbiAqL1xuXG4vLyBAc2VjdGlvbiBUb29sdGlwIG1ldGhvZHNcbkxheWVyLmluY2x1ZGUoe1xuXG5cdC8vIEBtZXRob2QgYmluZFRvb2x0aXAoY29udGVudDogU3RyaW5nfEhUTUxFbGVtZW50fEZ1bmN0aW9ufFRvb2x0aXAsIG9wdGlvbnM/OiBUb29sdGlwIG9wdGlvbnMpOiB0aGlzXG5cdC8vIEJpbmRzIGEgdG9vbHRpcCB0byB0aGUgbGF5ZXIgd2l0aCB0aGUgcGFzc2VkIGBjb250ZW50YCBhbmQgc2V0cyB1cCB0aGVcblx0Ly8gbmVjZXNzYXJ5IGV2ZW50IGxpc3RlbmVycy4gSWYgYSBgRnVuY3Rpb25gIGlzIHBhc3NlZCBpdCB3aWxsIHJlY2VpdmVcblx0Ly8gdGhlIGxheWVyIGFzIHRoZSBmaXJzdCBhcmd1bWVudCBhbmQgc2hvdWxkIHJldHVybiBhIGBTdHJpbmdgIG9yIGBIVE1MRWxlbWVudGAuXG5cdGJpbmRUb29sdGlwOiBmdW5jdGlvbiAoY29udGVudCwgb3B0aW9ucykge1xuXG5cdFx0aWYgKGNvbnRlbnQgaW5zdGFuY2VvZiBUb29sdGlwKSB7XG5cdFx0XHRzZXRPcHRpb25zKGNvbnRlbnQsIG9wdGlvbnMpO1xuXHRcdFx0dGhpcy5fdG9vbHRpcCA9IGNvbnRlbnQ7XG5cdFx0XHRjb250ZW50Ll9zb3VyY2UgPSB0aGlzO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRpZiAoIXRoaXMuX3Rvb2x0aXAgfHwgb3B0aW9ucykge1xuXHRcdFx0XHR0aGlzLl90b29sdGlwID0gbmV3IFRvb2x0aXAob3B0aW9ucywgdGhpcyk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl90b29sdGlwLnNldENvbnRlbnQoY29udGVudCk7XG5cblx0XHR9XG5cblx0XHR0aGlzLl9pbml0VG9vbHRpcEludGVyYWN0aW9ucygpO1xuXG5cdFx0aWYgKHRoaXMuX3Rvb2x0aXAub3B0aW9ucy5wZXJtYW5lbnQgJiYgdGhpcy5fbWFwICYmIHRoaXMuX21hcC5oYXNMYXllcih0aGlzKSkge1xuXHRcdFx0dGhpcy5vcGVuVG9vbHRpcCgpO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgdW5iaW5kVG9vbHRpcCgpOiB0aGlzXG5cdC8vIFJlbW92ZXMgdGhlIHRvb2x0aXAgcHJldmlvdXNseSBib3VuZCB3aXRoIGBiaW5kVG9vbHRpcGAuXG5cdHVuYmluZFRvb2x0aXA6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fdG9vbHRpcCkge1xuXHRcdFx0dGhpcy5faW5pdFRvb2x0aXBJbnRlcmFjdGlvbnModHJ1ZSk7XG5cdFx0XHR0aGlzLmNsb3NlVG9vbHRpcCgpO1xuXHRcdFx0dGhpcy5fdG9vbHRpcCA9IG51bGw7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdF9pbml0VG9vbHRpcEludGVyYWN0aW9uczogZnVuY3Rpb24gKHJlbW92ZSQkMSkge1xuXHRcdGlmICghcmVtb3ZlJCQxICYmIHRoaXMuX3Rvb2x0aXBIYW5kbGVyc0FkZGVkKSB7IHJldHVybjsgfVxuXHRcdHZhciBvbk9mZiA9IHJlbW92ZSQkMSA/ICdvZmYnIDogJ29uJyxcblx0XHQgICAgZXZlbnRzID0ge1xuXHRcdFx0cmVtb3ZlOiB0aGlzLmNsb3NlVG9vbHRpcCxcblx0XHRcdG1vdmU6IHRoaXMuX21vdmVUb29sdGlwXG5cdFx0ICAgIH07XG5cdFx0aWYgKCF0aGlzLl90b29sdGlwLm9wdGlvbnMucGVybWFuZW50KSB7XG5cdFx0XHRldmVudHMubW91c2VvdmVyID0gdGhpcy5fb3BlblRvb2x0aXA7XG5cdFx0XHRldmVudHMubW91c2VvdXQgPSB0aGlzLmNsb3NlVG9vbHRpcDtcblx0XHRcdGlmICh0aGlzLl90b29sdGlwLm9wdGlvbnMuc3RpY2t5KSB7XG5cdFx0XHRcdGV2ZW50cy5tb3VzZW1vdmUgPSB0aGlzLl9tb3ZlVG9vbHRpcDtcblx0XHRcdH1cblx0XHRcdGlmICh0b3VjaCkge1xuXHRcdFx0XHRldmVudHMuY2xpY2sgPSB0aGlzLl9vcGVuVG9vbHRpcDtcblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXHRcdFx0ZXZlbnRzLmFkZCA9IHRoaXMuX29wZW5Ub29sdGlwO1xuXHRcdH1cblx0XHR0aGlzW29uT2ZmXShldmVudHMpO1xuXHRcdHRoaXMuX3Rvb2x0aXBIYW5kbGVyc0FkZGVkID0gIXJlbW92ZSQkMTtcblx0fSxcblxuXHQvLyBAbWV0aG9kIG9wZW5Ub29sdGlwKGxhdGxuZz86IExhdExuZyk6IHRoaXNcblx0Ly8gT3BlbnMgdGhlIGJvdW5kIHRvb2x0aXAgYXQgdGhlIHNwZWNpZmllZCBgbGF0bG5nYCBvciBhdCB0aGUgZGVmYXVsdCB0b29sdGlwIGFuY2hvciBpZiBubyBgbGF0bG5nYCBpcyBwYXNzZWQuXG5cdG9wZW5Ub29sdGlwOiBmdW5jdGlvbiAobGF5ZXIsIGxhdGxuZykge1xuXHRcdGlmICghKGxheWVyIGluc3RhbmNlb2YgTGF5ZXIpKSB7XG5cdFx0XHRsYXRsbmcgPSBsYXllcjtcblx0XHRcdGxheWVyID0gdGhpcztcblx0XHR9XG5cblx0XHRpZiAobGF5ZXIgaW5zdGFuY2VvZiBGZWF0dXJlR3JvdXApIHtcblx0XHRcdGZvciAodmFyIGlkIGluIHRoaXMuX2xheWVycykge1xuXHRcdFx0XHRsYXllciA9IHRoaXMuX2xheWVyc1tpZF07XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICghbGF0bG5nKSB7XG5cdFx0XHRsYXRsbmcgPSBsYXllci5nZXRDZW50ZXIgPyBsYXllci5nZXRDZW50ZXIoKSA6IGxheWVyLmdldExhdExuZygpO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLl90b29sdGlwICYmIHRoaXMuX21hcCkge1xuXG5cdFx0XHQvLyBzZXQgdG9vbHRpcCBzb3VyY2UgdG8gdGhpcyBsYXllclxuXHRcdFx0dGhpcy5fdG9vbHRpcC5fc291cmNlID0gbGF5ZXI7XG5cblx0XHRcdC8vIHVwZGF0ZSB0aGUgdG9vbHRpcCAoY29udGVudCwgbGF5b3V0LCBlY3QuLi4pXG5cdFx0XHR0aGlzLl90b29sdGlwLnVwZGF0ZSgpO1xuXG5cdFx0XHQvLyBvcGVuIHRoZSB0b29sdGlwIG9uIHRoZSBtYXBcblx0XHRcdHRoaXMuX21hcC5vcGVuVG9vbHRpcCh0aGlzLl90b29sdGlwLCBsYXRsbmcpO1xuXG5cdFx0XHQvLyBUb29sdGlwIGNvbnRhaW5lciBtYXkgbm90IGJlIGRlZmluZWQgaWYgbm90IHBlcm1hbmVudCBhbmQgbmV2ZXJcblx0XHRcdC8vIG9wZW5lZC5cblx0XHRcdGlmICh0aGlzLl90b29sdGlwLm9wdGlvbnMuaW50ZXJhY3RpdmUgJiYgdGhpcy5fdG9vbHRpcC5fY29udGFpbmVyKSB7XG5cdFx0XHRcdGFkZENsYXNzKHRoaXMuX3Rvb2x0aXAuX2NvbnRhaW5lciwgJ2xlYWZsZXQtY2xpY2thYmxlJyk7XG5cdFx0XHRcdHRoaXMuYWRkSW50ZXJhY3RpdmVUYXJnZXQodGhpcy5fdG9vbHRpcC5fY29udGFpbmVyKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIGNsb3NlVG9vbHRpcCgpOiB0aGlzXG5cdC8vIENsb3NlcyB0aGUgdG9vbHRpcCBib3VuZCB0byB0aGlzIGxheWVyIGlmIGl0IGlzIG9wZW4uXG5cdGNsb3NlVG9vbHRpcDogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl90b29sdGlwKSB7XG5cdFx0XHR0aGlzLl90b29sdGlwLl9jbG9zZSgpO1xuXHRcdFx0aWYgKHRoaXMuX3Rvb2x0aXAub3B0aW9ucy5pbnRlcmFjdGl2ZSAmJiB0aGlzLl90b29sdGlwLl9jb250YWluZXIpIHtcblx0XHRcdFx0cmVtb3ZlQ2xhc3ModGhpcy5fdG9vbHRpcC5fY29udGFpbmVyLCAnbGVhZmxldC1jbGlja2FibGUnKTtcblx0XHRcdFx0dGhpcy5yZW1vdmVJbnRlcmFjdGl2ZVRhcmdldCh0aGlzLl90b29sdGlwLl9jb250YWluZXIpO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIHRvZ2dsZVRvb2x0aXAoKTogdGhpc1xuXHQvLyBPcGVucyBvciBjbG9zZXMgdGhlIHRvb2x0aXAgYm91bmQgdG8gdGhpcyBsYXllciBkZXBlbmRpbmcgb24gaXRzIGN1cnJlbnQgc3RhdGUuXG5cdHRvZ2dsZVRvb2x0aXA6IGZ1bmN0aW9uICh0YXJnZXQpIHtcblx0XHRpZiAodGhpcy5fdG9vbHRpcCkge1xuXHRcdFx0aWYgKHRoaXMuX3Rvb2x0aXAuX21hcCkge1xuXHRcdFx0XHR0aGlzLmNsb3NlVG9vbHRpcCgpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5vcGVuVG9vbHRpcCh0YXJnZXQpO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIGlzVG9vbHRpcE9wZW4oKTogYm9vbGVhblxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgdG9vbHRpcCBib3VuZCB0byB0aGlzIGxheWVyIGlzIGN1cnJlbnRseSBvcGVuLlxuXHRpc1Rvb2x0aXBPcGVuOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3Rvb2x0aXAuaXNPcGVuKCk7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBzZXRUb29sdGlwQ29udGVudChjb250ZW50OiBTdHJpbmd8SFRNTEVsZW1lbnR8VG9vbHRpcCk6IHRoaXNcblx0Ly8gU2V0cyB0aGUgY29udGVudCBvZiB0aGUgdG9vbHRpcCBib3VuZCB0byB0aGlzIGxheWVyLlxuXHRzZXRUb29sdGlwQ29udGVudDogZnVuY3Rpb24gKGNvbnRlbnQpIHtcblx0XHRpZiAodGhpcy5fdG9vbHRpcCkge1xuXHRcdFx0dGhpcy5fdG9vbHRpcC5zZXRDb250ZW50KGNvbnRlbnQpO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIGdldFRvb2x0aXAoKTogVG9vbHRpcFxuXHQvLyBSZXR1cm5zIHRoZSB0b29sdGlwIGJvdW5kIHRvIHRoaXMgbGF5ZXIuXG5cdGdldFRvb2x0aXA6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fdG9vbHRpcDtcblx0fSxcblxuXHRfb3BlblRvb2x0aXA6IGZ1bmN0aW9uIChlKSB7XG5cdFx0dmFyIGxheWVyID0gZS5sYXllciB8fCBlLnRhcmdldDtcblxuXHRcdGlmICghdGhpcy5fdG9vbHRpcCB8fCAhdGhpcy5fbWFwKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHRoaXMub3BlblRvb2x0aXAobGF5ZXIsIHRoaXMuX3Rvb2x0aXAub3B0aW9ucy5zdGlja3kgPyBlLmxhdGxuZyA6IHVuZGVmaW5lZCk7XG5cdH0sXG5cblx0X21vdmVUb29sdGlwOiBmdW5jdGlvbiAoZSkge1xuXHRcdHZhciBsYXRsbmcgPSBlLmxhdGxuZywgY29udGFpbmVyUG9pbnQsIGxheWVyUG9pbnQ7XG5cdFx0aWYgKHRoaXMuX3Rvb2x0aXAub3B0aW9ucy5zdGlja3kgJiYgZS5vcmlnaW5hbEV2ZW50KSB7XG5cdFx0XHRjb250YWluZXJQb2ludCA9IHRoaXMuX21hcC5tb3VzZUV2ZW50VG9Db250YWluZXJQb2ludChlLm9yaWdpbmFsRXZlbnQpO1xuXHRcdFx0bGF5ZXJQb2ludCA9IHRoaXMuX21hcC5jb250YWluZXJQb2ludFRvTGF5ZXJQb2ludChjb250YWluZXJQb2ludCk7XG5cdFx0XHRsYXRsbmcgPSB0aGlzLl9tYXAubGF5ZXJQb2ludFRvTGF0TG5nKGxheWVyUG9pbnQpO1xuXHRcdH1cblx0XHR0aGlzLl90b29sdGlwLnNldExhdExuZyhsYXRsbmcpO1xuXHR9XG59KTtcblxuLypcbiAqIEBjbGFzcyBEaXZJY29uXG4gKiBAYWthIEwuRGl2SWNvblxuICogQGluaGVyaXRzIEljb25cbiAqXG4gKiBSZXByZXNlbnRzIGEgbGlnaHR3ZWlnaHQgaWNvbiBmb3IgbWFya2VycyB0aGF0IHVzZXMgYSBzaW1wbGUgYDxkaXY+YFxuICogZWxlbWVudCBpbnN0ZWFkIG9mIGFuIGltYWdlLiBJbmhlcml0cyBmcm9tIGBJY29uYCBidXQgaWdub3JlcyB0aGUgYGljb25VcmxgIGFuZCBzaGFkb3cgb3B0aW9ucy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBganNcbiAqIHZhciBteUljb24gPSBMLmRpdkljb24oe2NsYXNzTmFtZTogJ215LWRpdi1pY29uJ30pO1xuICogLy8geW91IGNhbiBzZXQgLm15LWRpdi1pY29uIHN0eWxlcyBpbiBDU1NcbiAqXG4gKiBMLm1hcmtlcihbNTAuNTA1LCAzMC41N10sIHtpY29uOiBteUljb259KS5hZGRUbyhtYXApO1xuICogYGBgXG4gKlxuICogQnkgZGVmYXVsdCwgaXQgaGFzIGEgJ2xlYWZsZXQtZGl2LWljb24nIENTUyBjbGFzcyBhbmQgaXMgc3R5bGVkIGFzIGEgbGl0dGxlIHdoaXRlIHNxdWFyZSB3aXRoIGEgc2hhZG93LlxuICovXG5cbnZhciBEaXZJY29uID0gSWNvbi5leHRlbmQoe1xuXHRvcHRpb25zOiB7XG5cdFx0Ly8gQHNlY3Rpb25cblx0XHQvLyBAYWthIERpdkljb24gb3B0aW9uc1xuXHRcdGljb25TaXplOiBbMTIsIDEyXSwgLy8gYWxzbyBjYW4gYmUgc2V0IHRocm91Z2ggQ1NTXG5cblx0XHQvLyBpY29uQW5jaG9yOiAoUG9pbnQpLFxuXHRcdC8vIHBvcHVwQW5jaG9yOiAoUG9pbnQpLFxuXG5cdFx0Ly8gQG9wdGlvbiBodG1sOiBTdHJpbmcgPSAnJ1xuXHRcdC8vIEN1c3RvbSBIVE1MIGNvZGUgdG8gcHV0IGluc2lkZSB0aGUgZGl2IGVsZW1lbnQsIGVtcHR5IGJ5IGRlZmF1bHQuXG5cdFx0aHRtbDogZmFsc2UsXG5cblx0XHQvLyBAb3B0aW9uIGJnUG9zOiBQb2ludCA9IFswLCAwXVxuXHRcdC8vIE9wdGlvbmFsIHJlbGF0aXZlIHBvc2l0aW9uIG9mIHRoZSBiYWNrZ3JvdW5kLCBpbiBwaXhlbHNcblx0XHRiZ1BvczogbnVsbCxcblxuXHRcdGNsYXNzTmFtZTogJ2xlYWZsZXQtZGl2LWljb24nXG5cdH0sXG5cblx0Y3JlYXRlSWNvbjogZnVuY3Rpb24gKG9sZEljb24pIHtcblx0XHR2YXIgZGl2ID0gKG9sZEljb24gJiYgb2xkSWNvbi50YWdOYW1lID09PSAnRElWJykgPyBvbGRJY29uIDogZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2JyksXG5cdFx0ICAgIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHRkaXYuaW5uZXJIVE1MID0gb3B0aW9ucy5odG1sICE9PSBmYWxzZSA/IG9wdGlvbnMuaHRtbCA6ICcnO1xuXG5cdFx0aWYgKG9wdGlvbnMuYmdQb3MpIHtcblx0XHRcdHZhciBiZ1BvcyA9IHRvUG9pbnQob3B0aW9ucy5iZ1Bvcyk7XG5cdFx0XHRkaXYuc3R5bGUuYmFja2dyb3VuZFBvc2l0aW9uID0gKC1iZ1Bvcy54KSArICdweCAnICsgKC1iZ1Bvcy55KSArICdweCc7XG5cdFx0fVxuXHRcdHRoaXMuX3NldEljb25TdHlsZXMoZGl2LCAnaWNvbicpO1xuXG5cdFx0cmV0dXJuIGRpdjtcblx0fSxcblxuXHRjcmVhdGVTaGFkb3c6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gbnVsbDtcblx0fVxufSk7XG5cbi8vIEBmYWN0b3J5IEwuZGl2SWNvbihvcHRpb25zOiBEaXZJY29uIG9wdGlvbnMpXG4vLyBDcmVhdGVzIGEgYERpdkljb25gIGluc3RhbmNlIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG5mdW5jdGlvbiBkaXZJY29uKG9wdGlvbnMpIHtcblx0cmV0dXJuIG5ldyBEaXZJY29uKG9wdGlvbnMpO1xufVxuXG5JY29uLkRlZmF1bHQgPSBJY29uRGVmYXVsdDtcblxuLypcbiAqIEBjbGFzcyBHcmlkTGF5ZXJcbiAqIEBpbmhlcml0cyBMYXllclxuICogQGFrYSBMLkdyaWRMYXllclxuICpcbiAqIEdlbmVyaWMgY2xhc3MgZm9yIGhhbmRsaW5nIGEgdGlsZWQgZ3JpZCBvZiBIVE1MIGVsZW1lbnRzLiBUaGlzIGlzIHRoZSBiYXNlIGNsYXNzIGZvciBhbGwgdGlsZSBsYXllcnMgYW5kIHJlcGxhY2VzIGBUaWxlTGF5ZXIuQ2FudmFzYC5cbiAqIEdyaWRMYXllciBjYW4gYmUgZXh0ZW5kZWQgdG8gY3JlYXRlIGEgdGlsZWQgZ3JpZCBvZiBIVE1MIGVsZW1lbnRzIGxpa2UgYDxjYW52YXM+YCwgYDxpbWc+YCBvciBgPGRpdj5gLiBHcmlkTGF5ZXIgd2lsbCBoYW5kbGUgY3JlYXRpbmcgYW5kIGFuaW1hdGluZyB0aGVzZSBET00gZWxlbWVudHMgZm9yIHlvdS5cbiAqXG4gKlxuICogQHNlY3Rpb24gU3luY2hyb25vdXMgdXNhZ2VcbiAqIEBleGFtcGxlXG4gKlxuICogVG8gY3JlYXRlIGEgY3VzdG9tIGxheWVyLCBleHRlbmQgR3JpZExheWVyIGFuZCBpbXBsZW1lbnQgdGhlIGBjcmVhdGVUaWxlKClgIG1ldGhvZCwgd2hpY2ggd2lsbCBiZSBwYXNzZWQgYSBgUG9pbnRgIG9iamVjdCB3aXRoIHRoZSBgeGAsIGB5YCwgYW5kIGB6YCAoem9vbSBsZXZlbCkgY29vcmRpbmF0ZXMgdG8gZHJhdyB5b3VyIHRpbGUuXG4gKlxuICogYGBganNcbiAqIHZhciBDYW52YXNMYXllciA9IEwuR3JpZExheWVyLmV4dGVuZCh7XG4gKiAgICAgY3JlYXRlVGlsZTogZnVuY3Rpb24oY29vcmRzKXtcbiAqICAgICAgICAgLy8gY3JlYXRlIGEgPGNhbnZhcz4gZWxlbWVudCBmb3IgZHJhd2luZ1xuICogICAgICAgICB2YXIgdGlsZSA9IEwuRG9tVXRpbC5jcmVhdGUoJ2NhbnZhcycsICdsZWFmbGV0LXRpbGUnKTtcbiAqXG4gKiAgICAgICAgIC8vIHNldHVwIHRpbGUgd2lkdGggYW5kIGhlaWdodCBhY2NvcmRpbmcgdG8gdGhlIG9wdGlvbnNcbiAqICAgICAgICAgdmFyIHNpemUgPSB0aGlzLmdldFRpbGVTaXplKCk7XG4gKiAgICAgICAgIHRpbGUud2lkdGggPSBzaXplLng7XG4gKiAgICAgICAgIHRpbGUuaGVpZ2h0ID0gc2l6ZS55O1xuICpcbiAqICAgICAgICAgLy8gZ2V0IGEgY2FudmFzIGNvbnRleHQgYW5kIGRyYXcgc29tZXRoaW5nIG9uIGl0IHVzaW5nIGNvb3Jkcy54LCBjb29yZHMueSBhbmQgY29vcmRzLnpcbiAqICAgICAgICAgdmFyIGN0eCA9IHRpbGUuZ2V0Q29udGV4dCgnMmQnKTtcbiAqXG4gKiAgICAgICAgIC8vIHJldHVybiB0aGUgdGlsZSBzbyBpdCBjYW4gYmUgcmVuZGVyZWQgb24gc2NyZWVuXG4gKiAgICAgICAgIHJldHVybiB0aWxlO1xuICogICAgIH1cbiAqIH0pO1xuICogYGBgXG4gKlxuICogQHNlY3Rpb24gQXN5bmNocm9ub3VzIHVzYWdlXG4gKiBAZXhhbXBsZVxuICpcbiAqIFRpbGUgY3JlYXRpb24gY2FuIGFsc28gYmUgYXN5bmNocm9ub3VzLCB0aGlzIGlzIHVzZWZ1bCB3aGVuIHVzaW5nIGEgdGhpcmQtcGFydHkgZHJhd2luZyBsaWJyYXJ5LiBPbmNlIHRoZSB0aWxlIGlzIGZpbmlzaGVkIGRyYXdpbmcgaXQgY2FuIGJlIHBhc3NlZCB0byB0aGUgYGRvbmUoKWAgY2FsbGJhY2suXG4gKlxuICogYGBganNcbiAqIHZhciBDYW52YXNMYXllciA9IEwuR3JpZExheWVyLmV4dGVuZCh7XG4gKiAgICAgY3JlYXRlVGlsZTogZnVuY3Rpb24oY29vcmRzLCBkb25lKXtcbiAqICAgICAgICAgdmFyIGVycm9yO1xuICpcbiAqICAgICAgICAgLy8gY3JlYXRlIGEgPGNhbnZhcz4gZWxlbWVudCBmb3IgZHJhd2luZ1xuICogICAgICAgICB2YXIgdGlsZSA9IEwuRG9tVXRpbC5jcmVhdGUoJ2NhbnZhcycsICdsZWFmbGV0LXRpbGUnKTtcbiAqXG4gKiAgICAgICAgIC8vIHNldHVwIHRpbGUgd2lkdGggYW5kIGhlaWdodCBhY2NvcmRpbmcgdG8gdGhlIG9wdGlvbnNcbiAqICAgICAgICAgdmFyIHNpemUgPSB0aGlzLmdldFRpbGVTaXplKCk7XG4gKiAgICAgICAgIHRpbGUud2lkdGggPSBzaXplLng7XG4gKiAgICAgICAgIHRpbGUuaGVpZ2h0ID0gc2l6ZS55O1xuICpcbiAqICAgICAgICAgLy8gZHJhdyBzb21ldGhpbmcgYXN5bmNocm9ub3VzbHkgYW5kIHBhc3MgdGhlIHRpbGUgdG8gdGhlIGRvbmUoKSBjYWxsYmFja1xuICogICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICogICAgICAgICAgICAgZG9uZShlcnJvciwgdGlsZSk7XG4gKiAgICAgICAgIH0sIDEwMDApO1xuICpcbiAqICAgICAgICAgcmV0dXJuIHRpbGU7XG4gKiAgICAgfVxuICogfSk7XG4gKiBgYGBcbiAqXG4gKiBAc2VjdGlvblxuICovXG5cblxudmFyIEdyaWRMYXllciA9IExheWVyLmV4dGVuZCh7XG5cblx0Ly8gQHNlY3Rpb25cblx0Ly8gQGFrYSBHcmlkTGF5ZXIgb3B0aW9uc1xuXHRvcHRpb25zOiB7XG5cdFx0Ly8gQG9wdGlvbiB0aWxlU2l6ZTogTnVtYmVyfFBvaW50ID0gMjU2XG5cdFx0Ly8gV2lkdGggYW5kIGhlaWdodCBvZiB0aWxlcyBpbiB0aGUgZ3JpZC4gVXNlIGEgbnVtYmVyIGlmIHdpZHRoIGFuZCBoZWlnaHQgYXJlIGVxdWFsLCBvciBgTC5wb2ludCh3aWR0aCwgaGVpZ2h0KWAgb3RoZXJ3aXNlLlxuXHRcdHRpbGVTaXplOiAyNTYsXG5cblx0XHQvLyBAb3B0aW9uIG9wYWNpdHk6IE51bWJlciA9IDEuMFxuXHRcdC8vIE9wYWNpdHkgb2YgdGhlIHRpbGVzLiBDYW4gYmUgdXNlZCBpbiB0aGUgYGNyZWF0ZVRpbGUoKWAgZnVuY3Rpb24uXG5cdFx0b3BhY2l0eTogMSxcblxuXHRcdC8vIEBvcHRpb24gdXBkYXRlV2hlbklkbGU6IEJvb2xlYW4gPSAoZGVwZW5kcylcblx0XHQvLyBMb2FkIG5ldyB0aWxlcyBvbmx5IHdoZW4gcGFubmluZyBlbmRzLlxuXHRcdC8vIGB0cnVlYCBieSBkZWZhdWx0IG9uIG1vYmlsZSBicm93c2VycywgaW4gb3JkZXIgdG8gYXZvaWQgdG9vIG1hbnkgcmVxdWVzdHMgYW5kIGtlZXAgc21vb3RoIG5hdmlnYXRpb24uXG5cdFx0Ly8gYGZhbHNlYCBvdGhlcndpc2UgaW4gb3JkZXIgdG8gZGlzcGxheSBuZXcgdGlsZXMgX2R1cmluZ18gcGFubmluZywgc2luY2UgaXQgaXMgZWFzeSB0byBwYW4gb3V0c2lkZSB0aGVcblx0XHQvLyBbYGtlZXBCdWZmZXJgXSgjZ3JpZGxheWVyLWtlZXBidWZmZXIpIG9wdGlvbiBpbiBkZXNrdG9wIGJyb3dzZXJzLlxuXHRcdHVwZGF0ZVdoZW5JZGxlOiBtb2JpbGUsXG5cblx0XHQvLyBAb3B0aW9uIHVwZGF0ZVdoZW5ab29taW5nOiBCb29sZWFuID0gdHJ1ZVxuXHRcdC8vIEJ5IGRlZmF1bHQsIGEgc21vb3RoIHpvb20gYW5pbWF0aW9uIChkdXJpbmcgYSBbdG91Y2ggem9vbV0oI21hcC10b3VjaHpvb20pIG9yIGEgW2BmbHlUbygpYF0oI21hcC1mbHl0bykpIHdpbGwgdXBkYXRlIGdyaWQgbGF5ZXJzIGV2ZXJ5IGludGVnZXIgem9vbSBsZXZlbC4gU2V0dGluZyB0aGlzIG9wdGlvbiB0byBgZmFsc2VgIHdpbGwgdXBkYXRlIHRoZSBncmlkIGxheWVyIG9ubHkgd2hlbiB0aGUgc21vb3RoIGFuaW1hdGlvbiBlbmRzLlxuXHRcdHVwZGF0ZVdoZW5ab29taW5nOiB0cnVlLFxuXG5cdFx0Ly8gQG9wdGlvbiB1cGRhdGVJbnRlcnZhbDogTnVtYmVyID0gMjAwXG5cdFx0Ly8gVGlsZXMgd2lsbCBub3QgdXBkYXRlIG1vcmUgdGhhbiBvbmNlIGV2ZXJ5IGB1cGRhdGVJbnRlcnZhbGAgbWlsbGlzZWNvbmRzIHdoZW4gcGFubmluZy5cblx0XHR1cGRhdGVJbnRlcnZhbDogMjAwLFxuXG5cdFx0Ly8gQG9wdGlvbiB6SW5kZXg6IE51bWJlciA9IDFcblx0XHQvLyBUaGUgZXhwbGljaXQgekluZGV4IG9mIHRoZSB0aWxlIGxheWVyLlxuXHRcdHpJbmRleDogMSxcblxuXHRcdC8vIEBvcHRpb24gYm91bmRzOiBMYXRMbmdCb3VuZHMgPSB1bmRlZmluZWRcblx0XHQvLyBJZiBzZXQsIHRpbGVzIHdpbGwgb25seSBiZSBsb2FkZWQgaW5zaWRlIHRoZSBzZXQgYExhdExuZ0JvdW5kc2AuXG5cdFx0Ym91bmRzOiBudWxsLFxuXG5cdFx0Ly8gQG9wdGlvbiBtaW5ab29tOiBOdW1iZXIgPSAwXG5cdFx0Ly8gVGhlIG1pbmltdW0gem9vbSBsZXZlbCBkb3duIHRvIHdoaWNoIHRoaXMgbGF5ZXIgd2lsbCBiZSBkaXNwbGF5ZWQgKGluY2x1c2l2ZSkuXG5cdFx0bWluWm9vbTogMCxcblxuXHRcdC8vIEBvcHRpb24gbWF4Wm9vbTogTnVtYmVyID0gdW5kZWZpbmVkXG5cdFx0Ly8gVGhlIG1heGltdW0gem9vbSBsZXZlbCB1cCB0byB3aGljaCB0aGlzIGxheWVyIHdpbGwgYmUgZGlzcGxheWVkIChpbmNsdXNpdmUpLlxuXHRcdG1heFpvb206IHVuZGVmaW5lZCxcblxuXHRcdC8vIEBvcHRpb24gbWF4TmF0aXZlWm9vbTogTnVtYmVyID0gdW5kZWZpbmVkXG5cdFx0Ly8gTWF4aW11bSB6b29tIG51bWJlciB0aGUgdGlsZSBzb3VyY2UgaGFzIGF2YWlsYWJsZS4gSWYgaXQgaXMgc3BlY2lmaWVkLFxuXHRcdC8vIHRoZSB0aWxlcyBvbiBhbGwgem9vbSBsZXZlbHMgaGlnaGVyIHRoYW4gYG1heE5hdGl2ZVpvb21gIHdpbGwgYmUgbG9hZGVkXG5cdFx0Ly8gZnJvbSBgbWF4TmF0aXZlWm9vbWAgbGV2ZWwgYW5kIGF1dG8tc2NhbGVkLlxuXHRcdG1heE5hdGl2ZVpvb206IHVuZGVmaW5lZCxcblxuXHRcdC8vIEBvcHRpb24gbWluTmF0aXZlWm9vbTogTnVtYmVyID0gdW5kZWZpbmVkXG5cdFx0Ly8gTWluaW11bSB6b29tIG51bWJlciB0aGUgdGlsZSBzb3VyY2UgaGFzIGF2YWlsYWJsZS4gSWYgaXQgaXMgc3BlY2lmaWVkLFxuXHRcdC8vIHRoZSB0aWxlcyBvbiBhbGwgem9vbSBsZXZlbHMgbG93ZXIgdGhhbiBgbWluTmF0aXZlWm9vbWAgd2lsbCBiZSBsb2FkZWRcblx0XHQvLyBmcm9tIGBtaW5OYXRpdmVab29tYCBsZXZlbCBhbmQgYXV0by1zY2FsZWQuXG5cdFx0bWluTmF0aXZlWm9vbTogdW5kZWZpbmVkLFxuXG5cdFx0Ly8gQG9wdGlvbiBub1dyYXA6IEJvb2xlYW4gPSBmYWxzZVxuXHRcdC8vIFdoZXRoZXIgdGhlIGxheWVyIGlzIHdyYXBwZWQgYXJvdW5kIHRoZSBhbnRpbWVyaWRpYW4uIElmIGB0cnVlYCwgdGhlXG5cdFx0Ly8gR3JpZExheWVyIHdpbGwgb25seSBiZSBkaXNwbGF5ZWQgb25jZSBhdCBsb3cgem9vbSBsZXZlbHMuIEhhcyBub1xuXHRcdC8vIGVmZmVjdCB3aGVuIHRoZSBbbWFwIENSU10oI21hcC1jcnMpIGRvZXNuJ3Qgd3JhcCBhcm91bmQuIENhbiBiZSB1c2VkXG5cdFx0Ly8gaW4gY29tYmluYXRpb24gd2l0aCBbYGJvdW5kc2BdKCNncmlkbGF5ZXItYm91bmRzKSB0byBwcmV2ZW50IHJlcXVlc3Rpbmdcblx0XHQvLyB0aWxlcyBvdXRzaWRlIHRoZSBDUlMgbGltaXRzLlxuXHRcdG5vV3JhcDogZmFsc2UsXG5cblx0XHQvLyBAb3B0aW9uIHBhbmU6IFN0cmluZyA9ICd0aWxlUGFuZSdcblx0XHQvLyBgTWFwIHBhbmVgIHdoZXJlIHRoZSBncmlkIGxheWVyIHdpbGwgYmUgYWRkZWQuXG5cdFx0cGFuZTogJ3RpbGVQYW5lJyxcblxuXHRcdC8vIEBvcHRpb24gY2xhc3NOYW1lOiBTdHJpbmcgPSAnJ1xuXHRcdC8vIEEgY3VzdG9tIGNsYXNzIG5hbWUgdG8gYXNzaWduIHRvIHRoZSB0aWxlIGxheWVyLiBFbXB0eSBieSBkZWZhdWx0LlxuXHRcdGNsYXNzTmFtZTogJycsXG5cblx0XHQvLyBAb3B0aW9uIGtlZXBCdWZmZXI6IE51bWJlciA9IDJcblx0XHQvLyBXaGVuIHBhbm5pbmcgdGhlIG1hcCwga2VlcCB0aGlzIG1hbnkgcm93cyBhbmQgY29sdW1ucyBvZiB0aWxlcyBiZWZvcmUgdW5sb2FkaW5nIHRoZW0uXG5cdFx0a2VlcEJ1ZmZlcjogMlxuXHR9LFxuXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG5cdFx0c2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcblx0fSxcblxuXHRvbkFkZDogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX2luaXRDb250YWluZXIoKTtcblxuXHRcdHRoaXMuX2xldmVscyA9IHt9O1xuXHRcdHRoaXMuX3RpbGVzID0ge307XG5cblx0XHR0aGlzLl9yZXNldFZpZXcoKTtcblx0XHR0aGlzLl91cGRhdGUoKTtcblx0fSxcblxuXHRiZWZvcmVBZGQ6IGZ1bmN0aW9uIChtYXApIHtcblx0XHRtYXAuX2FkZFpvb21MaW1pdCh0aGlzKTtcblx0fSxcblxuXHRvblJlbW92ZTogZnVuY3Rpb24gKG1hcCkge1xuXHRcdHRoaXMuX3JlbW92ZUFsbFRpbGVzKCk7XG5cdFx0cmVtb3ZlKHRoaXMuX2NvbnRhaW5lcik7XG5cdFx0bWFwLl9yZW1vdmVab29tTGltaXQodGhpcyk7XG5cdFx0dGhpcy5fY29udGFpbmVyID0gbnVsbDtcblx0XHR0aGlzLl90aWxlWm9vbSA9IHVuZGVmaW5lZDtcblx0fSxcblxuXHQvLyBAbWV0aG9kIGJyaW5nVG9Gcm9udDogdGhpc1xuXHQvLyBCcmluZ3MgdGhlIHRpbGUgbGF5ZXIgdG8gdGhlIHRvcCBvZiBhbGwgdGlsZSBsYXllcnMuXG5cdGJyaW5nVG9Gcm9udDogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9tYXApIHtcblx0XHRcdHRvRnJvbnQodGhpcy5fY29udGFpbmVyKTtcblx0XHRcdHRoaXMuX3NldEF1dG9aSW5kZXgoTWF0aC5tYXgpO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIGJyaW5nVG9CYWNrOiB0aGlzXG5cdC8vIEJyaW5ncyB0aGUgdGlsZSBsYXllciB0byB0aGUgYm90dG9tIG9mIGFsbCB0aWxlIGxheWVycy5cblx0YnJpbmdUb0JhY2s6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fbWFwKSB7XG5cdFx0XHR0b0JhY2sodGhpcy5fY29udGFpbmVyKTtcblx0XHRcdHRoaXMuX3NldEF1dG9aSW5kZXgoTWF0aC5taW4pO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIGdldENvbnRhaW5lcjogSFRNTEVsZW1lbnRcblx0Ly8gUmV0dXJucyB0aGUgSFRNTCBlbGVtZW50IHRoYXQgY29udGFpbnMgdGhlIHRpbGVzIGZvciB0aGlzIGxheWVyLlxuXHRnZXRDb250YWluZXI6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fY29udGFpbmVyO1xuXHR9LFxuXG5cdC8vIEBtZXRob2Qgc2V0T3BhY2l0eShvcGFjaXR5OiBOdW1iZXIpOiB0aGlzXG5cdC8vIENoYW5nZXMgdGhlIFtvcGFjaXR5XSgjZ3JpZGxheWVyLW9wYWNpdHkpIG9mIHRoZSBncmlkIGxheWVyLlxuXHRzZXRPcGFjaXR5OiBmdW5jdGlvbiAob3BhY2l0eSkge1xuXHRcdHRoaXMub3B0aW9ucy5vcGFjaXR5ID0gb3BhY2l0eTtcblx0XHR0aGlzLl91cGRhdGVPcGFjaXR5KCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBzZXRaSW5kZXgoekluZGV4OiBOdW1iZXIpOiB0aGlzXG5cdC8vIENoYW5nZXMgdGhlIFt6SW5kZXhdKCNncmlkbGF5ZXItemluZGV4KSBvZiB0aGUgZ3JpZCBsYXllci5cblx0c2V0WkluZGV4OiBmdW5jdGlvbiAoekluZGV4KSB7XG5cdFx0dGhpcy5vcHRpb25zLnpJbmRleCA9IHpJbmRleDtcblx0XHR0aGlzLl91cGRhdGVaSW5kZXgoKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgaXNMb2FkaW5nOiBCb29sZWFuXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIGFueSB0aWxlIGluIHRoZSBncmlkIGxheWVyIGhhcyBub3QgZmluaXNoZWQgbG9hZGluZy5cblx0aXNMb2FkaW5nOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2xvYWRpbmc7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCByZWRyYXc6IHRoaXNcblx0Ly8gQ2F1c2VzIHRoZSBsYXllciB0byBjbGVhciBhbGwgdGhlIHRpbGVzIGFuZCByZXF1ZXN0IHRoZW0gYWdhaW4uXG5cdHJlZHJhdzogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9tYXApIHtcblx0XHRcdHRoaXMuX3JlbW92ZUFsbFRpbGVzKCk7XG5cdFx0XHR0aGlzLl91cGRhdGUoKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Z2V0RXZlbnRzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGV2ZW50cyA9IHtcblx0XHRcdHZpZXdwcmVyZXNldDogdGhpcy5faW52YWxpZGF0ZUFsbCxcblx0XHRcdHZpZXdyZXNldDogdGhpcy5fcmVzZXRWaWV3LFxuXHRcdFx0em9vbTogdGhpcy5fcmVzZXRWaWV3LFxuXHRcdFx0bW92ZWVuZDogdGhpcy5fb25Nb3ZlRW5kXG5cdFx0fTtcblxuXHRcdGlmICghdGhpcy5vcHRpb25zLnVwZGF0ZVdoZW5JZGxlKSB7XG5cdFx0XHQvLyB1cGRhdGUgdGlsZXMgb24gbW92ZSwgYnV0IG5vdCBtb3JlIG9mdGVuIHRoYW4gb25jZSBwZXIgZ2l2ZW4gaW50ZXJ2YWxcblx0XHRcdGlmICghdGhpcy5fb25Nb3ZlKSB7XG5cdFx0XHRcdHRoaXMuX29uTW92ZSA9IHRocm90dGxlKHRoaXMuX29uTW92ZUVuZCwgdGhpcy5vcHRpb25zLnVwZGF0ZUludGVydmFsLCB0aGlzKTtcblx0XHRcdH1cblxuXHRcdFx0ZXZlbnRzLm1vdmUgPSB0aGlzLl9vbk1vdmU7XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuX3pvb21BbmltYXRlZCkge1xuXHRcdFx0ZXZlbnRzLnpvb21hbmltID0gdGhpcy5fYW5pbWF0ZVpvb207XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGV2ZW50cztcblx0fSxcblxuXHQvLyBAc2VjdGlvbiBFeHRlbnNpb24gbWV0aG9kc1xuXHQvLyBMYXllcnMgZXh0ZW5kaW5nIGBHcmlkTGF5ZXJgIHNoYWxsIHJlaW1wbGVtZW50IHRoZSBmb2xsb3dpbmcgbWV0aG9kLlxuXHQvLyBAbWV0aG9kIGNyZWF0ZVRpbGUoY29vcmRzOiBPYmplY3QsIGRvbmU/OiBGdW5jdGlvbik6IEhUTUxFbGVtZW50XG5cdC8vIENhbGxlZCBvbmx5IGludGVybmFsbHksIG11c3QgYmUgb3ZlcnJpZGRlbiBieSBjbGFzc2VzIGV4dGVuZGluZyBgR3JpZExheWVyYC5cblx0Ly8gUmV0dXJucyB0aGUgYEhUTUxFbGVtZW50YCBjb3JyZXNwb25kaW5nIHRvIHRoZSBnaXZlbiBgY29vcmRzYC4gSWYgdGhlIGBkb25lYCBjYWxsYmFja1xuXHQvLyBpcyBzcGVjaWZpZWQsIGl0IG11c3QgYmUgY2FsbGVkIHdoZW4gdGhlIHRpbGUgaGFzIGZpbmlzaGVkIGxvYWRpbmcgYW5kIGRyYXdpbmcuXG5cdGNyZWF0ZVRpbGU6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG5cdH0sXG5cblx0Ly8gQHNlY3Rpb25cblx0Ly8gQG1ldGhvZCBnZXRUaWxlU2l6ZTogUG9pbnRcblx0Ly8gTm9ybWFsaXplcyB0aGUgW3RpbGVTaXplIG9wdGlvbl0oI2dyaWRsYXllci10aWxlc2l6ZSkgaW50byBhIHBvaW50LiBVc2VkIGJ5IHRoZSBgY3JlYXRlVGlsZSgpYCBtZXRob2QuXG5cdGdldFRpbGVTaXplOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHMgPSB0aGlzLm9wdGlvbnMudGlsZVNpemU7XG5cdFx0cmV0dXJuIHMgaW5zdGFuY2VvZiBQb2ludCA/IHMgOiBuZXcgUG9pbnQocywgcyk7XG5cdH0sXG5cblx0X3VwZGF0ZVpJbmRleDogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9jb250YWluZXIgJiYgdGhpcy5vcHRpb25zLnpJbmRleCAhPT0gdW5kZWZpbmVkICYmIHRoaXMub3B0aW9ucy56SW5kZXggIT09IG51bGwpIHtcblx0XHRcdHRoaXMuX2NvbnRhaW5lci5zdHlsZS56SW5kZXggPSB0aGlzLm9wdGlvbnMuekluZGV4O1xuXHRcdH1cblx0fSxcblxuXHRfc2V0QXV0b1pJbmRleDogZnVuY3Rpb24gKGNvbXBhcmUpIHtcblx0XHQvLyBnbyB0aHJvdWdoIGFsbCBvdGhlciBsYXllcnMgb2YgdGhlIHNhbWUgcGFuZSwgc2V0IHpJbmRleCB0byBtYXggKyAxIChmcm9udCkgb3IgbWluIC0gMSAoYmFjaylcblxuXHRcdHZhciBsYXllcnMgPSB0aGlzLmdldFBhbmUoKS5jaGlsZHJlbixcblx0XHQgICAgZWRnZVpJbmRleCA9IC1jb21wYXJlKC1JbmZpbml0eSwgSW5maW5pdHkpOyAvLyAtSW5maW5pdHkgZm9yIG1heCwgSW5maW5pdHkgZm9yIG1pblxuXG5cdFx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IGxheWVycy5sZW5ndGgsIHpJbmRleDsgaSA8IGxlbjsgaSsrKSB7XG5cblx0XHRcdHpJbmRleCA9IGxheWVyc1tpXS5zdHlsZS56SW5kZXg7XG5cblx0XHRcdGlmIChsYXllcnNbaV0gIT09IHRoaXMuX2NvbnRhaW5lciAmJiB6SW5kZXgpIHtcblx0XHRcdFx0ZWRnZVpJbmRleCA9IGNvbXBhcmUoZWRnZVpJbmRleCwgK3pJbmRleCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKGlzRmluaXRlKGVkZ2VaSW5kZXgpKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMuekluZGV4ID0gZWRnZVpJbmRleCArIGNvbXBhcmUoLTEsIDEpO1xuXHRcdFx0dGhpcy5fdXBkYXRlWkluZGV4KCk7XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGVPcGFjaXR5OiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKCF0aGlzLl9tYXApIHsgcmV0dXJuOyB9XG5cblx0XHQvLyBJRSBkb2Vzbid0IGluaGVyaXQgZmlsdGVyIG9wYWNpdHkgcHJvcGVybHksIHNvIHdlJ3JlIGZvcmNlZCB0byBzZXQgaXQgb24gdGlsZXNcblx0XHRpZiAoaWVsdDkpIHsgcmV0dXJuOyB9XG5cblx0XHRzZXRPcGFjaXR5KHRoaXMuX2NvbnRhaW5lciwgdGhpcy5vcHRpb25zLm9wYWNpdHkpO1xuXG5cdFx0dmFyIG5vdyA9ICtuZXcgRGF0ZSgpLFxuXHRcdCAgICBuZXh0RnJhbWUgPSBmYWxzZSxcblx0XHQgICAgd2lsbFBydW5lID0gZmFsc2U7XG5cblx0XHRmb3IgKHZhciBrZXkgaW4gdGhpcy5fdGlsZXMpIHtcblx0XHRcdHZhciB0aWxlID0gdGhpcy5fdGlsZXNba2V5XTtcblx0XHRcdGlmICghdGlsZS5jdXJyZW50IHx8ICF0aWxlLmxvYWRlZCkgeyBjb250aW51ZTsgfVxuXG5cdFx0XHR2YXIgZmFkZSA9IE1hdGgubWluKDEsIChub3cgLSB0aWxlLmxvYWRlZCkgLyAyMDApO1xuXG5cdFx0XHRzZXRPcGFjaXR5KHRpbGUuZWwsIGZhZGUpO1xuXHRcdFx0aWYgKGZhZGUgPCAxKSB7XG5cdFx0XHRcdG5leHRGcmFtZSA9IHRydWU7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRpZiAodGlsZS5hY3RpdmUpIHtcblx0XHRcdFx0XHR3aWxsUHJ1bmUgPSB0cnVlO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRoaXMuX29uT3BhcXVlVGlsZSh0aWxlKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aWxlLmFjdGl2ZSA9IHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKHdpbGxQcnVuZSAmJiAhdGhpcy5fbm9QcnVuZSkgeyB0aGlzLl9wcnVuZVRpbGVzKCk7IH1cblxuXHRcdGlmIChuZXh0RnJhbWUpIHtcblx0XHRcdGNhbmNlbEFuaW1GcmFtZSh0aGlzLl9mYWRlRnJhbWUpO1xuXHRcdFx0dGhpcy5fZmFkZUZyYW1lID0gcmVxdWVzdEFuaW1GcmFtZSh0aGlzLl91cGRhdGVPcGFjaXR5LCB0aGlzKTtcblx0XHR9XG5cdH0sXG5cblx0X29uT3BhcXVlVGlsZTogZmFsc2VGbixcblxuXHRfaW5pdENvbnRhaW5lcjogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9jb250YWluZXIpIHsgcmV0dXJuOyB9XG5cblx0XHR0aGlzLl9jb250YWluZXIgPSBjcmVhdGUkMSgnZGl2JywgJ2xlYWZsZXQtbGF5ZXIgJyArICh0aGlzLm9wdGlvbnMuY2xhc3NOYW1lIHx8ICcnKSk7XG5cdFx0dGhpcy5fdXBkYXRlWkluZGV4KCk7XG5cblx0XHRpZiAodGhpcy5vcHRpb25zLm9wYWNpdHkgPCAxKSB7XG5cdFx0XHR0aGlzLl91cGRhdGVPcGFjaXR5KCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5nZXRQYW5lKCkuYXBwZW5kQ2hpbGQodGhpcy5fY29udGFpbmVyKTtcblx0fSxcblxuXHRfdXBkYXRlTGV2ZWxzOiBmdW5jdGlvbiAoKSB7XG5cblx0XHR2YXIgem9vbSA9IHRoaXMuX3RpbGVab29tLFxuXHRcdCAgICBtYXhab29tID0gdGhpcy5vcHRpb25zLm1heFpvb207XG5cblx0XHRpZiAoem9vbSA9PT0gdW5kZWZpbmVkKSB7IHJldHVybiB1bmRlZmluZWQ7IH1cblxuXHRcdGZvciAodmFyIHogaW4gdGhpcy5fbGV2ZWxzKSB7XG5cdFx0XHRpZiAodGhpcy5fbGV2ZWxzW3pdLmVsLmNoaWxkcmVuLmxlbmd0aCB8fCB6ID09PSB6b29tKSB7XG5cdFx0XHRcdHRoaXMuX2xldmVsc1t6XS5lbC5zdHlsZS56SW5kZXggPSBtYXhab29tIC0gTWF0aC5hYnMoem9vbSAtIHopO1xuXHRcdFx0XHR0aGlzLl9vblVwZGF0ZUxldmVsKHopO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmVtb3ZlKHRoaXMuX2xldmVsc1t6XS5lbCk7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZVRpbGVzQXRab29tKHopO1xuXHRcdFx0XHR0aGlzLl9vblJlbW92ZUxldmVsKHopO1xuXHRcdFx0XHRkZWxldGUgdGhpcy5fbGV2ZWxzW3pdO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHZhciBsZXZlbCA9IHRoaXMuX2xldmVsc1t6b29tXSxcblx0XHQgICAgbWFwID0gdGhpcy5fbWFwO1xuXG5cdFx0aWYgKCFsZXZlbCkge1xuXHRcdFx0bGV2ZWwgPSB0aGlzLl9sZXZlbHNbem9vbV0gPSB7fTtcblxuXHRcdFx0bGV2ZWwuZWwgPSBjcmVhdGUkMSgnZGl2JywgJ2xlYWZsZXQtdGlsZS1jb250YWluZXIgbGVhZmxldC16b29tLWFuaW1hdGVkJywgdGhpcy5fY29udGFpbmVyKTtcblx0XHRcdGxldmVsLmVsLnN0eWxlLnpJbmRleCA9IG1heFpvb207XG5cblx0XHRcdGxldmVsLm9yaWdpbiA9IG1hcC5wcm9qZWN0KG1hcC51bnByb2plY3QobWFwLmdldFBpeGVsT3JpZ2luKCkpLCB6b29tKS5yb3VuZCgpO1xuXHRcdFx0bGV2ZWwuem9vbSA9IHpvb207XG5cblx0XHRcdHRoaXMuX3NldFpvb21UcmFuc2Zvcm0obGV2ZWwsIG1hcC5nZXRDZW50ZXIoKSwgbWFwLmdldFpvb20oKSk7XG5cblx0XHRcdC8vIGZvcmNlIHRoZSBicm93c2VyIHRvIGNvbnNpZGVyIHRoZSBuZXdseSBhZGRlZCBlbGVtZW50IGZvciB0cmFuc2l0aW9uXG5cdFx0XHRmYWxzZUZuKGxldmVsLmVsLm9mZnNldFdpZHRoKTtcblxuXHRcdFx0dGhpcy5fb25DcmVhdGVMZXZlbChsZXZlbCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fbGV2ZWwgPSBsZXZlbDtcblxuXHRcdHJldHVybiBsZXZlbDtcblx0fSxcblxuXHRfb25VcGRhdGVMZXZlbDogZmFsc2VGbixcblxuXHRfb25SZW1vdmVMZXZlbDogZmFsc2VGbixcblxuXHRfb25DcmVhdGVMZXZlbDogZmFsc2VGbixcblxuXHRfcHJ1bmVUaWxlczogZnVuY3Rpb24gKCkge1xuXHRcdGlmICghdGhpcy5fbWFwKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIGtleSwgdGlsZTtcblxuXHRcdHZhciB6b29tID0gdGhpcy5fbWFwLmdldFpvb20oKTtcblx0XHRpZiAoem9vbSA+IHRoaXMub3B0aW9ucy5tYXhab29tIHx8XG5cdFx0XHR6b29tIDwgdGhpcy5vcHRpb25zLm1pblpvb20pIHtcblx0XHRcdHRoaXMuX3JlbW92ZUFsbFRpbGVzKCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Zm9yIChrZXkgaW4gdGhpcy5fdGlsZXMpIHtcblx0XHRcdHRpbGUgPSB0aGlzLl90aWxlc1trZXldO1xuXHRcdFx0dGlsZS5yZXRhaW4gPSB0aWxlLmN1cnJlbnQ7XG5cdFx0fVxuXG5cdFx0Zm9yIChrZXkgaW4gdGhpcy5fdGlsZXMpIHtcblx0XHRcdHRpbGUgPSB0aGlzLl90aWxlc1trZXldO1xuXHRcdFx0aWYgKHRpbGUuY3VycmVudCAmJiAhdGlsZS5hY3RpdmUpIHtcblx0XHRcdFx0dmFyIGNvb3JkcyA9IHRpbGUuY29vcmRzO1xuXHRcdFx0XHRpZiAoIXRoaXMuX3JldGFpblBhcmVudChjb29yZHMueCwgY29vcmRzLnksIGNvb3Jkcy56LCBjb29yZHMueiAtIDUpKSB7XG5cdFx0XHRcdFx0dGhpcy5fcmV0YWluQ2hpbGRyZW4oY29vcmRzLngsIGNvb3Jkcy55LCBjb29yZHMueiwgY29vcmRzLnogKyAyKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGZvciAoa2V5IGluIHRoaXMuX3RpbGVzKSB7XG5cdFx0XHRpZiAoIXRoaXMuX3RpbGVzW2tleV0ucmV0YWluKSB7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZVRpbGUoa2V5KTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X3JlbW92ZVRpbGVzQXRab29tOiBmdW5jdGlvbiAoem9vbSkge1xuXHRcdGZvciAodmFyIGtleSBpbiB0aGlzLl90aWxlcykge1xuXHRcdFx0aWYgKHRoaXMuX3RpbGVzW2tleV0uY29vcmRzLnogIT09IHpvb20pIHtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9yZW1vdmVUaWxlKGtleSk7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZW1vdmVBbGxUaWxlczogZnVuY3Rpb24gKCkge1xuXHRcdGZvciAodmFyIGtleSBpbiB0aGlzLl90aWxlcykge1xuXHRcdFx0dGhpcy5fcmVtb3ZlVGlsZShrZXkpO1xuXHRcdH1cblx0fSxcblxuXHRfaW52YWxpZGF0ZUFsbDogZnVuY3Rpb24gKCkge1xuXHRcdGZvciAodmFyIHogaW4gdGhpcy5fbGV2ZWxzKSB7XG5cdFx0XHRyZW1vdmUodGhpcy5fbGV2ZWxzW3pdLmVsKTtcblx0XHRcdHRoaXMuX29uUmVtb3ZlTGV2ZWwoeik7XG5cdFx0XHRkZWxldGUgdGhpcy5fbGV2ZWxzW3pdO1xuXHRcdH1cblx0XHR0aGlzLl9yZW1vdmVBbGxUaWxlcygpO1xuXG5cdFx0dGhpcy5fdGlsZVpvb20gPSB1bmRlZmluZWQ7XG5cdH0sXG5cblx0X3JldGFpblBhcmVudDogZnVuY3Rpb24gKHgsIHksIHosIG1pblpvb20pIHtcblx0XHR2YXIgeDIgPSBNYXRoLmZsb29yKHggLyAyKSxcblx0XHQgICAgeTIgPSBNYXRoLmZsb29yKHkgLyAyKSxcblx0XHQgICAgejIgPSB6IC0gMSxcblx0XHQgICAgY29vcmRzMiA9IG5ldyBQb2ludCgreDIsICt5Mik7XG5cdFx0Y29vcmRzMi56ID0gK3oyO1xuXG5cdFx0dmFyIGtleSA9IHRoaXMuX3RpbGVDb29yZHNUb0tleShjb29yZHMyKSxcblx0XHQgICAgdGlsZSA9IHRoaXMuX3RpbGVzW2tleV07XG5cblx0XHRpZiAodGlsZSAmJiB0aWxlLmFjdGl2ZSkge1xuXHRcdFx0dGlsZS5yZXRhaW4gPSB0cnVlO1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cblx0XHR9IGVsc2UgaWYgKHRpbGUgJiYgdGlsZS5sb2FkZWQpIHtcblx0XHRcdHRpbGUucmV0YWluID0gdHJ1ZTtcblx0XHR9XG5cblx0XHRpZiAoejIgPiBtaW5ab29tKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5fcmV0YWluUGFyZW50KHgyLCB5MiwgejIsIG1pblpvb20pO1xuXHRcdH1cblxuXHRcdHJldHVybiBmYWxzZTtcblx0fSxcblxuXHRfcmV0YWluQ2hpbGRyZW46IGZ1bmN0aW9uICh4LCB5LCB6LCBtYXhab29tKSB7XG5cblx0XHRmb3IgKHZhciBpID0gMiAqIHg7IGkgPCAyICogeCArIDI7IGkrKykge1xuXHRcdFx0Zm9yICh2YXIgaiA9IDIgKiB5OyBqIDwgMiAqIHkgKyAyOyBqKyspIHtcblxuXHRcdFx0XHR2YXIgY29vcmRzID0gbmV3IFBvaW50KGksIGopO1xuXHRcdFx0XHRjb29yZHMueiA9IHogKyAxO1xuXG5cdFx0XHRcdHZhciBrZXkgPSB0aGlzLl90aWxlQ29vcmRzVG9LZXkoY29vcmRzKSxcblx0XHRcdFx0ICAgIHRpbGUgPSB0aGlzLl90aWxlc1trZXldO1xuXG5cdFx0XHRcdGlmICh0aWxlICYmIHRpbGUuYWN0aXZlKSB7XG5cdFx0XHRcdFx0dGlsZS5yZXRhaW4gPSB0cnVlO1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAodGlsZSAmJiB0aWxlLmxvYWRlZCkge1xuXHRcdFx0XHRcdHRpbGUucmV0YWluID0gdHJ1ZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICh6ICsgMSA8IG1heFpvb20pIHtcblx0XHRcdFx0XHR0aGlzLl9yZXRhaW5DaGlsZHJlbihpLCBqLCB6ICsgMSwgbWF4Wm9vbSk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X3Jlc2V0VmlldzogZnVuY3Rpb24gKGUpIHtcblx0XHR2YXIgYW5pbWF0aW5nID0gZSAmJiAoZS5waW5jaCB8fCBlLmZseVRvKTtcblx0XHR0aGlzLl9zZXRWaWV3KHRoaXMuX21hcC5nZXRDZW50ZXIoKSwgdGhpcy5fbWFwLmdldFpvb20oKSwgYW5pbWF0aW5nLCBhbmltYXRpbmcpO1xuXHR9LFxuXG5cdF9hbmltYXRlWm9vbTogZnVuY3Rpb24gKGUpIHtcblx0XHR0aGlzLl9zZXRWaWV3KGUuY2VudGVyLCBlLnpvb20sIHRydWUsIGUubm9VcGRhdGUpO1xuXHR9LFxuXG5cdF9jbGFtcFpvb206IGZ1bmN0aW9uICh6b29tKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHRpZiAodW5kZWZpbmVkICE9PSBvcHRpb25zLm1pbk5hdGl2ZVpvb20gJiYgem9vbSA8IG9wdGlvbnMubWluTmF0aXZlWm9vbSkge1xuXHRcdFx0cmV0dXJuIG9wdGlvbnMubWluTmF0aXZlWm9vbTtcblx0XHR9XG5cblx0XHRpZiAodW5kZWZpbmVkICE9PSBvcHRpb25zLm1heE5hdGl2ZVpvb20gJiYgb3B0aW9ucy5tYXhOYXRpdmVab29tIDwgem9vbSkge1xuXHRcdFx0cmV0dXJuIG9wdGlvbnMubWF4TmF0aXZlWm9vbTtcblx0XHR9XG5cblx0XHRyZXR1cm4gem9vbTtcblx0fSxcblxuXHRfc2V0VmlldzogZnVuY3Rpb24gKGNlbnRlciwgem9vbSwgbm9QcnVuZSwgbm9VcGRhdGUpIHtcblx0XHR2YXIgdGlsZVpvb20gPSB0aGlzLl9jbGFtcFpvb20oTWF0aC5yb3VuZCh6b29tKSk7XG5cdFx0aWYgKCh0aGlzLm9wdGlvbnMubWF4Wm9vbSAhPT0gdW5kZWZpbmVkICYmIHRpbGVab29tID4gdGhpcy5vcHRpb25zLm1heFpvb20pIHx8XG5cdFx0ICAgICh0aGlzLm9wdGlvbnMubWluWm9vbSAhPT0gdW5kZWZpbmVkICYmIHRpbGVab29tIDwgdGhpcy5vcHRpb25zLm1pblpvb20pKSB7XG5cdFx0XHR0aWxlWm9vbSA9IHVuZGVmaW5lZDtcblx0XHR9XG5cblx0XHR2YXIgdGlsZVpvb21DaGFuZ2VkID0gdGhpcy5vcHRpb25zLnVwZGF0ZVdoZW5ab29taW5nICYmICh0aWxlWm9vbSAhPT0gdGhpcy5fdGlsZVpvb20pO1xuXG5cdFx0aWYgKCFub1VwZGF0ZSB8fCB0aWxlWm9vbUNoYW5nZWQpIHtcblxuXHRcdFx0dGhpcy5fdGlsZVpvb20gPSB0aWxlWm9vbTtcblxuXHRcdFx0aWYgKHRoaXMuX2Fib3J0TG9hZGluZykge1xuXHRcdFx0XHR0aGlzLl9hYm9ydExvYWRpbmcoKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fdXBkYXRlTGV2ZWxzKCk7XG5cdFx0XHR0aGlzLl9yZXNldEdyaWQoKTtcblxuXHRcdFx0aWYgKHRpbGVab29tICE9PSB1bmRlZmluZWQpIHtcblx0XHRcdFx0dGhpcy5fdXBkYXRlKGNlbnRlcik7XG5cdFx0XHR9XG5cblx0XHRcdGlmICghbm9QcnVuZSkge1xuXHRcdFx0XHR0aGlzLl9wcnVuZVRpbGVzKCk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEZsYWcgdG8gcHJldmVudCBfdXBkYXRlT3BhY2l0eSBmcm9tIHBydW5pbmcgdGlsZXMgZHVyaW5nXG5cdFx0XHQvLyBhIHpvb20gYW5pbSBvciBhIHBpbmNoIGdlc3R1cmVcblx0XHRcdHRoaXMuX25vUHJ1bmUgPSAhIW5vUHJ1bmU7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc2V0Wm9vbVRyYW5zZm9ybXMoY2VudGVyLCB6b29tKTtcblx0fSxcblxuXHRfc2V0Wm9vbVRyYW5zZm9ybXM6IGZ1bmN0aW9uIChjZW50ZXIsIHpvb20pIHtcblx0XHRmb3IgKHZhciBpIGluIHRoaXMuX2xldmVscykge1xuXHRcdFx0dGhpcy5fc2V0Wm9vbVRyYW5zZm9ybSh0aGlzLl9sZXZlbHNbaV0sIGNlbnRlciwgem9vbSk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRab29tVHJhbnNmb3JtOiBmdW5jdGlvbiAobGV2ZWwsIGNlbnRlciwgem9vbSkge1xuXHRcdHZhciBzY2FsZSA9IHRoaXMuX21hcC5nZXRab29tU2NhbGUoem9vbSwgbGV2ZWwuem9vbSksXG5cdFx0ICAgIHRyYW5zbGF0ZSA9IGxldmVsLm9yaWdpbi5tdWx0aXBseUJ5KHNjYWxlKVxuXHRcdCAgICAgICAgLnN1YnRyYWN0KHRoaXMuX21hcC5fZ2V0TmV3UGl4ZWxPcmlnaW4oY2VudGVyLCB6b29tKSkucm91bmQoKTtcblxuXHRcdGlmIChhbnkzZCkge1xuXHRcdFx0c2V0VHJhbnNmb3JtKGxldmVsLmVsLCB0cmFuc2xhdGUsIHNjYWxlKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0c2V0UG9zaXRpb24obGV2ZWwuZWwsIHRyYW5zbGF0ZSk7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZXNldEdyaWQ6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBjcnMgPSBtYXAub3B0aW9ucy5jcnMsXG5cdFx0ICAgIHRpbGVTaXplID0gdGhpcy5fdGlsZVNpemUgPSB0aGlzLmdldFRpbGVTaXplKCksXG5cdFx0ICAgIHRpbGVab29tID0gdGhpcy5fdGlsZVpvb207XG5cblx0XHR2YXIgYm91bmRzID0gdGhpcy5fbWFwLmdldFBpeGVsV29ybGRCb3VuZHModGhpcy5fdGlsZVpvb20pO1xuXHRcdGlmIChib3VuZHMpIHtcblx0XHRcdHRoaXMuX2dsb2JhbFRpbGVSYW5nZSA9IHRoaXMuX3B4Qm91bmRzVG9UaWxlUmFuZ2UoYm91bmRzKTtcblx0XHR9XG5cblx0XHR0aGlzLl93cmFwWCA9IGNycy53cmFwTG5nICYmICF0aGlzLm9wdGlvbnMubm9XcmFwICYmIFtcblx0XHRcdE1hdGguZmxvb3IobWFwLnByb2plY3QoWzAsIGNycy53cmFwTG5nWzBdXSwgdGlsZVpvb20pLnggLyB0aWxlU2l6ZS54KSxcblx0XHRcdE1hdGguY2VpbChtYXAucHJvamVjdChbMCwgY3JzLndyYXBMbmdbMV1dLCB0aWxlWm9vbSkueCAvIHRpbGVTaXplLnkpXG5cdFx0XTtcblx0XHR0aGlzLl93cmFwWSA9IGNycy53cmFwTGF0ICYmICF0aGlzLm9wdGlvbnMubm9XcmFwICYmIFtcblx0XHRcdE1hdGguZmxvb3IobWFwLnByb2plY3QoW2Nycy53cmFwTGF0WzBdLCAwXSwgdGlsZVpvb20pLnkgLyB0aWxlU2l6ZS54KSxcblx0XHRcdE1hdGguY2VpbChtYXAucHJvamVjdChbY3JzLndyYXBMYXRbMV0sIDBdLCB0aWxlWm9vbSkueSAvIHRpbGVTaXplLnkpXG5cdFx0XTtcblx0fSxcblxuXHRfb25Nb3ZlRW5kOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKCF0aGlzLl9tYXAgfHwgdGhpcy5fbWFwLl9hbmltYXRpbmdab29tKSB7IHJldHVybjsgfVxuXG5cdFx0dGhpcy5fdXBkYXRlKCk7XG5cdH0sXG5cblx0X2dldFRpbGVkUGl4ZWxCb3VuZHM6IGZ1bmN0aW9uIChjZW50ZXIpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBtYXBab29tID0gbWFwLl9hbmltYXRpbmdab29tID8gTWF0aC5tYXgobWFwLl9hbmltYXRlVG9ab29tLCBtYXAuZ2V0Wm9vbSgpKSA6IG1hcC5nZXRab29tKCksXG5cdFx0ICAgIHNjYWxlID0gbWFwLmdldFpvb21TY2FsZShtYXBab29tLCB0aGlzLl90aWxlWm9vbSksXG5cdFx0ICAgIHBpeGVsQ2VudGVyID0gbWFwLnByb2plY3QoY2VudGVyLCB0aGlzLl90aWxlWm9vbSkuZmxvb3IoKSxcblx0XHQgICAgaGFsZlNpemUgPSBtYXAuZ2V0U2l6ZSgpLmRpdmlkZUJ5KHNjYWxlICogMik7XG5cblx0XHRyZXR1cm4gbmV3IEJvdW5kcyhwaXhlbENlbnRlci5zdWJ0cmFjdChoYWxmU2l6ZSksIHBpeGVsQ2VudGVyLmFkZChoYWxmU2l6ZSkpO1xuXHR9LFxuXG5cdC8vIFByaXZhdGUgbWV0aG9kIHRvIGxvYWQgdGlsZXMgaW4gdGhlIGdyaWQncyBhY3RpdmUgem9vbSBsZXZlbCBhY2NvcmRpbmcgdG8gbWFwIGJvdW5kc1xuXHRfdXBkYXRlOiBmdW5jdGlvbiAoY2VudGVyKSB7XG5cdFx0dmFyIG1hcCA9IHRoaXMuX21hcDtcblx0XHRpZiAoIW1hcCkgeyByZXR1cm47IH1cblx0XHR2YXIgem9vbSA9IHRoaXMuX2NsYW1wWm9vbShtYXAuZ2V0Wm9vbSgpKTtcblxuXHRcdGlmIChjZW50ZXIgPT09IHVuZGVmaW5lZCkgeyBjZW50ZXIgPSBtYXAuZ2V0Q2VudGVyKCk7IH1cblx0XHRpZiAodGhpcy5fdGlsZVpvb20gPT09IHVuZGVmaW5lZCkgeyByZXR1cm47IH1cdC8vIGlmIG91dCBvZiBtaW56b29tL21heHpvb21cblxuXHRcdHZhciBwaXhlbEJvdW5kcyA9IHRoaXMuX2dldFRpbGVkUGl4ZWxCb3VuZHMoY2VudGVyKSxcblx0XHQgICAgdGlsZVJhbmdlID0gdGhpcy5fcHhCb3VuZHNUb1RpbGVSYW5nZShwaXhlbEJvdW5kcyksXG5cdFx0ICAgIHRpbGVDZW50ZXIgPSB0aWxlUmFuZ2UuZ2V0Q2VudGVyKCksXG5cdFx0ICAgIHF1ZXVlID0gW10sXG5cdFx0ICAgIG1hcmdpbiA9IHRoaXMub3B0aW9ucy5rZWVwQnVmZmVyLFxuXHRcdCAgICBub1BydW5lUmFuZ2UgPSBuZXcgQm91bmRzKHRpbGVSYW5nZS5nZXRCb3R0b21MZWZ0KCkuc3VidHJhY3QoW21hcmdpbiwgLW1hcmdpbl0pLFxuXHRcdCAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpbGVSYW5nZS5nZXRUb3BSaWdodCgpLmFkZChbbWFyZ2luLCAtbWFyZ2luXSkpO1xuXG5cdFx0Ly8gU2FuaXR5IGNoZWNrOiBwYW5pYyBpZiB0aGUgdGlsZSByYW5nZSBjb250YWlucyBJbmZpbml0eSBzb21ld2hlcmUuXG5cdFx0aWYgKCEoaXNGaW5pdGUodGlsZVJhbmdlLm1pbi54KSAmJlxuXHRcdCAgICAgIGlzRmluaXRlKHRpbGVSYW5nZS5taW4ueSkgJiZcblx0XHQgICAgICBpc0Zpbml0ZSh0aWxlUmFuZ2UubWF4LngpICYmXG5cdFx0ICAgICAgaXNGaW5pdGUodGlsZVJhbmdlLm1heC55KSkpIHsgdGhyb3cgbmV3IEVycm9yKCdBdHRlbXB0ZWQgdG8gbG9hZCBhbiBpbmZpbml0ZSBudW1iZXIgb2YgdGlsZXMnKTsgfVxuXG5cdFx0Zm9yICh2YXIga2V5IGluIHRoaXMuX3RpbGVzKSB7XG5cdFx0XHR2YXIgYyA9IHRoaXMuX3RpbGVzW2tleV0uY29vcmRzO1xuXHRcdFx0aWYgKGMueiAhPT0gdGhpcy5fdGlsZVpvb20gfHwgIW5vUHJ1bmVSYW5nZS5jb250YWlucyhuZXcgUG9pbnQoYy54LCBjLnkpKSkge1xuXHRcdFx0XHR0aGlzLl90aWxlc1trZXldLmN1cnJlbnQgPSBmYWxzZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBfdXBkYXRlIGp1c3QgbG9hZHMgbW9yZSB0aWxlcy4gSWYgdGhlIHRpbGUgem9vbSBsZXZlbCBkaWZmZXJzIHRvbyBtdWNoXG5cdFx0Ly8gZnJvbSB0aGUgbWFwJ3MsIGxldCBfc2V0VmlldyByZXNldCBsZXZlbHMgYW5kIHBydW5lIG9sZCB0aWxlcy5cblx0XHRpZiAoTWF0aC5hYnMoem9vbSAtIHRoaXMuX3RpbGVab29tKSA+IDEpIHsgdGhpcy5fc2V0VmlldyhjZW50ZXIsIHpvb20pOyByZXR1cm47IH1cblxuXHRcdC8vIGNyZWF0ZSBhIHF1ZXVlIG9mIGNvb3JkaW5hdGVzIHRvIGxvYWQgdGlsZXMgZnJvbVxuXHRcdGZvciAodmFyIGogPSB0aWxlUmFuZ2UubWluLnk7IGogPD0gdGlsZVJhbmdlLm1heC55OyBqKyspIHtcblx0XHRcdGZvciAodmFyIGkgPSB0aWxlUmFuZ2UubWluLng7IGkgPD0gdGlsZVJhbmdlLm1heC54OyBpKyspIHtcblx0XHRcdFx0dmFyIGNvb3JkcyA9IG5ldyBQb2ludChpLCBqKTtcblx0XHRcdFx0Y29vcmRzLnogPSB0aGlzLl90aWxlWm9vbTtcblxuXHRcdFx0XHRpZiAoIXRoaXMuX2lzVmFsaWRUaWxlKGNvb3JkcykpIHsgY29udGludWU7IH1cblxuXHRcdFx0XHR2YXIgdGlsZSA9IHRoaXMuX3RpbGVzW3RoaXMuX3RpbGVDb29yZHNUb0tleShjb29yZHMpXTtcblx0XHRcdFx0aWYgKHRpbGUpIHtcblx0XHRcdFx0XHR0aWxlLmN1cnJlbnQgPSB0cnVlO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHF1ZXVlLnB1c2goY29vcmRzKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIHNvcnQgdGlsZSBxdWV1ZSB0byBsb2FkIHRpbGVzIGluIG9yZGVyIG9mIHRoZWlyIGRpc3RhbmNlIHRvIGNlbnRlclxuXHRcdHF1ZXVlLnNvcnQoZnVuY3Rpb24gKGEsIGIpIHtcblx0XHRcdHJldHVybiBhLmRpc3RhbmNlVG8odGlsZUNlbnRlcikgLSBiLmRpc3RhbmNlVG8odGlsZUNlbnRlcik7XG5cdFx0fSk7XG5cblx0XHRpZiAocXVldWUubGVuZ3RoICE9PSAwKSB7XG5cdFx0XHQvLyBpZiBpdCdzIHRoZSBmaXJzdCBiYXRjaCBvZiB0aWxlcyB0byBsb2FkXG5cdFx0XHRpZiAoIXRoaXMuX2xvYWRpbmcpIHtcblx0XHRcdFx0dGhpcy5fbG9hZGluZyA9IHRydWU7XG5cdFx0XHRcdC8vIEBldmVudCBsb2FkaW5nOiBFdmVudFxuXHRcdFx0XHQvLyBGaXJlZCB3aGVuIHRoZSBncmlkIGxheWVyIHN0YXJ0cyBsb2FkaW5nIHRpbGVzLlxuXHRcdFx0XHR0aGlzLmZpcmUoJ2xvYWRpbmcnKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gY3JlYXRlIERPTSBmcmFnbWVudCB0byBhcHBlbmQgdGlsZXMgaW4gb25lIGJhdGNoXG5cdFx0XHR2YXIgZnJhZ21lbnQgPSBkb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7XG5cblx0XHRcdGZvciAoaSA9IDA7IGkgPCBxdWV1ZS5sZW5ndGg7IGkrKykge1xuXHRcdFx0XHR0aGlzLl9hZGRUaWxlKHF1ZXVlW2ldLCBmcmFnbWVudCk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2xldmVsLmVsLmFwcGVuZENoaWxkKGZyYWdtZW50KTtcblx0XHR9XG5cdH0sXG5cblx0X2lzVmFsaWRUaWxlOiBmdW5jdGlvbiAoY29vcmRzKSB7XG5cdFx0dmFyIGNycyA9IHRoaXMuX21hcC5vcHRpb25zLmNycztcblxuXHRcdGlmICghY3JzLmluZmluaXRlKSB7XG5cdFx0XHQvLyBkb24ndCBsb2FkIHRpbGUgaWYgaXQncyBvdXQgb2YgYm91bmRzIGFuZCBub3Qgd3JhcHBlZFxuXHRcdFx0dmFyIGJvdW5kcyA9IHRoaXMuX2dsb2JhbFRpbGVSYW5nZTtcblx0XHRcdGlmICgoIWNycy53cmFwTG5nICYmIChjb29yZHMueCA8IGJvdW5kcy5taW4ueCB8fCBjb29yZHMueCA+IGJvdW5kcy5tYXgueCkpIHx8XG5cdFx0XHQgICAgKCFjcnMud3JhcExhdCAmJiAoY29vcmRzLnkgPCBib3VuZHMubWluLnkgfHwgY29vcmRzLnkgPiBib3VuZHMubWF4LnkpKSkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHR9XG5cblx0XHRpZiAoIXRoaXMub3B0aW9ucy5ib3VuZHMpIHsgcmV0dXJuIHRydWU7IH1cblxuXHRcdC8vIGRvbid0IGxvYWQgdGlsZSBpZiBpdCBkb2Vzbid0IGludGVyc2VjdCB0aGUgYm91bmRzIGluIG9wdGlvbnNcblx0XHR2YXIgdGlsZUJvdW5kcyA9IHRoaXMuX3RpbGVDb29yZHNUb0JvdW5kcyhjb29yZHMpO1xuXHRcdHJldHVybiB0b0xhdExuZ0JvdW5kcyh0aGlzLm9wdGlvbnMuYm91bmRzKS5vdmVybGFwcyh0aWxlQm91bmRzKTtcblx0fSxcblxuXHRfa2V5VG9Cb3VuZHM6IGZ1bmN0aW9uIChrZXkpIHtcblx0XHRyZXR1cm4gdGhpcy5fdGlsZUNvb3Jkc1RvQm91bmRzKHRoaXMuX2tleVRvVGlsZUNvb3JkcyhrZXkpKTtcblx0fSxcblxuXHRfdGlsZUNvb3Jkc1RvTndTZTogZnVuY3Rpb24gKGNvb3Jkcykge1xuXHRcdHZhciBtYXAgPSB0aGlzLl9tYXAsXG5cdFx0ICAgIHRpbGVTaXplID0gdGhpcy5nZXRUaWxlU2l6ZSgpLFxuXHRcdCAgICBud1BvaW50ID0gY29vcmRzLnNjYWxlQnkodGlsZVNpemUpLFxuXHRcdCAgICBzZVBvaW50ID0gbndQb2ludC5hZGQodGlsZVNpemUpLFxuXHRcdCAgICBudyA9IG1hcC51bnByb2plY3QobndQb2ludCwgY29vcmRzLnopLFxuXHRcdCAgICBzZSA9IG1hcC51bnByb2plY3Qoc2VQb2ludCwgY29vcmRzLnopO1xuXHRcdHJldHVybiBbbncsIHNlXTtcblx0fSxcblxuXHQvLyBjb252ZXJ0cyB0aWxlIGNvb3JkaW5hdGVzIHRvIGl0cyBnZW9ncmFwaGljYWwgYm91bmRzXG5cdF90aWxlQ29vcmRzVG9Cb3VuZHM6IGZ1bmN0aW9uIChjb29yZHMpIHtcblx0XHR2YXIgYnAgPSB0aGlzLl90aWxlQ29vcmRzVG9Od1NlKGNvb3JkcyksXG5cdFx0ICAgIGJvdW5kcyA9IG5ldyBMYXRMbmdCb3VuZHMoYnBbMF0sIGJwWzFdKTtcblxuXHRcdGlmICghdGhpcy5vcHRpb25zLm5vV3JhcCkge1xuXHRcdFx0Ym91bmRzID0gdGhpcy5fbWFwLndyYXBMYXRMbmdCb3VuZHMoYm91bmRzKTtcblx0XHR9XG5cdFx0cmV0dXJuIGJvdW5kcztcblx0fSxcblx0Ly8gY29udmVydHMgdGlsZSBjb29yZGluYXRlcyB0byBrZXkgZm9yIHRoZSB0aWxlIGNhY2hlXG5cdF90aWxlQ29vcmRzVG9LZXk6IGZ1bmN0aW9uIChjb29yZHMpIHtcblx0XHRyZXR1cm4gY29vcmRzLnggKyAnOicgKyBjb29yZHMueSArICc6JyArIGNvb3Jkcy56O1xuXHR9LFxuXG5cdC8vIGNvbnZlcnRzIHRpbGUgY2FjaGUga2V5IHRvIGNvb3JkaW5hdGVzXG5cdF9rZXlUb1RpbGVDb29yZHM6IGZ1bmN0aW9uIChrZXkpIHtcblx0XHR2YXIgayA9IGtleS5zcGxpdCgnOicpLFxuXHRcdCAgICBjb29yZHMgPSBuZXcgUG9pbnQoK2tbMF0sICtrWzFdKTtcblx0XHRjb29yZHMueiA9ICtrWzJdO1xuXHRcdHJldHVybiBjb29yZHM7XG5cdH0sXG5cblx0X3JlbW92ZVRpbGU6IGZ1bmN0aW9uIChrZXkpIHtcblx0XHR2YXIgdGlsZSA9IHRoaXMuX3RpbGVzW2tleV07XG5cdFx0aWYgKCF0aWxlKSB7IHJldHVybjsgfVxuXG5cdFx0Ly8gQ2FuY2VscyBhbnkgcGVuZGluZyBodHRwIHJlcXVlc3RzIGFzc29jaWF0ZWQgd2l0aCB0aGUgdGlsZVxuXHRcdC8vIHVubGVzcyB3ZSdyZSBvbiBBbmRyb2lkJ3Mgc3RvY2sgYnJvd3Nlcixcblx0XHQvLyBzZWUgaHR0cHM6Ly9naXRodWIuY29tL0xlYWZsZXQvTGVhZmxldC9pc3N1ZXMvMTM3XG5cdFx0aWYgKCFhbmRyb2lkU3RvY2spIHtcblx0XHRcdHRpbGUuZWwuc2V0QXR0cmlidXRlKCdzcmMnLCBlbXB0eUltYWdlVXJsKTtcblx0XHR9XG5cdFx0cmVtb3ZlKHRpbGUuZWwpO1xuXG5cdFx0ZGVsZXRlIHRoaXMuX3RpbGVzW2tleV07XG5cblx0XHQvLyBAZXZlbnQgdGlsZXVubG9hZDogVGlsZUV2ZW50XG5cdFx0Ly8gRmlyZWQgd2hlbiBhIHRpbGUgaXMgcmVtb3ZlZCAoZS5nLiB3aGVuIGEgdGlsZSBnb2VzIG9mZiB0aGUgc2NyZWVuKS5cblx0XHR0aGlzLmZpcmUoJ3RpbGV1bmxvYWQnLCB7XG5cdFx0XHR0aWxlOiB0aWxlLmVsLFxuXHRcdFx0Y29vcmRzOiB0aGlzLl9rZXlUb1RpbGVDb29yZHMoa2V5KVxuXHRcdH0pO1xuXHR9LFxuXG5cdF9pbml0VGlsZTogZnVuY3Rpb24gKHRpbGUpIHtcblx0XHRhZGRDbGFzcyh0aWxlLCAnbGVhZmxldC10aWxlJyk7XG5cblx0XHR2YXIgdGlsZVNpemUgPSB0aGlzLmdldFRpbGVTaXplKCk7XG5cdFx0dGlsZS5zdHlsZS53aWR0aCA9IHRpbGVTaXplLnggKyAncHgnO1xuXHRcdHRpbGUuc3R5bGUuaGVpZ2h0ID0gdGlsZVNpemUueSArICdweCc7XG5cblx0XHR0aWxlLm9uc2VsZWN0c3RhcnQgPSBmYWxzZUZuO1xuXHRcdHRpbGUub25tb3VzZW1vdmUgPSBmYWxzZUZuO1xuXG5cdFx0Ly8gdXBkYXRlIG9wYWNpdHkgb24gdGlsZXMgaW4gSUU3LTggYmVjYXVzZSBvZiBmaWx0ZXIgaW5oZXJpdGFuY2UgcHJvYmxlbXNcblx0XHRpZiAoaWVsdDkgJiYgdGhpcy5vcHRpb25zLm9wYWNpdHkgPCAxKSB7XG5cdFx0XHRzZXRPcGFjaXR5KHRpbGUsIHRoaXMub3B0aW9ucy5vcGFjaXR5KTtcblx0XHR9XG5cblx0XHQvLyB3aXRob3V0IHRoaXMgaGFjaywgdGlsZXMgZGlzYXBwZWFyIGFmdGVyIHpvb20gb24gQ2hyb21lIGZvciBBbmRyb2lkXG5cdFx0Ly8gaHR0cHM6Ly9naXRodWIuY29tL0xlYWZsZXQvTGVhZmxldC9pc3N1ZXMvMjA3OFxuXHRcdGlmIChhbmRyb2lkICYmICFhbmRyb2lkMjMpIHtcblx0XHRcdHRpbGUuc3R5bGUuV2Via2l0QmFja2ZhY2VWaXNpYmlsaXR5ID0gJ2hpZGRlbic7XG5cdFx0fVxuXHR9LFxuXG5cdF9hZGRUaWxlOiBmdW5jdGlvbiAoY29vcmRzLCBjb250YWluZXIpIHtcblx0XHR2YXIgdGlsZVBvcyA9IHRoaXMuX2dldFRpbGVQb3MoY29vcmRzKSxcblx0XHQgICAga2V5ID0gdGhpcy5fdGlsZUNvb3Jkc1RvS2V5KGNvb3Jkcyk7XG5cblx0XHR2YXIgdGlsZSA9IHRoaXMuY3JlYXRlVGlsZSh0aGlzLl93cmFwQ29vcmRzKGNvb3JkcyksIGJpbmQodGhpcy5fdGlsZVJlYWR5LCB0aGlzLCBjb29yZHMpKTtcblxuXHRcdHRoaXMuX2luaXRUaWxlKHRpbGUpO1xuXG5cdFx0Ly8gaWYgY3JlYXRlVGlsZSBpcyBkZWZpbmVkIHdpdGggYSBzZWNvbmQgYXJndW1lbnQgKFwiZG9uZVwiIGNhbGxiYWNrKSxcblx0XHQvLyB3ZSBrbm93IHRoYXQgdGlsZSBpcyBhc3luYyBhbmQgd2lsbCBiZSByZWFkeSBsYXRlcjsgb3RoZXJ3aXNlXG5cdFx0aWYgKHRoaXMuY3JlYXRlVGlsZS5sZW5ndGggPCAyKSB7XG5cdFx0XHQvLyBtYXJrIHRpbGUgYXMgcmVhZHksIGJ1dCBkZWxheSBvbmUgZnJhbWUgZm9yIG9wYWNpdHkgYW5pbWF0aW9uIHRvIGhhcHBlblxuXHRcdFx0cmVxdWVzdEFuaW1GcmFtZShiaW5kKHRoaXMuX3RpbGVSZWFkeSwgdGhpcywgY29vcmRzLCBudWxsLCB0aWxlKSk7XG5cdFx0fVxuXG5cdFx0c2V0UG9zaXRpb24odGlsZSwgdGlsZVBvcyk7XG5cblx0XHQvLyBzYXZlIHRpbGUgaW4gY2FjaGVcblx0XHR0aGlzLl90aWxlc1trZXldID0ge1xuXHRcdFx0ZWw6IHRpbGUsXG5cdFx0XHRjb29yZHM6IGNvb3Jkcyxcblx0XHRcdGN1cnJlbnQ6IHRydWVcblx0XHR9O1xuXG5cdFx0Y29udGFpbmVyLmFwcGVuZENoaWxkKHRpbGUpO1xuXHRcdC8vIEBldmVudCB0aWxlbG9hZHN0YXJ0OiBUaWxlRXZlbnRcblx0XHQvLyBGaXJlZCB3aGVuIGEgdGlsZSBpcyByZXF1ZXN0ZWQgYW5kIHN0YXJ0cyBsb2FkaW5nLlxuXHRcdHRoaXMuZmlyZSgndGlsZWxvYWRzdGFydCcsIHtcblx0XHRcdHRpbGU6IHRpbGUsXG5cdFx0XHRjb29yZHM6IGNvb3Jkc1xuXHRcdH0pO1xuXHR9LFxuXG5cdF90aWxlUmVhZHk6IGZ1bmN0aW9uIChjb29yZHMsIGVyciwgdGlsZSkge1xuXHRcdGlmICghdGhpcy5fbWFwKSB7IHJldHVybjsgfVxuXG5cdFx0aWYgKGVycikge1xuXHRcdFx0Ly8gQGV2ZW50IHRpbGVlcnJvcjogVGlsZUVycm9yRXZlbnRcblx0XHRcdC8vIEZpcmVkIHdoZW4gdGhlcmUgaXMgYW4gZXJyb3IgbG9hZGluZyBhIHRpbGUuXG5cdFx0XHR0aGlzLmZpcmUoJ3RpbGVlcnJvcicsIHtcblx0XHRcdFx0ZXJyb3I6IGVycixcblx0XHRcdFx0dGlsZTogdGlsZSxcblx0XHRcdFx0Y29vcmRzOiBjb29yZHNcblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdHZhciBrZXkgPSB0aGlzLl90aWxlQ29vcmRzVG9LZXkoY29vcmRzKTtcblxuXHRcdHRpbGUgPSB0aGlzLl90aWxlc1trZXldO1xuXHRcdGlmICghdGlsZSkgeyByZXR1cm47IH1cblxuXHRcdHRpbGUubG9hZGVkID0gK25ldyBEYXRlKCk7XG5cdFx0aWYgKHRoaXMuX21hcC5fZmFkZUFuaW1hdGVkKSB7XG5cdFx0XHRzZXRPcGFjaXR5KHRpbGUuZWwsIDApO1xuXHRcdFx0Y2FuY2VsQW5pbUZyYW1lKHRoaXMuX2ZhZGVGcmFtZSk7XG5cdFx0XHR0aGlzLl9mYWRlRnJhbWUgPSByZXF1ZXN0QW5pbUZyYW1lKHRoaXMuX3VwZGF0ZU9wYWNpdHksIHRoaXMpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aWxlLmFjdGl2ZSA9IHRydWU7XG5cdFx0XHR0aGlzLl9wcnVuZVRpbGVzKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCFlcnIpIHtcblx0XHRcdGFkZENsYXNzKHRpbGUuZWwsICdsZWFmbGV0LXRpbGUtbG9hZGVkJyk7XG5cblx0XHRcdC8vIEBldmVudCB0aWxlbG9hZDogVGlsZUV2ZW50XG5cdFx0XHQvLyBGaXJlZCB3aGVuIGEgdGlsZSBsb2Fkcy5cblx0XHRcdHRoaXMuZmlyZSgndGlsZWxvYWQnLCB7XG5cdFx0XHRcdHRpbGU6IHRpbGUuZWwsXG5cdFx0XHRcdGNvb3JkczogY29vcmRzXG5cdFx0XHR9KTtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5fbm9UaWxlc1RvTG9hZCgpKSB7XG5cdFx0XHR0aGlzLl9sb2FkaW5nID0gZmFsc2U7XG5cdFx0XHQvLyBAZXZlbnQgbG9hZDogRXZlbnRcblx0XHRcdC8vIEZpcmVkIHdoZW4gdGhlIGdyaWQgbGF5ZXIgbG9hZGVkIGFsbCB2aXNpYmxlIHRpbGVzLlxuXHRcdFx0dGhpcy5maXJlKCdsb2FkJyk7XG5cblx0XHRcdGlmIChpZWx0OSB8fCAhdGhpcy5fbWFwLl9mYWRlQW5pbWF0ZWQpIHtcblx0XHRcdFx0cmVxdWVzdEFuaW1GcmFtZSh0aGlzLl9wcnVuZVRpbGVzLCB0aGlzKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vIFdhaXQgYSBiaXQgbW9yZSB0aGFuIDAuMiBzZWNzICh0aGUgZHVyYXRpb24gb2YgdGhlIHRpbGUgZmFkZS1pbilcblx0XHRcdFx0Ly8gdG8gdHJpZ2dlciBhIHBydW5pbmcuXG5cdFx0XHRcdHNldFRpbWVvdXQoYmluZCh0aGlzLl9wcnVuZVRpbGVzLCB0aGlzKSwgMjUwKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X2dldFRpbGVQb3M6IGZ1bmN0aW9uIChjb29yZHMpIHtcblx0XHRyZXR1cm4gY29vcmRzLnNjYWxlQnkodGhpcy5nZXRUaWxlU2l6ZSgpKS5zdWJ0cmFjdCh0aGlzLl9sZXZlbC5vcmlnaW4pO1xuXHR9LFxuXG5cdF93cmFwQ29vcmRzOiBmdW5jdGlvbiAoY29vcmRzKSB7XG5cdFx0dmFyIG5ld0Nvb3JkcyA9IG5ldyBQb2ludChcblx0XHRcdHRoaXMuX3dyYXBYID8gd3JhcE51bShjb29yZHMueCwgdGhpcy5fd3JhcFgpIDogY29vcmRzLngsXG5cdFx0XHR0aGlzLl93cmFwWSA/IHdyYXBOdW0oY29vcmRzLnksIHRoaXMuX3dyYXBZKSA6IGNvb3Jkcy55KTtcblx0XHRuZXdDb29yZHMueiA9IGNvb3Jkcy56O1xuXHRcdHJldHVybiBuZXdDb29yZHM7XG5cdH0sXG5cblx0X3B4Qm91bmRzVG9UaWxlUmFuZ2U6IGZ1bmN0aW9uIChib3VuZHMpIHtcblx0XHR2YXIgdGlsZVNpemUgPSB0aGlzLmdldFRpbGVTaXplKCk7XG5cdFx0cmV0dXJuIG5ldyBCb3VuZHMoXG5cdFx0XHRib3VuZHMubWluLnVuc2NhbGVCeSh0aWxlU2l6ZSkuZmxvb3IoKSxcblx0XHRcdGJvdW5kcy5tYXgudW5zY2FsZUJ5KHRpbGVTaXplKS5jZWlsKCkuc3VidHJhY3QoWzEsIDFdKSk7XG5cdH0sXG5cblx0X25vVGlsZXNUb0xvYWQ6IGZ1bmN0aW9uICgpIHtcblx0XHRmb3IgKHZhciBrZXkgaW4gdGhpcy5fdGlsZXMpIHtcblx0XHRcdGlmICghdGhpcy5fdGlsZXNba2V5XS5sb2FkZWQpIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0fVxuXHRcdHJldHVybiB0cnVlO1xuXHR9XG59KTtcblxuLy8gQGZhY3RvcnkgTC5ncmlkTGF5ZXIob3B0aW9ucz86IEdyaWRMYXllciBvcHRpb25zKVxuLy8gQ3JlYXRlcyBhIG5ldyBpbnN0YW5jZSBvZiBHcmlkTGF5ZXIgd2l0aCB0aGUgc3VwcGxpZWQgb3B0aW9ucy5cbmZ1bmN0aW9uIGdyaWRMYXllcihvcHRpb25zKSB7XG5cdHJldHVybiBuZXcgR3JpZExheWVyKG9wdGlvbnMpO1xufVxuXG4vKlxyXG4gKiBAY2xhc3MgVGlsZUxheWVyXHJcbiAqIEBpbmhlcml0cyBHcmlkTGF5ZXJcclxuICogQGFrYSBMLlRpbGVMYXllclxyXG4gKiBVc2VkIHRvIGxvYWQgYW5kIGRpc3BsYXkgdGlsZSBsYXllcnMgb24gdGhlIG1hcC4gRXh0ZW5kcyBgR3JpZExheWVyYC5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogYGBganNcclxuICogTC50aWxlTGF5ZXIoJ2h0dHA6Ly97c30udGlsZS5vcGVuc3RyZWV0bWFwLm9yZy97en0ve3h9L3t5fS5wbmc/e2Zvb30nLCB7Zm9vOiAnYmFyJ30pLmFkZFRvKG1hcCk7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBAc2VjdGlvbiBVUkwgdGVtcGxhdGVcclxuICogQGV4YW1wbGVcclxuICpcclxuICogQSBzdHJpbmcgb2YgdGhlIGZvbGxvd2luZyBmb3JtOlxyXG4gKlxyXG4gKiBgYGBcclxuICogJ2h0dHA6Ly97c30uc29tZWRvbWFpbi5jb20vYmxhYmxhL3t6fS97eH0ve3l9e3J9LnBuZydcclxuICogYGBgXHJcbiAqXHJcbiAqIGB7c31gIG1lYW5zIG9uZSBvZiB0aGUgYXZhaWxhYmxlIHN1YmRvbWFpbnMgKHVzZWQgc2VxdWVudGlhbGx5IHRvIGhlbHAgd2l0aCBicm93c2VyIHBhcmFsbGVsIHJlcXVlc3RzIHBlciBkb21haW4gbGltaXRhdGlvbjsgc3ViZG9tYWluIHZhbHVlcyBhcmUgc3BlY2lmaWVkIGluIG9wdGlvbnM7IGBhYCwgYGJgIG9yIGBjYCBieSBkZWZhdWx0LCBjYW4gYmUgb21pdHRlZCksIGB7en1gIOKAlCB6b29tIGxldmVsLCBge3h9YCBhbmQgYHt5fWAg4oCUIHRpbGUgY29vcmRpbmF0ZXMuIGB7cn1gIGNhbiBiZSB1c2VkIHRvIGFkZCBcIiZjb21tYXQ7MnhcIiB0byB0aGUgVVJMIHRvIGxvYWQgcmV0aW5hIHRpbGVzLlxyXG4gKlxyXG4gKiBZb3UgY2FuIHVzZSBjdXN0b20ga2V5cyBpbiB0aGUgdGVtcGxhdGUsIHdoaWNoIHdpbGwgYmUgW2V2YWx1YXRlZF0oI3V0aWwtdGVtcGxhdGUpIGZyb20gVGlsZUxheWVyIG9wdGlvbnMsIGxpa2UgdGhpczpcclxuICpcclxuICogYGBgXHJcbiAqIEwudGlsZUxheWVyKCdodHRwOi8ve3N9LnNvbWVkb21haW4uY29tL3tmb299L3t6fS97eH0ve3l9LnBuZycsIHtmb286ICdiYXInfSk7XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcblxyXG52YXIgVGlsZUxheWVyID0gR3JpZExheWVyLmV4dGVuZCh7XHJcblxyXG5cdC8vIEBzZWN0aW9uXHJcblx0Ly8gQGFrYSBUaWxlTGF5ZXIgb3B0aW9uc1xyXG5cdG9wdGlvbnM6IHtcclxuXHRcdC8vIEBvcHRpb24gbWluWm9vbTogTnVtYmVyID0gMFxyXG5cdFx0Ly8gVGhlIG1pbmltdW0gem9vbSBsZXZlbCBkb3duIHRvIHdoaWNoIHRoaXMgbGF5ZXIgd2lsbCBiZSBkaXNwbGF5ZWQgKGluY2x1c2l2ZSkuXHJcblx0XHRtaW5ab29tOiAwLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gbWF4Wm9vbTogTnVtYmVyID0gMThcclxuXHRcdC8vIFRoZSBtYXhpbXVtIHpvb20gbGV2ZWwgdXAgdG8gd2hpY2ggdGhpcyBsYXllciB3aWxsIGJlIGRpc3BsYXllZCAoaW5jbHVzaXZlKS5cclxuXHRcdG1heFpvb206IDE4LFxyXG5cclxuXHRcdC8vIEBvcHRpb24gc3ViZG9tYWluczogU3RyaW5nfFN0cmluZ1tdID0gJ2FiYydcclxuXHRcdC8vIFN1YmRvbWFpbnMgb2YgdGhlIHRpbGUgc2VydmljZS4gQ2FuIGJlIHBhc3NlZCBpbiB0aGUgZm9ybSBvZiBvbmUgc3RyaW5nICh3aGVyZSBlYWNoIGxldHRlciBpcyBhIHN1YmRvbWFpbiBuYW1lKSBvciBhbiBhcnJheSBvZiBzdHJpbmdzLlxyXG5cdFx0c3ViZG9tYWluczogJ2FiYycsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBlcnJvclRpbGVVcmw6IFN0cmluZyA9ICcnXHJcblx0XHQvLyBVUkwgdG8gdGhlIHRpbGUgaW1hZ2UgdG8gc2hvdyBpbiBwbGFjZSBvZiB0aGUgdGlsZSB0aGF0IGZhaWxlZCB0byBsb2FkLlxyXG5cdFx0ZXJyb3JUaWxlVXJsOiAnJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHpvb21PZmZzZXQ6IE51bWJlciA9IDBcclxuXHRcdC8vIFRoZSB6b29tIG51bWJlciB1c2VkIGluIHRpbGUgVVJMcyB3aWxsIGJlIG9mZnNldCB3aXRoIHRoaXMgdmFsdWUuXHJcblx0XHR6b29tT2Zmc2V0OiAwLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gdG1zOiBCb29sZWFuID0gZmFsc2VcclxuXHRcdC8vIElmIGB0cnVlYCwgaW52ZXJzZXMgWSBheGlzIG51bWJlcmluZyBmb3IgdGlsZXMgKHR1cm4gdGhpcyBvbiBmb3IgW1RNU10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVGlsZV9NYXBfU2VydmljZSkgc2VydmljZXMpLlxyXG5cdFx0dG1zOiBmYWxzZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHpvb21SZXZlcnNlOiBCb29sZWFuID0gZmFsc2VcclxuXHRcdC8vIElmIHNldCB0byB0cnVlLCB0aGUgem9vbSBudW1iZXIgdXNlZCBpbiB0aWxlIFVSTHMgd2lsbCBiZSByZXZlcnNlZCAoYG1heFpvb20gLSB6b29tYCBpbnN0ZWFkIG9mIGB6b29tYClcclxuXHRcdHpvb21SZXZlcnNlOiBmYWxzZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGRldGVjdFJldGluYTogQm9vbGVhbiA9IGZhbHNlXHJcblx0XHQvLyBJZiBgdHJ1ZWAgYW5kIHVzZXIgaXMgb24gYSByZXRpbmEgZGlzcGxheSwgaXQgd2lsbCByZXF1ZXN0IGZvdXIgdGlsZXMgb2YgaGFsZiB0aGUgc3BlY2lmaWVkIHNpemUgYW5kIGEgYmlnZ2VyIHpvb20gbGV2ZWwgaW4gcGxhY2Ugb2Ygb25lIHRvIHV0aWxpemUgdGhlIGhpZ2ggcmVzb2x1dGlvbi5cclxuXHRcdGRldGVjdFJldGluYTogZmFsc2UsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBjcm9zc09yaWdpbjogQm9vbGVhbiA9IGZhbHNlXHJcblx0XHQvLyBJZiB0cnVlLCBhbGwgdGlsZXMgd2lsbCBoYXZlIHRoZWlyIGNyb3NzT3JpZ2luIGF0dHJpYnV0ZSBzZXQgdG8gJycuIFRoaXMgaXMgbmVlZGVkIGlmIHlvdSB3YW50IHRvIGFjY2VzcyB0aWxlIHBpeGVsIGRhdGEuXHJcblx0XHRjcm9zc09yaWdpbjogZmFsc2VcclxuXHR9LFxyXG5cclxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAodXJsLCBvcHRpb25zKSB7XHJcblxyXG5cdFx0dGhpcy5fdXJsID0gdXJsO1xyXG5cclxuXHRcdG9wdGlvbnMgPSBzZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xyXG5cclxuXHRcdC8vIGRldGVjdGluZyByZXRpbmEgZGlzcGxheXMsIGFkanVzdGluZyB0aWxlU2l6ZSBhbmQgem9vbSBsZXZlbHNcclxuXHRcdGlmIChvcHRpb25zLmRldGVjdFJldGluYSAmJiByZXRpbmEgJiYgb3B0aW9ucy5tYXhab29tID4gMCkge1xyXG5cclxuXHRcdFx0b3B0aW9ucy50aWxlU2l6ZSA9IE1hdGguZmxvb3Iob3B0aW9ucy50aWxlU2l6ZSAvIDIpO1xyXG5cclxuXHRcdFx0aWYgKCFvcHRpb25zLnpvb21SZXZlcnNlKSB7XHJcblx0XHRcdFx0b3B0aW9ucy56b29tT2Zmc2V0Kys7XHJcblx0XHRcdFx0b3B0aW9ucy5tYXhab29tLS07XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0b3B0aW9ucy56b29tT2Zmc2V0LS07XHJcblx0XHRcdFx0b3B0aW9ucy5taW5ab29tKys7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdG9wdGlvbnMubWluWm9vbSA9IE1hdGgubWF4KDAsIG9wdGlvbnMubWluWm9vbSk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKHR5cGVvZiBvcHRpb25zLnN1YmRvbWFpbnMgPT09ICdzdHJpbmcnKSB7XHJcblx0XHRcdG9wdGlvbnMuc3ViZG9tYWlucyA9IG9wdGlvbnMuc3ViZG9tYWlucy5zcGxpdCgnJyk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZm9yIGh0dHBzOi8vZ2l0aHViLmNvbS9MZWFmbGV0L0xlYWZsZXQvaXNzdWVzLzEzN1xyXG5cdFx0aWYgKCFhbmRyb2lkKSB7XHJcblx0XHRcdHRoaXMub24oJ3RpbGV1bmxvYWQnLCB0aGlzLl9vblRpbGVSZW1vdmUpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0VXJsKHVybDogU3RyaW5nLCBub1JlZHJhdz86IEJvb2xlYW4pOiB0aGlzXHJcblx0Ly8gVXBkYXRlcyB0aGUgbGF5ZXIncyBVUkwgdGVtcGxhdGUgYW5kIHJlZHJhd3MgaXQgKHVubGVzcyBgbm9SZWRyYXdgIGlzIHNldCB0byBgdHJ1ZWApLlxyXG5cdHNldFVybDogZnVuY3Rpb24gKHVybCwgbm9SZWRyYXcpIHtcclxuXHRcdHRoaXMuX3VybCA9IHVybDtcclxuXHJcblx0XHRpZiAoIW5vUmVkcmF3KSB7XHJcblx0XHRcdHRoaXMucmVkcmF3KCk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGNyZWF0ZVRpbGUoY29vcmRzOiBPYmplY3QsIGRvbmU/OiBGdW5jdGlvbik6IEhUTUxFbGVtZW50XHJcblx0Ly8gQ2FsbGVkIG9ubHkgaW50ZXJuYWxseSwgb3ZlcnJpZGVzIEdyaWRMYXllcidzIFtgY3JlYXRlVGlsZSgpYF0oI2dyaWRsYXllci1jcmVhdGV0aWxlKVxyXG5cdC8vIHRvIHJldHVybiBhbiBgPGltZz5gIEhUTUwgZWxlbWVudCB3aXRoIHRoZSBhcHByb3ByaWF0ZSBpbWFnZSBVUkwgZ2l2ZW4gYGNvb3Jkc2AuIFRoZSBgZG9uZWBcclxuXHQvLyBjYWxsYmFjayBpcyBjYWxsZWQgd2hlbiB0aGUgdGlsZSBoYXMgYmVlbiBsb2FkZWQuXHJcblx0Y3JlYXRlVGlsZTogZnVuY3Rpb24gKGNvb3JkcywgZG9uZSkge1xyXG5cdFx0dmFyIHRpbGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbWcnKTtcclxuXHJcblx0XHRvbih0aWxlLCAnbG9hZCcsIGJpbmQodGhpcy5fdGlsZU9uTG9hZCwgdGhpcywgZG9uZSwgdGlsZSkpO1xyXG5cdFx0b24odGlsZSwgJ2Vycm9yJywgYmluZCh0aGlzLl90aWxlT25FcnJvciwgdGhpcywgZG9uZSwgdGlsZSkpO1xyXG5cclxuXHRcdGlmICh0aGlzLm9wdGlvbnMuY3Jvc3NPcmlnaW4pIHtcclxuXHRcdFx0dGlsZS5jcm9zc09yaWdpbiA9ICcnO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8qXHJcblx0XHQgQWx0IHRhZyBpcyBzZXQgdG8gZW1wdHkgc3RyaW5nIHRvIGtlZXAgc2NyZWVuIHJlYWRlcnMgZnJvbSByZWFkaW5nIFVSTCBhbmQgZm9yIGNvbXBsaWFuY2UgcmVhc29uc1xyXG5cdFx0IGh0dHA6Ly93d3cudzMub3JnL1RSL1dDQUcyMC1URUNIUy9INjdcclxuXHRcdCovXHJcblx0XHR0aWxlLmFsdCA9ICcnO1xyXG5cclxuXHRcdC8qXHJcblx0XHQgU2V0IHJvbGU9XCJwcmVzZW50YXRpb25cIiB0byBmb3JjZSBzY3JlZW4gcmVhZGVycyB0byBpZ25vcmUgdGhpc1xyXG5cdFx0IGh0dHBzOi8vd3d3LnczLm9yZy9UUi93YWktYXJpYS9yb2xlcyN0ZXh0YWx0ZXJuYXRpdmVjb21wdXRhdGlvblxyXG5cdFx0Ki9cclxuXHRcdHRpbGUuc2V0QXR0cmlidXRlKCdyb2xlJywgJ3ByZXNlbnRhdGlvbicpO1xyXG5cclxuXHRcdHRpbGUuc3JjID0gdGhpcy5nZXRUaWxlVXJsKGNvb3Jkcyk7XHJcblxyXG5cdFx0cmV0dXJuIHRpbGU7XHJcblx0fSxcclxuXHJcblx0Ly8gQHNlY3Rpb24gRXh0ZW5zaW9uIG1ldGhvZHNcclxuXHQvLyBAdW5pbmhlcml0YWJsZVxyXG5cdC8vIExheWVycyBleHRlbmRpbmcgYFRpbGVMYXllcmAgbWlnaHQgcmVpbXBsZW1lbnQgdGhlIGZvbGxvd2luZyBtZXRob2QuXHJcblx0Ly8gQG1ldGhvZCBnZXRUaWxlVXJsKGNvb3JkczogT2JqZWN0KTogU3RyaW5nXHJcblx0Ly8gQ2FsbGVkIG9ubHkgaW50ZXJuYWxseSwgcmV0dXJucyB0aGUgVVJMIGZvciBhIHRpbGUgZ2l2ZW4gaXRzIGNvb3JkaW5hdGVzLlxyXG5cdC8vIENsYXNzZXMgZXh0ZW5kaW5nIGBUaWxlTGF5ZXJgIGNhbiBvdmVycmlkZSB0aGlzIGZ1bmN0aW9uIHRvIHByb3ZpZGUgY3VzdG9tIHRpbGUgVVJMIG5hbWluZyBzY2hlbWVzLlxyXG5cdGdldFRpbGVVcmw6IGZ1bmN0aW9uIChjb29yZHMpIHtcclxuXHRcdHZhciBkYXRhID0ge1xyXG5cdFx0XHRyOiByZXRpbmEgPyAnQDJ4JyA6ICcnLFxyXG5cdFx0XHRzOiB0aGlzLl9nZXRTdWJkb21haW4oY29vcmRzKSxcclxuXHRcdFx0eDogY29vcmRzLngsXHJcblx0XHRcdHk6IGNvb3Jkcy55LFxyXG5cdFx0XHR6OiB0aGlzLl9nZXRab29tRm9yVXJsKClcclxuXHRcdH07XHJcblx0XHRpZiAodGhpcy5fbWFwICYmICF0aGlzLl9tYXAub3B0aW9ucy5jcnMuaW5maW5pdGUpIHtcclxuXHRcdFx0dmFyIGludmVydGVkWSA9IHRoaXMuX2dsb2JhbFRpbGVSYW5nZS5tYXgueSAtIGNvb3Jkcy55O1xyXG5cdFx0XHRpZiAodGhpcy5vcHRpb25zLnRtcykge1xyXG5cdFx0XHRcdGRhdGFbJ3knXSA9IGludmVydGVkWTtcclxuXHRcdFx0fVxyXG5cdFx0XHRkYXRhWycteSddID0gaW52ZXJ0ZWRZO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0ZW1wbGF0ZSh0aGlzLl91cmwsIGV4dGVuZChkYXRhLCB0aGlzLm9wdGlvbnMpKTtcclxuXHR9LFxyXG5cclxuXHRfdGlsZU9uTG9hZDogZnVuY3Rpb24gKGRvbmUsIHRpbGUpIHtcclxuXHRcdC8vIEZvciBodHRwczovL2dpdGh1Yi5jb20vTGVhZmxldC9MZWFmbGV0L2lzc3Vlcy8zMzMyXHJcblx0XHRpZiAoaWVsdDkpIHtcclxuXHRcdFx0c2V0VGltZW91dChiaW5kKGRvbmUsIHRoaXMsIG51bGwsIHRpbGUpLCAwKTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGRvbmUobnVsbCwgdGlsZSk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X3RpbGVPbkVycm9yOiBmdW5jdGlvbiAoZG9uZSwgdGlsZSwgZSkge1xyXG5cdFx0dmFyIGVycm9yVXJsID0gdGhpcy5vcHRpb25zLmVycm9yVGlsZVVybDtcclxuXHRcdGlmIChlcnJvclVybCAmJiB0aWxlLmdldEF0dHJpYnV0ZSgnc3JjJykgIT09IGVycm9yVXJsKSB7XHJcblx0XHRcdHRpbGUuc3JjID0gZXJyb3JVcmw7XHJcblx0XHR9XHJcblx0XHRkb25lKGUsIHRpbGUpO1xyXG5cdH0sXHJcblxyXG5cdF9vblRpbGVSZW1vdmU6IGZ1bmN0aW9uIChlKSB7XHJcblx0XHRlLnRpbGUub25sb2FkID0gbnVsbDtcclxuXHR9LFxyXG5cclxuXHRfZ2V0Wm9vbUZvclVybDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIHpvb20gPSB0aGlzLl90aWxlWm9vbSxcclxuXHRcdG1heFpvb20gPSB0aGlzLm9wdGlvbnMubWF4Wm9vbSxcclxuXHRcdHpvb21SZXZlcnNlID0gdGhpcy5vcHRpb25zLnpvb21SZXZlcnNlLFxyXG5cdFx0em9vbU9mZnNldCA9IHRoaXMub3B0aW9ucy56b29tT2Zmc2V0O1xyXG5cclxuXHRcdGlmICh6b29tUmV2ZXJzZSkge1xyXG5cdFx0XHR6b29tID0gbWF4Wm9vbSAtIHpvb207XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHpvb20gKyB6b29tT2Zmc2V0O1xyXG5cdH0sXHJcblxyXG5cdF9nZXRTdWJkb21haW46IGZ1bmN0aW9uICh0aWxlUG9pbnQpIHtcclxuXHRcdHZhciBpbmRleCA9IE1hdGguYWJzKHRpbGVQb2ludC54ICsgdGlsZVBvaW50LnkpICUgdGhpcy5vcHRpb25zLnN1YmRvbWFpbnMubGVuZ3RoO1xyXG5cdFx0cmV0dXJuIHRoaXMub3B0aW9ucy5zdWJkb21haW5zW2luZGV4XTtcclxuXHR9LFxyXG5cclxuXHQvLyBzdG9wcyBsb2FkaW5nIGFsbCB0aWxlcyBpbiB0aGUgYmFja2dyb3VuZCBsYXllclxyXG5cdF9hYm9ydExvYWRpbmc6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBpLCB0aWxlO1xyXG5cdFx0Zm9yIChpIGluIHRoaXMuX3RpbGVzKSB7XHJcblx0XHRcdGlmICh0aGlzLl90aWxlc1tpXS5jb29yZHMueiAhPT0gdGhpcy5fdGlsZVpvb20pIHtcclxuXHRcdFx0XHR0aWxlID0gdGhpcy5fdGlsZXNbaV0uZWw7XHJcblxyXG5cdFx0XHRcdHRpbGUub25sb2FkID0gZmFsc2VGbjtcclxuXHRcdFx0XHR0aWxlLm9uZXJyb3IgPSBmYWxzZUZuO1xyXG5cclxuXHRcdFx0XHRpZiAoIXRpbGUuY29tcGxldGUpIHtcclxuXHRcdFx0XHRcdHRpbGUuc3JjID0gZW1wdHlJbWFnZVVybDtcclxuXHRcdFx0XHRcdHJlbW92ZSh0aWxlKTtcclxuXHRcdFx0XHRcdGRlbGV0ZSB0aGlzLl90aWxlc1tpXTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcbn0pO1xyXG5cclxuXHJcbi8vIEBmYWN0b3J5IEwudGlsZWxheWVyKHVybFRlbXBsYXRlOiBTdHJpbmcsIG9wdGlvbnM/OiBUaWxlTGF5ZXIgb3B0aW9ucylcclxuLy8gSW5zdGFudGlhdGVzIGEgdGlsZSBsYXllciBvYmplY3QgZ2l2ZW4gYSBgVVJMIHRlbXBsYXRlYCBhbmQgb3B0aW9uYWxseSBhbiBvcHRpb25zIG9iamVjdC5cclxuXHJcbmZ1bmN0aW9uIHRpbGVMYXllcih1cmwsIG9wdGlvbnMpIHtcclxuXHRyZXR1cm4gbmV3IFRpbGVMYXllcih1cmwsIG9wdGlvbnMpO1xyXG59XG5cbi8qXHJcbiAqIEBjbGFzcyBUaWxlTGF5ZXIuV01TXHJcbiAqIEBpbmhlcml0cyBUaWxlTGF5ZXJcclxuICogQGFrYSBMLlRpbGVMYXllci5XTVNcclxuICogVXNlZCB0byBkaXNwbGF5IFtXTVNdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1dlYl9NYXBfU2VydmljZSkgc2VydmljZXMgYXMgdGlsZSBsYXllcnMgb24gdGhlIG1hcC4gRXh0ZW5kcyBgVGlsZUxheWVyYC5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogYGBganNcclxuICogdmFyIG5leHJhZCA9IEwudGlsZUxheWVyLndtcyhcImh0dHA6Ly9tZXNvbmV0LmFncm9uLmlhc3RhdGUuZWR1L2NnaS1iaW4vd21zL25leHJhZC9uMHIuY2dpXCIsIHtcclxuICogXHRsYXllcnM6ICduZXhyYWQtbjByLTkwMDkxMycsXHJcbiAqIFx0Zm9ybWF0OiAnaW1hZ2UvcG5nJyxcclxuICogXHR0cmFuc3BhcmVudDogdHJ1ZSxcclxuICogXHRhdHRyaWJ1dGlvbjogXCJXZWF0aGVyIGRhdGEgwqkgMjAxMiBJRU0gTmV4cmFkXCJcclxuICogfSk7XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcbnZhciBUaWxlTGF5ZXJXTVMgPSBUaWxlTGF5ZXIuZXh0ZW5kKHtcclxuXHJcblx0Ly8gQHNlY3Rpb25cclxuXHQvLyBAYWthIFRpbGVMYXllci5XTVMgb3B0aW9uc1xyXG5cdC8vIElmIGFueSBjdXN0b20gb3B0aW9ucyBub3QgZG9jdW1lbnRlZCBoZXJlIGFyZSB1c2VkLCB0aGV5IHdpbGwgYmUgc2VudCB0byB0aGVcclxuXHQvLyBXTVMgc2VydmVyIGFzIGV4dHJhIHBhcmFtZXRlcnMgaW4gZWFjaCByZXF1ZXN0IFVSTC4gVGhpcyBjYW4gYmUgdXNlZnVsIGZvclxyXG5cdC8vIFtub24tc3RhbmRhcmQgdmVuZG9yIFdNUyBwYXJhbWV0ZXJzXShodHRwOi8vZG9jcy5nZW9zZXJ2ZXIub3JnL3N0YWJsZS9lbi91c2VyL3NlcnZpY2VzL3dtcy92ZW5kb3IuaHRtbCkuXHJcblx0ZGVmYXVsdFdtc1BhcmFtczoge1xyXG5cdFx0c2VydmljZTogJ1dNUycsXHJcblx0XHRyZXF1ZXN0OiAnR2V0TWFwJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGxheWVyczogU3RyaW5nID0gJydcclxuXHRcdC8vICoqKHJlcXVpcmVkKSoqIENvbW1hLXNlcGFyYXRlZCBsaXN0IG9mIFdNUyBsYXllcnMgdG8gc2hvdy5cclxuXHRcdGxheWVyczogJycsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBzdHlsZXM6IFN0cmluZyA9ICcnXHJcblx0XHQvLyBDb21tYS1zZXBhcmF0ZWQgbGlzdCBvZiBXTVMgc3R5bGVzLlxyXG5cdFx0c3R5bGVzOiAnJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGZvcm1hdDogU3RyaW5nID0gJ2ltYWdlL2pwZWcnXHJcblx0XHQvLyBXTVMgaW1hZ2UgZm9ybWF0ICh1c2UgYCdpbWFnZS9wbmcnYCBmb3IgbGF5ZXJzIHdpdGggdHJhbnNwYXJlbmN5KS5cclxuXHRcdGZvcm1hdDogJ2ltYWdlL2pwZWcnLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gdHJhbnNwYXJlbnQ6IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gSWYgYHRydWVgLCB0aGUgV01TIHNlcnZpY2Ugd2lsbCByZXR1cm4gaW1hZ2VzIHdpdGggdHJhbnNwYXJlbmN5LlxyXG5cdFx0dHJhbnNwYXJlbnQ6IGZhbHNlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gdmVyc2lvbjogU3RyaW5nID0gJzEuMS4xJ1xyXG5cdFx0Ly8gVmVyc2lvbiBvZiB0aGUgV01TIHNlcnZpY2UgdG8gdXNlXHJcblx0XHR2ZXJzaW9uOiAnMS4xLjEnXHJcblx0fSxcclxuXHJcblx0b3B0aW9uczoge1xyXG5cdFx0Ly8gQG9wdGlvbiBjcnM6IENSUyA9IG51bGxcclxuXHRcdC8vIENvb3JkaW5hdGUgUmVmZXJlbmNlIFN5c3RlbSB0byB1c2UgZm9yIHRoZSBXTVMgcmVxdWVzdHMsIGRlZmF1bHRzIHRvXHJcblx0XHQvLyBtYXAgQ1JTLiBEb24ndCBjaGFuZ2UgdGhpcyBpZiB5b3UncmUgbm90IHN1cmUgd2hhdCBpdCBtZWFucy5cclxuXHRcdGNyczogbnVsbCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHVwcGVyY2FzZTogQm9vbGVhbiA9IGZhbHNlXHJcblx0XHQvLyBJZiBgdHJ1ZWAsIFdNUyByZXF1ZXN0IHBhcmFtZXRlciBrZXlzIHdpbGwgYmUgdXBwZXJjYXNlLlxyXG5cdFx0dXBwZXJjYXNlOiBmYWxzZVxyXG5cdH0sXHJcblxyXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uICh1cmwsIG9wdGlvbnMpIHtcclxuXHJcblx0XHR0aGlzLl91cmwgPSB1cmw7XHJcblxyXG5cdFx0dmFyIHdtc1BhcmFtcyA9IGV4dGVuZCh7fSwgdGhpcy5kZWZhdWx0V21zUGFyYW1zKTtcclxuXHJcblx0XHQvLyBhbGwga2V5cyB0aGF0IGFyZSBub3QgVGlsZUxheWVyIG9wdGlvbnMgZ28gdG8gV01TIHBhcmFtc1xyXG5cdFx0Zm9yICh2YXIgaSBpbiBvcHRpb25zKSB7XHJcblx0XHRcdGlmICghKGkgaW4gdGhpcy5vcHRpb25zKSkge1xyXG5cdFx0XHRcdHdtc1BhcmFtc1tpXSA9IG9wdGlvbnNbaV07XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRvcHRpb25zID0gc2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcclxuXHJcblx0XHR2YXIgcmVhbFJldGluYSA9IG9wdGlvbnMuZGV0ZWN0UmV0aW5hICYmIHJldGluYSA/IDIgOiAxO1xyXG5cdFx0dmFyIHRpbGVTaXplID0gdGhpcy5nZXRUaWxlU2l6ZSgpO1xyXG5cdFx0d21zUGFyYW1zLndpZHRoID0gdGlsZVNpemUueCAqIHJlYWxSZXRpbmE7XHJcblx0XHR3bXNQYXJhbXMuaGVpZ2h0ID0gdGlsZVNpemUueSAqIHJlYWxSZXRpbmE7XHJcblxyXG5cdFx0dGhpcy53bXNQYXJhbXMgPSB3bXNQYXJhbXM7XHJcblx0fSxcclxuXHJcblx0b25BZGQ6IGZ1bmN0aW9uIChtYXApIHtcclxuXHJcblx0XHR0aGlzLl9jcnMgPSB0aGlzLm9wdGlvbnMuY3JzIHx8IG1hcC5vcHRpb25zLmNycztcclxuXHRcdHRoaXMuX3dtc1ZlcnNpb24gPSBwYXJzZUZsb2F0KHRoaXMud21zUGFyYW1zLnZlcnNpb24pO1xyXG5cclxuXHRcdHZhciBwcm9qZWN0aW9uS2V5ID0gdGhpcy5fd21zVmVyc2lvbiA+PSAxLjMgPyAnY3JzJyA6ICdzcnMnO1xyXG5cdFx0dGhpcy53bXNQYXJhbXNbcHJvamVjdGlvbktleV0gPSB0aGlzLl9jcnMuY29kZTtcclxuXHJcblx0XHRUaWxlTGF5ZXIucHJvdG90eXBlLm9uQWRkLmNhbGwodGhpcywgbWFwKTtcclxuXHR9LFxyXG5cclxuXHRnZXRUaWxlVXJsOiBmdW5jdGlvbiAoY29vcmRzKSB7XHJcblxyXG5cdFx0dmFyIHRpbGVCb3VuZHMgPSB0aGlzLl90aWxlQ29vcmRzVG9Od1NlKGNvb3JkcyksXHJcblx0XHQgICAgY3JzID0gdGhpcy5fY3JzLFxyXG5cdFx0ICAgIGJvdW5kcyA9IHRvQm91bmRzKGNycy5wcm9qZWN0KHRpbGVCb3VuZHNbMF0pLCBjcnMucHJvamVjdCh0aWxlQm91bmRzWzFdKSksXHJcblx0XHQgICAgbWluID0gYm91bmRzLm1pbixcclxuXHRcdCAgICBtYXggPSBib3VuZHMubWF4LFxyXG5cdFx0ICAgIGJib3ggPSAodGhpcy5fd21zVmVyc2lvbiA+PSAxLjMgJiYgdGhpcy5fY3JzID09PSBFUFNHNDMyNiA/XHJcblx0XHQgICAgW21pbi55LCBtaW4ueCwgbWF4LnksIG1heC54XSA6XHJcblx0XHQgICAgW21pbi54LCBtaW4ueSwgbWF4LngsIG1heC55XSkuam9pbignLCcpLFxyXG5cdFx0dXJsID0gTC5UaWxlTGF5ZXIucHJvdG90eXBlLmdldFRpbGVVcmwuY2FsbCh0aGlzLCBjb29yZHMpO1xyXG5cdFx0cmV0dXJuIHVybCArXHJcblx0XHRcdGdldFBhcmFtU3RyaW5nKHRoaXMud21zUGFyYW1zLCB1cmwsIHRoaXMub3B0aW9ucy51cHBlcmNhc2UpICtcclxuXHRcdFx0KHRoaXMub3B0aW9ucy51cHBlcmNhc2UgPyAnJkJCT1g9JyA6ICcmYmJveD0nKSArIGJib3g7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBzZXRQYXJhbXMocGFyYW1zOiBPYmplY3QsIG5vUmVkcmF3PzogQm9vbGVhbik6IHRoaXNcclxuXHQvLyBNZXJnZXMgYW4gb2JqZWN0IHdpdGggdGhlIG5ldyBwYXJhbWV0ZXJzIGFuZCByZS1yZXF1ZXN0cyB0aWxlcyBvbiB0aGUgY3VycmVudCBzY3JlZW4gKHVubGVzcyBgbm9SZWRyYXdgIHdhcyBzZXQgdG8gdHJ1ZSkuXHJcblx0c2V0UGFyYW1zOiBmdW5jdGlvbiAocGFyYW1zLCBub1JlZHJhdykge1xyXG5cclxuXHRcdGV4dGVuZCh0aGlzLndtc1BhcmFtcywgcGFyYW1zKTtcclxuXHJcblx0XHRpZiAoIW5vUmVkcmF3KSB7XHJcblx0XHRcdHRoaXMucmVkcmF3KCk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fVxyXG59KTtcclxuXHJcblxyXG4vLyBAZmFjdG9yeSBMLnRpbGVMYXllci53bXMoYmFzZVVybDogU3RyaW5nLCBvcHRpb25zOiBUaWxlTGF5ZXIuV01TIG9wdGlvbnMpXHJcbi8vIEluc3RhbnRpYXRlcyBhIFdNUyB0aWxlIGxheWVyIG9iamVjdCBnaXZlbiBhIGJhc2UgVVJMIG9mIHRoZSBXTVMgc2VydmljZSBhbmQgYSBXTVMgcGFyYW1ldGVycy9vcHRpb25zIG9iamVjdC5cclxuZnVuY3Rpb24gdGlsZUxheWVyV01TKHVybCwgb3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgVGlsZUxheWVyV01TKHVybCwgb3B0aW9ucyk7XHJcbn1cblxuVGlsZUxheWVyLldNUyA9IFRpbGVMYXllcldNUztcbnRpbGVMYXllci53bXMgPSB0aWxlTGF5ZXJXTVM7XG5cbi8qXG4gKiBAY2xhc3MgUmVuZGVyZXJcbiAqIEBpbmhlcml0cyBMYXllclxuICogQGFrYSBMLlJlbmRlcmVyXG4gKlxuICogQmFzZSBjbGFzcyBmb3IgdmVjdG9yIHJlbmRlcmVyIGltcGxlbWVudGF0aW9ucyAoYFNWR2AsIGBDYW52YXNgKS4gSGFuZGxlcyB0aGVcbiAqIERPTSBjb250YWluZXIgb2YgdGhlIHJlbmRlcmVyLCBpdHMgYm91bmRzLCBhbmQgaXRzIHpvb20gYW5pbWF0aW9uLlxuICpcbiAqIEEgYFJlbmRlcmVyYCB3b3JrcyBhcyBhbiBpbXBsaWNpdCBsYXllciBncm91cCBmb3IgYWxsIGBQYXRoYHMgLSB0aGUgcmVuZGVyZXJcbiAqIGl0c2VsZiBjYW4gYmUgYWRkZWQgb3IgcmVtb3ZlZCB0byB0aGUgbWFwLiBBbGwgcGF0aHMgdXNlIGEgcmVuZGVyZXIsIHdoaWNoIGNhblxuICogYmUgaW1wbGljaXQgKHRoZSBtYXAgd2lsbCBkZWNpZGUgdGhlIHR5cGUgb2YgcmVuZGVyZXIgYW5kIHVzZSBpdCBhdXRvbWF0aWNhbGx5KVxuICogb3IgZXhwbGljaXQgKHVzaW5nIHRoZSBbYHJlbmRlcmVyYF0oI3BhdGgtcmVuZGVyZXIpIG9wdGlvbiBvZiB0aGUgcGF0aCkuXG4gKlxuICogRG8gbm90IHVzZSB0aGlzIGNsYXNzIGRpcmVjdGx5LCB1c2UgYFNWR2AgYW5kIGBDYW52YXNgIGluc3RlYWQuXG4gKlxuICogQGV2ZW50IHVwZGF0ZTogRXZlbnRcbiAqIEZpcmVkIHdoZW4gdGhlIHJlbmRlcmVyIHVwZGF0ZXMgaXRzIGJvdW5kcywgY2VudGVyIGFuZCB6b29tLCBmb3IgZXhhbXBsZSB3aGVuXG4gKiBpdHMgbWFwIGhhcyBtb3ZlZFxuICovXG5cbnZhciBSZW5kZXJlciA9IExheWVyLmV4dGVuZCh7XG5cblx0Ly8gQHNlY3Rpb25cblx0Ly8gQGFrYSBSZW5kZXJlciBvcHRpb25zXG5cdG9wdGlvbnM6IHtcblx0XHQvLyBAb3B0aW9uIHBhZGRpbmc6IE51bWJlciA9IDAuMVxuXHRcdC8vIEhvdyBtdWNoIHRvIGV4dGVuZCB0aGUgY2xpcCBhcmVhIGFyb3VuZCB0aGUgbWFwIHZpZXcgKHJlbGF0aXZlIHRvIGl0cyBzaXplKVxuXHRcdC8vIGUuZy4gMC4xIHdvdWxkIGJlIDEwJSBvZiBtYXAgdmlldyBpbiBlYWNoIGRpcmVjdGlvblxuXHRcdHBhZGRpbmc6IDAuMSxcblxuXHRcdC8vIEBvcHRpb24gdG9sZXJhbmNlOiBOdW1iZXIgPSAwXG5cdFx0Ly8gSG93IG11Y2ggdG8gZXh0ZW5kIGNsaWNrIHRvbGVyYW5jZSByb3VuZCBhIHBhdGgvb2JqZWN0IG9uIHRoZSBtYXBcblx0XHR0b2xlcmFuY2UgOiAwXG5cdH0sXG5cblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcblx0XHRzZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xuXHRcdHN0YW1wKHRoaXMpO1xuXHRcdHRoaXMuX2xheWVycyA9IHRoaXMuX2xheWVycyB8fCB7fTtcblx0fSxcblxuXHRvbkFkZDogZnVuY3Rpb24gKCkge1xuXHRcdGlmICghdGhpcy5fY29udGFpbmVyKSB7XG5cdFx0XHR0aGlzLl9pbml0Q29udGFpbmVyKCk7IC8vIGRlZmluZWQgYnkgcmVuZGVyZXIgaW1wbGVtZW50YXRpb25zXG5cblx0XHRcdGlmICh0aGlzLl96b29tQW5pbWF0ZWQpIHtcblx0XHRcdFx0YWRkQ2xhc3ModGhpcy5fY29udGFpbmVyLCAnbGVhZmxldC16b29tLWFuaW1hdGVkJyk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5nZXRQYW5lKCkuYXBwZW5kQ2hpbGQodGhpcy5fY29udGFpbmVyKTtcblx0XHR0aGlzLl91cGRhdGUoKTtcblx0XHR0aGlzLm9uKCd1cGRhdGUnLCB0aGlzLl91cGRhdGVQYXRocywgdGhpcyk7XG5cdH0sXG5cblx0b25SZW1vdmU6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLm9mZigndXBkYXRlJywgdGhpcy5fdXBkYXRlUGF0aHMsIHRoaXMpO1xuXHRcdHRoaXMuX2Rlc3Ryb3lDb250YWluZXIoKTtcblx0fSxcblxuXHRnZXRFdmVudHM6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgZXZlbnRzID0ge1xuXHRcdFx0dmlld3Jlc2V0OiB0aGlzLl9yZXNldCxcblx0XHRcdHpvb206IHRoaXMuX29uWm9vbSxcblx0XHRcdG1vdmVlbmQ6IHRoaXMuX3VwZGF0ZSxcblx0XHRcdHpvb21lbmQ6IHRoaXMuX29uWm9vbUVuZFxuXHRcdH07XG5cdFx0aWYgKHRoaXMuX3pvb21BbmltYXRlZCkge1xuXHRcdFx0ZXZlbnRzLnpvb21hbmltID0gdGhpcy5fb25BbmltWm9vbTtcblx0XHR9XG5cdFx0cmV0dXJuIGV2ZW50cztcblx0fSxcblxuXHRfb25BbmltWm9vbTogZnVuY3Rpb24gKGV2KSB7XG5cdFx0dGhpcy5fdXBkYXRlVHJhbnNmb3JtKGV2LmNlbnRlciwgZXYuem9vbSk7XG5cdH0sXG5cblx0X29uWm9vbTogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3VwZGF0ZVRyYW5zZm9ybSh0aGlzLl9tYXAuZ2V0Q2VudGVyKCksIHRoaXMuX21hcC5nZXRab29tKCkpO1xuXHR9LFxuXG5cdF91cGRhdGVUcmFuc2Zvcm06IGZ1bmN0aW9uIChjZW50ZXIsIHpvb20pIHtcblx0XHR2YXIgc2NhbGUgPSB0aGlzLl9tYXAuZ2V0Wm9vbVNjYWxlKHpvb20sIHRoaXMuX3pvb20pLFxuXHRcdCAgICBwb3NpdGlvbiA9IGdldFBvc2l0aW9uKHRoaXMuX2NvbnRhaW5lciksXG5cdFx0ICAgIHZpZXdIYWxmID0gdGhpcy5fbWFwLmdldFNpemUoKS5tdWx0aXBseUJ5KDAuNSArIHRoaXMub3B0aW9ucy5wYWRkaW5nKSxcblx0XHQgICAgY3VycmVudENlbnRlclBvaW50ID0gdGhpcy5fbWFwLnByb2plY3QodGhpcy5fY2VudGVyLCB6b29tKSxcblx0XHQgICAgZGVzdENlbnRlclBvaW50ID0gdGhpcy5fbWFwLnByb2plY3QoY2VudGVyLCB6b29tKSxcblx0XHQgICAgY2VudGVyT2Zmc2V0ID0gZGVzdENlbnRlclBvaW50LnN1YnRyYWN0KGN1cnJlbnRDZW50ZXJQb2ludCksXG5cblx0XHQgICAgdG9wTGVmdE9mZnNldCA9IHZpZXdIYWxmLm11bHRpcGx5QnkoLXNjYWxlKS5hZGQocG9zaXRpb24pLmFkZCh2aWV3SGFsZikuc3VidHJhY3QoY2VudGVyT2Zmc2V0KTtcblxuXHRcdGlmIChhbnkzZCkge1xuXHRcdFx0c2V0VHJhbnNmb3JtKHRoaXMuX2NvbnRhaW5lciwgdG9wTGVmdE9mZnNldCwgc2NhbGUpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRzZXRQb3NpdGlvbih0aGlzLl9jb250YWluZXIsIHRvcExlZnRPZmZzZXQpO1xuXHRcdH1cblx0fSxcblxuXHRfcmVzZXQ6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl91cGRhdGUoKTtcblx0XHR0aGlzLl91cGRhdGVUcmFuc2Zvcm0odGhpcy5fY2VudGVyLCB0aGlzLl96b29tKTtcblxuXHRcdGZvciAodmFyIGlkIGluIHRoaXMuX2xheWVycykge1xuXHRcdFx0dGhpcy5fbGF5ZXJzW2lkXS5fcmVzZXQoKTtcblx0XHR9XG5cdH0sXG5cblx0X29uWm9vbUVuZDogZnVuY3Rpb24gKCkge1xuXHRcdGZvciAodmFyIGlkIGluIHRoaXMuX2xheWVycykge1xuXHRcdFx0dGhpcy5fbGF5ZXJzW2lkXS5fcHJvamVjdCgpO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlUGF0aHM6IGZ1bmN0aW9uICgpIHtcblx0XHRmb3IgKHZhciBpZCBpbiB0aGlzLl9sYXllcnMpIHtcblx0XHRcdHRoaXMuX2xheWVyc1tpZF0uX3VwZGF0ZSgpO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlOiBmdW5jdGlvbiAoKSB7XG5cdFx0Ly8gVXBkYXRlIHBpeGVsIGJvdW5kcyBvZiByZW5kZXJlciBjb250YWluZXIgKGZvciBwb3NpdGlvbmluZy9zaXppbmcvY2xpcHBpbmcgbGF0ZXIpXG5cdFx0Ly8gU3ViY2xhc3NlcyBhcmUgcmVzcG9uc2libGUgb2YgZmlyaW5nIHRoZSAndXBkYXRlJyBldmVudC5cblx0XHR2YXIgcCA9IHRoaXMub3B0aW9ucy5wYWRkaW5nLFxuXHRcdCAgICBzaXplID0gdGhpcy5fbWFwLmdldFNpemUoKSxcblx0XHQgICAgbWluID0gdGhpcy5fbWFwLmNvbnRhaW5lclBvaW50VG9MYXllclBvaW50KHNpemUubXVsdGlwbHlCeSgtcCkpLnJvdW5kKCk7XG5cblx0XHR0aGlzLl9ib3VuZHMgPSBuZXcgQm91bmRzKG1pbiwgbWluLmFkZChzaXplLm11bHRpcGx5QnkoMSArIHAgKiAyKSkucm91bmQoKSk7XG5cblx0XHR0aGlzLl9jZW50ZXIgPSB0aGlzLl9tYXAuZ2V0Q2VudGVyKCk7XG5cdFx0dGhpcy5fem9vbSA9IHRoaXMuX21hcC5nZXRab29tKCk7XG5cdH1cbn0pO1xuXG4vKlxuICogQGNsYXNzIENhbnZhc1xuICogQGluaGVyaXRzIFJlbmRlcmVyXG4gKiBAYWthIEwuQ2FudmFzXG4gKlxuICogQWxsb3dzIHZlY3RvciBsYXllcnMgdG8gYmUgZGlzcGxheWVkIHdpdGggW2A8Y2FudmFzPmBdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL0FQSS9DYW52YXNfQVBJKS5cbiAqIEluaGVyaXRzIGBSZW5kZXJlcmAuXG4gKlxuICogRHVlIHRvIFt0ZWNobmljYWwgbGltaXRhdGlvbnNdKGh0dHA6Ly9jYW5pdXNlLmNvbS8jc2VhcmNoPWNhbnZhcyksIENhbnZhcyBpcyBub3RcbiAqIGF2YWlsYWJsZSBpbiBhbGwgd2ViIGJyb3dzZXJzLCBub3RhYmx5IElFOCwgYW5kIG92ZXJsYXBwaW5nIGdlb21ldHJpZXMgbWlnaHRcbiAqIG5vdCBkaXNwbGF5IHByb3Blcmx5IGluIHNvbWUgZWRnZSBjYXNlcy5cbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIFVzZSBDYW52YXMgYnkgZGVmYXVsdCBmb3IgYWxsIHBhdGhzIGluIHRoZSBtYXA6XG4gKlxuICogYGBganNcbiAqIHZhciBtYXAgPSBMLm1hcCgnbWFwJywge1xuICogXHRyZW5kZXJlcjogTC5jYW52YXMoKVxuICogfSk7XG4gKiBgYGBcbiAqXG4gKiBVc2UgYSBDYW52YXMgcmVuZGVyZXIgd2l0aCBleHRyYSBwYWRkaW5nIGZvciBzcGVjaWZpYyB2ZWN0b3IgZ2VvbWV0cmllczpcbiAqXG4gKiBgYGBqc1xuICogdmFyIG1hcCA9IEwubWFwKCdtYXAnKTtcbiAqIHZhciBteVJlbmRlcmVyID0gTC5jYW52YXMoeyBwYWRkaW5nOiAwLjUgfSk7XG4gKiB2YXIgbGluZSA9IEwucG9seWxpbmUoIGNvb3JkaW5hdGVzLCB7IHJlbmRlcmVyOiBteVJlbmRlcmVyIH0gKTtcbiAqIHZhciBjaXJjbGUgPSBMLmNpcmNsZSggY2VudGVyLCB7IHJlbmRlcmVyOiBteVJlbmRlcmVyIH0gKTtcbiAqIGBgYFxuICovXG5cbnZhciBDYW52YXMgPSBSZW5kZXJlci5leHRlbmQoe1xuXHRnZXRFdmVudHM6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgZXZlbnRzID0gUmVuZGVyZXIucHJvdG90eXBlLmdldEV2ZW50cy5jYWxsKHRoaXMpO1xuXHRcdGV2ZW50cy52aWV3cHJlcmVzZXQgPSB0aGlzLl9vblZpZXdQcmVSZXNldDtcblx0XHRyZXR1cm4gZXZlbnRzO1xuXHR9LFxuXG5cdF9vblZpZXdQcmVSZXNldDogZnVuY3Rpb24gKCkge1xuXHRcdC8vIFNldCBhIGZsYWcgc28gdGhhdCBhIHZpZXdwcmVyZXNldCttb3ZlZW5kK3ZpZXdyZXNldCBvbmx5IHVwZGF0ZXMmcmVkcmF3cyBvbmNlXG5cdFx0dGhpcy5fcG9zdHBvbmVVcGRhdGVQYXRocyA9IHRydWU7XG5cdH0sXG5cblx0b25BZGQ6IGZ1bmN0aW9uICgpIHtcblx0XHRSZW5kZXJlci5wcm90b3R5cGUub25BZGQuY2FsbCh0aGlzKTtcblxuXHRcdC8vIFJlZHJhdyB2ZWN0b3JzIHNpbmNlIGNhbnZhcyBpcyBjbGVhcmVkIHVwb24gcmVtb3ZhbCxcblx0XHQvLyBpbiBjYXNlIG9mIHJlbW92aW5nIHRoZSByZW5kZXJlciBpdHNlbGYgZnJvbSB0aGUgbWFwLlxuXHRcdHRoaXMuX2RyYXcoKTtcblx0fSxcblxuXHRfaW5pdENvbnRhaW5lcjogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBjb250YWluZXIgPSB0aGlzLl9jb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdjYW52YXMnKTtcblxuXHRcdG9uKGNvbnRhaW5lciwgJ21vdXNlbW92ZScsIHRocm90dGxlKHRoaXMuX29uTW91c2VNb3ZlLCAzMiwgdGhpcyksIHRoaXMpO1xuXHRcdG9uKGNvbnRhaW5lciwgJ2NsaWNrIGRibGNsaWNrIG1vdXNlZG93biBtb3VzZXVwIGNvbnRleHRtZW51JywgdGhpcy5fb25DbGljaywgdGhpcyk7XG5cdFx0b24oY29udGFpbmVyLCAnbW91c2VvdXQnLCB0aGlzLl9oYW5kbGVNb3VzZU91dCwgdGhpcyk7XG5cblx0XHR0aGlzLl9jdHggPSBjb250YWluZXIuZ2V0Q29udGV4dCgnMmQnKTtcblx0fSxcblxuXHRfZGVzdHJveUNvbnRhaW5lcjogZnVuY3Rpb24gKCkge1xuXHRcdGRlbGV0ZSB0aGlzLl9jdHg7XG5cdFx0cmVtb3ZlKHRoaXMuX2NvbnRhaW5lcik7XG5cdFx0b2ZmKHRoaXMuX2NvbnRhaW5lcik7XG5cdFx0ZGVsZXRlIHRoaXMuX2NvbnRhaW5lcjtcblx0fSxcblxuXHRfdXBkYXRlUGF0aHM6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fcG9zdHBvbmVVcGRhdGVQYXRocykgeyByZXR1cm47IH1cblxuXHRcdHZhciBsYXllcjtcblx0XHR0aGlzLl9yZWRyYXdCb3VuZHMgPSBudWxsO1xuXHRcdGZvciAodmFyIGlkIGluIHRoaXMuX2xheWVycykge1xuXHRcdFx0bGF5ZXIgPSB0aGlzLl9sYXllcnNbaWRdO1xuXHRcdFx0bGF5ZXIuX3VwZGF0ZSgpO1xuXHRcdH1cblx0XHR0aGlzLl9yZWRyYXcoKTtcblx0fSxcblxuXHRfdXBkYXRlOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX21hcC5fYW5pbWF0aW5nWm9vbSAmJiB0aGlzLl9ib3VuZHMpIHsgcmV0dXJuOyB9XG5cblx0XHR0aGlzLl9kcmF3bkxheWVycyA9IHt9O1xuXG5cdFx0UmVuZGVyZXIucHJvdG90eXBlLl91cGRhdGUuY2FsbCh0aGlzKTtcblxuXHRcdHZhciBiID0gdGhpcy5fYm91bmRzLFxuXHRcdCAgICBjb250YWluZXIgPSB0aGlzLl9jb250YWluZXIsXG5cdFx0ICAgIHNpemUgPSBiLmdldFNpemUoKSxcblx0XHQgICAgbSA9IHJldGluYSA/IDIgOiAxO1xuXG5cdFx0c2V0UG9zaXRpb24oY29udGFpbmVyLCBiLm1pbik7XG5cblx0XHQvLyBzZXQgY2FudmFzIHNpemUgKGFsc28gY2xlYXJpbmcgaXQpOyB1c2UgZG91YmxlIHNpemUgb24gcmV0aW5hXG5cdFx0Y29udGFpbmVyLndpZHRoID0gbSAqIHNpemUueDtcblx0XHRjb250YWluZXIuaGVpZ2h0ID0gbSAqIHNpemUueTtcblx0XHRjb250YWluZXIuc3R5bGUud2lkdGggPSBzaXplLnggKyAncHgnO1xuXHRcdGNvbnRhaW5lci5zdHlsZS5oZWlnaHQgPSBzaXplLnkgKyAncHgnO1xuXG5cdFx0aWYgKHJldGluYSkge1xuXHRcdFx0dGhpcy5fY3R4LnNjYWxlKDIsIDIpO1xuXHRcdH1cblxuXHRcdC8vIHRyYW5zbGF0ZSBzbyB3ZSB1c2UgdGhlIHNhbWUgcGF0aCBjb29yZGluYXRlcyBhZnRlciBjYW52YXMgZWxlbWVudCBtb3Zlc1xuXHRcdHRoaXMuX2N0eC50cmFuc2xhdGUoLWIubWluLngsIC1iLm1pbi55KTtcblxuXHRcdC8vIFRlbGwgcGF0aHMgdG8gcmVkcmF3IHRoZW1zZWx2ZXNcblx0XHR0aGlzLmZpcmUoJ3VwZGF0ZScpO1xuXHR9LFxuXG5cdF9yZXNldDogZnVuY3Rpb24gKCkge1xuXHRcdFJlbmRlcmVyLnByb3RvdHlwZS5fcmVzZXQuY2FsbCh0aGlzKTtcblxuXHRcdGlmICh0aGlzLl9wb3N0cG9uZVVwZGF0ZVBhdGhzKSB7XG5cdFx0XHR0aGlzLl9wb3N0cG9uZVVwZGF0ZVBhdGhzID0gZmFsc2U7XG5cdFx0XHR0aGlzLl91cGRhdGVQYXRocygpO1xuXHRcdH1cblx0fSxcblxuXHRfaW5pdFBhdGg6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHRoaXMuX3VwZGF0ZURhc2hBcnJheShsYXllcik7XG5cdFx0dGhpcy5fbGF5ZXJzW3N0YW1wKGxheWVyKV0gPSBsYXllcjtcblxuXHRcdHZhciBvcmRlciA9IGxheWVyLl9vcmRlciA9IHtcblx0XHRcdGxheWVyOiBsYXllcixcblx0XHRcdHByZXY6IHRoaXMuX2RyYXdMYXN0LFxuXHRcdFx0bmV4dDogbnVsbFxuXHRcdH07XG5cdFx0aWYgKHRoaXMuX2RyYXdMYXN0KSB7IHRoaXMuX2RyYXdMYXN0Lm5leHQgPSBvcmRlcjsgfVxuXHRcdHRoaXMuX2RyYXdMYXN0ID0gb3JkZXI7XG5cdFx0dGhpcy5fZHJhd0ZpcnN0ID0gdGhpcy5fZHJhd0ZpcnN0IHx8IHRoaXMuX2RyYXdMYXN0O1xuXHR9LFxuXG5cdF9hZGRQYXRoOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR0aGlzLl9yZXF1ZXN0UmVkcmF3KGxheWVyKTtcblx0fSxcblxuXHRfcmVtb3ZlUGF0aDogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dmFyIG9yZGVyID0gbGF5ZXIuX29yZGVyO1xuXHRcdHZhciBuZXh0ID0gb3JkZXIubmV4dDtcblx0XHR2YXIgcHJldiA9IG9yZGVyLnByZXY7XG5cblx0XHRpZiAobmV4dCkge1xuXHRcdFx0bmV4dC5wcmV2ID0gcHJldjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5fZHJhd0xhc3QgPSBwcmV2O1xuXHRcdH1cblx0XHRpZiAocHJldikge1xuXHRcdFx0cHJldi5uZXh0ID0gbmV4dDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5fZHJhd0ZpcnN0ID0gbmV4dDtcblx0XHR9XG5cblx0XHRkZWxldGUgbGF5ZXIuX29yZGVyO1xuXG5cdFx0ZGVsZXRlIHRoaXMuX2xheWVyc1tMLnN0YW1wKGxheWVyKV07XG5cblx0XHR0aGlzLl9yZXF1ZXN0UmVkcmF3KGxheWVyKTtcblx0fSxcblxuXHRfdXBkYXRlUGF0aDogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0Ly8gUmVkcmF3IHRoZSB1bmlvbiBvZiB0aGUgbGF5ZXIncyBvbGQgcGl4ZWxcblx0XHQvLyBib3VuZHMgYW5kIHRoZSBuZXcgcGl4ZWwgYm91bmRzLlxuXHRcdHRoaXMuX2V4dGVuZFJlZHJhd0JvdW5kcyhsYXllcik7XG5cdFx0bGF5ZXIuX3Byb2plY3QoKTtcblx0XHRsYXllci5fdXBkYXRlKCk7XG5cdFx0Ly8gVGhlIHJlZHJhdyB3aWxsIGV4dGVuZCB0aGUgcmVkcmF3IGJvdW5kc1xuXHRcdC8vIHdpdGggdGhlIG5ldyBwaXhlbCBib3VuZHMuXG5cdFx0dGhpcy5fcmVxdWVzdFJlZHJhdyhsYXllcik7XG5cdH0sXG5cblx0X3VwZGF0ZVN0eWxlOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR0aGlzLl91cGRhdGVEYXNoQXJyYXkobGF5ZXIpO1xuXHRcdHRoaXMuX3JlcXVlc3RSZWRyYXcobGF5ZXIpO1xuXHR9LFxuXG5cdF91cGRhdGVEYXNoQXJyYXk6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdGlmIChsYXllci5vcHRpb25zLmRhc2hBcnJheSkge1xuXHRcdFx0dmFyIHBhcnRzID0gbGF5ZXIub3B0aW9ucy5kYXNoQXJyYXkuc3BsaXQoJywnKSxcblx0XHRcdCAgICBkYXNoQXJyYXkgPSBbXSxcblx0XHRcdCAgICBpO1xuXHRcdFx0Zm9yIChpID0gMDsgaSA8IHBhcnRzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRcdGRhc2hBcnJheS5wdXNoKE51bWJlcihwYXJ0c1tpXSkpO1xuXHRcdFx0fVxuXHRcdFx0bGF5ZXIub3B0aW9ucy5fZGFzaEFycmF5ID0gZGFzaEFycmF5O1xuXHRcdH1cblx0fSxcblxuXHRfcmVxdWVzdFJlZHJhdzogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0aWYgKCF0aGlzLl9tYXApIHsgcmV0dXJuOyB9XG5cblx0XHR0aGlzLl9leHRlbmRSZWRyYXdCb3VuZHMobGF5ZXIpO1xuXHRcdHRoaXMuX3JlZHJhd1JlcXVlc3QgPSB0aGlzLl9yZWRyYXdSZXF1ZXN0IHx8IHJlcXVlc3RBbmltRnJhbWUodGhpcy5fcmVkcmF3LCB0aGlzKTtcblx0fSxcblxuXHRfZXh0ZW5kUmVkcmF3Qm91bmRzOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHRpZiAobGF5ZXIuX3B4Qm91bmRzKSB7XG5cdFx0XHR2YXIgcGFkZGluZyA9IChsYXllci5vcHRpb25zLndlaWdodCB8fCAwKSArIDE7XG5cdFx0XHR0aGlzLl9yZWRyYXdCb3VuZHMgPSB0aGlzLl9yZWRyYXdCb3VuZHMgfHwgbmV3IEJvdW5kcygpO1xuXHRcdFx0dGhpcy5fcmVkcmF3Qm91bmRzLmV4dGVuZChsYXllci5fcHhCb3VuZHMubWluLnN1YnRyYWN0KFtwYWRkaW5nLCBwYWRkaW5nXSkpO1xuXHRcdFx0dGhpcy5fcmVkcmF3Qm91bmRzLmV4dGVuZChsYXllci5fcHhCb3VuZHMubWF4LmFkZChbcGFkZGluZywgcGFkZGluZ10pKTtcblx0XHR9XG5cdH0sXG5cblx0X3JlZHJhdzogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3JlZHJhd1JlcXVlc3QgPSBudWxsO1xuXG5cdFx0aWYgKHRoaXMuX3JlZHJhd0JvdW5kcykge1xuXHRcdFx0dGhpcy5fcmVkcmF3Qm91bmRzLm1pbi5fZmxvb3IoKTtcblx0XHRcdHRoaXMuX3JlZHJhd0JvdW5kcy5tYXguX2NlaWwoKTtcblx0XHR9XG5cblx0XHR0aGlzLl9jbGVhcigpOyAvLyBjbGVhciBsYXllcnMgaW4gcmVkcmF3IGJvdW5kc1xuXHRcdHRoaXMuX2RyYXcoKTsgLy8gZHJhdyBsYXllcnNcblxuXHRcdHRoaXMuX3JlZHJhd0JvdW5kcyA9IG51bGw7XG5cdH0sXG5cblx0X2NsZWFyOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGJvdW5kcyA9IHRoaXMuX3JlZHJhd0JvdW5kcztcblx0XHRpZiAoYm91bmRzKSB7XG5cdFx0XHR2YXIgc2l6ZSA9IGJvdW5kcy5nZXRTaXplKCk7XG5cdFx0XHR0aGlzLl9jdHguY2xlYXJSZWN0KGJvdW5kcy5taW4ueCwgYm91bmRzLm1pbi55LCBzaXplLngsIHNpemUueSk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuX2N0eC5jbGVhclJlY3QoMCwgMCwgdGhpcy5fY29udGFpbmVyLndpZHRoLCB0aGlzLl9jb250YWluZXIuaGVpZ2h0KTtcblx0XHR9XG5cdH0sXG5cblx0X2RyYXc6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgbGF5ZXIsIGJvdW5kcyA9IHRoaXMuX3JlZHJhd0JvdW5kcztcblx0XHR0aGlzLl9jdHguc2F2ZSgpO1xuXHRcdGlmIChib3VuZHMpIHtcblx0XHRcdHZhciBzaXplID0gYm91bmRzLmdldFNpemUoKTtcblx0XHRcdHRoaXMuX2N0eC5iZWdpblBhdGgoKTtcblx0XHRcdHRoaXMuX2N0eC5yZWN0KGJvdW5kcy5taW4ueCwgYm91bmRzLm1pbi55LCBzaXplLngsIHNpemUueSk7XG5cdFx0XHR0aGlzLl9jdHguY2xpcCgpO1xuXHRcdH1cblxuXHRcdHRoaXMuX2RyYXdpbmcgPSB0cnVlO1xuXG5cdFx0Zm9yICh2YXIgb3JkZXIgPSB0aGlzLl9kcmF3Rmlyc3Q7IG9yZGVyOyBvcmRlciA9IG9yZGVyLm5leHQpIHtcblx0XHRcdGxheWVyID0gb3JkZXIubGF5ZXI7XG5cdFx0XHRpZiAoIWJvdW5kcyB8fCAobGF5ZXIuX3B4Qm91bmRzICYmIGxheWVyLl9weEJvdW5kcy5pbnRlcnNlY3RzKGJvdW5kcykpKSB7XG5cdFx0XHRcdGxheWVyLl91cGRhdGVQYXRoKCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5fZHJhd2luZyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5fY3R4LnJlc3RvcmUoKTsgIC8vIFJlc3RvcmUgc3RhdGUgYmVmb3JlIGNsaXBwaW5nLlxuXHR9LFxuXG5cdF91cGRhdGVQb2x5OiBmdW5jdGlvbiAobGF5ZXIsIGNsb3NlZCkge1xuXHRcdGlmICghdGhpcy5fZHJhd2luZykgeyByZXR1cm47IH1cblxuXHRcdHZhciBpLCBqLCBsZW4yLCBwLFxuXHRcdCAgICBwYXJ0cyA9IGxheWVyLl9wYXJ0cyxcblx0XHQgICAgbGVuID0gcGFydHMubGVuZ3RoLFxuXHRcdCAgICBjdHggPSB0aGlzLl9jdHg7XG5cblx0XHRpZiAoIWxlbikgeyByZXR1cm47IH1cblxuXHRcdHRoaXMuX2RyYXduTGF5ZXJzW2xheWVyLl9sZWFmbGV0X2lkXSA9IGxheWVyO1xuXG5cdFx0Y3R4LmJlZ2luUGF0aCgpO1xuXG5cdFx0Zm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRmb3IgKGogPSAwLCBsZW4yID0gcGFydHNbaV0ubGVuZ3RoOyBqIDwgbGVuMjsgaisrKSB7XG5cdFx0XHRcdHAgPSBwYXJ0c1tpXVtqXTtcblx0XHRcdFx0Y3R4W2ogPyAnbGluZVRvJyA6ICdtb3ZlVG8nXShwLngsIHAueSk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoY2xvc2VkKSB7XG5cdFx0XHRcdGN0eC5jbG9zZVBhdGgoKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLl9maWxsU3Ryb2tlKGN0eCwgbGF5ZXIpO1xuXG5cdFx0Ly8gVE9ETyBvcHRpbWl6YXRpb246IDEgZmlsbC9zdHJva2UgZm9yIGFsbCBmZWF0dXJlcyB3aXRoIGVxdWFsIHN0eWxlIGluc3RlYWQgb2YgMSBmb3IgZWFjaCBmZWF0dXJlXG5cdH0sXG5cblx0X3VwZGF0ZUNpcmNsZTogZnVuY3Rpb24gKGxheWVyKSB7XG5cblx0XHRpZiAoIXRoaXMuX2RyYXdpbmcgfHwgbGF5ZXIuX2VtcHR5KCkpIHsgcmV0dXJuOyB9XG5cblx0XHR2YXIgcCA9IGxheWVyLl9wb2ludCxcblx0XHQgICAgY3R4ID0gdGhpcy5fY3R4LFxuXHRcdCAgICByID0gTWF0aC5tYXgoTWF0aC5yb3VuZChsYXllci5fcmFkaXVzKSwgMSksXG5cdFx0ICAgIHMgPSAoTWF0aC5tYXgoTWF0aC5yb3VuZChsYXllci5fcmFkaXVzWSksIDEpIHx8IHIpIC8gcjtcblxuXHRcdHRoaXMuX2RyYXduTGF5ZXJzW2xheWVyLl9sZWFmbGV0X2lkXSA9IGxheWVyO1xuXG5cdFx0aWYgKHMgIT09IDEpIHtcblx0XHRcdGN0eC5zYXZlKCk7XG5cdFx0XHRjdHguc2NhbGUoMSwgcyk7XG5cdFx0fVxuXG5cdFx0Y3R4LmJlZ2luUGF0aCgpO1xuXHRcdGN0eC5hcmMocC54LCBwLnkgLyBzLCByLCAwLCBNYXRoLlBJICogMiwgZmFsc2UpO1xuXG5cdFx0aWYgKHMgIT09IDEpIHtcblx0XHRcdGN0eC5yZXN0b3JlKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fZmlsbFN0cm9rZShjdHgsIGxheWVyKTtcblx0fSxcblxuXHRfZmlsbFN0cm9rZTogZnVuY3Rpb24gKGN0eCwgbGF5ZXIpIHtcblx0XHR2YXIgb3B0aW9ucyA9IGxheWVyLm9wdGlvbnM7XG5cblx0XHRpZiAob3B0aW9ucy5maWxsKSB7XG5cdFx0XHRjdHguZ2xvYmFsQWxwaGEgPSBvcHRpb25zLmZpbGxPcGFjaXR5O1xuXHRcdFx0Y3R4LmZpbGxTdHlsZSA9IG9wdGlvbnMuZmlsbENvbG9yIHx8IG9wdGlvbnMuY29sb3I7XG5cdFx0XHRjdHguZmlsbChvcHRpb25zLmZpbGxSdWxlIHx8ICdldmVub2RkJyk7XG5cdFx0fVxuXG5cdFx0aWYgKG9wdGlvbnMuc3Ryb2tlICYmIG9wdGlvbnMud2VpZ2h0ICE9PSAwKSB7XG5cdFx0XHRpZiAoY3R4LnNldExpbmVEYXNoKSB7XG5cdFx0XHRcdGN0eC5zZXRMaW5lRGFzaChsYXllci5vcHRpb25zICYmIGxheWVyLm9wdGlvbnMuX2Rhc2hBcnJheSB8fCBbXSk7XG5cdFx0XHR9XG5cdFx0XHRjdHguZ2xvYmFsQWxwaGEgPSBvcHRpb25zLm9wYWNpdHk7XG5cdFx0XHRjdHgubGluZVdpZHRoID0gb3B0aW9ucy53ZWlnaHQ7XG5cdFx0XHRjdHguc3Ryb2tlU3R5bGUgPSBvcHRpb25zLmNvbG9yO1xuXHRcdFx0Y3R4LmxpbmVDYXAgPSBvcHRpb25zLmxpbmVDYXA7XG5cdFx0XHRjdHgubGluZUpvaW4gPSBvcHRpb25zLmxpbmVKb2luO1xuXHRcdFx0Y3R4LnN0cm9rZSgpO1xuXHRcdH1cblx0fSxcblxuXHQvLyBDYW52YXMgb2J2aW91c2x5IGRvZXNuJ3QgaGF2ZSBtb3VzZSBldmVudHMgZm9yIGluZGl2aWR1YWwgZHJhd24gb2JqZWN0cyxcblx0Ly8gc28gd2UgZW11bGF0ZSB0aGF0IGJ5IGNhbGN1bGF0aW5nIHdoYXQncyB1bmRlciB0aGUgbW91c2Ugb24gbW91c2Vtb3ZlL2NsaWNrIG1hbnVhbGx5XG5cblx0X29uQ2xpY2s6IGZ1bmN0aW9uIChlKSB7XG5cdFx0dmFyIHBvaW50ID0gdGhpcy5fbWFwLm1vdXNlRXZlbnRUb0xheWVyUG9pbnQoZSksIGxheWVyLCBjbGlja2VkTGF5ZXI7XG5cblx0XHRmb3IgKHZhciBvcmRlciA9IHRoaXMuX2RyYXdGaXJzdDsgb3JkZXI7IG9yZGVyID0gb3JkZXIubmV4dCkge1xuXHRcdFx0bGF5ZXIgPSBvcmRlci5sYXllcjtcblx0XHRcdGlmIChsYXllci5vcHRpb25zLmludGVyYWN0aXZlICYmIGxheWVyLl9jb250YWluc1BvaW50KHBvaW50KSAmJiAhdGhpcy5fbWFwLl9kcmFnZ2FibGVNb3ZlZChsYXllcikpIHtcblx0XHRcdFx0Y2xpY2tlZExheWVyID0gbGF5ZXI7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGlmIChjbGlja2VkTGF5ZXIpICB7XG5cdFx0XHRmYWtlU3RvcChlKTtcblx0XHRcdHRoaXMuX2ZpcmVFdmVudChbY2xpY2tlZExheWVyXSwgZSk7XG5cdFx0fVxuXHR9LFxuXG5cdF9vbk1vdXNlTW92ZTogZnVuY3Rpb24gKGUpIHtcblx0XHRpZiAoIXRoaXMuX21hcCB8fCB0aGlzLl9tYXAuZHJhZ2dpbmcubW92aW5nKCkgfHwgdGhpcy5fbWFwLl9hbmltYXRpbmdab29tKSB7IHJldHVybjsgfVxuXG5cdFx0dmFyIHBvaW50ID0gdGhpcy5fbWFwLm1vdXNlRXZlbnRUb0xheWVyUG9pbnQoZSk7XG5cdFx0dGhpcy5faGFuZGxlTW91c2VIb3ZlcihlLCBwb2ludCk7XG5cdH0sXG5cblxuXHRfaGFuZGxlTW91c2VPdXQ6IGZ1bmN0aW9uIChlKSB7XG5cdFx0dmFyIGxheWVyID0gdGhpcy5faG92ZXJlZExheWVyO1xuXHRcdGlmIChsYXllcikge1xuXHRcdFx0Ly8gaWYgd2UncmUgbGVhdmluZyB0aGUgbGF5ZXIsIGZpcmUgbW91c2VvdXRcblx0XHRcdHJlbW92ZUNsYXNzKHRoaXMuX2NvbnRhaW5lciwgJ2xlYWZsZXQtaW50ZXJhY3RpdmUnKTtcblx0XHRcdHRoaXMuX2ZpcmVFdmVudChbbGF5ZXJdLCBlLCAnbW91c2VvdXQnKTtcblx0XHRcdHRoaXMuX2hvdmVyZWRMYXllciA9IG51bGw7XG5cdFx0fVxuXHR9LFxuXG5cdF9oYW5kbGVNb3VzZUhvdmVyOiBmdW5jdGlvbiAoZSwgcG9pbnQpIHtcblx0XHR2YXIgbGF5ZXIsIGNhbmRpZGF0ZUhvdmVyZWRMYXllcjtcblxuXHRcdGZvciAodmFyIG9yZGVyID0gdGhpcy5fZHJhd0ZpcnN0OyBvcmRlcjsgb3JkZXIgPSBvcmRlci5uZXh0KSB7XG5cdFx0XHRsYXllciA9IG9yZGVyLmxheWVyO1xuXHRcdFx0aWYgKGxheWVyLm9wdGlvbnMuaW50ZXJhY3RpdmUgJiYgbGF5ZXIuX2NvbnRhaW5zUG9pbnQocG9pbnQpKSB7XG5cdFx0XHRcdGNhbmRpZGF0ZUhvdmVyZWRMYXllciA9IGxheWVyO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmIChjYW5kaWRhdGVIb3ZlcmVkTGF5ZXIgIT09IHRoaXMuX2hvdmVyZWRMYXllcikge1xuXHRcdFx0dGhpcy5faGFuZGxlTW91c2VPdXQoZSk7XG5cblx0XHRcdGlmIChjYW5kaWRhdGVIb3ZlcmVkTGF5ZXIpIHtcblx0XHRcdFx0YWRkQ2xhc3ModGhpcy5fY29udGFpbmVyLCAnbGVhZmxldC1pbnRlcmFjdGl2ZScpOyAvLyBjaGFuZ2UgY3Vyc29yXG5cdFx0XHRcdHRoaXMuX2ZpcmVFdmVudChbY2FuZGlkYXRlSG92ZXJlZExheWVyXSwgZSwgJ21vdXNlb3ZlcicpO1xuXHRcdFx0XHR0aGlzLl9ob3ZlcmVkTGF5ZXIgPSBjYW5kaWRhdGVIb3ZlcmVkTGF5ZXI7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuX2hvdmVyZWRMYXllcikge1xuXHRcdFx0dGhpcy5fZmlyZUV2ZW50KFt0aGlzLl9ob3ZlcmVkTGF5ZXJdLCBlKTtcblx0XHR9XG5cdH0sXG5cblx0X2ZpcmVFdmVudDogZnVuY3Rpb24gKGxheWVycywgZSwgdHlwZSkge1xuXHRcdHRoaXMuX21hcC5fZmlyZURPTUV2ZW50KGUsIHR5cGUgfHwgZS50eXBlLCBsYXllcnMpO1xuXHR9LFxuXG5cdF9icmluZ1RvRnJvbnQ6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHZhciBvcmRlciA9IGxheWVyLl9vcmRlcjtcblx0XHR2YXIgbmV4dCA9IG9yZGVyLm5leHQ7XG5cdFx0dmFyIHByZXYgPSBvcmRlci5wcmV2O1xuXG5cdFx0aWYgKG5leHQpIHtcblx0XHRcdG5leHQucHJldiA9IHByZXY7XG5cdFx0fSBlbHNlIHtcblx0XHRcdC8vIEFscmVhZHkgbGFzdFxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRpZiAocHJldikge1xuXHRcdFx0cHJldi5uZXh0ID0gbmV4dDtcblx0XHR9IGVsc2UgaWYgKG5leHQpIHtcblx0XHRcdC8vIFVwZGF0ZSBmaXJzdCBlbnRyeSB1bmxlc3MgdGhpcyBpcyB0aGVcblx0XHRcdC8vIHNpbmdsZSBlbnRyeVxuXHRcdFx0dGhpcy5fZHJhd0ZpcnN0ID0gbmV4dDtcblx0XHR9XG5cblx0XHRvcmRlci5wcmV2ID0gdGhpcy5fZHJhd0xhc3Q7XG5cdFx0dGhpcy5fZHJhd0xhc3QubmV4dCA9IG9yZGVyO1xuXG5cdFx0b3JkZXIubmV4dCA9IG51bGw7XG5cdFx0dGhpcy5fZHJhd0xhc3QgPSBvcmRlcjtcblxuXHRcdHRoaXMuX3JlcXVlc3RSZWRyYXcobGF5ZXIpO1xuXHR9LFxuXG5cdF9icmluZ1RvQmFjazogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dmFyIG9yZGVyID0gbGF5ZXIuX29yZGVyO1xuXHRcdHZhciBuZXh0ID0gb3JkZXIubmV4dDtcblx0XHR2YXIgcHJldiA9IG9yZGVyLnByZXY7XG5cblx0XHRpZiAocHJldikge1xuXHRcdFx0cHJldi5uZXh0ID0gbmV4dDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gQWxyZWFkeSBmaXJzdFxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRpZiAobmV4dCkge1xuXHRcdFx0bmV4dC5wcmV2ID0gcHJldjtcblx0XHR9IGVsc2UgaWYgKHByZXYpIHtcblx0XHRcdC8vIFVwZGF0ZSBsYXN0IGVudHJ5IHVubGVzcyB0aGlzIGlzIHRoZVxuXHRcdFx0Ly8gc2luZ2xlIGVudHJ5XG5cdFx0XHR0aGlzLl9kcmF3TGFzdCA9IHByZXY7XG5cdFx0fVxuXG5cdFx0b3JkZXIucHJldiA9IG51bGw7XG5cblx0XHRvcmRlci5uZXh0ID0gdGhpcy5fZHJhd0ZpcnN0O1xuXHRcdHRoaXMuX2RyYXdGaXJzdC5wcmV2ID0gb3JkZXI7XG5cdFx0dGhpcy5fZHJhd0ZpcnN0ID0gb3JkZXI7XG5cblx0XHR0aGlzLl9yZXF1ZXN0UmVkcmF3KGxheWVyKTtcblx0fVxufSk7XG5cbi8vIEBmYWN0b3J5IEwuY2FudmFzKG9wdGlvbnM/OiBSZW5kZXJlciBvcHRpb25zKVxuLy8gQ3JlYXRlcyBhIENhbnZhcyByZW5kZXJlciB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuZnVuY3Rpb24gY2FudmFzJDEob3B0aW9ucykge1xuXHRyZXR1cm4gY2FudmFzID8gbmV3IENhbnZhcyhvcHRpb25zKSA6IG51bGw7XG59XG5cbi8qXG4gKiBUaGFua3MgdG8gRG1pdHJ5IEJhcmFub3Zza3kgYW5kIGhpcyBSYXBoYWVsIGxpYnJhcnkgZm9yIGluc3BpcmF0aW9uIVxuICovXG5cblxudmFyIHZtbENyZWF0ZSA9IChmdW5jdGlvbiAoKSB7XG5cdHRyeSB7XG5cdFx0ZG9jdW1lbnQubmFtZXNwYWNlcy5hZGQoJ2x2bWwnLCAndXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwnKTtcblx0XHRyZXR1cm4gZnVuY3Rpb24gKG5hbWUpIHtcblx0XHRcdHJldHVybiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCc8bHZtbDonICsgbmFtZSArICcgY2xhc3M9XCJsdm1sXCI+Jyk7XG5cdFx0fTtcblx0fSBjYXRjaCAoZSkge1xuXHRcdHJldHVybiBmdW5jdGlvbiAobmFtZSkge1xuXHRcdFx0cmV0dXJuIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJzwnICsgbmFtZSArICcgeG1sbnM9XCJ1cm46c2NoZW1hcy1taWNyb3NvZnQuY29tOnZtbFwiIGNsYXNzPVwibHZtbFwiPicpO1xuXHRcdH07XG5cdH1cbn0pKCk7XG5cblxuLypcbiAqIEBjbGFzcyBTVkdcbiAqXG4gKiBBbHRob3VnaCBTVkcgaXMgbm90IGF2YWlsYWJsZSBvbiBJRTcgYW5kIElFOCwgdGhlc2UgYnJvd3NlcnMgc3VwcG9ydCBbVk1MXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9WZWN0b3JfTWFya3VwX0xhbmd1YWdlKSwgYW5kIHRoZSBTVkcgcmVuZGVyZXIgd2lsbCBmYWxsIGJhY2sgdG8gVk1MIGluIHRoaXMgY2FzZS5cbiAqXG4gKiBWTUwgd2FzIGRlcHJlY2F0ZWQgaW4gMjAxMiwgd2hpY2ggbWVhbnMgVk1MIGZ1bmN0aW9uYWxpdHkgZXhpc3RzIG9ubHkgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5XG4gKiB3aXRoIG9sZCB2ZXJzaW9ucyBvZiBJbnRlcm5ldCBFeHBsb3Jlci5cbiAqL1xuXG4vLyBtaXhpbiB0byByZWRlZmluZSBzb21lIFNWRyBtZXRob2RzIHRvIGhhbmRsZSBWTUwgc3ludGF4IHdoaWNoIGlzIHNpbWlsYXIgYnV0IHdpdGggc29tZSBkaWZmZXJlbmNlc1xudmFyIHZtbE1peGluID0ge1xuXG5cdF9pbml0Q29udGFpbmVyOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5fY29udGFpbmVyID0gY3JlYXRlJDEoJ2RpdicsICdsZWFmbGV0LXZtbC1jb250YWluZXInKTtcblx0fSxcblxuXHRfdXBkYXRlOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX21hcC5fYW5pbWF0aW5nWm9vbSkgeyByZXR1cm47IH1cblx0XHRSZW5kZXJlci5wcm90b3R5cGUuX3VwZGF0ZS5jYWxsKHRoaXMpO1xuXHRcdHRoaXMuZmlyZSgndXBkYXRlJyk7XG5cdH0sXG5cblx0X2luaXRQYXRoOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR2YXIgY29udGFpbmVyID0gbGF5ZXIuX2NvbnRhaW5lciA9IHZtbENyZWF0ZSgnc2hhcGUnKTtcblxuXHRcdGFkZENsYXNzKGNvbnRhaW5lciwgJ2xlYWZsZXQtdm1sLXNoYXBlICcgKyAodGhpcy5vcHRpb25zLmNsYXNzTmFtZSB8fCAnJykpO1xuXG5cdFx0Y29udGFpbmVyLmNvb3Jkc2l6ZSA9ICcxIDEnO1xuXG5cdFx0bGF5ZXIuX3BhdGggPSB2bWxDcmVhdGUoJ3BhdGgnKTtcblx0XHRjb250YWluZXIuYXBwZW5kQ2hpbGQobGF5ZXIuX3BhdGgpO1xuXG5cdFx0dGhpcy5fdXBkYXRlU3R5bGUobGF5ZXIpO1xuXHRcdHRoaXMuX2xheWVyc1tzdGFtcChsYXllcildID0gbGF5ZXI7XG5cdH0sXG5cblx0X2FkZFBhdGg6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHZhciBjb250YWluZXIgPSBsYXllci5fY29udGFpbmVyO1xuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmRDaGlsZChjb250YWluZXIpO1xuXG5cdFx0aWYgKGxheWVyLm9wdGlvbnMuaW50ZXJhY3RpdmUpIHtcblx0XHRcdGxheWVyLmFkZEludGVyYWN0aXZlVGFyZ2V0KGNvbnRhaW5lcik7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZW1vdmVQYXRoOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR2YXIgY29udGFpbmVyID0gbGF5ZXIuX2NvbnRhaW5lcjtcblx0XHRyZW1vdmUoY29udGFpbmVyKTtcblx0XHRsYXllci5yZW1vdmVJbnRlcmFjdGl2ZVRhcmdldChjb250YWluZXIpO1xuXHRcdGRlbGV0ZSB0aGlzLl9sYXllcnNbc3RhbXAobGF5ZXIpXTtcblx0fSxcblxuXHRfdXBkYXRlU3R5bGU6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHZhciBzdHJva2UgPSBsYXllci5fc3Ryb2tlLFxuXHRcdCAgICBmaWxsID0gbGF5ZXIuX2ZpbGwsXG5cdFx0ICAgIG9wdGlvbnMgPSBsYXllci5vcHRpb25zLFxuXHRcdCAgICBjb250YWluZXIgPSBsYXllci5fY29udGFpbmVyO1xuXG5cdFx0Y29udGFpbmVyLnN0cm9rZWQgPSAhIW9wdGlvbnMuc3Ryb2tlO1xuXHRcdGNvbnRhaW5lci5maWxsZWQgPSAhIW9wdGlvbnMuZmlsbDtcblxuXHRcdGlmIChvcHRpb25zLnN0cm9rZSkge1xuXHRcdFx0aWYgKCFzdHJva2UpIHtcblx0XHRcdFx0c3Ryb2tlID0gbGF5ZXIuX3N0cm9rZSA9IHZtbENyZWF0ZSgnc3Ryb2tlJyk7XG5cdFx0XHR9XG5cdFx0XHRjb250YWluZXIuYXBwZW5kQ2hpbGQoc3Ryb2tlKTtcblx0XHRcdHN0cm9rZS53ZWlnaHQgPSBvcHRpb25zLndlaWdodCArICdweCc7XG5cdFx0XHRzdHJva2UuY29sb3IgPSBvcHRpb25zLmNvbG9yO1xuXHRcdFx0c3Ryb2tlLm9wYWNpdHkgPSBvcHRpb25zLm9wYWNpdHk7XG5cblx0XHRcdGlmIChvcHRpb25zLmRhc2hBcnJheSkge1xuXHRcdFx0XHRzdHJva2UuZGFzaFN0eWxlID0gaXNBcnJheShvcHRpb25zLmRhc2hBcnJheSkgP1xuXHRcdFx0XHQgICAgb3B0aW9ucy5kYXNoQXJyYXkuam9pbignICcpIDpcblx0XHRcdFx0ICAgIG9wdGlvbnMuZGFzaEFycmF5LnJlcGxhY2UoLyggKiwgKikvZywgJyAnKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHN0cm9rZS5kYXNoU3R5bGUgPSAnJztcblx0XHRcdH1cblx0XHRcdHN0cm9rZS5lbmRjYXAgPSBvcHRpb25zLmxpbmVDYXAucmVwbGFjZSgnYnV0dCcsICdmbGF0Jyk7XG5cdFx0XHRzdHJva2Uuam9pbnN0eWxlID0gb3B0aW9ucy5saW5lSm9pbjtcblxuXHRcdH0gZWxzZSBpZiAoc3Ryb2tlKSB7XG5cdFx0XHRjb250YWluZXIucmVtb3ZlQ2hpbGQoc3Ryb2tlKTtcblx0XHRcdGxheWVyLl9zdHJva2UgPSBudWxsO1xuXHRcdH1cblxuXHRcdGlmIChvcHRpb25zLmZpbGwpIHtcblx0XHRcdGlmICghZmlsbCkge1xuXHRcdFx0XHRmaWxsID0gbGF5ZXIuX2ZpbGwgPSB2bWxDcmVhdGUoJ2ZpbGwnKTtcblx0XHRcdH1cblx0XHRcdGNvbnRhaW5lci5hcHBlbmRDaGlsZChmaWxsKTtcblx0XHRcdGZpbGwuY29sb3IgPSBvcHRpb25zLmZpbGxDb2xvciB8fCBvcHRpb25zLmNvbG9yO1xuXHRcdFx0ZmlsbC5vcGFjaXR5ID0gb3B0aW9ucy5maWxsT3BhY2l0eTtcblxuXHRcdH0gZWxzZSBpZiAoZmlsbCkge1xuXHRcdFx0Y29udGFpbmVyLnJlbW92ZUNoaWxkKGZpbGwpO1xuXHRcdFx0bGF5ZXIuX2ZpbGwgPSBudWxsO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlQ2lyY2xlOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR2YXIgcCA9IGxheWVyLl9wb2ludC5yb3VuZCgpLFxuXHRcdCAgICByID0gTWF0aC5yb3VuZChsYXllci5fcmFkaXVzKSxcblx0XHQgICAgcjIgPSBNYXRoLnJvdW5kKGxheWVyLl9yYWRpdXNZIHx8IHIpO1xuXG5cdFx0dGhpcy5fc2V0UGF0aChsYXllciwgbGF5ZXIuX2VtcHR5KCkgPyAnTTAgMCcgOlxuXHRcdFx0J0FMICcgKyBwLnggKyAnLCcgKyBwLnkgKyAnICcgKyByICsgJywnICsgcjIgKyAnIDAsJyArICg2NTUzNSAqIDM2MCkpO1xuXHR9LFxuXG5cdF9zZXRQYXRoOiBmdW5jdGlvbiAobGF5ZXIsIHBhdGgpIHtcblx0XHRsYXllci5fcGF0aC52ID0gcGF0aDtcblx0fSxcblxuXHRfYnJpbmdUb0Zyb250OiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR0b0Zyb250KGxheWVyLl9jb250YWluZXIpO1xuXHR9LFxuXG5cdF9icmluZ1RvQmFjazogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dG9CYWNrKGxheWVyLl9jb250YWluZXIpO1xuXHR9XG59O1xuXG52YXIgY3JlYXRlJDIgPSB2bWwgPyB2bWxDcmVhdGUgOiBzdmdDcmVhdGU7XG5cbi8qXG4gKiBAY2xhc3MgU1ZHXG4gKiBAaW5oZXJpdHMgUmVuZGVyZXJcbiAqIEBha2EgTC5TVkdcbiAqXG4gKiBBbGxvd3MgdmVjdG9yIGxheWVycyB0byBiZSBkaXNwbGF5ZWQgd2l0aCBbU1ZHXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9TVkcpLlxuICogSW5oZXJpdHMgYFJlbmRlcmVyYC5cbiAqXG4gKiBEdWUgdG8gW3RlY2huaWNhbCBsaW1pdGF0aW9uc10oaHR0cDovL2Nhbml1c2UuY29tLyNzZWFyY2g9c3ZnKSwgU1ZHIGlzIG5vdFxuICogYXZhaWxhYmxlIGluIGFsbCB3ZWIgYnJvd3NlcnMsIG5vdGFibHkgQW5kcm9pZCAyLnggYW5kIDMueC5cbiAqXG4gKiBBbHRob3VnaCBTVkcgaXMgbm90IGF2YWlsYWJsZSBvbiBJRTcgYW5kIElFOCwgdGhlc2UgYnJvd3NlcnMgc3VwcG9ydFxuICogW1ZNTF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVmVjdG9yX01hcmt1cF9MYW5ndWFnZSlcbiAqIChhIG5vdyBkZXByZWNhdGVkIHRlY2hub2xvZ3kpLCBhbmQgdGhlIFNWRyByZW5kZXJlciB3aWxsIGZhbGwgYmFjayB0byBWTUwgaW5cbiAqIHRoaXMgY2FzZS5cbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIFVzZSBTVkcgYnkgZGVmYXVsdCBmb3IgYWxsIHBhdGhzIGluIHRoZSBtYXA6XG4gKlxuICogYGBganNcbiAqIHZhciBtYXAgPSBMLm1hcCgnbWFwJywge1xuICogXHRyZW5kZXJlcjogTC5zdmcoKVxuICogfSk7XG4gKiBgYGBcbiAqXG4gKiBVc2UgYSBTVkcgcmVuZGVyZXIgd2l0aCBleHRyYSBwYWRkaW5nIGZvciBzcGVjaWZpYyB2ZWN0b3IgZ2VvbWV0cmllczpcbiAqXG4gKiBgYGBqc1xuICogdmFyIG1hcCA9IEwubWFwKCdtYXAnKTtcbiAqIHZhciBteVJlbmRlcmVyID0gTC5zdmcoeyBwYWRkaW5nOiAwLjUgfSk7XG4gKiB2YXIgbGluZSA9IEwucG9seWxpbmUoIGNvb3JkaW5hdGVzLCB7IHJlbmRlcmVyOiBteVJlbmRlcmVyIH0gKTtcbiAqIHZhciBjaXJjbGUgPSBMLmNpcmNsZSggY2VudGVyLCB7IHJlbmRlcmVyOiBteVJlbmRlcmVyIH0gKTtcbiAqIGBgYFxuICovXG5cbnZhciBTVkcgPSBSZW5kZXJlci5leHRlbmQoe1xuXG5cdGdldEV2ZW50czogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBldmVudHMgPSBSZW5kZXJlci5wcm90b3R5cGUuZ2V0RXZlbnRzLmNhbGwodGhpcyk7XG5cdFx0ZXZlbnRzLnpvb21zdGFydCA9IHRoaXMuX29uWm9vbVN0YXJ0O1xuXHRcdHJldHVybiBldmVudHM7XG5cdH0sXG5cblx0X2luaXRDb250YWluZXI6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9jb250YWluZXIgPSBjcmVhdGUkMignc3ZnJyk7XG5cblx0XHQvLyBtYWtlcyBpdCBwb3NzaWJsZSB0byBjbGljayB0aHJvdWdoIHN2ZyByb290OyB3ZSdsbCByZXNldCBpdCBiYWNrIGluIGluZGl2aWR1YWwgcGF0aHNcblx0XHR0aGlzLl9jb250YWluZXIuc2V0QXR0cmlidXRlKCdwb2ludGVyLWV2ZW50cycsICdub25lJyk7XG5cblx0XHR0aGlzLl9yb290R3JvdXAgPSBjcmVhdGUkMignZycpO1xuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLl9yb290R3JvdXApO1xuXHR9LFxuXG5cdF9kZXN0cm95Q29udGFpbmVyOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmVtb3ZlKHRoaXMuX2NvbnRhaW5lcik7XG5cdFx0b2ZmKHRoaXMuX2NvbnRhaW5lcik7XG5cdFx0ZGVsZXRlIHRoaXMuX2NvbnRhaW5lcjtcblx0XHRkZWxldGUgdGhpcy5fcm9vdEdyb3VwO1xuXHRcdGRlbGV0ZSB0aGlzLl9zdmdTaXplO1xuXHR9LFxuXG5cdF9vblpvb21TdGFydDogZnVuY3Rpb24gKCkge1xuXHRcdC8vIERyYWctdGhlbi1waW5jaCBpbnRlcmFjdGlvbnMgbWlnaHQgbWVzcyB1cCB0aGUgY2VudGVyIGFuZCB6b29tLlxuXHRcdC8vIEluIHRoaXMgY2FzZSwgdGhlIGVhc2llc3Qgd2F5IHRvIHByZXZlbnQgdGhpcyBpcyByZS1kbyB0aGUgcmVuZGVyZXJcblx0XHQvLyAgIGJvdW5kcyBhbmQgcGFkZGluZyB3aGVuIHRoZSB6b29taW5nIHN0YXJ0cy5cblx0XHR0aGlzLl91cGRhdGUoKTtcblx0fSxcblxuXHRfdXBkYXRlOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX21hcC5fYW5pbWF0aW5nWm9vbSAmJiB0aGlzLl9ib3VuZHMpIHsgcmV0dXJuOyB9XG5cblx0XHRSZW5kZXJlci5wcm90b3R5cGUuX3VwZGF0ZS5jYWxsKHRoaXMpO1xuXG5cdFx0dmFyIGIgPSB0aGlzLl9ib3VuZHMsXG5cdFx0ICAgIHNpemUgPSBiLmdldFNpemUoKSxcblx0XHQgICAgY29udGFpbmVyID0gdGhpcy5fY29udGFpbmVyO1xuXG5cdFx0Ly8gc2V0IHNpemUgb2Ygc3ZnLWNvbnRhaW5lciBpZiBjaGFuZ2VkXG5cdFx0aWYgKCF0aGlzLl9zdmdTaXplIHx8ICF0aGlzLl9zdmdTaXplLmVxdWFscyhzaXplKSkge1xuXHRcdFx0dGhpcy5fc3ZnU2l6ZSA9IHNpemU7XG5cdFx0XHRjb250YWluZXIuc2V0QXR0cmlidXRlKCd3aWR0aCcsIHNpemUueCk7XG5cdFx0XHRjb250YWluZXIuc2V0QXR0cmlidXRlKCdoZWlnaHQnLCBzaXplLnkpO1xuXHRcdH1cblxuXHRcdC8vIG1vdmVtZW50OiB1cGRhdGUgY29udGFpbmVyIHZpZXdCb3ggc28gdGhhdCB3ZSBkb24ndCBoYXZlIHRvIGNoYW5nZSBjb29yZGluYXRlcyBvZiBpbmRpdmlkdWFsIGxheWVyc1xuXHRcdHNldFBvc2l0aW9uKGNvbnRhaW5lciwgYi5taW4pO1xuXHRcdGNvbnRhaW5lci5zZXRBdHRyaWJ1dGUoJ3ZpZXdCb3gnLCBbYi5taW4ueCwgYi5taW4ueSwgc2l6ZS54LCBzaXplLnldLmpvaW4oJyAnKSk7XG5cblx0XHR0aGlzLmZpcmUoJ3VwZGF0ZScpO1xuXHR9LFxuXG5cdC8vIG1ldGhvZHMgYmVsb3cgYXJlIGNhbGxlZCBieSB2ZWN0b3IgbGF5ZXJzIGltcGxlbWVudGF0aW9uc1xuXG5cdF9pbml0UGF0aDogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dmFyIHBhdGggPSBsYXllci5fcGF0aCA9IGNyZWF0ZSQyKCdwYXRoJyk7XG5cblx0XHQvLyBAbmFtZXNwYWNlIFBhdGhcblx0XHQvLyBAb3B0aW9uIGNsYXNzTmFtZTogU3RyaW5nID0gbnVsbFxuXHRcdC8vIEN1c3RvbSBjbGFzcyBuYW1lIHNldCBvbiBhbiBlbGVtZW50LiBPbmx5IGZvciBTVkcgcmVuZGVyZXIuXG5cdFx0aWYgKGxheWVyLm9wdGlvbnMuY2xhc3NOYW1lKSB7XG5cdFx0XHRhZGRDbGFzcyhwYXRoLCBsYXllci5vcHRpb25zLmNsYXNzTmFtZSk7XG5cdFx0fVxuXG5cdFx0aWYgKGxheWVyLm9wdGlvbnMuaW50ZXJhY3RpdmUpIHtcblx0XHRcdGFkZENsYXNzKHBhdGgsICdsZWFmbGV0LWludGVyYWN0aXZlJyk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fdXBkYXRlU3R5bGUobGF5ZXIpO1xuXHRcdHRoaXMuX2xheWVyc1tzdGFtcChsYXllcildID0gbGF5ZXI7XG5cdH0sXG5cblx0X2FkZFBhdGg6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdGlmICghdGhpcy5fcm9vdEdyb3VwKSB7IHRoaXMuX2luaXRDb250YWluZXIoKTsgfVxuXHRcdHRoaXMuX3Jvb3RHcm91cC5hcHBlbmRDaGlsZChsYXllci5fcGF0aCk7XG5cdFx0bGF5ZXIuYWRkSW50ZXJhY3RpdmVUYXJnZXQobGF5ZXIuX3BhdGgpO1xuXHR9LFxuXG5cdF9yZW1vdmVQYXRoOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHRyZW1vdmUobGF5ZXIuX3BhdGgpO1xuXHRcdGxheWVyLnJlbW92ZUludGVyYWN0aXZlVGFyZ2V0KGxheWVyLl9wYXRoKTtcblx0XHRkZWxldGUgdGhpcy5fbGF5ZXJzW3N0YW1wKGxheWVyKV07XG5cdH0sXG5cblx0X3VwZGF0ZVBhdGg6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdGxheWVyLl9wcm9qZWN0KCk7XG5cdFx0bGF5ZXIuX3VwZGF0ZSgpO1xuXHR9LFxuXG5cdF91cGRhdGVTdHlsZTogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dmFyIHBhdGggPSBsYXllci5fcGF0aCxcblx0XHQgICAgb3B0aW9ucyA9IGxheWVyLm9wdGlvbnM7XG5cblx0XHRpZiAoIXBhdGgpIHsgcmV0dXJuOyB9XG5cblx0XHRpZiAob3B0aW9ucy5zdHJva2UpIHtcblx0XHRcdHBhdGguc2V0QXR0cmlidXRlKCdzdHJva2UnLCBvcHRpb25zLmNvbG9yKTtcblx0XHRcdHBhdGguc2V0QXR0cmlidXRlKCdzdHJva2Utb3BhY2l0eScsIG9wdGlvbnMub3BhY2l0eSk7XG5cdFx0XHRwYXRoLnNldEF0dHJpYnV0ZSgnc3Ryb2tlLXdpZHRoJywgb3B0aW9ucy53ZWlnaHQpO1xuXHRcdFx0cGF0aC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS1saW5lY2FwJywgb3B0aW9ucy5saW5lQ2FwKTtcblx0XHRcdHBhdGguc2V0QXR0cmlidXRlKCdzdHJva2UtbGluZWpvaW4nLCBvcHRpb25zLmxpbmVKb2luKTtcblxuXHRcdFx0aWYgKG9wdGlvbnMuZGFzaEFycmF5KSB7XG5cdFx0XHRcdHBhdGguc2V0QXR0cmlidXRlKCdzdHJva2UtZGFzaGFycmF5Jywgb3B0aW9ucy5kYXNoQXJyYXkpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cGF0aC5yZW1vdmVBdHRyaWJ1dGUoJ3N0cm9rZS1kYXNoYXJyYXknKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKG9wdGlvbnMuZGFzaE9mZnNldCkge1xuXHRcdFx0XHRwYXRoLnNldEF0dHJpYnV0ZSgnc3Ryb2tlLWRhc2hvZmZzZXQnLCBvcHRpb25zLmRhc2hPZmZzZXQpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cGF0aC5yZW1vdmVBdHRyaWJ1dGUoJ3N0cm9rZS1kYXNob2Zmc2V0Jyk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdHBhdGguc2V0QXR0cmlidXRlKCdzdHJva2UnLCAnbm9uZScpO1xuXHRcdH1cblxuXHRcdGlmIChvcHRpb25zLmZpbGwpIHtcblx0XHRcdHBhdGguc2V0QXR0cmlidXRlKCdmaWxsJywgb3B0aW9ucy5maWxsQ29sb3IgfHwgb3B0aW9ucy5jb2xvcik7XG5cdFx0XHRwYXRoLnNldEF0dHJpYnV0ZSgnZmlsbC1vcGFjaXR5Jywgb3B0aW9ucy5maWxsT3BhY2l0eSk7XG5cdFx0XHRwYXRoLnNldEF0dHJpYnV0ZSgnZmlsbC1ydWxlJywgb3B0aW9ucy5maWxsUnVsZSB8fCAnZXZlbm9kZCcpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRwYXRoLnNldEF0dHJpYnV0ZSgnZmlsbCcsICdub25lJyk7XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGVQb2x5OiBmdW5jdGlvbiAobGF5ZXIsIGNsb3NlZCkge1xuXHRcdHRoaXMuX3NldFBhdGgobGF5ZXIsIHBvaW50c1RvUGF0aChsYXllci5fcGFydHMsIGNsb3NlZCkpO1xuXHR9LFxuXG5cdF91cGRhdGVDaXJjbGU6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHZhciBwID0gbGF5ZXIuX3BvaW50LFxuXHRcdCAgICByID0gTWF0aC5tYXgoTWF0aC5yb3VuZChsYXllci5fcmFkaXVzKSwgMSksXG5cdFx0ICAgIHIyID0gTWF0aC5tYXgoTWF0aC5yb3VuZChsYXllci5fcmFkaXVzWSksIDEpIHx8IHIsXG5cdFx0ICAgIGFyYyA9ICdhJyArIHIgKyAnLCcgKyByMiArICcgMCAxLDAgJztcblxuXHRcdC8vIGRyYXdpbmcgYSBjaXJjbGUgd2l0aCB0d28gaGFsZi1hcmNzXG5cdFx0dmFyIGQgPSBsYXllci5fZW1wdHkoKSA/ICdNMCAwJyA6XG5cdFx0XHQnTScgKyAocC54IC0gcikgKyAnLCcgKyBwLnkgK1xuXHRcdFx0YXJjICsgKHIgKiAyKSArICcsMCAnICtcblx0XHRcdGFyYyArICgtciAqIDIpICsgJywwICc7XG5cblx0XHR0aGlzLl9zZXRQYXRoKGxheWVyLCBkKTtcblx0fSxcblxuXHRfc2V0UGF0aDogZnVuY3Rpb24gKGxheWVyLCBwYXRoKSB7XG5cdFx0bGF5ZXIuX3BhdGguc2V0QXR0cmlidXRlKCdkJywgcGF0aCk7XG5cdH0sXG5cblx0Ly8gU1ZHIGRvZXMgbm90IGhhdmUgdGhlIGNvbmNlcHQgb2YgekluZGV4IHNvIHdlIHJlc29ydCB0byBjaGFuZ2luZyB0aGUgRE9NIG9yZGVyIG9mIGVsZW1lbnRzXG5cdF9icmluZ1RvRnJvbnQ6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHRvRnJvbnQobGF5ZXIuX3BhdGgpO1xuXHR9LFxuXG5cdF9icmluZ1RvQmFjazogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dG9CYWNrKGxheWVyLl9wYXRoKTtcblx0fVxufSk7XG5cbmlmICh2bWwpIHtcblx0U1ZHLmluY2x1ZGUodm1sTWl4aW4pO1xufVxuXG4vLyBAbmFtZXNwYWNlIFNWR1xuLy8gQGZhY3RvcnkgTC5zdmcob3B0aW9ucz86IFJlbmRlcmVyIG9wdGlvbnMpXG4vLyBDcmVhdGVzIGEgU1ZHIHJlbmRlcmVyIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG5mdW5jdGlvbiBzdmckMShvcHRpb25zKSB7XG5cdHJldHVybiBzdmcgfHwgdm1sID8gbmV3IFNWRyhvcHRpb25zKSA6IG51bGw7XG59XG5cbk1hcC5pbmNsdWRlKHtcblx0Ly8gQG5hbWVzcGFjZSBNYXA7IEBtZXRob2QgZ2V0UmVuZGVyZXIobGF5ZXI6IFBhdGgpOiBSZW5kZXJlclxuXHQvLyBSZXR1cm5zIHRoZSBpbnN0YW5jZSBvZiBgUmVuZGVyZXJgIHRoYXQgc2hvdWxkIGJlIHVzZWQgdG8gcmVuZGVyIHRoZSBnaXZlblxuXHQvLyBgUGF0aGAuIEl0IHdpbGwgZW5zdXJlIHRoYXQgdGhlIGByZW5kZXJlcmAgb3B0aW9ucyBvZiB0aGUgbWFwIGFuZCBwYXRoc1xuXHQvLyBhcmUgcmVzcGVjdGVkLCBhbmQgdGhhdCB0aGUgcmVuZGVyZXJzIGRvIGV4aXN0IG9uIHRoZSBtYXAuXG5cdGdldFJlbmRlcmVyOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHQvLyBAbmFtZXNwYWNlIFBhdGg7IEBvcHRpb24gcmVuZGVyZXI6IFJlbmRlcmVyXG5cdFx0Ly8gVXNlIHRoaXMgc3BlY2lmaWMgaW5zdGFuY2Ugb2YgYFJlbmRlcmVyYCBmb3IgdGhpcyBwYXRoLiBUYWtlc1xuXHRcdC8vIHByZWNlZGVuY2Ugb3ZlciB0aGUgbWFwJ3MgW2RlZmF1bHQgcmVuZGVyZXJdKCNtYXAtcmVuZGVyZXIpLlxuXHRcdHZhciByZW5kZXJlciA9IGxheWVyLm9wdGlvbnMucmVuZGVyZXIgfHwgdGhpcy5fZ2V0UGFuZVJlbmRlcmVyKGxheWVyLm9wdGlvbnMucGFuZSkgfHwgdGhpcy5vcHRpb25zLnJlbmRlcmVyIHx8IHRoaXMuX3JlbmRlcmVyO1xuXG5cdFx0aWYgKCFyZW5kZXJlcikge1xuXHRcdFx0Ly8gQG5hbWVzcGFjZSBNYXA7IEBvcHRpb24gcHJlZmVyQ2FudmFzOiBCb29sZWFuID0gZmFsc2Vcblx0XHRcdC8vIFdoZXRoZXIgYFBhdGhgcyBzaG91bGQgYmUgcmVuZGVyZWQgb24gYSBgQ2FudmFzYCByZW5kZXJlci5cblx0XHRcdC8vIEJ5IGRlZmF1bHQsIGFsbCBgUGF0aGBzIGFyZSByZW5kZXJlZCBpbiBhIGBTVkdgIHJlbmRlcmVyLlxuXHRcdFx0cmVuZGVyZXIgPSB0aGlzLl9yZW5kZXJlciA9ICh0aGlzLm9wdGlvbnMucHJlZmVyQ2FudmFzICYmIGNhbnZhcyQxKCkpIHx8IHN2ZyQxKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCF0aGlzLmhhc0xheWVyKHJlbmRlcmVyKSkge1xuXHRcdFx0dGhpcy5hZGRMYXllcihyZW5kZXJlcik7XG5cdFx0fVxuXHRcdHJldHVybiByZW5kZXJlcjtcblx0fSxcblxuXHRfZ2V0UGFuZVJlbmRlcmVyOiBmdW5jdGlvbiAobmFtZSkge1xuXHRcdGlmIChuYW1lID09PSAnb3ZlcmxheVBhbmUnIHx8IG5hbWUgPT09IHVuZGVmaW5lZCkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHZhciByZW5kZXJlciA9IHRoaXMuX3BhbmVSZW5kZXJlcnNbbmFtZV07XG5cdFx0aWYgKHJlbmRlcmVyID09PSB1bmRlZmluZWQpIHtcblx0XHRcdHJlbmRlcmVyID0gKFNWRyAmJiBzdmckMSh7cGFuZTogbmFtZX0pKSB8fCAoQ2FudmFzICYmIGNhbnZhcyQxKHtwYW5lOiBuYW1lfSkpO1xuXHRcdFx0dGhpcy5fcGFuZVJlbmRlcmVyc1tuYW1lXSA9IHJlbmRlcmVyO1xuXHRcdH1cblx0XHRyZXR1cm4gcmVuZGVyZXI7XG5cdH1cbn0pO1xuXG4vKlxuICogTC5SZWN0YW5nbGUgZXh0ZW5kcyBQb2x5Z29uIGFuZCBjcmVhdGVzIGEgcmVjdGFuZ2xlIHdoZW4gcGFzc2VkIGEgTGF0TG5nQm91bmRzIG9iamVjdC5cbiAqL1xuXG4vKlxuICogQGNsYXNzIFJlY3RhbmdsZVxuICogQGFrYSBMLlJlY3RhbmdsZVxuICogQGluaGVyaXRzIFBvbHlnb25cbiAqXG4gKiBBIGNsYXNzIGZvciBkcmF3aW5nIHJlY3RhbmdsZSBvdmVybGF5cyBvbiBhIG1hcC4gRXh0ZW5kcyBgUG9seWdvbmAuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiBgYGBqc1xuICogLy8gZGVmaW5lIHJlY3RhbmdsZSBnZW9ncmFwaGljYWwgYm91bmRzXG4gKiB2YXIgYm91bmRzID0gW1s1NC41NTkzMjIsIC01Ljc2NzgyMl0sIFs1Ni4xMjEwNjA0LCAtMy4wMjEyNDBdXTtcbiAqXG4gKiAvLyBjcmVhdGUgYW4gb3JhbmdlIHJlY3RhbmdsZVxuICogTC5yZWN0YW5nbGUoYm91bmRzLCB7Y29sb3I6IFwiI2ZmNzgwMFwiLCB3ZWlnaHQ6IDF9KS5hZGRUbyhtYXApO1xuICpcbiAqIC8vIHpvb20gdGhlIG1hcCB0byB0aGUgcmVjdGFuZ2xlIGJvdW5kc1xuICogbWFwLmZpdEJvdW5kcyhib3VuZHMpO1xuICogYGBgXG4gKlxuICovXG5cblxudmFyIFJlY3RhbmdsZSA9IFBvbHlnb24uZXh0ZW5kKHtcblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKGxhdExuZ0JvdW5kcywgb3B0aW9ucykge1xuXHRcdFBvbHlnb24ucHJvdG90eXBlLmluaXRpYWxpemUuY2FsbCh0aGlzLCB0aGlzLl9ib3VuZHNUb0xhdExuZ3MobGF0TG5nQm91bmRzKSwgb3B0aW9ucyk7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBzZXRCb3VuZHMobGF0TG5nQm91bmRzOiBMYXRMbmdCb3VuZHMpOiB0aGlzXG5cdC8vIFJlZHJhd3MgdGhlIHJlY3RhbmdsZSB3aXRoIHRoZSBwYXNzZWQgYm91bmRzLlxuXHRzZXRCb3VuZHM6IGZ1bmN0aW9uIChsYXRMbmdCb3VuZHMpIHtcblx0XHRyZXR1cm4gdGhpcy5zZXRMYXRMbmdzKHRoaXMuX2JvdW5kc1RvTGF0TG5ncyhsYXRMbmdCb3VuZHMpKTtcblx0fSxcblxuXHRfYm91bmRzVG9MYXRMbmdzOiBmdW5jdGlvbiAobGF0TG5nQm91bmRzKSB7XG5cdFx0bGF0TG5nQm91bmRzID0gdG9MYXRMbmdCb3VuZHMobGF0TG5nQm91bmRzKTtcblx0XHRyZXR1cm4gW1xuXHRcdFx0bGF0TG5nQm91bmRzLmdldFNvdXRoV2VzdCgpLFxuXHRcdFx0bGF0TG5nQm91bmRzLmdldE5vcnRoV2VzdCgpLFxuXHRcdFx0bGF0TG5nQm91bmRzLmdldE5vcnRoRWFzdCgpLFxuXHRcdFx0bGF0TG5nQm91bmRzLmdldFNvdXRoRWFzdCgpXG5cdFx0XTtcblx0fVxufSk7XG5cblxuLy8gQGZhY3RvcnkgTC5yZWN0YW5nbGUobGF0TG5nQm91bmRzOiBMYXRMbmdCb3VuZHMsIG9wdGlvbnM/OiBQb2x5bGluZSBvcHRpb25zKVxuZnVuY3Rpb24gcmVjdGFuZ2xlKGxhdExuZ0JvdW5kcywgb3B0aW9ucykge1xuXHRyZXR1cm4gbmV3IFJlY3RhbmdsZShsYXRMbmdCb3VuZHMsIG9wdGlvbnMpO1xufVxuXG5TVkcuY3JlYXRlID0gY3JlYXRlJDI7XG5TVkcucG9pbnRzVG9QYXRoID0gcG9pbnRzVG9QYXRoO1xuXG5HZW9KU09OLmdlb21ldHJ5VG9MYXllciA9IGdlb21ldHJ5VG9MYXllcjtcbkdlb0pTT04uY29vcmRzVG9MYXRMbmcgPSBjb29yZHNUb0xhdExuZztcbkdlb0pTT04uY29vcmRzVG9MYXRMbmdzID0gY29vcmRzVG9MYXRMbmdzO1xuR2VvSlNPTi5sYXRMbmdUb0Nvb3JkcyA9IGxhdExuZ1RvQ29vcmRzO1xuR2VvSlNPTi5sYXRMbmdzVG9Db29yZHMgPSBsYXRMbmdzVG9Db29yZHM7XG5HZW9KU09OLmdldEZlYXR1cmUgPSBnZXRGZWF0dXJlO1xuR2VvSlNPTi5hc0ZlYXR1cmUgPSBhc0ZlYXR1cmU7XG5cbi8qXG4gKiBMLkhhbmRsZXIuQm94Wm9vbSBpcyB1c2VkIHRvIGFkZCBzaGlmdC1kcmFnIHpvb20gaW50ZXJhY3Rpb24gdG8gdGhlIG1hcFxuICogKHpvb20gdG8gYSBzZWxlY3RlZCBib3VuZGluZyBib3gpLCBlbmFibGVkIGJ5IGRlZmF1bHQuXG4gKi9cblxuLy8gQG5hbWVzcGFjZSBNYXBcbi8vIEBzZWN0aW9uIEludGVyYWN0aW9uIE9wdGlvbnNcbk1hcC5tZXJnZU9wdGlvbnMoe1xuXHQvLyBAb3B0aW9uIGJveFpvb206IEJvb2xlYW4gPSB0cnVlXG5cdC8vIFdoZXRoZXIgdGhlIG1hcCBjYW4gYmUgem9vbWVkIHRvIGEgcmVjdGFuZ3VsYXIgYXJlYSBzcGVjaWZpZWQgYnlcblx0Ly8gZHJhZ2dpbmcgdGhlIG1vdXNlIHdoaWxlIHByZXNzaW5nIHRoZSBzaGlmdCBrZXkuXG5cdGJveFpvb206IHRydWVcbn0pO1xuXG52YXIgQm94Wm9vbSA9IEhhbmRsZXIuZXh0ZW5kKHtcblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKG1hcCkge1xuXHRcdHRoaXMuX21hcCA9IG1hcDtcblx0XHR0aGlzLl9jb250YWluZXIgPSBtYXAuX2NvbnRhaW5lcjtcblx0XHR0aGlzLl9wYW5lID0gbWFwLl9wYW5lcy5vdmVybGF5UGFuZTtcblx0XHR0aGlzLl9yZXNldFN0YXRlVGltZW91dCA9IDA7XG5cdFx0bWFwLm9uKCd1bmxvYWQnLCB0aGlzLl9kZXN0cm95LCB0aGlzKTtcblx0fSxcblxuXHRhZGRIb29rczogZnVuY3Rpb24gKCkge1xuXHRcdG9uKHRoaXMuX2NvbnRhaW5lciwgJ21vdXNlZG93bicsIHRoaXMuX29uTW91c2VEb3duLCB0aGlzKTtcblx0fSxcblxuXHRyZW1vdmVIb29rczogZnVuY3Rpb24gKCkge1xuXHRcdG9mZih0aGlzLl9jb250YWluZXIsICdtb3VzZWRvd24nLCB0aGlzLl9vbk1vdXNlRG93biwgdGhpcyk7XG5cdH0sXG5cblx0bW92ZWQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fbW92ZWQ7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uICgpIHtcblx0XHRyZW1vdmUodGhpcy5fcGFuZSk7XG5cdFx0ZGVsZXRlIHRoaXMuX3BhbmU7XG5cdH0sXG5cblx0X3Jlc2V0U3RhdGU6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9yZXNldFN0YXRlVGltZW91dCA9IDA7XG5cdFx0dGhpcy5fbW92ZWQgPSBmYWxzZTtcblx0fSxcblxuXHRfY2xlYXJEZWZlcnJlZFJlc2V0U3RhdGU6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fcmVzZXRTdGF0ZVRpbWVvdXQgIT09IDApIHtcblx0XHRcdGNsZWFyVGltZW91dCh0aGlzLl9yZXNldFN0YXRlVGltZW91dCk7XG5cdFx0XHR0aGlzLl9yZXNldFN0YXRlVGltZW91dCA9IDA7XG5cdFx0fVxuXHR9LFxuXG5cdF9vbk1vdXNlRG93bjogZnVuY3Rpb24gKGUpIHtcblx0XHRpZiAoIWUuc2hpZnRLZXkgfHwgKChlLndoaWNoICE9PSAxKSAmJiAoZS5idXR0b24gIT09IDEpKSkgeyByZXR1cm4gZmFsc2U7IH1cblxuXHRcdC8vIENsZWFyIHRoZSBkZWZlcnJlZCByZXNldFN0YXRlIGlmIGl0IGhhc24ndCBleGVjdXRlZCB5ZXQsIG90aGVyd2lzZSBpdFxuXHRcdC8vIHdpbGwgaW50ZXJydXB0IHRoZSBpbnRlcmFjdGlvbiBhbmQgb3JwaGFuIGEgYm94IGVsZW1lbnQgaW4gdGhlIGNvbnRhaW5lci5cblx0XHR0aGlzLl9jbGVhckRlZmVycmVkUmVzZXRTdGF0ZSgpO1xuXHRcdHRoaXMuX3Jlc2V0U3RhdGUoKTtcblxuXHRcdGRpc2FibGVUZXh0U2VsZWN0aW9uKCk7XG5cdFx0ZGlzYWJsZUltYWdlRHJhZygpO1xuXG5cdFx0dGhpcy5fc3RhcnRQb2ludCA9IHRoaXMuX21hcC5tb3VzZUV2ZW50VG9Db250YWluZXJQb2ludChlKTtcblxuXHRcdG9uKGRvY3VtZW50LCB7XG5cdFx0XHRjb250ZXh0bWVudTogc3RvcCxcblx0XHRcdG1vdXNlbW92ZTogdGhpcy5fb25Nb3VzZU1vdmUsXG5cdFx0XHRtb3VzZXVwOiB0aGlzLl9vbk1vdXNlVXAsXG5cdFx0XHRrZXlkb3duOiB0aGlzLl9vbktleURvd25cblx0XHR9LCB0aGlzKTtcblx0fSxcblxuXHRfb25Nb3VzZU1vdmU6IGZ1bmN0aW9uIChlKSB7XG5cdFx0aWYgKCF0aGlzLl9tb3ZlZCkge1xuXHRcdFx0dGhpcy5fbW92ZWQgPSB0cnVlO1xuXG5cdFx0XHR0aGlzLl9ib3ggPSBjcmVhdGUkMSgnZGl2JywgJ2xlYWZsZXQtem9vbS1ib3gnLCB0aGlzLl9jb250YWluZXIpO1xuXHRcdFx0YWRkQ2xhc3ModGhpcy5fY29udGFpbmVyLCAnbGVhZmxldC1jcm9zc2hhaXInKTtcblxuXHRcdFx0dGhpcy5fbWFwLmZpcmUoJ2JveHpvb21zdGFydCcpO1xuXHRcdH1cblxuXHRcdHRoaXMuX3BvaW50ID0gdGhpcy5fbWFwLm1vdXNlRXZlbnRUb0NvbnRhaW5lclBvaW50KGUpO1xuXG5cdFx0dmFyIGJvdW5kcyA9IG5ldyBCb3VuZHModGhpcy5fcG9pbnQsIHRoaXMuX3N0YXJ0UG9pbnQpLFxuXHRcdCAgICBzaXplID0gYm91bmRzLmdldFNpemUoKTtcblxuXHRcdHNldFBvc2l0aW9uKHRoaXMuX2JveCwgYm91bmRzLm1pbik7XG5cblx0XHR0aGlzLl9ib3guc3R5bGUud2lkdGggID0gc2l6ZS54ICsgJ3B4Jztcblx0XHR0aGlzLl9ib3guc3R5bGUuaGVpZ2h0ID0gc2l6ZS55ICsgJ3B4Jztcblx0fSxcblxuXHRfZmluaXNoOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX21vdmVkKSB7XG5cdFx0XHRyZW1vdmUodGhpcy5fYm94KTtcblx0XHRcdHJlbW92ZUNsYXNzKHRoaXMuX2NvbnRhaW5lciwgJ2xlYWZsZXQtY3Jvc3NoYWlyJyk7XG5cdFx0fVxuXG5cdFx0ZW5hYmxlVGV4dFNlbGVjdGlvbigpO1xuXHRcdGVuYWJsZUltYWdlRHJhZygpO1xuXG5cdFx0b2ZmKGRvY3VtZW50LCB7XG5cdFx0XHRjb250ZXh0bWVudTogc3RvcCxcblx0XHRcdG1vdXNlbW92ZTogdGhpcy5fb25Nb3VzZU1vdmUsXG5cdFx0XHRtb3VzZXVwOiB0aGlzLl9vbk1vdXNlVXAsXG5cdFx0XHRrZXlkb3duOiB0aGlzLl9vbktleURvd25cblx0XHR9LCB0aGlzKTtcblx0fSxcblxuXHRfb25Nb3VzZVVwOiBmdW5jdGlvbiAoZSkge1xuXHRcdGlmICgoZS53aGljaCAhPT0gMSkgJiYgKGUuYnV0dG9uICE9PSAxKSkgeyByZXR1cm47IH1cblxuXHRcdHRoaXMuX2ZpbmlzaCgpO1xuXG5cdFx0aWYgKCF0aGlzLl9tb3ZlZCkgeyByZXR1cm47IH1cblx0XHQvLyBQb3N0cG9uZSB0byBuZXh0IEpTIHRpY2sgc28gaW50ZXJuYWwgY2xpY2sgZXZlbnQgaGFuZGxpbmdcblx0XHQvLyBzdGlsbCBzZWUgaXQgYXMgXCJtb3ZlZFwiLlxuXHRcdHRoaXMuX2NsZWFyRGVmZXJyZWRSZXNldFN0YXRlKCk7XG5cdFx0dGhpcy5fcmVzZXRTdGF0ZVRpbWVvdXQgPSBzZXRUaW1lb3V0KGJpbmQodGhpcy5fcmVzZXRTdGF0ZSwgdGhpcyksIDApO1xuXG5cdFx0dmFyIGJvdW5kcyA9IG5ldyBMYXRMbmdCb3VuZHMoXG5cdFx0ICAgICAgICB0aGlzLl9tYXAuY29udGFpbmVyUG9pbnRUb0xhdExuZyh0aGlzLl9zdGFydFBvaW50KSxcblx0XHQgICAgICAgIHRoaXMuX21hcC5jb250YWluZXJQb2ludFRvTGF0TG5nKHRoaXMuX3BvaW50KSk7XG5cblx0XHR0aGlzLl9tYXBcblx0XHRcdC5maXRCb3VuZHMoYm91bmRzKVxuXHRcdFx0LmZpcmUoJ2JveHpvb21lbmQnLCB7Ym94Wm9vbUJvdW5kczogYm91bmRzfSk7XG5cdH0sXG5cblx0X29uS2V5RG93bjogZnVuY3Rpb24gKGUpIHtcblx0XHRpZiAoZS5rZXlDb2RlID09PSAyNykge1xuXHRcdFx0dGhpcy5fZmluaXNoKCk7XG5cdFx0fVxuXHR9XG59KTtcblxuLy8gQHNlY3Rpb24gSGFuZGxlcnNcbi8vIEBwcm9wZXJ0eSBib3hab29tOiBIYW5kbGVyXG4vLyBCb3ggKHNoaWZ0LWRyYWcgd2l0aCBtb3VzZSkgem9vbSBoYW5kbGVyLlxuTWFwLmFkZEluaXRIb29rKCdhZGRIYW5kbGVyJywgJ2JveFpvb20nLCBCb3hab29tKTtcblxuLypcbiAqIEwuSGFuZGxlci5Eb3VibGVDbGlja1pvb20gaXMgdXNlZCB0byBoYW5kbGUgZG91YmxlLWNsaWNrIHpvb20gb24gdGhlIG1hcCwgZW5hYmxlZCBieSBkZWZhdWx0LlxuICovXG5cbi8vIEBuYW1lc3BhY2UgTWFwXG4vLyBAc2VjdGlvbiBJbnRlcmFjdGlvbiBPcHRpb25zXG5cbk1hcC5tZXJnZU9wdGlvbnMoe1xuXHQvLyBAb3B0aW9uIGRvdWJsZUNsaWNrWm9vbTogQm9vbGVhbnxTdHJpbmcgPSB0cnVlXG5cdC8vIFdoZXRoZXIgdGhlIG1hcCBjYW4gYmUgem9vbWVkIGluIGJ5IGRvdWJsZSBjbGlja2luZyBvbiBpdCBhbmRcblx0Ly8gem9vbWVkIG91dCBieSBkb3VibGUgY2xpY2tpbmcgd2hpbGUgaG9sZGluZyBzaGlmdC4gSWYgcGFzc2VkXG5cdC8vIGAnY2VudGVyJ2AsIGRvdWJsZS1jbGljayB6b29tIHdpbGwgem9vbSB0byB0aGUgY2VudGVyIG9mIHRoZVxuXHQvLyAgdmlldyByZWdhcmRsZXNzIG9mIHdoZXJlIHRoZSBtb3VzZSB3YXMuXG5cdGRvdWJsZUNsaWNrWm9vbTogdHJ1ZVxufSk7XG5cbnZhciBEb3VibGVDbGlja1pvb20gPSBIYW5kbGVyLmV4dGVuZCh7XG5cdGFkZEhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5fbWFwLm9uKCdkYmxjbGljaycsIHRoaXMuX29uRG91YmxlQ2xpY2ssIHRoaXMpO1xuXHR9LFxuXG5cdHJlbW92ZUhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5fbWFwLm9mZignZGJsY2xpY2snLCB0aGlzLl9vbkRvdWJsZUNsaWNrLCB0aGlzKTtcblx0fSxcblxuXHRfb25Eb3VibGVDbGljazogZnVuY3Rpb24gKGUpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBvbGRab29tID0gbWFwLmdldFpvb20oKSxcblx0XHQgICAgZGVsdGEgPSBtYXAub3B0aW9ucy56b29tRGVsdGEsXG5cdFx0ICAgIHpvb20gPSBlLm9yaWdpbmFsRXZlbnQuc2hpZnRLZXkgPyBvbGRab29tIC0gZGVsdGEgOiBvbGRab29tICsgZGVsdGE7XG5cblx0XHRpZiAobWFwLm9wdGlvbnMuZG91YmxlQ2xpY2tab29tID09PSAnY2VudGVyJykge1xuXHRcdFx0bWFwLnNldFpvb20oem9vbSk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdG1hcC5zZXRab29tQXJvdW5kKGUuY29udGFpbmVyUG9pbnQsIHpvb20pO1xuXHRcdH1cblx0fVxufSk7XG5cbi8vIEBzZWN0aW9uIEhhbmRsZXJzXG4vL1xuLy8gTWFwIHByb3BlcnRpZXMgaW5jbHVkZSBpbnRlcmFjdGlvbiBoYW5kbGVycyB0aGF0IGFsbG93IHlvdSB0byBjb250cm9sXG4vLyBpbnRlcmFjdGlvbiBiZWhhdmlvciBpbiBydW50aW1lLCBlbmFibGluZyBvciBkaXNhYmxpbmcgY2VydGFpbiBmZWF0dXJlcyBzdWNoXG4vLyBhcyBkcmFnZ2luZyBvciB0b3VjaCB6b29tIChzZWUgYEhhbmRsZXJgIG1ldGhvZHMpLiBGb3IgZXhhbXBsZTpcbi8vXG4vLyBgYGBqc1xuLy8gbWFwLmRvdWJsZUNsaWNrWm9vbS5kaXNhYmxlKCk7XG4vLyBgYGBcbi8vXG4vLyBAcHJvcGVydHkgZG91YmxlQ2xpY2tab29tOiBIYW5kbGVyXG4vLyBEb3VibGUgY2xpY2sgem9vbSBoYW5kbGVyLlxuTWFwLmFkZEluaXRIb29rKCdhZGRIYW5kbGVyJywgJ2RvdWJsZUNsaWNrWm9vbScsIERvdWJsZUNsaWNrWm9vbSk7XG5cbi8qXG4gKiBMLkhhbmRsZXIuTWFwRHJhZyBpcyB1c2VkIHRvIG1ha2UgdGhlIG1hcCBkcmFnZ2FibGUgKHdpdGggcGFubmluZyBpbmVydGlhKSwgZW5hYmxlZCBieSBkZWZhdWx0LlxuICovXG5cbi8vIEBuYW1lc3BhY2UgTWFwXG4vLyBAc2VjdGlvbiBJbnRlcmFjdGlvbiBPcHRpb25zXG5NYXAubWVyZ2VPcHRpb25zKHtcblx0Ly8gQG9wdGlvbiBkcmFnZ2luZzogQm9vbGVhbiA9IHRydWVcblx0Ly8gV2hldGhlciB0aGUgbWFwIGJlIGRyYWdnYWJsZSB3aXRoIG1vdXNlL3RvdWNoIG9yIG5vdC5cblx0ZHJhZ2dpbmc6IHRydWUsXG5cblx0Ly8gQHNlY3Rpb24gUGFubmluZyBJbmVydGlhIE9wdGlvbnNcblx0Ly8gQG9wdGlvbiBpbmVydGlhOiBCb29sZWFuID0gKlxuXHQvLyBJZiBlbmFibGVkLCBwYW5uaW5nIG9mIHRoZSBtYXAgd2lsbCBoYXZlIGFuIGluZXJ0aWEgZWZmZWN0IHdoZXJlXG5cdC8vIHRoZSBtYXAgYnVpbGRzIG1vbWVudHVtIHdoaWxlIGRyYWdnaW5nIGFuZCBjb250aW51ZXMgbW92aW5nIGluXG5cdC8vIHRoZSBzYW1lIGRpcmVjdGlvbiBmb3Igc29tZSB0aW1lLiBGZWVscyBlc3BlY2lhbGx5IG5pY2Ugb24gdG91Y2hcblx0Ly8gZGV2aWNlcy4gRW5hYmxlZCBieSBkZWZhdWx0IHVubGVzcyBydW5uaW5nIG9uIG9sZCBBbmRyb2lkIGRldmljZXMuXG5cdGluZXJ0aWE6ICFhbmRyb2lkMjMsXG5cblx0Ly8gQG9wdGlvbiBpbmVydGlhRGVjZWxlcmF0aW9uOiBOdW1iZXIgPSAzMDAwXG5cdC8vIFRoZSByYXRlIHdpdGggd2hpY2ggdGhlIGluZXJ0aWFsIG1vdmVtZW50IHNsb3dzIGRvd24sIGluIHBpeGVscy9zZWNvbmTCsi5cblx0aW5lcnRpYURlY2VsZXJhdGlvbjogMzQwMCwgLy8gcHgvc14yXG5cblx0Ly8gQG9wdGlvbiBpbmVydGlhTWF4U3BlZWQ6IE51bWJlciA9IEluZmluaXR5XG5cdC8vIE1heCBzcGVlZCBvZiB0aGUgaW5lcnRpYWwgbW92ZW1lbnQsIGluIHBpeGVscy9zZWNvbmQuXG5cdGluZXJ0aWFNYXhTcGVlZDogSW5maW5pdHksIC8vIHB4L3NcblxuXHQvLyBAb3B0aW9uIGVhc2VMaW5lYXJpdHk6IE51bWJlciA9IDAuMlxuXHRlYXNlTGluZWFyaXR5OiAwLjIsXG5cblx0Ly8gVE9ETyByZWZhY3RvciwgbW92ZSB0byBDUlNcblx0Ly8gQG9wdGlvbiB3b3JsZENvcHlKdW1wOiBCb29sZWFuID0gZmFsc2Vcblx0Ly8gV2l0aCB0aGlzIG9wdGlvbiBlbmFibGVkLCB0aGUgbWFwIHRyYWNrcyB3aGVuIHlvdSBwYW4gdG8gYW5vdGhlciBcImNvcHlcIlxuXHQvLyBvZiB0aGUgd29ybGQgYW5kIHNlYW1sZXNzbHkganVtcHMgdG8gdGhlIG9yaWdpbmFsIG9uZSBzbyB0aGF0IGFsbCBvdmVybGF5c1xuXHQvLyBsaWtlIG1hcmtlcnMgYW5kIHZlY3RvciBsYXllcnMgYXJlIHN0aWxsIHZpc2libGUuXG5cdHdvcmxkQ29weUp1bXA6IGZhbHNlLFxuXG5cdC8vIEBvcHRpb24gbWF4Qm91bmRzVmlzY29zaXR5OiBOdW1iZXIgPSAwLjBcblx0Ly8gSWYgYG1heEJvdW5kc2AgaXMgc2V0LCB0aGlzIG9wdGlvbiB3aWxsIGNvbnRyb2wgaG93IHNvbGlkIHRoZSBib3VuZHNcblx0Ly8gYXJlIHdoZW4gZHJhZ2dpbmcgdGhlIG1hcCBhcm91bmQuIFRoZSBkZWZhdWx0IHZhbHVlIG9mIGAwLjBgIGFsbG93cyB0aGVcblx0Ly8gdXNlciB0byBkcmFnIG91dHNpZGUgdGhlIGJvdW5kcyBhdCBub3JtYWwgc3BlZWQsIGhpZ2hlciB2YWx1ZXMgd2lsbFxuXHQvLyBzbG93IGRvd24gbWFwIGRyYWdnaW5nIG91dHNpZGUgYm91bmRzLCBhbmQgYDEuMGAgbWFrZXMgdGhlIGJvdW5kcyBmdWxseVxuXHQvLyBzb2xpZCwgcHJldmVudGluZyB0aGUgdXNlciBmcm9tIGRyYWdnaW5nIG91dHNpZGUgdGhlIGJvdW5kcy5cblx0bWF4Qm91bmRzVmlzY29zaXR5OiAwLjBcbn0pO1xuXG52YXIgRHJhZyA9IEhhbmRsZXIuZXh0ZW5kKHtcblx0YWRkSG9va3M6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAoIXRoaXMuX2RyYWdnYWJsZSkge1xuXHRcdFx0dmFyIG1hcCA9IHRoaXMuX21hcDtcblxuXHRcdFx0dGhpcy5fZHJhZ2dhYmxlID0gbmV3IERyYWdnYWJsZShtYXAuX21hcFBhbmUsIG1hcC5fY29udGFpbmVyKTtcblxuXHRcdFx0dGhpcy5fZHJhZ2dhYmxlLm9uKHtcblx0XHRcdFx0ZHJhZ3N0YXJ0OiB0aGlzLl9vbkRyYWdTdGFydCxcblx0XHRcdFx0ZHJhZzogdGhpcy5fb25EcmFnLFxuXHRcdFx0XHRkcmFnZW5kOiB0aGlzLl9vbkRyYWdFbmRcblx0XHRcdH0sIHRoaXMpO1xuXG5cdFx0XHR0aGlzLl9kcmFnZ2FibGUub24oJ3ByZWRyYWcnLCB0aGlzLl9vblByZURyYWdMaW1pdCwgdGhpcyk7XG5cdFx0XHRpZiAobWFwLm9wdGlvbnMud29ybGRDb3B5SnVtcCkge1xuXHRcdFx0XHR0aGlzLl9kcmFnZ2FibGUub24oJ3ByZWRyYWcnLCB0aGlzLl9vblByZURyYWdXcmFwLCB0aGlzKTtcblx0XHRcdFx0bWFwLm9uKCd6b29tZW5kJywgdGhpcy5fb25ab29tRW5kLCB0aGlzKTtcblxuXHRcdFx0XHRtYXAud2hlblJlYWR5KHRoaXMuX29uWm9vbUVuZCwgdGhpcyk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGFkZENsYXNzKHRoaXMuX21hcC5fY29udGFpbmVyLCAnbGVhZmxldC1ncmFiIGxlYWZsZXQtdG91Y2gtZHJhZycpO1xuXHRcdHRoaXMuX2RyYWdnYWJsZS5lbmFibGUoKTtcblx0XHR0aGlzLl9wb3NpdGlvbnMgPSBbXTtcblx0XHR0aGlzLl90aW1lcyA9IFtdO1xuXHR9LFxuXG5cdHJlbW92ZUhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmVtb3ZlQ2xhc3ModGhpcy5fbWFwLl9jb250YWluZXIsICdsZWFmbGV0LWdyYWInKTtcblx0XHRyZW1vdmVDbGFzcyh0aGlzLl9tYXAuX2NvbnRhaW5lciwgJ2xlYWZsZXQtdG91Y2gtZHJhZycpO1xuXHRcdHRoaXMuX2RyYWdnYWJsZS5kaXNhYmxlKCk7XG5cdH0sXG5cblx0bW92ZWQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fZHJhZ2dhYmxlICYmIHRoaXMuX2RyYWdnYWJsZS5fbW92ZWQ7XG5cdH0sXG5cblx0bW92aW5nOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2RyYWdnYWJsZSAmJiB0aGlzLl9kcmFnZ2FibGUuX21vdmluZztcblx0fSxcblxuXHRfb25EcmFnU3RhcnQ6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwO1xuXG5cdFx0bWFwLl9zdG9wKCk7XG5cdFx0aWYgKHRoaXMuX21hcC5vcHRpb25zLm1heEJvdW5kcyAmJiB0aGlzLl9tYXAub3B0aW9ucy5tYXhCb3VuZHNWaXNjb3NpdHkpIHtcblx0XHRcdHZhciBib3VuZHMgPSB0b0xhdExuZ0JvdW5kcyh0aGlzLl9tYXAub3B0aW9ucy5tYXhCb3VuZHMpO1xuXG5cdFx0XHR0aGlzLl9vZmZzZXRMaW1pdCA9IHRvQm91bmRzKFxuXHRcdFx0XHR0aGlzLl9tYXAubGF0TG5nVG9Db250YWluZXJQb2ludChib3VuZHMuZ2V0Tm9ydGhXZXN0KCkpLm11bHRpcGx5QnkoLTEpLFxuXHRcdFx0XHR0aGlzLl9tYXAubGF0TG5nVG9Db250YWluZXJQb2ludChib3VuZHMuZ2V0U291dGhFYXN0KCkpLm11bHRpcGx5QnkoLTEpXG5cdFx0XHRcdFx0LmFkZCh0aGlzLl9tYXAuZ2V0U2l6ZSgpKSk7XG5cblx0XHRcdHRoaXMuX3Zpc2Nvc2l0eSA9IE1hdGgubWluKDEuMCwgTWF0aC5tYXgoMC4wLCB0aGlzLl9tYXAub3B0aW9ucy5tYXhCb3VuZHNWaXNjb3NpdHkpKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5fb2Zmc2V0TGltaXQgPSBudWxsO1xuXHRcdH1cblxuXHRcdG1hcFxuXHRcdCAgICAuZmlyZSgnbW92ZXN0YXJ0Jylcblx0XHQgICAgLmZpcmUoJ2RyYWdzdGFydCcpO1xuXG5cdFx0aWYgKG1hcC5vcHRpb25zLmluZXJ0aWEpIHtcblx0XHRcdHRoaXMuX3Bvc2l0aW9ucyA9IFtdO1xuXHRcdFx0dGhpcy5fdGltZXMgPSBbXTtcblx0XHR9XG5cdH0sXG5cblx0X29uRHJhZzogZnVuY3Rpb24gKGUpIHtcblx0XHRpZiAodGhpcy5fbWFwLm9wdGlvbnMuaW5lcnRpYSkge1xuXHRcdFx0dmFyIHRpbWUgPSB0aGlzLl9sYXN0VGltZSA9ICtuZXcgRGF0ZSgpLFxuXHRcdFx0ICAgIHBvcyA9IHRoaXMuX2xhc3RQb3MgPSB0aGlzLl9kcmFnZ2FibGUuX2Fic1BvcyB8fCB0aGlzLl9kcmFnZ2FibGUuX25ld1BvcztcblxuXHRcdFx0dGhpcy5fcG9zaXRpb25zLnB1c2gocG9zKTtcblx0XHRcdHRoaXMuX3RpbWVzLnB1c2godGltZSk7XG5cblx0XHRcdHRoaXMuX3BydW5lUG9zaXRpb25zKHRpbWUpO1xuXHRcdH1cblxuXHRcdHRoaXMuX21hcFxuXHRcdCAgICAuZmlyZSgnbW92ZScsIGUpXG5cdFx0ICAgIC5maXJlKCdkcmFnJywgZSk7XG5cdH0sXG5cblx0X3BydW5lUG9zaXRpb25zOiBmdW5jdGlvbiAodGltZSkge1xuXHRcdHdoaWxlICh0aGlzLl9wb3NpdGlvbnMubGVuZ3RoID4gMSAmJiB0aW1lIC0gdGhpcy5fdGltZXNbMF0gPiA1MCkge1xuXHRcdFx0dGhpcy5fcG9zaXRpb25zLnNoaWZ0KCk7XG5cdFx0XHR0aGlzLl90aW1lcy5zaGlmdCgpO1xuXHRcdH1cblx0fSxcblxuXHRfb25ab29tRW5kOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHB4Q2VudGVyID0gdGhpcy5fbWFwLmdldFNpemUoKS5kaXZpZGVCeSgyKSxcblx0XHQgICAgcHhXb3JsZENlbnRlciA9IHRoaXMuX21hcC5sYXRMbmdUb0xheWVyUG9pbnQoWzAsIDBdKTtcblxuXHRcdHRoaXMuX2luaXRpYWxXb3JsZE9mZnNldCA9IHB4V29ybGRDZW50ZXIuc3VidHJhY3QocHhDZW50ZXIpLng7XG5cdFx0dGhpcy5fd29ybGRXaWR0aCA9IHRoaXMuX21hcC5nZXRQaXhlbFdvcmxkQm91bmRzKCkuZ2V0U2l6ZSgpLng7XG5cdH0sXG5cblx0X3Zpc2NvdXNMaW1pdDogZnVuY3Rpb24gKHZhbHVlLCB0aHJlc2hvbGQpIHtcblx0XHRyZXR1cm4gdmFsdWUgLSAodmFsdWUgLSB0aHJlc2hvbGQpICogdGhpcy5fdmlzY29zaXR5O1xuXHR9LFxuXG5cdF9vblByZURyYWdMaW1pdDogZnVuY3Rpb24gKCkge1xuXHRcdGlmICghdGhpcy5fdmlzY29zaXR5IHx8ICF0aGlzLl9vZmZzZXRMaW1pdCkgeyByZXR1cm47IH1cblxuXHRcdHZhciBvZmZzZXQgPSB0aGlzLl9kcmFnZ2FibGUuX25ld1Bvcy5zdWJ0cmFjdCh0aGlzLl9kcmFnZ2FibGUuX3N0YXJ0UG9zKTtcblxuXHRcdHZhciBsaW1pdCA9IHRoaXMuX29mZnNldExpbWl0O1xuXHRcdGlmIChvZmZzZXQueCA8IGxpbWl0Lm1pbi54KSB7IG9mZnNldC54ID0gdGhpcy5fdmlzY291c0xpbWl0KG9mZnNldC54LCBsaW1pdC5taW4ueCk7IH1cblx0XHRpZiAob2Zmc2V0LnkgPCBsaW1pdC5taW4ueSkgeyBvZmZzZXQueSA9IHRoaXMuX3Zpc2NvdXNMaW1pdChvZmZzZXQueSwgbGltaXQubWluLnkpOyB9XG5cdFx0aWYgKG9mZnNldC54ID4gbGltaXQubWF4LngpIHsgb2Zmc2V0LnggPSB0aGlzLl92aXNjb3VzTGltaXQob2Zmc2V0LngsIGxpbWl0Lm1heC54KTsgfVxuXHRcdGlmIChvZmZzZXQueSA+IGxpbWl0Lm1heC55KSB7IG9mZnNldC55ID0gdGhpcy5fdmlzY291c0xpbWl0KG9mZnNldC55LCBsaW1pdC5tYXgueSk7IH1cblxuXHRcdHRoaXMuX2RyYWdnYWJsZS5fbmV3UG9zID0gdGhpcy5fZHJhZ2dhYmxlLl9zdGFydFBvcy5hZGQob2Zmc2V0KTtcblx0fSxcblxuXHRfb25QcmVEcmFnV3JhcDogZnVuY3Rpb24gKCkge1xuXHRcdC8vIFRPRE8gcmVmYWN0b3IgdG8gYmUgYWJsZSB0byBhZGp1c3QgbWFwIHBhbmUgcG9zaXRpb24gYWZ0ZXIgem9vbVxuXHRcdHZhciB3b3JsZFdpZHRoID0gdGhpcy5fd29ybGRXaWR0aCxcblx0XHQgICAgaGFsZldpZHRoID0gTWF0aC5yb3VuZCh3b3JsZFdpZHRoIC8gMiksXG5cdFx0ICAgIGR4ID0gdGhpcy5faW5pdGlhbFdvcmxkT2Zmc2V0LFxuXHRcdCAgICB4ID0gdGhpcy5fZHJhZ2dhYmxlLl9uZXdQb3MueCxcblx0XHQgICAgbmV3WDEgPSAoeCAtIGhhbGZXaWR0aCArIGR4KSAlIHdvcmxkV2lkdGggKyBoYWxmV2lkdGggLSBkeCxcblx0XHQgICAgbmV3WDIgPSAoeCArIGhhbGZXaWR0aCArIGR4KSAlIHdvcmxkV2lkdGggLSBoYWxmV2lkdGggLSBkeCxcblx0XHQgICAgbmV3WCA9IE1hdGguYWJzKG5ld1gxICsgZHgpIDwgTWF0aC5hYnMobmV3WDIgKyBkeCkgPyBuZXdYMSA6IG5ld1gyO1xuXG5cdFx0dGhpcy5fZHJhZ2dhYmxlLl9hYnNQb3MgPSB0aGlzLl9kcmFnZ2FibGUuX25ld1Bvcy5jbG9uZSgpO1xuXHRcdHRoaXMuX2RyYWdnYWJsZS5fbmV3UG9zLnggPSBuZXdYO1xuXHR9LFxuXG5cdF9vbkRyYWdFbmQ6IGZ1bmN0aW9uIChlKSB7XG5cdFx0dmFyIG1hcCA9IHRoaXMuX21hcCxcblx0XHQgICAgb3B0aW9ucyA9IG1hcC5vcHRpb25zLFxuXG5cdFx0ICAgIG5vSW5lcnRpYSA9ICFvcHRpb25zLmluZXJ0aWEgfHwgdGhpcy5fdGltZXMubGVuZ3RoIDwgMjtcblxuXHRcdG1hcC5maXJlKCdkcmFnZW5kJywgZSk7XG5cblx0XHRpZiAobm9JbmVydGlhKSB7XG5cdFx0XHRtYXAuZmlyZSgnbW92ZWVuZCcpO1xuXG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuX3BydW5lUG9zaXRpb25zKCtuZXcgRGF0ZSgpKTtcblxuXHRcdFx0dmFyIGRpcmVjdGlvbiA9IHRoaXMuX2xhc3RQb3Muc3VidHJhY3QodGhpcy5fcG9zaXRpb25zWzBdKSxcblx0XHRcdCAgICBkdXJhdGlvbiA9ICh0aGlzLl9sYXN0VGltZSAtIHRoaXMuX3RpbWVzWzBdKSAvIDEwMDAsXG5cdFx0XHQgICAgZWFzZSA9IG9wdGlvbnMuZWFzZUxpbmVhcml0eSxcblxuXHRcdFx0ICAgIHNwZWVkVmVjdG9yID0gZGlyZWN0aW9uLm11bHRpcGx5QnkoZWFzZSAvIGR1cmF0aW9uKSxcblx0XHRcdCAgICBzcGVlZCA9IHNwZWVkVmVjdG9yLmRpc3RhbmNlVG8oWzAsIDBdKSxcblxuXHRcdFx0ICAgIGxpbWl0ZWRTcGVlZCA9IE1hdGgubWluKG9wdGlvbnMuaW5lcnRpYU1heFNwZWVkLCBzcGVlZCksXG5cdFx0XHQgICAgbGltaXRlZFNwZWVkVmVjdG9yID0gc3BlZWRWZWN0b3IubXVsdGlwbHlCeShsaW1pdGVkU3BlZWQgLyBzcGVlZCksXG5cblx0XHRcdCAgICBkZWNlbGVyYXRpb25EdXJhdGlvbiA9IGxpbWl0ZWRTcGVlZCAvIChvcHRpb25zLmluZXJ0aWFEZWNlbGVyYXRpb24gKiBlYXNlKSxcblx0XHRcdCAgICBvZmZzZXQgPSBsaW1pdGVkU3BlZWRWZWN0b3IubXVsdGlwbHlCeSgtZGVjZWxlcmF0aW9uRHVyYXRpb24gLyAyKS5yb3VuZCgpO1xuXG5cdFx0XHRpZiAoIW9mZnNldC54ICYmICFvZmZzZXQueSkge1xuXHRcdFx0XHRtYXAuZmlyZSgnbW92ZWVuZCcpO1xuXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRvZmZzZXQgPSBtYXAuX2xpbWl0T2Zmc2V0KG9mZnNldCwgbWFwLm9wdGlvbnMubWF4Qm91bmRzKTtcblxuXHRcdFx0XHRyZXF1ZXN0QW5pbUZyYW1lKGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRtYXAucGFuQnkob2Zmc2V0LCB7XG5cdFx0XHRcdFx0XHRkdXJhdGlvbjogZGVjZWxlcmF0aW9uRHVyYXRpb24sXG5cdFx0XHRcdFx0XHRlYXNlTGluZWFyaXR5OiBlYXNlLFxuXHRcdFx0XHRcdFx0bm9Nb3ZlU3RhcnQ6IHRydWUsXG5cdFx0XHRcdFx0XHRhbmltYXRlOiB0cnVlXG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxufSk7XG5cbi8vIEBzZWN0aW9uIEhhbmRsZXJzXG4vLyBAcHJvcGVydHkgZHJhZ2dpbmc6IEhhbmRsZXJcbi8vIE1hcCBkcmFnZ2luZyBoYW5kbGVyIChieSBib3RoIG1vdXNlIGFuZCB0b3VjaCkuXG5NYXAuYWRkSW5pdEhvb2soJ2FkZEhhbmRsZXInLCAnZHJhZ2dpbmcnLCBEcmFnKTtcblxuLypcbiAqIEwuTWFwLktleWJvYXJkIGlzIGhhbmRsaW5nIGtleWJvYXJkIGludGVyYWN0aW9uIHdpdGggdGhlIG1hcCwgZW5hYmxlZCBieSBkZWZhdWx0LlxuICovXG5cbi8vIEBuYW1lc3BhY2UgTWFwXG4vLyBAc2VjdGlvbiBLZXlib2FyZCBOYXZpZ2F0aW9uIE9wdGlvbnNcbk1hcC5tZXJnZU9wdGlvbnMoe1xuXHQvLyBAb3B0aW9uIGtleWJvYXJkOiBCb29sZWFuID0gdHJ1ZVxuXHQvLyBNYWtlcyB0aGUgbWFwIGZvY3VzYWJsZSBhbmQgYWxsb3dzIHVzZXJzIHRvIG5hdmlnYXRlIHRoZSBtYXAgd2l0aCBrZXlib2FyZFxuXHQvLyBhcnJvd3MgYW5kIGArYC9gLWAga2V5cy5cblx0a2V5Ym9hcmQ6IHRydWUsXG5cblx0Ly8gQG9wdGlvbiBrZXlib2FyZFBhbkRlbHRhOiBOdW1iZXIgPSA4MFxuXHQvLyBBbW91bnQgb2YgcGl4ZWxzIHRvIHBhbiB3aGVuIHByZXNzaW5nIGFuIGFycm93IGtleS5cblx0a2V5Ym9hcmRQYW5EZWx0YTogODBcbn0pO1xuXG52YXIgS2V5Ym9hcmQgPSBIYW5kbGVyLmV4dGVuZCh7XG5cblx0a2V5Q29kZXM6IHtcblx0XHRsZWZ0OiAgICBbMzddLFxuXHRcdHJpZ2h0OiAgIFszOV0sXG5cdFx0ZG93bjogICAgWzQwXSxcblx0XHR1cDogICAgICBbMzhdLFxuXHRcdHpvb21JbjogIFsxODcsIDEwNywgNjEsIDE3MV0sXG5cdFx0em9vbU91dDogWzE4OSwgMTA5LCA1NCwgMTczXVxuXHR9LFxuXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChtYXApIHtcblx0XHR0aGlzLl9tYXAgPSBtYXA7XG5cblx0XHR0aGlzLl9zZXRQYW5EZWx0YShtYXAub3B0aW9ucy5rZXlib2FyZFBhbkRlbHRhKTtcblx0XHR0aGlzLl9zZXRab29tRGVsdGEobWFwLm9wdGlvbnMuem9vbURlbHRhKTtcblx0fSxcblxuXHRhZGRIb29rczogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBjb250YWluZXIgPSB0aGlzLl9tYXAuX2NvbnRhaW5lcjtcblxuXHRcdC8vIG1ha2UgdGhlIGNvbnRhaW5lciBmb2N1c2FibGUgYnkgdGFiYmluZ1xuXHRcdGlmIChjb250YWluZXIudGFiSW5kZXggPD0gMCkge1xuXHRcdFx0Y29udGFpbmVyLnRhYkluZGV4ID0gJzAnO1xuXHRcdH1cblxuXHRcdG9uKGNvbnRhaW5lciwge1xuXHRcdFx0Zm9jdXM6IHRoaXMuX29uRm9jdXMsXG5cdFx0XHRibHVyOiB0aGlzLl9vbkJsdXIsXG5cdFx0XHRtb3VzZWRvd246IHRoaXMuX29uTW91c2VEb3duXG5cdFx0fSwgdGhpcyk7XG5cblx0XHR0aGlzLl9tYXAub24oe1xuXHRcdFx0Zm9jdXM6IHRoaXMuX2FkZEhvb2tzLFxuXHRcdFx0Ymx1cjogdGhpcy5fcmVtb3ZlSG9va3Ncblx0XHR9LCB0aGlzKTtcblx0fSxcblxuXHRyZW1vdmVIb29rczogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3JlbW92ZUhvb2tzKCk7XG5cblx0XHRvZmYodGhpcy5fbWFwLl9jb250YWluZXIsIHtcblx0XHRcdGZvY3VzOiB0aGlzLl9vbkZvY3VzLFxuXHRcdFx0Ymx1cjogdGhpcy5fb25CbHVyLFxuXHRcdFx0bW91c2Vkb3duOiB0aGlzLl9vbk1vdXNlRG93blxuXHRcdH0sIHRoaXMpO1xuXG5cdFx0dGhpcy5fbWFwLm9mZih7XG5cdFx0XHRmb2N1czogdGhpcy5fYWRkSG9va3MsXG5cdFx0XHRibHVyOiB0aGlzLl9yZW1vdmVIb29rc1xuXHRcdH0sIHRoaXMpO1xuXHR9LFxuXG5cdF9vbk1vdXNlRG93bjogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9mb2N1c2VkKSB7IHJldHVybjsgfVxuXG5cdFx0dmFyIGJvZHkgPSBkb2N1bWVudC5ib2R5LFxuXHRcdCAgICBkb2NFbCA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCxcblx0XHQgICAgdG9wID0gYm9keS5zY3JvbGxUb3AgfHwgZG9jRWwuc2Nyb2xsVG9wLFxuXHRcdCAgICBsZWZ0ID0gYm9keS5zY3JvbGxMZWZ0IHx8IGRvY0VsLnNjcm9sbExlZnQ7XG5cblx0XHR0aGlzLl9tYXAuX2NvbnRhaW5lci5mb2N1cygpO1xuXG5cdFx0d2luZG93LnNjcm9sbFRvKGxlZnQsIHRvcCk7XG5cdH0sXG5cblx0X29uRm9jdXM6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9mb2N1c2VkID0gdHJ1ZTtcblx0XHR0aGlzLl9tYXAuZmlyZSgnZm9jdXMnKTtcblx0fSxcblxuXHRfb25CbHVyOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5fZm9jdXNlZCA9IGZhbHNlO1xuXHRcdHRoaXMuX21hcC5maXJlKCdibHVyJyk7XG5cdH0sXG5cblx0X3NldFBhbkRlbHRhOiBmdW5jdGlvbiAocGFuRGVsdGEpIHtcblx0XHR2YXIga2V5cyA9IHRoaXMuX3BhbktleXMgPSB7fSxcblx0XHQgICAgY29kZXMgPSB0aGlzLmtleUNvZGVzLFxuXHRcdCAgICBpLCBsZW47XG5cblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBjb2Rlcy5sZWZ0Lmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRrZXlzW2NvZGVzLmxlZnRbaV1dID0gWy0xICogcGFuRGVsdGEsIDBdO1xuXHRcdH1cblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBjb2Rlcy5yaWdodC5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuXHRcdFx0a2V5c1tjb2Rlcy5yaWdodFtpXV0gPSBbcGFuRGVsdGEsIDBdO1xuXHRcdH1cblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBjb2Rlcy5kb3duLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRrZXlzW2NvZGVzLmRvd25baV1dID0gWzAsIHBhbkRlbHRhXTtcblx0XHR9XG5cdFx0Zm9yIChpID0gMCwgbGVuID0gY29kZXMudXAubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdGtleXNbY29kZXMudXBbaV1dID0gWzAsIC0xICogcGFuRGVsdGFdO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0Wm9vbURlbHRhOiBmdW5jdGlvbiAoem9vbURlbHRhKSB7XG5cdFx0dmFyIGtleXMgPSB0aGlzLl96b29tS2V5cyA9IHt9LFxuXHRcdCAgICBjb2RlcyA9IHRoaXMua2V5Q29kZXMsXG5cdFx0ICAgIGksIGxlbjtcblxuXHRcdGZvciAoaSA9IDAsIGxlbiA9IGNvZGVzLnpvb21Jbi5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuXHRcdFx0a2V5c1tjb2Rlcy56b29tSW5baV1dID0gem9vbURlbHRhO1xuXHRcdH1cblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBjb2Rlcy56b29tT3V0Lmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRrZXlzW2NvZGVzLnpvb21PdXRbaV1dID0gLXpvb21EZWx0YTtcblx0XHR9XG5cdH0sXG5cblx0X2FkZEhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0b24oZG9jdW1lbnQsICdrZXlkb3duJywgdGhpcy5fb25LZXlEb3duLCB0aGlzKTtcblx0fSxcblxuXHRfcmVtb3ZlSG9va3M6IGZ1bmN0aW9uICgpIHtcblx0XHRvZmYoZG9jdW1lbnQsICdrZXlkb3duJywgdGhpcy5fb25LZXlEb3duLCB0aGlzKTtcblx0fSxcblxuXHRfb25LZXlEb3duOiBmdW5jdGlvbiAoZSkge1xuXHRcdGlmIChlLmFsdEtleSB8fCBlLmN0cmxLZXkgfHwgZS5tZXRhS2V5KSB7IHJldHVybjsgfVxuXG5cdFx0dmFyIGtleSA9IGUua2V5Q29kZSxcblx0XHQgICAgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBvZmZzZXQ7XG5cblx0XHRpZiAoa2V5IGluIHRoaXMuX3BhbktleXMpIHtcblxuXHRcdFx0aWYgKG1hcC5fcGFuQW5pbSAmJiBtYXAuX3BhbkFuaW0uX2luUHJvZ3Jlc3MpIHsgcmV0dXJuOyB9XG5cblx0XHRcdG9mZnNldCA9IHRoaXMuX3BhbktleXNba2V5XTtcblx0XHRcdGlmIChlLnNoaWZ0S2V5KSB7XG5cdFx0XHRcdG9mZnNldCA9IHRvUG9pbnQob2Zmc2V0KS5tdWx0aXBseUJ5KDMpO1xuXHRcdFx0fVxuXG5cdFx0XHRtYXAucGFuQnkob2Zmc2V0KTtcblxuXHRcdFx0aWYgKG1hcC5vcHRpb25zLm1heEJvdW5kcykge1xuXHRcdFx0XHRtYXAucGFuSW5zaWRlQm91bmRzKG1hcC5vcHRpb25zLm1heEJvdW5kcyk7XG5cdFx0XHR9XG5cblx0XHR9IGVsc2UgaWYgKGtleSBpbiB0aGlzLl96b29tS2V5cykge1xuXHRcdFx0bWFwLnNldFpvb20obWFwLmdldFpvb20oKSArIChlLnNoaWZ0S2V5ID8gMyA6IDEpICogdGhpcy5fem9vbUtleXNba2V5XSk7XG5cblx0XHR9IGVsc2UgaWYgKGtleSA9PT0gMjcgJiYgbWFwLl9wb3B1cCAmJiBtYXAuX3BvcHVwLm9wdGlvbnMuY2xvc2VPbkVzY2FwZUtleSkge1xuXHRcdFx0bWFwLmNsb3NlUG9wdXAoKTtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0c3RvcChlKTtcblx0fVxufSk7XG5cbi8vIEBzZWN0aW9uIEhhbmRsZXJzXG4vLyBAc2VjdGlvbiBIYW5kbGVyc1xuLy8gQHByb3BlcnR5IGtleWJvYXJkOiBIYW5kbGVyXG4vLyBLZXlib2FyZCBuYXZpZ2F0aW9uIGhhbmRsZXIuXG5NYXAuYWRkSW5pdEhvb2soJ2FkZEhhbmRsZXInLCAna2V5Ym9hcmQnLCBLZXlib2FyZCk7XG5cbi8qXG4gKiBMLkhhbmRsZXIuU2Nyb2xsV2hlZWxab29tIGlzIHVzZWQgYnkgTC5NYXAgdG8gZW5hYmxlIG1vdXNlIHNjcm9sbCB3aGVlbCB6b29tIG9uIHRoZSBtYXAuXG4gKi9cblxuLy8gQG5hbWVzcGFjZSBNYXBcbi8vIEBzZWN0aW9uIEludGVyYWN0aW9uIE9wdGlvbnNcbk1hcC5tZXJnZU9wdGlvbnMoe1xuXHQvLyBAc2VjdGlvbiBNb3VzZXdoZWVsIG9wdGlvbnNcblx0Ly8gQG9wdGlvbiBzY3JvbGxXaGVlbFpvb206IEJvb2xlYW58U3RyaW5nID0gdHJ1ZVxuXHQvLyBXaGV0aGVyIHRoZSBtYXAgY2FuIGJlIHpvb21lZCBieSB1c2luZyB0aGUgbW91c2Ugd2hlZWwuIElmIHBhc3NlZCBgJ2NlbnRlcidgLFxuXHQvLyBpdCB3aWxsIHpvb20gdG8gdGhlIGNlbnRlciBvZiB0aGUgdmlldyByZWdhcmRsZXNzIG9mIHdoZXJlIHRoZSBtb3VzZSB3YXMuXG5cdHNjcm9sbFdoZWVsWm9vbTogdHJ1ZSxcblxuXHQvLyBAb3B0aW9uIHdoZWVsRGVib3VuY2VUaW1lOiBOdW1iZXIgPSA0MFxuXHQvLyBMaW1pdHMgdGhlIHJhdGUgYXQgd2hpY2ggYSB3aGVlbCBjYW4gZmlyZSAoaW4gbWlsbGlzZWNvbmRzKS4gQnkgZGVmYXVsdFxuXHQvLyB1c2VyIGNhbid0IHpvb20gdmlhIHdoZWVsIG1vcmUgb2Z0ZW4gdGhhbiBvbmNlIHBlciA0MCBtcy5cblx0d2hlZWxEZWJvdW5jZVRpbWU6IDQwLFxuXG5cdC8vIEBvcHRpb24gd2hlZWxQeFBlclpvb21MZXZlbDogTnVtYmVyID0gNjBcblx0Ly8gSG93IG1hbnkgc2Nyb2xsIHBpeGVscyAoYXMgcmVwb3J0ZWQgYnkgW0wuRG9tRXZlbnQuZ2V0V2hlZWxEZWx0YV0oI2RvbWV2ZW50LWdldHdoZWVsZGVsdGEpKVxuXHQvLyBtZWFuIGEgY2hhbmdlIG9mIG9uZSBmdWxsIHpvb20gbGV2ZWwuIFNtYWxsZXIgdmFsdWVzIHdpbGwgbWFrZSB3aGVlbC16b29taW5nXG5cdC8vIGZhc3RlciAoYW5kIHZpY2UgdmVyc2EpLlxuXHR3aGVlbFB4UGVyWm9vbUxldmVsOiA2MFxufSk7XG5cbnZhciBTY3JvbGxXaGVlbFpvb20gPSBIYW5kbGVyLmV4dGVuZCh7XG5cdGFkZEhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0b24odGhpcy5fbWFwLl9jb250YWluZXIsICdtb3VzZXdoZWVsJywgdGhpcy5fb25XaGVlbFNjcm9sbCwgdGhpcyk7XG5cblx0XHR0aGlzLl9kZWx0YSA9IDA7XG5cdH0sXG5cblx0cmVtb3ZlSG9va3M6IGZ1bmN0aW9uICgpIHtcblx0XHRvZmYodGhpcy5fbWFwLl9jb250YWluZXIsICdtb3VzZXdoZWVsJywgdGhpcy5fb25XaGVlbFNjcm9sbCwgdGhpcyk7XG5cdH0sXG5cblx0X29uV2hlZWxTY3JvbGw6IGZ1bmN0aW9uIChlKSB7XG5cdFx0dmFyIGRlbHRhID0gZ2V0V2hlZWxEZWx0YShlKTtcblxuXHRcdHZhciBkZWJvdW5jZSA9IHRoaXMuX21hcC5vcHRpb25zLndoZWVsRGVib3VuY2VUaW1lO1xuXG5cdFx0dGhpcy5fZGVsdGEgKz0gZGVsdGE7XG5cdFx0dGhpcy5fbGFzdE1vdXNlUG9zID0gdGhpcy5fbWFwLm1vdXNlRXZlbnRUb0NvbnRhaW5lclBvaW50KGUpO1xuXG5cdFx0aWYgKCF0aGlzLl9zdGFydFRpbWUpIHtcblx0XHRcdHRoaXMuX3N0YXJ0VGltZSA9ICtuZXcgRGF0ZSgpO1xuXHRcdH1cblxuXHRcdHZhciBsZWZ0ID0gTWF0aC5tYXgoZGVib3VuY2UgLSAoK25ldyBEYXRlKCkgLSB0aGlzLl9zdGFydFRpbWUpLCAwKTtcblxuXHRcdGNsZWFyVGltZW91dCh0aGlzLl90aW1lcik7XG5cdFx0dGhpcy5fdGltZXIgPSBzZXRUaW1lb3V0KGJpbmQodGhpcy5fcGVyZm9ybVpvb20sIHRoaXMpLCBsZWZ0KTtcblxuXHRcdHN0b3AoZSk7XG5cdH0sXG5cblx0X3BlcmZvcm1ab29tOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIG1hcCA9IHRoaXMuX21hcCxcblx0XHQgICAgem9vbSA9IG1hcC5nZXRab29tKCksXG5cdFx0ICAgIHNuYXAgPSB0aGlzLl9tYXAub3B0aW9ucy56b29tU25hcCB8fCAwO1xuXG5cdFx0bWFwLl9zdG9wKCk7IC8vIHN0b3AgcGFubmluZyBhbmQgZmx5IGFuaW1hdGlvbnMgaWYgYW55XG5cblx0XHQvLyBtYXAgdGhlIGRlbHRhIHdpdGggYSBzaWdtb2lkIGZ1bmN0aW9uIHRvIC00Li40IHJhbmdlIGxlYW5pbmcgb24gLTEuLjFcblx0XHR2YXIgZDIgPSB0aGlzLl9kZWx0YSAvICh0aGlzLl9tYXAub3B0aW9ucy53aGVlbFB4UGVyWm9vbUxldmVsICogNCksXG5cdFx0ICAgIGQzID0gNCAqIE1hdGgubG9nKDIgLyAoMSArIE1hdGguZXhwKC1NYXRoLmFicyhkMikpKSkgLyBNYXRoLkxOMixcblx0XHQgICAgZDQgPSBzbmFwID8gTWF0aC5jZWlsKGQzIC8gc25hcCkgKiBzbmFwIDogZDMsXG5cdFx0ICAgIGRlbHRhID0gbWFwLl9saW1pdFpvb20oem9vbSArICh0aGlzLl9kZWx0YSA+IDAgPyBkNCA6IC1kNCkpIC0gem9vbTtcblxuXHRcdHRoaXMuX2RlbHRhID0gMDtcblx0XHR0aGlzLl9zdGFydFRpbWUgPSBudWxsO1xuXG5cdFx0aWYgKCFkZWx0YSkgeyByZXR1cm47IH1cblxuXHRcdGlmIChtYXAub3B0aW9ucy5zY3JvbGxXaGVlbFpvb20gPT09ICdjZW50ZXInKSB7XG5cdFx0XHRtYXAuc2V0Wm9vbSh6b29tICsgZGVsdGEpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRtYXAuc2V0Wm9vbUFyb3VuZCh0aGlzLl9sYXN0TW91c2VQb3MsIHpvb20gKyBkZWx0YSk7XG5cdFx0fVxuXHR9XG59KTtcblxuLy8gQHNlY3Rpb24gSGFuZGxlcnNcbi8vIEBwcm9wZXJ0eSBzY3JvbGxXaGVlbFpvb206IEhhbmRsZXJcbi8vIFNjcm9sbCB3aGVlbCB6b29tIGhhbmRsZXIuXG5NYXAuYWRkSW5pdEhvb2soJ2FkZEhhbmRsZXInLCAnc2Nyb2xsV2hlZWxab29tJywgU2Nyb2xsV2hlZWxab29tKTtcblxuLypcbiAqIEwuTWFwLlRhcCBpcyB1c2VkIHRvIGVuYWJsZSBtb2JpbGUgaGFja3MgbGlrZSBxdWljayB0YXBzIGFuZCBsb25nIGhvbGQuXG4gKi9cblxuLy8gQG5hbWVzcGFjZSBNYXBcbi8vIEBzZWN0aW9uIEludGVyYWN0aW9uIE9wdGlvbnNcbk1hcC5tZXJnZU9wdGlvbnMoe1xuXHQvLyBAc2VjdGlvbiBUb3VjaCBpbnRlcmFjdGlvbiBvcHRpb25zXG5cdC8vIEBvcHRpb24gdGFwOiBCb29sZWFuID0gdHJ1ZVxuXHQvLyBFbmFibGVzIG1vYmlsZSBoYWNrcyBmb3Igc3VwcG9ydGluZyBpbnN0YW50IHRhcHMgKGZpeGluZyAyMDBtcyBjbGlja1xuXHQvLyBkZWxheSBvbiBpT1MvQW5kcm9pZCkgYW5kIHRvdWNoIGhvbGRzIChmaXJlZCBhcyBgY29udGV4dG1lbnVgIGV2ZW50cykuXG5cdHRhcDogdHJ1ZSxcblxuXHQvLyBAb3B0aW9uIHRhcFRvbGVyYW5jZTogTnVtYmVyID0gMTVcblx0Ly8gVGhlIG1heCBudW1iZXIgb2YgcGl4ZWxzIGEgdXNlciBjYW4gc2hpZnQgaGlzIGZpbmdlciBkdXJpbmcgdG91Y2hcblx0Ly8gZm9yIGl0IHRvIGJlIGNvbnNpZGVyZWQgYSB2YWxpZCB0YXAuXG5cdHRhcFRvbGVyYW5jZTogMTVcbn0pO1xuXG52YXIgVGFwID0gSGFuZGxlci5leHRlbmQoe1xuXHRhZGRIb29rczogZnVuY3Rpb24gKCkge1xuXHRcdG9uKHRoaXMuX21hcC5fY29udGFpbmVyLCAndG91Y2hzdGFydCcsIHRoaXMuX29uRG93biwgdGhpcyk7XG5cdH0sXG5cblx0cmVtb3ZlSG9va3M6IGZ1bmN0aW9uICgpIHtcblx0XHRvZmYodGhpcy5fbWFwLl9jb250YWluZXIsICd0b3VjaHN0YXJ0JywgdGhpcy5fb25Eb3duLCB0aGlzKTtcblx0fSxcblxuXHRfb25Eb3duOiBmdW5jdGlvbiAoZSkge1xuXHRcdGlmICghZS50b3VjaGVzKSB7IHJldHVybjsgfVxuXG5cdFx0cHJldmVudERlZmF1bHQoZSk7XG5cblx0XHR0aGlzLl9maXJlQ2xpY2sgPSB0cnVlO1xuXG5cdFx0Ly8gZG9uJ3Qgc2ltdWxhdGUgY2xpY2sgb3IgdHJhY2sgbG9uZ3ByZXNzIGlmIG1vcmUgdGhhbiAxIHRvdWNoXG5cdFx0aWYgKGUudG91Y2hlcy5sZW5ndGggPiAxKSB7XG5cdFx0XHR0aGlzLl9maXJlQ2xpY2sgPSBmYWxzZTtcblx0XHRcdGNsZWFyVGltZW91dCh0aGlzLl9ob2xkVGltZW91dCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIGZpcnN0ID0gZS50b3VjaGVzWzBdLFxuXHRcdCAgICBlbCA9IGZpcnN0LnRhcmdldDtcblxuXHRcdHRoaXMuX3N0YXJ0UG9zID0gdGhpcy5fbmV3UG9zID0gbmV3IFBvaW50KGZpcnN0LmNsaWVudFgsIGZpcnN0LmNsaWVudFkpO1xuXG5cdFx0Ly8gaWYgdG91Y2hpbmcgYSBsaW5rLCBoaWdobGlnaHQgaXRcblx0XHRpZiAoZWwudGFnTmFtZSAmJiBlbC50YWdOYW1lLnRvTG93ZXJDYXNlKCkgPT09ICdhJykge1xuXHRcdFx0YWRkQ2xhc3MoZWwsICdsZWFmbGV0LWFjdGl2ZScpO1xuXHRcdH1cblxuXHRcdC8vIHNpbXVsYXRlIGxvbmcgaG9sZCBidXQgc2V0dGluZyBhIHRpbWVvdXRcblx0XHR0aGlzLl9ob2xkVGltZW91dCA9IHNldFRpbWVvdXQoYmluZChmdW5jdGlvbiAoKSB7XG5cdFx0XHRpZiAodGhpcy5faXNUYXBWYWxpZCgpKSB7XG5cdFx0XHRcdHRoaXMuX2ZpcmVDbGljayA9IGZhbHNlO1xuXHRcdFx0XHR0aGlzLl9vblVwKCk7XG5cdFx0XHRcdHRoaXMuX3NpbXVsYXRlRXZlbnQoJ2NvbnRleHRtZW51JywgZmlyc3QpO1xuXHRcdFx0fVxuXHRcdH0sIHRoaXMpLCAxMDAwKTtcblxuXHRcdHRoaXMuX3NpbXVsYXRlRXZlbnQoJ21vdXNlZG93bicsIGZpcnN0KTtcblxuXHRcdG9uKGRvY3VtZW50LCB7XG5cdFx0XHR0b3VjaG1vdmU6IHRoaXMuX29uTW92ZSxcblx0XHRcdHRvdWNoZW5kOiB0aGlzLl9vblVwXG5cdFx0fSwgdGhpcyk7XG5cdH0sXG5cblx0X29uVXA6IGZ1bmN0aW9uIChlKSB7XG5cdFx0Y2xlYXJUaW1lb3V0KHRoaXMuX2hvbGRUaW1lb3V0KTtcblxuXHRcdG9mZihkb2N1bWVudCwge1xuXHRcdFx0dG91Y2htb3ZlOiB0aGlzLl9vbk1vdmUsXG5cdFx0XHR0b3VjaGVuZDogdGhpcy5fb25VcFxuXHRcdH0sIHRoaXMpO1xuXG5cdFx0aWYgKHRoaXMuX2ZpcmVDbGljayAmJiBlICYmIGUuY2hhbmdlZFRvdWNoZXMpIHtcblxuXHRcdFx0dmFyIGZpcnN0ID0gZS5jaGFuZ2VkVG91Y2hlc1swXSxcblx0XHRcdCAgICBlbCA9IGZpcnN0LnRhcmdldDtcblxuXHRcdFx0aWYgKGVsICYmIGVsLnRhZ05hbWUgJiYgZWwudGFnTmFtZS50b0xvd2VyQ2FzZSgpID09PSAnYScpIHtcblx0XHRcdFx0cmVtb3ZlQ2xhc3MoZWwsICdsZWFmbGV0LWFjdGl2ZScpO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLl9zaW11bGF0ZUV2ZW50KCdtb3VzZXVwJywgZmlyc3QpO1xuXG5cdFx0XHQvLyBzaW11bGF0ZSBjbGljayBpZiB0aGUgdG91Y2ggZGlkbid0IG1vdmUgdG9vIG11Y2hcblx0XHRcdGlmICh0aGlzLl9pc1RhcFZhbGlkKCkpIHtcblx0XHRcdFx0dGhpcy5fc2ltdWxhdGVFdmVudCgnY2xpY2snLCBmaXJzdCk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdF9pc1RhcFZhbGlkOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX25ld1Bvcy5kaXN0YW5jZVRvKHRoaXMuX3N0YXJ0UG9zKSA8PSB0aGlzLl9tYXAub3B0aW9ucy50YXBUb2xlcmFuY2U7XG5cdH0sXG5cblx0X29uTW92ZTogZnVuY3Rpb24gKGUpIHtcblx0XHR2YXIgZmlyc3QgPSBlLnRvdWNoZXNbMF07XG5cdFx0dGhpcy5fbmV3UG9zID0gbmV3IFBvaW50KGZpcnN0LmNsaWVudFgsIGZpcnN0LmNsaWVudFkpO1xuXHRcdHRoaXMuX3NpbXVsYXRlRXZlbnQoJ21vdXNlbW92ZScsIGZpcnN0KTtcblx0fSxcblxuXHRfc2ltdWxhdGVFdmVudDogZnVuY3Rpb24gKHR5cGUsIGUpIHtcblx0XHR2YXIgc2ltdWxhdGVkRXZlbnQgPSBkb2N1bWVudC5jcmVhdGVFdmVudCgnTW91c2VFdmVudHMnKTtcblxuXHRcdHNpbXVsYXRlZEV2ZW50Ll9zaW11bGF0ZWQgPSB0cnVlO1xuXHRcdGUudGFyZ2V0Ll9zaW11bGF0ZWRDbGljayA9IHRydWU7XG5cblx0XHRzaW11bGF0ZWRFdmVudC5pbml0TW91c2VFdmVudChcblx0XHQgICAgICAgIHR5cGUsIHRydWUsIHRydWUsIHdpbmRvdywgMSxcblx0XHQgICAgICAgIGUuc2NyZWVuWCwgZS5zY3JlZW5ZLFxuXHRcdCAgICAgICAgZS5jbGllbnRYLCBlLmNsaWVudFksXG5cdFx0ICAgICAgICBmYWxzZSwgZmFsc2UsIGZhbHNlLCBmYWxzZSwgMCwgbnVsbCk7XG5cblx0XHRlLnRhcmdldC5kaXNwYXRjaEV2ZW50KHNpbXVsYXRlZEV2ZW50KTtcblx0fVxufSk7XG5cbi8vIEBzZWN0aW9uIEhhbmRsZXJzXG4vLyBAcHJvcGVydHkgdGFwOiBIYW5kbGVyXG4vLyBNb2JpbGUgdG91Y2ggaGFja3MgKHF1aWNrIHRhcCBhbmQgdG91Y2ggaG9sZCkgaGFuZGxlci5cbmlmICh0b3VjaCAmJiAhcG9pbnRlcikge1xuXHRNYXAuYWRkSW5pdEhvb2soJ2FkZEhhbmRsZXInLCAndGFwJywgVGFwKTtcbn1cblxuLypcbiAqIEwuSGFuZGxlci5Ub3VjaFpvb20gaXMgdXNlZCBieSBMLk1hcCB0byBhZGQgcGluY2ggem9vbSBvbiBzdXBwb3J0ZWQgbW9iaWxlIGJyb3dzZXJzLlxuICovXG5cbi8vIEBuYW1lc3BhY2UgTWFwXG4vLyBAc2VjdGlvbiBJbnRlcmFjdGlvbiBPcHRpb25zXG5NYXAubWVyZ2VPcHRpb25zKHtcblx0Ly8gQHNlY3Rpb24gVG91Y2ggaW50ZXJhY3Rpb24gb3B0aW9uc1xuXHQvLyBAb3B0aW9uIHRvdWNoWm9vbTogQm9vbGVhbnxTdHJpbmcgPSAqXG5cdC8vIFdoZXRoZXIgdGhlIG1hcCBjYW4gYmUgem9vbWVkIGJ5IHRvdWNoLWRyYWdnaW5nIHdpdGggdHdvIGZpbmdlcnMuIElmXG5cdC8vIHBhc3NlZCBgJ2NlbnRlcidgLCBpdCB3aWxsIHpvb20gdG8gdGhlIGNlbnRlciBvZiB0aGUgdmlldyByZWdhcmRsZXNzIG9mXG5cdC8vIHdoZXJlIHRoZSB0b3VjaCBldmVudHMgKGZpbmdlcnMpIHdlcmUuIEVuYWJsZWQgZm9yIHRvdWNoLWNhcGFibGUgd2ViXG5cdC8vIGJyb3dzZXJzIGV4Y2VwdCBmb3Igb2xkIEFuZHJvaWRzLlxuXHR0b3VjaFpvb206IHRvdWNoICYmICFhbmRyb2lkMjMsXG5cblx0Ly8gQG9wdGlvbiBib3VuY2VBdFpvb21MaW1pdHM6IEJvb2xlYW4gPSB0cnVlXG5cdC8vIFNldCBpdCB0byBmYWxzZSBpZiB5b3UgZG9uJ3Qgd2FudCB0aGUgbWFwIHRvIHpvb20gYmV5b25kIG1pbi9tYXggem9vbVxuXHQvLyBhbmQgdGhlbiBib3VuY2UgYmFjayB3aGVuIHBpbmNoLXpvb21pbmcuXG5cdGJvdW5jZUF0Wm9vbUxpbWl0czogdHJ1ZVxufSk7XG5cbnZhciBUb3VjaFpvb20gPSBIYW5kbGVyLmV4dGVuZCh7XG5cdGFkZEhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0YWRkQ2xhc3ModGhpcy5fbWFwLl9jb250YWluZXIsICdsZWFmbGV0LXRvdWNoLXpvb20nKTtcblx0XHRvbih0aGlzLl9tYXAuX2NvbnRhaW5lciwgJ3RvdWNoc3RhcnQnLCB0aGlzLl9vblRvdWNoU3RhcnQsIHRoaXMpO1xuXHR9LFxuXG5cdHJlbW92ZUhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmVtb3ZlQ2xhc3ModGhpcy5fbWFwLl9jb250YWluZXIsICdsZWFmbGV0LXRvdWNoLXpvb20nKTtcblx0XHRvZmYodGhpcy5fbWFwLl9jb250YWluZXIsICd0b3VjaHN0YXJ0JywgdGhpcy5fb25Ub3VjaFN0YXJ0LCB0aGlzKTtcblx0fSxcblxuXHRfb25Ub3VjaFN0YXJ0OiBmdW5jdGlvbiAoZSkge1xuXHRcdHZhciBtYXAgPSB0aGlzLl9tYXA7XG5cdFx0aWYgKCFlLnRvdWNoZXMgfHwgZS50b3VjaGVzLmxlbmd0aCAhPT0gMiB8fCBtYXAuX2FuaW1hdGluZ1pvb20gfHwgdGhpcy5fem9vbWluZykgeyByZXR1cm47IH1cblxuXHRcdHZhciBwMSA9IG1hcC5tb3VzZUV2ZW50VG9Db250YWluZXJQb2ludChlLnRvdWNoZXNbMF0pLFxuXHRcdCAgICBwMiA9IG1hcC5tb3VzZUV2ZW50VG9Db250YWluZXJQb2ludChlLnRvdWNoZXNbMV0pO1xuXG5cdFx0dGhpcy5fY2VudGVyUG9pbnQgPSBtYXAuZ2V0U2l6ZSgpLl9kaXZpZGVCeSgyKTtcblx0XHR0aGlzLl9zdGFydExhdExuZyA9IG1hcC5jb250YWluZXJQb2ludFRvTGF0TG5nKHRoaXMuX2NlbnRlclBvaW50KTtcblx0XHRpZiAobWFwLm9wdGlvbnMudG91Y2hab29tICE9PSAnY2VudGVyJykge1xuXHRcdFx0dGhpcy5fcGluY2hTdGFydExhdExuZyA9IG1hcC5jb250YWluZXJQb2ludFRvTGF0TG5nKHAxLmFkZChwMikuX2RpdmlkZUJ5KDIpKTtcblx0XHR9XG5cblx0XHR0aGlzLl9zdGFydERpc3QgPSBwMS5kaXN0YW5jZVRvKHAyKTtcblx0XHR0aGlzLl9zdGFydFpvb20gPSBtYXAuZ2V0Wm9vbSgpO1xuXG5cdFx0dGhpcy5fbW92ZWQgPSBmYWxzZTtcblx0XHR0aGlzLl96b29taW5nID0gdHJ1ZTtcblxuXHRcdG1hcC5fc3RvcCgpO1xuXG5cdFx0b24oZG9jdW1lbnQsICd0b3VjaG1vdmUnLCB0aGlzLl9vblRvdWNoTW92ZSwgdGhpcyk7XG5cdFx0b24oZG9jdW1lbnQsICd0b3VjaGVuZCcsIHRoaXMuX29uVG91Y2hFbmQsIHRoaXMpO1xuXG5cdFx0cHJldmVudERlZmF1bHQoZSk7XG5cdH0sXG5cblx0X29uVG91Y2hNb3ZlOiBmdW5jdGlvbiAoZSkge1xuXHRcdGlmICghZS50b3VjaGVzIHx8IGUudG91Y2hlcy5sZW5ndGggIT09IDIgfHwgIXRoaXMuX3pvb21pbmcpIHsgcmV0dXJuOyB9XG5cblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBwMSA9IG1hcC5tb3VzZUV2ZW50VG9Db250YWluZXJQb2ludChlLnRvdWNoZXNbMF0pLFxuXHRcdCAgICBwMiA9IG1hcC5tb3VzZUV2ZW50VG9Db250YWluZXJQb2ludChlLnRvdWNoZXNbMV0pLFxuXHRcdCAgICBzY2FsZSA9IHAxLmRpc3RhbmNlVG8ocDIpIC8gdGhpcy5fc3RhcnREaXN0O1xuXG5cdFx0dGhpcy5fem9vbSA9IG1hcC5nZXRTY2FsZVpvb20oc2NhbGUsIHRoaXMuX3N0YXJ0Wm9vbSk7XG5cblx0XHRpZiAoIW1hcC5vcHRpb25zLmJvdW5jZUF0Wm9vbUxpbWl0cyAmJiAoXG5cdFx0XHQodGhpcy5fem9vbSA8IG1hcC5nZXRNaW5ab29tKCkgJiYgc2NhbGUgPCAxKSB8fFxuXHRcdFx0KHRoaXMuX3pvb20gPiBtYXAuZ2V0TWF4Wm9vbSgpICYmIHNjYWxlID4gMSkpKSB7XG5cdFx0XHR0aGlzLl96b29tID0gbWFwLl9saW1pdFpvb20odGhpcy5fem9vbSk7XG5cdFx0fVxuXG5cdFx0aWYgKG1hcC5vcHRpb25zLnRvdWNoWm9vbSA9PT0gJ2NlbnRlcicpIHtcblx0XHRcdHRoaXMuX2NlbnRlciA9IHRoaXMuX3N0YXJ0TGF0TG5nO1xuXHRcdFx0aWYgKHNjYWxlID09PSAxKSB7IHJldHVybjsgfVxuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBHZXQgZGVsdGEgZnJvbSBwaW5jaCB0byBjZW50ZXIsIHNvIGNlbnRlckxhdExuZyBpcyBkZWx0YSBhcHBsaWVkIHRvIGluaXRpYWwgcGluY2hMYXRMbmdcblx0XHRcdHZhciBkZWx0YSA9IHAxLl9hZGQocDIpLl9kaXZpZGVCeSgyKS5fc3VidHJhY3QodGhpcy5fY2VudGVyUG9pbnQpO1xuXHRcdFx0aWYgKHNjYWxlID09PSAxICYmIGRlbHRhLnggPT09IDAgJiYgZGVsdGEueSA9PT0gMCkgeyByZXR1cm47IH1cblx0XHRcdHRoaXMuX2NlbnRlciA9IG1hcC51bnByb2plY3QobWFwLnByb2plY3QodGhpcy5fcGluY2hTdGFydExhdExuZywgdGhpcy5fem9vbSkuc3VidHJhY3QoZGVsdGEpLCB0aGlzLl96b29tKTtcblx0XHR9XG5cblx0XHRpZiAoIXRoaXMuX21vdmVkKSB7XG5cdFx0XHRtYXAuX21vdmVTdGFydCh0cnVlLCBmYWxzZSk7XG5cdFx0XHR0aGlzLl9tb3ZlZCA9IHRydWU7XG5cdFx0fVxuXG5cdFx0Y2FuY2VsQW5pbUZyYW1lKHRoaXMuX2FuaW1SZXF1ZXN0KTtcblxuXHRcdHZhciBtb3ZlRm4gPSBiaW5kKG1hcC5fbW92ZSwgbWFwLCB0aGlzLl9jZW50ZXIsIHRoaXMuX3pvb20sIHtwaW5jaDogdHJ1ZSwgcm91bmQ6IGZhbHNlfSk7XG5cdFx0dGhpcy5fYW5pbVJlcXVlc3QgPSByZXF1ZXN0QW5pbUZyYW1lKG1vdmVGbiwgdGhpcywgdHJ1ZSk7XG5cblx0XHRwcmV2ZW50RGVmYXVsdChlKTtcblx0fSxcblxuXHRfb25Ub3VjaEVuZDogZnVuY3Rpb24gKCkge1xuXHRcdGlmICghdGhpcy5fbW92ZWQgfHwgIXRoaXMuX3pvb21pbmcpIHtcblx0XHRcdHRoaXMuX3pvb21pbmcgPSBmYWxzZTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLl96b29taW5nID0gZmFsc2U7XG5cdFx0Y2FuY2VsQW5pbUZyYW1lKHRoaXMuX2FuaW1SZXF1ZXN0KTtcblxuXHRcdG9mZihkb2N1bWVudCwgJ3RvdWNobW92ZScsIHRoaXMuX29uVG91Y2hNb3ZlKTtcblx0XHRvZmYoZG9jdW1lbnQsICd0b3VjaGVuZCcsIHRoaXMuX29uVG91Y2hFbmQpO1xuXG5cdFx0Ly8gUGluY2ggdXBkYXRlcyBHcmlkTGF5ZXJzJyBsZXZlbHMgb25seSB3aGVuIHpvb21TbmFwIGlzIG9mZiwgc28gem9vbVNuYXAgYmVjb21lcyBub1VwZGF0ZS5cblx0XHRpZiAodGhpcy5fbWFwLm9wdGlvbnMuem9vbUFuaW1hdGlvbikge1xuXHRcdFx0dGhpcy5fbWFwLl9hbmltYXRlWm9vbSh0aGlzLl9jZW50ZXIsIHRoaXMuX21hcC5fbGltaXRab29tKHRoaXMuX3pvb20pLCB0cnVlLCB0aGlzLl9tYXAub3B0aW9ucy56b29tU25hcCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuX21hcC5fcmVzZXRWaWV3KHRoaXMuX2NlbnRlciwgdGhpcy5fbWFwLl9saW1pdFpvb20odGhpcy5fem9vbSkpO1xuXHRcdH1cblx0fVxufSk7XG5cbi8vIEBzZWN0aW9uIEhhbmRsZXJzXG4vLyBAcHJvcGVydHkgdG91Y2hab29tOiBIYW5kbGVyXG4vLyBUb3VjaCB6b29tIGhhbmRsZXIuXG5NYXAuYWRkSW5pdEhvb2soJ2FkZEhhbmRsZXInLCAndG91Y2hab29tJywgVG91Y2hab29tKTtcblxuTWFwLkJveFpvb20gPSBCb3hab29tO1xuTWFwLkRvdWJsZUNsaWNrWm9vbSA9IERvdWJsZUNsaWNrWm9vbTtcbk1hcC5EcmFnID0gRHJhZztcbk1hcC5LZXlib2FyZCA9IEtleWJvYXJkO1xuTWFwLlNjcm9sbFdoZWVsWm9vbSA9IFNjcm9sbFdoZWVsWm9vbTtcbk1hcC5UYXAgPSBUYXA7XG5NYXAuVG91Y2hab29tID0gVG91Y2hab29tO1xuXG4vLyBtaXNjXHJcblxyXG52YXIgb2xkTCA9IHdpbmRvdy5MO1xyXG5mdW5jdGlvbiBub0NvbmZsaWN0KCkge1xyXG5cdHdpbmRvdy5MID0gb2xkTDtcclxuXHRyZXR1cm4gdGhpcztcclxufVxyXG5cclxuLy8gQWx3YXlzIGV4cG9ydCB1cyB0byB3aW5kb3cgZ2xvYmFsIChzZWUgIzIzNjQpXHJcbndpbmRvdy5MID0gZXhwb3J0cztcclxuXHJcbk9iamVjdC5mcmVlemUgPSBmcmVlemU7XG5cbmV4cG9ydHMudmVyc2lvbiA9IHZlcnNpb247XG5leHBvcnRzLm5vQ29uZmxpY3QgPSBub0NvbmZsaWN0O1xuZXhwb3J0cy5Db250cm9sID0gQ29udHJvbDtcbmV4cG9ydHMuY29udHJvbCA9IGNvbnRyb2w7XG5leHBvcnRzLkJyb3dzZXIgPSBCcm93c2VyO1xuZXhwb3J0cy5FdmVudGVkID0gRXZlbnRlZDtcbmV4cG9ydHMuTWl4aW4gPSBNaXhpbjtcbmV4cG9ydHMuVXRpbCA9IFV0aWw7XG5leHBvcnRzLkNsYXNzID0gQ2xhc3M7XG5leHBvcnRzLkhhbmRsZXIgPSBIYW5kbGVyO1xuZXhwb3J0cy5leHRlbmQgPSBleHRlbmQ7XG5leHBvcnRzLmJpbmQgPSBiaW5kO1xuZXhwb3J0cy5zdGFtcCA9IHN0YW1wO1xuZXhwb3J0cy5zZXRPcHRpb25zID0gc2V0T3B0aW9ucztcbmV4cG9ydHMuRG9tRXZlbnQgPSBEb21FdmVudDtcbmV4cG9ydHMuRG9tVXRpbCA9IERvbVV0aWw7XG5leHBvcnRzLlBvc0FuaW1hdGlvbiA9IFBvc0FuaW1hdGlvbjtcbmV4cG9ydHMuRHJhZ2dhYmxlID0gRHJhZ2dhYmxlO1xuZXhwb3J0cy5MaW5lVXRpbCA9IExpbmVVdGlsO1xuZXhwb3J0cy5Qb2x5VXRpbCA9IFBvbHlVdGlsO1xuZXhwb3J0cy5Qb2ludCA9IFBvaW50O1xuZXhwb3J0cy5wb2ludCA9IHRvUG9pbnQ7XG5leHBvcnRzLkJvdW5kcyA9IEJvdW5kcztcbmV4cG9ydHMuYm91bmRzID0gdG9Cb3VuZHM7XG5leHBvcnRzLlRyYW5zZm9ybWF0aW9uID0gVHJhbnNmb3JtYXRpb247XG5leHBvcnRzLnRyYW5zZm9ybWF0aW9uID0gdG9UcmFuc2Zvcm1hdGlvbjtcbmV4cG9ydHMuUHJvamVjdGlvbiA9IGluZGV4O1xuZXhwb3J0cy5MYXRMbmcgPSBMYXRMbmc7XG5leHBvcnRzLmxhdExuZyA9IHRvTGF0TG5nO1xuZXhwb3J0cy5MYXRMbmdCb3VuZHMgPSBMYXRMbmdCb3VuZHM7XG5leHBvcnRzLmxhdExuZ0JvdW5kcyA9IHRvTGF0TG5nQm91bmRzO1xuZXhwb3J0cy5DUlMgPSBDUlM7XG5leHBvcnRzLkdlb0pTT04gPSBHZW9KU09OO1xuZXhwb3J0cy5nZW9KU09OID0gZ2VvSlNPTjtcbmV4cG9ydHMuZ2VvSnNvbiA9IGdlb0pzb247XG5leHBvcnRzLkxheWVyID0gTGF5ZXI7XG5leHBvcnRzLkxheWVyR3JvdXAgPSBMYXllckdyb3VwO1xuZXhwb3J0cy5sYXllckdyb3VwID0gbGF5ZXJHcm91cDtcbmV4cG9ydHMuRmVhdHVyZUdyb3VwID0gRmVhdHVyZUdyb3VwO1xuZXhwb3J0cy5mZWF0dXJlR3JvdXAgPSBmZWF0dXJlR3JvdXA7XG5leHBvcnRzLkltYWdlT3ZlcmxheSA9IEltYWdlT3ZlcmxheTtcbmV4cG9ydHMuaW1hZ2VPdmVybGF5ID0gaW1hZ2VPdmVybGF5O1xuZXhwb3J0cy5WaWRlb092ZXJsYXkgPSBWaWRlb092ZXJsYXk7XG5leHBvcnRzLnZpZGVvT3ZlcmxheSA9IHZpZGVvT3ZlcmxheTtcbmV4cG9ydHMuRGl2T3ZlcmxheSA9IERpdk92ZXJsYXk7XG5leHBvcnRzLlBvcHVwID0gUG9wdXA7XG5leHBvcnRzLnBvcHVwID0gcG9wdXA7XG5leHBvcnRzLlRvb2x0aXAgPSBUb29sdGlwO1xuZXhwb3J0cy50b29sdGlwID0gdG9vbHRpcDtcbmV4cG9ydHMuSWNvbiA9IEljb247XG5leHBvcnRzLmljb24gPSBpY29uO1xuZXhwb3J0cy5EaXZJY29uID0gRGl2SWNvbjtcbmV4cG9ydHMuZGl2SWNvbiA9IGRpdkljb247XG5leHBvcnRzLk1hcmtlciA9IE1hcmtlcjtcbmV4cG9ydHMubWFya2VyID0gbWFya2VyO1xuZXhwb3J0cy5UaWxlTGF5ZXIgPSBUaWxlTGF5ZXI7XG5leHBvcnRzLnRpbGVMYXllciA9IHRpbGVMYXllcjtcbmV4cG9ydHMuR3JpZExheWVyID0gR3JpZExheWVyO1xuZXhwb3J0cy5ncmlkTGF5ZXIgPSBncmlkTGF5ZXI7XG5leHBvcnRzLlNWRyA9IFNWRztcbmV4cG9ydHMuc3ZnID0gc3ZnJDE7XG5leHBvcnRzLlJlbmRlcmVyID0gUmVuZGVyZXI7XG5leHBvcnRzLkNhbnZhcyA9IENhbnZhcztcbmV4cG9ydHMuY2FudmFzID0gY2FudmFzJDE7XG5leHBvcnRzLlBhdGggPSBQYXRoO1xuZXhwb3J0cy5DaXJjbGVNYXJrZXIgPSBDaXJjbGVNYXJrZXI7XG5leHBvcnRzLmNpcmNsZU1hcmtlciA9IGNpcmNsZU1hcmtlcjtcbmV4cG9ydHMuQ2lyY2xlID0gQ2lyY2xlO1xuZXhwb3J0cy5jaXJjbGUgPSBjaXJjbGU7XG5leHBvcnRzLlBvbHlsaW5lID0gUG9seWxpbmU7XG5leHBvcnRzLnBvbHlsaW5lID0gcG9seWxpbmU7XG5leHBvcnRzLlBvbHlnb24gPSBQb2x5Z29uO1xuZXhwb3J0cy5wb2x5Z29uID0gcG9seWdvbjtcbmV4cG9ydHMuUmVjdGFuZ2xlID0gUmVjdGFuZ2xlO1xuZXhwb3J0cy5yZWN0YW5nbGUgPSByZWN0YW5nbGU7XG5leHBvcnRzLk1hcCA9IE1hcDtcbmV4cG9ydHMubWFwID0gY3JlYXRlTWFwO1xuXG59KSkpO1xuLy8jIHNvdXJjZU1hcHBpbmdVUkw9bGVhZmxldC1zcmMuanMubWFwXG5cblxuXG4vLy8vLy8vLy8vLy8vLy8vLy9cbi8vIFdFQlBBQ0sgRk9PVEVSXG4vLyAuL25vZGVfbW9kdWxlcy9sZWFmbGV0L2Rpc3QvbGVhZmxldC1zcmMuanNcbi8vIG1vZHVsZSBpZCA9IC4vbm9kZV9tb2R1bGVzL2xlYWZsZXQvZGlzdC9sZWFmbGV0LXNyYy5qc1xuLy8gbW9kdWxlIGNodW5rcyA9IDAgMSJdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/leaflet/dist/leaflet-src.js\n");
/***/ }),
/***/ "./node_modules/process/browser.js":
/***/ (function(module, exports) {
eval("// shim for using process in browser\nvar process = module.exports = {};\n\n// cached from whatever global is present so that test runners that stub it\n// don't break things. But we need to wrap it in a try catch in case it is\n// wrapped in strict mode code which doesn't define any globals. It's inside a\n// function because try/catches deoptimize in certain engines.\n\nvar cachedSetTimeout;\nvar cachedClearTimeout;\n\nfunction defaultSetTimout() {\n throw new Error('setTimeout has not been defined');\n}\nfunction defaultClearTimeout () {\n throw new Error('clearTimeout has not been defined');\n}\n(function () {\n try {\n if (typeof setTimeout === 'function') {\n cachedSetTimeout = setTimeout;\n } else {\n cachedSetTimeout = defaultSetTimout;\n }\n } catch (e) {\n cachedSetTimeout = defaultSetTimout;\n }\n try {\n if (typeof clearTimeout === 'function') {\n cachedClearTimeout = clearTimeout;\n } else {\n cachedClearTimeout = defaultClearTimeout;\n }\n } catch (e) {\n cachedClearTimeout = defaultClearTimeout;\n }\n} ())\nfunction runTimeout(fun) {\n if (cachedSetTimeout === setTimeout) {\n //normal enviroments in sane situations\n return setTimeout(fun, 0);\n }\n // if setTimeout wasn't available but was latter defined\n if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {\n cachedSetTimeout = setTimeout;\n return setTimeout(fun, 0);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedSetTimeout(fun, 0);\n } catch(e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedSetTimeout.call(null, fun, 0);\n } catch(e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error\n return cachedSetTimeout.call(this, fun, 0);\n }\n }\n\n\n}\nfunction runClearTimeout(marker) {\n if (cachedClearTimeout === clearTimeout) {\n //normal enviroments in sane situations\n return clearTimeout(marker);\n }\n // if clearTimeout wasn't available but was latter defined\n if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {\n cachedClearTimeout = clearTimeout;\n return clearTimeout(marker);\n }\n try {\n // when when somebody has screwed with setTimeout but no I.E. maddness\n return cachedClearTimeout(marker);\n } catch (e){\n try {\n // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally\n return cachedClearTimeout.call(null, marker);\n } catch (e){\n // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.\n // Some versions of I.E. have different rules for clearTimeout vs setTimeout\n return cachedClearTimeout.call(this, marker);\n }\n }\n\n\n\n}\nvar queue = [];\nvar draining = false;\nvar currentQueue;\nvar queueIndex = -1;\n\nfunction cleanUpNextTick() {\n if (!draining || !currentQueue) {\n return;\n }\n draining = false;\n if (currentQueue.length) {\n queue = currentQueue.concat(queue);\n } else {\n queueIndex = -1;\n }\n if (queue.length) {\n drainQueue();\n }\n}\n\nfunction drainQueue() {\n if (draining) {\n return;\n }\n var timeout = runTimeout(cleanUpNextTick);\n draining = true;\n\n var len = queue.length;\n while(len) {\n currentQueue = queue;\n queue = [];\n while (++queueIndex < len) {\n if (currentQueue) {\n currentQueue[queueIndex].run();\n }\n }\n queueIndex = -1;\n len = queue.length;\n }\n currentQueue = null;\n draining = false;\n runClearTimeout(timeout);\n}\n\nprocess.nextTick = function (fun) {\n var args = new Array(arguments.length - 1);\n if (arguments.length > 1) {\n for (var i = 1; i < arguments.length; i++) {\n args[i - 1] = arguments[i];\n }\n }\n queue.push(new Item(fun, args));\n if (queue.length === 1 && !draining) {\n runTimeout(drainQueue);\n }\n};\n\n// v8 likes predictible objects\nfunction Item(fun, array) {\n this.fun = fun;\n this.array = array;\n}\nItem.prototype.run = function () {\n this.fun.apply(null, this.array);\n};\nprocess.title = 'browser';\nprocess.browser = true;\nprocess.env = {};\nprocess.argv = [];\nprocess.version = ''; // empty string to avoid regexp issues\nprocess.versions = {};\n\nfunction noop() {}\n\nprocess.on = noop;\nprocess.addListener = noop;\nprocess.once = noop;\nprocess.off = noop;\nprocess.removeListener = noop;\nprocess.removeAllListeners = noop;\nprocess.emit = noop;\nprocess.prependListener = noop;\nprocess.prependOnceListener = noop;\n\nprocess.listeners = function (name) { return [] }\n\nprocess.binding = function (name) {\n throw new Error('process.binding is not supported');\n};\n\nprocess.cwd = function () { return '/' };\nprocess.chdir = function (dir) {\n throw new Error('process.chdir is not supported');\n};\nprocess.umask = function() { return 0; };\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvcHJvY2Vzcy9icm93c2VyLmpzPzViNjkiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxDQUFDO0FBQ0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QixzQkFBc0I7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHFDQUFxQzs7QUFFckM7QUFDQTtBQUNBOztBQUVBLDJCQUEyQjtBQUMzQjtBQUNBO0FBQ0E7QUFDQSw0QkFBNEIsVUFBVSIsImZpbGUiOiIuL25vZGVfbW9kdWxlcy9wcm9jZXNzL2Jyb3dzZXIuanMuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBzaGltIGZvciB1c2luZyBwcm9jZXNzIGluIGJyb3dzZXJcbnZhciBwcm9jZXNzID0gbW9kdWxlLmV4cG9ydHMgPSB7fTtcblxuLy8gY2FjaGVkIGZyb20gd2hhdGV2ZXIgZ2xvYmFsIGlzIHByZXNlbnQgc28gdGhhdCB0ZXN0IHJ1bm5lcnMgdGhhdCBzdHViIGl0XG4vLyBkb24ndCBicmVhayB0aGluZ3MuICBCdXQgd2UgbmVlZCB0byB3cmFwIGl0IGluIGEgdHJ5IGNhdGNoIGluIGNhc2UgaXQgaXNcbi8vIHdyYXBwZWQgaW4gc3RyaWN0IG1vZGUgY29kZSB3aGljaCBkb2Vzbid0IGRlZmluZSBhbnkgZ2xvYmFscy4gIEl0J3MgaW5zaWRlIGFcbi8vIGZ1bmN0aW9uIGJlY2F1c2UgdHJ5L2NhdGNoZXMgZGVvcHRpbWl6ZSBpbiBjZXJ0YWluIGVuZ2luZXMuXG5cbnZhciBjYWNoZWRTZXRUaW1lb3V0O1xudmFyIGNhY2hlZENsZWFyVGltZW91dDtcblxuZnVuY3Rpb24gZGVmYXVsdFNldFRpbW91dCgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3NldFRpbWVvdXQgaGFzIG5vdCBiZWVuIGRlZmluZWQnKTtcbn1cbmZ1bmN0aW9uIGRlZmF1bHRDbGVhclRpbWVvdXQgKCkge1xuICAgIHRocm93IG5ldyBFcnJvcignY2xlYXJUaW1lb3V0IGhhcyBub3QgYmVlbiBkZWZpbmVkJyk7XG59XG4oZnVuY3Rpb24gKCkge1xuICAgIHRyeSB7XG4gICAgICAgIGlmICh0eXBlb2Ygc2V0VGltZW91dCA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IHNldFRpbWVvdXQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gZGVmYXVsdFNldFRpbW91dDtcbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY2FjaGVkU2V0VGltZW91dCA9IGRlZmF1bHRTZXRUaW1vdXQ7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIGlmICh0eXBlb2YgY2xlYXJUaW1lb3V0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBjbGVhclRpbWVvdXQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBkZWZhdWx0Q2xlYXJUaW1lb3V0O1xuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjYWNoZWRDbGVhclRpbWVvdXQgPSBkZWZhdWx0Q2xlYXJUaW1lb3V0O1xuICAgIH1cbn0gKCkpXG5mdW5jdGlvbiBydW5UaW1lb3V0KGZ1bikge1xuICAgIGlmIChjYWNoZWRTZXRUaW1lb3V0ID09PSBzZXRUaW1lb3V0KSB7XG4gICAgICAgIC8vbm9ybWFsIGVudmlyb21lbnRzIGluIHNhbmUgc2l0dWF0aW9uc1xuICAgICAgICByZXR1cm4gc2V0VGltZW91dChmdW4sIDApO1xuICAgIH1cbiAgICAvLyBpZiBzZXRUaW1lb3V0IHdhc24ndCBhdmFpbGFibGUgYnV0IHdhcyBsYXR0ZXIgZGVmaW5lZFxuICAgIGlmICgoY2FjaGVkU2V0VGltZW91dCA9PT0gZGVmYXVsdFNldFRpbW91dCB8fCAhY2FjaGVkU2V0VGltZW91dCkgJiYgc2V0VGltZW91dCkge1xuICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gc2V0VGltZW91dDtcbiAgICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuLCAwKTtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgLy8gd2hlbiB3aGVuIHNvbWVib2R5IGhhcyBzY3Jld2VkIHdpdGggc2V0VGltZW91dCBidXQgbm8gSS5FLiBtYWRkbmVzc1xuICAgICAgICByZXR1cm4gY2FjaGVkU2V0VGltZW91dChmdW4sIDApO1xuICAgIH0gY2F0Y2goZSl7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBXaGVuIHdlIGFyZSBpbiBJLkUuIGJ1dCB0aGUgc2NyaXB0IGhhcyBiZWVuIGV2YWxlZCBzbyBJLkUuIGRvZXNuJ3QgdHJ1c3QgdGhlIGdsb2JhbCBvYmplY3Qgd2hlbiBjYWxsZWQgbm9ybWFsbHlcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0LmNhbGwobnVsbCwgZnVuLCAwKTtcbiAgICAgICAgfSBjYXRjaChlKXtcbiAgICAgICAgICAgIC8vIHNhbWUgYXMgYWJvdmUgYnV0IHdoZW4gaXQncyBhIHZlcnNpb24gb2YgSS5FLiB0aGF0IG11c3QgaGF2ZSB0aGUgZ2xvYmFsIG9iamVjdCBmb3IgJ3RoaXMnLCBob3BmdWxseSBvdXIgY29udGV4dCBjb3JyZWN0IG90aGVyd2lzZSBpdCB3aWxsIHRocm93IGEgZ2xvYmFsIGVycm9yXG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkU2V0VGltZW91dC5jYWxsKHRoaXMsIGZ1biwgMCk7XG4gICAgICAgIH1cbiAgICB9XG5cblxufVxuZnVuY3Rpb24gcnVuQ2xlYXJUaW1lb3V0KG1hcmtlcikge1xuICAgIGlmIChjYWNoZWRDbGVhclRpbWVvdXQgPT09IGNsZWFyVGltZW91dCkge1xuICAgICAgICAvL25vcm1hbCBlbnZpcm9tZW50cyBpbiBzYW5lIHNpdHVhdGlvbnNcbiAgICAgICAgcmV0dXJuIGNsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH1cbiAgICAvLyBpZiBjbGVhclRpbWVvdXQgd2Fzbid0IGF2YWlsYWJsZSBidXQgd2FzIGxhdHRlciBkZWZpbmVkXG4gICAgaWYgKChjYWNoZWRDbGVhclRpbWVvdXQgPT09IGRlZmF1bHRDbGVhclRpbWVvdXQgfHwgIWNhY2hlZENsZWFyVGltZW91dCkgJiYgY2xlYXJUaW1lb3V0KSB7XG4gICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGNsZWFyVGltZW91dDtcbiAgICAgICAgcmV0dXJuIGNsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICAvLyB3aGVuIHdoZW4gc29tZWJvZHkgaGFzIHNjcmV3ZWQgd2l0aCBzZXRUaW1lb3V0IGJ1dCBubyBJLkUuIG1hZGRuZXNzXG4gICAgICAgIHJldHVybiBjYWNoZWRDbGVhclRpbWVvdXQobWFya2VyKTtcbiAgICB9IGNhdGNoIChlKXtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIFdoZW4gd2UgYXJlIGluIEkuRS4gYnV0IHRoZSBzY3JpcHQgaGFzIGJlZW4gZXZhbGVkIHNvIEkuRS4gZG9lc24ndCAgdHJ1c3QgdGhlIGdsb2JhbCBvYmplY3Qgd2hlbiBjYWxsZWQgbm9ybWFsbHlcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRDbGVhclRpbWVvdXQuY2FsbChudWxsLCBtYXJrZXIpO1xuICAgICAgICB9IGNhdGNoIChlKXtcbiAgICAgICAgICAgIC8vIHNhbWUgYXMgYWJvdmUgYnV0IHdoZW4gaXQncyBhIHZlcnNpb24gb2YgSS5FLiB0aGF0IG11c3QgaGF2ZSB0aGUgZ2xvYmFsIG9iamVjdCBmb3IgJ3RoaXMnLCBob3BmdWxseSBvdXIgY29udGV4dCBjb3JyZWN0IG90aGVyd2lzZSBpdCB3aWxsIHRocm93IGEgZ2xvYmFsIGVycm9yLlxuICAgICAgICAgICAgLy8gU29tZSB2ZXJzaW9ucyBvZiBJLkUuIGhhdmUgZGlmZmVyZW50IHJ1bGVzIGZvciBjbGVhclRpbWVvdXQgdnMgc2V0VGltZW91dFxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dC5jYWxsKHRoaXMsIG1hcmtlcik7XG4gICAgICAgIH1cbiAgICB9XG5cblxuXG59XG52YXIgcXVldWUgPSBbXTtcbnZhciBkcmFpbmluZyA9IGZhbHNlO1xudmFyIGN1cnJlbnRRdWV1ZTtcbnZhciBxdWV1ZUluZGV4ID0gLTE7XG5cbmZ1bmN0aW9uIGNsZWFuVXBOZXh0VGljaygpIHtcbiAgICBpZiAoIWRyYWluaW5nIHx8ICFjdXJyZW50UXVldWUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBkcmFpbmluZyA9IGZhbHNlO1xuICAgIGlmIChjdXJyZW50UXVldWUubGVuZ3RoKSB7XG4gICAgICAgIHF1ZXVlID0gY3VycmVudFF1ZXVlLmNvbmNhdChxdWV1ZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgcXVldWVJbmRleCA9IC0xO1xuICAgIH1cbiAgICBpZiAocXVldWUubGVuZ3RoKSB7XG4gICAgICAgIGRyYWluUXVldWUoKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGRyYWluUXVldWUoKSB7XG4gICAgaWYgKGRyYWluaW5nKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdmFyIHRpbWVvdXQgPSBydW5UaW1lb3V0KGNsZWFuVXBOZXh0VGljayk7XG4gICAgZHJhaW5pbmcgPSB0cnVlO1xuXG4gICAgdmFyIGxlbiA9IHF1ZXVlLmxlbmd0aDtcbiAgICB3aGlsZShsZW4pIHtcbiAgICAgICAgY3VycmVudFF1ZXVlID0gcXVldWU7XG4gICAgICAgIHF1ZXVlID0gW107XG4gICAgICAgIHdoaWxlICgrK3F1ZXVlSW5kZXggPCBsZW4pIHtcbiAgICAgICAgICAgIGlmIChjdXJyZW50UXVldWUpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50UXVldWVbcXVldWVJbmRleF0ucnVuKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcXVldWVJbmRleCA9IC0xO1xuICAgICAgICBsZW4gPSBxdWV1ZS5sZW5ndGg7XG4gICAgfVxuICAgIGN1cnJlbnRRdWV1ZSA9IG51bGw7XG4gICAgZHJhaW5pbmcgPSBmYWxzZTtcbiAgICBydW5DbGVhclRpbWVvdXQodGltZW91dCk7XG59XG5cbnByb2Nlc3MubmV4dFRpY2sgPSBmdW5jdGlvbiAoZnVuKSB7XG4gICAgdmFyIGFyZ3MgPSBuZXcgQXJyYXkoYXJndW1lbnRzLmxlbmd0aCAtIDEpO1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMSkge1xuICAgICAgICBmb3IgKHZhciBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgYXJnc1tpIC0gMV0gPSBhcmd1bWVudHNbaV07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcXVldWUucHVzaChuZXcgSXRlbShmdW4sIGFyZ3MpKTtcbiAgICBpZiAocXVldWUubGVuZ3RoID09PSAxICYmICFkcmFpbmluZykge1xuICAgICAgICBydW5UaW1lb3V0KGRyYWluUXVldWUpO1xuICAgIH1cbn07XG5cbi8vIHY4IGxpa2VzIHByZWRpY3RpYmxlIG9iamVjdHNcbmZ1bmN0aW9uIEl0ZW0oZnVuLCBhcnJheSkge1xuICAgIHRoaXMuZnVuID0gZnVuO1xuICAgIHRoaXMuYXJyYXkgPSBhcnJheTtcbn1cbkl0ZW0ucHJvdG90eXBlLnJ1biA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmZ1bi5hcHBseShudWxsLCB0aGlzLmFycmF5KTtcbn07XG5wcm9jZXNzLnRpdGxlID0gJ2Jyb3dzZXInO1xucHJvY2Vzcy5icm93c2VyID0gdHJ1ZTtcbnByb2Nlc3MuZW52ID0ge307XG5wcm9jZXNzLmFyZ3YgPSBbXTtcbnByb2Nlc3MudmVyc2lvbiA9ICcnOyAvLyBlbXB0eSBzdHJpbmcgdG8gYXZvaWQgcmVnZXhwIGlzc3Vlc1xucHJvY2Vzcy52ZXJzaW9ucyA9IHt9O1xuXG5mdW5jdGlvbiBub29wKCkge31cblxucHJvY2Vzcy5vbiA9IG5vb3A7XG5wcm9jZXNzLmFkZExpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3Mub25jZSA9IG5vb3A7XG5wcm9jZXNzLm9mZiA9IG5vb3A7XG5wcm9jZXNzLnJlbW92ZUxpc3RlbmVyID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlQWxsTGlzdGVuZXJzID0gbm9vcDtcbnByb2Nlc3MuZW1pdCA9IG5vb3A7XG5wcm9jZXNzLnByZXBlbmRMaXN0ZW5lciA9IG5vb3A7XG5wcm9jZXNzLnByZXBlbmRPbmNlTGlzdGVuZXIgPSBub29wO1xuXG5wcm9jZXNzLmxpc3RlbmVycyA9IGZ1bmN0aW9uIChuYW1lKSB7IHJldHVybiBbXSB9XG5cbnByb2Nlc3MuYmluZGluZyA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmJpbmRpbmcgaXMgbm90IHN1cHBvcnRlZCcpO1xufTtcblxucHJvY2Vzcy5jd2QgPSBmdW5jdGlvbiAoKSB7IHJldHVybiAnLycgfTtcbnByb2Nlc3MuY2hkaXIgPSBmdW5jdGlvbiAoZGlyKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdwcm9jZXNzLmNoZGlyIGlzIG5vdCBzdXBwb3J0ZWQnKTtcbn07XG5wcm9jZXNzLnVtYXNrID0gZnVuY3Rpb24oKSB7IHJldHVybiAwOyB9O1xuXG5cblxuLy8vLy8vLy8vLy8vLy8vLy8vXG4vLyBXRUJQQUNLIEZPT1RFUlxuLy8gLi9ub2RlX21vZHVsZXMvcHJvY2Vzcy9icm93c2VyLmpzXG4vLyBtb2R1bGUgaWQgPSAuL25vZGVfbW9kdWxlcy9wcm9jZXNzL2Jyb3dzZXIuanNcbi8vIG1vZHVsZSBjaHVua3MgPSAwIDEgMiJdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./node_modules/process/browser.js\n");
/***/ }),
/***/ "./resources/js/admin/app.js":
/***/ (function(module, exports, __webpack_require__) {
eval("/**\n * Admin stuff needed\n */\n\n__webpack_require__(\"./resources/js/bootstrap.js\");\n\n// Import the mapping function\nwindow.phpvms.map = __webpack_require__(\"./resources/js/maps/index.js\");//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9yZXNvdXJjZXMvanMvYWRtaW4vYXBwLmpzP2ExNzUiXSwibmFtZXMiOlsicmVxdWlyZSIsIndpbmRvdyIsInBocHZtcyIsIm1hcCJdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7QUFJQSxtQkFBQUEsQ0FBUSw2QkFBUjs7QUFFQTtBQUNBQyxPQUFPQyxNQUFQLENBQWNDLEdBQWQsR0FBb0IsbUJBQUFILENBQVEsOEJBQVIsQ0FBcEIiLCJmaWxlIjoiLi9yZXNvdXJjZXMvanMvYWRtaW4vYXBwLmpzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBZG1pbiBzdHVmZiBuZWVkZWRcbiAqL1xuXG5yZXF1aXJlKCcuLy4uL2Jvb3RzdHJhcCcpO1xuXG4vLyBJbXBvcnQgdGhlIG1hcHBpbmcgZnVuY3Rpb25cbndpbmRvdy5waHB2bXMubWFwID0gcmVxdWlyZSgnLi4vbWFwcy9pbmRleCcpO1xuXG5cblxuLy8gV0VCUEFDSyBGT09URVIgLy9cbi8vIC4vcmVzb3VyY2VzL2pzL2FkbWluL2FwcC5qcyJdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./resources/js/admin/app.js\n");
/***/ }),
/***/ "./resources/js/bootstrap.js":
/***/ (function(module, exports, __webpack_require__) {
eval("/**\n * Bootstrap any Javascript libraries required\n */\n\n//window._ = require('lodash')\n//window.Popper = require('popper.js').default;\n//window.$ = window.jquery = require('jquery');\n//window.select2 = require('select2');\n//window.pjax = require('pjax');\nwindow.axios = __webpack_require__(\"./node_modules/axios/index.js\");\n\n/**\n * Container for phpVMS specific functions\n */\nwindow.phpvms = {};\n\n/**\n * Configure Axios with both the csrf token and the API key\n */\nwindow.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';\nvar token = document.head.querySelector('meta[name=\"csrf-token\"]');\n\nif (token) {\n window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;\n /*window.jquery.ajaxSetup({\n 'X-CSRF-TOKEN': token.content\n })*/\n} else {\n console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');\n}\n\nvar api_key = document.head.querySelector('meta[name=\"api-key\"]');\nif (api_key) {\n window.axios.defaults.headers.common['x-api-key'] = api_key.content;\n window.PHPVMS_USER_API_KEY = api_key.content;\n} else {\n window.PHPVMS_USER_API_KEY = false;\n console.error('API Key not found!');\n}//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9yZXNvdXJjZXMvanMvYm9vdHN0cmFwLmpzPzBlNTgiXSwibmFtZXMiOlsid2luZG93IiwiYXhpb3MiLCJyZXF1aXJlIiwicGhwdm1zIiwiZGVmYXVsdHMiLCJoZWFkZXJzIiwiY29tbW9uIiwidG9rZW4iLCJkb2N1bWVudCIsImhlYWQiLCJxdWVyeVNlbGVjdG9yIiwiY29udGVudCIsImNvbnNvbGUiLCJlcnJvciIsImFwaV9rZXkiLCJQSFBWTVNfVVNFUl9BUElfS0VZIl0sIm1hcHBpbmdzIjoiQUFBQTs7OztBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQUEsT0FBT0MsS0FBUCxHQUFlLG1CQUFBQyxDQUFRLCtCQUFSLENBQWY7O0FBRUE7OztBQUdBRixPQUFPRyxNQUFQLEdBQWdCLEVBQWhCOztBQUVBOzs7QUFHQUgsT0FBT0MsS0FBUCxDQUFhRyxRQUFiLENBQXNCQyxPQUF0QixDQUE4QkMsTUFBOUIsQ0FBcUMsa0JBQXJDLElBQTJELGdCQUEzRDtBQUNBLElBQU1DLFFBQVFDLFNBQVNDLElBQVQsQ0FBY0MsYUFBZCxDQUE0Qix5QkFBNUIsQ0FBZDs7QUFFQSxJQUFJSCxLQUFKLEVBQVc7QUFDVFAsU0FBT0MsS0FBUCxDQUFhRyxRQUFiLENBQXNCQyxPQUF0QixDQUE4QkMsTUFBOUIsQ0FBcUMsY0FBckMsSUFBdURDLE1BQU1JLE9BQTdEO0FBQ0E7OztBQUdELENBTEQsTUFLTztBQUNMQyxVQUFRQyxLQUFSLENBQWMsdUVBQWQ7QUFDRDs7QUFFRCxJQUFNQyxVQUFVTixTQUFTQyxJQUFULENBQWNDLGFBQWQsQ0FBNEIsc0JBQTVCLENBQWhCO0FBQ0EsSUFBSUksT0FBSixFQUFhO0FBQ1hkLFNBQU9DLEtBQVAsQ0FBYUcsUUFBYixDQUFzQkMsT0FBdEIsQ0FBOEJDLE1BQTlCLENBQXFDLFdBQXJDLElBQW9EUSxRQUFRSCxPQUE1RDtBQUNBWCxTQUFPZSxtQkFBUCxHQUE2QkQsUUFBUUgsT0FBckM7QUFDRCxDQUhELE1BR087QUFDTFgsU0FBT2UsbUJBQVAsR0FBNkIsS0FBN0I7QUFDQUgsVUFBUUMsS0FBUixDQUFjLG9CQUFkO0FBQ0QiLCJmaWxlIjoiLi9yZXNvdXJjZXMvanMvYm9vdHN0cmFwLmpzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBCb290c3RyYXAgYW55IEphdmFzY3JpcHQgbGlicmFyaWVzIHJlcXVpcmVkXG4gKi9cblxuLy93aW5kb3cuXyA9IHJlcXVpcmUoJ2xvZGFzaCcpXG4vL3dpbmRvdy5Qb3BwZXIgPSByZXF1aXJlKCdwb3BwZXIuanMnKS5kZWZhdWx0O1xuLy93aW5kb3cuJCA9IHdpbmRvdy5qcXVlcnkgPSByZXF1aXJlKCdqcXVlcnknKTtcbi8vd2luZG93LnNlbGVjdDIgPSByZXF1aXJlKCdzZWxlY3QyJyk7XG4vL3dpbmRvdy5wamF4ID0gcmVxdWlyZSgncGpheCcpO1xud2luZG93LmF4aW9zID0gcmVxdWlyZSgnYXhpb3MnKTtcblxuLyoqXG4gKiBDb250YWluZXIgZm9yIHBocFZNUyBzcGVjaWZpYyBmdW5jdGlvbnNcbiAqL1xud2luZG93LnBocHZtcyA9IHt9O1xuXG4vKipcbiAqIENvbmZpZ3VyZSBBeGlvcyB3aXRoIGJvdGggdGhlIGNzcmYgdG9rZW4gYW5kIHRoZSBBUEkga2V5XG4gKi9cbndpbmRvdy5heGlvcy5kZWZhdWx0cy5oZWFkZXJzLmNvbW1vblsnWC1SZXF1ZXN0ZWQtV2l0aCddID0gJ1hNTEh0dHBSZXF1ZXN0JztcbmNvbnN0IHRva2VuID0gZG9jdW1lbnQuaGVhZC5xdWVyeVNlbGVjdG9yKCdtZXRhW25hbWU9XCJjc3JmLXRva2VuXCJdJyk7XG5cbmlmICh0b2tlbikge1xuICB3aW5kb3cuYXhpb3MuZGVmYXVsdHMuaGVhZGVycy5jb21tb25bJ1gtQ1NSRi1UT0tFTiddID0gdG9rZW4uY29udGVudFxuICAvKndpbmRvdy5qcXVlcnkuYWpheFNldHVwKHtcbiAgICAnWC1DU1JGLVRPS0VOJzogdG9rZW4uY29udGVudFxuICB9KSovXG59IGVsc2Uge1xuICBjb25zb2xlLmVycm9yKCdDU1JGIHRva2VuIG5vdCBmb3VuZDogaHR0cHM6Ly9sYXJhdmVsLmNvbS9kb2NzL2NzcmYjY3NyZi14LWNzcmYtdG9rZW4nKVxufVxuXG5jb25zdCBhcGlfa2V5ID0gZG9jdW1lbnQuaGVhZC5xdWVyeVNlbGVjdG9yKCdtZXRhW25hbWU9XCJhcGkta2V5XCJdJyk7XG5pZiAoYXBpX2tleSkge1xuICB3aW5kb3cuYXhpb3MuZGVmYXVsdHMuaGVhZGVycy5jb21tb25bJ3gtYXBpLWtleSddID0gYXBpX2tleS5jb250ZW50O1xuICB3aW5kb3cuUEhQVk1TX1VTRVJfQVBJX0tFWSA9IGFwaV9rZXkuY29udGVudFxufSBlbHNlIHtcbiAgd2luZG93LlBIUFZNU19VU0VSX0FQSV9LRVkgPSBmYWxzZTtcbiAgY29uc29sZS5lcnJvcignQVBJIEtleSBub3QgZm91bmQhJylcbn1cblxuXG5cbi8vIFdFQlBBQ0sgRk9PVEVSIC8vXG4vLyAuL3Jlc291cmNlcy9qcy9ib290c3RyYXAuanMiXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./resources/js/bootstrap.js\n");
/***/ }),
/***/ "./resources/js/maps/airspace_map.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__base_map__ = __webpack_require__(\"./resources/js/maps/base_map.js\");\n\nvar leaflet = __webpack_require__(\"./node_modules/leaflet/dist/leaflet-src.js\");\n\n\n\n/**\n * Render a map with the airspace, etc around a given set of coords\n * e.g, the airport map\n * @param opts\n */\n/* harmony default export */ __webpack_exports__[\"a\"] = (function (opts) {\n opts = Object.assign({\n render_elem: 'map',\n overlay_elem: '',\n lat: 0,\n lon: 0,\n zoom: 12,\n layers: [],\n set_marker: true\n }, opts);\n\n var map = Object(__WEBPACK_IMPORTED_MODULE_0__base_map__[\"a\" /* default */])(opts);\n var coords = [opts.lat, opts.lon];\n console.log('Applying coords', coords);\n\n map.setView(coords, opts.zoom);\n if (opts.set_marker === true) {\n leaflet.marker(coords).addTo(map);\n }\n\n return map;\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9yZXNvdXJjZXMvanMvbWFwcy9haXJzcGFjZV9tYXAuanM/NGZiMCJdLCJuYW1lcyI6WyJsZWFmbGV0IiwicmVxdWlyZSIsIm9wdHMiLCJPYmplY3QiLCJhc3NpZ24iLCJyZW5kZXJfZWxlbSIsIm92ZXJsYXlfZWxlbSIsImxhdCIsImxvbiIsInpvb20iLCJsYXllcnMiLCJzZXRfbWFya2VyIiwibWFwIiwiZHJhd19iYXNlX21hcCIsImNvb3JkcyIsImNvbnNvbGUiLCJsb2ciLCJzZXRWaWV3IiwibWFya2VyIiwiYWRkVG8iXSwibWFwcGluZ3MiOiI7O0FBQ0EsSUFBTUEsVUFBVSxtQkFBQUMsQ0FBUSw0Q0FBUixDQUFoQjs7QUFFQTs7QUFFQTs7Ozs7QUFLQSx5REFBZSxVQUFDQyxJQUFELEVBQVU7QUFDdkJBLFNBQU9DLE9BQU9DLE1BQVAsQ0FBYztBQUNuQkMsaUJBQWEsS0FETTtBQUVuQkMsa0JBQWMsRUFGSztBQUduQkMsU0FBSyxDQUhjO0FBSW5CQyxTQUFLLENBSmM7QUFLbkJDLFVBQU0sRUFMYTtBQU1uQkMsWUFBUSxFQU5XO0FBT25CQyxnQkFBWTtBQVBPLEdBQWQsRUFRSlQsSUFSSSxDQUFQOztBQVVBLE1BQUlVLE1BQU0sa0VBQUFDLENBQWNYLElBQWQsQ0FBVjtBQUNBLE1BQU1ZLFNBQVMsQ0FBQ1osS0FBS0ssR0FBTixFQUFXTCxLQUFLTSxHQUFoQixDQUFmO0FBQ0FPLFVBQVFDLEdBQVIsQ0FBWSxpQkFBWixFQUErQkYsTUFBL0I7O0FBRUFGLE1BQUlLLE9BQUosQ0FBWUgsTUFBWixFQUFvQlosS0FBS08sSUFBekI7QUFDQSxNQUFJUCxLQUFLUyxVQUFMLEtBQW9CLElBQXhCLEVBQThCO0FBQzVCWCxZQUFRa0IsTUFBUixDQUFlSixNQUFmLEVBQXVCSyxLQUF2QixDQUE2QlAsR0FBN0I7QUFDRDs7QUFFRCxTQUFPQSxHQUFQO0FBQ0QsQ0FyQkQiLCJmaWxlIjoiLi9yZXNvdXJjZXMvanMvbWFwcy9haXJzcGFjZV9tYXAuanMuanMiLCJzb3VyY2VzQ29udGVudCI6WyJcbmNvbnN0IGxlYWZsZXQgPSByZXF1aXJlKCdsZWFmbGV0Jyk7XG5cbmltcG9ydCBkcmF3X2Jhc2VfbWFwIGZyb20gJy4vYmFzZV9tYXAnXG5cbi8qKlxuICogUmVuZGVyIGEgbWFwIHdpdGggdGhlIGFpcnNwYWNlLCBldGMgYXJvdW5kIGEgZ2l2ZW4gc2V0IG9mIGNvb3Jkc1xuICogZS5nLCB0aGUgYWlycG9ydCBtYXBcbiAqIEBwYXJhbSBvcHRzXG4gKi9cbmV4cG9ydCBkZWZhdWx0IChvcHRzKSA9PiB7XG4gIG9wdHMgPSBPYmplY3QuYXNzaWduKHtcbiAgICByZW5kZXJfZWxlbTogJ21hcCcsXG4gICAgb3ZlcmxheV9lbGVtOiAnJyxcbiAgICBsYXQ6IDAsXG4gICAgbG9uOiAwLFxuICAgIHpvb206IDEyLFxuICAgIGxheWVyczogW10sXG4gICAgc2V0X21hcmtlcjogdHJ1ZSxcbiAgfSwgb3B0cyk7XG5cbiAgbGV0IG1hcCA9IGRyYXdfYmFzZV9tYXAob3B0cylcbiAgY29uc3QgY29vcmRzID0gW29wdHMubGF0LCBvcHRzLmxvbl1cbiAgY29uc29sZS5sb2coJ0FwcGx5aW5nIGNvb3JkcycsIGNvb3JkcylcblxuICBtYXAuc2V0Vmlldyhjb29yZHMsIG9wdHMuem9vbSlcbiAgaWYgKG9wdHMuc2V0X21hcmtlciA9PT0gdHJ1ZSkge1xuICAgIGxlYWZsZXQubWFya2VyKGNvb3JkcykuYWRkVG8obWFwKVxuICB9XG5cbiAgcmV0dXJuIG1hcFxufTtcblxuXG5cbi8vIFdFQlBBQ0sgRk9PVEVSIC8vXG4vLyAuL3Jlc291cmNlcy9qcy9tYXBzL2FpcnNwYWNlX21hcC5qcyJdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./resources/js/maps/airspace_map.js\n");
/***/ }),
/***/ "./resources/js/maps/base_map.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("\nvar leaflet = __webpack_require__(\"./node_modules/leaflet/dist/leaflet-src.js\");\n\n/* harmony default export */ __webpack_exports__[\"a\"] = (function (opts) {\n\n opts = Object.assign({\n render_elem: 'map',\n center: [29.98139, -95.33374],\n zoom: 5,\n maxZoom: 10,\n layers: [],\n set_marker: false\n }, opts);\n\n var feature_groups = [];\n /*var openaip_airspace_labels = new leaflet.TileLayer.WMS(\n \"http://{s}.tile.maps.openaip.net/geowebcache/service/wms\", {\n maxZoom: 14,\n minZoom: 12,\n layers: 'openaip_approved_airspaces_labels',\n tileSize: 1024,\n detectRetina: true,\n subdomains: '12',\n format: 'image/png',\n transparent: true\n });\n openaip_airspace_labels.addTo(map);*/\n\n var opencyclemap_phys_osm = new leaflet.TileLayer('http://{s}.tile.thunderforest.com/landscape/{z}/{x}/{y}.png?apikey=f09a38fa87514de4890fc96e7fe8ecb1', {\n maxZoom: 14,\n minZoom: 4,\n format: 'image/png',\n transparent: true\n });\n\n feature_groups.push(opencyclemap_phys_osm);\n\n /*const openaip_cached_basemap = new leaflet.TileLayer(\"http://{s}.tile.maps.openaip.net/geowebcache/service/tms/1.0.0/openaip_basemap@EPSG%3A900913@png/{z}/{x}/{y}.png\", {\n maxZoom: 14,\n minZoom: 4,\n tms: true,\n detectRetina: true,\n subdomains: '12',\n format: 'image/png',\n transparent: true\n });\n feature_groups.push(openaip_cached_basemap);\n */\n\n var openaip_basemap_phys_osm = leaflet.featureGroup(feature_groups);\n\n var map = leaflet.map('map', {\n layers: [openaip_basemap_phys_osm],\n center: opts.center,\n zoom: opts.zoom,\n scrollWheelZoom: false\n });\n\n var attrib = leaflet.control.attribution({ position: 'bottomleft' });\n attrib.addAttribution('Thunderforest ');\n attrib.addAttribution('openAIP ');\n attrib.addAttribution('OpenStreetMap contributors');\n attrib.addAttribution('OpenWeatherMap ');\n\n attrib.addTo(map);\n\n return map;\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9yZXNvdXJjZXMvanMvbWFwcy9iYXNlX21hcC5qcz80MzA3Il0sIm5hbWVzIjpbImxlYWZsZXQiLCJyZXF1aXJlIiwib3B0cyIsIk9iamVjdCIsImFzc2lnbiIsInJlbmRlcl9lbGVtIiwiY2VudGVyIiwiem9vbSIsIm1heFpvb20iLCJsYXllcnMiLCJzZXRfbWFya2VyIiwiZmVhdHVyZV9ncm91cHMiLCJvcGVuY3ljbGVtYXBfcGh5c19vc20iLCJUaWxlTGF5ZXIiLCJtaW5ab29tIiwiZm9ybWF0IiwidHJhbnNwYXJlbnQiLCJwdXNoIiwib3BlbmFpcF9iYXNlbWFwX3BoeXNfb3NtIiwiZmVhdHVyZUdyb3VwIiwibWFwIiwic2Nyb2xsV2hlZWxab29tIiwiYXR0cmliIiwiY29udHJvbCIsImF0dHJpYnV0aW9uIiwicG9zaXRpb24iLCJhZGRBdHRyaWJ1dGlvbiIsImFkZFRvIl0sIm1hcHBpbmdzIjoiO0FBQ0EsSUFBTUEsVUFBVSxtQkFBQUMsQ0FBUSw0Q0FBUixDQUFoQjs7QUFFQSx5REFBZSxVQUFDQyxJQUFELEVBQVU7O0FBRXZCQSxTQUFPQyxPQUFPQyxNQUFQLENBQWM7QUFDbkJDLGlCQUFhLEtBRE07QUFFbkJDLFlBQVEsQ0FBQyxRQUFELEVBQVcsQ0FBQyxRQUFaLENBRlc7QUFHbkJDLFVBQU0sQ0FIYTtBQUluQkMsYUFBUyxFQUpVO0FBS25CQyxZQUFRLEVBTFc7QUFNbkJDLGdCQUFZO0FBTk8sR0FBZCxFQU9KUixJQVBJLENBQVA7O0FBU0EsTUFBSVMsaUJBQWlCLEVBQXJCO0FBQ0E7Ozs7Ozs7Ozs7Ozs7QUFjQSxNQUFNQyx3QkFBd0IsSUFBSVosUUFBUWEsU0FBWixDQUM1QixxR0FENEIsRUFDMkU7QUFDckdMLGFBQVMsRUFENEY7QUFFckdNLGFBQVMsQ0FGNEY7QUFHckdDLFlBQVEsV0FINkY7QUFJckdDLGlCQUFhO0FBSndGLEdBRDNFLENBQTlCOztBQVFBTCxpQkFBZU0sSUFBZixDQUFvQkwscUJBQXBCOztBQUVBOzs7Ozs7Ozs7Ozs7QUFhQSxNQUFNTSwyQkFBMkJsQixRQUFRbUIsWUFBUixDQUFxQlIsY0FBckIsQ0FBakM7O0FBRUEsTUFBSVMsTUFBTXBCLFFBQVFvQixHQUFSLENBQVksS0FBWixFQUFtQjtBQUMzQlgsWUFBUSxDQUFDUyx3QkFBRCxDQURtQjtBQUUzQlosWUFBUUosS0FBS0ksTUFGYztBQUczQkMsVUFBTUwsS0FBS0ssSUFIZ0I7QUFJM0JjLHFCQUFpQjtBQUpVLEdBQW5CLENBQVY7O0FBT0EsTUFBTUMsU0FBU3RCLFFBQVF1QixPQUFSLENBQWdCQyxXQUFoQixDQUE0QixFQUFDQyxVQUFVLFlBQVgsRUFBNUIsQ0FBZjtBQUNBSCxTQUFPSSxjQUFQLENBQXNCLG9GQUF0QjtBQUNBSixTQUFPSSxjQUFQLENBQXNCLHdFQUF0QjtBQUNBSixTQUFPSSxjQUFQLENBQXNCLDJHQUF0QjtBQUNBSixTQUFPSSxjQUFQLENBQXNCLHNGQUF0Qjs7QUFFQUosU0FBT0ssS0FBUCxDQUFhUCxHQUFiOztBQUVBLFNBQU9BLEdBQVA7QUFDRCxDQW5FRCIsImZpbGUiOiIuL3Jlc291cmNlcy9qcy9tYXBzL2Jhc2VfbWFwLmpzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiXG5jb25zdCBsZWFmbGV0ID0gcmVxdWlyZSgnbGVhZmxldCcpO1xuXG5leHBvcnQgZGVmYXVsdCAob3B0cykgPT4ge1xuXG4gIG9wdHMgPSBPYmplY3QuYXNzaWduKHtcbiAgICByZW5kZXJfZWxlbTogJ21hcCcsXG4gICAgY2VudGVyOiBbMjkuOTgxMzksIC05NS4zMzM3NF0sXG4gICAgem9vbTogNSxcbiAgICBtYXhab29tOiAxMCxcbiAgICBsYXllcnM6IFtdLFxuICAgIHNldF9tYXJrZXI6IGZhbHNlLFxuICB9LCBvcHRzKTtcblxuICBsZXQgZmVhdHVyZV9ncm91cHMgPSBbXTtcbiAgLyp2YXIgb3BlbmFpcF9haXJzcGFjZV9sYWJlbHMgPSBuZXcgbGVhZmxldC5UaWxlTGF5ZXIuV01TKFxuICAgICAgXCJodHRwOi8ve3N9LnRpbGUubWFwcy5vcGVuYWlwLm5ldC9nZW93ZWJjYWNoZS9zZXJ2aWNlL3dtc1wiLCB7XG4gICAgICAgICAgbWF4Wm9vbTogMTQsXG4gICAgICAgICAgbWluWm9vbTogMTIsXG4gICAgICAgICAgbGF5ZXJzOiAnb3BlbmFpcF9hcHByb3ZlZF9haXJzcGFjZXNfbGFiZWxzJyxcbiAgICAgICAgICB0aWxlU2l6ZTogMTAyNCxcbiAgICAgICAgICBkZXRlY3RSZXRpbmE6IHRydWUsXG4gICAgICAgICAgc3ViZG9tYWluczogJzEyJyxcbiAgICAgICAgICBmb3JtYXQ6ICdpbWFnZS9wbmcnLFxuICAgICAgICAgIHRyYW5zcGFyZW50OiB0cnVlXG4gICAgICB9KTtcblxuICBvcGVuYWlwX2FpcnNwYWNlX2xhYmVscy5hZGRUbyhtYXApOyovXG5cbiAgY29uc3Qgb3BlbmN5Y2xlbWFwX3BoeXNfb3NtID0gbmV3IGxlYWZsZXQuVGlsZUxheWVyKFxuICAgICdodHRwOi8ve3N9LnRpbGUudGh1bmRlcmZvcmVzdC5jb20vbGFuZHNjYXBlL3t6fS97eH0ve3l9LnBuZz9hcGlrZXk9ZjA5YTM4ZmE4NzUxNGRlNDg5MGZjOTZlN2ZlOGVjYjEnLCB7XG4gICAgICBtYXhab29tOiAxNCxcbiAgICAgIG1pblpvb206IDQsXG4gICAgICBmb3JtYXQ6ICdpbWFnZS9wbmcnLFxuICAgICAgdHJhbnNwYXJlbnQ6IHRydWVcbiAgICB9KVxuXG4gIGZlYXR1cmVfZ3JvdXBzLnB1c2gob3BlbmN5Y2xlbWFwX3BoeXNfb3NtKVxuXG4gIC8qY29uc3Qgb3BlbmFpcF9jYWNoZWRfYmFzZW1hcCA9IG5ldyBsZWFmbGV0LlRpbGVMYXllcihcImh0dHA6Ly97c30udGlsZS5tYXBzLm9wZW5haXAubmV0L2dlb3dlYmNhY2hlL3NlcnZpY2UvdG1zLzEuMC4wL29wZW5haXBfYmFzZW1hcEBFUFNHJTNBOTAwOTEzQHBuZy97en0ve3h9L3t5fS5wbmdcIiwge1xuICAgICAgbWF4Wm9vbTogMTQsXG4gICAgICBtaW5ab29tOiA0LFxuICAgICAgdG1zOiB0cnVlLFxuICAgICAgZGV0ZWN0UmV0aW5hOiB0cnVlLFxuICAgICAgc3ViZG9tYWluczogJzEyJyxcbiAgICAgIGZvcm1hdDogJ2ltYWdlL3BuZycsXG4gICAgICB0cmFuc3BhcmVudDogdHJ1ZVxuICB9KTtcblxuICBmZWF0dXJlX2dyb3Vwcy5wdXNoKG9wZW5haXBfY2FjaGVkX2Jhc2VtYXApO1xuICAqL1xuXG4gIGNvbnN0IG9wZW5haXBfYmFzZW1hcF9waHlzX29zbSA9IGxlYWZsZXQuZmVhdHVyZUdyb3VwKGZlYXR1cmVfZ3JvdXBzKVxuXG4gIGxldCBtYXAgPSBsZWFmbGV0Lm1hcCgnbWFwJywge1xuICAgIGxheWVyczogW29wZW5haXBfYmFzZW1hcF9waHlzX29zbV0sXG4gICAgY2VudGVyOiBvcHRzLmNlbnRlcixcbiAgICB6b29tOiBvcHRzLnpvb20sXG4gICAgc2Nyb2xsV2hlZWxab29tOiBmYWxzZSxcbiAgfSlcblxuICBjb25zdCBhdHRyaWIgPSBsZWFmbGV0LmNvbnRyb2wuYXR0cmlidXRpb24oe3Bvc2l0aW9uOiAnYm90dG9tbGVmdCd9KVxuICBhdHRyaWIuYWRkQXR0cmlidXRpb24oJzxhIGhyZWY9XCJodHRwczovL3d3dy50aHVuZGVyZm9yZXN0LmNvbVwiIHRhcmdldD1cIl9ibGFua1wiIHN0eWxlPVwiXCI+VGh1bmRlcmZvcmVzdDwvYT4nKVxuICBhdHRyaWIuYWRkQXR0cmlidXRpb24oJzxhIGhyZWY9XCJodHRwczovL3d3dy5vcGVuYWlwLm5ldFwiIHRhcmdldD1cIl9ibGFua1wiIHN0eWxlPVwiXCI+b3BlbkFJUDwvYT4nKVxuICBhdHRyaWIuYWRkQXR0cmlidXRpb24oJzxhIGhyZWY9XCJodHRwczovL3d3dy5vcGVuc3RyZWV0bWFwLm9yZy9jb3B5cmlnaHRcIiB0YXJnZXQ9XCJfYmxhbmtcIiBzdHlsZT1cIlwiPk9wZW5TdHJlZXRNYXA8L2E+IGNvbnRyaWJ1dG9ycycpXG4gIGF0dHJpYi5hZGRBdHRyaWJ1dGlvbignPGEgaHJlZj1cImh0dHBzOi8vd3d3Lm9wZW53ZWF0aGVybWFwLm9yZ1wiIHRhcmdldD1cIl9ibGFua1wiIHN0eWxlPVwiXCI+T3BlbldlYXRoZXJNYXA8L2E+JylcblxuICBhdHRyaWIuYWRkVG8obWFwKVxuXG4gIHJldHVybiBtYXBcbn07XG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8gLi9yZXNvdXJjZXMvanMvbWFwcy9iYXNlX21hcC5qcyJdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./resources/js/maps/base_map.js\n");
/***/ }),
/***/ "./resources/js/maps/config.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"b\", function() { return PLAN_ROUTE_COLOR; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"a\", function() { return ACTUAL_ROUTE_COLOR; });\nvar PLAN_ROUTE_COLOR = '#36b123',\n ACTUAL_ROUTE_COLOR = '#172aea';//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9yZXNvdXJjZXMvanMvbWFwcy9jb25maWcuanM/NzdmNyJdLCJuYW1lcyI6WyJQTEFOX1JPVVRFX0NPTE9SIiwiQUNUVUFMX1JPVVRFX0NPTE9SIl0sIm1hcHBpbmdzIjoiOztBQUFPLElBQ0xBLG1CQUFtQixTQURkO0FBQUEsSUFFTEMscUJBQXFCLFNBRmhCIiwiZmlsZSI6Ii4vcmVzb3VyY2VzL2pzL21hcHMvY29uZmlnLmpzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0IGxldFxuICBQTEFOX1JPVVRFX0NPTE9SID0gJyMzNmIxMjMnLFxuICBBQ1RVQUxfUk9VVEVfQ09MT1IgPSAnIzE3MmFlYSdcblxuXG5cbi8vIFdFQlBBQ0sgRk9PVEVSIC8vXG4vLyAuL3Jlc291cmNlcy9qcy9tYXBzL2NvbmZpZy5qcyJdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./resources/js/maps/config.js\n");
/***/ }),
/***/ "./resources/js/maps/index.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("Object.defineProperty(__webpack_exports__, \"__esModule\", { value: true });\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__airspace_map__ = __webpack_require__(\"./resources/js/maps/airspace_map.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__live_map__ = __webpack_require__(\"./resources/js/maps/live_map.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__route_map__ = __webpack_require__(\"./resources/js/maps/route_map.js\");\n/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, \"render_airspace_map\", function() { return __WEBPACK_IMPORTED_MODULE_0__airspace_map__[\"a\"]; });\n/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, \"render_live_map\", function() { return __WEBPACK_IMPORTED_MODULE_1__live_map__[\"a\"]; });\n/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, \"render_route_map\", function() { return __WEBPACK_IMPORTED_MODULE_2__route_map__[\"a\"]; });\n/**\n * All of the functionality required for maps\n */\n\nwindow.L = __webpack_require__(\"./node_modules/leaflet/dist/leaflet-src.js\");\n__webpack_require__(\"./node_modules/Leaflet.Geodesic/Leaflet.Geodesic.js\");\n__webpack_require__(\"./node_modules/leaflet-rotatedmarker/leaflet.rotatedMarker.js\");\n\n\n\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9yZXNvdXJjZXMvanMvbWFwcy9pbmRleC5qcz85MmYwIl0sIm5hbWVzIjpbIndpbmRvdyIsIkwiLCJyZXF1aXJlIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFBQTtBQUFBOzs7O0FBSUFBLE9BQU9DLENBQVAsR0FBVyxtQkFBQUMsQ0FBUSw0Q0FBUixDQUFYO0FBQ0EsbUJBQUFBLENBQVEscURBQVI7QUFDQSxtQkFBQUEsQ0FBUSwrREFBUjs7QUFFQTtBQUNBO0FBQ0EiLCJmaWxlIjoiLi9yZXNvdXJjZXMvanMvbWFwcy9pbmRleC5qcy5qcyIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQWxsIG9mIHRoZSBmdW5jdGlvbmFsaXR5IHJlcXVpcmVkIGZvciBtYXBzXG4gKi9cblxud2luZG93LkwgPSByZXF1aXJlKCdsZWFmbGV0Jyk7XG5yZXF1aXJlKCdMZWFmbGV0Lkdlb2Rlc2ljJyk7XG5yZXF1aXJlKCdsZWFmbGV0LXJvdGF0ZWRtYXJrZXInKTtcblxuaW1wb3J0IHJlbmRlcl9haXJzcGFjZV9tYXAgZnJvbSAnLi9haXJzcGFjZV9tYXAnXG5pbXBvcnQgcmVuZGVyX2xpdmVfbWFwIGZyb20gJy4vbGl2ZV9tYXAnXG5pbXBvcnQgcmVuZGVyX3JvdXRlX21hcCBmcm9tICcuL3JvdXRlX21hcCdcblxuZXhwb3J0IHtcbiAgcmVuZGVyX2FpcnNwYWNlX21hcCxcbiAgcmVuZGVyX2xpdmVfbWFwLFxuICByZW5kZXJfcm91dGVfbWFwLFxufVxuXG5cblxuLy8gV0VCUEFDSyBGT09URVIgLy9cbi8vIC4vcmVzb3VyY2VzL2pzL21hcHMvaW5kZXguanMiXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./resources/js/maps/index.js\n");
/***/ }),
/***/ "./resources/js/maps/live_map.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__base_map__ = __webpack_require__(\"./resources/js/maps/base_map.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__config__ = __webpack_require__(\"./resources/js/maps/config.js\");\n\nvar leaflet = __webpack_require__(\"./node_modules/leaflet/dist/leaflet-src.js\");\n\n\n\n\n/**\n * Render the live map\n * @param opts\n * @private\n */\n/* harmony default export */ __webpack_exports__[\"a\"] = (function (opts) {\n\n opts = Object.assign({\n update_uri: '/api/acars',\n pirep_uri: '/api/pireps/{id}/acars',\n positions: null,\n render_elem: 'map',\n aircraft_icon: '/assets/img/acars/aircraft.png'\n }, opts);\n\n var map = Object(__WEBPACK_IMPORTED_MODULE_0__base_map__[\"a\" /* default */])(opts);\n var aircraftIcon = leaflet.icon({\n iconUrl: opts.aircraft_icon,\n iconSize: [42, 42],\n iconAnchor: [21, 21]\n });\n\n var layerFlights = null;\n var layerSelFlight = null;\n var layerSelFlightFeature = null;\n var layerSelFlightLayer = null;\n\n /**\n * When a flight is clicked on, show the path, etc for that flight\n * @param feature\n * @param layer\n */\n var onFlightClick = function onFlightClick(feature, layer) {\n\n var uri = opts.pirep_uri.replace('{id}', feature.properties.pirep_id);\n\n var flight_route = $.ajax({\n url: uri,\n dataType: 'json',\n error: console.log\n });\n\n $.when(flight_route).done(function (routeJson) {\n if (layerSelFlight !== null) {\n map.removeLayer(layerSelFlight);\n }\n\n layerSelFlight = leaflet.geodesic([], {\n weight: 7,\n opacity: 0.9,\n color: __WEBPACK_IMPORTED_MODULE_1__config__[\"a\" /* ACTUAL_ROUTE_COLOR */],\n wrap: false\n }).addTo(map);\n\n layerSelFlight.geoJson(routeJson.line);\n\n layerSelFlightFeature = feature;\n layerSelFlightLayer = layer;\n //map.fitBounds(layerSelFlight.getBounds());\n });\n };\n\n var updateMap = function updateMap() {\n\n console.log('reloading flights from acars...');\n\n /**\n * AJAX UPDATE\n */\n\n var flights = $.ajax({\n url: opts.update_uri,\n dataType: 'json',\n error: console.log\n });\n\n $.when(flights).done(function (flightGeoJson) {\n\n if (layerFlights !== null) {\n layerFlights.clearLayers();\n }\n\n layerFlights = leaflet.geoJSON(flightGeoJson, {\n onEachFeature: function onEachFeature(feature, layer) {\n\n layer.on({\n click: function click(e) {\n onFlightClick(feature, layer);\n }\n });\n\n var popup_html = '';\n if (feature.properties && feature.properties.popup) {\n popup_html += feature.properties.popup;\n }\n\n layer.bindPopup(popup_html);\n },\n pointToLayer: function pointToLayer(feature, latlon) {\n return leaflet.marker(latlon, {\n icon: aircraftIcon,\n rotationAngle: feature.properties.heading\n });\n }\n });\n\n layerFlights.addTo(map);\n\n if (layerSelFlight !== null) {\n onFlightClick(layerSelFlightFeature, layerSelFlightLayer);\n }\n });\n };\n\n updateMap();\n setInterval(updateMap, 10000);\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9yZXNvdXJjZXMvanMvbWFwcy9saXZlX21hcC5qcz9lN2Y2Il0sIm5hbWVzIjpbImxlYWZsZXQiLCJyZXF1aXJlIiwib3B0cyIsIk9iamVjdCIsImFzc2lnbiIsInVwZGF0ZV91cmkiLCJwaXJlcF91cmkiLCJwb3NpdGlvbnMiLCJyZW5kZXJfZWxlbSIsImFpcmNyYWZ0X2ljb24iLCJtYXAiLCJkcmF3X2Jhc2VfbWFwIiwiYWlyY3JhZnRJY29uIiwiaWNvbiIsImljb25VcmwiLCJpY29uU2l6ZSIsImljb25BbmNob3IiLCJsYXllckZsaWdodHMiLCJsYXllclNlbEZsaWdodCIsImxheWVyU2VsRmxpZ2h0RmVhdHVyZSIsImxheWVyU2VsRmxpZ2h0TGF5ZXIiLCJvbkZsaWdodENsaWNrIiwiZmVhdHVyZSIsImxheWVyIiwidXJpIiwicmVwbGFjZSIsInByb3BlcnRpZXMiLCJwaXJlcF9pZCIsImZsaWdodF9yb3V0ZSIsIiQiLCJhamF4IiwidXJsIiwiZGF0YVR5cGUiLCJlcnJvciIsImNvbnNvbGUiLCJsb2ciLCJ3aGVuIiwiZG9uZSIsInJvdXRlSnNvbiIsInJlbW92ZUxheWVyIiwiZ2VvZGVzaWMiLCJ3ZWlnaHQiLCJvcGFjaXR5IiwiY29sb3IiLCJ3cmFwIiwiYWRkVG8iLCJnZW9Kc29uIiwibGluZSIsInVwZGF0ZU1hcCIsImZsaWdodHMiLCJmbGlnaHRHZW9Kc29uIiwiY2xlYXJMYXllcnMiLCJnZW9KU09OIiwib25FYWNoRmVhdHVyZSIsIm9uIiwiY2xpY2siLCJlIiwicG9wdXBfaHRtbCIsInBvcHVwIiwiYmluZFBvcHVwIiwicG9pbnRUb0xheWVyIiwibGF0bG9uIiwibWFya2VyIiwicm90YXRpb25BbmdsZSIsImhlYWRpbmciLCJzZXRJbnRlcnZhbCJdLCJtYXBwaW5ncyI6Ijs7O0FBQ0EsSUFBTUEsVUFBVSxtQkFBQUMsQ0FBUSw0Q0FBUixDQUFoQjs7QUFFQTtBQUNBOztBQUVBOzs7OztBQUtBLHlEQUFlLFVBQUNDLElBQUQsRUFBVTs7QUFFdkJBLFNBQU9DLE9BQU9DLE1BQVAsQ0FBYztBQUNuQkMsZ0JBQVksWUFETztBQUVuQkMsZUFBVyx3QkFGUTtBQUduQkMsZUFBVyxJQUhRO0FBSW5CQyxpQkFBYSxLQUpNO0FBS25CQyxtQkFBZTtBQUxJLEdBQWQsRUFNSlAsSUFOSSxDQUFQOztBQVFBLE1BQU1RLE1BQU0sa0VBQUFDLENBQWNULElBQWQsQ0FBWjtBQUNBLE1BQU1VLGVBQWVaLFFBQVFhLElBQVIsQ0FBYTtBQUNoQ0MsYUFBU1osS0FBS08sYUFEa0I7QUFFaENNLGNBQVUsQ0FBQyxFQUFELEVBQUssRUFBTCxDQUZzQjtBQUdoQ0MsZ0JBQVksQ0FBQyxFQUFELEVBQUssRUFBTDtBQUhvQixHQUFiLENBQXJCOztBQU1BLE1BQUlDLGVBQWUsSUFBbkI7QUFDQSxNQUFJQyxpQkFBaUIsSUFBckI7QUFDQSxNQUFJQyx3QkFBd0IsSUFBNUI7QUFDQSxNQUFJQyxzQkFBc0IsSUFBMUI7O0FBRUE7Ozs7O0FBS0EsTUFBTUMsZ0JBQWdCLFNBQWhCQSxhQUFnQixDQUFDQyxPQUFELEVBQVVDLEtBQVYsRUFBb0I7O0FBRXhDLFFBQU1DLE1BQU10QixLQUFLSSxTQUFMLENBQWVtQixPQUFmLENBQXVCLE1BQXZCLEVBQStCSCxRQUFRSSxVQUFSLENBQW1CQyxRQUFsRCxDQUFaOztBQUVBLFFBQU1DLGVBQWVDLEVBQUVDLElBQUYsQ0FBTztBQUMxQkMsV0FBS1AsR0FEcUI7QUFFMUJRLGdCQUFVLE1BRmdCO0FBRzFCQyxhQUFPQyxRQUFRQztBQUhXLEtBQVAsQ0FBckI7O0FBTUFOLE1BQUVPLElBQUYsQ0FBT1IsWUFBUCxFQUFxQlMsSUFBckIsQ0FBMEIsVUFBQ0MsU0FBRCxFQUFlO0FBQ3ZDLFVBQUlwQixtQkFBbUIsSUFBdkIsRUFBNkI7QUFDM0JSLFlBQUk2QixXQUFKLENBQWdCckIsY0FBaEI7QUFDRDs7QUFFREEsdUJBQWlCbEIsUUFBUXdDLFFBQVIsQ0FBaUIsRUFBakIsRUFBcUI7QUFDcENDLGdCQUFRLENBRDRCO0FBRXBDQyxpQkFBUyxHQUYyQjtBQUdwQ0MsZUFBTyxtRUFINkI7QUFJcENDLGNBQU07QUFKOEIsT0FBckIsRUFLZEMsS0FMYyxDQUtSbkMsR0FMUSxDQUFqQjs7QUFPQVEscUJBQWU0QixPQUFmLENBQXVCUixVQUFVUyxJQUFqQzs7QUFFQTVCLDhCQUF3QkcsT0FBeEI7QUFDQUYsNEJBQXNCRyxLQUF0QjtBQUNBO0FBQ0QsS0FqQkQ7QUFrQkQsR0E1QkQ7O0FBOEJBLE1BQU15QixZQUFZLFNBQVpBLFNBQVksR0FBTTs7QUFFdEJkLFlBQVFDLEdBQVIsQ0FBWSxpQ0FBWjs7QUFFQTs7OztBQUlBLFFBQUljLFVBQVVwQixFQUFFQyxJQUFGLENBQU87QUFDbkJDLFdBQUs3QixLQUFLRyxVQURTO0FBRW5CMkIsZ0JBQVUsTUFGUztBQUduQkMsYUFBT0MsUUFBUUM7QUFISSxLQUFQLENBQWQ7O0FBTUFOLE1BQUVPLElBQUYsQ0FBT2EsT0FBUCxFQUFnQlosSUFBaEIsQ0FBcUIsVUFBVWEsYUFBVixFQUF5Qjs7QUFFNUMsVUFBSWpDLGlCQUFpQixJQUFyQixFQUEyQjtBQUN6QkEscUJBQWFrQyxXQUFiO0FBQ0Q7O0FBRURsQyxxQkFBZWpCLFFBQVFvRCxPQUFSLENBQWdCRixhQUFoQixFQUErQjtBQUM1Q0csdUJBQWUsdUJBQUMvQixPQUFELEVBQVVDLEtBQVYsRUFBb0I7O0FBRWpDQSxnQkFBTStCLEVBQU4sQ0FBUztBQUNQQyxtQkFBTyxlQUFDQyxDQUFELEVBQU87QUFDWm5DLDRCQUFjQyxPQUFkLEVBQXVCQyxLQUF2QjtBQUNEO0FBSE0sV0FBVDs7QUFNQSxjQUFJa0MsYUFBYSxFQUFqQjtBQUNBLGNBQUluQyxRQUFRSSxVQUFSLElBQXNCSixRQUFRSSxVQUFSLENBQW1CZ0MsS0FBN0MsRUFBb0Q7QUFDbERELDBCQUFjbkMsUUFBUUksVUFBUixDQUFtQmdDLEtBQWpDO0FBQ0Q7O0FBRURuQyxnQkFBTW9DLFNBQU4sQ0FBZ0JGLFVBQWhCO0FBQ0QsU0FmMkM7QUFnQjVDRyxzQkFBYyxzQkFBVXRDLE9BQVYsRUFBbUJ1QyxNQUFuQixFQUEyQjtBQUN2QyxpQkFBTzdELFFBQVE4RCxNQUFSLENBQWVELE1BQWYsRUFBdUI7QUFDNUJoRCxrQkFBTUQsWUFEc0I7QUFFNUJtRCwyQkFBZXpDLFFBQVFJLFVBQVIsQ0FBbUJzQztBQUZOLFdBQXZCLENBQVA7QUFJRDtBQXJCMkMsT0FBL0IsQ0FBZjs7QUF3QkEvQyxtQkFBYTRCLEtBQWIsQ0FBbUJuQyxHQUFuQjs7QUFFQSxVQUFJUSxtQkFBbUIsSUFBdkIsRUFBNkI7QUFDM0JHLHNCQUFjRixxQkFBZCxFQUFxQ0MsbUJBQXJDO0FBQ0Q7QUFDRixLQW5DRDtBQW9DRCxHQWxERDs7QUFvREE0QjtBQUNBaUIsY0FBWWpCLFNBQVosRUFBdUIsS0FBdkI7QUFDRCxDQS9HRCIsImZpbGUiOiIuL3Jlc291cmNlcy9qcy9tYXBzL2xpdmVfbWFwLmpzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiXG5jb25zdCBsZWFmbGV0ID0gcmVxdWlyZSgnbGVhZmxldCcpO1xuXG5pbXBvcnQgZHJhd19iYXNlX21hcCBmcm9tICcuL2Jhc2VfbWFwJ1xuaW1wb3J0IHsgQUNUVUFMX1JPVVRFX0NPTE9SIH0gZnJvbSAnLi9jb25maWcnXG5cbi8qKlxuICogUmVuZGVyIHRoZSBsaXZlIG1hcFxuICogQHBhcmFtIG9wdHNcbiAqIEBwcml2YXRlXG4gKi9cbmV4cG9ydCBkZWZhdWx0IChvcHRzKSA9PiB7XG5cbiAgb3B0cyA9IE9iamVjdC5hc3NpZ24oe1xuICAgIHVwZGF0ZV91cmk6ICcvYXBpL2FjYXJzJyxcbiAgICBwaXJlcF91cmk6ICcvYXBpL3BpcmVwcy97aWR9L2FjYXJzJyxcbiAgICBwb3NpdGlvbnM6IG51bGwsXG4gICAgcmVuZGVyX2VsZW06ICdtYXAnLFxuICAgIGFpcmNyYWZ0X2ljb246ICcvYXNzZXRzL2ltZy9hY2Fycy9haXJjcmFmdC5wbmcnLFxuICB9LCBvcHRzKTtcblxuICBjb25zdCBtYXAgPSBkcmF3X2Jhc2VfbWFwKG9wdHMpO1xuICBjb25zdCBhaXJjcmFmdEljb24gPSBsZWFmbGV0Lmljb24oe1xuICAgIGljb25Vcmw6IG9wdHMuYWlyY3JhZnRfaWNvbixcbiAgICBpY29uU2l6ZTogWzQyLCA0Ml0sXG4gICAgaWNvbkFuY2hvcjogWzIxLCAyMV0sXG4gIH0pXG5cbiAgbGV0IGxheWVyRmxpZ2h0cyA9IG51bGxcbiAgbGV0IGxheWVyU2VsRmxpZ2h0ID0gbnVsbFxuICBsZXQgbGF5ZXJTZWxGbGlnaHRGZWF0dXJlID0gbnVsbFxuICBsZXQgbGF5ZXJTZWxGbGlnaHRMYXllciA9IG51bGxcblxuICAvKipcbiAgICogV2hlbiBhIGZsaWdodCBpcyBjbGlja2VkIG9uLCBzaG93IHRoZSBwYXRoLCBldGMgZm9yIHRoYXQgZmxpZ2h0XG4gICAqIEBwYXJhbSBmZWF0dXJlXG4gICAqIEBwYXJhbSBsYXllclxuICAgKi9cbiAgY29uc3Qgb25GbGlnaHRDbGljayA9IChmZWF0dXJlLCBsYXllcikgPT4ge1xuXG4gICAgY29uc3QgdXJpID0gb3B0cy5waXJlcF91cmkucmVwbGFjZSgne2lkfScsIGZlYXR1cmUucHJvcGVydGllcy5waXJlcF9pZClcblxuICAgIGNvbnN0IGZsaWdodF9yb3V0ZSA9ICQuYWpheCh7XG4gICAgICB1cmw6IHVyaSxcbiAgICAgIGRhdGFUeXBlOiAnanNvbicsXG4gICAgICBlcnJvcjogY29uc29sZS5sb2dcbiAgICB9KVxuXG4gICAgJC53aGVuKGZsaWdodF9yb3V0ZSkuZG9uZSgocm91dGVKc29uKSA9PiB7XG4gICAgICBpZiAobGF5ZXJTZWxGbGlnaHQgIT09IG51bGwpIHtcbiAgICAgICAgbWFwLnJlbW92ZUxheWVyKGxheWVyU2VsRmxpZ2h0KVxuICAgICAgfVxuXG4gICAgICBsYXllclNlbEZsaWdodCA9IGxlYWZsZXQuZ2VvZGVzaWMoW10sIHtcbiAgICAgICAgd2VpZ2h0OiA3LFxuICAgICAgICBvcGFjaXR5OiAwLjksXG4gICAgICAgIGNvbG9yOiBBQ1RVQUxfUk9VVEVfQ09MT1IsXG4gICAgICAgIHdyYXA6IGZhbHNlLFxuICAgICAgfSkuYWRkVG8obWFwKVxuXG4gICAgICBsYXllclNlbEZsaWdodC5nZW9Kc29uKHJvdXRlSnNvbi5saW5lKVxuXG4gICAgICBsYXllclNlbEZsaWdodEZlYXR1cmUgPSBmZWF0dXJlXG4gICAgICBsYXllclNlbEZsaWdodExheWVyID0gbGF5ZXJcbiAgICAgIC8vbWFwLmZpdEJvdW5kcyhsYXllclNlbEZsaWdodC5nZXRCb3VuZHMoKSk7XG4gICAgfSlcbiAgfVxuXG4gIGNvbnN0IHVwZGF0ZU1hcCA9ICgpID0+IHtcblxuICAgIGNvbnNvbGUubG9nKCdyZWxvYWRpbmcgZmxpZ2h0cyBmcm9tIGFjYXJzLi4uJylcblxuICAgIC8qKlxuICAgICAqIEFKQVggVVBEQVRFXG4gICAgICovXG5cbiAgICBsZXQgZmxpZ2h0cyA9ICQuYWpheCh7XG4gICAgICB1cmw6IG9wdHMudXBkYXRlX3VyaSxcbiAgICAgIGRhdGFUeXBlOiAnanNvbicsXG4gICAgICBlcnJvcjogY29uc29sZS5sb2dcbiAgICB9KVxuXG4gICAgJC53aGVuKGZsaWdodHMpLmRvbmUoZnVuY3Rpb24gKGZsaWdodEdlb0pzb24pIHtcblxuICAgICAgaWYgKGxheWVyRmxpZ2h0cyAhPT0gbnVsbCkge1xuICAgICAgICBsYXllckZsaWdodHMuY2xlYXJMYXllcnMoKVxuICAgICAgfVxuXG4gICAgICBsYXllckZsaWdodHMgPSBsZWFmbGV0Lmdlb0pTT04oZmxpZ2h0R2VvSnNvbiwge1xuICAgICAgICBvbkVhY2hGZWF0dXJlOiAoZmVhdHVyZSwgbGF5ZXIpID0+IHtcblxuICAgICAgICAgIGxheWVyLm9uKHtcbiAgICAgICAgICAgIGNsaWNrOiAoZSkgPT4ge1xuICAgICAgICAgICAgICBvbkZsaWdodENsaWNrKGZlYXR1cmUsIGxheWVyKVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pXG5cbiAgICAgICAgICBsZXQgcG9wdXBfaHRtbCA9ICcnXG4gICAgICAgICAgaWYgKGZlYXR1cmUucHJvcGVydGllcyAmJiBmZWF0dXJlLnByb3BlcnRpZXMucG9wdXApIHtcbiAgICAgICAgICAgIHBvcHVwX2h0bWwgKz0gZmVhdHVyZS5wcm9wZXJ0aWVzLnBvcHVwXG4gICAgICAgICAgfVxuXG4gICAgICAgICAgbGF5ZXIuYmluZFBvcHVwKHBvcHVwX2h0bWwpXG4gICAgICAgIH0sXG4gICAgICAgIHBvaW50VG9MYXllcjogZnVuY3Rpb24gKGZlYXR1cmUsIGxhdGxvbikge1xuICAgICAgICAgIHJldHVybiBsZWFmbGV0Lm1hcmtlcihsYXRsb24sIHtcbiAgICAgICAgICAgIGljb246IGFpcmNyYWZ0SWNvbixcbiAgICAgICAgICAgIHJvdGF0aW9uQW5nbGU6IGZlYXR1cmUucHJvcGVydGllcy5oZWFkaW5nXG4gICAgICAgICAgfSlcbiAgICAgICAgfVxuICAgICAgfSlcblxuICAgICAgbGF5ZXJGbGlnaHRzLmFkZFRvKG1hcClcblxuICAgICAgaWYgKGxheWVyU2VsRmxpZ2h0ICE9PSBudWxsKSB7XG4gICAgICAgIG9uRmxpZ2h0Q2xpY2sobGF5ZXJTZWxGbGlnaHRGZWF0dXJlLCBsYXllclNlbEZsaWdodExheWVyKVxuICAgICAgfVxuICAgIH0pXG4gIH1cblxuICB1cGRhdGVNYXAoKVxuICBzZXRJbnRlcnZhbCh1cGRhdGVNYXAsIDEwMDAwKVxufTtcblxuXG5cbi8vIFdFQlBBQ0sgRk9PVEVSIC8vXG4vLyAuL3Jlc291cmNlcy9qcy9tYXBzL2xpdmVfbWFwLmpzIl0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./resources/js/maps/live_map.js\n");
/***/ }),
/***/ "./resources/js/maps/route_map.js":
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
eval("/* unused harmony export onFeaturePointClick */\n/* unused harmony export pointToLayer */\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__base_map__ = __webpack_require__(\"./resources/js/maps/base_map.js\");\n/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__config__ = __webpack_require__(\"./resources/js/maps/config.js\");\n\nvar leaflet = __webpack_require__(\"./node_modules/leaflet/dist/leaflet-src.js\");\n\n\n\n\n/**\n * Show some popup text when a feature is clicked on\n * @param feature\n * @param layer\n */\nvar onFeaturePointClick = function onFeaturePointClick(feature, layer) {\n var popup_html = '';\n if (feature.properties && feature.properties.popup) {\n popup_html += feature.properties.popup;\n }\n\n layer.bindPopup(popup_html);\n};\n\n/**\n * Show each point as a marker\n * @param feature\n * @param latlng\n * @returns {*}\n */\nvar pointToLayer = function pointToLayer(feature, latlng) {\n return leaflet.circleMarker(latlng, {\n radius: 12,\n fillColor: '#ff7800',\n color: '#000',\n weight: 1,\n opacity: 1,\n fillOpacity: 0.8\n });\n};\n\n/**\n *\n * @param opts\n * @private\n */\n/* harmony default export */ __webpack_exports__[\"a\"] = (function (opts) {\n\n opts = Object.assign({\n route_points: null,\n planned_route_line: null,\n actual_route_points: null,\n actual_route_line: null,\n render_elem: 'map'\n }, opts);\n\n console.log(opts);\n\n var map = Object(__WEBPACK_IMPORTED_MODULE_0__base_map__[\"a\" /* default */])(opts);\n\n var geodesicLayer = leaflet.geodesic([], {\n weight: 7,\n opacity: 0.9,\n color: __WEBPACK_IMPORTED_MODULE_1__config__[\"b\" /* PLAN_ROUTE_COLOR */],\n steps: 50,\n wrap: false\n }).addTo(map);\n\n geodesicLayer.geoJson(opts.planned_route_line);\n\n try {\n map.fitBounds(geodesicLayer.getBounds());\n } catch (e) {\n console.log(e);\n }\n\n // Draw the route points after\n if (opts.route_points !== null) {\n var route_points = leaflet.geoJSON(opts.route_points, {\n onEachFeature: onFeaturePointClick,\n pointToLayer: pointToLayer,\n style: {\n 'color': __WEBPACK_IMPORTED_MODULE_1__config__[\"b\" /* PLAN_ROUTE_COLOR */],\n 'weight': 5,\n 'opacity': 0.65\n }\n });\n\n route_points.addTo(map);\n }\n\n /**\n * draw the actual route\n */\n\n if (opts.actual_route_line !== null && opts.actual_route_line.features.length > 0) {\n var _geodesicLayer = leaflet.geodesic([], {\n weight: 7,\n opacity: 0.9,\n color: __WEBPACK_IMPORTED_MODULE_1__config__[\"a\" /* ACTUAL_ROUTE_COLOR */],\n steps: 50,\n wrap: false\n }).addTo(map);\n\n _geodesicLayer.geoJson(opts.actual_route_line);\n\n try {\n map.fitBounds(_geodesicLayer.getBounds());\n } catch (e) {\n console.log(e);\n }\n }\n\n if (opts.actual_route_points !== null && opts.actual_route_points.features.length > 0) {\n var _route_points = leaflet.geoJSON(opts.actual_route_points, {\n onEachFeature: onFeaturePointClick,\n pointToLayer: pointToLayer,\n style: {\n 'color': __WEBPACK_IMPORTED_MODULE_1__config__[\"a\" /* ACTUAL_ROUTE_COLOR */],\n 'weight': 5,\n 'opacity': 0.65\n }\n });\n\n _route_points.addTo(map);\n }\n});//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9yZXNvdXJjZXMvanMvbWFwcy9yb3V0ZV9tYXAuanM/YTc0NSJdLCJuYW1lcyI6WyJsZWFmbGV0IiwicmVxdWlyZSIsIm9uRmVhdHVyZVBvaW50Q2xpY2siLCJmZWF0dXJlIiwibGF5ZXIiLCJwb3B1cF9odG1sIiwicHJvcGVydGllcyIsInBvcHVwIiwiYmluZFBvcHVwIiwicG9pbnRUb0xheWVyIiwibGF0bG5nIiwiY2lyY2xlTWFya2VyIiwicmFkaXVzIiwiZmlsbENvbG9yIiwiY29sb3IiLCJ3ZWlnaHQiLCJvcGFjaXR5IiwiZmlsbE9wYWNpdHkiLCJvcHRzIiwiT2JqZWN0IiwiYXNzaWduIiwicm91dGVfcG9pbnRzIiwicGxhbm5lZF9yb3V0ZV9saW5lIiwiYWN0dWFsX3JvdXRlX3BvaW50cyIsImFjdHVhbF9yb3V0ZV9saW5lIiwicmVuZGVyX2VsZW0iLCJjb25zb2xlIiwibG9nIiwibWFwIiwiZHJhd19iYXNlX21hcCIsImdlb2Rlc2ljTGF5ZXIiLCJnZW9kZXNpYyIsInN0ZXBzIiwid3JhcCIsImFkZFRvIiwiZ2VvSnNvbiIsImZpdEJvdW5kcyIsImdldEJvdW5kcyIsImUiLCJnZW9KU09OIiwib25FYWNoRmVhdHVyZSIsInN0eWxlIiwiZmVhdHVyZXMiLCJsZW5ndGgiXSwibWFwcGluZ3MiOiI7Ozs7O0FBQ0EsSUFBTUEsVUFBVSxtQkFBQUMsQ0FBUSw0Q0FBUixDQUFoQjs7QUFFQTtBQUNBOztBQUVBOzs7OztBQUtPLElBQU1DLHNCQUFzQixTQUF0QkEsbUJBQXNCLENBQUNDLE9BQUQsRUFBVUMsS0FBVixFQUFvQjtBQUNyRCxNQUFJQyxhQUFhLEVBQWpCO0FBQ0EsTUFBSUYsUUFBUUcsVUFBUixJQUFzQkgsUUFBUUcsVUFBUixDQUFtQkMsS0FBN0MsRUFBb0Q7QUFDbERGLGtCQUFjRixRQUFRRyxVQUFSLENBQW1CQyxLQUFqQztBQUNEOztBQUVESCxRQUFNSSxTQUFOLENBQWdCSCxVQUFoQjtBQUNELENBUE07O0FBU1A7Ozs7OztBQU1PLElBQU1JLGVBQWUsU0FBZkEsWUFBZSxDQUFDTixPQUFELEVBQVVPLE1BQVYsRUFBcUI7QUFDL0MsU0FBT1YsUUFBUVcsWUFBUixDQUFxQkQsTUFBckIsRUFBNkI7QUFDbENFLFlBQVEsRUFEMEI7QUFFbENDLGVBQVcsU0FGdUI7QUFHbENDLFdBQU8sTUFIMkI7QUFJbENDLFlBQVEsQ0FKMEI7QUFLbENDLGFBQVMsQ0FMeUI7QUFNbENDLGlCQUFhO0FBTnFCLEdBQTdCLENBQVA7QUFRRCxDQVRNOztBQVdQOzs7Ozt5REFLZSxVQUFDQyxJQUFELEVBQVU7O0FBRXZCQSxTQUFPQyxPQUFPQyxNQUFQLENBQWM7QUFDbkJDLGtCQUFjLElBREs7QUFFbkJDLHdCQUFvQixJQUZEO0FBR25CQyx5QkFBcUIsSUFIRjtBQUluQkMsdUJBQW1CLElBSkE7QUFLbkJDLGlCQUFhO0FBTE0sR0FBZCxFQU1KUCxJQU5JLENBQVA7O0FBUUFRLFVBQVFDLEdBQVIsQ0FBWVQsSUFBWjs7QUFFQSxNQUFJVSxNQUFNLGtFQUFBQyxDQUFjWCxJQUFkLENBQVY7O0FBRUEsTUFBSVksZ0JBQWdCOUIsUUFBUStCLFFBQVIsQ0FBaUIsRUFBakIsRUFBcUI7QUFDdkNoQixZQUFRLENBRCtCO0FBRXZDQyxhQUFTLEdBRjhCO0FBR3ZDRixXQUFPLGlFQUhnQztBQUl2Q2tCLFdBQU8sRUFKZ0M7QUFLdkNDLFVBQU07QUFMaUMsR0FBckIsRUFNakJDLEtBTmlCLENBTVhOLEdBTlcsQ0FBcEI7O0FBUUFFLGdCQUFjSyxPQUFkLENBQXNCakIsS0FBS0ksa0JBQTNCOztBQUVBLE1BQUk7QUFDRk0sUUFBSVEsU0FBSixDQUFjTixjQUFjTyxTQUFkLEVBQWQ7QUFDRCxHQUZELENBRUUsT0FBT0MsQ0FBUCxFQUFVO0FBQ1ZaLFlBQVFDLEdBQVIsQ0FBWVcsQ0FBWjtBQUNEOztBQUVEO0FBQ0EsTUFBSXBCLEtBQUtHLFlBQUwsS0FBc0IsSUFBMUIsRUFBZ0M7QUFDOUIsUUFBSUEsZUFBZXJCLFFBQVF1QyxPQUFSLENBQWdCckIsS0FBS0csWUFBckIsRUFBbUM7QUFDcERtQixxQkFBZXRDLG1CQURxQztBQUVwRE8sb0JBQWNBLFlBRnNDO0FBR3BEZ0MsYUFBTztBQUNMLGlCQUFTLGlFQURKO0FBRUwsa0JBQVUsQ0FGTDtBQUdMLG1CQUFXO0FBSE47QUFINkMsS0FBbkMsQ0FBbkI7O0FBVUFwQixpQkFBYWEsS0FBYixDQUFtQk4sR0FBbkI7QUFDRDs7QUFFRDs7OztBQUlBLE1BQUlWLEtBQUtNLGlCQUFMLEtBQTJCLElBQTNCLElBQW1DTixLQUFLTSxpQkFBTCxDQUF1QmtCLFFBQXZCLENBQWdDQyxNQUFoQyxHQUF5QyxDQUFoRixFQUFtRjtBQUNqRixRQUFJYixpQkFBZ0I5QixRQUFRK0IsUUFBUixDQUFpQixFQUFqQixFQUFxQjtBQUN2Q2hCLGNBQVEsQ0FEK0I7QUFFdkNDLGVBQVMsR0FGOEI7QUFHdkNGLGFBQU8sbUVBSGdDO0FBSXZDa0IsYUFBTyxFQUpnQztBQUt2Q0MsWUFBTTtBQUxpQyxLQUFyQixFQU1qQkMsS0FOaUIsQ0FNWE4sR0FOVyxDQUFwQjs7QUFRQUUsbUJBQWNLLE9BQWQsQ0FBc0JqQixLQUFLTSxpQkFBM0I7O0FBRUEsUUFBSTtBQUNGSSxVQUFJUSxTQUFKLENBQWNOLGVBQWNPLFNBQWQsRUFBZDtBQUNELEtBRkQsQ0FFRSxPQUFPQyxDQUFQLEVBQVU7QUFDVlosY0FBUUMsR0FBUixDQUFZVyxDQUFaO0FBQ0Q7QUFDRjs7QUFFRCxNQUFJcEIsS0FBS0ssbUJBQUwsS0FBNkIsSUFBN0IsSUFBcUNMLEtBQUtLLG1CQUFMLENBQXlCbUIsUUFBekIsQ0FBa0NDLE1BQWxDLEdBQTJDLENBQXBGLEVBQXVGO0FBQ3JGLFFBQUl0QixnQkFBZXJCLFFBQVF1QyxPQUFSLENBQWdCckIsS0FBS0ssbUJBQXJCLEVBQTBDO0FBQzNEaUIscUJBQWV0QyxtQkFENEM7QUFFM0RPLG9CQUFjQSxZQUY2QztBQUczRGdDLGFBQU87QUFDTCxpQkFBUyxtRUFESjtBQUVMLGtCQUFVLENBRkw7QUFHTCxtQkFBVztBQUhOO0FBSG9ELEtBQTFDLENBQW5COztBQVVBcEIsa0JBQWFhLEtBQWIsQ0FBbUJOLEdBQW5CO0FBQ0Q7QUFDRixDQWhGRCIsImZpbGUiOiIuL3Jlc291cmNlcy9qcy9tYXBzL3JvdXRlX21hcC5qcy5qcyIsInNvdXJjZXNDb250ZW50IjpbIlxuY29uc3QgbGVhZmxldCA9IHJlcXVpcmUoJ2xlYWZsZXQnKTtcblxuaW1wb3J0IGRyYXdfYmFzZV9tYXAgZnJvbSAnLi9iYXNlX21hcCdcbmltcG9ydCB7IEFDVFVBTF9ST1VURV9DT0xPUiwgUExBTl9ST1VURV9DT0xPUiB9IGZyb20gJy4vY29uZmlnJ1xuXG4vKipcbiAqIFNob3cgc29tZSBwb3B1cCB0ZXh0IHdoZW4gYSBmZWF0dXJlIGlzIGNsaWNrZWQgb25cbiAqIEBwYXJhbSBmZWF0dXJlXG4gKiBAcGFyYW0gbGF5ZXJcbiAqL1xuZXhwb3J0IGNvbnN0IG9uRmVhdHVyZVBvaW50Q2xpY2sgPSAoZmVhdHVyZSwgbGF5ZXIpID0+IHtcbiAgbGV0IHBvcHVwX2h0bWwgPSAnJztcbiAgaWYgKGZlYXR1cmUucHJvcGVydGllcyAmJiBmZWF0dXJlLnByb3BlcnRpZXMucG9wdXApIHtcbiAgICBwb3B1cF9odG1sICs9IGZlYXR1cmUucHJvcGVydGllcy5wb3B1cFxuICB9XG5cbiAgbGF5ZXIuYmluZFBvcHVwKHBvcHVwX2h0bWwpXG59O1xuXG4vKipcbiAqIFNob3cgZWFjaCBwb2ludCBhcyBhIG1hcmtlclxuICogQHBhcmFtIGZlYXR1cmVcbiAqIEBwYXJhbSBsYXRsbmdcbiAqIEByZXR1cm5zIHsqfVxuICovXG5leHBvcnQgY29uc3QgcG9pbnRUb0xheWVyID0gKGZlYXR1cmUsIGxhdGxuZykgPT4ge1xuICByZXR1cm4gbGVhZmxldC5jaXJjbGVNYXJrZXIobGF0bG5nLCB7XG4gICAgcmFkaXVzOiAxMixcbiAgICBmaWxsQ29sb3I6ICcjZmY3ODAwJyxcbiAgICBjb2xvcjogJyMwMDAnLFxuICAgIHdlaWdodDogMSxcbiAgICBvcGFjaXR5OiAxLFxuICAgIGZpbGxPcGFjaXR5OiAwLjhcbiAgfSlcbn1cblxuLyoqXG4gKlxuICogQHBhcmFtIG9wdHNcbiAqIEBwcml2YXRlXG4gKi9cbmV4cG9ydCBkZWZhdWx0IChvcHRzKSA9PiB7XG5cbiAgb3B0cyA9IE9iamVjdC5hc3NpZ24oe1xuICAgIHJvdXRlX3BvaW50czogbnVsbCxcbiAgICBwbGFubmVkX3JvdXRlX2xpbmU6IG51bGwsXG4gICAgYWN0dWFsX3JvdXRlX3BvaW50czogbnVsbCxcbiAgICBhY3R1YWxfcm91dGVfbGluZTogbnVsbCxcbiAgICByZW5kZXJfZWxlbTogJ21hcCcsXG4gIH0sIG9wdHMpO1xuXG4gIGNvbnNvbGUubG9nKG9wdHMpXG5cbiAgbGV0IG1hcCA9IGRyYXdfYmFzZV9tYXAob3B0cylcblxuICBsZXQgZ2VvZGVzaWNMYXllciA9IGxlYWZsZXQuZ2VvZGVzaWMoW10sIHtcbiAgICB3ZWlnaHQ6IDcsXG4gICAgb3BhY2l0eTogMC45LFxuICAgIGNvbG9yOiBQTEFOX1JPVVRFX0NPTE9SLFxuICAgIHN0ZXBzOiA1MCxcbiAgICB3cmFwOiBmYWxzZSxcbiAgfSkuYWRkVG8obWFwKVxuXG4gIGdlb2Rlc2ljTGF5ZXIuZ2VvSnNvbihvcHRzLnBsYW5uZWRfcm91dGVfbGluZSlcblxuICB0cnkge1xuICAgIG1hcC5maXRCb3VuZHMoZ2VvZGVzaWNMYXllci5nZXRCb3VuZHMoKSlcbiAgfSBjYXRjaCAoZSkge1xuICAgIGNvbnNvbGUubG9nKGUpXG4gIH1cblxuICAvLyBEcmF3IHRoZSByb3V0ZSBwb2ludHMgYWZ0ZXJcbiAgaWYgKG9wdHMucm91dGVfcG9pbnRzICE9PSBudWxsKSB7XG4gICAgbGV0IHJvdXRlX3BvaW50cyA9IGxlYWZsZXQuZ2VvSlNPTihvcHRzLnJvdXRlX3BvaW50cywge1xuICAgICAgb25FYWNoRmVhdHVyZTogb25GZWF0dXJlUG9pbnRDbGljayxcbiAgICAgIHBvaW50VG9MYXllcjogcG9pbnRUb0xheWVyLFxuICAgICAgc3R5bGU6IHtcbiAgICAgICAgJ2NvbG9yJzogUExBTl9ST1VURV9DT0xPUixcbiAgICAgICAgJ3dlaWdodCc6IDUsXG4gICAgICAgICdvcGFjaXR5JzogMC42NSxcbiAgICAgIH0sXG4gICAgfSlcblxuICAgIHJvdXRlX3BvaW50cy5hZGRUbyhtYXApXG4gIH1cblxuICAvKipcbiAgICogZHJhdyB0aGUgYWN0dWFsIHJvdXRlXG4gICAqL1xuXG4gIGlmIChvcHRzLmFjdHVhbF9yb3V0ZV9saW5lICE9PSBudWxsICYmIG9wdHMuYWN0dWFsX3JvdXRlX2xpbmUuZmVhdHVyZXMubGVuZ3RoID4gMCkge1xuICAgIGxldCBnZW9kZXNpY0xheWVyID0gbGVhZmxldC5nZW9kZXNpYyhbXSwge1xuICAgICAgd2VpZ2h0OiA3LFxuICAgICAgb3BhY2l0eTogMC45LFxuICAgICAgY29sb3I6IEFDVFVBTF9ST1VURV9DT0xPUixcbiAgICAgIHN0ZXBzOiA1MCxcbiAgICAgIHdyYXA6IGZhbHNlLFxuICAgIH0pLmFkZFRvKG1hcClcblxuICAgIGdlb2Rlc2ljTGF5ZXIuZ2VvSnNvbihvcHRzLmFjdHVhbF9yb3V0ZV9saW5lKVxuXG4gICAgdHJ5IHtcbiAgICAgIG1hcC5maXRCb3VuZHMoZ2VvZGVzaWNMYXllci5nZXRCb3VuZHMoKSlcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjb25zb2xlLmxvZyhlKVxuICAgIH1cbiAgfVxuXG4gIGlmIChvcHRzLmFjdHVhbF9yb3V0ZV9wb2ludHMgIT09IG51bGwgJiYgb3B0cy5hY3R1YWxfcm91dGVfcG9pbnRzLmZlYXR1cmVzLmxlbmd0aCA+IDApIHtcbiAgICBsZXQgcm91dGVfcG9pbnRzID0gbGVhZmxldC5nZW9KU09OKG9wdHMuYWN0dWFsX3JvdXRlX3BvaW50cywge1xuICAgICAgb25FYWNoRmVhdHVyZTogb25GZWF0dXJlUG9pbnRDbGljayxcbiAgICAgIHBvaW50VG9MYXllcjogcG9pbnRUb0xheWVyLFxuICAgICAgc3R5bGU6IHtcbiAgICAgICAgJ2NvbG9yJzogQUNUVUFMX1JPVVRFX0NPTE9SLFxuICAgICAgICAnd2VpZ2h0JzogNSxcbiAgICAgICAgJ29wYWNpdHknOiAwLjY1LFxuICAgICAgfSxcbiAgICB9KVxuXG4gICAgcm91dGVfcG9pbnRzLmFkZFRvKG1hcClcbiAgfVxufTtcblxuXG5cbi8vIFdFQlBBQ0sgRk9PVEVSIC8vXG4vLyAuL3Jlc291cmNlcy9qcy9tYXBzL3JvdXRlX21hcC5qcyJdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./resources/js/maps/route_map.js\n");
/***/ }),
/***/ 2:
/***/ (function(module, exports, __webpack_require__) {
module.exports = __webpack_require__("./resources/js/admin/app.js");
/***/ })
/******/ });