NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Remove from Feed Button for YouTube // @description Easily remove items from your YouTube subscription feed with a single click // @version 0.0.7 // @author Jerome Dane <jeromedane.com> // @namespace http://jeromedane.com/remove-from-feed-for-youtube // @include http://www.youtube.com/feed/subscriptions* // @include https://www.youtube.com/feed/subscriptions* // // This project is hosted on GitHub at https://github.com/JeromeDane/YouTube-Remove-From-Feed-Button // // Issue tracker: https://github.com/JeromeDane/YouTube-Remove-From-Feed-Button/issues // // License: GPL-2.0 // // ==/UserScript== /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) /******/ return installedModules[moduleId].exports; /******/ /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ exports: {}, /******/ id: moduleId, /******/ loaded: false /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.loaded = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ function(module, exports, __webpack_require__) { __webpack_require__(1); var click = __webpack_require__(5); function RemoveFeedFromYouTube() { // configuration variables var removeButtonClass = 'bcRemoveButton'; var feedItemContainerClass = 'feed-item-container'; var feedWrapperSelector = '#browse-items-primary > ol'; var feedItemSelector = feedWrapperSelector + ' .' + feedItemContainerClass; var gridItemContainer = 'yt-shelf-grid-item'; var gridItemSelector = feedWrapperSelector + ' .' + gridItemContainer; function getVideoItemSelector() { var gridItems = document.body.querySelectorAll(gridItemSelector); if(gridItems && gridItems.length > 0) { return gridItemSelector; } return feedItemSelector; } function getRemoveTrigger(postElem) { var removeTrigger = postElem.querySelector('.dismiss-menu-choice'); return removeTrigger; } // hack to auto load images for vids as they come into view function triggerAutoLoad() { var x = window.scrollX; var y = window.scrollY; window.scroll(x,y+1); setTimeout(function() { window.scroll(x,y); },50); } function removePost(postElem) { var removeTrigger = getRemoveTrigger(postElem); click(removeTrigger); postElem.remove(); triggerAutoLoad(); } // create a new button element in the document function createNewButtonElement() { var src = __webpack_require__(6); var button = document.createElement('img'); button.src = src; button.className = removeButtonClass; button.title = "Remove this item from your subscription feed"; return button; } // inject a remove button into a post function injectButton(postElem) { if(!postElem.className.match(/buttonEnabled/)) { postElem.className += ' buttonEnabled'; var removeTrigger = getRemoveTrigger(postElem); if(removeTrigger) { //var actionMenuElem = postElem.querySelector('.feed-item-action-menu'); var button = createNewButtonElement(); postElem.appendChild(button); button.onclick = function() { removePost(postElem); }; } } }; // draw mute button for existing posts function injectButtonsIntoPosts() { var videoElements = document.querySelectorAll(getVideoItemSelector()); for(var i = 0; i < videoElements.length; i++) { injectButton(videoElements[i]); } } // listen for new videos in the DOM and add the remove button as necessary function listenForNewVideos() { var target = document.querySelector(feedWrapperSelector); // create an observer instance var observer = new MutationObserver(function(mutations) { mutations.forEach(function(mutation) { for(var i = 0; i < mutation.addedNodes.length; i++) { var node = mutation.addedNodes[i]; if(node.querySelector) { var item = node.querySelector('.' + feedItemContainerClass); if(item) { injectButton(item); } } } }); }); // configuration of the observer: var config = { attributes: true, childList: true, characterData: true } // pass in the target node, as well as the observer options observer.observe(target, config); } function removeAllWatched() { var videoElements = document.querySelectorAll(getVideoItemSelector()); for(var i = 0; i < videoElements.length; i++) { var videoElement = videoElements[i]; var watched = videoElement.querySelector('.watched-badge'); if(watched) { removePost(videoElement); } injectButton(videoElements[i]); } } function injectRemoveWatchedButton() { // create remove all watched button var button = document.createElement('a'); button.id = "bcRemoveAll"; button.className = "yt-uix-button feed-header-message secondary-nav yt-uix-sessionlink yt-uix-button-epic-nav-item yt-uix-button-size-default"; button.innerHTML = '<span class="yt-uix-button-content">Remove All Watched</span>'; button.onclick = removeAllWatched; // insert remove watched button next to manage subscriptions button var target = document.querySelector('.feed-header .feed-manage-link'); target.parentNode.insertBefore(button, target.nextSibling); } return { init: function() { injectButtonsIntoPosts(); listenForNewVideos(); } }; } module.exports = RemoveFeedFromYouTube; (new RemoveFeedFromYouTube).init(); /***/ }, /* 1 */ /***/ function(module, exports, __webpack_require__) { // style-loader: Adds some css to the DOM by adding a <style> tag // load the styles var content = __webpack_require__(2); if(typeof content === 'string') content = [[module.id, content, '']]; // add the styles to the DOM var update = __webpack_require__(4)(content, {}); if(content.locals) module.exports = content.locals; // Hot Module Replacement if(false) { // When the styles change, update the <style> tags if(!content.locals) { module.hot.accept("!!./../node_modules/css-loader/index.js!./userscript.style.css", function() { var newContent = require("!!./../node_modules/css-loader/index.js!./userscript.style.css"); if(typeof newContent === 'string') newContent = [[module.id, newContent, '']]; update(newContent); }); } // When the module is disposed, remove the <style> tags module.hot.dispose(function() { update(); }); } /***/ }, /* 2 */ /***/ function(module, exports, __webpack_require__) { exports = module.exports = __webpack_require__(3)(); // imports // module exports.push([module.id, ".buttonEnabled{ position: relative; }\n\n// hide removed from feed notices\n.feed-item-dismissal-notices { display:none; }\n\n.bcRemoveButton {\n\tcursor:pointer;\n\topacity:.45;\n\tposition:absolute;\n\ttop:50px;\n\tright:35px;\n\tdisplay:none;\n\tpadding:3px;\n}\n\n\n.feed-item-container:hover .bcRemoveButton { display:block; }\n\n.bcRemoveButton:hover { opacity:.6; }\n\n#bcRemoveAll {\n\tmargin-right: 1em;\n}\n#bcRemoveAll:hover {\n\ttext-decoration: underline;\n}\n\n/* new grid view */\n.yt-shelf-grid-item .bcRemoveButton {\n\ttop: 1px;\n\tright: 1px;\n\tbackground: #000;\n}\n.feed-item-container:hover .yt-shelf-grid-item .bcRemoveButton { display:none; }\n.yt-shelf-grid-item:hover .bcRemoveButton { display:block !important; }\n", ""]); // exports /***/ }, /* 3 */ /***/ function(module, exports) { /* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ // css base code, injected by the css-loader module.exports = function() { var list = []; // return the list of modules as css string list.toString = function toString() { var result = []; for(var i = 0; i < this.length; i++) { var item = this[i]; if(item[2]) { result.push("@media " + item[2] + "{" + item[1] + "}"); } else { result.push(item[1]); } } return result.join(""); }; // import a list of modules into the list list.i = function(modules, mediaQuery) { if(typeof modules === "string") modules = [[null, modules, ""]]; var alreadyImportedModules = {}; for(var i = 0; i < this.length; i++) { var id = this[i][0]; if(typeof id === "number") alreadyImportedModules[id] = true; } for(i = 0; i < modules.length; i++) { var item = modules[i]; // skip already imported module // this implementation is not 100% perfect for weird media query combinations // when a module is imported multiple times with different media queries. // I hope this will never occur (Hey this way we have smaller bundles) if(typeof item[0] !== "number" || !alreadyImportedModules[item[0]]) { if(mediaQuery && !item[2]) { item[2] = mediaQuery; } else if(mediaQuery) { item[2] = "(" + item[2] + ") and (" + mediaQuery + ")"; } list.push(item); } } }; return list; }; /***/ }, /* 4 */ /***/ function(module, exports, __webpack_require__) { /* MIT License http://www.opensource.org/licenses/mit-license.php Author Tobias Koppers @sokra */ var stylesInDom = {}, memoize = function(fn) { var memo; return function () { if (typeof memo === "undefined") memo = fn.apply(this, arguments); return memo; }; }, isOldIE = memoize(function() { return /msie [6-9]\b/.test(window.navigator.userAgent.toLowerCase()); }), getHeadElement = memoize(function () { return document.head || document.getElementsByTagName("head")[0]; }), singletonElement = null, singletonCounter = 0; module.exports = function(list, options) { if(false) { if(typeof document !== "object") throw new Error("The style-loader cannot be used in a non-browser environment"); } options = options || {}; // Force single-tag solution on IE6-9, which has a hard limit on the # of <style> // tags it will allow on a page if (typeof options.singleton === "undefined") options.singleton = isOldIE(); var styles = listToStyles(list); addStylesToDom(styles, options); return function update(newList) { var mayRemove = []; for(var i = 0; i < styles.length; i++) { var item = styles[i]; var domStyle = stylesInDom[item.id]; domStyle.refs--; mayRemove.push(domStyle); } if(newList) { var newStyles = listToStyles(newList); addStylesToDom(newStyles, options); } for(var i = 0; i < mayRemove.length; i++) { var domStyle = mayRemove[i]; if(domStyle.refs === 0) { for(var j = 0; j < domStyle.parts.length; j++) domStyle.parts[j](); delete stylesInDom[domStyle.id]; } } }; } function addStylesToDom(styles, options) { for(var i = 0; i < styles.length; i++) { var item = styles[i]; var domStyle = stylesInDom[item.id]; if(domStyle) { domStyle.refs++; for(var j = 0; j < domStyle.parts.length; j++) { domStyle.parts[j](item.parts[j]); } for(; j < item.parts.length; j++) { domStyle.parts.push(addStyle(item.parts[j], options)); } } else { var parts = []; for(var j = 0; j < item.parts.length; j++) { parts.push(addStyle(item.parts[j], options)); } stylesInDom[item.id] = {id: item.id, refs: 1, parts: parts}; } } } function listToStyles(list) { var styles = []; var newStyles = {}; for(var i = 0; i < list.length; i++) { var item = list[i]; var id = item[0]; var css = item[1]; var media = item[2]; var sourceMap = item[3]; var part = {css: css, media: media, sourceMap: sourceMap}; if(!newStyles[id]) styles.push(newStyles[id] = {id: id, parts: [part]}); else newStyles[id].parts.push(part); } return styles; } function createStyleElement() { var styleElement = document.createElement("style"); var head = getHeadElement(); styleElement.type = "text/css"; head.appendChild(styleElement); return styleElement; } function createLinkElement() { var linkElement = document.createElement("link"); var head = getHeadElement(); linkElement.rel = "stylesheet"; head.appendChild(linkElement); return linkElement; } function addStyle(obj, options) { var styleElement, update, remove; if (options.singleton) { var styleIndex = singletonCounter++; styleElement = singletonElement || (singletonElement = createStyleElement()); update = applyToSingletonTag.bind(null, styleElement, styleIndex, false); remove = applyToSingletonTag.bind(null, styleElement, styleIndex, true); } else if(obj.sourceMap && typeof URL === "function" && typeof URL.createObjectURL === "function" && typeof URL.revokeObjectURL === "function" && typeof Blob === "function" && typeof btoa === "function") { styleElement = createLinkElement(); update = updateLink.bind(null, styleElement); remove = function() { styleElement.parentNode.removeChild(styleElement); if(styleElement.href) URL.revokeObjectURL(styleElement.href); }; } else { styleElement = createStyleElement(); update = applyToTag.bind(null, styleElement); remove = function() { styleElement.parentNode.removeChild(styleElement); }; } update(obj); return function updateStyle(newObj) { if(newObj) { if(newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap) return; update(obj = newObj); } else { remove(); } }; } var replaceText = (function () { var textStore = []; return function (index, replacement) { textStore[index] = replacement; return textStore.filter(Boolean).join('\n'); }; })(); function applyToSingletonTag(styleElement, index, remove, obj) { var css = remove ? "" : obj.css; if (styleElement.styleSheet) { styleElement.styleSheet.cssText = replaceText(index, css); } else { var cssNode = document.createTextNode(css); var childNodes = styleElement.childNodes; if (childNodes[index]) styleElement.removeChild(childNodes[index]); if (childNodes.length) { styleElement.insertBefore(cssNode, childNodes[index]); } else { styleElement.appendChild(cssNode); } } } function applyToTag(styleElement, obj) { var css = obj.css; var media = obj.media; var sourceMap = obj.sourceMap; if(media) { styleElement.setAttribute("media", media) } if(styleElement.styleSheet) { styleElement.styleSheet.cssText = css; } else { while(styleElement.firstChild) { styleElement.removeChild(styleElement.firstChild); } styleElement.appendChild(document.createTextNode(css)); } } function updateLink(linkElement, obj) { var css = obj.css; var media = obj.media; var sourceMap = obj.sourceMap; if(sourceMap) { // http://stackoverflow.com/a/26603875 css += "\n/*# sourceMappingURL=data:application/json;base64," + btoa(unescape(encodeURIComponent(JSON.stringify(sourceMap)))) + " */"; } var blob = new Blob([css], { type: "text/css" }); var oldSrc = linkElement.href; linkElement.href = URL.createObjectURL(blob); if(oldSrc) URL.revokeObjectURL(oldSrc); } /***/ }, /* 5 */ /***/ function(module, exports) { /* * The MIT License * * Copyright 2015 Jerome Dane <jeromedane.com>. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ module.exports = function(element) { var clickEvent; clickEvent = document.createEvent("MouseEvents"); clickEvent.initEvent("mousedown", true, true); element.dispatchEvent(clickEvent); clickEvent = document.createEvent("MouseEvents"); clickEvent.initEvent("click", true, true); element.dispatchEvent(clickEvent); clickEvent = document.createEvent("MouseEvents"); clickEvent.initEvent("mouseup", true, true); element.dispatchEvent(clickEvent); }; /***/ }, /* 6 */ /***/ function(module, exports) { module.exports = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAFNSURBVDiNpdOxalRREAbg717FZBufwiKCglnfICDpZCu7PMbCWp09Nl7Qt7DTZrEzAd8gWSEBLXyP1UKuxf1vuAasdmA4MPPPnH/+M6fp+97Uaq1HOMMcxwlvcYUPpZQfU3wzNqi13sMSaxwkv8s5y/kbBe9LKX+gnRSf4y0avAmDh/F5Yg06nKfG/XRe4gTf8aqUcuNf22Jba/2Ej8Eu0TXr9foI39L9OX5iha6U8isMD8cYHuESPZ61EewgBTcBFmxqrYcp3iS2CqZLzVmb+QQkyS84xef4aWLdHey8NTzVDtcQ2gtc4EX8AotxpGB3OG7taa1B4RmecivYZnLzyGSTnGBn2LaGDRPaDCKOM7+Mj5qs7mCv9n7Gpu97tdaVYQv/t0jS6IlhkR7jdSmlGzfxXeY8wWWttYsO15OZF2HxAF9Ts/9navb9zn8BCnmU7ekAdZMAAAAASUVORK5CYII=" /***/ } /******/ ]); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vd2VicGFjay9ib290c3RyYXAgODkzZGQzNjNlNzliMDY1M2ExYTUiLCJ3ZWJwYWNrOi8vLy4vc3JjL3VzZXJzY3JpcHQuY29kZS5qcyIsIndlYnBhY2s6Ly8vLi9zcmMvdXNlcnNjcmlwdC5zdHlsZS5jc3M/OTJkNSIsIndlYnBhY2s6Ly8vLi9zcmMvdXNlcnNjcmlwdC5zdHlsZS5jc3MiLCJ3ZWJwYWNrOi8vLy4vfi9jc3MtbG9hZGVyL2xpYi9jc3MtYmFzZS5qcyIsIndlYnBhY2s6Ly8vLi9+L3N0eWxlLWxvYWRlci9hZGRTdHlsZXMuanMiLCJ3ZWJwYWNrOi8vLy4vfi9zaW11bGF0ZS1jbGljay1qcy9zcmMvc2ltdWxhdGUtY2xpY2suanMiLCJ3ZWJwYWNrOi8vLy4vc3JjL2ltYWdlcy9jbG9zZV8xNl9yOC5wbmciXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHVCQUFlO0FBQ2Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7Ozs7Ozs7QUN0Q0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFHO0FBQ0g7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtB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RUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBQzs7QUFFRDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHdEQUF1RDtBQUN2RDs7QUFFQSw4QkFBNkIsbUJBQW1COztBQUVoRDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7Ozs7Ozs7QUMxTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEc7Ozs7OztBQ3ZDQSxrQ0FBaUMsb25CIiwiZmlsZSI6Ijg5M2RkMzYzZTc5YjA2NTNhMWE1LmpzIiwic291cmNlc0NvbnRlbnQiOlsiIFx0Ly8gVGhlIG1vZHVsZSBjYWNoZVxuIFx0dmFyIGluc3RhbGxlZE1vZHVsZXMgPSB7fTtcblxuIFx0Ly8gVGhlIHJlcXVpcmUgZnVuY3Rpb25cbiBcdGZ1bmN0aW9uIF9fd2VicGFja19yZXF1aXJlX18obW9kdWxlSWQpIHtcblxuIFx0XHQvLyBDaGVjayBpZiBtb2R1bGUgaXMgaW4gY2FjaGVcbiBcdFx0aWYoaW5zdGFsbGVkTW9kdWxlc1ttb2R1bGVJZF0pXG4gXHRcdFx0cmV0dXJuIGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdLmV4cG9ydHM7XG5cbiBcdFx0Ly8gQ3JlYXRlIGEgbmV3IG1vZHVsZSAoYW5kIHB1dCBpdCBpbnRvIHRoZSBjYWNoZSlcbiBcdFx0dmFyIG1vZHVsZSA9IGluc3RhbGxlZE1vZHVsZXNbbW9kdWxlSWRdID0ge1xuIFx0XHRcdGV4cG9ydHM6IHt9LFxuIFx0XHRcdGlkOiBtb2R1bGVJZCxcbiBcdFx0XHRsb2FkZWQ6IGZhbHNlXG4gXHRcdH07XG5cbiBcdFx0Ly8gRXhlY3V0ZSB0aGUgbW9kdWxlIGZ1bmN0aW9uXG4gXHRcdG1vZHVsZXNbbW9kdWxlSWRdLmNhbGwobW9kdWxlLmV4cG9ydHMsIG1vZHVsZSwgbW9kdWxlLmV4cG9ydHMsIF9fd2VicGFja19yZXF1aXJlX18pO1xuXG4gXHRcdC8vIEZsYWcgdGhlIG1vZHVsZSBhcyBsb2FkZWRcbiBcdFx0bW9kdWxlLmxvYWRlZCA9IHRydWU7XG5cbiBcdFx0Ly8gUmV0dXJuIHRoZSBleHBvcnRzIG9mIHRoZSBtb2R1bGVcbiBcdFx0cmV0dXJuIG1vZHVsZS5leHBvcnRzO1xuIFx0fVxuXG5cbiBcdC8vIGV4cG9zZSB0aGUgbW9kdWxlcyBvYmplY3QgKF9fd2VicGFja19tb2R1bGVzX18pXG4gXHRfX3dlYnBhY2tfcmVxdWlyZV9fLm0gPSBtb2R1bGVzO1xuXG4gXHQvLyBleHBvc2UgdGhlIG1vZHVsZSBjYWNoZVxuIFx0X193ZWJwYWNrX3JlcXVpcmVfXy5jID0gaW5zdGFsbGVkTW9kdWxlcztcblxuIFx0Ly8gX193ZWJwYWNrX3B1YmxpY19wYXRoX19cbiBcdF9fd2VicGFja19yZXF1aXJlX18ucCA9IFwiXCI7XG5cbiBcdC8vIExvYWQgZW50cnkgbW9kdWxlIGFuZCByZXR1cm4gZXhwb3J0c1xuIFx0cmV0dXJuIF9fd2VicGFja19yZXF1aXJlX18oMCk7XG5cblxuXG4vKiogV0VCUEFDSyBGT09URVIgKipcbiAqKiB3ZWJwYWNrL2Jvb3RzdHJhcCA4OTNkZDM2M2U3OWIwNjUzYTFhNVxuICoqLyIsInJlcXVpcmUoJy4vdXNlcnNjcmlwdC5zdHlsZS5jc3MnKTtcblxudmFyIGNsaWNrID0gcmVxdWlyZSgnc2ltdWxhdGUtY2xpY2stanMnKTtcblxuZnVuY3Rpb24gUmVtb3ZlRmVlZEZyb21Zb3VUdWJlKCkge1xuXG5cdC8vIGNvbmZpZ3VyYXRpb24gdmFyaWFibGVzXG5cdHZhciByZW1vdmVCdXR0b25DbGFzcyA9ICdiY1JlbW92ZUJ1dHRvbic7XG5cdHZhciBmZWVkSXRlbUNvbnRhaW5lckNsYXNzID0gJ2ZlZWQtaXRlbS1jb250YWluZXInO1xuXHR2YXIgZmVlZFdyYXBwZXJTZWxlY3RvciA9ICcjYnJvd3NlLWl0ZW1zLXByaW1hcnkgPiBvbCc7XG5cdHZhciBmZWVkSXRlbVNlbGVjdG9yID0gZmVlZFdyYXBwZXJTZWxlY3RvciArICcgLicgKyBmZWVkSXRlbUNvbnRhaW5lckNsYXNzO1xuXHR2YXIgZ3JpZEl0ZW1Db250YWluZXIgPSAneXQtc2hlbGYtZ3JpZC1pdGVtJztcblx0dmFyIGdyaWRJdGVtU2VsZWN0b3IgPSBmZWVkV3JhcHBlclNlbGVjdG9yICsgJyAuJyArIGdyaWRJdGVtQ29udGFpbmVyO1xuXG5cdGZ1bmN0aW9uIGdldFZpZGVvSXRlbVNlbGVjdG9yKCkge1xuXHRcdHZhciBncmlkSXRlbXMgPSBkb2N1bWVudC5ib2R5LnF1ZXJ5U2VsZWN0b3JBbGwoZ3JpZEl0ZW1TZWxlY3Rvcik7XG5cdFx0aWYoZ3JpZEl0ZW1zICYmIGdyaWRJdGVtcy5sZW5ndGggPiAwKSB7XG5cdFx0XHRcdHJldHVybiBncmlkSXRlbVNlbGVjdG9yO1xuXHRcdH1cblx0XHRyZXR1cm4gZmVlZEl0ZW1TZWxlY3Rvcjtcblx0fVxuXG5cdGZ1bmN0aW9uIGdldFJlbW92ZVRyaWdnZXIocG9zdEVsZW0pIHtcblx0XHR2YXIgcmVtb3ZlVHJpZ2dlciA9IHBvc3RFbGVtLnF1ZXJ5U2VsZWN0b3IoJy5kaXNtaXNzLW1lbnUtY2hvaWNlJyk7XG5cdFx0cmV0dXJuIHJlbW92ZVRyaWdnZXI7XG5cdH1cblxuXHQvLyBoYWNrIHRvIGF1dG8gbG9hZCBpbWFnZXMgZm9yIHZpZHMgYXMgdGhleSBjb21lIGludG8gdmlld1xuXHRmdW5jdGlvbiB0cmlnZ2VyQXV0b0xvYWQoKSB7XG5cdFx0dmFyIHggPSB3aW5kb3cuc2Nyb2xsWDtcblx0XHR2YXIgeSA9IHdpbmRvdy5zY3JvbGxZO1xuXHRcdHdpbmRvdy5zY3JvbGwoeCx5KzEpO1xuXHRcdHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG5cdFx0XHR3aW5kb3cuc2Nyb2xsKHgseSk7XG5cdFx0fSw1MCk7XG5cdH1cblxuXHRmdW5jdGlvbiByZW1vdmVQb3N0KHBvc3RFbGVtKSB7XG5cdFx0dmFyIHJlbW92ZVRyaWdnZXIgPSBnZXRSZW1vdmVUcmlnZ2VyKHBvc3RFbGVtKTtcblx0XHRjbGljayhyZW1vdmVUcmlnZ2VyKTtcblx0XHRwb3N0RWxlbS5yZW1vdmUoKTtcblx0XHR0cmlnZ2VyQXV0b0xvYWQoKTtcblx0fVxuXG5cdC8vIGNyZWF0ZSBhIG5ldyBidXR0b24gZWxlbWVudCBpbiB0aGUgZG9jdW1lbnRcblx0ZnVuY3Rpb24gY3JlYXRlTmV3QnV0dG9uRWxlbWVudCgpIHtcblx0XHR2YXIgc3JjID0gcmVxdWlyZSgnLi9pbWFnZXMvY2xvc2VfMTZfcjgucG5nJyk7XG5cdFx0dmFyIGJ1dHRvbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2ltZycpO1xuXHRcdGJ1dHRvbi5zcmMgPSBzcmM7XG5cdFx0YnV0dG9uLmNsYXNzTmFtZSA9IHJlbW92ZUJ1dHRvbkNsYXNzO1xuXHRcdGJ1dHRvbi50aXRsZSA9IFwiUmVtb3ZlIHRoaXMgaXRlbSBmcm9tIHlvdXIgc3Vic2NyaXB0aW9uIGZlZWRcIjtcblx0XHRyZXR1cm4gYnV0dG9uO1xuXHR9XG5cblx0Ly8gaW5qZWN0IGEgcmVtb3ZlIGJ1dHRvbiBpbnRvIGEgcG9zdFxuXHRmdW5jdGlvbiBpbmplY3RCdXR0b24ocG9zdEVsZW0pIHtcblx0XHRpZighcG9zdEVsZW0uY2xhc3NOYW1lLm1hdGNoKC9idXR0b25FbmFibGVkLykpIHtcblx0XHRcdHBvc3RFbGVtLmNsYXNzTmFtZSArPSAnIGJ1dHRvbkVuYWJsZWQnO1xuXHRcdFx0dmFyIHJlbW92ZVRyaWdnZXIgPSBnZXRSZW1vdmVUcmlnZ2VyKHBvc3RFbGVtKTtcblx0XHRcdGlmKHJlbW92ZVRyaWdnZXIpIHtcblx0XHRcdFx0Ly92YXIgYWN0aW9uTWVudUVsZW0gPSBwb3N0RWxlbS5xdWVyeVNlbGVjdG9yKCcuZmVlZC1pdGVtLWFjdGlvbi1tZW51Jyk7XG5cdFx0XHRcdHZhciBidXR0b24gPSBjcmVhdGVOZXdCdXR0b25FbGVtZW50KCk7XG5cdFx0XHRcdHBvc3RFbGVtLmFwcGVuZENoaWxkKGJ1dHRvbik7XG5cdFx0XHRcdGJ1dHRvbi5vbmNsaWNrID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0cmVtb3ZlUG9zdChwb3N0RWxlbSk7XG5cdFx0XHRcdH07XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xuXG5cdC8vIGRyYXcgbXV0ZSBidXR0b24gZm9yIGV4aXN0aW5nIHBvc3RzXG5cdGZ1bmN0aW9uIGluamVjdEJ1dHRvbnNJbnRvUG9zdHMoKSB7XG5cdFx0dmFyIHZpZGVvRWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKGdldFZpZGVvSXRlbVNlbGVjdG9yKCkpO1xuXHRcdGZvcih2YXIgaSA9IDA7IGkgPCB2aWRlb0VsZW1lbnRzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRpbmplY3RCdXR0b24odmlkZW9FbGVtZW50c1tpXSk7XG5cdFx0fVxuXHR9XG5cblxuXHQvLyBsaXN0ZW4gZm9yIG5ldyB2aWRlb3MgaW4gdGhlIERPTSBhbmQgYWRkIHRoZSByZW1vdmUgYnV0dG9uIGFzIG5lY2Vzc2FyeVxuXHRmdW5jdGlvbiBsaXN0ZW5Gb3JOZXdWaWRlb3MoKSB7XG5cblx0XHR2YXIgdGFyZ2V0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihmZWVkV3JhcHBlclNlbGVjdG9yKTtcblxuXHRcdC8vIGNyZWF0ZSBhbiBvYnNlcnZlciBpbnN0YW5jZVxuXHRcdHZhciBvYnNlcnZlciA9IG5ldyBNdXRhdGlvbk9ic2VydmVyKGZ1bmN0aW9uKG11dGF0aW9ucykge1xuXHRcdFx0bXV0YXRpb25zLmZvckVhY2goZnVuY3Rpb24obXV0YXRpb24pIHtcblx0XHRcdFx0Zm9yKHZhciBpID0gMDsgaSA8IG11dGF0aW9uLmFkZGVkTm9kZXMubGVuZ3RoOyBpKyspIHtcblx0XHRcdFx0XHR2YXIgIG5vZGUgPSBtdXRhdGlvbi5hZGRlZE5vZGVzW2ldO1xuXHRcdFx0XHRcdGlmKG5vZGUucXVlcnlTZWxlY3Rvcikge1xuXHRcdFx0XHRcdFx0dmFyIGl0ZW0gPSBub2RlLnF1ZXJ5U2VsZWN0b3IoJy4nICsgZmVlZEl0ZW1Db250YWluZXJDbGFzcyk7XG5cdFx0XHRcdFx0XHRpZihpdGVtKSB7XG5cdFx0XHRcdFx0XHRcdGluamVjdEJ1dHRvbihpdGVtKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdH0pO1xuXG5cdFx0Ly8gY29uZmlndXJhdGlvbiBvZiB0aGUgb2JzZXJ2ZXI6XG5cdFx0dmFyIGNvbmZpZyA9IHsgYXR0cmlidXRlczogdHJ1ZSwgY2hpbGRMaXN0OiB0cnVlLCBjaGFyYWN0ZXJEYXRhOiB0cnVlIH1cblxuXHRcdC8vIHBhc3MgaW4gdGhlIHRhcmdldCBub2RlLCBhcyB3ZWxsIGFzIHRoZSBvYnNlcnZlciBvcHRpb25zXG5cdFx0b2JzZXJ2ZXIub2JzZXJ2ZSh0YXJnZXQsIGNvbmZpZyk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlbW92ZUFsbFdhdGNoZWQoKSB7XG5cdFx0dmFyIHZpZGVvRWxlbWVudHMgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsKGdldFZpZGVvSXRlbVNlbGVjdG9yKCkpO1xuXHRcdGZvcih2YXIgaSA9IDA7IGkgPCB2aWRlb0VsZW1lbnRzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHR2YXIgdmlkZW9FbGVtZW50ID0gdmlkZW9FbGVtZW50c1tpXTtcblx0XHRcdHZhciB3YXRjaGVkID0gdmlkZW9FbGVtZW50LnF1ZXJ5U2VsZWN0b3IoJy53YXRjaGVkLWJhZGdlJyk7XG5cdFx0XHRpZih3YXRjaGVkKSB7XG5cdFx0XHRcdHJlbW92ZVBvc3QodmlkZW9FbGVtZW50KTtcblx0XHRcdH1cblx0XHRcdGluamVjdEJ1dHRvbih2aWRlb0VsZW1lbnRzW2ldKTtcblx0XHR9XG5cdH1cblxuXHRmdW5jdGlvbiBpbmplY3RSZW1vdmVXYXRjaGVkQnV0dG9uKCkge1xuXHRcdC8vIGNyZWF0ZSByZW1vdmUgYWxsIHdhdGNoZWQgYnV0dG9uXG5cdFx0dmFyIGJ1dHRvbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2EnKTtcblx0XHRidXR0b24uaWQgPSBcImJjUmVtb3ZlQWxsXCI7XG5cdFx0YnV0dG9uLmNsYXNzTmFtZSA9IFwieXQtdWl4LWJ1dHRvbiBmZWVkLWhlYWRlci1tZXNzYWdlIHNlY29uZGFyeS1uYXYgeXQtdWl4LXNlc3Npb25saW5rIHl0LXVpeC1idXR0b24tZXBpYy1uYXYtaXRlbSB5dC11aXgtYnV0dG9uLXNpemUtZGVmYXVsdFwiO1xuXHRcdGJ1dHRvbi5pbm5lckhUTUwgPSAnPHNwYW4gY2xhc3M9XCJ5dC11aXgtYnV0dG9uLWNvbnRlbnRcIj5SZW1vdmUgQWxsIFdhdGNoZWQ8L3NwYW4+JztcblxuXHRcdGJ1dHRvbi5vbmNsaWNrID0gcmVtb3ZlQWxsV2F0Y2hlZDtcblxuXHRcdC8vIGluc2VydCByZW1vdmUgd2F0Y2hlZCBidXR0b24gbmV4dCB0byBtYW5hZ2Ugc3Vic2NyaXB0aW9ucyBidXR0b25cblx0XHR2YXIgdGFyZ2V0ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignLmZlZWQtaGVhZGVyIC5mZWVkLW1hbmFnZS1saW5rJyk7XG5cdFx0dGFyZ2V0LnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGJ1dHRvbiwgdGFyZ2V0Lm5leHRTaWJsaW5nKTtcblxuXHR9XG5cblx0cmV0dXJuIHtcblx0XHRpbml0OiBmdW5jdGlvbigpIHtcblx0XHRcdGluamVjdEJ1dHRvbnNJbnRvUG9zdHMoKTtcblx0XHRcdGxpc3RlbkZvck5ld1ZpZGVvcygpO1xuXHRcdH1cblx0fTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBSZW1vdmVGZWVkRnJvbVlvdVR1YmU7XG5cbihuZXcgUmVtb3ZlRmVlZEZyb21Zb3VUdWJlKS5pbml0KCk7XG5cblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIC4vc3JjL3VzZXJzY3JpcHQuY29kZS5qc1xuICoqIG1vZHVsZSBpZCA9IDBcbiAqKiBtb2R1bGUgY2h1bmtzID0gMFxuICoqLyIsIi8vIHN0eWxlLWxvYWRlcjogQWRkcyBzb21lIGNzcyB0byB0aGUgRE9NIGJ5IGFkZGluZyBhIDxzdHlsZT4gdGFnXG5cbi8vIGxvYWQgdGhlIHN0eWxlc1xudmFyIGNvbnRlbnQgPSByZXF1aXJlKFwiISEuLy4uL25vZGVfbW9kdWxlcy9jc3MtbG9hZGVyL2luZGV4LmpzIS4vdXNlcnNjcmlwdC5zdHlsZS5jc3NcIik7XG5pZih0eXBlb2YgY29udGVudCA9PT0gJ3N0cmluZycpIGNvbnRlbnQgPSBbW21vZHVsZS5pZCwgY29udGVudCwgJyddXTtcbi8vIGFkZCB0aGUgc3R5bGVzIHRvIHRoZSBET01cbnZhciB1cGRhdGUgPSByZXF1aXJlKFwiIS4vLi4vbm9kZV9tb2R1bGVzL3N0eWxlLWxvYWRlci9hZGRTdHlsZXMuanNcIikoY29udGVudCwge30pO1xuaWYoY29udGVudC5sb2NhbHMpIG1vZHVsZS5leHBvcnRzID0gY29udGVudC5sb2NhbHM7XG4vLyBIb3QgTW9kdWxlIFJlcGxhY2VtZW50XG5pZihtb2R1bGUuaG90KSB7XG5cdC8vIFdoZW4gdGhlIHN0eWxlcyBjaGFuZ2UsIHVwZGF0ZSB0aGUgPHN0eWxlPiB0YWdzXG5cdGlmKCFjb250ZW50LmxvY2Fscykge1xuXHRcdG1vZHVsZS5ob3QuYWNjZXB0KFwiISEuLy4uL25vZGVfbW9kdWxlcy9jc3MtbG9hZGVyL2luZGV4LmpzIS4vdXNlcnNjcmlwdC5zdHlsZS5jc3NcIiwgZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgbmV3Q29udGVudCA9IHJlcXVpcmUoXCIhIS4vLi4vbm9kZV9tb2R1bGVzL2Nzcy1sb2FkZXIvaW5kZXguanMhLi91c2Vyc2NyaXB0LnN0eWxlLmNzc1wiKTtcblx0XHRcdGlmKHR5cGVvZiBuZXdDb250ZW50ID09PSAnc3RyaW5nJykgbmV3Q29udGVudCA9IFtbbW9kdWxlLmlkLCBuZXdDb250ZW50LCAnJ11dO1xuXHRcdFx0dXBkYXRlKG5ld0NvbnRlbnQpO1xuXHRcdH0pO1xuXHR9XG5cdC8vIFdoZW4gdGhlIG1vZHVsZSBpcyBkaXNwb3NlZCwgcmVtb3ZlIHRoZSA8c3R5bGU+IHRhZ3Ncblx0bW9kdWxlLmhvdC5kaXNwb3NlKGZ1bmN0aW9uKCkgeyB1cGRhdGUoKTsgfSk7XG59XG5cblxuLyoqKioqKioqKioqKioqKioqXG4gKiogV0VCUEFDSyBGT09URVJcbiAqKiAuL3NyYy91c2Vyc2NyaXB0LnN0eWxlLmNzc1xuICoqIG1vZHVsZSBpZCA9IDFcbiAqKiBtb2R1bGUgY2h1bmtzID0gMFxuICoqLyIsImV4cG9ydHMgPSBtb2R1bGUuZXhwb3J0cyA9IHJlcXVpcmUoXCIuLy4uL25vZGVfbW9kdWxlcy9jc3MtbG9hZGVyL2xpYi9jc3MtYmFzZS5qc1wiKSgpO1xuLy8gaW1wb3J0c1xuXG5cbi8vIG1vZHVsZVxuZXhwb3J0cy5wdXNoKFttb2R1bGUuaWQsIFwiLmJ1dHRvbkVuYWJsZWR7IHBvc2l0aW9uOiByZWxhdGl2ZTsgfVxcblxcbi8vIGhpZGUgcmVtb3ZlZCBmcm9tIGZlZWQgbm90aWNlc1xcbi5mZWVkLWl0ZW0tZGlzbWlzc2FsLW5vdGljZXMgeyBkaXNwbGF5Om5vbmU7IH1cXG5cXG4uYmNSZW1vdmVCdXR0b24ge1xcblxcdGN1cnNvcjpwb2ludGVyO1xcblxcdG9wYWNpdHk6LjQ1O1xcblxcdHBvc2l0aW9uOmFic29sdXRlO1xcblxcdHRvcDo1MHB4O1xcblxcdHJpZ2h0OjM1cHg7XFxuXFx0ZGlzcGxheTpub25lO1xcblxcdHBhZGRpbmc6M3B4O1xcbn1cXG5cXG5cXG4uZmVlZC1pdGVtLWNvbnRhaW5lcjpob3ZlciAuYmNSZW1vdmVCdXR0b24geyBkaXNwbGF5OmJsb2NrOyB9XFxuXFxuLmJjUmVtb3ZlQnV0dG9uOmhvdmVyIHsgb3BhY2l0eTouNjsgfVxcblxcbiNiY1JlbW92ZUFsbCB7XFxuXFx0bWFyZ2luLXJpZ2h0OiAxZW07XFxufVxcbiNiY1JlbW92ZUFsbDpob3ZlciB7XFxuXFx0dGV4dC1kZWNvcmF0aW9uOiB1bmRlcmxpbmU7XFxufVxcblxcbi8qIG5ldyBncmlkIHZpZXcgKi9cXG4ueXQtc2hlbGYtZ3JpZC1pdGVtIC5iY1JlbW92ZUJ1dHRvbiB7XFxuXFx0dG9wOiAxcHg7XFxuXFx0cmlnaHQ6IDFweDtcXG5cXHRiYWNrZ3JvdW5kOiAjMDAwO1xcbn1cXG4uZmVlZC1pdGVtLWNvbnRhaW5lcjpob3ZlciAueXQtc2hlbGYtZ3JpZC1pdGVtIC5iY1JlbW92ZUJ1dHRvbiB7IGRpc3BsYXk6bm9uZTsgfVxcbi55dC1zaGVsZi1ncmlkLWl0ZW06aG92ZXIgLmJjUmVtb3ZlQnV0dG9uIHsgZGlzcGxheTpibG9jayAhaW1wb3J0YW50OyB9XFxuXCIsIFwiXCJdKTtcblxuLy8gZXhwb3J0c1xuXG5cblxuLyoqKioqKioqKioqKioqKioqXG4gKiogV0VCUEFDSyBGT09URVJcbiAqKiAuL34vY3NzLWxvYWRlciEuL3NyYy91c2Vyc2NyaXB0LnN0eWxlLmNzc1xuICoqIG1vZHVsZSBpZCA9IDJcbiAqKiBtb2R1bGUgY2h1bmtzID0gMFxuICoqLyIsIi8qXHJcblx0TUlUIExpY2Vuc2UgaHR0cDovL3d3dy5vcGVuc291cmNlLm9yZy9saWNlbnNlcy9taXQtbGljZW5zZS5waHBcclxuXHRBdXRob3IgVG9iaWFzIEtvcHBlcnMgQHNva3JhXHJcbiovXHJcbi8vIGNzcyBiYXNlIGNvZGUsIGluamVjdGVkIGJ5IHRoZSBjc3MtbG9hZGVyXHJcbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oKSB7XHJcblx0dmFyIGxpc3QgPSBbXTtcclxuXHJcblx0Ly8gcmV0dXJuIHRoZSBsaXN0IG9mIG1vZHVsZXMgYXMgY3NzIHN0cmluZ1xyXG5cdGxpc3QudG9TdHJpbmcgPSBmdW5jdGlvbiB0b1N0cmluZygpIHtcclxuXHRcdHZhciByZXN1bHQgPSBbXTtcclxuXHRcdGZvcih2YXIgaSA9IDA7IGkgPCB0aGlzLmxlbmd0aDsgaSsrKSB7XHJcblx0XHRcdHZhciBpdGVtID0gdGhpc1tpXTtcclxuXHRcdFx0aWYoaXRlbVsyXSkge1xyXG5cdFx0XHRcdHJlc3VsdC5wdXNoKFwiQG1lZGlhIFwiICsgaXRlbVsyXSArIFwie1wiICsgaXRlbVsxXSArIFwifVwiKTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRyZXN1bHQucHVzaChpdGVtWzFdKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHJlc3VsdC5qb2luKFwiXCIpO1xyXG5cdH07XHJcblxyXG5cdC8vIGltcG9ydCBhIGxpc3Qgb2YgbW9kdWxlcyBpbnRvIHRoZSBsaXN0XHJcblx0bGlzdC5pID0gZnVuY3Rpb24obW9kdWxlcywgbWVkaWFRdWVyeSkge1xyXG5cdFx0aWYodHlwZW9mIG1vZHVsZXMgPT09IFwic3RyaW5nXCIpXHJcblx0XHRcdG1vZHVsZXMgPSBbW251bGwsIG1vZHVsZXMsIFwiXCJdXTtcclxuXHRcdHZhciBhbHJlYWR5SW1wb3J0ZWRNb2R1bGVzID0ge307XHJcblx0XHRmb3IodmFyIGkgPSAwOyBpIDwgdGhpcy5sZW5ndGg7IGkrKykge1xyXG5cdFx0XHR2YXIgaWQgPSB0aGlzW2ldWzBdO1xyXG5cdFx0XHRpZih0eXBlb2YgaWQgPT09IFwibnVtYmVyXCIpXHJcblx0XHRcdFx0YWxyZWFkeUltcG9ydGVkTW9kdWxlc1tpZF0gPSB0cnVlO1xyXG5cdFx0fVxyXG5cdFx0Zm9yKGkgPSAwOyBpIDwgbW9kdWxlcy5sZW5ndGg7IGkrKykge1xyXG5cdFx0XHR2YXIgaXRlbSA9IG1vZHVsZXNbaV07XHJcblx0XHRcdC8vIHNraXAgYWxyZWFkeSBpbXBvcnRlZCBtb2R1bGVcclxuXHRcdFx0Ly8gdGhpcyBpbXBsZW1lbnRhdGlvbiBpcyBub3QgMTAwJSBwZXJmZWN0IGZvciB3ZWlyZCBtZWRpYSBxdWVyeSBjb21iaW5hdGlvbnNcclxuXHRcdFx0Ly8gIHdoZW4gYSBtb2R1bGUgaXMgaW1wb3J0ZWQgbXVsdGlwbGUgdGltZXMgd2l0aCBkaWZmZXJlbnQgbWVkaWEgcXVlcmllcy5cclxuXHRcdFx0Ly8gIEkgaG9wZSB0aGlzIHdpbGwgbmV2ZXIgb2NjdXIgKEhleSB0aGlzIHdheSB3ZSBoYXZlIHNtYWxsZXIgYnVuZGxlcylcclxuXHRcdFx0aWYodHlwZW9mIGl0ZW1bMF0gIT09IFwibnVtYmVyXCIgfHwgIWFscmVhZHlJbXBvcnRlZE1vZHVsZXNbaXRlbVswXV0pIHtcclxuXHRcdFx0XHRpZihtZWRpYVF1ZXJ5ICYmICFpdGVtWzJdKSB7XHJcblx0XHRcdFx0XHRpdGVtWzJdID0gbWVkaWFRdWVyeTtcclxuXHRcdFx0XHR9IGVsc2UgaWYobWVkaWFRdWVyeSkge1xyXG5cdFx0XHRcdFx0aXRlbVsyXSA9IFwiKFwiICsgaXRlbVsyXSArIFwiKSBhbmQgKFwiICsgbWVkaWFRdWVyeSArIFwiKVwiO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRsaXN0LnB1c2goaXRlbSk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9O1xyXG5cdHJldHVybiBsaXN0O1xyXG59O1xyXG5cblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIC4vfi9jc3MtbG9hZGVyL2xpYi9jc3MtYmFzZS5qc1xuICoqIG1vZHVsZSBpZCA9IDNcbiAqKiBtb2R1bGUgY2h1bmtzID0gMFxuICoqLyIsIi8qXHJcblx0TUlUIExpY2Vuc2UgaHR0cDovL3d3dy5vcGVuc291cmNlLm9yZy9saWNlbnNlcy9taXQtbGljZW5zZS5waHBcclxuXHRBdXRob3IgVG9iaWFzIEtvcHBlcnMgQHNva3JhXHJcbiovXHJcbnZhciBzdHlsZXNJbkRvbSA9IHt9LFxyXG5cdG1lbW9pemUgPSBmdW5jdGlvbihmbikge1xyXG5cdFx0dmFyIG1lbW87XHJcblx0XHRyZXR1cm4gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRpZiAodHlwZW9mIG1lbW8gPT09IFwidW5kZWZpbmVkXCIpIG1lbW8gPSBmbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xyXG5cdFx0XHRyZXR1cm4gbWVtbztcclxuXHRcdH07XHJcblx0fSxcclxuXHRpc09sZElFID0gbWVtb2l6ZShmdW5jdGlvbigpIHtcclxuXHRcdHJldHVybiAvbXNpZSBbNi05XVxcYi8udGVzdCh3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudC50b0xvd2VyQ2FzZSgpKTtcclxuXHR9KSxcclxuXHRnZXRIZWFkRWxlbWVudCA9IG1lbW9pemUoZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIGRvY3VtZW50LmhlYWQgfHwgZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoXCJoZWFkXCIpWzBdO1xyXG5cdH0pLFxyXG5cdHNpbmdsZXRvbkVsZW1lbnQgPSBudWxsLFxyXG5cdHNpbmdsZXRvbkNvdW50ZXIgPSAwO1xyXG5cclxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihsaXN0LCBvcHRpb25zKSB7XHJcblx0aWYodHlwZW9mIERFQlVHICE9PSBcInVuZGVmaW5lZFwiICYmIERFQlVHKSB7XHJcblx0XHRpZih0eXBlb2YgZG9jdW1lbnQgIT09IFwib2JqZWN0XCIpIHRocm93IG5ldyBFcnJvcihcIlRoZSBzdHlsZS1sb2FkZXIgY2Fubm90IGJlIHVzZWQgaW4gYSBub24tYnJvd3NlciBlbnZpcm9ubWVudFwiKTtcclxuXHR9XHJcblxyXG5cdG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xyXG5cdC8vIEZvcmNlIHNpbmdsZS10YWcgc29sdXRpb24gb24gSUU2LTksIHdoaWNoIGhhcyBhIGhhcmQgbGltaXQgb24gdGhlICMgb2YgPHN0eWxlPlxyXG5cdC8vIHRhZ3MgaXQgd2lsbCBhbGxvdyBvbiBhIHBhZ2VcclxuXHRpZiAodHlwZW9mIG9wdGlvbnMuc2luZ2xldG9uID09PSBcInVuZGVmaW5lZFwiKSBvcHRpb25zLnNpbmdsZXRvbiA9IGlzT2xkSUUoKTtcclxuXHJcblx0dmFyIHN0eWxlcyA9IGxpc3RUb1N0eWxlcyhsaXN0KTtcclxuXHRhZGRTdHlsZXNUb0RvbShzdHlsZXMsIG9wdGlvbnMpO1xyXG5cclxuXHRyZXR1cm4gZnVuY3Rpb24gdXBkYXRlKG5ld0xpc3QpIHtcclxuXHRcdHZhciBtYXlSZW1vdmUgPSBbXTtcclxuXHRcdGZvcih2YXIgaSA9IDA7IGkgPCBzdHlsZXMubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0dmFyIGl0ZW0gPSBzdHlsZXNbaV07XHJcblx0XHRcdHZhciBkb21TdHlsZSA9IHN0eWxlc0luRG9tW2l0ZW0uaWRdO1xyXG5cdFx0XHRkb21TdHlsZS5yZWZzLS07XHJcblx0XHRcdG1heVJlbW92ZS5wdXNoKGRvbVN0eWxlKTtcclxuXHRcdH1cclxuXHRcdGlmKG5ld0xpc3QpIHtcclxuXHRcdFx0dmFyIG5ld1N0eWxlcyA9IGxpc3RUb1N0eWxlcyhuZXdMaXN0KTtcclxuXHRcdFx0YWRkU3R5bGVzVG9Eb20obmV3U3R5bGVzLCBvcHRpb25zKTtcclxuXHRcdH1cclxuXHRcdGZvcih2YXIgaSA9IDA7IGkgPCBtYXlSZW1vdmUubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0dmFyIGRvbVN0eWxlID0gbWF5UmVtb3ZlW2ldO1xyXG5cdFx0XHRpZihkb21TdHlsZS5yZWZzID09PSAwKSB7XHJcblx0XHRcdFx0Zm9yKHZhciBqID0gMDsgaiA8IGRvbVN0eWxlLnBhcnRzLmxlbmd0aDsgaisrKVxyXG5cdFx0XHRcdFx0ZG9tU3R5bGUucGFydHNbal0oKTtcclxuXHRcdFx0XHRkZWxldGUgc3R5bGVzSW5Eb21bZG9tU3R5bGUuaWRdO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fTtcclxufVxyXG5cclxuZnVuY3Rpb24gYWRkU3R5bGVzVG9Eb20oc3R5bGVzLCBvcHRpb25zKSB7XHJcblx0Zm9yKHZhciBpID0gMDsgaSA8IHN0eWxlcy5sZW5ndGg7IGkrKykge1xyXG5cdFx0dmFyIGl0ZW0gPSBzdHlsZXNbaV07XHJcblx0XHR2YXIgZG9tU3R5bGUgPSBzdHlsZXNJbkRvbVtpdGVtLmlkXTtcclxuXHRcdGlmKGRvbVN0eWxlKSB7XHJcblx0XHRcdGRvbVN0eWxlLnJlZnMrKztcclxuXHRcdFx0Zm9yKHZhciBqID0gMDsgaiA8IGRvbVN0eWxlLnBhcnRzLmxlbmd0aDsgaisrKSB7XHJcblx0XHRcdFx0ZG9tU3R5bGUucGFydHNbal0oaXRlbS5wYXJ0c1tqXSk7XHJcblx0XHRcdH1cclxuXHRcdFx0Zm9yKDsgaiA8IGl0ZW0ucGFydHMubGVuZ3RoOyBqKyspIHtcclxuXHRcdFx0XHRkb21TdHlsZS5wYXJ0cy5wdXNoKGFkZFN0eWxlKGl0ZW0ucGFydHNbal0sIG9wdGlvbnMpKTtcclxuXHRcdFx0fVxyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0dmFyIHBhcnRzID0gW107XHJcblx0XHRcdGZvcih2YXIgaiA9IDA7IGogPCBpdGVtLnBhcnRzLmxlbmd0aDsgaisrKSB7XHJcblx0XHRcdFx0cGFydHMucHVzaChhZGRTdHlsZShpdGVtLnBhcnRzW2pdLCBvcHRpb25zKSk7XHJcblx0XHRcdH1cclxuXHRcdFx0c3R5bGVzSW5Eb21baXRlbS5pZF0gPSB7aWQ6IGl0ZW0uaWQsIHJlZnM6IDEsIHBhcnRzOiBwYXJ0c307XHJcblx0XHR9XHJcblx0fVxyXG59XHJcblxyXG5mdW5jdGlvbiBsaXN0VG9TdHlsZXMobGlzdCkge1xyXG5cdHZhciBzdHlsZXMgPSBbXTtcclxuXHR2YXIgbmV3U3R5bGVzID0ge307XHJcblx0Zm9yKHZhciBpID0gMDsgaSA8IGxpc3QubGVuZ3RoOyBpKyspIHtcclxuXHRcdHZhciBpdGVtID0gbGlzdFtpXTtcclxuXHRcdHZhciBpZCA9IGl0ZW1bMF07XHJcblx0XHR2YXIgY3NzID0gaXRlbVsxXTtcclxuXHRcdHZhciBtZWRpYSA9IGl0ZW1bMl07XHJcblx0XHR2YXIgc291cmNlTWFwID0gaXRlbVszXTtcclxuXHRcdHZhciBwYXJ0ID0ge2NzczogY3NzLCBtZWRpYTogbWVkaWEsIHNvdXJjZU1hcDogc291cmNlTWFwfTtcclxuXHRcdGlmKCFuZXdTdHlsZXNbaWRdKVxyXG5cdFx0XHRzdHlsZXMucHVzaChuZXdTdHlsZXNbaWRdID0ge2lkOiBpZCwgcGFydHM6IFtwYXJ0XX0pO1xyXG5cdFx0ZWxzZVxyXG5cdFx0XHRuZXdTdHlsZXNbaWRdLnBhcnRzLnB1c2gocGFydCk7XHJcblx0fVxyXG5cdHJldHVybiBzdHlsZXM7XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGNyZWF0ZVN0eWxlRWxlbWVudCgpIHtcclxuXHR2YXIgc3R5bGVFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInN0eWxlXCIpO1xyXG5cdHZhciBoZWFkID0gZ2V0SGVhZEVsZW1lbnQoKTtcclxuXHRzdHlsZUVsZW1lbnQudHlwZSA9IFwidGV4dC9jc3NcIjtcclxuXHRoZWFkLmFwcGVuZENoaWxkKHN0eWxlRWxlbWVudCk7XHJcblx0cmV0dXJuIHN0eWxlRWxlbWVudDtcclxufVxyXG5cclxuZnVuY3Rpb24gY3JlYXRlTGlua0VsZW1lbnQoKSB7XHJcblx0dmFyIGxpbmtFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImxpbmtcIik7XHJcblx0dmFyIGhlYWQgPSBnZXRIZWFkRWxlbWVudCgpO1xyXG5cdGxpbmtFbGVtZW50LnJlbCA9IFwic3R5bGVzaGVldFwiO1xyXG5cdGhlYWQuYXBwZW5kQ2hpbGQobGlua0VsZW1lbnQpO1xyXG5cdHJldHVybiBsaW5rRWxlbWVudDtcclxufVxyXG5cclxuZnVuY3Rpb24gYWRkU3R5bGUob2JqLCBvcHRpb25zKSB7XHJcblx0dmFyIHN0eWxlRWxlbWVudCwgdXBkYXRlLCByZW1vdmU7XHJcblxyXG5cdGlmIChvcHRpb25zLnNpbmdsZXRvbikge1xyXG5cdFx0dmFyIHN0eWxlSW5kZXggPSBzaW5nbGV0b25Db3VudGVyKys7XHJcblx0XHRzdHlsZUVsZW1lbnQgPSBzaW5nbGV0b25FbGVtZW50IHx8IChzaW5nbGV0b25FbGVtZW50ID0gY3JlYXRlU3R5bGVFbGVtZW50KCkpO1xyXG5cdFx0dXBkYXRlID0gYXBwbHlUb1NpbmdsZXRvblRhZy5iaW5kKG51bGwsIHN0eWxlRWxlbWVudCwgc3R5bGVJbmRleCwgZmFsc2UpO1xyXG5cdFx0cmVtb3ZlID0gYXBwbHlUb1NpbmdsZXRvblRhZy5iaW5kKG51bGwsIHN0eWxlRWxlbWVudCwgc3R5bGVJbmRleCwgdHJ1ZSk7XHJcblx0fSBlbHNlIGlmKG9iai5zb3VyY2VNYXAgJiZcclxuXHRcdHR5cGVvZiBVUkwgPT09IFwiZnVuY3Rpb25cIiAmJlxyXG5cdFx0dHlwZW9mIFVSTC5jcmVhdGVPYmplY3RVUkwgPT09IFwiZnVuY3Rpb25cIiAmJlxyXG5cdFx0dHlwZW9mIFVSTC5yZXZva2VPYmplY3RVUkwgPT09IFwiZnVuY3Rpb25cIiAmJlxyXG5cdFx0dHlwZW9mIEJsb2IgPT09IFwiZnVuY3Rpb25cIiAmJlxyXG5cdFx0dHlwZW9mIGJ0b2EgPT09IFwiZnVuY3Rpb25cIikge1xyXG5cdFx0c3R5bGVFbGVtZW50ID0gY3JlYXRlTGlua0VsZW1lbnQoKTtcclxuXHRcdHVwZGF0ZSA9IHVwZGF0ZUxpbmsuYmluZChudWxsLCBzdHlsZUVsZW1lbnQpO1xyXG5cdFx0cmVtb3ZlID0gZnVuY3Rpb24oKSB7XHJcblx0XHRcdHN0eWxlRWxlbWVudC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHN0eWxlRWxlbWVudCk7XHJcblx0XHRcdGlmKHN0eWxlRWxlbWVudC5ocmVmKVxyXG5cdFx0XHRcdFVSTC5yZXZva2VPYmplY3RVUkwoc3R5bGVFbGVtZW50LmhyZWYpO1xyXG5cdFx0fTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0c3R5bGVFbGVtZW50ID0gY3JlYXRlU3R5bGVFbGVtZW50KCk7XHJcblx0XHR1cGRhdGUgPSBhcHBseVRvVGFnLmJpbmQobnVsbCwgc3R5bGVFbGVtZW50KTtcclxuXHRcdHJlbW92ZSA9IGZ1bmN0aW9uKCkge1xyXG5cdFx0XHRzdHlsZUVsZW1lbnQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChzdHlsZUVsZW1lbnQpO1xyXG5cdFx0fTtcclxuXHR9XHJcblxyXG5cdHVwZGF0ZShvYmopO1xyXG5cclxuXHRyZXR1cm4gZnVuY3Rpb24gdXBkYXRlU3R5bGUobmV3T2JqKSB7XHJcblx0XHRpZihuZXdPYmopIHtcclxuXHRcdFx0aWYobmV3T2JqLmNzcyA9PT0gb2JqLmNzcyAmJiBuZXdPYmoubWVkaWEgPT09IG9iai5tZWRpYSAmJiBuZXdPYmouc291cmNlTWFwID09PSBvYmouc291cmNlTWFwKVxyXG5cdFx0XHRcdHJldHVybjtcclxuXHRcdFx0dXBkYXRlKG9iaiA9IG5ld09iaik7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRyZW1vdmUoKTtcclxuXHRcdH1cclxuXHR9O1xyXG59XHJcblxyXG52YXIgcmVwbGFjZVRleHQgPSAoZnVuY3Rpb24gKCkge1xyXG5cdHZhciB0ZXh0U3RvcmUgPSBbXTtcclxuXHJcblx0cmV0dXJuIGZ1bmN0aW9uIChpbmRleCwgcmVwbGFjZW1lbnQpIHtcclxuXHRcdHRleHRTdG9yZVtpbmRleF0gPSByZXBsYWNlbWVudDtcclxuXHRcdHJldHVybiB0ZXh0U3RvcmUuZmlsdGVyKEJvb2xlYW4pLmpvaW4oJ1xcbicpO1xyXG5cdH07XHJcbn0pKCk7XHJcblxyXG5mdW5jdGlvbiBhcHBseVRvU2luZ2xldG9uVGFnKHN0eWxlRWxlbWVudCwgaW5kZXgsIHJlbW92ZSwgb2JqKSB7XHJcblx0dmFyIGNzcyA9IHJlbW92ZSA/IFwiXCIgOiBvYmouY3NzO1xyXG5cclxuXHRpZiAoc3R5bGVFbGVtZW50LnN0eWxlU2hlZXQpIHtcclxuXHRcdHN0eWxlRWxlbWVudC5zdHlsZVNoZWV0LmNzc1RleHQgPSByZXBsYWNlVGV4dChpbmRleCwgY3NzKTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0dmFyIGNzc05vZGUgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShjc3MpO1xyXG5cdFx0dmFyIGNoaWxkTm9kZXMgPSBzdHlsZUVsZW1lbnQuY2hpbGROb2RlcztcclxuXHRcdGlmIChjaGlsZE5vZGVzW2luZGV4XSkgc3R5bGVFbGVtZW50LnJlbW92ZUNoaWxkKGNoaWxkTm9kZXNbaW5kZXhdKTtcclxuXHRcdGlmIChjaGlsZE5vZGVzLmxlbmd0aCkge1xyXG5cdFx0XHRzdHlsZUVsZW1lbnQuaW5zZXJ0QmVmb3JlKGNzc05vZGUsIGNoaWxkTm9kZXNbaW5kZXhdKTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdHN0eWxlRWxlbWVudC5hcHBlbmRDaGlsZChjc3NOb2RlKTtcclxuXHRcdH1cclxuXHR9XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGFwcGx5VG9UYWcoc3R5bGVFbGVtZW50LCBvYmopIHtcclxuXHR2YXIgY3NzID0gb2JqLmNzcztcclxuXHR2YXIgbWVkaWEgPSBvYmoubWVkaWE7XHJcblx0dmFyIHNvdXJjZU1hcCA9IG9iai5zb3VyY2VNYXA7XHJcblxyXG5cdGlmKG1lZGlhKSB7XHJcblx0XHRzdHlsZUVsZW1lbnQuc2V0QXR0cmlidXRlKFwibWVkaWFcIiwgbWVkaWEpXHJcblx0fVxyXG5cclxuXHRpZihzdHlsZUVsZW1lbnQuc3R5bGVTaGVldCkge1xyXG5cdFx0c3R5bGVFbGVtZW50LnN0eWxlU2hlZXQuY3NzVGV4dCA9IGNzcztcclxuXHR9IGVsc2Uge1xyXG5cdFx0d2hpbGUoc3R5bGVFbGVtZW50LmZpcnN0Q2hpbGQpIHtcclxuXHRcdFx0c3R5bGVFbGVtZW50LnJlbW92ZUNoaWxkKHN0eWxlRWxlbWVudC5maXJzdENoaWxkKTtcclxuXHRcdH1cclxuXHRcdHN0eWxlRWxlbWVudC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShjc3MpKTtcclxuXHR9XHJcbn1cclxuXHJcbmZ1bmN0aW9uIHVwZGF0ZUxpbmsobGlua0VsZW1lbnQsIG9iaikge1xyXG5cdHZhciBjc3MgPSBvYmouY3NzO1xyXG5cdHZhciBtZWRpYSA9IG9iai5tZWRpYTtcclxuXHR2YXIgc291cmNlTWFwID0gb2JqLnNvdXJjZU1hcDtcclxuXHJcblx0aWYoc291cmNlTWFwKSB7XHJcblx0XHQvLyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8yNjYwMzg3NVxyXG5cdFx0Y3NzICs9IFwiXFxuLyojIHNvdXJjZU1hcHBpbmdVUkw9ZGF0YTphcHBsaWNhdGlvbi9qc29uO2Jhc2U2NCxcIiArIGJ0b2EodW5lc2NhcGUoZW5jb2RlVVJJQ29tcG9uZW50KEpTT04uc3RyaW5naWZ5KHNvdXJjZU1hcCkpKSkgKyBcIiAqL1wiO1xyXG5cdH1cclxuXHJcblx0dmFyIGJsb2IgPSBuZXcgQmxvYihbY3NzXSwgeyB0eXBlOiBcInRleHQvY3NzXCIgfSk7XHJcblxyXG5cdHZhciBvbGRTcmMgPSBsaW5rRWxlbWVudC5ocmVmO1xyXG5cclxuXHRsaW5rRWxlbWVudC5ocmVmID0gVVJMLmNyZWF0ZU9iamVjdFVSTChibG9iKTtcclxuXHJcblx0aWYob2xkU3JjKVxyXG5cdFx0VVJMLnJldm9rZU9iamVjdFVSTChvbGRTcmMpO1xyXG59XHJcblxuXG5cbi8qKioqKioqKioqKioqKioqKlxuICoqIFdFQlBBQ0sgRk9PVEVSXG4gKiogLi9+L3N0eWxlLWxvYWRlci9hZGRTdHlsZXMuanNcbiAqKiBtb2R1bGUgaWQgPSA0XG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iLCIvKiBcbiAqIFRoZSBNSVQgTGljZW5zZVxuICpcbiAqIENvcHlyaWdodCAyMDE1IEplcm9tZSBEYW5lIDxqZXJvbWVkYW5lLmNvbT4uXG4gKlxuICogUGVybWlzc2lvbiBpcyBoZXJlYnkgZ3JhbnRlZCwgZnJlZSBvZiBjaGFyZ2UsIHRvIGFueSBwZXJzb24gb2J0YWluaW5nIGEgY29weVxuICogb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxuICogaW4gdGhlIFNvZnR3YXJlIHdpdGhvdXQgcmVzdHJpY3Rpb24sIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0c1xuICogdG8gdXNlLCBjb3B5LCBtb2RpZnksIG1lcmdlLCBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbFxuICogY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXG4gKiBmdXJuaXNoZWQgdG8gZG8gc28sIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuICpcbiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkIGluXG4gKiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAqXG4gKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTIE9SXG4gKiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSxcbiAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxuICogQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSwgREFNQUdFUyBPUiBPVEhFUlxuICogTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUiBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSxcbiAqIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cbiAqIFRIRSBTT0ZUV0FSRS5cbiAqL1xuXG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oZWxlbWVudCkge1xuXHRcblx0dmFyIGNsaWNrRXZlbnQ7XG5cdGNsaWNrRXZlbnQgPSBkb2N1bWVudC5jcmVhdGVFdmVudChcIk1vdXNlRXZlbnRzXCIpO1xuXHRjbGlja0V2ZW50LmluaXRFdmVudChcIm1vdXNlZG93blwiLCB0cnVlLCB0cnVlKTtcblx0ZWxlbWVudC5kaXNwYXRjaEV2ZW50KGNsaWNrRXZlbnQpO1xuXG5cdGNsaWNrRXZlbnQgPSBkb2N1bWVudC5jcmVhdGVFdmVudChcIk1vdXNlRXZlbnRzXCIpO1xuXHRjbGlja0V2ZW50LmluaXRFdmVudChcImNsaWNrXCIsIHRydWUsIHRydWUpO1xuXHRlbGVtZW50LmRpc3BhdGNoRXZlbnQoY2xpY2tFdmVudCk7XG5cblx0Y2xpY2tFdmVudCA9IGRvY3VtZW50LmNyZWF0ZUV2ZW50KFwiTW91c2VFdmVudHNcIik7XG5cdGNsaWNrRXZlbnQuaW5pdEV2ZW50KFwibW91c2V1cFwiLCB0cnVlLCB0cnVlKTtcblx0ZWxlbWVudC5kaXNwYXRjaEV2ZW50KGNsaWNrRXZlbnQpO1xufTtcblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIC4vfi9zaW11bGF0ZS1jbGljay1qcy9zcmMvc2ltdWxhdGUtY2xpY2suanNcbiAqKiBtb2R1bGUgaWQgPSA1XG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iLCJtb2R1bGUuZXhwb3J0cyA9IFwiZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFCQUFBQUFRQ0FZQUFBQWY4LzloQUFBQUJITkNTVlFJQ0FnSWZBaGtpQUFBQUFsd1NGbHpBQUFOMXdBQURkY0JRaWliZUFBQUFCbDBSVmgwVTI5bWRIZGhjbVVBZDNkM0xtbHVhM05qWVhCbExtOXlaNXZ1UEJvQUFBRk5TVVJCVkRpTnBkT3hhbFJSRUFiZzcxN0ZaQnVmd2lLQ2dsbmZJQ0RwWkN1N1BNYkNXcDA5Tmw3UXQ3RFRackV6QWQ4Z1dTRUJMWHlQMVVLdXhmMXZ1QWFzZG1BNE1QUFBuSC8rTTZmcCs5N1VhcTFIT01NY3h3bHZjWVVQcFpRZlUzd3pOcWkxM3NNU2F4d2t2OHM1eS9rYkJlOUxLWCtnblJTZjR5MGF2QW1EaC9GNVlnMDZuS2ZHL1hSZTRnVGY4YXFVY3VOZjIySmJhLzJFajhFdTBUWHI5Zm9JMzlMOU9YNWloYTZVOGlzTUQ4Y1lIdUVTUFo2MUVld2dCVGNCRm14cXJZY3AzaVMyQ3FaTHpWbWIrUVFreVM4NHhlZjRhV0xkSGV5OE5UelZEdGNRMmd0YzRFWDhBb3R4cEdCM09HN3RhYTFCNFJtZWNpdllabkx6eUdTVG5HQm4yTGFHRFJQYURDS09NNytNajVxczdtQ3Y5bjdHcHU5N3RkYVZZUXYvdDBqUzZJbGhrUjdqZFNtbEd6ZnhYZVk4d1dXdHRZc08xNU9aRjJIeEFGOVRzLzluYXZiOXpuOEJDbm1VN2VrQWRaTUFBQUFBU1VWT1JLNUNZSUk9XCJcblxuXG4vKioqKioqKioqKioqKioqKipcbiAqKiBXRUJQQUNLIEZPT1RFUlxuICoqIC4vc3JjL2ltYWdlcy9jbG9zZV8xNl9yOC5wbmdcbiAqKiBtb2R1bGUgaWQgPSA2XG4gKiogbW9kdWxlIGNodW5rcyA9IDBcbiAqKi8iXSwic291cmNlUm9vdCI6IiJ9