您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds an option to add and review your own custom vocabulary
当前为
// ==UserScript== // @name Wanikani Self-Study Plus // @namespace wkselfstudyplus // @description Adds an option to add and review your own custom vocabulary // @include *.wanikani.com/* // @include *.wanikani.com/chat/* // @exclude *.wanikani.com // @include *.wanikani.com/dashboard* // @include *.wanikani.com/community* // @version 0.2.0 // @author shudouken and Ethan // @run-at document-end // @grant none // ==/UserScript== /* * This script is licensed under the Creative Commons License * "Attribution-NonCommercial 3.0 Unported" * * More information at: * http://creativecommons.org/licenses/by-nc/3.0/ */ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ var buildNode = require('./buildnode.js'); // Create DOM for 'add' window var addElement = buildNode('div', {id: "add", className: "WKSS"}); var formElement = buildNode('form', {id: "addForm"}); addElement.appendChild(formElement); var buttonElement = buildNode('button', {id: "AddCloseBtn", className: "wkss-close", type: "reset"}); formElement.appendChild(buttonElement); var iconElement = buildNode('i', {className: "icon-remove"}); buttonElement.appendChild(iconElement); var headerElement = buildNode('h1'); formElement.appendChild(headerElement); var headerText = document.createTextNode("Add a new Item"); headerElement.appendChild(headerText); var inputKanjiElement = buildNode('input', {id: "addKanji", type: "text", placeholder: "Enter 漢字, ひらがな or カタカナ"}); formElement.appendChild(inputKanjiElement); var inputReadingElement = buildNode('input', {id: "addReading", type: "text", title: "Leave empty to add vocabulary like する (to do)", placeholder: "Enter reading"}); formElement.appendChild(inputReadingElement); var inputMeaningElement = buildNode('input', {id: "addMeaning", type: "text", placeholder: "Enter meaning"}); formElement.appendChild(inputMeaningElement); var pElement = buildNode('p', {id: "addStatus"}); formElement.appendChild(pElement); var pText = document.createTextNode("Ready to add.."); pElement.appendChild(pText); var execButtonElement = buildNode('button', {id: "AddItemBtn", type: "button"}); formElement.appendChild(execButtonElement); var execText = document.createTextNode("Add new Item"); execButtonElement.appendChild(execText); module.exports = addElement; },{"./buildnode.js":2}],2:[function(require,module,exports){ /** Builds a node element with an id and className and other attributes if provided * @param {string} type - The type of element to create ('div', 'p', etc...) * @param {object} [options] * @param {string} options.id - The id of the node * @param {string} options.className - One or more classes for the element seperated by spaces * @returns {HTMLElement} The node built as specified */ var buildNode = function(type, options){ var node = document.createElement(type); for (var option in options) if (options.hasOwnProperty(option)) { if (option === "className" || option === "id"){ node[option] = options[option]; } else { node.setAttribute(option, options[option]); } } return node; }; module.exports = buildNode; },{}],3:[function(require,module,exports){ var buildNode = require('./buildnode.js'); // tag, id, className, other, childNodes /* IWindow: { id: "WKSS-edit", className: "WKSS", childNodes:[{ tag: 'form', id: "WKSS-editForm", childNodes:[{ tag: 'button', id: "WKSS-editCloseBtn", className: "WKSS-close" childNodes:[{ tag: 'i', className: "icon-remove" }] },{ tag: 'h1', childNodes:[ "Edit your Vocab" <--- string types for text node ] },{ tag: 'select', id: "editWindow", other: {size: "8"} <--- 'other' avoids clashes with HTMLElement attributes just in case },{ tag: 'input', other:{ type: "text", name: "", size: "40", placeholder: "Select vocab, click edit, change and save!" }, id: "editItem" },{ tag: 'p', id: "editStatus" childNodes:["Ready to edit..."] },{ tag: 'button', id: "EditEditBtn", other: {type: "button"}, childNodes:["Edit"] },{ tag: 'button', id: "EditSaveBtn", other:{type: "button"}, childNodes:["Save"] },{ tag: 'button', id: "EditDeleteBtn", other: {type: "button", title: "Delete selected item"}, childNodes:["Delete"] },{ tag: 'button', id: "EditDeleteAllBtn", other: {type: "button", title: "本当にやるの?"}, childNodes:["Delete All"] },{ tag: 'button', id: "ResetLevelsBtn", other: {type: "button"}, childNodes:["Reset levels"] }] }] } */ var struct = { id: "WKSS-edit", className: "WKSS", childNodes:[{ tag: 'form', id: "WKSS-editForm", childNodes:[{ tag: 'button', id: "WKSS-editCloseBtn", className: "WKSS-close", childNodes:[{ tag: 'i', className: "icon-remove" }] },{ tag: 'h1', childNodes:["Edit your Vocab"] },{ tag: 'select', id: "editWindow", other: {size: "8"} },{ tag: 'input', other:{ type: "text", name: "", size: "40", placeholder: "Select vocab, click edit, change and save!" }, id: "editItem" },{ tag: 'p', id: "editStatus", childNodes:["Ready to edit..."] },{ tag: 'button', id: "EditEditBtn", other: {type: "button"}, childNodes:["Edit"] },{ tag: 'button', id: "EditSaveBtn", other:{type: "button"}, childNodes:["Save"] },{ tag: 'button', id: "EditDeleteBtn", other: {type: "button", title: "Delete selected item"}, childNodes:["Delete"] },{ tag: 'button', id: "EditDeleteAllBtn", other: {type: "button", title: "本当にやるの?"}, childNodes:["Delete All"] },{ tag: 'button', id: "ResetLevelsBtn", other: {type: "button"}, childNodes:["Reset levels"] }] }] }; // 'this' context is node to attach to var attachChildNode = function(childNode){ var el; if ("string" === typeof childNode){ //TextNode el = document.createTextNode(childNode); } else{ el = buildNode(childNode.tag, {id: childNode.id, className: childNode.className}); for (var attr in childNode.other){ el.setAttribute(attr, childNode.other[attr]); } if (childNode.childNodes){ childNode.childNodes.forEach(attachChildNode, el); } } this.appendChild(el); }; /** Takes a JSON object with the structure of the window to create and builds a DIVElement from that * @param {IWindow} windowStructure * @returns {DIVElement} The specified window. */ var buildWindow = function(windowStructure) { var resultWindow = buildNode('div', {id: windowStructure.id, className: windowStructure.className}); for (var attr in windowStructure.other){ resultWindow.setAttribute(attr, windowStructure.other[attr]); } if (windowStructure.childNodes){ windowStructure.childNodes.forEach(attachChildNode, resultWindow); } return resultWindow; }; /* { var editForm = buildNode('form', {id: "WKSS-editForm"}); editWindow.appendChild(editForm); var editCloseButton = buildNode('button', {id: "WKSS-editCloseBtn", className: "WKSS-close"}); editForm.appendChild(editCloseButton); editCloseButton.appendChild(buildNode('i', {className: "icon-remove"})); var h1Element = buildNode('h1'); editForm.appendChild(h1Element); h1Element.appendChild(document.createTextNode("Edit your Vocab")); var selectElement = buildNode('select', {id: "editWindow", size: "8"}); editForm.appendChild(selectElement); var editItemText = buildNode('input', {type: "text" id: "editItem" name: "" size: "40" placeholder: "Select vocab, click edit, change and save!"}); editForm.appendChild(editItemText);//.. var editStatus = buildNode('p', {id: "editStatus"}); editForm.appendChild(editStatus); editStatus.appendChild(document.createTextNode("Ready to edit..")); var editButton = buildNode('button', {id: "EditEditBtn", type: "button"}); editForm.appendChild(editButton); editButton.appendChild(document.createTextNode("Edit")); var editSave = buildNode('button', {id: "EditSaveBtn", type: "button"}); editForm.appendChild(editSave); editSave.appendChild(document.createTextNode("Save")); var editDelete = buildNode('button', {id: "EditDeleteBtn", type: "button", title: "Delete selected item"}); editForm.appendChild(editDelete); editDelete.appendChild(document.createTextNode("Delete")); var editDeleteAll = buildNode('button', {id: "EditDeleteAllBtn", type: "button", title: "本当にやるの?"}); editForm.appendChild(editDeleteAll); editDeleteAll.appendChild(document.createTextNode("Delete All")); var editResetLevels = buildNode('button', {id: "ResetLevelsBtn", type: "button"}); editForm.appendChild(editResetLevels); editResetLevels.appendChild(document.createTextNode("Reset levels")); return editWindow; };*/ module.exports = buildWindow; },{"./buildnode.js":2}],4:[function(require,module,exports){ module.exports = function(){ var kanji = $("#addKanji").val().toLowerCase(); var reading = $("#addReading").val().toLowerCase().split(/[,、]+\s*/); //split at , or 、followed by 0 or any number of spaces var meaning = $("#addMeaning").val().toLowerCase().split(/[,、]+\s*/); var success = false; //initalise values var meanlen = 0; var i = meaning.length; while (i--){ meanlen += meaning[i].length; } //input is invalid: prompt user for valid input var item = {}; if (kanji.length === 0 || meanlen === 0) { $("#addStatus").text("One or more required fields are empty!"); if (kanji.length === 0) { $("#addKanji").addClass("error"); } else { $("#addKanji").removeClass("error"); } if (meanlen === 0) { $("#addMeaning").addClass("error"); } else { $("#addMeaning").removeClass("error"); } } else { if (debugging) {console.log("building item: "+kanji);} item.kanji = kanji; item.reading = reading; //optional item.meaning = meaning; success = true; if (debugging) {console.log("item is valid");} } //on successful creation of item if (success) { //clear error layout to required fields $("#addKanji").removeClass("error"); $("#addMeaning").removeClass("error"); //if there are already user items, retrieve vocabList // var vocabList = []; var vocabList = getFullList(); if (debugging) {console.log("vocabList retrieved, length: "+vocabList.length);} //check stored user items for duplicates ****************** to do: option for editing duplicate item with new input if(checkForDuplicates(vocabList,item)) { $("#addStatus").text("Duplicate Item detected!"); $("#addKanji").addClass("error"); return; } setVocItem(item); if (debugging) {console.log("clear form");} $("#addForm")[0].reset(); //-------------------------------------------------------------------------------------------------------- if (item.manualLock === "yes" || item.manualLock === "DB" && lockDB){ $("#addStatus").html("<i class=\"icon-lock\"></i> Added locked item"); } else { $("#addStatus").html("<i class=\"icon-unlock\"></i>Added successfully"); } //-------------------------------------------------------------------------------------------------------- } }; },{}],5:[function(require,module,exports){ module.exports = function(){ // {"level":"17","meaning_explanation":"This word consists of kanji with hiragana attached. Because the hiragana ends with an [ja]う[/ja] sound, you know this word is a verb. The kanji itself means [kanji]flourish[/kanji] or [kanji]prosperity[/kanji], so the verb vocab versions of these would be [vocabulary]to flourish[/vocabulary] or [vocabulary]to prosper[/vocabulary].","reading_explanation":"Since this word consists of a kanji with hiragana attached, you can bet that it will use the kun'yomi reading. You didn't learn that reading with this kanji, so here's a mnemonic to help you: What do you flourish at? You're an amazing [vocabulary]soccer[/vocabulary] ([ja]さか[/ja]) player who flourishes and prospers no matter where you go to play this wonderful (but not as good as baseball) sport.","en":"To Flourish, To Prosper","kana":"さかえる","sentences":[["中国には、覚せい剤の生産で栄えていた村がありました。","There was a village in China flourishing on their production of stimulants. "]],"parts_of_speech_ids":["4","19"],"part_of_speech":"Intransitive Verb, Ichidan Verb","audio":"2e194cbf194371cd478480d6ea67769da623e99a.mp3","meaning_note":null,"reading_note":null,"related":[{"kan":"栄","en":"Prosperity, Flourish","slug":"栄"}]} if (typeof $.mockjax === "function"){ $.mockjax({ url: /^\/json\/progress\?vWKSS(.+)\[\]=(.+)&vWKSS.+\[\]=(.+)$/, urlParams:["WKSSid", "MeaningWrong", "ReadingWrong"], response: function(settings) { // do any required cleanup var id = Number(settings.urlParams.WKSSid); var Mw = Number(settings.urlParams.MeaningWrong); var Rw = Number(settings.urlParams.ReadingWrong); var UserVocab = localGet("User-Vocab")||[]; console.log("is this your card?", UserVocab[id]); if (UserVocab[id].due < Date.now()){//double check that item was due for review if (Mw||Rw){ //drop levels if wrong //Adapted from WaniKani's srs to authentically mimic level downs var o = (Mw||0)+(Rw||0); var t = UserVocab[id].level; var r=t>=5?2*Math.round(o/2):1*Math.round(o/2); var n=t-r<1?1:t-r;//don't stay on 'started' UserVocab[id].level = n; }else{ //increase level if none wrong UserVocab[id].level++; } //Put UserVocab back in storage UserVocab[id].date = Date.now(); UserVocab[id].due = Date.now() + srsintervals[UserVocab[id].level]; localSet("User-Vocab", UserVocab); console.log(UserVocab[id].due +" > "+ Date.now() + " (" + ms2str(UserVocab[id].due - Date.now())+")"); }else{ console.log("This item is not due for review yet, discarding results"); } this.responseText = '{"vWKSS'+id.toString()+'":["'+Mw.toString()+'","'+Rw.toString()+'"]}'; } }); $.mockjax({ url: /^\/json\/vocabulary\/WKSS(.+)/, urlParams:["WKSSid"], response: function(settings) { // Investigate the `settings` to determine the response... var id = settings.urlParams.WKSSid.toString(); var currentItem = $.jStorage.get("currentItem"); if (currentItem.id === "WKSS"+id){ console.log("as expected"); } var related = '['; for (i = 0; i < currentItem.components.length; i++){ related += '{"kan":"'+currentItem.components[i]+'","en":"","slug":"'+currentItem.components[i]+'"}'; related += (i+1<currentItem.components.length)?',':''; } related += ']'; var respText = JSON.stringify({ level: "U", meaning_explanation: "This is user-defined item. Meaning explanations are not supported at this time. [id: "+id+"]", reading_explanation: "This is user-defined item. Reading explanations are not supported at this time. [id: "+id+"]", en: currentItem.en.join(", "), kana: currentItem.kana.join(", "), sentences:[], parts_of_speech_ids:[], part_of_speech:[], audio:null, meaning_note:null, reading_note:null, related:JSON.parse(related) }); this.responseText = respText; }, onAfterComplete: function() { // do any required cleanup $(".user-synonyms").remove(); // keeping the hooks for Community Mnemonics $("#note-meaning, #note-reading").html(""); } }); } }; //--------------End Insert Into WK Review Functions-------------- },{}],6:[function(require,module,exports){ var ImportUtil = { fileUpload: function(ev){ var csvHeader = true; //first row contains stuff like "Kanji/Vocab, Reading, Meaning" etc var tsvfile; //tabs separate fields, commas seperate values? or false for vice versa var CSVs = ev.target.files; var name =CSVs[0].name; var colsplit, vsplit; if (name.substr(name.lastIndexOf("."),4)===".csv"){ tsvfile = false; colsplit = ","; vsplit = "\t"; }else{ tsvfile = true; colsplit = "\t"; vsplit = ","; } if (debugging) { console.log("tsvfile: "); } if (debugging) { console.log("file uploaded: "+CSVs[0].name); } var reader = new FileReader(); reader.readAsText(CSVs[0]); reader.onload = function(ev){ var csvString = ev.target.result; var csvRow = csvString.split("\n"); //default column rows var k = 0; var r = 1; var m = 2; var i = csvRow.length; //process header, changing k,r,m if necessary var JSONimport = []; while(i--){ var row = csvRow[i]; if ((csvHeader === true && i === 0)|| // Skip header (row === "") // Skip empty rows ){ if (debugging) { console.log("Skipping row #"+i); } }else{ console.log(row); var elem = row.split(colsplit); var item = {}; var c; if (elem[k]){ item.kanji = elem[k].trim(); if (elem[r]){ if (elem[r].indexOf(vsplit)>-1){ // eg 'reading 1[tab]reading 2[tab]reading 3' item.reading = elem[r].split(vsplit); }else{ //no tabs in string, single value item.reading=[elem[r]]; } }else{ item.reading=[""]; } if (elem[m]){ if (elem[m].indexOf(vsplit)>-1){ // eg 'meaning 1[tab]meaning 2[tab]meaning 3' item.meaning = elem[m].split("\t"); }else{ //no tabs in string, single value item.meaning=[elem[m]]; } c = item.meaning.length; while(c--){ console.log("item.meaning["+c+"]: "+item.meaning[c]); } }else{//todo: provide overwrite option on forced meaning item.meaning=[""]; } JSONimport.push(item); }else{ // corrupt row ('kanji' is mandatory (can be kana-only word), is not present on row, skip } } } var JSONstring = JSON.stringify(JSONimport); console.log(JSONimport); if (JSONstring.length !== 0) { try { var add = JSON.parse(JSONstring.toLowerCase()); /*//---------/------------- if (!checkAdd(add)) { $("#importStatus").text("No valid input (duplicates?)!"); return; } //----------------------*/ var a = add.length; while(a--){ StorageUtil.setVocItem(add[a]); } $("#importStatus").text("Import successful!"); $("#importForm")[0].reset(); $("#importArea").text(""); } catch (e) { $("#importStatus").text("Parsing Error!"); console.log(e); } } else { $("#importStatus").text("Nothing to import :( Please paste your stuff first"); } }; } }; module.exports = ImportUtil; },{}],7:[function(require,module,exports){ var StorageUtil = { /** Initialise User-Vocab */ initStorage: function(){ if (!localGet("User-Vocab")){ localSet("User-Vocab", []); } }, /** */ localGet: function(strName){ var strObj = localStorage.getItem(strName); return parseString(strObj); }, /** Sets strings and objects into browser storage * @requires localStorage * @requires JSON */ localSet: function(strName, obj){ localStorage.setItem(strName, typeof obj === "string"? obj : JSON.stringify(obj)); }, /** */ sessionGet: function(strName){ var strObj = sessionStorage.getItem(strName); return parseString(strObj); }, /** Sets strings and objects into browser session storage * @requires localStorage * @requires JSON */ sessionSet: function(strName, obj){ sessionStorage.setItem(strName, typeof obj === "string"? obj : JSON.stringify(obj)); }, /** */ getVocList: function(){ var vocList = JSON.parse(localStorage.getItem('User-Vocab'))||[]; if (vocList){ var v=vocList.length; while(v--){ vocList[v].i = v; //set index for item (->out) } } return vocList; }, setVocList: function(vocList){ this.localSet('User-Vocab', vocList); }, /** */ setVocItem: function(item){ //Assumption: item comes only with kanji, reading and meaning item.level = 0; item.date = Date.now(); item.manualLock = ""; item = setLocks(item); //0.1.9 adding in 'due' property to make review building simpler item.due = item.date + srsObject[item.level].duration; var vocList = localGet('User-Vocab')||[]; var found = vocList.find(function(task){ return task.kanji === item.kanji; }, this); //add meaning and reading to existing item // vocList[v].meaning = item.meaning; // vocList[v].reading = item.reading; if (!found) { //provide index for faster searches console.log(item.kanji +" not found in vocablist, adding now"); item.i = vocList.length; vocList.push(item); localSet('User-Vocab',vocList); } } }; module.exports = StorageUtil; },{}],8:[function(require,module,exports){ /* This is the original code that I am breaking into bite size bits */ //NEED TO MAKE SURE BROWSERIFY PUTS THIS ON THE TOP // ==UserScript== // @name Wanikani Self-Study Plus // @namespace wkselfstudyplus // @description Adds an option to add and review your own custom vocabulary // @include *.wanikani.com/* // @include *.wanikani.com/chat/* // @exclude *.wanikani.com // @include *.wanikani.com/dashboard* // @include *.wanikani.com/community* // @version 0.2.0 // @author shudouken and Ethan // @run-at document-end // @grant none // ==/UserScript== /* * This script is licensed under the Creative Commons License * "Attribution-NonCommercial 3.0 Unported" * * More information at: * http://creativecommons.org/licenses/by-nc/3.0/ */ /** Describes any object that can be reviewed or learned, includes IRadical, IKanji, and IVocabulary * @typedef {Object} Task * @property {boolean|string} locked - locked * @property {boolean|string} manualLock - manualLock */ var StorageUtil = require('./storageutil.js'); var ImportUtil = require('./importutil.js'); var WanikaniUtil = require('./wanikaniutil.js'); function main(){ "use strict"; $("head").prepend("<script src='https://cdn.jsdelivr.net/jquery.mockjax/1.6.1/jquery.mockjax.js'></script>"); var APIkey = "YOUR_API_HERE"; var locksOn = true; //Disable vocab locks (unlocked items persist until deleted) var lockDB = true; //Set to false to unlock Kanji is not available on WaniKani (ie. not returned by API) var reverse = true; //Include English to ひらがな reading reviews var debugging = true; var asWK = true; //Push user reviews into the main WK review queue // shut up JSHint /* jshint multistr: true , jquery: true, expr: true, indent:2 */ /* global window, wanakana, XDomainRequest */ /** Debugging */ console.log = debugging ? function (msg) { if (typeof msg === 'string') { window.console.log("WKSS: " + msg); } else { window.console.log("WKSS: ", msg); } } : function () { }; $("head").prepend('<script src="https://rawgit.com/WaniKani/WanaKana/master/lib/wanakana.js" type="text/javascript"></script>'); var localSet = function(strName, obj){ debugging&&console.log(strName + " is of type " + typeof obj); if (typeof obj === "object") obj=JSON.stringify(obj); localStorage.setItem(strName, obj); }; //track versions & datatypes localSet("WKSSdata", { v: "0.1.13", propertyType: { meaning: "array", reading: "array", kanji: "string", i:"number", components: "array", date: "number", due: "number", locked: "string", manualLock: "string" }, propertyDesc: { meaning: "list of meanings", reading: "list of readings", kanji: "item prompt", i:"item index", components: "kanji found in word", date: "timestamp of new level", due: "timestamp of item's next review", locked: "indicator of whether components are eligible", manualLock: "latch for 'locked' so failing components don't re-lock the item" } }); /** Settings and constants */ var errorAllowance = 4; //every x letters, you can make one mistake when entering the meaning //srs 4h, 8h, 24h, 3d (guru), 1w, 2w (master), 1m (enlightened), 4m (burned) var hrs = 60*60*1000; var days = 24*hrs; var weeks = 7*days; var srsObject = [ {level: 0, rank: "Started", duration: 0}, {level: 1, rank: "Apprentice", duration: 4*hrs}, {level: 2, rank: "Apprentice", duration: 8*hrs}, {level: 3, rank: "Apprentice", duration: 1*days}, {level: 4, rank: "Apprentice", duration: 3*days}, {level: 5, rank: "Guru", duration: 1*weeks}, {level: 6, rank: "Guru", duration: 2*weeks}, {level: 7, rank: "Master", duration: 730*hrs}, {level: 8, rank: "Enlightened", duration: 2922*hrs}, {level: 9, rank: "Burned"} ]; var parseString = function(strObj){ //avoids duplication of code for sesssionGet and localGet var obj; try { obj = JSON.parse(strObj); debugging&&console.log("Variable is of type " + typeof obj); } catch(e){ if (e.name === "SyntaxError"){ debugging&&console.log(strObj + " is an ordinary string that cannot be parsed."); obj = strObj; } else{ console.error("Could not parse " + strObj + ". Error: ", e); } } return obj; }; var localGet = function(strName){ var strObj = localStorage.getItem(strName); return parseString(strObj); }; // Initialise User-Vocab StorageUtil.initStorage(); //GM_addStyle shim for compatibility with greasemonkey var gM_addStyle = function(CssString){ //get DOM head var head = document.getElementsByTagName('head')[0]; if (head) { //build style tag var style = document.createElement('style'); style.setAttribute('type', 'text/css'); style.textContent = CssString; //insert DOM style into head head.appendChild(style); } }; /** JQuery fixes */ $("[placeholder]").focus(function () { var input = $(this); if (input.val() == input.attr("placeholder")) { input.val("''"); input.removeClass("'placeholder'"); } }).blur(function () { var input = $(this); if (input.val() == "''" || input.val() == input.attr("placeholder")) { input.addClass("placeholder"); input.val(input.attr("placeholder")); } }).blur(); $("[placeholder]").parents("form").submit(function () { $(this).find("[placeholder]").each(function () { var input = $(this); if (input.val() == input.attr("placeholder")) { input.val(""); } }); }); /** Handle the users API key. * @param {string} APIkey - the users API key to set. If given "YOUR_API_HERE", it will return the key in browser storage. * @returns {string} the users API key as supplied and stored, or in the case of "YOUR_API_HERE" being passed, the stored key. */ var getSetApi = function(APIkey){ var storedAPI = localStorage.getItem('WaniKani-API'); if (APIkey === "YOUR_API_HERE"){ if (storedAPI !== null){ APIkey = storedAPI; } } else{ //API has been set in code. if (storedAPI !== APIkey){ localSet('WaniKani-API', APIkey);//overwrite with new API } } return APIkey; }; APIkey = getSetApi(APIkey); //--------------Start Insert Into WK Review Functions-------------- /** Messing around with vanilla WaniKani review variables */ var joinReviews = function(WKItems){ console.log("joining reviews"); $.jStorage.stopListening("reviewQueue", joinReviews); var WKreview = $.jStorage.get("reviewQueue")||[]; var WKcombined = WKreview.concat(WKItems); $.jStorage.set("reviewQueue", WKcombined); }; var WKItems = []; console.groupCollapsed("Loading Items"); var wKSS_to_WK = function(WKSSItem){ var WKItem = {}; // WKItem.aud = ""; WKItem.en = WKSSItem.meaning.map(function(s) { //trim whitespace and capitalize words return s.trim().replace(/\b\w/g , function(m){ return m.toUpperCase(); }); }); WKItem.id = "WKSS" + WKSSItem.i; WKItem.kana = WKSSItem.reading; WKItem.srs = WKSSItem.level+1;//WK starts levels from 1, WKSS starts them from 0 WKItem.voc = WKSSItem.kanji; WKItem.components = WKSSItem.components; WKItem.syn = []; //Add synonyms of strings without bracketed info to get around checking the full string including brackets WKSSItem.meaning.forEach(function(meaning){ var openBracket = meaning.indexOf("("); if (openBracket !== -1 && meaning.indexOf(")") !== -1){ WKItem.syn.push(meaning.substr(0, openBracket).trim().replace(/\b\w/g , function(m){ return m.toUpperCase();})); } }, this); return WKItem; }; var loadTasks = function(userVocab, i, userVocabs){ var dueNow = (userVocab.locked === "no" && userVocab.level < 9 && Date.now() > userVocab.due); if (dueNow){ if (userVocab.kanji.length * userVocab.meaning[0].length * userVocab.reading[0].length){ //Sorry, we need all three to add to WK review, no kana only without readings etc. debugging&&console.log("item:" + userVocab.kanji + ", " + userVocab.locked +" === \"no\" && " + userVocab.level + " < 9 && " + Date.now() + " > " + userVocab.due); debugging&&console.log(dueNow); WKItems.push(wKSS_to_WK(userVocab)); }else{ debugging&&console.log("Item " + userVocab.kanji + " could not be added, it is missing one or more of the essential fields for a WK vocabulary review"); } } }; var userVocabs = localGet("User-Vocab")||[]; userVocabs.forEach(loadTasks);//, this); console.groupEnd(); //where the magic happens if (asWK){ $.jStorage.listenKeyChange("reviewQueue", function(){joinReviews(WKItems);}); } var sessionSet = function(strName, obj){ debugging&&console.log(strName + " is of type " + typeof obj); if (typeof obj === "object") obj=JSON.stringify(obj); sessionStorage.setItem(strName, obj); }; var sessionGet = function(strName){ var strObj = sessionStorage.getItem(strName); return parseString(strObj); }; var generateReviewList = function(reviewActive) { //don't interfere with an active session if (reviewActive){ document.getElementById('user-review').innerHTML = "Review in Progress"; return; } debugging&&console.log("generateReviewList()"); // function generateReviewList() builds a review session and updates the html menu to show number waiting. var numReviews = 0; var soonest = Infinity; var next; var reviewList = []; //check to see if there is vocab already in offline storage if (localStorage.getItem('User-Vocab')) { var vocabList = StorageUtil.getVocList(); debugging&&console.log(vocabList); var now = Date.now(); //for each vocab in storage, get the amount of time vocab has lived //var i = vocabList.length; //while(i--){ vocabList.forEach(function(task, i){ var due = task.date + srsObject[task.level].duration; // if tem is unlocked and unburned if (task.level < 9 && (task.manualLock === "no" || task.manualLock === "n" || task.manualLock ==="DB" && !lockDB )){ // if it is past review time if(now >= due) { // count vocab up for review numReviews++; // add item-meaning object to reviewList // have made this optional for surname lists etc. if (task.meaning[0] !== "") { //Rev_Item object args: prompt, kanji, type, solution, index var revItem = new Rev_Item(task.kanji, task.kanji, "Meaning", task.meaning, i); reviewList.push(revItem); } // reading is optional, if there is a reading for the vocab, add its object. if (task.reading[0] !== "") { //Rev_Item object args: prompt, kanji, type, solution, index var revItem2 = new Rev_Item(task.kanji, task.kanji, "Reading", task.reading, i); reviewList.push(revItem2); } //if there is a meaning and reading, and reverse flag is true, test reading from english if (task.reading[0] !== "" && task.meaning[0] !== "" && reverse){ //Rev_Item object args: prompt, kanji, type, solution, index var revItem3 = new Rev_Item(task.meaning.join(", "), task.kanji, "Reverse", task.reading, i); reviewList.push(revItem3); } } else{//unlocked/unburned but not time to review yet debugging&&console.log("setting soonest"); next = due - now; soonest = Math.min(soonest, next); } }//end if item is up for review }, this);// end iterate through vocablist }// end if localStorage if (reviewList.length !== 0){ //store reviewList in current session sessionSet('User-Review', JSON.stringify(reviewList)); debugging&&console.log(reviewList); } else{ debugging&&console.log("reviewList is empty: "+JSON.stringify(reviewList)); document.getElementById('user-review').innerHTML = soonest<Infinity? "Next Review in "+ms2str(soonest) : "No Reviews Available"; } var strReviews = numReviews.toString(); /* If you want to do the 42+ thing. if (numReviews > 42) { strReviews = "42+"; //hail the crabigator! } //*/ // return the number of reviews debugging&&console.log(numReviews.toString() +" reviews created"); if (numReviews > 0){ var reviewString = (soonest !== void 0)? "<br/>\ More to come in "+ms2str(soonest):""; document.getElementById('user-review').innerHTML = "Review (" + strReviews + ")" + reviewString; } }; /* * populate reviews when menu button pressed */ window.generateReviewList = function() { //if menu is invisible, it is about to be visible if ( $("#WKSS_dropdown").is(":hidden") ){ //This is really the only time it needs to run //unless we want to start updating in realtime by keeping track of the soonest item generateReviewList(); } }; /* * Add Item */ // event function to open "add window" and close any other window that might be open at the time. window.WKSS_add = function () { //show the add window $("#add").show(); //hide other windows $("#export").hide(); $("#import").hide(); $("#edit").hide(); $("#selfstudy").hide(); }; //'add window' html text var addHtml = '\n\ <div id="add" class="WKSS">\n\ <form id="addForm">\n\ <button id="AddCloseBtn" class="wkss-close" type="reset"><i class="icon-remove"></i></button>\n\ <h1>Add a new Item</h1>\n\ <input type="text" id="addKanji" placeholder="Enter 漢字, ひらがな or カタカナ">\n\ <input type="text" id="addReading" title="Leave empty to add vocabulary like する (to do)" placeholder="Enter reading">\n\ <input type="text" id="addMeaning" placeholder="Enter meaning">\n\ \n\ <p id="addStatus">Ready to add..</p>\n\ <button id="AddItemBtn" type="button">Add new Item</button>\n\ </form>\n\ </div>\n'; //add html to page source $("body").append(addHtml); //hide add window ("div add" code that was just appended) $("#add").hide(); //function to fire on click event for "Add new Item" $("#AddItemBtn").click(function () { handleAddClick(); }); $("#AddCloseBtn").click(function () { $("#add").hide(); $("#addForm")[0].reset(); $("#addStatus").text('Ready to add..'); $("#addKanji").removeClass("error"); $("#addMeaning").removeClass("error"); }); //---Function wrappers to facilitate use of one localstorage array //---Maintains data integrity between previously two (vocab and srs) function setSrsItem(srsitem,srsList){ var index = srsitem.i; debugging&&console.log("setSrsItem: "); if(srsList){ if(srsList[index].kanji===srsitem.kanji){// try search by index debugging&&console.log("success: "+srsitem.kanji+" found at index "+ index); //replace only the srs parts of the item srsList[index].date = srsitem.date; srsList[index].level = srsitem.level; srsList[index].locked = srsitem.locked; srsList[index].manualLock = srsitem.manualLock; }else{ //backup plan (cycle through list?) debugging&&console.log("SRS Kanji not found in vocablist, needs work"); } debugging&&console.log("item: "); return srsList; } } function getSrsList(){ var srsList = StorageUtil.getVocList(); return srsList; } function getFullList(){ var fullList = JSON.parse(localStorage.getItem('User-Vocab'))||[]; if(!fullList){ fullList=[]; } return fullList; } //-------- /* * Edit Items */ window.WKSS_edit = function () { generateEditOptions(); $("#edit").show(); //hide other windows $("#export").hide(); $("#import").hide(); $("#add").hide(); $("#selfstudy").hide(); }; $("body").append(" \ <div id=\"edit\" class=\"WKSS\"> \ <form id=\"editForm\"> \ <button id=\"EditCloseBtn\" class=\"wkss-close\" type=\"button\"><i class=\"icon-remove\"></i></button>\ <h1>Edit your Vocab</h1> \ <select id=\"editWindow\" size=\"8\"></select>\ <input type=\"text\" id=\"editItem\" name=\"\" size=\"40\" placeholder=\"Select vocab, click edit, change and save!\">\ \ <p id=\"editStatus\">Ready to edit..</p>\ <button id=\"EditEditBtn\" type=\"button\">Edit</button>\ <button id=\"EditSaveBtn\" type=\"button\">Save</button> \ <button id=\"EditDeleteBtn\" type=\"button\" title=\"Delete selected item\">Delete</button> \ <button id=\"EditDeleteAllBtn\" type=\"button\" title=\"本当にやるの?\">Delete All</button> \ <button id=\"ResetLevelsBtn\" type=\"button\">Reset levels</button> \ </form> \ </div>"); $("#edit").hide(); $("#ResetLevelsBtn").click(function () { //var srslist = getSrsList(); var srsList = JSON.parse(localStorage.getItem('User-Vocab'))||[]; if (srsList) { var i = srsList.length; while(i--){ srsList[i].level = 0; debugging&&console.log("srsList[i].i before: "+srsList[i].i); srsList[i].i=i; debugging&&console.log("srsList[i].i after: "+srsList[i].i); var srsList2 = localGet('User-Vocab')||[]; srsList2 = setSrsItem(srsList[i],srsList2); localSet('User-Vocab', srsList2); } } }); $("#EditEditBtn").click(function () { //get handle for 'select' area var select = document.getElementById("editWindow"); //get the index for the currently selected item var index = select.selectedIndex; //select.options[select.selectedIndex].value is not required, option values are set to index var vocabList = StorageUtil.getVocList(); vocabList = vocabList.reverse(); document.getElementById("editItem").value = JSON.stringify(vocabList[index]); document.getElementById("editItem").name = index; //using name to save the index $("#editStatus").text('Loaded item to edit'); }); $("#EditSaveBtn").click(function () { if ($("#editItem").val().length !== 0) { //-- be aware //deleting one item may cause mismatch if i is property of item in list try { var index = document.getElementById("editItem").name; var item = JSON.parse(document.getElementById("editItem").value.toLowerCase()); var m = item.meaning.length; while(m--){ if (item.meaning[m] === ""){ delete item.meaning[m]; } } var fullList = getFullList().reverse(); if (isItemValid(item) &&//item is valid !(checkForDuplicates(fullList,item) && //kanji (if changed) is not already in the list fullList[index].kanji !== item.kanji)) {//unless it is the item being edited var srslist = getSrsList().reverse(); //get srs components of item(list) fullList[index] = item;//does not have srs stuff, re-add it now debugging&&console.log(fullList[index]); debugging&&console.log(srslist[index]); fullList[index].date = srslist[index].date; fullList[index].level = srslist[index].level; fullList[index].locked = srslist[index].locked; fullList[index].manualLock = srslist[index].manualLock; fullList = fullList.reverse(); //reset order of array localSet('User-Vocab', fullList); generateEditOptions(); $("#editStatus").html('Saved changes!'); document.getElementById("editItem").value = ""; document.getElementById("editItem").name = ""; } else{ $("#editStatus").text('Invalid item or duplicate!'); alert(isItemValid(item).toString() +" && !("+ checkForDuplicates(fullList,item).toString()+" && !("+fullList[index].kanji+" !== "+item.kanji+")"); } } catch (e) { $("#editStatus").text(e); } } }); $("#EditDeleteBtn").click(function () { //select options element window var select = document.getElementById("editWindow"); //index of selected item var item = select.options[select.selectedIndex].value; //fetch JSON strings from storage and convert them into Javascript literals var vocabList = getFullList(); //starting at selected index, remove 1 entry (the selected index). if (item > -1) { if (vocabList !== null){ vocabList.splice(item, 1); } } //yuck if (vocabList.length !== 0) { localSet('User-Vocab', vocabList); } else { localStorage.removeItem('User-Vocab'); } updateEditGUI(); $("#editStatus").text('Item deleted!'); }); $("#EditDeleteAllBtn").click(function () { var deleteAll = confirm("Are you sure you want to delete all entries?"); if (deleteAll) { //drop local storage localStorage.removeItem('User-Vocab'); updateEditGUI(); $("#editStatus").text('All items deleted!'); } }); $("#EditCloseBtn").click(function () { $("#edit").hide(); $("#editForm")[0].reset(); $("#editStatus").text('Ready to edit..'); }); /* * Export */ window.WKSS_export = function () { $("#export").show(); //hide other windows $("#add").hide(); $("#import").hide(); $("#edit").hide(); $("#selfstudy").hide(); }; $("body").append(' \ <div id="export" class="WKSS"> \ <form id="exportForm"> \ <button id="ExportCloseBtn" class="wkss-close" type="button"><i class="icon-remove"></i></button>\ <h1>Export Items</h1> \ <textarea cols="50" rows="18" id="exportArea" placeholder="Export your stuff! Sharing is caring ;)"></textarea> \ \ <p id="exportStatus">Ready to export..</p> \ <button id="ExportItemsBtn" type="button">Export Items</button>\ <button id="ExportSelectAllBtn" type="button">Select All</button>\ <button id="ExportCsvBtn" type="button">Export CSV</button>\ </form> \ </div>'); $("#export").hide(); $("#ExportItemsBtn").click(function () { if (localStorage.getItem('User-Vocab')) { $("#exportForm")[0].reset(); var vocabList = StorageUtil.getVocList(); $("#exportArea").text(JSON.stringify(vocabList)); $("#exportStatus").text("Copy this text and share it with others!"); } else { $("#exportStatus").text("Nothing to export yet :("); } }); $("#ExportSelectAllBtn").click(function () { if ($("#exportArea").val().length !== 0) { select_all("exportArea"); $("#exportStatus").text("Don't forget to CTRL + C!"); } }); $("#ExportCsvBtn").click(function () { var vocabList = getFullList(); var CsvFile = createCSV(vocabList); window.open(CsvFile); }); $("#ExportCloseBtn").click( function () { $("#export").hide(); $("#exportForm")[0].reset(); $("#exportArea").text(""); $("#exportStatus").text('Ready to export..'); } ); /* * Import */ window.WKSS_import = function () { $("#import").show(); //hide other windows $("#add").hide(); $("#export").hide(); $("#edit").hide(); $("#selfstudy").hide(); }; $("body").append(' \ <div id="import" class="WKSS"> \ <form id="importForm"> \ <button id="ImportCloseBtn" class="wkss-close" type="reset"><i class="icon-remove"></i></button>\ <h1>Import Items</h1>\ <textarea cols="50" rows="18" id="importArea" placeholder="Paste your stuff and hit the import button! Use with caution!"></textarea> \ \ <p id="importStatus">Ready to import..</p> \ <label class="button" id="ImportItemsBtn" style="display:inline;">Import Items</label>\ \ <label id="ImportCsvBtn" class="button" style="display:inline;cursor: pointer;">Import CSV \ \ <input type="file" id="upload" accept=".csv,.tsv" style="height:0px;width:0px;background:red;opacity:0;filter:opacity(1);" />\ \ </label>\ \ <label class="button" id="ImportWKBtn" style="display:inline;"><i class="icon-download-alt"></i> WK</label>\ </form> \ </div>'); $("#import").hide(); document.getElementById("upload") && document.getElementById("upload").addEventListener('change', ImportUtil.fileUpload, false); $("#ImportCsvBtn").click(function () { }); $("#ImportWKBtn").click(function(){ WanikaniUtil.getServerResp(APIkey,"vocabulary"); debugging&&console.log("maybe?"); }); $("#ImportItemsBtn").click(function () { if ($("#importArea").val().length !== 0) { try { var add = JSON.parse($("#importArea").val().toLowerCase()); alert(JSON.stringify(add)); if (checkAdd(add)) { $("#importStatus").text("No valid input (duplicates?)!"); return; } var newlist; var srslist = []; if (localStorage.getItem('User-Vocab')) { var vocabList = StorageUtil.getVocList(); srslist = getSrsList(); newlist = vocabList.concat(add); } else { newlist = add; } var i = add.length; while(i--){ StorageUtil.setVocItem(add[i]); } $("#importStatus").text("Import successful!"); $("#importForm")[0].reset(); $("#importArea").text(""); } catch (e) { $("#importStatus").text("Parsing Error!"); debugging&&console.log(e); } } else { $("#importStatus").text("Nothing to import :( Please paste your stuff first"); } }); $("#ImportCloseBtn").click(function () { $("#import").hide(); $("#importForm")[0].reset(); $("#importArea").text(""); $("#importStatus").text('Ready to import..'); }); /* * Review Items */ window.WKSS_review = function () { //is there a session waiting in storage? if(sessionStorage.getItem('User-Review')) { //show the selfstudy window $("#selfstudy").show(); //hide other windows $("#add").hide(); $("#export").hide(); $("#edit").hide(); $("#import").hide(); startReview(); } }; $("body").append(' \ <div id="selfstudy" class="WKSS">\ <button id="SelfstudyCloseBtn" class="wkss-close" type="button"><i class="icon-remove"></i></button>\ <h1>Review<span id="RevNum"></span></h1>\ <div id="wkss-kanji">\ <span id="rev-kanji"></span>\ </div><div id="wkss-type">\ <span id="rev-type"></span><br />\ </div><div id="wkss-solution">\ <span id="rev-solution"></span>\ </div><div id="wkss-input">\ <input type="text" id="rev-input" size="40" placeholder="">\ </div><span id="rev-index" style="display: block;"></span>\ \ <form id="audio-form">\ <label id="AudioButton" class="button">Play audio</label>\ <label id="WrapUpBtn" class="button">Wrap Up</label>\ </form>\ <div id="rev-audio" style="display:none;"></div>\ </div>'); $("#selfstudy").hide(); $("#SelfstudyCloseBtn").click(function () { $("#selfstudy").hide(); $("#rev-input").val(""); reviewActive = false; }); $("#WrapUpBtn").click(function() { var sessionList = sessionGet('User-Review')||[]; var statsList = sessionGet('User-Stats')||[]; //if an index in sessionList matches one in statsList, don't delete var sessionI = sessionList.length; var item = sessionGet('WKSS-item')||[]; var arr2 = []; //for every item in sessionList, look for index in statsList, //if not there (-1) delete item from sessionList while (sessionI--){ var index = findIndex(statsList,sessionList[sessionI]); if ((Math.sign(1/index) !== -1)||(sessionList[sessionI].index == item.index)){ arr2.push(sessionList[sessionI]); } } debugging&&console.log(arr2); sessionSet('User-Review', JSON.stringify(arr2)); }); $("#AudioButton").click(function () { openInNewTab(document.getElementById('rev-audio').innerHTML); }); $("body").append(' \ <div id="resultwindow" class="WKSS"> \ <button id="ReviewresultsCloseBtn" class="wkss-close" type="button"><i class="icon-remove"></i></button>\ <h1>Review Results</h1>\ <h2>All</h2>\ <div id="stats-a"></div>\ </div>'); $("#resultwindow").hide(); $("#ReviewresultsCloseBtn").click(function () { $("#resultwindow").hide(); document.getElementById("stats-a").innerHTML = ""; }); //declare global values for keyup event //is an answer being submitted? var submit = true; //jquery keyup event $("#rev-input").keyup(function (e) { //functions: // inputCorrect() //check if key press was 'enter' (keyCode 13) on the way up //and keystate true (answer being submitted) //and cursor is focused in reviewfield if (e.keyCode == 13 && submit === true) { var input = $("#rev-input").val(); var reviewList = sessionGet('User-Review')||[]; var rnd = sessionStorage.getItem('WKSS-rnd')||0; var item = sessionGet('WKSS-item'); //-- starting implementation of forgiveness protocol item.forgive = [];//"ゆるす"]; //placeholder (許す to forgive) if (item === null){ alert("Item Null??"); reviewList.splice(rnd, 1); }else{ //handle grading and storing solution //check for input, do nothing if none if(input.length === 0){ return; } //disable input after submission //document.getElementById('rev-input').disabled = true; //was the input correct? var correct = inputCorrect(); //was the input forgiven? var forgiven = (item.forgive.indexOf(input) !== -1); if (correct) { //highlight in (default) green $("#rev-input").addClass("correct"); //show answer $("#rev-solution").addClass("info"); } else if (forgiven){ $("#rev-input").addClass("caution"); } else { //highight in red $("#rev-input").addClass("error"); //show answer $("#rev-solution").addClass("info"); } //remove from sessionList if correct if (correct) { debugging&&console.log("correct answer"); if (reviewList !== null){ var oldlen = reviewList.length; reviewList.splice(rnd, 1); debugging&&console.log("sessionList.length: "+ oldlen +" -> "+reviewList.length); //replace shorter (by one) sessionList to session if (reviewList.length !== 0) { debugging&&console.log("sessionList.length: "+ reviewList.length); sessionSet('User-Review', JSON.stringify(reviewList)); } else { //reveiw over, delete sessionlist from session sessionStorage.removeItem('User-Review'); } }else{ console.error("Error: no review session found"); } }else{ // if(forgiven){ // debugging&&console.log(input +" has been forgiven. "+item.type); // return; //} debugging&&console.log("wrong answer"); } item = markAnswer(item); sessionSet(item.index, item); var list = JSON.parse(sessionStorage.getItem("User-Stats"))||[]; var found = false; if (list){ var i = list.length; while(i--){ if (list[i].index == item.index) { list[i] = item; //replace item if it exists found = true; break; } } if(!found){ list = saveToSortedList(list,item); } } else { list = [item]; } sessionSet("User-Stats", JSON.stringify(list)); //playAudio(); //answer submitted, next 'enter' proceeds with script submit = false; }//null garbage collection } else if (e.keyCode == 13 && submit === false) { debugging&&console.log("keystat = " + submit); //there are still more reviews in session? if (sessionStorage.getItem('User-Review')) { // debugging&&console.log("found a 'User-Review': " + sessionStorage.getItem('User-Review')); setTimeout(function () { debugging&&console.log("refreshing reviewList from storage"); var reviewList = JSON.parse(sessionStorage.getItem('User-Review')); //cue up first remaining review nextReview(reviewList); debugging&&console.log("checking for empty reviewList"); if (reviewList.length === 0){ debugging&&console.log("session over. reviewList: "+JSON.stringify(reviewList)); sessionStorage.removeItem("User-Review"); } // document.getElementById('rev-input').disabled = true; $("#rev-solution").removeClass("info"); $("#selfstudy").hide().fadeIn('fast'); }, 1); } else { // no review stored in session, review is over setTimeout(function () { $("#selfstudy").hide(); //document.getElementById('rev-input').disabled = false; $("#rev-solution").removeClass("info"); debugging&&console.log("showResults"); showResults(); $("#resultwindow").show(); debugging&&console.log("showResults completed"); //*/ //clear session sessionStorage.clear(); reviewActive = false; }, 1); } submit = true; } }); /** populate reviews when menu button pressed */ window.generateReviewList = function() { //if menu is invisible, it is about to be visible if ( $("#WKSS_dropdown").is(":hidden") ){ //This is really the only time it needs to run //unless we want to start updating in realtime by keeping track of the soonest item generateReviewList(reviewActive); } }; /** Add Item: event function to open "add window" and close any other window that might be open at the time. */ window.WKSS_add = function () { //show the add window $("#add").show(); //hide other windows $("#export").hide(); $("#import").hide(); $("#edit").hide(); $("#selfstudy").hide(); }; var addElement = require('./addelement.js'); //add html to page source $("body").append(addElement); //hide add window ("div add" code that was just appended) $("#add").hide(); var handleAddClick = require('./handleAddClick.js'); //function to fire on click event for "Add new Item" $("#AddItemBtn").click(function () { handleAddClick(); }); $("#AddCloseBtn").click(function () { $("#add").hide(); $("#addForm")[0].reset(); $("#addStatus").text('Ready to add..'); $("#addKanji").removeClass("error"); $("#addMeaning").removeClass("error"); }); /** Keeps legacy srsList updated. * @depreciate * @param {SrsItem} srsitem * @param {Array.<SrsItem>} srsList * @returns {Array.<SrsItem>} The srs data for a task. Or null if no srsList was provided. */ var updateSrsInList = function(srsitem, srsList){ var index = srsitem.i; if(srsList){ if(srsList[index].kanji===srsitem.kanji){// try search by index debugging&&console.log("success: "+srsitem.kanji+" found at index "+ index); //replace only the srs parts of the item srsList[index].date = srsitem.date; srsList[index].level = srsitem.level; srsList[index].locked = srsitem.locked; srsList[index].manualLock = srsitem.manualLock; } return srsList; } else{ return null; } }; /** Checks if an item's kanji is represented in a list * @returns {boolean} */ var checkForDuplicates = function(list, item){ return list.some(function(a){return a.kanji === item.kanji;}); }; /** Creates a lookup array for each kanji with its srs level. Used for displaying component levels. * @param item * @param kanjilist * @returns An array of the kanji with SRS values for each kanji component. * @example eg. 折り紙: compSRS = [{"kanji": "折", "srs": "guru"}, {"kanji": "紙", "srs": "apprentice"}] */ var getCompKanji = function(item, kanjiList){ if (!kanjiList){ kanjiList = []; } debugging&&console.log("getCompKanji(item, kanjiList)"); var compSRS = []; var kanjiReady = false; //indicates if the kanjiList has been populated var userGuppy = false; //indicates if kanjiList has less than 100 items var kanjiObj = {}; //has the server responded yet if (kanjiList.length > 0){ debugging&&console.log("kanjiList is > 0"); kanjiReady = true; //create lookup object for (var k=0;k<kanjiList.length;k++){ kanjiObj[kanjiList[k].character] = kanjiList[k]; } //is there less than 100 kanji in the response if (kanjiList.length < 100){ debugging&&console.log("kanjiList is < 100"); userGuppy = true; } } var components = item.components; //for each kanji character component // this is the outer loop since there will be far less of them than kanjiList for(var i = 0; i < components.length; i++){ var matched = false; //for each kanji returned by the server // for(var j=0; j<kanjiList.length; j++){ //if the kanji returned by the server matches the character in the item if (typeof kanjiObj[components[i]] !== 'undefined'){ // if (kanjiList[j].character == components[i]){ compSRS[i] = {"kanji": components[i], "srs": kanjiObj[components[i]].srs}; matched = true; // break; //kanji found: 'i' is its position in item components; 'j' is its postion in the 'kanjiList' server response } // } if (matched === false){ // character got all the way through kanjiList without a match. if (kanjiReady){ //was there a server response? if (userGuppy){ //is the user a guppy (kanji probably matches a turtles response) debugging&&console.log("matched=false, kanjiList.length: "+kanjiList.length); compSRS[i] = {"kanji": components[i], "srs": "noMatchGuppy"}; } else{ //user is a turtle, kanji must not have been added to WK (yet) debugging&&console.log("matched=false, kanjiList.length: "+kanjiList.length); compSRS[i] = {"kanji": components[i], "srs": "noMatchWK"}; } } else{ debugging&&console.log("matched=false, kanjiReady=false, noServerResp"); compSRS[i] = {"kanji": components[i], "srs": "noServerResp"}; } } } return compSRS; }; var isKanjiLocked = function(srsitem, kanjiList, locksOn){ //item unlocked by default //may have no kanji, only unlocked kanji will get through the code unflagged // Enumeration "yes", "no", "DB" var locked = "no"; if (locksOn){ //get the kanji characters in the word. var componentList = getCompKanji(srsitem, kanjiList); // eg: componentList = getCompKanji("折り紙", kanjiList); // componentList = [{"kanji": "折", "srs": "guru"}, {"kanji": "紙", "srs": "apprentice"}] var c = componentList.length; while(c--){ //look for locked kanji in list if (componentList[c].srs == "apprentice" || componentList[c].srs == "noServerResp"|| componentList[c].srs == "unreached" ){ //----could be apprentice etc. //Simple: lock is 'yes' locked = "yes"; // "yes": item will be locked while there is no database connection. // if the server response indicates that it has been unlocked, only then will it be available for review debugging&&console.log("test srs for apprentice etc. 'locked': "+ locked); debugging&&console.log(componentList[c].kanji +": "+componentList[c].srs +" -> "+ locked); break; // as soon as one kanji is locked, the whole item is locked } //DB locks get special state if (componentList[c].srs == "noMatchWK" || componentList[c].srs == "noMatchGuppy"){ locked = "DB"; //"DB" : database limitations, one of two things //a. the kanji isn't in the database and the user is a guppy --could change if user subscribes or first two levels change/expand //b. the kanji isn't in the database and the user is a turtle --could change if more kanji added. debugging&&console.log("test srs for unmatched kanji. 'locked': "+ locked); debugging&&console.log(componentList[c].kanji +": "+componentList[c].srs +" -> "+ locked); } } //for char in componentList debugging&&console.log("out of character loop"); } //locked will be either "yes","no", or "DB" return [locked]; }; /** Gets the Kanji characters in a given string. * @param {string} vocabString - * @return {Array.<string>} An array of the kanji components in the given string */ var getComponents = function(vocabString){ return Array.prototype.filter.call(vocabString, function(ch){ return /^[\u4e00-\u9faf]+$/.test(ch); }, this); }; /** Manages the locked and manualLock properties of srsitem. This is to stop items being locked again after they have been unlocked if any of the kanji used falls below the unlock threshold (eg. if the 勉 in 勉強 falls back to apprentice, we do not want to lock up 勉強 again.) * @param {Object} item * @param {string} item.locked - (String enumeration) A real time evaluation of the item (is any of the kanji in the word locked?) * @param {string} item.manualLock - (String enumeration) Will return 'no' if .locked has ever returned 'no'. * @returns {ITask} item */ var setLocks = function(item){ //once manualLock is "no" it stays "no" if (item.manualLock !== false && item.manualLock !== "no" && item.manualLock !== "n"){ var kanjiList = localGet('User-KanjiList')||[]; item.components = getComponents(item.kanji); var kanjiLockedResult = isKanjiLocked(item, kanjiList, locksOn); item.locked = kanjiLockedResult[0]; item.manualLock = item.locked; }else{ item.manualLock = false; } debugging&&console.log("setting locks for "+ item.kanji +": locked: "+item.locked+", manualLock: "+ item.manualLock); return item; }; /** Converts number of milliseconds into a readable string * @param {number} milliseconds - The number of milliseconds to approximate * @returns {string} Readable time frame ('2 months', '3 hours', '1 week' etc). */ var ms2str = function(milliseconds){ var num; //number of months weeks hours etc //more time has elapsed than required for the level if(milliseconds <= 0) { return "Now" ; } if(milliseconds > 2628000000) {//About a month num = Math.floor(milliseconds/2628000000).toString()+" month"; if (num !== "1 month"){ return num+"s"; }else{ return num; } } if(milliseconds > 604800000) {//A week num = Math.floor(milliseconds/604800000).toString()+" week"; if (num !== "1 week"){ return num+"s"; }else{ return num; } } if(milliseconds > 86400000) {//A day num = Math.floor(milliseconds/86400000).toString()+" day"; if (num !== "1 day"){ return num+"s"; }else{ return num; } } if(milliseconds > 3600000) {//An hour num = Math.floor(milliseconds/3600000).toString()+" hour"; if (num !== "1 hour"){ return num+"s"; }else{ return num; } } if(milliseconds > 60000) {//A minute num = Math.floor(milliseconds/60000).toString()+" minute"; if (num !== "1 minute"){ return num+"s"; }else{ return num; } } if(milliseconds > 0) {//A second is 1000, but need to return something for less than one too num = Math.floor(milliseconds/1000).toString()+" second"; if (num !== "1 second"){ return num+"s"; }else{ return num; } } }; /** Retrieves values from storage to populate 'editItems' menu */ var generateEditOptions = function() { var select = document.getElementById('editWindow'); //clear the editWindow while (select.firstChild) { select.removeChild(select.firstChild); } //check for items to add if (localStorage.getItem('User-Vocab')) { //retrieve from local storage var vocabList = StorageUtil.getVocList(); var srslist = StorageUtil.getVocList(); var options = []; //build option string //var i = vocabList.length; //while (i--){ vocabList.forEach(function(task){ //form element to save string var opt = document.createElement('option'); //dynamic components of string //when is this item up for review var due = task.due||task.date + srsObject[task.level].duration; var review = ""; //no future reviews if burned if(task.level >= 9) { review = "Never"; } //calculate next relative review time //current timestamp is past due date. else if(Date.now() >= due) { review = "Now" ; } else { review = ms2str(due - Date.now()); }//end if review is not 'never' or 'now' var text = task.kanji + " & " + task.reading + " & " + task.meaning + " (" + srsObject[task.level].rank + " - Review: " + review + ") Locked: " + task.manualLock; opt.value = i; opt.innerHTML = text; options.push(opt);//for future use (sorting data etc) select.appendChild(opt);//export item to option menu }, this); } }; /** Edit Items */ window.WKSS_edit = function () { generateEditOptions(); $("#edit").show(); //hide other windows $("#export").hide(); $("#import").hide(); $("#add").hide(); $("#selfstudy").hide(); }; var buildNode = require('./buildnode.js'); var buildWindow = require('./buildwindow.js'); /*var addEditWindow = function() { var editWindow = buildNode('div', {id: "WKSS-edit", className: "WKSS"}); var editForm = buildNode('form', {id: "WKSS-editForm"}); editWindow.appendChild(editForm); var editCloseButton = buildNode('button', {id: "WKSS-editCloseBtn", className: "WKSS-close"}); editForm.appendChild(editCloseButton); editCloseButton.appendChild(buildNode('i', {className: "icon-remove"})); var h1Element = buildNode('h1'); editForm.appendChild(h1Element); h1Element.appendChild(document.createTextNode("Edit your Vocab")); var selectElement = buildNode('select', {id: "editWindow", size: "8"}); editForm.appendChild(selectElement); var editItemText = buildNode('input', {type: "text" id: "editItem" name: "" size: "40" placeholder: "Select vocab, click edit, change and save!"}); editForm.appendChild(editItemText); var editStatus = buildNode('p', {id: "editStatus"}); editForm.appendChild(editStatus); editStatus.appendChild(document.createTextNode("Ready to edit..")); var editButton = buildNode('button', {id: "EditEditBtn", type: "button"}); editForm.appendChild(editButton); editButton.appendChild(document.createTextNode("Edit")); var editSave = buildNode('button', {id: "EditSaveBtn", type: "button"}); editForm.appendChild(editSave); editSave.appendChild(document.createTextNode("Save")); var editDelete = buildNode('button', {id: "EditDeleteBtn", type: "button", title: "Delete selected item"}); editForm.appendChild(editDelete); editDelete.appendChild(document.createTextNode("Delete")); var editDeleteAll = buildNode('button', {id: "EditDeleteAllBtn", type: "button", title: "本当にやるの?"}); editForm.appendChild(editDeleteAll); editDeleteAll.appendChild(document.createTextNode("Delete All")); var editResetLevels = buildNode('button', {id: "ResetLevelsBtn", type: "button"}); editForm.appendChild(editResetLevels); editResetLevels.appendChild(document.createTextNode("Reset levels")); return editWindow; }; */ var editWindowStructure = { id: "WKSS-edit", className: "WKSS", childNodes:[{ tag: 'form', id: "WKSS-editForm", childNodes:[{ tag: 'button', id: "WKSS-editCloseBtn", className: "WKSS-close", childNodes:[{ tag: 'i', className: "icon-remove" }] },{ tag: 'h1', childNodes:["Edit your Vocab"] },{ tag: 'select', id: "editWindow", other: {size: "8"} },{ tag: 'input', other:{ type: "text", name: "", size: "40", placeholder: "Select vocab, click edit, change and save!" }, id: "editItem" },{ tag: 'p', id: "editStatus", childNodes:["Ready to edit..."] },{ tag: 'button', id: "EditEditBtn", other: {type: "button"}, childNodes:["Edit"] },{ tag: 'button', id: "EditSaveBtn", other:{type: "button"}, childNodes:["Save"] },{ tag: 'button', id: "EditDeleteBtn", other: {type: "button", title: "Delete selected item"}, childNodes:["Delete"] },{ tag: 'button', id: "EditDeleteAllBtn", other: {type: "button", title: "本当にやるの?"}, childNodes:["Delete All"] },{ tag: 'button', id: "ResetLevelsBtn", other: {type: "button"}, childNodes:["Reset levels"] }] }] }; var addEditWindow = buildWindow(editWindowStructure); $("body").append(addEditWindow); $("#WKSS-edit").hide(); /** Resets the levels of all tasks and re-indexes them in storage. * @param {Event} evt - Click event (not used) */ var resetLevels = function (evt) { var vocList = StorageUtil.getVocList().map(function(vocItem, i){ vocItem.level = 0; debugging&&console.log("vocList[i].i before: "+vocItem.i); vocItem.i=i; debugging&&console.log("vocList[i].i after: "+vocItem.i); return vocItem; }, this); StorageUtil.setVocList(vocList); }; $("#ResetLevelsBtn").click(resetLevels); $("#EditEditBtn").click(function () { //get handle for 'select' area var select = document.getElementById("editWindow"); //get the index for the currently selected item var index = select.selectedIndex; //select.options[select.selectedIndex].value is not required, option values are set to index var vocabList = StorageUtil.getVocList(); vocabList = vocabList.reverse(); document.getElementById("editItem").value = JSON.stringify(vocabList[index]); document.getElementById("editItem").name = index; //using name to save the index $("#editStatus").text('Loaded item to edit'); }); var isEmpty = function(value) { return (value === void 0 || value === null); }; var isArray = function(arg){ return Array.isArray ? Array.isArray(arg) : Object.prototype.toString.call(arg) === '[object Array]'; }; /** Validates a task object * @param {Task} add - The Task being verified * @returns {Boolean} If the provided task has all the necessary properties to be added to the review list. */ var isItemValid = function(add) { return (!isEmpty(add.kanji) && //kanji property exists !isEmpty(add.meaning) && //meaning property exists !isEmpty(add.reading) && //reading property exists isArray(add.meaning) &&//meaning is an array isArray(add.reading));//reading is an array }; $("#EditSaveBtn").click(function () { //-- be aware //deleting one item may cause mismatch if i is property of item in list try { if ($("#editItem").val().length !== 0) { var editItem = document.getElementById("editItem"); var index = editItem.name; var item = JSON.parse(editItem.value.toLowerCase()); // Make sure that the word 'meaning' is immutable, so it exists to trim if (item.meaning){ item.meaning.forEach(function(meaning, m, meanings){ if (meaning === ""){ delete meanings[m]; } }, this); } var fullList = StorageUtil.getVocList().reverse(); if (isItemValid(item) &&//item is valid !(checkForDuplicates(fullList,item) && //kanji (if changed) is not already in the list fullList[index].kanji !== item.kanji)) {//unless it is the item being edited var srslist = StorageUtil.getVocList().reverse(); //get srs components of item(list) fullList[index] = item;//does not have srs stuff, re-add it now fullList[index].date = srslist[index].date; fullList[index].level = srslist[index].level; fullList[index].locked = srslist[index].locked; fullList[index].manualLock = srslist[index].manualLock; fullList = fullList.reverse(); //reset order of array localSet('User-Vocab', fullList); generateEditOptions(); $("#editStatus").html('Saved changes!'); document.getElementById("editItem").value = ""; document.getElementById("editItem").name = ""; } else{ $("#editStatus").text('Invalid item or duplicate!'); alert(isItemValid(item).toString() +" && !("+ checkForDuplicates(fullList,item).toString()+" && !("+fullList[index].kanji+" !== "+item.kanji+")"); } } } catch (e) { $("#editStatus").text(e); } }); var updateEditGUI = function(){ generateEditOptions(); document.getElementById("editItem").value = ""; document.getElementById("editItem").name = ""; }; var editDelete = function () { //select options element window var select = document.getElementById("editWindow"); //index of selected item var item = select.options[select.selectedIndex].value; //fetch JSON strings from storage and convert them into Javascript literals var vocabList = StorageUtil.getVocList(); //starting at selected index, remove 1 entry (the selected index). if (item > -1) { if (vocabList !== null){ vocabList.splice(item, 1); } } //yuck if (vocabList.length !== 0) { localSet('User-Vocab', vocabList); } else { localStorage.removeItem('User-Vocab'); } updateEditGUI(); $("#editStatus").text('Item deleted!'); }; $("#EditDeleteBtn").click(editDelete); var editDeleteAll = function () { var deleteAll = confirm("Are you sure you want to delete all entries?"); if (deleteAll) { //drop local storage localStorage.removeItem('User-Vocab'); updateEditGUI(); $("#editStatus").text('All items deleted!'); } }; $("#EditDeleteAllBtn").click(editDeleteAll); $("#EditCloseBtn").click(function () { $("#edit").hide(); $("#editForm")[0].reset(); $("#editStatus").text('Ready to edit..'); }); /** Export */ window.WKSS_export = function () { $("#export").show(); //hide other windows $("#add").hide(); $("#import").hide(); $("#edit").hide(); $("#selfstudy").hide(); }; var exportWindowStructure = { id: "WKSS-export", className: "WKSS", childNodes:[{ tag: 'form', id: "WKSS-exportForm", childNodes:[ { tag: 'button', id: "WKSS-exportCloseBtn", className: "WKSS-close", childNodes:[{ tag: 'i', className: "icon-remove" }] }, { tag: 'h1', childNodes:["Export Items"] }, { tag: 'textarea', id: "exportArea", other: {cols: "50", rows: "18", placeholder: "Export your stuff! Sharing is caring ;)"} }, { tag: 'p', id: "exportStatus", childNodes:["Ready to export..."] }, { tag: 'button', id: "ExportItemsBtn", other: {type: "button"}, childNodes:["Export Items"] }, { tag: 'button', id: "ExportSelectAllBtn", other:{type: "button"}, childNodes:["Select All"] }, { tag: 'button', id: "ExportCsvBtn", other: {type: "button"}, childNodes:["Export CSV"] } ] }] }; var exportWindow = buildWindow(exportWindowStructure); $("body").append(exportWindow); $("#WKSS-export").hide(); $("#ExportItemsBtn").click(function () { if (localStorage.getItem('User-Vocab')) { $("#exportForm")[0].reset(); var vocabList = StorageUtil.getVocList(); $("#exportArea").text(JSON.stringify(vocabList)); $("#exportStatus").text("Copy this text and share it with others!"); } else { $("#exportStatus").text("Nothing to export yet :("); } }); var select_all = function(str) { var text_val = document.getElementById(str); debugging&&console.log(text_val); text_val.focus(); text_val.select(); }; $("#ExportSelectAllBtn").click(function () { if ($("#exportArea").val().length !== 0) { select_all("exportArea"); $("#exportStatus").text("Don't forget to CTRL + C!"); } }); var createCSV = function(JSONstring){ var JSONobject = (typeof JSONstring === 'string') ? JSON.parse(JSONstring) : JSONstring; var key; var CSVarray = []; var header = []; var id = JSONobject.length; if (id){//object not empty for (key in JSONobject[0]){ if (JSONobject[0].hasOwnProperty(key)){ header.push(key); } } } CSVarray.push(header.join(',')); while(id--){ var line = []; var h = header.length; while(h--){// only do keys in header, in the header's order. //JSONobject[id]){ key = header[h]; if(JSONobject[id][key] !== undefined){ if (Array.isArray(JSONobject[id][key])){ //parse array here line.push(JSONobject[id][key].join("\t")); }else{ line.push(JSONobject[id][key]); } } }line = line.reverse(); CSVarray.push(line.join(',')); } var CSVstring = CSVarray.join("\r\n"); return encodeURI("data:text/csv;charset=utf-8," + CSVstring); }; $("#ExportCsvBtn").click(function () { var vocabList = StorageUtil.getVocList(); var CsvFile = createCSV(vocabList); window.open(CsvFile); }); $("#ExportCloseBtn").click(function () { $("#export").hide(); $("#exportForm")[0].reset(); $("#exportArea").text(""); $("#exportStatus").text('Ready to export..'); }); /** Import */ window.WKSS_import = function () { $("#import").show(); //hide other windows $("#add").hide(); $("#export").hide(); $("#edit").hide(); $("#selfstudy").hide(); }; var importWindowStructure = { id: "WKSS-import", className: "WKSS", childNodes:[{ tag: 'form', id: "WKSS-importForm", childNodes:[ { tag: 'button', id: "WKSS-importCloseBtn", className: "WKSS-close", childNodes:[{ tag: 'i', className: "icon-remove" }] }, { tag: 'h1', childNodes:["Import Items"] }, { tag: 'textarea', id: "importArea", other: {cols: "50", rows: "18", placeholder: "Paste your stuff and hit the import button! Use with caution!"} }, { tag: 'p', id: "importStatus", childNodes:["Ready to import..."] }, { tag: 'label', id: "ImportItemsBtn", className: "button", other: {type: "button", style: "display:inline;"}, childNodes:["Import Items"] }, { tag: 'label', id: "ImportCsvBtn", className: "button", other: {style:"display:inline; cursor: pointer;"}, childNodes:["Import CSV", { tag: 'input', id: "upload", other: { type: "file", accept: ".csv, .tsv", style: "height:0px;width:0px;background:red;opacity:0;filter:opacity(1);" } } ] }, { tag: 'label', id: "ImportWKBtn", className: "button", other: {style: "display:inline;"}, childNodes:[ { tag:'i', className: "icon-download-alt" }, "WK" ] } ] }] }; var importWindow = buildWindow(importWindowStructure); $("body").append(importWindow); $("#import").hide(); var checkAdd = function(add) { //take a JSON object (parsed from import window) and check with stored items for any duplicates // Returns true if each item in 'add' array is valid and //at least one of them already exists in storage var i = add.length; if(localStorage.getItem('User-Vocab')) { var vocabList = StorageUtil.getVocList(); while(i--){ if (isItemValid(add[i]) && checkForDuplicates(vocabList,add[i])) return true; } } return false; }; document.getElementById("upload") && document.getElementById("upload").addEventListener('change', ImportUtil.fileUpload, false); var refreshLocks = function(){ var vocList = StorageUtil.getVocList().map(function(vocItem){ debugging&&console.log("vocList[i] = setLocks(vocList[i]);"); vocItem = setLocks(vocItem); return vocItem; }, this); console.groupEnd(); StorageUtil.setVocList(vocList); }; $("#ImportWKBtn").click(function(){ WanikaniUtil.getServerResp(APIkey,"vocabulary"); debugging&&console.log("maybe?"); }); $("#ImportItemsBtn").click(function () { if ($("#importArea").val().length !== 0) { try { var add = JSON.parse($("#importArea").val().toLowerCase()); alert(JSON.stringify(add)); if (checkAdd(add)) { $("#importStatus").text("No valid input (duplicates?)!"); return; } var newlist; var srslist = []; if (localStorage.getItem('User-Vocab')) { var vocabList = StorageUtil.getVocList(); srslist = StorageUtil.getVocList(); newlist = vocabList.concat(add); } else { newlist = add; } var i = add.length; while(i--){ StorageUtil.setVocItem(add[i]); } $("#importStatus").text("Import successful!"); $("#importForm")[0].reset(); $("#importArea").text(""); } catch (e) { $("#importStatus").text("Parsing Error!"); debugging&&console.log(e); } } else { $("#importStatus").text("Nothing to import :( Please paste your stuff first"); } }); $("#ImportCloseBtn").click(function () { $("#import").hide(); $("#importForm")[0].reset(); $("#importArea").text(""); $("#importStatus").text('Ready to import..'); }); var playAudio = function() { var kanji = document.getElementById('rev-kanji').innerHTML; var kana = (document.getElementById('rev-solution').innerHTML.split(/[,、]+\s*/))[0]; document.getElementById('rev-audio').innerHTML = ""; document.getElementById('audio-form').action = ""; //document.getElementById('AudioButton').disabled = true; if( !kanji.match(/[a-zA-Z]+/i) && !kana.match(/[a-zA-Z]+/i)) { kanji = encodeURIComponent(kanji); kana = encodeURIComponent(kana); var i; var newkanji = ""; for(i = 1; i < kanji.length; i = i+3) { newkanji = newkanji.concat(kanji[i-1]); newkanji = newkanji.concat('2'); newkanji = newkanji.concat('5'); newkanji = newkanji.concat(kanji[i]); newkanji = newkanji.concat(kanji[i+1]); } var newkana = ""; for(i = 1; i < kana.length; i = i+3) { newkana = newkana.concat(kana[i-1]); newkana = newkana.concat('2'); newkana = newkana.concat('5'); newkana = newkana.concat(kana[i]); newkana = newkana.concat(kana[i+1]); } var url = "http://www.csse.monash.edu.au/~jwb/audiock.swf?u=kana=" + newkana + "%26kanji=" + newkanji; debugging&&console.log("Audio URL: " + url); document.getElementById('AudioButton').disabled = false; document.getElementById('rev-audio').innerHTML = url; } }; var nextReview = function(reviewList) { //sets up the next item for review //uses functions: // wanakana.bind/unbind var rnd = Math.floor(Math.random()*reviewList.length); var item = reviewList[rnd]; sessionSet('WKSS-item', JSON.stringify(item)); sessionSet('WKSS-rnd', rnd); if (sessionStorage.getItem('User-Stats')){ $("#RevNum").innerHtml = sessionGet('User-Stats').length; } document.getElementById('rev-kanji').innerHTML = item.prompt; document.getElementById('rev-type').innerHTML = item.type; var typeBgColor = 'grey'; if (item.type.toLowerCase() == 'meaning'){ typeBgColor = 'blue'; } else if (item.type.toLowerCase() == 'reading'){ typeBgColor = 'orange'; } else if (item.type.toLowerCase() == 'reverse'){ typeBgColor = 'orange'; } document.getElementById('wkss-type').style.backgroundColor = typeBgColor; $("#rev-solution").removeClass("info"); document.getElementById('rev-solution').innerHTML = item.solution; document.getElementById('rev-index').innerHTML = item.index; //initialise the input field $("#rev-input").focus(); $("#rev-input").removeClass("caution"); $("#rev-input").removeClass("error"); $("#rev-input").removeClass("correct"); $("#rev-input").val(""); //check for alphabet letters and decide to bind or unbind wanakana if (item.solution[0].match(/[a-zA-Z]+/i)) { wanakana.unbind(document.getElementById('rev-input')); $('#rev-input').attr('placeholder','Your response'); $('#rev-input').attr('lang','en'); } else { wanakana.bind(document.getElementById('rev-input')); $('#rev-input').attr('placeholder','答え'); $('#rev-input').attr('lang','ja'); } playAudio(); }; //global to keep track of when a review is in session. var reviewActive = false; var startReview = function() { debugging&&console.log("startReview()"); submit = true; reviewActive = true; //get the review 'list' from session storage, line up the first item in queue var reviewList = sessionGet('User-Review')||[]; nextReview(reviewList); }; /** Review Items */ window.WKSS_review = function () { //is there a session waiting in storage? if(sessionStorage.getItem('User-Review')) { //show the selfstudy window $("#selfstudy").show(); //hide other windows $("#add").hide(); $("#export").hide(); $("#edit").hide(); $("#import").hide(); startReview(); } }; $("body").append(' \ <div id="selfstudy" class="WKSS">\ <button id="SelfstudyCloseBtn" class="wkss-close" type="button"><i class="icon-remove"></i></button>\ <h1>Review<span id="RevNum"></span></h1>\ <div id="wkss-kanji">\ <span id="rev-kanji"></span>\ </div><div id="wkss-type">\ <span id="rev-type"></span><br />\ </div><div id="wkss-solution">\ <span id="rev-solution"></span>\ </div><div id="wkss-input">\ <input type="text" id="rev-input" size="40" placeholder="">\ </div><span id="rev-index" style="display: block;"></span>\ \ <form id="audio-form">\ <label id="AudioButton" class="button">Play audio</label>\ <label id="WrapUpBtn" class="button">Wrap Up</label>\ </form>\ <div id="rev-audio" style="display:none;"></div>\ </div>'); $("#selfstudy").hide(); $("#SelfstudyCloseBtn").click(function () { $("#selfstudy").hide(); $("#rev-input").val(""); reviewActive = false; }); var binarySearch = function(values, target, start, end) { //debugging&&console.log("binarySearch(values: ,target: , start: "+start+", end: "+end+")"); if (start > end) { //start has higher value than target, end has lower value //item belongs between // need to return 'start' with a flag that it hasn't been found //invert sign :) return -(start); //for testing truths // return String(end)+" < "+item.index+" < "+String(start); } //does not exist var middle = Math.floor((start + end) / 2); var value = values[middle]; /*debugging&&console.log("start.index: "+values[start].index); debugging&&console.log("middle.index: "+values[middle].index); debugging&&console.log("end.index: "+values[end].index); */ if (Number(value.index) > Number(target.index)) { return binarySearch(values, target, start, middle-1); } if (Number(value.index) < Number(target.index)) { return binarySearch(values, target, middle+1, end); } return middle; //found! }; var findIndex = function(values, target) { return binarySearch(values, target, 0, values.length - 1); }; $("#WrapUpBtn").click(function() { var sessionList = sessionGet('User-Review')||[]; var statsList = sessionGet('User-Stats')||[]; //if an index in sessionList matches one in statsList, don't delete var sessionI = sessionList.length; var item = sessionGet('WKSS-item')||[]; var arr2 = []; //for every item in sessionList, look for index in statsList, //if not there (-1) delete item from sessionList while (sessionI--){ var index = findIndex(statsList,sessionList[sessionI]); if ((Math.sign(1/index) !== -1)||(sessionList[sessionI].index == item.index)){ arr2.push(sessionList[sessionI]); } } debugging&&console.log(arr2); sessionSet('User-Review', JSON.stringify(arr2)); }); /** Save to list based on .index property * @param {Array.<task>} eList * @param {task} eItem */ var saveToSortedList = function(eList,eItem){ var get = findIndex(eList,eItem); if (Math.sign(1/get) === -1){ eList.splice(-get,0,eItem); } return eList; }; //------- var openInNewTab = function(url) { var win=window.open(url, '_blank'); win.focus(); }; $("#AudioButton").click(function () { openInNewTab(document.getElementById('rev-audio').innerHTML); }); var Rev_Item = function(prompt, kanji, type, solution, index){ this.prompt = prompt; this.kanji = kanji; this.type = type; this.solution = solution; this.index = index; }; var updateSRS = function(stats, voclist) { var now = Date.now(); if (voclist[stats.index].due < now){ //double check that the item was really up for review. if(!stats.numWrong && voclist[stats.index].level < 9) {//all correct (none wrong) voclist[stats.index].level++; } else { stats.numWrong = {}; //Adapted from WaniKani's srs to authentically mimic level downs var o = (stats.numWrong.Meaning||0)+(stats.numWrong.Reading||0)+(stats.numWrong.Reverse||0); var t = voclist[stats.index].level; var r=t>=5?2*Math.round(o/2):1*Math.round(o/2); var n=t-r<1?1:t-r; voclist[stats.index].level = n;//don't stay on 'started' } voclist[stats.index].date = now; voclist[stats.index].due = now + srsObject[voclist[stats.index].level].duration; console.log("Next review in "+ms2str(srsObject[voclist[stats.index].level].duration)); return voclist; } }; var showResults = function() { var statsList = sessionGet('User-Stats')||[]; sessionStorage.clear(); console.log("statslist", statsList); var voclist = StorageUtil.getVocList(); statsList.forEach(function(stats, i, statsList){ debugging&&console.log("stats",stats); var altText = voclist[stats.index].level;//+stats.type; if (stats.numWrong) { if (stats.numWrong.Meaning) altText = altText + " Meaning Wrong x"+stats.numWrong.Meaning +"\n"; if (stats.numWrong.Reading) altText = altText + " Reading Wrong x"+stats.numWrong.Reading +"\n"; if (stats.numWrong.Reverse) altText = altText + " Reverse Wrong x"+stats.numWrong.Reverse +"\n"; } if (stats.numCorrect){ if (stats.numCorrect.Meaning) altText = altText + " Meaning Correct x"+stats.numCorrect.Meaning +"\n"; if (stats.numCorrect.Reading) altText = altText + " Reading Correct x"+stats.numCorrect.Reading +"\n"; if (stats.numCorrect.Reverse) altText = altText + " Reverse Correct x"+stats.numCorrect.Reverse +"\n"; } console.log(stats); //TODO sort into apprentice, guru, etc document.getElementById("stats-a").innerHTML += "<span class=" + (stats.numWrong? "\"rev-error\"":"\"rev-correct\"") + " title='"+altText+"'>" + stats.kanji + "</span>"; //map with side effects? statsList[i] = updateSRS(stats, voclist); }, this); sessionSet("User-Stats",statsList); localSet("User-Vocab", voclist); }; $("body").append(' \ <div id="resultwindow" class="WKSS"> \ <button id="ReviewresultsCloseBtn" class="wkss-close" type="button"><i class="icon-remove"></i></button>\ <h1>Review Results</h1>\ <h2>All</h2>\ <div id="stats-a"></div>\ </div>'); $("#resultwindow").hide(); $("#ReviewresultsCloseBtn").click(function () { $("#resultwindow").hide(); document.getElementById("stats-a").innerHTML = ""; }); var markAnswer = function(item) { //evaluate 'item' against the question. // match by index // get type of question // determine if right or wrong and return result appropriately //get the question //var prompt = document.getElementById('rev-kanji').innerHTML.trim(); //get the answer var answer = $("#rev-input").val().toLowerCase(); //get the index var index = document.getElementById('rev-index').innerHTML.trim(); //get the question type var type = document.getElementById('rev-type').innerHTML.trim(); //var vocab = localGet("User-Vocab"); //get the item if it is in the current session var storedItem = sessionGet(item.index); if (storedItem){ item.numCorrect = storedItem.numCorrect; item.numWrong = storedItem.numWrong; } if (index == item.index){//------------- if (inputCorrect()){ debugging&&console.log(answer+"/"+item.solution[0]); if (!item.numCorrect){ debugging&&console.log("initialising numCorrect"); item.numCorrect={}; } debugging&&console.log("Correct: "+ type); if (type == "Meaning"){ if (!item.numCorrect.Meaning) item.numCorrect.Meaning = 0; item.numCorrect.Meaning++; } if (type == "Reading"){ if (!item.numCorrect.Reading) item.numCorrect.Reading = 0; item.numCorrect.Reading++; } if (type == "Reverse"){ if (!item.numCorrect.Reverse) item.numCorrect.Reverse = 0; item.numCorrect.Reverse++; } }else{ debugging&&console.log(answer+"!="+item.solution); if (!item.numWrong){ debugging&&console.log("initialising numCorrect"); item.numWrong={}; } debugging&&console.log("Wrong: "+ type); if (type == "Meaning"){ if (!item.numWrong.Meaning) item.numWrong.Meaning = 0; item.numWrong.Meaning++; } if (type == "Reading"){ if (!item.numWrong.Reading) item.numWrong.Reading = 0; item.numWrong.Reading++; } if (type == "Reverse"){ if (!item.numWrong.Reverse) item.numWrong.Reverse = 0; item.numWrong.Reverse++; } } } else { console.error("Error: indexes don't match"); } return item; }; //jquery keyup event $("#rev-input").keyup(ReviewUtil.submitResponse); /** Adds the Button */ var addUserVocabButton = function() { debugging&&console.log("addUserVocabButton()"); //Functions (indirect) // WKSS_add() // WKSS_edit() // WKSS_export() // WKSS_import() // WKSS_lock() // WKSS_review() var nav = document.getElementsByClassName('nav'); debugging&&console.log("generating review list because: initialising script and populating reviews"); if (nav&&nav.length>2) { nav[2].innerHTML = nav[2].innerHTML + "\n\ <li class=\"dropdown custom\">\n\ <a class=\"dropdown-toggle custom\" data-toggle=\"dropdown\" href=\"#\" onclick=\"generateReviewList();\">\n\ <span lang=\"ja\">自習</span>\n\ Self-Study <i class=\"icon-chevron-down\"></i>\n\ </a>\n\ <ul class=\"dropdown-menu\" id=\"WKSS_dropdown\">\n\ <li class=\"nav-header\">Customize</li>\n\ <li><a id=\"click\" href=\"#\" onclick=\"WKSS_add();\">Add</a></li>\n\ <li><a href=\"#\" onclick=\"WKSS_edit();\">Edit</a></li>\n\ <li><a href=\"#\" onclick=\"WKSS_export();\">Export</a></li>\n\ <li><a href=\"#\" onclick=\"WKSS_import();\">Import</a></li>\n\ <!--// <li><a href=\"#\" onclick=\"WKSS_lock();\">Server Settings</a></li>//-->\n\ <li class=\"nav-header\">Learn</li>\n\ <li><a id=\"user-review\" href=\"#\" onclick=\"WKSS_review();\">Please wait...</a></li>\n\ </ul>\n\ </li>"; }else{ console.error("could not find nav", nav); } console.log("addUserVocab"); }; /** Error handling * Can use 'error.stack', not cross-browser (though it should work on Firefox and Chrome) */ var logError = function(error) { debugging&&console.log("logError(error)"); var stackMessage = ""; if ("stack" in error) stackMessage = "\n\tStack: " + error.stack; debugging&&console.log("WKSS: Error: " + error.name + "\n\tMessage: " + error.message + stackMessage); console.error("WKSS: Error: " + error.name + "\n\tMessage: " + error.message + stackMessage); }; /** Prepares the script */ var scriptInit = function() { debugging&&console.log("scriptInit()"); //functions: // addUserVocabButton() // logError(err) debugging&&console.log("Initializing Wanikani UserVocab Script!"); gM_addStyle(".custom .dropdown-menu {background-color: #DBA901 !important;}"); gM_addStyle(".custom .dropdown-menu:after {border-bottom-color: #DBA901 !important;"); gM_addStyle(".custom .dropdown-menu:before {border-bottom-color: #DBA901 !important;"); gM_addStyle(".open .dropdown-toggle.custom {background-color: #FFC400 !important;}"); gM_addStyle(".custom .dropdown-menu a:hover {background-color: #A67F00 !important;}"); gM_addStyle(".custom:hover {color: #FFC400 !important;}"); gM_addStyle(".custom:hover span {border-color: #FFC400 !important;}"); gM_addStyle(".custom:focus {color: #FFC400 !important;}"); gM_addStyle(".custom:focus span {border-color: #FFC400 !important;}"); gM_addStyle(".open .custom span {border-color: #FFFFFF !important;}"); gM_addStyle(".open .custom {color: #FFFFFF !important}"); var wkStyleCSS = require('./wkstyle.js'); gM_addStyle(wkStyleCSS); // Set up buttons try { if (typeof localStorage !== "undefined") { addUserVocabButton(); //provide warning to users trying to use the (incomplete) script. debugging&&console.log("this script is still incomplete: \n\ It is provided as is without warranty express or implied\n\ in the hope that you may find it useful."); } else { debugging&&console.log("Wanikani Self-Study: Your browser does not support localStorage.. Sorry :("); } } catch (err) { logError(err); } }; console.info(document.readyState); console.log("adding DOM listener", document.readyState); // Check for file API support. if (window.File && window.FileReader && window.FileList && window.Blob) { } else { alert('The File APIs are not fully supported in this browser.'); } /** Start the script */ //unless the user navigated from the review directory, they are unlikely to have unlocked any kanji var noNewStuff = /^https:\/\/.*\.wanikani\.com\/.*/.test(document.referrer)&&!(/https:\/\/.*\.wanikani\.com\/review.*/.test(document.referrer)); var usingHTTPS = /^https:/.test(window.location.href); console.info(usingHTTPS, window.location.href); if (usingHTTPS){ if (!noNewStuff){ //Don't waste time if user is browsing site WanikaniUtil.getServerResp(APIkey); }else{ debugging&&console.log("User is unlikely to have new kanji unlocked"); } debugging&&console.info("WaniKani Self-Study Plus is about to start"); scriptInit(); }else{ debugging&&console.warn("It appears that you are not using https protocol. Attempting to redirect to https now."); window.location.href = window.location.href.replace(/^http/, "https"); } } if (document.readyState === 'complete'){ console.info("About to initialise WKSS+"); main(); } else { window.addEventListener("load", main, false); } },{"./addelement.js":1,"./buildnode.js":2,"./buildwindow.js":3,"./handleAddClick.js":4,"./importutil.js":6,"./storageutil.js":7,"./wanikaniutil.js":9,"./wkstyle.js":11}],9:[function(require,module,exports){ /** Utilities for interaction with the Wanikani API and general website. */ var WanikaniUtil = { hijackRequests: require('./hijackrequests.js'), createCORSRequest: function(method, url){ var xhr = new XMLHttpRequest(); if ("withCredentials" in xhr){ xhr.open(method, url, true); } else if (typeof XDomainRequest !== "undefined"){ xhr = new XDomainRequest(); xhr.open(method, url); } else { xhr = null; } return xhr; }, /** Gets the user information using the Wanikani API and stores them directly into browser storage. * @param * @param */ getServerResp: function(APIkey, requestedItem){ requestedItem = requestedItem === void 0 ? 'kanji' :requestedItem; if (APIkey !== "test"){ var levels = (requestedItem ==="kanji")? "/1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50": "/1,2,3,4,5,6,7,8,9,10"; var xhrk = this.createCORSRequest("get", "https://www.wanikani.com/api/user/" + APIkey + "/" + requestedItem + levels); if (!isEmpty(xhrk)){ xhrk.onreadystatechange = function() { if (xhrk.readyState == 4){ var kanjiList = this.handleReadyStateFour(xhrk,requestedItem); if (requestedItem === 'kanji'){ localSet('User-KanjiList', kanjiList); console.log("kanjiList from server", kanjiList); //update locks in localStorage //pass kanjilist into this function //(don't shift things through storage unecessarily) refreshLocks(); } else{ var v = kanjiList.length; console.log(v + " items found, attempting to import"); while (v--){ StorageUtil.setVocItem(kanjiList[v]); } } } }; xhrk.send(); console.log("below"); } } else { //dummy server response for testing. setTimeout(function () { var kanjiList = []; console.log("creating dummy response"); kanjiList.push({"character": "猫", "srs": "noServerResp"}); var SRS = "apprentice"; //prompt("enter SRS for 子", "guru"); kanjiList.push({"character": "子", "srs": SRS}); kanjiList.push({"character": "品", "srs": "guru"}); kanjiList.push({"character": "供", "srs": "guru"}); kanjiList.push({"character": "本", "srs": "guru"}); kanjiList.push({"character": "聞", "srs": "apprentice"}); kanjiList.push({"character": "人", "srs": "enlightened"}); kanjiList.push({"character": "楽", "srs": "burned"}); kanjiList.push({"character": "相", "srs": "guru"}); kanjiList.push({"character": "卒", "srs": "noMatchWK"}); kanjiList.push({"character": "無", "srs": "noMatchGuppy"}); console.log("Server responded with dummy kanjiList: \n"+JSON.stringify(kanjiList)); localSet('User-KanjiList', kanjiList); //update locks in localStorage refreshLocks(); }, 10000); } }, handleReadyStateFour: function(xhrk, requestedItem){ var localkanjiList = []; console.log("readystate: "+ xhrk.readyState); var resp = JSON.parse(xhrk.responseText); console.log("about to loop through requested information"); if (resp.requested_information && resp.requested_information.length){ localkanjiList = resp.requested_information.map(function(requestedTask){ if (requestedItem === "kanji"){ if (requestedTask.user_specific !== null){ return { character: requestedTask.character, srs: requestedTask.user_specific.srs, reading: requestedTask[requestedTask.important_reading].split(",")[0], meaning: requestedTask.meaning.split(",")[0] }; } else{ return { character: requestedTask.character, srs: "unreached" }; } } else if(requestedItem === "vocabulary"){ if (requestedTask.user_specific !== null||true){ //-- //build vocablist return { kanji: requestedTask.character, reading: requestedTask.kana.split(","), meaning: requestedTask.meaning.split(",") }; } } }, this); } //return kanjiList // console.log("Server responded with new kanjiList: \n"+JSON.stringify(kanjiList)); return localkanjiList; } }; },{"./hijackrequests.js":5}],10:[function(require,module,exports){ // Window Configs module.exports = { add:{height: "300px", width: "300px"}, exportImport:{height: "275px", width: "390px"}, edit:{height: "380px", width: "800px"}, study:{height: "auto", width: "600px"}, //height : auto result:{height: "500px", width: "700px"} }; },{}],11:[function(require,module,exports){ /* jshint multistr: true */ // Config for window sizes in pixels var windowConfig = require('./windowconfig.js'); //.WKSS var classWKSS = [ {position: "fixed"}, {zIndex: "2"}, {top: "125px"}, {left: "50%"}, {margin: "0px"}, {background: "#FFF"}, {padding: "5px"}, {font: "12px \"ヒラギノ角ゴ Pro W3\", \"Hiragino Kaku Gothic Pro\",Osaka, \"メイリオ\", Meiryo, \"MS Pゴシック\", \"MS PGothic\", sans-serif"}, {color: "#888"}, {textShadow: "1px 1px 1px #FFF"}, {border: "1px solid #DDD"}, {borderRadius: "5px"}, {WebkitBorderRadius: "5px"}, {MozBorderRadius: "5px"}, {boxShadow: "10px 10px 5px #888888"} ]; //.WKSS h1 var classWKSS_h1 = [ {font: "25px \"ヒラギノ角ゴ Pro W3\", \"Hiragino Kaku Gothic Pro\",Osaka, \"メイリオ\", Meiryo, \"MS Pゴシック\", \"MS PGothic\", sans-serif"}, {paddingLeft: "5px"}, {display: "block"}, {borderBottom: "1px solid #DADADA"}, {margin: "0px"}, {color: "#888"} ]; //.WKSS h1 > span var classWKSS_h1_direct_Span = [ {display: "block"}, {fontSize: "11px"} ]; //.WKSS label var w = [ {display: "block"}, {margin: "0px 0px 5px"}, ]; //.WKSS label>span w = [ {float: "left"}, {width: "80px"}, {textAlign: "right"}, {paddingRight: "10px"}, {marginTop: "10px"}, {color: "#333"}, {fontFamily: "\"ヒラギノ角ゴ Pro W3\", \"Hiragino Kaku Gothic Pro\",Osaka, \"メイリオ\", Meiryo, \"MS Pゴシック\", \"MS PGothic\", sans-serif"}, {fontWeight: "bold"} ]; //.WKSS input[type=\"text\"], .WKSS input[type=\"email\"], .WKSS textarea w = [ {border: "1px solid #CCC"}, {color: "#888"}, {height: "20px"}, {marginBottom: "16px"}, {marginRight: "6px"}, {marginTop: "2px"}, {outline: "0 none"}, {padding: "6px 12px"}, {width: "80%"}, {borderRadius: "4px"}, {lineHeight: "normal !important"}, {WebkitBorderRadius: "4px"}, {MozBorderRadius: "4px"}, {font: "normal 14px/14px \"ヒラギノ角ゴ Pro W3\", \"Hiragino Kaku Gothic Pro\",Osaka, \"メイリオ\", Meiryo, \"MS Pゴシック\", \"MS PGothic\", sans-serif"}, {WebkitBoxShadow: "inset 0 1px 1px rgba(0, 0, 0, 0.075)"}, {boxShadow: "inset 0 1px 1px rgba(0, 0, 0, 0.075)"}, {MozBoxShadow: "inset 0 1px 1px rgba(0, 0, 0, 0.075)"} ]; //.WKSS select w = [ {border: "1px solid \"#CCC\""}, {color: "#888"}, {outline: "0 none"}, {padding: "6px 12px"}, {height: "160px !important"}, {width: "95%"}, {borderRadius: "4px"}, {WebkitBorderRadius: "4px"}, {MozBorderRadius: "4px"}, {font: "normal 14px/14px \"ヒラギノ角ゴ Pro W3\", \"Hiragino Kaku Gothic Pro\",Osaka, \"メイリオ\", Meiryo, \"MS Pゴシック\", \"MS PGothic\", sans-serif"}, {WebkitBoxShadow: "inset 0 1px 1px rgba(0, 0, 0, 0.075)"}, {boxShadow: "inset 0 1px 1px rgba(0, 0, 0, 0.075)"}, {MozBoxShadow: "inset 0 1px 1px rgba(0, 0, 0, 0.075)"}, {background: "#FFF url('down-arrow.png') no-repeat right"}, {appearance: "none"}, {WebkitAppearance: "none"}, {MozAppearance: "none"}, {textIndent: "0.01px"}, {textOverflow: "''"} ]; //.WKSS textarea w = [ {height: "100px"} ]; //.WKSS button, .button w = [ {position: "relative"}, {background: "#FFF"}, {border: "1px solid #CCC"}, {padding: "10px 25px 10px 25px"}, {color: "#333"}, {borderRadius: "4px"}, {display: "inline !important"} ]; //.WKSS button:disabled w = [ {background: "#EBEBEB"}, {border: "1px solid #CCC"}, {padding: "10px 25px 10px 25px"}, {color: "#333"}, {borderRadius: "4px"} ]; //.WKSS .button:hover, button:hover:enabled w = [ {color: "#333"}, {backgroundColor: "#EBEBEB"}, {borderColor: "#ADADAD"} ]; //.WKSS button:hover:disabled w = [ {cursor: "default"} ]; //.error w = [ {borderColor:"#F00 !important"}, {color: "#F00 !important"} ]; //.caution w = [ {borderColor: "#F90 !important"}, {color: "#F90 !important"} ]; //.correct w = [ {borderColor: "#0F0 !important"}, {color: "#0F0 !important"} ]; //.info w = [ {borderColor: "#696969 !important"}, {color: "#696969 !important"} ]; //.rev-error w = [ {textShadow: "none"}, {border: "1px solid #F00 !important"}, {borderRadius: "10px"}, {backgroundColor: "#F00"}, {padding: "4px"}, {margin: "4px"}, {color: "#FFFFFF"}, {font: "normal 18px \"ヒラギノ角ゴ Pro W3\", \"Hiragino Kaku Gothic Pro\",Osaka, \"メイリオ\", Meiryo, \"MS Pゴシック\", \"MS PGothic\", sans-serif"} ]; //.rev-correct w = [ {textShadow:"none"}, {border: "1px"}, {solid: "#088A08 !important"}, {borderRadius: "10px"}, {backgroundColor: "#088A08"}, {padding: "4px"}, {margin:"4px"}, {color: "#FFFFFF"}, {font: "normal 18px \"ヒラギノ角ゴ Pro W3\", \"Hiragino Kaku Gothic Pro\",Osaka, \"メイリオ\", Meiryo, \"MS Pゴシック\", \"MS PGothic\", sans-serif"} ]; //#add w = [ {width: windowConfig.add.width}, {height: windowConfig.add.height}, {marginLeft: -windowConfig.add.width/2} ]; //#export, #import w = [ {background: "#fff"}, {width: windowConfig.exportImport.width}, {height: windowConfig.exportImport.height}, {marginLeft: -windowConfig.exportImport.width/2} ]; //#edit w = [ {width: windowConfig.edit.width}, {height: windowConfig.edit.height}, {marginLeft: -windowConfig.edit.width/2} ]; //#selfstudy w = [ {left: "50%"}, {width: windowConfig.study.width}, {height: windowConfig.study.height}, {marginLeft: -windowConfig.study.width/2} ]; //#resultwindow w = [ {left:"50%"}, {width: windowConfig.result.width + "px"}, {height: windowConfig.result.height + "px"}, {marginLeft: -windowConfig.result.width/2 + "px"} ]; //#AudioButton w = [ {marginTop: "35px"}, {position: "relative"}, {display: "inline !important"}, {WebkitMarginBefore: "50px"} ]; //button.wkss-close w = [ {float: "right"}, {backgroundColor: "#ff4040"}, {color: "#fff"}, {padding: "0px"}, {height: "27px"}, {width: "27px"} ]; //#wkss-close w = [ {float: "right"}, {backgroundColor: "#ff4040"}, {color: "#fff"}, {padding: "0px"}, {height: "27px"}, {width: "27px"} ]; //#wkss-kanji, #rev-kanji w = [ {textAlign: "center !important"}, {fontSize: "50px !important"}, {backgroundColor: "#9400D3 !important"}, {color: "#FFFFFF !important"}, {borderRadius: "10px 10px 0px 0px"} ]; //#wkss-solution, #rev-solution w = [ {textAlign: "center !important"}, {fontSize: "30px !important"}, {color: "#FFFFFF"}, {padding: "2px"} ]; //#wkss-type w = [ {textAlign: "center !important"}, {fontSize: "24px !important"}, {backgroundColor: "#696969"}, {color: "#FFFFFF !important"}, {borderRadius: "0px 0px 10px 10px"} ]; //#rev-type w = [ {textAlign: "center !important"}, {fontSize: "24px !important"}, {color: "#FFFFFF !important"}, {borderRadius: "0px 0px 10px 10px"} ]; //#wkss-input w = [ {textAlign: "center !important"}, {fontSize: "40px !important"}, {height: "80px !important"}, {lineHeight: "normal !important"} ]; //#rev-input w = [ {textAlign: "center !important"}, {fontSize: "40px !important"}, {height: "60px !important"}, {lineHeight: "normal !important"} ]; //---- module.exports = classWKSS; //module.exports = wkstyleCSS; },{"./windowconfig.js":10}]},{},[8]) //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJzcmMvYWRkZWxlbWVudC5qcyIsInNyYy9idWlsZG5vZGUuanMiLCJzcmMvYnVpbGR3aW5kb3cuanMiLCJzcmMvaGFuZGxlQWRkQ2xpY2suanMiLCJzcmMvaGlqYWNrcmVxdWVzdHMuanMiLCJzcmMvaW1wb3J0dXRpbC5qcyIsInNyYy9zdG9yYWdldXRpbC5qcyIsInNyYy90cnVuay5qcyIsInNyYy93YW5pa2FuaXV0aWwuanMiLCJzcmMvd2luZG93Y29uZmlnLmpzIiwic3JjL3drc3R5bGUuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDL01BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9IQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JnRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNQQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsInZhciBidWlsZE5vZGUgPSByZXF1aXJlKCcuL2J1aWxkbm9kZS5qcycpO1xyXG5cclxuLy8gQ3JlYXRlIERPTSBmb3IgJ2FkZCcgd2luZG93XHJcbnZhciBhZGRFbGVtZW50ID0gYnVpbGROb2RlKCdkaXYnLCB7aWQ6IFwiYWRkXCIsIGNsYXNzTmFtZTogXCJXS1NTXCJ9KTtcclxuXHJcbnZhciBmb3JtRWxlbWVudCA9IGJ1aWxkTm9kZSgnZm9ybScsIHtpZDogXCJhZGRGb3JtXCJ9KTtcclxuYWRkRWxlbWVudC5hcHBlbmRDaGlsZChmb3JtRWxlbWVudCk7XHJcblxyXG52YXIgYnV0dG9uRWxlbWVudCA9IGJ1aWxkTm9kZSgnYnV0dG9uJywge2lkOiBcIkFkZENsb3NlQnRuXCIsIGNsYXNzTmFtZTogXCJ3a3NzLWNsb3NlXCIsIHR5cGU6IFwicmVzZXRcIn0pO1xyXG5mb3JtRWxlbWVudC5hcHBlbmRDaGlsZChidXR0b25FbGVtZW50KTtcclxuXHJcbnZhciBpY29uRWxlbWVudCA9IGJ1aWxkTm9kZSgnaScsIHtjbGFzc05hbWU6IFwiaWNvbi1yZW1vdmVcIn0pO1xyXG5idXR0b25FbGVtZW50LmFwcGVuZENoaWxkKGljb25FbGVtZW50KTtcclxuXHJcbnZhciBoZWFkZXJFbGVtZW50ID0gYnVpbGROb2RlKCdoMScpO1xyXG5mb3JtRWxlbWVudC5hcHBlbmRDaGlsZChoZWFkZXJFbGVtZW50KTtcclxuXHJcbnZhciBoZWFkZXJUZXh0ID0gZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoXCJBZGQgYSBuZXcgSXRlbVwiKTtcclxuaGVhZGVyRWxlbWVudC5hcHBlbmRDaGlsZChoZWFkZXJUZXh0KTtcclxuXHJcbnZhciBpbnB1dEthbmppRWxlbWVudCA9IGJ1aWxkTm9kZSgnaW5wdXQnLCB7aWQ6IFwiYWRkS2FuamlcIiwgdHlwZTogXCJ0ZXh0XCIsIHBsYWNlaG9sZGVyOiBcIkVudGVyIOa8ouWtlywg44Gy44KJ44GM44GqIG9yIOOCq+OCv+OCq+ODilwifSk7XHJcbmZvcm1FbGVtZW50LmFwcGVuZENoaWxkKGlucHV0S2FuamlFbGVtZW50KTtcclxuXHJcbnZhciBpbnB1dFJlYWRpbmdFbGVtZW50ID0gYnVpbGROb2RlKCdpbnB1dCcsIHtpZDogXCJhZGRSZWFkaW5nXCIsIHR5cGU6IFwidGV4dFwiLCB0aXRsZTogXCJMZWF2ZSBlbXB0eSB0byBhZGQgdm9jYWJ1bGFyeSBsaWtlIOOBmeOCiyAodG8gZG8pXCIsIHBsYWNlaG9sZGVyOiBcIkVudGVyIHJlYWRpbmdcIn0pO1xyXG5mb3JtRWxlbWVudC5hcHBlbmRDaGlsZChpbnB1dFJlYWRpbmdFbGVtZW50KTtcclxuXHJcbnZhciBpbnB1dE1lYW5pbmdFbGVtZW50ID0gYnVpbGROb2RlKCdpbnB1dCcsIHtpZDogXCJhZGRNZWFuaW5nXCIsIHR5cGU6IFwidGV4dFwiLCBwbGFjZWhvbGRlcjogXCJFbnRlciBtZWFuaW5nXCJ9KTtcclxuZm9ybUVsZW1lbnQuYXBwZW5kQ2hpbGQoaW5wdXRNZWFuaW5nRWxlbWVudCk7XHJcblxyXG52YXIgcEVsZW1lbnQgPSBidWlsZE5vZGUoJ3AnLCB7aWQ6IFwiYWRkU3RhdHVzXCJ9KTtcclxuZm9ybUVsZW1lbnQuYXBwZW5kQ2hpbGQocEVsZW1lbnQpO1xyXG5cclxudmFyIHBUZXh0ID0gZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoXCJSZWFkeSB0byBhZGQuLlwiKTtcclxucEVsZW1lbnQuYXBwZW5kQ2hpbGQocFRleHQpO1xyXG5cclxudmFyIGV4ZWNCdXR0b25FbGVtZW50ID0gYnVpbGROb2RlKCdidXR0b24nLCB7aWQ6IFwiQWRkSXRlbUJ0blwiLCB0eXBlOiBcImJ1dHRvblwifSk7XHJcbmZvcm1FbGVtZW50LmFwcGVuZENoaWxkKGV4ZWNCdXR0b25FbGVtZW50KTtcclxuXHJcbnZhciBleGVjVGV4dCA9IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKFwiQWRkIG5ldyBJdGVtXCIpO1xyXG5leGVjQnV0dG9uRWxlbWVudC5hcHBlbmRDaGlsZChleGVjVGV4dCk7XHJcblxyXG5tb2R1bGUuZXhwb3J0cyA9IGFkZEVsZW1lbnQ7IiwiLyoqIEJ1aWxkcyBhIG5vZGUgZWxlbWVudCB3aXRoIGFuIGlkIGFuZCBjbGFzc05hbWUgYW5kIG90aGVyIGF0dHJpYnV0ZXMgaWYgcHJvdmlkZWRcclxuKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSB0eXBlIG9mIGVsZW1lbnQgdG8gY3JlYXRlICgnZGl2JywgJ3AnLCBldGMuLi4pXHJcbiogQHBhcmFtIHtvYmplY3R9IFtvcHRpb25zXVxyXG4qIEBwYXJhbSB7c3RyaW5nfSBvcHRpb25zLmlkIC0gVGhlIGlkIG9mIHRoZSBub2RlXHJcbiogQHBhcmFtIHtzdHJpbmd9IG9wdGlvbnMuY2xhc3NOYW1lIC0gT25lIG9yIG1vcmUgY2xhc3NlcyBmb3IgdGhlIGVsZW1lbnQgc2VwZXJhdGVkIGJ5IHNwYWNlc1xyXG4qIEByZXR1cm5zIHtIVE1MRWxlbWVudH0gVGhlIG5vZGUgYnVpbHQgYXMgc3BlY2lmaWVkXHJcbiovXHJcbnZhciBidWlsZE5vZGUgPSBmdW5jdGlvbih0eXBlLCBvcHRpb25zKXtcclxuXHR2YXIgbm9kZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodHlwZSk7XHJcblx0Zm9yICh2YXIgb3B0aW9uIGluIG9wdGlvbnMpIGlmIChvcHRpb25zLmhhc093blByb3BlcnR5KG9wdGlvbikpIHtcclxuXHRcdGlmIChvcHRpb24gPT09IFwiY2xhc3NOYW1lXCIgfHwgb3B0aW9uID09PSBcImlkXCIpe1xyXG5cdFx0XHRub2RlW29wdGlvbl0gPSBvcHRpb25zW29wdGlvbl07XHJcblx0XHR9XHJcblx0XHRlbHNlIHtcclxuXHRcdFx0bm9kZS5zZXRBdHRyaWJ1dGUob3B0aW9uLCBvcHRpb25zW29wdGlvbl0pO1xyXG5cdFx0fVxyXG5cdH1cclxuXHRyZXR1cm4gbm9kZTtcclxufTtcclxuXHJcbm1vZHVsZS5leHBvcnRzID0gYnVpbGROb2RlOyIsInZhciBidWlsZE5vZGUgPSByZXF1aXJlKCcuL2J1aWxkbm9kZS5qcycpO1xyXG5cclxuLy8gdGFnLCBpZCwgY2xhc3NOYW1lLCBvdGhlciwgY2hpbGROb2Rlc1xyXG5cclxuLyogSVdpbmRvdzpcclxuXHJcbntcclxuXHRpZDogXCJXS1NTLWVkaXRcIixcclxuXHRjbGFzc05hbWU6IFwiV0tTU1wiLFxyXG5cdGNoaWxkTm9kZXM6W3tcclxuXHRcdHRhZzogJ2Zvcm0nLFxyXG5cdFx0aWQ6IFwiV0tTUy1lZGl0Rm9ybVwiLFxyXG5cdFx0Y2hpbGROb2Rlczpbe1xyXG5cdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRpZDogXCJXS1NTLWVkaXRDbG9zZUJ0blwiLFxyXG5cdFx0XHRjbGFzc05hbWU6IFwiV0tTUy1jbG9zZVwiXHJcblx0XHRcdGNoaWxkTm9kZXM6W3tcclxuXHRcdFx0XHR0YWc6ICdpJyxcclxuXHRcdFx0XHRjbGFzc05hbWU6IFwiaWNvbi1yZW1vdmVcIlxyXG5cdFx0XHR9XVxyXG5cdFx0fSx7XHJcblx0XHRcdHRhZzogJ2gxJyxcclxuXHRcdFx0Y2hpbGROb2RlczpbXHJcblx0XHRcdFx0XCJFZGl0IHlvdXIgVm9jYWJcIiAgICAgICAgICAgICAgICAgPC0tLSBzdHJpbmcgdHlwZXMgZm9yIHRleHQgbm9kZVxyXG5cdFx0XHRdXHJcblx0XHR9LHtcclxuXHRcdFx0dGFnOiAnc2VsZWN0JyxcclxuXHRcdFx0aWQ6IFwiZWRpdFdpbmRvd1wiLFxyXG5cdFx0XHRvdGhlcjoge3NpemU6IFwiOFwifVx0XHRcdFx0XHQ8LS0tICdvdGhlcicgYXZvaWRzIGNsYXNoZXMgd2l0aCBIVE1MRWxlbWVudCBhdHRyaWJ1dGVzIGp1c3QgaW4gY2FzZVxyXG5cdFx0fSx7XHJcblx0XHRcdHRhZzogJ2lucHV0JywgXHJcblx0XHRcdG90aGVyOntcclxuXHRcdFx0XHR0eXBlOiBcInRleHRcIixcclxuXHRcdFx0XHRuYW1lOiBcIlwiLFxyXG5cdFx0XHRcdHNpemU6IFwiNDBcIixcclxuXHRcdFx0XHRwbGFjZWhvbGRlcjogXCJTZWxlY3Qgdm9jYWIsIGNsaWNrIGVkaXQsIGNoYW5nZSBhbmQgc2F2ZSFcIlxyXG5cdFx0XHR9LFxyXG5cdFx0XHRpZDogXCJlZGl0SXRlbVwiXHJcblx0XHR9LHtcclxuXHRcdFx0dGFnOiAncCcsIFxyXG5cdFx0XHRpZDogXCJlZGl0U3RhdHVzXCJcclxuXHRcdFx0Y2hpbGROb2RlczpbXCJSZWFkeSB0byBlZGl0Li4uXCJdXHJcblx0XHR9LHtcclxuXHRcdFx0dGFnOiAnYnV0dG9uJyxcclxuXHRcdFx0aWQ6IFwiRWRpdEVkaXRCdG5cIixcclxuXHRcdFx0b3RoZXI6IHt0eXBlOiBcImJ1dHRvblwifSxcclxuXHRcdFx0Y2hpbGROb2RlczpbXCJFZGl0XCJdXHJcblx0XHR9LHtcclxuXHRcdFx0dGFnOiAnYnV0dG9uJyxcclxuXHRcdFx0aWQ6IFwiRWRpdFNhdmVCdG5cIixcclxuXHRcdFx0b3RoZXI6e3R5cGU6IFwiYnV0dG9uXCJ9LFxyXG5cdFx0XHRjaGlsZE5vZGVzOltcIlNhdmVcIl1cclxuXHRcdH0se1xyXG5cdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRpZDogXCJFZGl0RGVsZXRlQnRuXCIsXHJcblx0XHRcdG90aGVyOiB7dHlwZTogXCJidXR0b25cIiwgdGl0bGU6IFwiRGVsZXRlIHNlbGVjdGVkIGl0ZW1cIn0sXHJcblx0XHRcdGNoaWxkTm9kZXM6W1wiRGVsZXRlXCJdXHJcblx0XHR9LHtcclxuXHRcdFx0dGFnOiAnYnV0dG9uJyxcclxuXHRcdFx0aWQ6IFwiRWRpdERlbGV0ZUFsbEJ0blwiLFxyXG5cdFx0XHRvdGhlcjoge3R5cGU6IFwiYnV0dG9uXCIsIHRpdGxlOiBcIuacrOW9k+OBq+OChOOCi+OBru+8n1wifSxcclxuXHRcdFx0Y2hpbGROb2RlczpbXCJEZWxldGUgQWxsXCJdXHJcblx0XHR9LHtcclxuXHRcdFx0dGFnOiAnYnV0dG9uJyxcclxuXHRcdFx0aWQ6IFwiUmVzZXRMZXZlbHNCdG5cIixcclxuXHRcdFx0b3RoZXI6IHt0eXBlOiBcImJ1dHRvblwifSxcclxuXHRcdFx0Y2hpbGROb2RlczpbXCJSZXNldCBsZXZlbHNcIl1cclxuXHRcdH1dXHJcblx0fV1cclxufVxyXG5cclxuKi9cclxuXHJcbnZhciBzdHJ1Y3QgPSB7XHJcblx0aWQ6IFwiV0tTUy1lZGl0XCIsXHJcblx0Y2xhc3NOYW1lOiBcIldLU1NcIixcclxuXHRjaGlsZE5vZGVzOlt7XHJcblx0XHR0YWc6ICdmb3JtJyxcclxuXHRcdGlkOiBcIldLU1MtZWRpdEZvcm1cIixcclxuXHRcdGNoaWxkTm9kZXM6W3tcclxuXHRcdFx0dGFnOiAnYnV0dG9uJyxcclxuXHRcdFx0aWQ6IFwiV0tTUy1lZGl0Q2xvc2VCdG5cIixcclxuXHRcdFx0Y2xhc3NOYW1lOiBcIldLU1MtY2xvc2VcIixcclxuXHRcdFx0Y2hpbGROb2Rlczpbe1xyXG5cdFx0XHRcdHRhZzogJ2knLFxyXG5cdFx0XHRcdGNsYXNzTmFtZTogXCJpY29uLXJlbW92ZVwiXHJcblx0XHRcdH1dXHJcblx0XHR9LHtcclxuXHRcdFx0dGFnOiAnaDEnLFxyXG5cdFx0XHRjaGlsZE5vZGVzOltcIkVkaXQgeW91ciBWb2NhYlwiXVxyXG5cdFx0fSx7XHJcblx0XHRcdHRhZzogJ3NlbGVjdCcsXHJcblx0XHRcdGlkOiBcImVkaXRXaW5kb3dcIixcclxuXHRcdFx0b3RoZXI6IHtzaXplOiBcIjhcIn1cclxuXHRcdH0se1xyXG5cdFx0XHR0YWc6ICdpbnB1dCcsIFxyXG5cdFx0XHRvdGhlcjp7XHJcblx0XHRcdFx0dHlwZTogXCJ0ZXh0XCIsXHJcblx0XHRcdFx0bmFtZTogXCJcIixcclxuXHRcdFx0XHRzaXplOiBcIjQwXCIsXHJcblx0XHRcdFx0cGxhY2Vob2xkZXI6IFwiU2VsZWN0IHZvY2FiLCBjbGljayBlZGl0LCBjaGFuZ2UgYW5kIHNhdmUhXCJcclxuXHRcdFx0fSxcclxuXHRcdFx0aWQ6IFwiZWRpdEl0ZW1cIlxyXG5cdFx0fSx7XHJcblx0XHRcdHRhZzogJ3AnLCBcclxuXHRcdFx0aWQ6IFwiZWRpdFN0YXR1c1wiLFxyXG5cdFx0XHRjaGlsZE5vZGVzOltcIlJlYWR5IHRvIGVkaXQuLi5cIl1cclxuXHRcdH0se1xyXG5cdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRpZDogXCJFZGl0RWRpdEJ0blwiLFxyXG5cdFx0XHRvdGhlcjoge3R5cGU6IFwiYnV0dG9uXCJ9LFxyXG5cdFx0XHRjaGlsZE5vZGVzOltcIkVkaXRcIl1cclxuXHRcdH0se1xyXG5cdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRpZDogXCJFZGl0U2F2ZUJ0blwiLFxyXG5cdFx0XHRvdGhlcjp7dHlwZTogXCJidXR0b25cIn0sXHJcblx0XHRcdGNoaWxkTm9kZXM6W1wiU2F2ZVwiXVxyXG5cdFx0fSx7XHJcblx0XHRcdHRhZzogJ2J1dHRvbicsXHJcblx0XHRcdGlkOiBcIkVkaXREZWxldGVCdG5cIixcclxuXHRcdFx0b3RoZXI6IHt0eXBlOiBcImJ1dHRvblwiLCB0aXRsZTogXCJEZWxldGUgc2VsZWN0ZWQgaXRlbVwifSxcclxuXHRcdFx0Y2hpbGROb2RlczpbXCJEZWxldGVcIl1cclxuXHRcdH0se1xyXG5cdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRpZDogXCJFZGl0RGVsZXRlQWxsQnRuXCIsXHJcblx0XHRcdG90aGVyOiB7dHlwZTogXCJidXR0b25cIiwgdGl0bGU6IFwi5pys5b2T44Gr44KE44KL44Gu77yfXCJ9LFxyXG5cdFx0XHRjaGlsZE5vZGVzOltcIkRlbGV0ZSBBbGxcIl1cclxuXHRcdH0se1xyXG5cdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRpZDogXCJSZXNldExldmVsc0J0blwiLFxyXG5cdFx0XHRvdGhlcjoge3R5cGU6IFwiYnV0dG9uXCJ9LFxyXG5cdFx0XHRjaGlsZE5vZGVzOltcIlJlc2V0IGxldmVsc1wiXVxyXG5cdFx0fV1cclxuXHR9XVxyXG59O1xyXG5cclxuLy8gJ3RoaXMnIGNvbnRleHQgaXMgbm9kZSB0byBhdHRhY2ggdG9cclxudmFyIGF0dGFjaENoaWxkTm9kZSA9IGZ1bmN0aW9uKGNoaWxkTm9kZSl7XHJcblx0dmFyIGVsO1xyXG5cdGlmIChcInN0cmluZ1wiID09PSB0eXBlb2YgY2hpbGROb2RlKXsgLy9UZXh0Tm9kZVxyXG5cdFx0IGVsID0gZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoY2hpbGROb2RlKTtcclxuXHR9XHJcblx0ZWxzZXtcclxuXHRcdGVsID0gYnVpbGROb2RlKGNoaWxkTm9kZS50YWcsIHtpZDogY2hpbGROb2RlLmlkLCBjbGFzc05hbWU6IGNoaWxkTm9kZS5jbGFzc05hbWV9KTtcclxuXHRcdGZvciAodmFyIGF0dHIgaW4gY2hpbGROb2RlLm90aGVyKXtcclxuXHRcdFx0ZWwuc2V0QXR0cmlidXRlKGF0dHIsIGNoaWxkTm9kZS5vdGhlclthdHRyXSk7XHJcblx0XHR9XHJcblx0XHRpZiAoY2hpbGROb2RlLmNoaWxkTm9kZXMpe1xyXG5cdFx0XHRjaGlsZE5vZGUuY2hpbGROb2Rlcy5mb3JFYWNoKGF0dGFjaENoaWxkTm9kZSwgZWwpO1xyXG5cdFx0fVxyXG5cdH1cclxuXHR0aGlzLmFwcGVuZENoaWxkKGVsKTtcclxufTtcclxuXHJcbi8qKiBUYWtlcyBhIEpTT04gb2JqZWN0IHdpdGggdGhlIHN0cnVjdHVyZSBvZiB0aGUgd2luZG93IHRvIGNyZWF0ZSBhbmQgYnVpbGRzIGEgRElWRWxlbWVudCBmcm9tIHRoYXRcclxuKiBAcGFyYW0ge0lXaW5kb3d9IHdpbmRvd1N0cnVjdHVyZVxyXG4qIEByZXR1cm5zIHtESVZFbGVtZW50fSBUaGUgc3BlY2lmaWVkIHdpbmRvdy5cclxuKi9cclxudmFyIGJ1aWxkV2luZG93ID0gZnVuY3Rpb24od2luZG93U3RydWN0dXJlKSB7XHJcblx0XHJcblx0dmFyIHJlc3VsdFdpbmRvdyA9IGJ1aWxkTm9kZSgnZGl2Jywge2lkOiB3aW5kb3dTdHJ1Y3R1cmUuaWQsIGNsYXNzTmFtZTogd2luZG93U3RydWN0dXJlLmNsYXNzTmFtZX0pO1xyXG5cdGZvciAodmFyIGF0dHIgaW4gd2luZG93U3RydWN0dXJlLm90aGVyKXtcclxuXHRcdHJlc3VsdFdpbmRvdy5zZXRBdHRyaWJ1dGUoYXR0ciwgd2luZG93U3RydWN0dXJlLm90aGVyW2F0dHJdKTtcclxuXHR9XHJcblx0aWYgKHdpbmRvd1N0cnVjdHVyZS5jaGlsZE5vZGVzKXtcclxuXHRcdHdpbmRvd1N0cnVjdHVyZS5jaGlsZE5vZGVzLmZvckVhY2goYXR0YWNoQ2hpbGROb2RlLCByZXN1bHRXaW5kb3cpO1xyXG5cdH1cclxuXHRyZXR1cm4gcmVzdWx0V2luZG93O1xyXG59O1xyXG5cclxuLypcdFxyXG57XHRcclxuXHRcdHZhciBlZGl0Rm9ybSA9IGJ1aWxkTm9kZSgnZm9ybScsIHtpZDogXCJXS1NTLWVkaXRGb3JtXCJ9KTtcclxuXHRlZGl0V2luZG93LmFwcGVuZENoaWxkKGVkaXRGb3JtKTtcclxuXHRcdFx0dmFyIGVkaXRDbG9zZUJ1dHRvbiA9IGJ1aWxkTm9kZSgnYnV0dG9uJywge2lkOiBcIldLU1MtZWRpdENsb3NlQnRuXCIsIGNsYXNzTmFtZTogXCJXS1NTLWNsb3NlXCJ9KTtcclxuXHRcdGVkaXRGb3JtLmFwcGVuZENoaWxkKGVkaXRDbG9zZUJ1dHRvbik7XHJcblx0XHJcblx0XHRcdGVkaXRDbG9zZUJ1dHRvbi5hcHBlbmRDaGlsZChidWlsZE5vZGUoJ2knLCB7Y2xhc3NOYW1lOiBcImljb24tcmVtb3ZlXCJ9KSk7XHJcblx0XHRcdHZhciBoMUVsZW1lbnQgPSBidWlsZE5vZGUoJ2gxJyk7XHJcblx0XHRlZGl0Rm9ybS5hcHBlbmRDaGlsZChoMUVsZW1lbnQpO1xyXG5cdFx0XHRoMUVsZW1lbnQuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoXCJFZGl0IHlvdXIgVm9jYWJcIikpO1xyXG5cdFx0XHR2YXIgc2VsZWN0RWxlbWVudCA9IGJ1aWxkTm9kZSgnc2VsZWN0Jywge2lkOiBcImVkaXRXaW5kb3dcIiwgc2l6ZTogXCI4XCJ9KTtcclxuXHRcdGVkaXRGb3JtLmFwcGVuZENoaWxkKHNlbGVjdEVsZW1lbnQpO1xyXG5cdFx0XHR2YXIgZWRpdEl0ZW1UZXh0ID0gYnVpbGROb2RlKCdpbnB1dCcsIHt0eXBlOiBcInRleHRcIiBpZDogXCJlZGl0SXRlbVwiIG5hbWU6IFwiXCIgc2l6ZTogXCI0MFwiIHBsYWNlaG9sZGVyOiBcIlNlbGVjdCB2b2NhYiwgY2xpY2sgZWRpdCwgY2hhbmdlIGFuZCBzYXZlIVwifSk7XHJcblx0XHRlZGl0Rm9ybS5hcHBlbmRDaGlsZChlZGl0SXRlbVRleHQpOy8vLi5cclxuXHRcdFx0dmFyIGVkaXRTdGF0dXMgPSBidWlsZE5vZGUoJ3AnLCB7aWQ6IFwiZWRpdFN0YXR1c1wifSk7XHJcblx0XHRlZGl0Rm9ybS5hcHBlbmRDaGlsZChlZGl0U3RhdHVzKTtcclxuXHRcdFx0ZWRpdFN0YXR1cy5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShcIlJlYWR5IHRvIGVkaXQuLlwiKSk7XHJcblx0XHJcblx0XHRcdHZhciBlZGl0QnV0dG9uID0gYnVpbGROb2RlKCdidXR0b24nLCB7aWQ6IFwiRWRpdEVkaXRCdG5cIiwgdHlwZTogXCJidXR0b25cIn0pO1xyXG5cdFx0ZWRpdEZvcm0uYXBwZW5kQ2hpbGQoZWRpdEJ1dHRvbik7XHJcblx0XHRcdGVkaXRCdXR0b24uYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoXCJFZGl0XCIpKTtcclxuXHRcdFx0dmFyIGVkaXRTYXZlID0gYnVpbGROb2RlKCdidXR0b24nLCB7aWQ6IFwiRWRpdFNhdmVCdG5cIiwgdHlwZTogXCJidXR0b25cIn0pO1xyXG5cdFx0ZWRpdEZvcm0uYXBwZW5kQ2hpbGQoZWRpdFNhdmUpO1xyXG5cdFx0XHRlZGl0U2F2ZS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShcIlNhdmVcIikpO1xyXG5cdFx0XHR2YXIgZWRpdERlbGV0ZSA9IGJ1aWxkTm9kZSgnYnV0dG9uJywge2lkOiBcIkVkaXREZWxldGVCdG5cIiwgdHlwZTogXCJidXR0b25cIiwgdGl0bGU6IFwiRGVsZXRlIHNlbGVjdGVkIGl0ZW1cIn0pO1xyXG5cdFx0ZWRpdEZvcm0uYXBwZW5kQ2hpbGQoZWRpdERlbGV0ZSk7XHJcblx0XHRcdGVkaXREZWxldGUuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoXCJEZWxldGVcIikpO1xyXG5cdFx0XHR2YXIgZWRpdERlbGV0ZUFsbCA9IGJ1aWxkTm9kZSgnYnV0dG9uJywge2lkOiBcIkVkaXREZWxldGVBbGxCdG5cIiwgdHlwZTogXCJidXR0b25cIiwgdGl0bGU6IFwi5pys5b2T44Gr44KE44KL44Gu77yfXCJ9KTtcclxuXHRcdGVkaXRGb3JtLmFwcGVuZENoaWxkKGVkaXREZWxldGVBbGwpO1xyXG5cdFx0XHRlZGl0RGVsZXRlQWxsLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKFwiRGVsZXRlIEFsbFwiKSk7XHJcblx0XHRcdHZhciBlZGl0UmVzZXRMZXZlbHMgPSBidWlsZE5vZGUoJ2J1dHRvbicsIHtpZDogXCJSZXNldExldmVsc0J0blwiLCB0eXBlOiBcImJ1dHRvblwifSk7XHJcblx0XHRlZGl0Rm9ybS5hcHBlbmRDaGlsZChlZGl0UmVzZXRMZXZlbHMpO1xyXG5cdFx0XHRlZGl0UmVzZXRMZXZlbHMuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoXCJSZXNldCBsZXZlbHNcIikpO1xyXG5cdFx0XHJcblx0cmV0dXJuIGVkaXRXaW5kb3c7XHJcbn07Ki9cclxubW9kdWxlLmV4cG9ydHMgPSBidWlsZFdpbmRvdzsiLCJtb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKCl7XHJcblxyXG5cdHZhciBrYW5qaSA9ICQoXCIjYWRkS2FuamlcIikudmFsKCkudG9Mb3dlckNhc2UoKTtcclxuXHR2YXIgcmVhZGluZyA9ICQoXCIjYWRkUmVhZGluZ1wiKS52YWwoKS50b0xvd2VyQ2FzZSgpLnNwbGl0KC9bLOOAgV0rXFxzKi8pOyAvL3NwbGl0IGF0ICwgb3Ig44CBZm9sbG93ZWQgYnkgMCBvciBhbnkgbnVtYmVyIG9mIHNwYWNlc1xyXG5cdHZhciBtZWFuaW5nID0gJChcIiNhZGRNZWFuaW5nXCIpLnZhbCgpLnRvTG93ZXJDYXNlKCkuc3BsaXQoL1ss44CBXStcXHMqLyk7XHJcblx0dmFyIHN1Y2Nlc3MgPSBmYWxzZTsgLy9pbml0YWxpc2UgdmFsdWVzXHJcblx0dmFyIG1lYW5sZW4gPSAwO1xyXG5cclxuXHR2YXIgaSA9IG1lYW5pbmcubGVuZ3RoO1xyXG5cdHdoaWxlIChpLS0pe1xyXG5cdFx0bWVhbmxlbiArPSBtZWFuaW5nW2ldLmxlbmd0aDtcclxuXHR9XHJcblxyXG5cdC8vaW5wdXQgaXMgaW52YWxpZDogcHJvbXB0IHVzZXIgZm9yIHZhbGlkIGlucHV0XHJcblx0dmFyIGl0ZW0gPSB7fTtcclxuXHRpZiAoa2FuamkubGVuZ3RoID09PSAwIHx8IG1lYW5sZW4gPT09IDApIHtcclxuXHRcdCQoXCIjYWRkU3RhdHVzXCIpLnRleHQoXCJPbmUgb3IgbW9yZSByZXF1aXJlZCBmaWVsZHMgYXJlIGVtcHR5IVwiKTtcclxuXHRcdGlmIChrYW5qaS5sZW5ndGggPT09IDApIHtcclxuXHRcdFx0JChcIiNhZGRLYW5qaVwiKS5hZGRDbGFzcyhcImVycm9yXCIpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0JChcIiNhZGRLYW5qaVwiKS5yZW1vdmVDbGFzcyhcImVycm9yXCIpO1xyXG5cdFx0fVxyXG5cdFx0aWYgKG1lYW5sZW4gPT09IDApIHtcclxuXHRcdFx0JChcIiNhZGRNZWFuaW5nXCIpLmFkZENsYXNzKFwiZXJyb3JcIik7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHQkKFwiI2FkZE1lYW5pbmdcIikucmVtb3ZlQ2xhc3MoXCJlcnJvclwiKTtcclxuXHRcdH1cclxuXHR9IGVsc2Uge1xyXG5cdFx0aWYgKGRlYnVnZ2luZykge2NvbnNvbGUubG9nKFwiYnVpbGRpbmcgaXRlbTogXCIra2FuamkpO31cclxuXHRcdGl0ZW0ua2FuamkgPSBrYW5qaTtcclxuXHRcdGl0ZW0ucmVhZGluZyA9IHJlYWRpbmc7IC8vb3B0aW9uYWxcclxuXHRcdGl0ZW0ubWVhbmluZyA9IG1lYW5pbmc7XHJcblxyXG5cdFx0c3VjY2VzcyA9IHRydWU7XHJcblx0XHRpZiAoZGVidWdnaW5nKSB7Y29uc29sZS5sb2coXCJpdGVtIGlzIHZhbGlkXCIpO31cclxuXHR9XHJcblxyXG5cdC8vb24gc3VjY2Vzc2Z1bCBjcmVhdGlvbiBvZiBpdGVtXHJcblx0aWYgKHN1Y2Nlc3MpIHtcclxuXHRcdC8vY2xlYXIgZXJyb3IgbGF5b3V0IHRvIHJlcXVpcmVkIGZpZWxkc1xyXG5cdFx0JChcIiNhZGRLYW5qaVwiKS5yZW1vdmVDbGFzcyhcImVycm9yXCIpO1xyXG5cdFx0JChcIiNhZGRNZWFuaW5nXCIpLnJlbW92ZUNsYXNzKFwiZXJyb3JcIik7XHJcblxyXG5cclxuXHJcblx0XHQvL2lmIHRoZXJlIGFyZSBhbHJlYWR5IHVzZXIgaXRlbXMsIHJldHJpZXZlIHZvY2FiTGlzdFxyXG5cdFx0Ly8gdmFyIHZvY2FiTGlzdCA9IFtdO1xyXG5cdFx0dmFyIHZvY2FiTGlzdCA9IGdldEZ1bGxMaXN0KCk7XHJcblxyXG5cdFx0aWYgKGRlYnVnZ2luZykge2NvbnNvbGUubG9nKFwidm9jYWJMaXN0IHJldHJpZXZlZCwgbGVuZ3RoOiBcIit2b2NhYkxpc3QubGVuZ3RoKTt9XHJcblx0XHQvL2NoZWNrIHN0b3JlZCB1c2VyIGl0ZW1zIGZvciBkdXBsaWNhdGVzICoqKioqKioqKioqKioqKioqKiB0byBkbzogb3B0aW9uIGZvciBlZGl0aW5nIGR1cGxpY2F0ZSBpdGVtIHdpdGggbmV3IGlucHV0XHJcblx0XHRpZihjaGVja0ZvckR1cGxpY2F0ZXModm9jYWJMaXN0LGl0ZW0pKSB7XHJcblx0XHRcdCQoXCIjYWRkU3RhdHVzXCIpLnRleHQoXCJEdXBsaWNhdGUgSXRlbSBkZXRlY3RlZCFcIik7XHJcblx0XHRcdCQoXCIjYWRkS2FuamlcIikuYWRkQ2xhc3MoXCJlcnJvclwiKTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdHNldFZvY0l0ZW0oaXRlbSk7XHJcblxyXG5cdFx0aWYgKGRlYnVnZ2luZykge2NvbnNvbGUubG9nKFwiY2xlYXIgZm9ybVwiKTt9XHJcblx0XHQkKFwiI2FkZEZvcm1cIilbMF0ucmVzZXQoKTtcclxuXHJcblx0XHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXHJcblx0XHRpZiAoaXRlbS5tYW51YWxMb2NrID09PSBcInllc1wiIHx8IGl0ZW0ubWFudWFsTG9jayA9PT0gXCJEQlwiICYmIGxvY2tEQil7XHJcblx0XHRcdCQoXCIjYWRkU3RhdHVzXCIpLmh0bWwoXCI8aSBjbGFzcz1cXFwiaWNvbi1sb2NrXFxcIj48L2k+IEFkZGVkIGxvY2tlZCBpdGVtXCIpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0JChcIiNhZGRTdGF0dXNcIikuaHRtbChcIjxpIGNsYXNzPVxcXCJpY29uLXVubG9ja1xcXCI+PC9pPkFkZGVkIHN1Y2Nlc3NmdWxseVwiKTtcclxuXHRcdH1cclxuXHRcdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cclxuXHR9XHJcbn07IiwibW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbigpe1xyXG5cdC8vIHtcImxldmVsXCI6XCIxN1wiLFwibWVhbmluZ19leHBsYW5hdGlvblwiOlwiVGhpcyB3b3JkIGNvbnNpc3RzIG9mIGthbmppIHdpdGggaGlyYWdhbmEgYXR0YWNoZWQuIEJlY2F1c2UgdGhlIGhpcmFnYW5hIGVuZHMgd2l0aCBhbiBbamFd44GGWy9qYV0gc291bmQsIHlvdSBrbm93IHRoaXMgd29yZCBpcyBhIHZlcmIuIFRoZSBrYW5qaSBpdHNlbGYgbWVhbnMgW2thbmppXWZsb3VyaXNoWy9rYW5qaV0gb3IgW2thbmppXXByb3NwZXJpdHlbL2thbmppXSwgc28gdGhlIHZlcmIgdm9jYWIgdmVyc2lvbnMgb2YgdGhlc2Ugd291bGQgYmUgW3ZvY2FidWxhcnlddG8gZmxvdXJpc2hbL3ZvY2FidWxhcnldIG9yIFt2b2NhYnVsYXJ5XXRvIHByb3NwZXJbL3ZvY2FidWxhcnldLlwiLFwicmVhZGluZ19leHBsYW5hdGlvblwiOlwiU2luY2UgdGhpcyB3b3JkIGNvbnNpc3RzIG9mIGEga2Fuamkgd2l0aCBoaXJhZ2FuYSBhdHRhY2hlZCwgeW91IGNhbiBiZXQgdGhhdCBpdCB3aWxsIHVzZSB0aGUga3VuJ3lvbWkgcmVhZGluZy4gWW91IGRpZG4ndCBsZWFybiB0aGF0IHJlYWRpbmcgd2l0aCB0aGlzIGthbmppLCBzbyBoZXJlJ3MgYSBtbmVtb25pYyB0byBoZWxwIHlvdTogV2hhdCBkbyB5b3UgZmxvdXJpc2ggYXQ/IFlvdSdyZSBhbiBhbWF6aW5nIFt2b2NhYnVsYXJ5XXNvY2Nlclsvdm9jYWJ1bGFyeV0gKFtqYV3jgZXjgYtbL2phXSkgcGxheWVyIHdobyBmbG91cmlzaGVzIGFuZCBwcm9zcGVycyBubyBtYXR0ZXIgd2hlcmUgeW91IGdvIHRvIHBsYXkgdGhpcyB3b25kZXJmdWwgKGJ1dCBub3QgYXMgZ29vZCBhcyBiYXNlYmFsbCkgc3BvcnQuXCIsXCJlblwiOlwiVG8gRmxvdXJpc2gsIFRvIFByb3NwZXJcIixcImthbmFcIjpcIuOBleOBi+OBiOOCi1wiLFwic2VudGVuY2VzXCI6W1tcIuS4reWbveOBq+OBr+OAgeimmuOBm+OBhOWJpOOBrueUn+eUo+OBp+aghOOBiOOBpuOBhOOBn+adkeOBjOOBguOCiuOBvuOBl+OBn+OAglwiLFwiVGhlcmUgd2FzIGEgdmlsbGFnZSBpbiBDaGluYSBmbG91cmlzaGluZyBvbiB0aGVpciBwcm9kdWN0aW9uIG9mIHN0aW11bGFudHMuIFwiXV0sXCJwYXJ0c19vZl9zcGVlY2hfaWRzXCI6W1wiNFwiLFwiMTlcIl0sXCJwYXJ0X29mX3NwZWVjaFwiOlwiSW50cmFuc2l0aXZlIFZlcmIsIEljaGlkYW4gVmVyYlwiLFwiYXVkaW9cIjpcIjJlMTk0Y2JmMTk0MzcxY2Q0Nzg0ODBkNmVhNjc3NjlkYTYyM2U5OWEubXAzXCIsXCJtZWFuaW5nX25vdGVcIjpudWxsLFwicmVhZGluZ19ub3RlXCI6bnVsbCxcInJlbGF0ZWRcIjpbe1wia2FuXCI6XCLmoIRcIixcImVuXCI6XCJQcm9zcGVyaXR5LCBGbG91cmlzaFwiLFwic2x1Z1wiOlwi5qCEXCJ9XX1cclxuXHJcblxyXG5cdGlmICh0eXBlb2YgJC5tb2NramF4ID09PSBcImZ1bmN0aW9uXCIpe1xyXG5cdFx0JC5tb2NramF4KHtcclxuXHRcdFx0dXJsOiAvXlxcL2pzb25cXC9wcm9ncmVzc1xcP3ZXS1NTKC4rKVxcW1xcXT0oLispJnZXS1NTLitcXFtcXF09KC4rKSQvLFxyXG5cdFx0XHR1cmxQYXJhbXM6W1wiV0tTU2lkXCIsIFwiTWVhbmluZ1dyb25nXCIsIFwiUmVhZGluZ1dyb25nXCJdLFxyXG5cdFx0XHRyZXNwb25zZTogZnVuY3Rpb24oc2V0dGluZ3MpIHtcclxuXHRcdFx0XHQvLyBkbyBhbnkgcmVxdWlyZWQgY2xlYW51cFxyXG5cdFx0XHRcdHZhciBpZCA9IE51bWJlcihzZXR0aW5ncy51cmxQYXJhbXMuV0tTU2lkKTtcclxuXHRcdFx0XHR2YXIgTXcgPSBOdW1iZXIoc2V0dGluZ3MudXJsUGFyYW1zLk1lYW5pbmdXcm9uZyk7XHJcblx0XHRcdFx0dmFyIFJ3ID0gTnVtYmVyKHNldHRpbmdzLnVybFBhcmFtcy5SZWFkaW5nV3JvbmcpO1xyXG5cdFx0XHRcdHZhciBVc2VyVm9jYWIgPSBsb2NhbEdldChcIlVzZXItVm9jYWJcIil8fFtdO1xyXG5cclxuXHRcdFx0XHRjb25zb2xlLmxvZyhcImlzIHRoaXMgeW91ciBjYXJkP1wiLCBVc2VyVm9jYWJbaWRdKTtcclxuXHRcdFx0XHRpZiAoVXNlclZvY2FiW2lkXS5kdWUgPCBEYXRlLm5vdygpKXsvL2RvdWJsZSBjaGVjayB0aGF0IGl0ZW0gd2FzIGR1ZSBmb3IgcmV2aWV3XHJcblx0XHRcdFx0XHRpZiAoTXd8fFJ3KXtcclxuXHRcdFx0XHRcdFx0Ly9kcm9wIGxldmVscyBpZiB3cm9uZ1xyXG5cclxuXHRcdFx0XHRcdFx0Ly9BZGFwdGVkIGZyb20gV2FuaUthbmkncyBzcnMgdG8gYXV0aGVudGljYWxseSBtaW1pYyBsZXZlbCBkb3duc1xyXG5cdFx0XHRcdFx0XHR2YXIgbyA9IChNd3x8MCkrKFJ3fHwwKTtcclxuXHRcdFx0XHRcdFx0dmFyIHQgPSBVc2VyVm9jYWJbaWRdLmxldmVsO1xyXG5cdFx0XHRcdFx0XHR2YXIgcj10Pj01PzIqTWF0aC5yb3VuZChvLzIpOjEqTWF0aC5yb3VuZChvLzIpO1xyXG5cdFx0XHRcdFx0XHR2YXIgbj10LXI8MT8xOnQtcjsvL2Rvbid0IHN0YXkgb24gJ3N0YXJ0ZWQnXHJcblxyXG5cdFx0XHRcdFx0XHRVc2VyVm9jYWJbaWRdLmxldmVsID0gbjtcclxuXHRcdFx0XHRcdH1lbHNle1xyXG5cdFx0XHRcdFx0XHQvL2luY3JlYXNlIGxldmVsIGlmIG5vbmUgd3JvbmdcclxuXHRcdFx0XHRcdFx0VXNlclZvY2FiW2lkXS5sZXZlbCsrO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0Ly9QdXQgVXNlclZvY2FiIGJhY2sgaW4gc3RvcmFnZVxyXG5cdFx0XHRcdFx0VXNlclZvY2FiW2lkXS5kYXRlID0gRGF0ZS5ub3coKTtcclxuXHRcdFx0XHRcdFVzZXJWb2NhYltpZF0uZHVlID0gRGF0ZS5ub3coKSArIHNyc2ludGVydmFsc1tVc2VyVm9jYWJbaWRdLmxldmVsXTtcclxuXHRcdFx0XHRcdGxvY2FsU2V0KFwiVXNlci1Wb2NhYlwiLCBVc2VyVm9jYWIpO1xyXG5cdFx0XHRcdFx0Y29uc29sZS5sb2coVXNlclZvY2FiW2lkXS5kdWUgK1wiID4gXCIrIERhdGUubm93KCkgKyBcIiAoXCIgKyBtczJzdHIoVXNlclZvY2FiW2lkXS5kdWUgLSBEYXRlLm5vdygpKStcIilcIik7XHJcblxyXG5cdFx0XHRcdH1lbHNle1xyXG5cdFx0XHRcdFx0Y29uc29sZS5sb2coXCJUaGlzIGl0ZW0gaXMgbm90IGR1ZSBmb3IgcmV2aWV3IHlldCwgZGlzY2FyZGluZyByZXN1bHRzXCIpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHR0aGlzLnJlc3BvbnNlVGV4dCA9ICd7XCJ2V0tTUycraWQudG9TdHJpbmcoKSsnXCI6W1wiJytNdy50b1N0cmluZygpKydcIixcIicrUncudG9TdHJpbmcoKSsnXCJdfSc7XHJcblxyXG5cdFx0XHR9XHJcblx0XHR9KTtcclxuXHJcblx0XHQkLm1vY2tqYXgoe1xyXG5cdFx0XHR1cmw6IC9eXFwvanNvblxcL3ZvY2FidWxhcnlcXC9XS1NTKC4rKS8sXHJcblx0XHRcdHVybFBhcmFtczpbXCJXS1NTaWRcIl0sXHJcblx0XHRcdHJlc3BvbnNlOiBmdW5jdGlvbihzZXR0aW5ncykge1xyXG5cclxuXHRcdFx0XHQvLyBJbnZlc3RpZ2F0ZSB0aGUgYHNldHRpbmdzYCB0byBkZXRlcm1pbmUgdGhlIHJlc3BvbnNlLi4uXHJcblx0XHRcdFx0dmFyIGlkID0gc2V0dGluZ3MudXJsUGFyYW1zLldLU1NpZC50b1N0cmluZygpO1xyXG5cdFx0XHRcdHZhciBjdXJyZW50SXRlbSA9ICQualN0b3JhZ2UuZ2V0KFwiY3VycmVudEl0ZW1cIik7XHJcblx0XHRcdFx0aWYgKGN1cnJlbnRJdGVtLmlkID09PSBcIldLU1NcIitpZCl7XHJcblx0XHRcdFx0XHRjb25zb2xlLmxvZyhcImFzIGV4cGVjdGVkXCIpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHR2YXIgcmVsYXRlZCA9ICdbJztcclxuXHRcdFx0XHRmb3IgKGkgPSAwOyBpIDwgY3VycmVudEl0ZW0uY29tcG9uZW50cy5sZW5ndGg7IGkrKyl7XHJcblx0XHRcdFx0XHRyZWxhdGVkICs9ICd7XCJrYW5cIjpcIicrY3VycmVudEl0ZW0uY29tcG9uZW50c1tpXSsnXCIsXCJlblwiOlwiXCIsXCJzbHVnXCI6XCInK2N1cnJlbnRJdGVtLmNvbXBvbmVudHNbaV0rJ1wifSc7XHJcblx0XHRcdFx0XHRyZWxhdGVkICs9IChpKzE8Y3VycmVudEl0ZW0uY29tcG9uZW50cy5sZW5ndGgpPycsJzonJztcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0cmVsYXRlZCArPSAnXSc7XHJcblxyXG5cdFx0XHRcdHZhciByZXNwVGV4dCA9IEpTT04uc3RyaW5naWZ5KHtcclxuXHRcdFx0XHRcdGxldmVsOiBcIlVcIixcclxuXHRcdFx0XHRcdG1lYW5pbmdfZXhwbGFuYXRpb246IFwiVGhpcyBpcyB1c2VyLWRlZmluZWQgaXRlbS4gTWVhbmluZyBleHBsYW5hdGlvbnMgYXJlIG5vdCBzdXBwb3J0ZWQgYXQgdGhpcyB0aW1lLiBbaWQ6IFwiK2lkK1wiXVwiLFxyXG5cdFx0XHRcdFx0cmVhZGluZ19leHBsYW5hdGlvbjogXCJUaGlzIGlzIHVzZXItZGVmaW5lZCBpdGVtLiBSZWFkaW5nIGV4cGxhbmF0aW9ucyBhcmUgbm90IHN1cHBvcnRlZCBhdCB0aGlzIHRpbWUuIFtpZDogXCIraWQrXCJdXCIsXHJcblx0XHRcdFx0XHRlbjogY3VycmVudEl0ZW0uZW4uam9pbihcIiwgXCIpLFxyXG5cdFx0XHRcdFx0a2FuYTogY3VycmVudEl0ZW0ua2FuYS5qb2luKFwiLCBcIiksXHJcblx0XHRcdFx0XHRzZW50ZW5jZXM6W10sXHJcblx0XHRcdFx0XHRwYXJ0c19vZl9zcGVlY2hfaWRzOltdLFxyXG5cdFx0XHRcdFx0cGFydF9vZl9zcGVlY2g6W10sXHJcblx0XHRcdFx0XHRhdWRpbzpudWxsLFxyXG5cdFx0XHRcdFx0bWVhbmluZ19ub3RlOm51bGwsXHJcblx0XHRcdFx0XHRyZWFkaW5nX25vdGU6bnVsbCxcclxuXHRcdFx0XHRcdHJlbGF0ZWQ6SlNPTi5wYXJzZShyZWxhdGVkKVxyXG5cdFx0XHRcdH0pO1xyXG5cdFx0XHRcdHRoaXMucmVzcG9uc2VUZXh0ID0gcmVzcFRleHQ7XHJcblx0XHRcdH0sXHJcblx0XHRcdG9uQWZ0ZXJDb21wbGV0ZTogZnVuY3Rpb24oKSB7XHJcblx0XHRcdFx0Ly8gZG8gYW55IHJlcXVpcmVkIGNsZWFudXBcclxuXHRcdFx0XHQkKFwiLnVzZXItc3lub255bXNcIikucmVtb3ZlKCk7XHJcblx0XHRcdFx0Ly8ga2VlcGluZyB0aGUgaG9va3MgZm9yIENvbW11bml0eSBNbmVtb25pY3NcclxuXHRcdFx0XHQkKFwiI25vdGUtbWVhbmluZywgI25vdGUtcmVhZGluZ1wiKS5odG1sKFwiXCIpO1xyXG5cdFx0XHR9XHJcblx0XHR9KTtcclxuXHR9XHJcbn07XHJcbi8vLS0tLS0tLS0tLS0tLS1FbmQgSW5zZXJ0IEludG8gV0sgUmV2aWV3IEZ1bmN0aW9ucy0tLS0tLS0tLS0tLS0tXHJcblxyXG4iLCJcclxudmFyIEltcG9ydFV0aWwgPSB7XHJcblx0ZmlsZVVwbG9hZDogZnVuY3Rpb24oZXYpe1xyXG5cdFx0dmFyIGNzdkhlYWRlciA9IHRydWU7ICAgICAgICAvL2ZpcnN0IHJvdyBjb250YWlucyBzdHVmZiBsaWtlIFwiS2FuamkvVm9jYWIsIFJlYWRpbmcsIE1lYW5pbmdcIiBldGNcclxuXHRcdHZhciB0c3ZmaWxlOyAgICAgICAgICAvL3RhYnMgc2VwYXJhdGUgZmllbGRzLCBjb21tYXMgc2VwZXJhdGUgdmFsdWVzPyBvciBmYWxzZSBmb3IgdmljZSB2ZXJzYVxyXG5cdFx0dmFyIENTVnMgPSBldi50YXJnZXQuZmlsZXM7XHJcblx0XHR2YXIgbmFtZSA9Q1NWc1swXS5uYW1lO1xyXG5cdFx0dmFyIGNvbHNwbGl0LCB2c3BsaXQ7XHJcblx0XHRpZiAobmFtZS5zdWJzdHIobmFtZS5sYXN0SW5kZXhPZihcIi5cIiksNCk9PT1cIi5jc3ZcIil7XHJcblx0XHRcdHRzdmZpbGUgPSBmYWxzZTtcclxuXHRcdFx0Y29sc3BsaXQgPSBcIixcIjtcclxuXHRcdFx0dnNwbGl0ID0gXCJcXHRcIjtcclxuXHRcdH1lbHNle1xyXG5cdFx0XHR0c3ZmaWxlID0gdHJ1ZTtcclxuXHRcdFx0Y29sc3BsaXQgPSBcIlxcdFwiO1xyXG5cdFx0XHR2c3BsaXQgPSBcIixcIjtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoZGVidWdnaW5nKSB7IGNvbnNvbGUubG9nKFwidHN2ZmlsZTogXCIpOyB9XHJcblx0XHRpZiAoZGVidWdnaW5nKSB7IGNvbnNvbGUubG9nKFwiZmlsZSB1cGxvYWRlZDogXCIrQ1NWc1swXS5uYW1lKTsgfVxyXG5cdFx0dmFyIHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyKCk7XHJcblx0XHRyZWFkZXIucmVhZEFzVGV4dChDU1ZzWzBdKTtcclxuXHRcdHJlYWRlci5vbmxvYWQgPSBmdW5jdGlvbihldil7XHJcblx0XHRcdHZhciBjc3ZTdHJpbmcgPSBldi50YXJnZXQucmVzdWx0O1xyXG5cdFx0XHR2YXIgY3N2Um93ID0gY3N2U3RyaW5nLnNwbGl0KFwiXFxuXCIpO1xyXG5cdFx0XHQvL2RlZmF1bHQgY29sdW1uIHJvd3NcclxuXHRcdFx0dmFyIGsgPSAwO1xyXG5cdFx0XHR2YXIgciA9IDE7XHJcblx0XHRcdHZhciBtID0gMjtcclxuXHJcblx0XHRcdHZhciBpID0gY3N2Um93Lmxlbmd0aDtcclxuXHRcdFx0Ly9wcm9jZXNzIGhlYWRlciwgY2hhbmdpbmcgayxyLG0gaWYgbmVjZXNzYXJ5XHJcblx0XHRcdHZhciBKU09OaW1wb3J0ID0gW107XHJcblx0XHRcdHdoaWxlKGktLSl7XHJcblx0XHRcdFx0dmFyIHJvdyA9IGNzdlJvd1tpXTtcclxuXHRcdFx0XHRpZiAoKGNzdkhlYWRlciA9PT0gdHJ1ZSAmJiBpID09PSAwKXx8ICAvLyAgU2tpcCBoZWFkZXJcclxuXHRcdFx0XHRcdChyb3cgPT09IFwiXCIpIC8vIFNraXAgZW1wdHkgcm93c1xyXG5cdFx0XHRcdCAgICl7XHJcblx0XHRcdFx0XHRpZiAoZGVidWdnaW5nKSB7IGNvbnNvbGUubG9nKFwiU2tpcHBpbmcgcm93ICNcIitpKTsgfVxyXG5cclxuXHRcdFx0XHR9ZWxzZXtcclxuXHRcdFx0XHRcdGNvbnNvbGUubG9nKHJvdyk7XHJcblxyXG5cclxuXHRcdFx0XHRcdHZhciBlbGVtID0gcm93LnNwbGl0KGNvbHNwbGl0KTtcclxuXHRcdFx0XHRcdHZhciBpdGVtID0ge307XHJcblx0XHRcdFx0XHR2YXIgYztcclxuXHJcblx0XHRcdFx0XHRpZiAoZWxlbVtrXSl7XHJcblx0XHRcdFx0XHRcdGl0ZW0ua2FuamkgPSBlbGVtW2tdLnRyaW0oKTtcclxuXHJcblx0XHRcdFx0XHRcdGlmIChlbGVtW3JdKXtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKGVsZW1bcl0uaW5kZXhPZih2c3BsaXQpPi0xKXtcclxuXHRcdFx0XHRcdFx0XHRcdC8vIGVnICdyZWFkaW5nIDFbdGFiXXJlYWRpbmcgMlt0YWJdcmVhZGluZyAzJ1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGl0ZW0ucmVhZGluZyA9IGVsZW1bcl0uc3BsaXQodnNwbGl0KTtcclxuXHRcdFx0XHRcdFx0XHR9ZWxzZXsgLy9ubyB0YWJzIGluIHN0cmluZywgc2luZ2xlIHZhbHVlXHJcblx0XHRcdFx0XHRcdFx0XHRpdGVtLnJlYWRpbmc9W2VsZW1bcl1dO1xyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdH1lbHNle1xyXG5cdFx0XHRcdFx0XHRcdGl0ZW0ucmVhZGluZz1bXCJcIl07XHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdGlmIChlbGVtW21dKXtcclxuXHJcblx0XHRcdFx0XHRcdFx0aWYgKGVsZW1bbV0uaW5kZXhPZih2c3BsaXQpPi0xKXtcclxuXHRcdFx0XHRcdFx0XHRcdC8vIGVnICdtZWFuaW5nIDFbdGFiXW1lYW5pbmcgMlt0YWJdbWVhbmluZyAzJ1xyXG5cclxuXHRcdFx0XHRcdFx0XHRcdGl0ZW0ubWVhbmluZyA9IGVsZW1bbV0uc3BsaXQoXCJcXHRcIik7XHJcblx0XHRcdFx0XHRcdFx0fWVsc2V7IC8vbm8gdGFicyBpbiBzdHJpbmcsIHNpbmdsZSB2YWx1ZVxyXG5cdFx0XHRcdFx0XHRcdFx0aXRlbS5tZWFuaW5nPVtlbGVtW21dXTtcclxuXHRcdFx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdFx0XHRcdGMgPSBpdGVtLm1lYW5pbmcubGVuZ3RoO1xyXG5cclxuXHRcdFx0XHRcdFx0XHR3aGlsZShjLS0pe1xyXG5cdFx0XHRcdFx0XHRcdFx0Y29uc29sZS5sb2coXCJpdGVtLm1lYW5pbmdbXCIrYytcIl06IFwiK2l0ZW0ubWVhbmluZ1tjXSk7XHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9ZWxzZXsvL3RvZG86IHByb3ZpZGUgb3ZlcndyaXRlIG9wdGlvbiBvbiBmb3JjZWQgbWVhbmluZ1xyXG5cdFx0XHRcdFx0XHRcdGl0ZW0ubWVhbmluZz1bXCJcIl07XHJcblx0XHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHRcdEpTT05pbXBvcnQucHVzaChpdGVtKTtcclxuXHRcdFx0XHRcdH1lbHNleyAvLyBjb3JydXB0IHJvdyAoJ2thbmppJyBpcyBtYW5kYXRvcnkgKGNhbiBiZSBrYW5hLW9ubHkgd29yZCksIGlzIG5vdCBwcmVzZW50IG9uIHJvdywgc2tpcFxyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHR2YXIgSlNPTnN0cmluZyA9IEpTT04uc3RyaW5naWZ5KEpTT05pbXBvcnQpO1xyXG5cdFx0XHRjb25zb2xlLmxvZyhKU09OaW1wb3J0KTtcclxuXHJcblx0XHRcdGlmIChKU09Oc3RyaW5nLmxlbmd0aCAhPT0gMCkge1xyXG5cdFx0XHRcdHRyeSB7XHJcblx0XHRcdFx0XHR2YXIgYWRkID0gSlNPTi5wYXJzZShKU09Oc3RyaW5nLnRvTG93ZXJDYXNlKCkpO1xyXG5cdFx0XHRcdFx0LyovLy0tLS0tLS0tLS8tLS0tLS0tLS0tLS0tXHJcblx0XHRcdFx0IGlmICghY2hlY2tBZGQoYWRkKSkge1xyXG5cdFx0XHRcdCAkKFwiI2ltcG9ydFN0YXR1c1wiKS50ZXh0KFwiTm8gdmFsaWQgaW5wdXQgKGR1cGxpY2F0ZXM/KSFcIik7XHJcblx0XHRcdFx0IHJldHVybjtcclxuXHRcdFx0XHQgfVxyXG5cdFx0XHRcdCAvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xyXG5cclxuXHRcdFx0XHRcdHZhciBhID0gYWRkLmxlbmd0aDtcclxuXHRcdFx0XHRcdHdoaWxlKGEtLSl7XHJcblx0XHRcdFx0XHRcdFN0b3JhZ2VVdGlsLnNldFZvY0l0ZW0oYWRkW2FdKTtcclxuXHRcdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0XHQkKFwiI2ltcG9ydFN0YXR1c1wiKS50ZXh0KFwiSW1wb3J0IHN1Y2Nlc3NmdWwhXCIpO1xyXG5cclxuXHRcdFx0XHRcdCQoXCIjaW1wb3J0Rm9ybVwiKVswXS5yZXNldCgpO1xyXG5cdFx0XHRcdFx0JChcIiNpbXBvcnRBcmVhXCIpLnRleHQoXCJcIik7XHJcblxyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRjYXRjaCAoZSkge1xyXG5cdFx0XHRcdFx0JChcIiNpbXBvcnRTdGF0dXNcIikudGV4dChcIlBhcnNpbmcgRXJyb3IhXCIpO1xyXG5cdFx0XHRcdFx0Y29uc29sZS5sb2coZSk7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fVxyXG5cdFx0XHRlbHNlIHtcclxuXHRcdFx0XHQkKFwiI2ltcG9ydFN0YXR1c1wiKS50ZXh0KFwiTm90aGluZyB0byBpbXBvcnQgOiggUGxlYXNlIHBhc3RlIHlvdXIgc3R1ZmYgZmlyc3RcIik7XHJcblx0XHRcdH1cclxuXHJcblx0XHR9O1xyXG5cdH1cclxufTtcclxuXHJcbm1vZHVsZS5leHBvcnRzID0gSW1wb3J0VXRpbDsiLCJcclxudmFyIFN0b3JhZ2VVdGlsID0ge1xyXG5cdC8qKiBJbml0aWFsaXNlIFVzZXItVm9jYWJcclxuXHQqL1xyXG5cdGluaXRTdG9yYWdlOiBmdW5jdGlvbigpe1xyXG5cdFx0aWYgKCFsb2NhbEdldChcIlVzZXItVm9jYWJcIikpe1xyXG5cdFx0XHRsb2NhbFNldChcIlVzZXItVm9jYWJcIiwgW10pO1xyXG5cdFx0fVxyXG5cdH0sXHJcblx0LyoqXHJcblx0Ki9cclxuXHRsb2NhbEdldDogZnVuY3Rpb24oc3RyTmFtZSl7XHJcbiAgICAgICAgdmFyIHN0ck9iaiA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKHN0ck5hbWUpO1xyXG4gICAgICAgIHJldHVybiBwYXJzZVN0cmluZyhzdHJPYmopO1xyXG4gICAgfSxcclxuXHQvKiogU2V0cyBzdHJpbmdzIGFuZCBvYmplY3RzIGludG8gYnJvd3NlciBzdG9yYWdlXHJcblx0KiBAcmVxdWlyZXMgbG9jYWxTdG9yYWdlXHJcblx0KiBAcmVxdWlyZXMgSlNPTlxyXG5cdCovXHJcblx0bG9jYWxTZXQ6IGZ1bmN0aW9uKHN0ck5hbWUsIG9iail7XHJcbiAgICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oc3RyTmFtZSwgdHlwZW9mIG9iaiA9PT0gXCJzdHJpbmdcIj8gb2JqIDogSlNPTi5zdHJpbmdpZnkob2JqKSk7XHJcbiAgICB9LFxyXG5cdC8qKlxyXG5cdCovXHJcblx0c2Vzc2lvbkdldDogZnVuY3Rpb24oc3RyTmFtZSl7XHJcbiAgICAgICAgdmFyIHN0ck9iaiA9IHNlc3Npb25TdG9yYWdlLmdldEl0ZW0oc3RyTmFtZSk7XHJcbiAgICAgICAgcmV0dXJuIHBhcnNlU3RyaW5nKHN0ck9iaik7XHJcbiAgICB9LFxyXG5cdC8qKiBTZXRzIHN0cmluZ3MgYW5kIG9iamVjdHMgaW50byBicm93c2VyIHNlc3Npb24gc3RvcmFnZVxyXG5cdCogQHJlcXVpcmVzIGxvY2FsU3RvcmFnZVxyXG5cdCogQHJlcXVpcmVzIEpTT05cclxuXHQqL1xyXG5cdHNlc3Npb25TZXQ6IGZ1bmN0aW9uKHN0ck5hbWUsIG9iail7XHJcbiAgICAgICAgc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbShzdHJOYW1lLCB0eXBlb2Ygb2JqID09PSBcInN0cmluZ1wiPyBvYmogOiBKU09OLnN0cmluZ2lmeShvYmopKTtcclxuICAgIH0sXHJcblx0LyoqXHJcblx0Ki9cclxuXHRnZXRWb2NMaXN0OiBmdW5jdGlvbigpe1xyXG4gICAgICAgIHZhciB2b2NMaXN0ID0gSlNPTi5wYXJzZShsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnVXNlci1Wb2NhYicpKXx8W107XHJcbiAgICAgICAgaWYgKHZvY0xpc3Qpe1xyXG4gICAgICAgICAgICB2YXIgdj12b2NMaXN0Lmxlbmd0aDtcclxuICAgICAgICAgICAgd2hpbGUodi0tKXtcclxuICAgICAgICAgICAgICAgIHZvY0xpc3Rbdl0uaSA9IHY7IC8vc2V0IGluZGV4IGZvciBpdGVtICgtPm91dClcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gdm9jTGlzdDtcclxuICAgIH0sXHJcblx0c2V0Vm9jTGlzdDogZnVuY3Rpb24odm9jTGlzdCl7XHJcblx0XHR0aGlzLmxvY2FsU2V0KCdVc2VyLVZvY2FiJywgdm9jTGlzdCk7XHJcblx0fSxcclxuXHQvKipcclxuXHQqL1xyXG5cdHNldFZvY0l0ZW06IGZ1bmN0aW9uKGl0ZW0pe1xyXG4gICAgICAgIC8vQXNzdW1wdGlvbjogaXRlbSBjb21lcyBvbmx5IHdpdGgga2FuamksIHJlYWRpbmcgYW5kIG1lYW5pbmdcclxuICAgICAgICBpdGVtLmxldmVsID0gMDtcclxuICAgICAgICBpdGVtLmRhdGUgPSBEYXRlLm5vdygpO1xyXG4gICAgICAgIGl0ZW0ubWFudWFsTG9jayA9IFwiXCI7XHJcbiAgICAgICAgaXRlbSA9IHNldExvY2tzKGl0ZW0pO1xyXG5cdFx0IC8vMC4xLjkgYWRkaW5nIGluICdkdWUnIHByb3BlcnR5IHRvIG1ha2UgcmV2aWV3IGJ1aWxkaW5nIHNpbXBsZXJcclxuICAgICAgICBpdGVtLmR1ZSA9IGl0ZW0uZGF0ZSArIHNyc09iamVjdFtpdGVtLmxldmVsXS5kdXJhdGlvbjtcclxuXHJcbiAgICAgICAgdmFyIHZvY0xpc3QgPSBsb2NhbEdldCgnVXNlci1Wb2NhYicpfHxbXTtcclxuXHJcblx0XHR2YXIgZm91bmQgPSB2b2NMaXN0LmZpbmQoZnVuY3Rpb24odGFzayl7XHJcbiAgICAgICAgICAgIHJldHVybiB0YXNrLmthbmppID09PSBpdGVtLmthbmppO1xyXG4gICAgICAgIH0sIHRoaXMpO1xyXG5cdFx0Ly9hZGQgbWVhbmluZyBhbmQgcmVhZGluZyB0byBleGlzdGluZyBpdGVtXHJcblx0XHQvLyAgICAgICAgdm9jTGlzdFt2XS5tZWFuaW5nID0gaXRlbS5tZWFuaW5nO1xyXG5cdFx0Ly8gICAgICB2b2NMaXN0W3ZdLnJlYWRpbmcgPSBpdGVtLnJlYWRpbmc7XHJcbiAgICAgICAgaWYgKCFmb3VuZCkge1xyXG4gICAgICAgICAgICAvL3Byb3ZpZGUgaW5kZXggZm9yIGZhc3RlciBzZWFyY2hlc1xyXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhpdGVtLmthbmppICtcIiBub3QgZm91bmQgaW4gdm9jYWJsaXN0LCBhZGRpbmcgbm93XCIpO1xyXG4gICAgICAgICAgICBpdGVtLmkgPSB2b2NMaXN0Lmxlbmd0aDtcclxuICAgICAgICAgICAgdm9jTGlzdC5wdXNoKGl0ZW0pO1xyXG5cclxuICAgICAgICAgICAgbG9jYWxTZXQoJ1VzZXItVm9jYWInLHZvY0xpc3QpO1xyXG4gICAgICAgIH1cclxuICAgIH1cclxufTtcclxuXHJcbm1vZHVsZS5leHBvcnRzID0gU3RvcmFnZVV0aWw7IiwiLyogIFRoaXMgaXMgdGhlIG9yaWdpbmFsIGNvZGUgdGhhdCBJIGFtIGJyZWFraW5nIGludG8gYml0ZSBzaXplIGJpdHMgKi9cclxuLy9ORUVEIFRPIE1BS0UgU1VSRSBCUk9XU0VSSUZZIFBVVFMgVEhJUyBPTiBUSEUgVE9QXHJcblxyXG4vLyA9PVVzZXJTY3JpcHQ9PVxyXG4vLyBAbmFtZSAgICAgICAgV2FuaWthbmkgU2VsZi1TdHVkeSBQbHVzXHJcbi8vIEBuYW1lc3BhY2UgICB3a3NlbGZzdHVkeXBsdXNcclxuLy8gQGRlc2NyaXB0aW9uIEFkZHMgYW4gb3B0aW9uIHRvIGFkZCBhbmQgcmV2aWV3IHlvdXIgb3duIGN1c3RvbSB2b2NhYnVsYXJ5XHJcbi8vIEBpbmNsdWRlICAgICAqLndhbmlrYW5pLmNvbS8qXHJcbi8vIEBpbmNsdWRlICAgICAqLndhbmlrYW5pLmNvbS9jaGF0LypcclxuLy8gQGV4Y2x1ZGVcdCAgICAqLndhbmlrYW5pLmNvbVxyXG4vLyBAaW5jbHVkZSAgICAgKi53YW5pa2FuaS5jb20vZGFzaGJvYXJkKlxyXG4vLyBAaW5jbHVkZSAgICAgKi53YW5pa2FuaS5jb20vY29tbXVuaXR5KlxyXG4vLyBAdmVyc2lvbiAgICAgMC4yLjBcclxuLy8gQGF1dGhvciAgICAgIHNodWRvdWtlbiBhbmQgRXRoYW5cclxuLy8gQHJ1bi1hdCAgICAgIGRvY3VtZW50LWVuZFxyXG4vLyBAZ3JhbnQgICAgICAgbm9uZVxyXG4vLyA9PS9Vc2VyU2NyaXB0PT1cclxuXHJcbi8qXHJcbiAqICBUaGlzIHNjcmlwdCBpcyBsaWNlbnNlZCB1bmRlciB0aGUgQ3JlYXRpdmUgQ29tbW9ucyBMaWNlbnNlXHJcbiAqICBcIkF0dHJpYnV0aW9uLU5vbkNvbW1lcmNpYWwgMy4wIFVucG9ydGVkXCJcclxuICpcclxuICogIE1vcmUgaW5mb3JtYXRpb24gYXQ6XHJcbiAqICBodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9saWNlbnNlcy9ieS1uYy8zLjAvXHJcbiAqL1xyXG5cclxuIFxyXG4gLyoqIERlc2NyaWJlcyBhbnkgb2JqZWN0IHRoYXQgY2FuIGJlIHJldmlld2VkIG9yIGxlYXJuZWQsIGluY2x1ZGVzIElSYWRpY2FsLCBJS2FuamksIGFuZCBJVm9jYWJ1bGFyeVxyXG4gKiBAdHlwZWRlZiB7T2JqZWN0fSBUYXNrXHJcbiAqIEBwcm9wZXJ0eSB7Ym9vbGVhbnxzdHJpbmd9IGxvY2tlZCAtIGxvY2tlZFxyXG4gKiBAcHJvcGVydHkge2Jvb2xlYW58c3RyaW5nfSBtYW51YWxMb2NrIC0gbWFudWFsTG9ja1xyXG4gKi9cclxuIFxyXG52YXIgU3RvcmFnZVV0aWwgPSByZXF1aXJlKCcuL3N0b3JhZ2V1dGlsLmpzJyk7XHJcbnZhciBJbXBvcnRVdGlsID0gcmVxdWlyZSgnLi9pbXBvcnR1dGlsLmpzJyk7XHJcbnZhciBXYW5pa2FuaVV0aWwgPSByZXF1aXJlKCcuL3dhbmlrYW5pdXRpbC5qcycpO1xyXG5cclxuZnVuY3Rpb24gbWFpbigpe1xyXG4gICAgXCJ1c2Ugc3RyaWN0XCI7XHJcblxyXG4gICAgJChcImhlYWRcIikucHJlcGVuZChcIjxzY3JpcHQgc3JjPSdodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvanF1ZXJ5Lm1vY2tqYXgvMS42LjEvanF1ZXJ5Lm1vY2tqYXguanMnPjwvc2NyaXB0PlwiKTtcclxuXHJcbiAgICB2YXIgQVBJa2V5ID0gXCJZT1VSX0FQSV9IRVJFXCI7XHJcbiAgICB2YXIgbG9ja3NPbiA9IHRydWU7IC8vRGlzYWJsZSB2b2NhYiBsb2NrcyAodW5sb2NrZWQgaXRlbXMgcGVyc2lzdCB1bnRpbCBkZWxldGVkKVxyXG4gICAgdmFyIGxvY2tEQiA9IHRydWU7IC8vU2V0IHRvIGZhbHNlIHRvIHVubG9jayBLYW5qaSBpcyBub3QgYXZhaWxhYmxlIG9uIFdhbmlLYW5pIChpZS4gbm90IHJldHVybmVkIGJ5IEFQSSlcclxuICAgIHZhciByZXZlcnNlID0gdHJ1ZTsgLy9JbmNsdWRlIEVuZ2xpc2ggdG8g44Gy44KJ44GM44GqIHJlYWRpbmcgcmV2aWV3c1xyXG4gICAgdmFyIGRlYnVnZ2luZyA9IHRydWU7XHJcbiAgICB2YXIgYXNXSyA9IHRydWU7IC8vUHVzaCB1c2VyIHJldmlld3MgaW50byB0aGUgbWFpbiBXSyByZXZpZXcgcXVldWVcclxuXHJcbiAgICAvLyBzaHV0IHVwIEpTSGludFxyXG4gICAgLyoganNoaW50IG11bHRpc3RyOiB0cnVlICwganF1ZXJ5OiB0cnVlLCBleHByOiB0cnVlLCBpbmRlbnQ6MiAqL1xyXG4gICAgLyogZ2xvYmFsIHdpbmRvdywgd2FuYWthbmEsIFhEb21haW5SZXF1ZXN0ICovXHJcblxyXG4gICAgLyoqIERlYnVnZ2luZ1xyXG5cdCAqL1xyXG5cdGNvbnNvbGUubG9nID0gZGVidWdnaW5nID8gZnVuY3Rpb24gKG1zZykge1xyXG5cdFx0aWYgKHR5cGVvZiBtc2cgPT09ICdzdHJpbmcnKSB7XHJcblx0XHRcdHdpbmRvdy5jb25zb2xlLmxvZyhcIldLU1M6IFwiICsgbXNnKTtcclxuXHRcdH1cclxuXHRcdGVsc2Uge1xyXG5cdFx0XHR3aW5kb3cuY29uc29sZS5sb2coXCJXS1NTOiBcIiwgbXNnKTtcclxuXHRcdH1cclxuXHR9IDogZnVuY3Rpb24gKCkge1xyXG5cdH07XHJcblx0XHJcbiAgICAkKFwiaGVhZFwiKS5wcmVwZW5kKCc8c2NyaXB0IHNyYz1cImh0dHBzOi8vcmF3Z2l0LmNvbS9XYW5pS2FuaS9XYW5hS2FuYS9tYXN0ZXIvbGliL3dhbmFrYW5hLmpzXCIgdHlwZT1cInRleHQvamF2YXNjcmlwdFwiPjwvc2NyaXB0PicpO1xyXG4gICAgXHJcbiAgICB2YXIgbG9jYWxTZXQgPSBmdW5jdGlvbihzdHJOYW1lLCBvYmope1xyXG4gICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coc3RyTmFtZSArIFwiIGlzIG9mIHR5cGUgXCIgKyB0eXBlb2Ygb2JqKTtcclxuICAgICAgICBpZiAodHlwZW9mIG9iaiA9PT0gXCJvYmplY3RcIilcclxuICAgICAgICAgICAgb2JqPUpTT04uc3RyaW5naWZ5KG9iaik7XHJcbiAgICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oc3RyTmFtZSwgb2JqKTtcclxuICAgIH07XHJcblxyXG5cdC8vdHJhY2sgdmVyc2lvbnMgJiBkYXRhdHlwZXNcclxuXHRsb2NhbFNldChcIldLU1NkYXRhXCIsIHtcclxuICAgICAgICB2OiBcIjAuMS4xM1wiLFxyXG4gICAgICAgIHByb3BlcnR5VHlwZToge1xyXG5cdFx0XHRtZWFuaW5nOiBcImFycmF5XCIsIHJlYWRpbmc6IFwiYXJyYXlcIiwga2Fuamk6IFwic3RyaW5nXCIsIGk6XCJudW1iZXJcIiwgY29tcG9uZW50czogXCJhcnJheVwiLCBkYXRlOiBcIm51bWJlclwiLCBkdWU6IFwibnVtYmVyXCIsIGxvY2tlZDogXCJzdHJpbmdcIiwgbWFudWFsTG9jazogXCJzdHJpbmdcIlxyXG5cdFx0fSxcclxuICAgICAgICBwcm9wZXJ0eURlc2M6IHtcclxuXHRcdFx0bWVhbmluZzogXCJsaXN0IG9mIG1lYW5pbmdzXCIsIHJlYWRpbmc6IFwibGlzdCBvZiByZWFkaW5nc1wiLCBrYW5qaTogXCJpdGVtIHByb21wdFwiLCBpOlwiaXRlbSBpbmRleFwiLCBjb21wb25lbnRzOiBcImthbmppIGZvdW5kIGluIHdvcmRcIiwgZGF0ZTogXCJ0aW1lc3RhbXAgb2YgbmV3IGxldmVsXCIsIGR1ZTogXCJ0aW1lc3RhbXAgb2YgaXRlbSdzIG5leHQgcmV2aWV3XCIsIGxvY2tlZDogXCJpbmRpY2F0b3Igb2Ygd2hldGhlciBjb21wb25lbnRzIGFyZSBlbGlnaWJsZVwiLCBtYW51YWxMb2NrOiBcImxhdGNoIGZvciAnbG9ja2VkJyBzbyBmYWlsaW5nIGNvbXBvbmVudHMgZG9uJ3QgcmUtbG9jayB0aGUgaXRlbVwiXHJcblx0XHR9XHJcbiAgICB9KTtcclxuXHJcblxyXG4gICAgLyoqIFNldHRpbmdzIGFuZCBjb25zdGFudHNcclxuXHQgKi9cclxuICAgIHZhciBlcnJvckFsbG93YW5jZSA9IDQ7IC8vZXZlcnkgeCBsZXR0ZXJzLCB5b3UgY2FuIG1ha2Ugb25lIG1pc3Rha2Ugd2hlbiBlbnRlcmluZyB0aGUgbWVhbmluZ1xyXG5cclxuICAgIC8vc3JzIDRoLCA4aCwgMjRoLCAzZCAoZ3VydSksIDF3LCAydyAobWFzdGVyKSwgMW0gKGVubGlnaHRlbmVkKSwgNG0gKGJ1cm5lZClcclxuICAgIFxyXG4gICAgdmFyIGhycyA9IDYwKjYwKjEwMDA7XHJcbiAgICB2YXIgZGF5cyA9IDI0KmhycztcclxuICAgIHZhciB3ZWVrcyA9IDcqZGF5cztcclxuXHR2YXIgc3JzT2JqZWN0ID0gW1xyXG5cdFx0e2xldmVsOiAwLCByYW5rOiBcIlN0YXJ0ZWRcIixcdFx0ZHVyYXRpb246IDB9LCBcclxuXHRcdHtsZXZlbDogMSwgcmFuazogXCJBcHByZW50aWNlXCIsXHRkdXJhdGlvbjogNCpocnN9LFxyXG5cdFx0e2xldmVsOiAyLCByYW5rOiBcIkFwcHJlbnRpY2VcIixcdGR1cmF0aW9uOiA4Kmhyc30sXHJcblx0XHR7bGV2ZWw6IDMsIHJhbms6IFwiQXBwcmVudGljZVwiLFx0ZHVyYXRpb246IDEqZGF5c30sXHJcblx0XHR7bGV2ZWw6IDQsIHJhbms6IFwiQXBwcmVudGljZVwiLFx0ZHVyYXRpb246IDMqZGF5c30sXHJcblx0XHR7bGV2ZWw6IDUsIHJhbms6IFwiR3VydVwiLFx0XHRkdXJhdGlvbjogMSp3ZWVrc30sXHJcblx0XHR7bGV2ZWw6IDYsIHJhbms6IFwiR3VydVwiLFx0XHRkdXJhdGlvbjogMip3ZWVrc30sXHJcblx0XHR7bGV2ZWw6IDcsIHJhbms6IFwiTWFzdGVyXCIsXHRcdGR1cmF0aW9uOiA3MzAqaHJzfSxcclxuXHRcdHtsZXZlbDogOCwgcmFuazogXCJFbmxpZ2h0ZW5lZFwiLFx0ZHVyYXRpb246IDI5MjIqaHJzfSxcclxuXHRcdHtsZXZlbDogOSwgcmFuazogXCJCdXJuZWRcIn1cclxuXHRdO1xyXG5cclxuXHR2YXIgcGFyc2VTdHJpbmcgPSBmdW5jdGlvbihzdHJPYmope1xyXG4gICAgICAgIC8vYXZvaWRzIGR1cGxpY2F0aW9uIG9mIGNvZGUgZm9yIHNlc3NzaW9uR2V0IGFuZCBsb2NhbEdldFxyXG4gICAgICAgIHZhciBvYmo7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgb2JqID0gSlNPTi5wYXJzZShzdHJPYmopO1xyXG4gICAgICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwiVmFyaWFibGUgaXMgb2YgdHlwZSBcIiArIHR5cGVvZiBvYmopO1xyXG4gICAgICAgIH1cclxuXHRcdGNhdGNoKGUpe1xyXG4gICAgICAgICAgICBpZiAoZS5uYW1lID09PSBcIlN5bnRheEVycm9yXCIpe1xyXG4gICAgICAgICAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhzdHJPYmogKyBcIiBpcyBhbiBvcmRpbmFyeSBzdHJpbmcgdGhhdCBjYW5ub3QgYmUgcGFyc2VkLlwiKTtcclxuICAgICAgICAgICAgICAgIG9iaiA9IHN0ck9iajtcclxuICAgICAgICAgICAgfVxyXG5cdFx0XHRlbHNle1xyXG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkNvdWxkIG5vdCBwYXJzZSBcIiArIHN0ck9iaiArIFwiLiBFcnJvcjogXCIsIGUpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBvYmo7XHJcbiAgICB9O1xyXG5cclxuXHJcblx0dmFyIGxvY2FsR2V0ID0gZnVuY3Rpb24oc3RyTmFtZSl7XHJcbiAgICAgICAgdmFyIHN0ck9iaiA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKHN0ck5hbWUpO1xyXG4gICAgICAgIHJldHVybiBwYXJzZVN0cmluZyhzdHJPYmopO1xyXG4gICAgfTtcclxuICAgIFxyXG5cdC8vIEluaXRpYWxpc2UgVXNlci1Wb2NhYlxyXG5cdFN0b3JhZ2VVdGlsLmluaXRTdG9yYWdlKCk7XHJcblx0XHJcblx0Ly9HTV9hZGRTdHlsZSBzaGltIGZvciBjb21wYXRpYmlsaXR5IHdpdGggZ3JlYXNlbW9ua2V5XHJcbiAgICB2YXIgZ01fYWRkU3R5bGUgPSBmdW5jdGlvbihDc3NTdHJpbmcpe1xyXG4gICAgICAgIC8vZ2V0IERPTSBoZWFkXHJcbiAgICAgICAgdmFyIGhlYWQgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnaGVhZCcpWzBdO1xyXG4gICAgICAgIGlmIChoZWFkKSB7XHJcbiAgICAgICAgICAgIC8vYnVpbGQgc3R5bGUgdGFnXHJcbiAgICAgICAgICAgIHZhciBzdHlsZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3N0eWxlJyk7XHJcbiAgICAgICAgICAgIHN0eWxlLnNldEF0dHJpYnV0ZSgndHlwZScsICd0ZXh0L2NzcycpO1xyXG4gICAgICAgICAgICBzdHlsZS50ZXh0Q29udGVudCA9IENzc1N0cmluZztcclxuICAgICAgICAgICAgLy9pbnNlcnQgRE9NIHN0eWxlIGludG8gaGVhZFxyXG4gICAgICAgICAgICBoZWFkLmFwcGVuZENoaWxkKHN0eWxlKTtcclxuICAgICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIC8qKiAgSlF1ZXJ5IGZpeGVzXHJcblx0ICovXHJcbiAgICAkKFwiW3BsYWNlaG9sZGVyXVwiKS5mb2N1cyhmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgdmFyIGlucHV0ID0gJCh0aGlzKTtcclxuICAgICAgICBpZiAoaW5wdXQudmFsKCkgPT0gaW5wdXQuYXR0cihcInBsYWNlaG9sZGVyXCIpKSB7XHJcbiAgICAgICAgICAgIGlucHV0LnZhbChcIicnXCIpO1xyXG4gICAgICAgICAgICBpbnB1dC5yZW1vdmVDbGFzcyhcIidwbGFjZWhvbGRlcidcIik7XHJcbiAgICAgICAgfVxyXG4gICAgfSkuYmx1cihmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgdmFyIGlucHV0ID0gJCh0aGlzKTtcclxuICAgICAgICBpZiAoaW5wdXQudmFsKCkgPT0gXCInJ1wiIHx8IGlucHV0LnZhbCgpID09IGlucHV0LmF0dHIoXCJwbGFjZWhvbGRlclwiKSkge1xyXG4gICAgICAgICAgICBpbnB1dC5hZGRDbGFzcyhcInBsYWNlaG9sZGVyXCIpO1xyXG4gICAgICAgICAgICBpbnB1dC52YWwoaW5wdXQuYXR0cihcInBsYWNlaG9sZGVyXCIpKTtcclxuICAgICAgICB9XHJcbiAgICB9KS5ibHVyKCk7XHJcblxyXG4gICAgJChcIltwbGFjZWhvbGRlcl1cIikucGFyZW50cyhcImZvcm1cIikuc3VibWl0KGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAkKHRoaXMpLmZpbmQoXCJbcGxhY2Vob2xkZXJdXCIpLmVhY2goZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICAgICB2YXIgaW5wdXQgPSAkKHRoaXMpO1xyXG4gICAgICAgICAgICBpZiAoaW5wdXQudmFsKCkgPT0gaW5wdXQuYXR0cihcInBsYWNlaG9sZGVyXCIpKSB7XHJcbiAgICAgICAgICAgICAgICBpbnB1dC52YWwoXCJcIik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgIH0pO1xyXG5cclxuXHQvKiogSGFuZGxlIHRoZSB1c2VycyBBUEkga2V5LlxyXG5cdCogQHBhcmFtIHtzdHJpbmd9IEFQSWtleSAtIHRoZSB1c2VycyBBUEkga2V5IHRvIHNldC4gSWYgZ2l2ZW4gXCJZT1VSX0FQSV9IRVJFXCIsIGl0IHdpbGwgcmV0dXJuIHRoZSBrZXkgaW4gYnJvd3NlciBzdG9yYWdlLlxyXG5cdCogQHJldHVybnMge3N0cmluZ30gdGhlIHVzZXJzIEFQSSBrZXkgYXMgc3VwcGxpZWQgYW5kIHN0b3JlZCwgb3IgaW4gdGhlIGNhc2Ugb2YgXCJZT1VSX0FQSV9IRVJFXCIgYmVpbmcgcGFzc2VkLCB0aGUgc3RvcmVkIGtleS5cclxuXHQqL1xyXG4gICAgdmFyIGdldFNldEFwaSA9IGZ1bmN0aW9uKEFQSWtleSl7XHJcbiAgICAgICAgdmFyIHN0b3JlZEFQSSA9IGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdXYW5pS2FuaS1BUEknKTtcclxuICAgICAgICBpZiAoQVBJa2V5ID09PSBcIllPVVJfQVBJX0hFUkVcIil7XHJcbiAgICAgICAgICAgIGlmIChzdG9yZWRBUEkgIT09IG51bGwpe1xyXG4gICAgICAgICAgICAgICAgQVBJa2V5ID0gc3RvcmVkQVBJO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cdFx0ZWxzZXtcclxuICAgICAgICAgICAgLy9BUEkgaGFzIGJlZW4gc2V0IGluIGNvZGUuXHJcbiAgICAgICAgICAgIGlmIChzdG9yZWRBUEkgIT09IEFQSWtleSl7XHJcbiAgICAgICAgICAgICAgICBsb2NhbFNldCgnV2FuaUthbmktQVBJJywgQVBJa2V5KTsvL292ZXJ3cml0ZSB3aXRoIG5ldyBBUElcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gQVBJa2V5O1xyXG4gICAgfTtcclxuICAgIEFQSWtleSA9IGdldFNldEFwaShBUElrZXkpO1xyXG5cclxuICAgIC8vLS0tLS0tLS0tLS0tLS1TdGFydCBJbnNlcnQgSW50byBXSyBSZXZpZXcgRnVuY3Rpb25zLS0tLS0tLS0tLS0tLS1cclxuXHJcblx0LyoqIE1lc3NpbmcgYXJvdW5kIHdpdGggdmFuaWxsYSBXYW5pS2FuaSByZXZpZXcgdmFyaWFibGVzXHJcblx0Ki9cclxuICAgIHZhciBqb2luUmV2aWV3cyA9IGZ1bmN0aW9uKFdLSXRlbXMpe1xyXG4gICAgICAgIGNvbnNvbGUubG9nKFwiam9pbmluZyByZXZpZXdzXCIpO1xyXG4gICAgICAgICQualN0b3JhZ2Uuc3RvcExpc3RlbmluZyhcInJldmlld1F1ZXVlXCIsIGpvaW5SZXZpZXdzKTtcclxuICAgICAgICB2YXIgV0tyZXZpZXcgPSAkLmpTdG9yYWdlLmdldChcInJldmlld1F1ZXVlXCIpfHxbXTtcclxuICAgICAgICB2YXIgV0tjb21iaW5lZCA9IFdLcmV2aWV3LmNvbmNhdChXS0l0ZW1zKTtcclxuICAgICAgICAkLmpTdG9yYWdlLnNldChcInJldmlld1F1ZXVlXCIsIFdLY29tYmluZWQpO1xyXG4gICAgfTtcclxuXHJcbiAgICB2YXIgV0tJdGVtcyA9IFtdO1xyXG4gICAgY29uc29sZS5ncm91cENvbGxhcHNlZChcIkxvYWRpbmcgSXRlbXNcIik7XHJcblx0XHJcblx0dmFyIHdLU1NfdG9fV0sgPSBmdW5jdGlvbihXS1NTSXRlbSl7XHJcbiAgICAgICAgdmFyIFdLSXRlbSA9IHt9O1xyXG4gICAgICAgIC8vICAgIFdLSXRlbS5hdWQgPSBcIlwiO1xyXG4gICAgICAgIFdLSXRlbS5lbiA9IFdLU1NJdGVtLm1lYW5pbmcubWFwKGZ1bmN0aW9uKHMpIHtcclxuXHRcdFx0IC8vdHJpbSB3aGl0ZXNwYWNlIGFuZCBjYXBpdGFsaXplIHdvcmRzXHJcblx0XHRcdCByZXR1cm4gcy50cmltKCkucmVwbGFjZSgvXFxiXFx3L2cgLCBmdW5jdGlvbihtKXtcclxuXHRcdFx0XHRyZXR1cm4gbS50b1VwcGVyQ2FzZSgpO1xyXG5cdFx0XHR9KTtcclxuXHRcdH0pO1xyXG4gICAgICAgIFdLSXRlbS5pZCA9IFwiV0tTU1wiICsgV0tTU0l0ZW0uaTtcclxuICAgICAgICBXS0l0ZW0ua2FuYSA9IFdLU1NJdGVtLnJlYWRpbmc7XHJcbiAgICAgICAgV0tJdGVtLnNycyA9IFdLU1NJdGVtLmxldmVsKzE7Ly9XSyBzdGFydHMgbGV2ZWxzIGZyb20gMSwgV0tTUyBzdGFydHMgdGhlbSBmcm9tIDBcclxuICAgICAgICBXS0l0ZW0udm9jID0gV0tTU0l0ZW0ua2Fuamk7XHJcbiAgICAgICAgV0tJdGVtLmNvbXBvbmVudHMgPSBXS1NTSXRlbS5jb21wb25lbnRzO1xyXG5cclxuICAgICAgICBXS0l0ZW0uc3luID0gW107XHJcbiAgICAgICAgLy9BZGQgc3lub255bXMgb2Ygc3RyaW5ncyB3aXRob3V0IGJyYWNrZXRlZCBpbmZvIHRvIGdldCBhcm91bmQgY2hlY2tpbmcgdGhlIGZ1bGwgc3RyaW5nIGluY2x1ZGluZyBicmFja2V0c1xyXG4gICAgICAgIFdLU1NJdGVtLm1lYW5pbmcuZm9yRWFjaChmdW5jdGlvbihtZWFuaW5nKXtcclxuICAgICAgICAgICAgdmFyIG9wZW5CcmFja2V0ID0gbWVhbmluZy5pbmRleE9mKFwiKFwiKTtcclxuICAgICAgICAgICAgaWYgKG9wZW5CcmFja2V0ICE9PSAtMSAmJiBtZWFuaW5nLmluZGV4T2YoXCIpXCIpICE9PSAtMSl7XHJcbiAgICAgICAgICAgICAgICBXS0l0ZW0uc3luLnB1c2gobWVhbmluZy5zdWJzdHIoMCwgb3BlbkJyYWNrZXQpLnRyaW0oKS5yZXBsYWNlKC9cXGJcXHcvZyAsIGZ1bmN0aW9uKG0peyByZXR1cm4gbS50b1VwcGVyQ2FzZSgpO30pKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH0sIHRoaXMpO1xyXG5cclxuICAgICAgICByZXR1cm4gV0tJdGVtO1xyXG4gICAgfTtcclxuXHJcblx0dmFyIGxvYWRUYXNrcyA9IGZ1bmN0aW9uKHVzZXJWb2NhYiwgaSwgdXNlclZvY2Ficyl7XHJcbiAgICAgICAgdmFyIGR1ZU5vdyA9ICh1c2VyVm9jYWIubG9ja2VkID09PSBcIm5vXCIgJiYgdXNlclZvY2FiLmxldmVsIDwgOSAmJiBEYXRlLm5vdygpID4gdXNlclZvY2FiLmR1ZSk7XHJcblxyXG4gICAgICAgIGlmIChkdWVOb3cpe1xyXG4gICAgICAgICAgICBpZiAodXNlclZvY2FiLmthbmppLmxlbmd0aCAqIHVzZXJWb2NhYi5tZWFuaW5nWzBdLmxlbmd0aCAqIHVzZXJWb2NhYi5yZWFkaW5nWzBdLmxlbmd0aCl7XHJcbiAgICAgICAgICAgICAgICAvL1NvcnJ5LCB3ZSBuZWVkIGFsbCB0aHJlZSB0byBhZGQgdG8gV0sgcmV2aWV3LCBubyBrYW5hIG9ubHkgd2l0aG91dCByZWFkaW5ncyBldGMuXHJcbiAgICAgICAgICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwiaXRlbTpcIiArIHVzZXJWb2NhYi5rYW5qaSArIFwiLCBcIiArIHVzZXJWb2NhYi5sb2NrZWQgK1wiID09PSBcXFwibm9cXFwiICYmIFwiICsgdXNlclZvY2FiLmxldmVsICsgXCIgPCA5ICYmIFwiICsgRGF0ZS5ub3coKSArIFwiID4gXCIgKyB1c2VyVm9jYWIuZHVlKTtcclxuICAgICAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coZHVlTm93KTtcclxuICAgICAgICAgICAgICAgIFdLSXRlbXMucHVzaCh3S1NTX3RvX1dLKHVzZXJWb2NhYikpO1xyXG4gICAgICAgICAgICB9ZWxzZXtcclxuICAgICAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJJdGVtIFwiICsgdXNlclZvY2FiLmthbmppICsgXCIgY291bGQgbm90IGJlIGFkZGVkLCBpdCBpcyBtaXNzaW5nIG9uZSBvciBtb3JlIG9mIHRoZSBlc3NlbnRpYWwgZmllbGRzIGZvciBhIFdLIHZvY2FidWxhcnkgcmV2aWV3XCIpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxuXHRcclxuICAgIHZhciB1c2VyVm9jYWJzID0gbG9jYWxHZXQoXCJVc2VyLVZvY2FiXCIpfHxbXTtcclxuICAgIHVzZXJWb2NhYnMuZm9yRWFjaChsb2FkVGFza3MpOy8vLCB0aGlzKTtcclxuICAgIGNvbnNvbGUuZ3JvdXBFbmQoKTtcclxuXHRcclxuICAgIC8vd2hlcmUgdGhlIG1hZ2ljIGhhcHBlbnNcclxuICAgIGlmIChhc1dLKXtcclxuICAgICAgICAkLmpTdG9yYWdlLmxpc3RlbktleUNoYW5nZShcInJldmlld1F1ZXVlXCIsIGZ1bmN0aW9uKCl7am9pblJldmlld3MoV0tJdGVtcyk7fSk7XHJcbiAgICB9XHJcblxyXG4gICAgdmFyIHNlc3Npb25TZXQgPSBmdW5jdGlvbihzdHJOYW1lLCBvYmope1xyXG4gICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coc3RyTmFtZSArIFwiIGlzIG9mIHR5cGUgXCIgKyB0eXBlb2Ygb2JqKTtcclxuICAgICAgICBpZiAodHlwZW9mIG9iaiA9PT0gXCJvYmplY3RcIilcclxuICAgICAgICAgICAgb2JqPUpTT04uc3RyaW5naWZ5KG9iaik7XHJcbiAgICAgICAgc2Vzc2lvblN0b3JhZ2Uuc2V0SXRlbShzdHJOYW1lLCBvYmopO1xyXG4gICAgfTtcclxuXHRcclxuICAgIHZhciBzZXNzaW9uR2V0ID0gZnVuY3Rpb24oc3RyTmFtZSl7XHJcbiAgICAgICAgdmFyIHN0ck9iaiA9IHNlc3Npb25TdG9yYWdlLmdldEl0ZW0oc3RyTmFtZSk7XHJcbiAgICAgICAgcmV0dXJuIHBhcnNlU3RyaW5nKHN0ck9iaik7XHJcbiAgICB9O1xyXG5cclxuXHR2YXIgZ2VuZXJhdGVSZXZpZXdMaXN0ID0gZnVuY3Rpb24ocmV2aWV3QWN0aXZlKSB7XHJcbiAgICAgICAgLy9kb24ndCBpbnRlcmZlcmUgd2l0aCBhbiBhY3RpdmUgc2Vzc2lvblxyXG4gICAgICAgIGlmIChyZXZpZXdBY3RpdmUpe1xyXG4gICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndXNlci1yZXZpZXcnKS5pbm5lckhUTUwgPSBcIlJldmlldyBpbiBQcm9ncmVzc1wiO1xyXG4gICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwiZ2VuZXJhdGVSZXZpZXdMaXN0KClcIik7XHJcbiAgICAgICAgLy8gZnVuY3Rpb24gZ2VuZXJhdGVSZXZpZXdMaXN0KCkgYnVpbGRzIGEgcmV2aWV3IHNlc3Npb24gYW5kIHVwZGF0ZXMgdGhlIGh0bWwgbWVudSB0byBzaG93IG51bWJlciB3YWl0aW5nLlxyXG4gICAgICAgIHZhciBudW1SZXZpZXdzID0gMDtcclxuICAgICAgICB2YXIgc29vbmVzdCA9IEluZmluaXR5O1xyXG4gICAgICAgIHZhciBuZXh0O1xyXG5cclxuICAgICAgICB2YXIgcmV2aWV3TGlzdCA9IFtdO1xyXG5cclxuICAgICAgICAvL2NoZWNrIHRvIHNlZSBpZiB0aGVyZSBpcyB2b2NhYiBhbHJlYWR5IGluIG9mZmxpbmUgc3RvcmFnZVxyXG4gICAgICAgIGlmIChsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnVXNlci1Wb2NhYicpKSB7XHJcbiAgICAgICAgICAgIHZhciB2b2NhYkxpc3QgPSBTdG9yYWdlVXRpbC5nZXRWb2NMaXN0KCk7XHJcbiAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2codm9jYWJMaXN0KTtcclxuICAgICAgICAgICAgdmFyIG5vdyA9IERhdGUubm93KCk7XHJcblxyXG4gICAgICAgICAgICAvL2ZvciBlYWNoIHZvY2FiIGluIHN0b3JhZ2UsIGdldCB0aGUgYW1vdW50IG9mIHRpbWUgdm9jYWIgaGFzIGxpdmVkXHJcbiAgICAgICAgICAgIC8vdmFyIGkgPSB2b2NhYkxpc3QubGVuZ3RoO1xyXG4gICAgICAgICAgICAvL3doaWxlKGktLSl7XHJcblx0XHRcdHZvY2FiTGlzdC5mb3JFYWNoKGZ1bmN0aW9uKHRhc2ssIGkpe1xyXG4gICAgICAgICAgICAgICAgdmFyIGR1ZSA9IHRhc2suZGF0ZSArIHNyc09iamVjdFt0YXNrLmxldmVsXS5kdXJhdGlvbjtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBpZiB0ZW0gaXMgdW5sb2NrZWQgYW5kIHVuYnVybmVkXHJcbiAgICAgICAgICAgICAgICBpZiAodGFzay5sZXZlbCA8IDkgJiZcclxuICAgICAgICAgICAgICAgICAgICAodGFzay5tYW51YWxMb2NrID09PSBcIm5vXCIgfHwgdGFzay5tYW51YWxMb2NrID09PSBcIm5cIiB8fFxyXG4gICAgICAgICAgICAgICAgICAgICB0YXNrLm1hbnVhbExvY2sgPT09XCJEQlwiICYmICFsb2NrREIgKSl7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gaWYgaXQgaXMgcGFzdCByZXZpZXcgdGltZVxyXG4gICAgICAgICAgICAgICAgICAgIGlmKG5vdyA+PSBkdWUpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY291bnQgdm9jYWIgdXAgZm9yIHJldmlld1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBudW1SZXZpZXdzKys7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBhZGQgaXRlbS1tZWFuaW5nIG9iamVjdCB0byByZXZpZXdMaXN0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGhhdmUgbWFkZSB0aGlzIG9wdGlvbmFsIGZvciBzdXJuYW1lIGxpc3RzIGV0Yy5cclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRhc2subWVhbmluZ1swXSAhPT0gXCJcIikge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9SZXZfSXRlbSBvYmplY3QgYXJnczogcHJvbXB0LCBrYW5qaSwgdHlwZSwgc29sdXRpb24sIGluZGV4XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmV2SXRlbSA9IG5ldyBSZXZfSXRlbSh0YXNrLmthbmppLCB0YXNrLmthbmppLCBcIk1lYW5pbmdcIiwgdGFzay5tZWFuaW5nLCBpKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldmlld0xpc3QucHVzaChyZXZJdGVtKTtcclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcmVhZGluZyBpcyBvcHRpb25hbCwgaWYgdGhlcmUgaXMgYSByZWFkaW5nIGZvciB0aGUgdm9jYWIsIGFkZCBpdHMgb2JqZWN0LlxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodGFzay5yZWFkaW5nWzBdICE9PSBcIlwiKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL1Jldl9JdGVtIG9iamVjdCBhcmdzOiBwcm9tcHQsIGthbmppLCB0eXBlLCBzb2x1dGlvbiwgaW5kZXhcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZXZJdGVtMiA9IG5ldyBSZXZfSXRlbSh0YXNrLmthbmppLCB0YXNrLmthbmppLCBcIlJlYWRpbmdcIiwgdGFzay5yZWFkaW5nLCBpKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldmlld0xpc3QucHVzaChyZXZJdGVtMik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vaWYgdGhlcmUgaXMgYSBtZWFuaW5nIGFuZCByZWFkaW5nLCBhbmQgcmV2ZXJzZSBmbGFnIGlzIHRydWUsIHRlc3QgcmVhZGluZyBmcm9tIGVuZ2xpc2hcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRhc2sucmVhZGluZ1swXSAhPT0gXCJcIiAmJiB0YXNrLm1lYW5pbmdbMF0gIT09IFwiXCIgJiYgcmV2ZXJzZSl7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvL1Jldl9JdGVtIG9iamVjdCBhcmdzOiBwcm9tcHQsIGthbmppLCB0eXBlLCBzb2x1dGlvbiwgaW5kZXhcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZXZJdGVtMyA9IG5ldyBSZXZfSXRlbSh0YXNrLm1lYW5pbmcuam9pbihcIiwgXCIpLCB0YXNrLmthbmppLCBcIlJldmVyc2VcIiwgdGFzay5yZWFkaW5nLCBpKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldmlld0xpc3QucHVzaChyZXZJdGVtMyk7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG5cdFx0XHRcdFx0ZWxzZXsvL3VubG9ja2VkL3VuYnVybmVkIGJ1dCBub3QgdGltZSB0byByZXZpZXcgeWV0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJzZXR0aW5nIHNvb25lc3RcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG5leHQgPSBkdWUgLSBub3c7XHJcblx0XHRcdFx0XHRcdHNvb25lc3QgPSBNYXRoLm1pbihzb29uZXN0LCBuZXh0KTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcblx0XHRcdFx0fS8vZW5kIGlmIGl0ZW0gaXMgdXAgZm9yIHJldmlld1xyXG5cdFx0XHR9LCB0aGlzKTsvLyBlbmQgaXRlcmF0ZSB0aHJvdWdoIHZvY2FibGlzdFxyXG5cdFx0fS8vIGVuZCBpZiBsb2NhbFN0b3JhZ2VcclxuICAgICAgICBpZiAocmV2aWV3TGlzdC5sZW5ndGggIT09IDApe1xyXG4gICAgICAgICAgICAvL3N0b3JlIHJldmlld0xpc3QgaW4gY3VycmVudCBzZXNzaW9uXHJcbiAgICAgICAgICAgIHNlc3Npb25TZXQoJ1VzZXItUmV2aWV3JywgSlNPTi5zdHJpbmdpZnkocmV2aWV3TGlzdCkpO1xyXG4gICAgICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKHJldmlld0xpc3QpO1xyXG4gICAgICAgIH1cclxuXHRcdGVsc2V7XHJcbiAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJyZXZpZXdMaXN0IGlzIGVtcHR5OiBcIitKU09OLnN0cmluZ2lmeShyZXZpZXdMaXN0KSk7XHJcblx0XHRcdGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd1c2VyLXJldmlldycpLmlubmVySFRNTCA9IHNvb25lc3Q8SW5maW5pdHk/IFwiTmV4dCBSZXZpZXcgaW4gXCIrbXMyc3RyKHNvb25lc3QpIDogXCJObyBSZXZpZXdzIEF2YWlsYWJsZVwiO1xyXG5cdFx0fVxyXG4gICAgICAgIHZhciBzdHJSZXZpZXdzID0gbnVtUmV2aWV3cy50b1N0cmluZygpO1xyXG5cclxuICAgICAgICAvKiBJZiB5b3Ugd2FudCB0byBkbyB0aGUgNDIrIHRoaW5nLlxyXG5cdFx0IGlmIChudW1SZXZpZXdzID4gNDIpIHtcclxuXHRcdCBzdHJSZXZpZXdzID0gXCI0MitcIjsgLy9oYWlsIHRoZSBjcmFiaWdhdG9yIVxyXG5cdFx0IH1cclxuXHRcdC8vKi9cclxuXHJcbiAgICAgICAgLy8gcmV0dXJuIHRoZSBudW1iZXIgb2YgcmV2aWV3c1xyXG4gICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2cobnVtUmV2aWV3cy50b1N0cmluZygpICtcIiByZXZpZXdzIGNyZWF0ZWRcIik7XHJcbiAgICAgICAgaWYgKG51bVJldmlld3MgPiAwKXtcclxuICAgICAgICAgICAgdmFyIHJldmlld1N0cmluZyA9IChzb29uZXN0ICE9PSB2b2lkIDApPyBcIjxici8+XFxcclxuTW9yZSB0byBjb21lIGluIFwiK21zMnN0cihzb29uZXN0KTpcIlwiO1xyXG4gICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgndXNlci1yZXZpZXcnKS5pbm5lckhUTUwgPSBcIlJldmlldyAoXCIgKyBzdHJSZXZpZXdzICsgXCIpXCIgKyByZXZpZXdTdHJpbmc7XHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxuXHJcblx0XHJcbi8qXHJcbiogcG9wdWxhdGUgcmV2aWV3cyB3aGVuIG1lbnUgYnV0dG9uIHByZXNzZWRcclxuKi9cclxuXHJcbndpbmRvdy5nZW5lcmF0ZVJldmlld0xpc3QgPSBmdW5jdGlvbigpIHtcclxuXHQvL2lmIG1lbnUgaXMgaW52aXNpYmxlLCBpdCBpcyBhYm91dCB0byBiZSB2aXNpYmxlXHJcblx0aWYgKCAkKFwiI1dLU1NfZHJvcGRvd25cIikuaXMoXCI6aGlkZGVuXCIpICl7XHJcblx0XHQvL1RoaXMgaXMgcmVhbGx5IHRoZSBvbmx5IHRpbWUgaXQgbmVlZHMgdG8gcnVuXHJcblx0XHQvL3VubGVzcyB3ZSB3YW50IHRvIHN0YXJ0IHVwZGF0aW5nIGluIHJlYWx0aW1lIGJ5IGtlZXBpbmcgdHJhY2sgb2YgdGhlIHNvb25lc3QgaXRlbVxyXG5cdFx0Z2VuZXJhdGVSZXZpZXdMaXN0KCk7XHJcblx0fVxyXG59O1xyXG5cclxuLypcclxuKiAgQWRkIEl0ZW1cclxuKi9cclxuLy8gZXZlbnQgZnVuY3Rpb24gdG8gb3BlbiBcImFkZCB3aW5kb3dcIiBhbmQgY2xvc2UgYW55IG90aGVyIHdpbmRvdyB0aGF0IG1pZ2h0IGJlIG9wZW4gYXQgdGhlIHRpbWUuXHJcbndpbmRvdy5XS1NTX2FkZCA9IGZ1bmN0aW9uICgpIHtcclxuXHQvL3Nob3cgdGhlIGFkZCB3aW5kb3dcclxuXHQkKFwiI2FkZFwiKS5zaG93KCk7XHJcblx0Ly9oaWRlIG90aGVyIHdpbmRvd3NcclxuXHQkKFwiI2V4cG9ydFwiKS5oaWRlKCk7XHJcblx0JChcIiNpbXBvcnRcIikuaGlkZSgpO1xyXG5cdCQoXCIjZWRpdFwiKS5oaWRlKCk7XHJcblx0JChcIiNzZWxmc3R1ZHlcIikuaGlkZSgpO1xyXG59O1xyXG5cclxuLy8nYWRkIHdpbmRvdycgaHRtbCB0ZXh0XHJcbnZhciBhZGRIdG1sID0gJ1xcblxcXHJcbjxkaXYgaWQ9XCJhZGRcIiBjbGFzcz1cIldLU1NcIj5cXG5cXFxyXG48Zm9ybSBpZD1cImFkZEZvcm1cIj5cXG5cXFxyXG48YnV0dG9uIGlkPVwiQWRkQ2xvc2VCdG5cIiBjbGFzcz1cIndrc3MtY2xvc2VcIiB0eXBlPVwicmVzZXRcIj48aSBjbGFzcz1cImljb24tcmVtb3ZlXCI+PC9pPjwvYnV0dG9uPlxcblxcXHJcbjxoMT5BZGQgYSBuZXcgSXRlbTwvaDE+XFxuXFxcclxuPGlucHV0IHR5cGU9XCJ0ZXh0XCIgaWQ9XCJhZGRLYW5qaVwiIHBsYWNlaG9sZGVyPVwiRW50ZXIg5ryi5a2XLCDjgbLjgonjgYzjgaogb3Ig44Kr44K/44Kr44OKXCI+XFxuXFxcclxuPGlucHV0IHR5cGU9XCJ0ZXh0XCIgaWQ9XCJhZGRSZWFkaW5nXCIgdGl0bGU9XCJMZWF2ZSBlbXB0eSB0byBhZGQgdm9jYWJ1bGFyeSBsaWtlIOOBmeOCiyAodG8gZG8pXCIgcGxhY2Vob2xkZXI9XCJFbnRlciByZWFkaW5nXCI+XFxuXFxcclxuPGlucHV0IHR5cGU9XCJ0ZXh0XCIgaWQ9XCJhZGRNZWFuaW5nXCIgcGxhY2Vob2xkZXI9XCJFbnRlciBtZWFuaW5nXCI+XFxuXFxcclxuXFxuXFxcclxuPHAgaWQ9XCJhZGRTdGF0dXNcIj5SZWFkeSB0byBhZGQuLjwvcD5cXG5cXFxyXG48YnV0dG9uIGlkPVwiQWRkSXRlbUJ0blwiIHR5cGU9XCJidXR0b25cIj5BZGQgbmV3IEl0ZW08L2J1dHRvbj5cXG5cXFxyXG48L2Zvcm0+XFxuXFxcclxuPC9kaXY+XFxuJztcclxuXHJcbi8vYWRkIGh0bWwgdG8gcGFnZSBzb3VyY2VcclxuJChcImJvZHlcIikuYXBwZW5kKGFkZEh0bWwpO1xyXG5cclxuLy9oaWRlIGFkZCB3aW5kb3cgKFwiZGl2IGFkZFwiIGNvZGUgdGhhdCB3YXMganVzdCBhcHBlbmRlZClcclxuJChcIiNhZGRcIikuaGlkZSgpO1xyXG5cclxuLy9mdW5jdGlvbiB0byBmaXJlIG9uIGNsaWNrIGV2ZW50IGZvciBcIkFkZCBuZXcgSXRlbVwiXHJcbiQoXCIjQWRkSXRlbUJ0blwiKS5jbGljayhmdW5jdGlvbiAoKSB7XHJcblx0aGFuZGxlQWRkQ2xpY2soKTtcclxufSk7XHJcblxyXG4kKFwiI0FkZENsb3NlQnRuXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcclxuXHQkKFwiI2FkZFwiKS5oaWRlKCk7XHJcblx0JChcIiNhZGRGb3JtXCIpWzBdLnJlc2V0KCk7XHJcblx0JChcIiNhZGRTdGF0dXNcIikudGV4dCgnUmVhZHkgdG8gYWRkLi4nKTtcclxuXHQkKFwiI2FkZEthbmppXCIpLnJlbW92ZUNsYXNzKFwiZXJyb3JcIik7XHJcblx0JChcIiNhZGRNZWFuaW5nXCIpLnJlbW92ZUNsYXNzKFwiZXJyb3JcIik7XHJcbn0pO1xyXG5cclxuXHJcblxyXG4vLy0tLUZ1bmN0aW9uIHdyYXBwZXJzIHRvIGZhY2lsaXRhdGUgdXNlIG9mIG9uZSBsb2NhbHN0b3JhZ2UgYXJyYXlcclxuLy8tLS1NYWludGFpbnMgZGF0YSBpbnRlZ3JpdHkgYmV0d2VlbiBwcmV2aW91c2x5IHR3byAodm9jYWIgYW5kIHNycylcclxuXHJcblxyXG5mdW5jdGlvbiBzZXRTcnNJdGVtKHNyc2l0ZW0sc3JzTGlzdCl7XHJcblx0dmFyIGluZGV4ID0gc3JzaXRlbS5pO1xyXG5cdGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJzZXRTcnNJdGVtOiBcIik7XHJcblxyXG5cdGlmKHNyc0xpc3Qpe1xyXG5cdFx0aWYoc3JzTGlzdFtpbmRleF0ua2Fuamk9PT1zcnNpdGVtLmthbmppKXsvLyB0cnkgc2VhcmNoIGJ5IGluZGV4XHJcblxyXG5cdFx0XHRkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwic3VjY2VzczogXCIrc3JzaXRlbS5rYW5qaStcIiBmb3VuZCBhdCBpbmRleCBcIisgaW5kZXgpO1xyXG5cdFx0XHQvL3JlcGxhY2Ugb25seSB0aGUgc3JzIHBhcnRzIG9mIHRoZSBpdGVtXHJcblx0XHRcdHNyc0xpc3RbaW5kZXhdLmRhdGUgPSBzcnNpdGVtLmRhdGU7XHJcblx0XHRcdHNyc0xpc3RbaW5kZXhdLmxldmVsID0gc3JzaXRlbS5sZXZlbDtcclxuXHRcdFx0c3JzTGlzdFtpbmRleF0ubG9ja2VkID0gc3JzaXRlbS5sb2NrZWQ7XHJcblx0XHRcdHNyc0xpc3RbaW5kZXhdLm1hbnVhbExvY2sgPSBzcnNpdGVtLm1hbnVhbExvY2s7XHJcblx0XHR9ZWxzZXsgLy9iYWNrdXAgcGxhbiAoY3ljbGUgdGhyb3VnaCBsaXN0PylcclxuXHRcdFx0ZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcIlNSUyBLYW5qaSBub3QgZm91bmQgaW4gdm9jYWJsaXN0LCBuZWVkcyB3b3JrXCIpO1xyXG5cclxuXHRcdH1cclxuXHRcdGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJpdGVtOiBcIik7XHJcblx0XHRyZXR1cm4gc3JzTGlzdDtcclxuXHR9XHJcbn1cclxuXHJcbmZ1bmN0aW9uIGdldFNyc0xpc3QoKXtcclxuXHR2YXIgc3JzTGlzdCA9IFN0b3JhZ2VVdGlsLmdldFZvY0xpc3QoKTtcclxuXHRyZXR1cm4gc3JzTGlzdDtcclxufVxyXG5cclxuXHJcbmZ1bmN0aW9uIGdldEZ1bGxMaXN0KCl7XHJcblx0dmFyIGZ1bGxMaXN0ID0gSlNPTi5wYXJzZShsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnVXNlci1Wb2NhYicpKXx8W107XHJcblx0aWYoIWZ1bGxMaXN0KXtcclxuXHRcdGZ1bGxMaXN0PVtdO1xyXG5cdH1cclxuXHRyZXR1cm4gZnVsbExpc3Q7XHJcbn1cclxuXHJcbi8vLS0tLS0tLS1cclxuXHJcbi8qXHJcbiogIEVkaXQgSXRlbXNcclxuKi9cclxud2luZG93LldLU1NfZWRpdCA9IGZ1bmN0aW9uICgpIHtcclxuXHRnZW5lcmF0ZUVkaXRPcHRpb25zKCk7XHJcblx0JChcIiNlZGl0XCIpLnNob3coKTtcclxuXHQvL2hpZGUgb3RoZXIgd2luZG93c1xyXG5cdCQoXCIjZXhwb3J0XCIpLmhpZGUoKTtcclxuXHQkKFwiI2ltcG9ydFwiKS5oaWRlKCk7XHJcblx0JChcIiNhZGRcIikuaGlkZSgpO1xyXG5cdCQoXCIjc2VsZnN0dWR5XCIpLmhpZGUoKTtcclxufTtcclxuXHJcbiQoXCJib2R5XCIpLmFwcGVuZChcIiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXFxyXG48ZGl2IGlkPVxcXCJlZGl0XFxcIiBjbGFzcz1cXFwiV0tTU1xcXCI+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXFxyXG48Zm9ybSBpZD1cXFwiZWRpdEZvcm1cXFwiPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXFxcclxuPGJ1dHRvbiBpZD1cXFwiRWRpdENsb3NlQnRuXFxcIiBjbGFzcz1cXFwid2tzcy1jbG9zZVxcXCIgdHlwZT1cXFwiYnV0dG9uXFxcIj48aSBjbGFzcz1cXFwiaWNvbi1yZW1vdmVcXFwiPjwvaT48L2J1dHRvbj5cXFxyXG48aDE+RWRpdCB5b3VyIFZvY2FiPC9oMT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXFxyXG48c2VsZWN0IGlkPVxcXCJlZGl0V2luZG93XFxcIiBzaXplPVxcXCI4XFxcIj48L3NlbGVjdD5cXFxyXG48aW5wdXQgdHlwZT1cXFwidGV4dFxcXCIgaWQ9XFxcImVkaXRJdGVtXFxcIiBuYW1lPVxcXCJcXFwiIHNpemU9XFxcIjQwXFxcIiBwbGFjZWhvbGRlcj1cXFwiU2VsZWN0IHZvY2FiLCBjbGljayBlZGl0LCBjaGFuZ2UgYW5kIHNhdmUhXFxcIj5cXFxyXG5cXFxyXG48cCBpZD1cXFwiZWRpdFN0YXR1c1xcXCI+UmVhZHkgdG8gZWRpdC4uPC9wPlxcXHJcbjxidXR0b24gaWQ9XFxcIkVkaXRFZGl0QnRuXFxcIiB0eXBlPVxcXCJidXR0b25cXFwiPkVkaXQ8L2J1dHRvbj5cXFxyXG48YnV0dG9uIGlkPVxcXCJFZGl0U2F2ZUJ0blxcXCIgdHlwZT1cXFwiYnV0dG9uXFxcIj5TYXZlPC9idXR0b24+ICAgICAgICAgXFxcclxuPGJ1dHRvbiBpZD1cXFwiRWRpdERlbGV0ZUJ0blxcXCIgdHlwZT1cXFwiYnV0dG9uXFxcIiB0aXRsZT1cXFwiRGVsZXRlIHNlbGVjdGVkIGl0ZW1cXFwiPkRlbGV0ZTwvYnV0dG9uPiAgICAgICAgIFxcXHJcbjxidXR0b24gaWQ9XFxcIkVkaXREZWxldGVBbGxCdG5cXFwiIHR5cGU9XFxcImJ1dHRvblxcXCIgdGl0bGU9XFxcIuacrOW9k+OBq+OChOOCi+OBru+8n1xcXCI+RGVsZXRlIEFsbDwvYnV0dG9uPiAgIFxcXHJcbjxidXR0b24gaWQ9XFxcIlJlc2V0TGV2ZWxzQnRuXFxcIiB0eXBlPVxcXCJidXR0b25cXFwiPlJlc2V0IGxldmVsczwvYnV0dG9uPiAgICAgICAgIFxcXHJcbjwvZm9ybT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXFxcclxuPC9kaXY+XCIpO1xyXG4kKFwiI2VkaXRcIikuaGlkZSgpO1xyXG5cclxuJChcIiNSZXNldExldmVsc0J0blwiKS5jbGljayhmdW5jdGlvbiAoKSB7XHJcblxyXG5cclxuXHQvL3ZhciBzcnNsaXN0ID0gZ2V0U3JzTGlzdCgpO1xyXG5cdHZhciBzcnNMaXN0ID0gSlNPTi5wYXJzZShsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnVXNlci1Wb2NhYicpKXx8W107XHJcblxyXG5cdGlmIChzcnNMaXN0KSB7XHJcblx0XHR2YXIgaSA9IHNyc0xpc3QubGVuZ3RoO1xyXG5cdFx0d2hpbGUoaS0tKXtcclxuXHRcdFx0c3JzTGlzdFtpXS5sZXZlbCA9IDA7XHJcblx0XHRcdGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJzcnNMaXN0W2ldLmkgYmVmb3JlOiBcIitzcnNMaXN0W2ldLmkpO1xyXG5cdFx0XHRzcnNMaXN0W2ldLmk9aTtcclxuXHRcdFx0ZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcInNyc0xpc3RbaV0uaSBhZnRlcjogXCIrc3JzTGlzdFtpXS5pKTtcclxuXHRcdFx0dmFyIHNyc0xpc3QyID0gbG9jYWxHZXQoJ1VzZXItVm9jYWInKXx8W107XHJcblxyXG5cdFx0XHRzcnNMaXN0MiA9IHNldFNyc0l0ZW0oc3JzTGlzdFtpXSxzcnNMaXN0Mik7XHJcblx0XHRcdGxvY2FsU2V0KCdVc2VyLVZvY2FiJywgc3JzTGlzdDIpO1xyXG5cclxuXHRcdH1cclxuXHR9XHJcbn0pO1xyXG5cclxuXHJcbiQoXCIjRWRpdEVkaXRCdG5cIikuY2xpY2soZnVuY3Rpb24gKCkge1xyXG5cdC8vZ2V0IGhhbmRsZSBmb3IgJ3NlbGVjdCcgYXJlYVxyXG5cdHZhciBzZWxlY3QgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImVkaXRXaW5kb3dcIik7XHJcblxyXG5cdC8vZ2V0IHRoZSBpbmRleCBmb3IgdGhlIGN1cnJlbnRseSBzZWxlY3RlZCBpdGVtXHJcblx0dmFyIGluZGV4ID0gc2VsZWN0LnNlbGVjdGVkSW5kZXg7IC8vc2VsZWN0Lm9wdGlvbnNbc2VsZWN0LnNlbGVjdGVkSW5kZXhdLnZhbHVlIGlzIG5vdCByZXF1aXJlZCwgb3B0aW9uIHZhbHVlcyBhcmUgc2V0IHRvIGluZGV4XHJcblx0dmFyIHZvY2FiTGlzdCA9IFN0b3JhZ2VVdGlsLmdldFZvY0xpc3QoKTtcclxuXHR2b2NhYkxpc3QgPSB2b2NhYkxpc3QucmV2ZXJzZSgpO1xyXG5cdGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwiZWRpdEl0ZW1cIikudmFsdWUgPSBKU09OLnN0cmluZ2lmeSh2b2NhYkxpc3RbaW5kZXhdKTtcclxuXHRkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImVkaXRJdGVtXCIpLm5hbWUgPSBpbmRleDsgLy91c2luZyBuYW1lIHRvIHNhdmUgdGhlIGluZGV4XHJcblx0JChcIiNlZGl0U3RhdHVzXCIpLnRleHQoJ0xvYWRlZCBpdGVtIHRvIGVkaXQnKTtcclxufSk7XHJcblxyXG4kKFwiI0VkaXRTYXZlQnRuXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcclxuXHRpZiAoJChcIiNlZGl0SXRlbVwiKS52YWwoKS5sZW5ndGggIT09IDApIHtcclxuXHRcdC8vLS0gYmUgYXdhcmVcclxuXHRcdC8vZGVsZXRpbmcgb25lIGl0ZW0gbWF5IGNhdXNlIG1pc21hdGNoIGlmIGkgaXMgcHJvcGVydHkgb2YgaXRlbSBpbiBsaXN0XHJcblx0XHR0cnkge1xyXG5cdFx0XHR2YXIgaW5kZXggPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImVkaXRJdGVtXCIpLm5hbWU7XHJcblx0XHRcdHZhciBpdGVtID0gSlNPTi5wYXJzZShkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImVkaXRJdGVtXCIpLnZhbHVlLnRvTG93ZXJDYXNlKCkpO1xyXG5cdFx0XHR2YXIgbSA9IGl0ZW0ubWVhbmluZy5sZW5ndGg7XHJcblx0XHRcdHdoaWxlKG0tLSl7XHJcblx0XHRcdFx0aWYgKGl0ZW0ubWVhbmluZ1ttXSA9PT0gXCJcIil7XHJcblx0XHRcdFx0XHRkZWxldGUgaXRlbS5tZWFuaW5nW21dO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHR2YXIgZnVsbExpc3QgPSBnZXRGdWxsTGlzdCgpLnJldmVyc2UoKTtcclxuXHJcblxyXG5cdFx0XHRpZiAoaXNJdGVtVmFsaWQoaXRlbSkgJiYvL2l0ZW0gaXMgdmFsaWRcclxuXHRcdFx0XHQhKGNoZWNrRm9yRHVwbGljYXRlcyhmdWxsTGlzdCxpdGVtKSAmJiAvL2thbmppIChpZiBjaGFuZ2VkKSBpcyBub3QgYWxyZWFkeSBpbiB0aGUgbGlzdFxyXG5cdFx0XHRcdCAgZnVsbExpc3RbaW5kZXhdLmthbmppICE9PSBpdGVtLmthbmppKSkgey8vdW5sZXNzIGl0IGlzIHRoZSBpdGVtIGJlaW5nIGVkaXRlZFxyXG5cclxuXHJcblx0XHRcdFx0dmFyIHNyc2xpc3QgPSBnZXRTcnNMaXN0KCkucmV2ZXJzZSgpO1xyXG5cdFx0XHRcdC8vZ2V0IHNycyBjb21wb25lbnRzIG9mIGl0ZW0obGlzdClcclxuXHJcblx0XHRcdFx0ZnVsbExpc3RbaW5kZXhdID0gaXRlbTsvL2RvZXMgbm90IGhhdmUgc3JzIHN0dWZmLCByZS1hZGQgaXQgbm93XHJcblxyXG5cdFx0XHRcdGRlYnVnZ2luZyYmY29uc29sZS5sb2coZnVsbExpc3RbaW5kZXhdKTtcclxuXHRcdFx0XHRkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKHNyc2xpc3RbaW5kZXhdKTtcclxuXHRcdFx0XHRmdWxsTGlzdFtpbmRleF0uZGF0ZSA9IHNyc2xpc3RbaW5kZXhdLmRhdGU7XHJcblx0XHRcdFx0ZnVsbExpc3RbaW5kZXhdLmxldmVsID0gc3JzbGlzdFtpbmRleF0ubGV2ZWw7XHJcblx0XHRcdFx0ZnVsbExpc3RbaW5kZXhdLmxvY2tlZCA9IHNyc2xpc3RbaW5kZXhdLmxvY2tlZDtcclxuXHRcdFx0XHRmdWxsTGlzdFtpbmRleF0ubWFudWFsTG9jayA9IHNyc2xpc3RbaW5kZXhdLm1hbnVhbExvY2s7XHJcblxyXG5cdFx0XHRcdGZ1bGxMaXN0ID0gZnVsbExpc3QucmV2ZXJzZSgpOyAvL3Jlc2V0IG9yZGVyIG9mIGFycmF5XHJcblxyXG5cdFx0XHRcdGxvY2FsU2V0KCdVc2VyLVZvY2FiJywgZnVsbExpc3QpO1xyXG5cclxuXHRcdFx0XHRnZW5lcmF0ZUVkaXRPcHRpb25zKCk7XHJcblx0XHRcdFx0JChcIiNlZGl0U3RhdHVzXCIpLmh0bWwoJ1NhdmVkIGNoYW5nZXMhJyk7XHJcblx0XHRcdFx0ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJlZGl0SXRlbVwiKS52YWx1ZSA9IFwiXCI7XHJcblx0XHRcdFx0ZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJlZGl0SXRlbVwiKS5uYW1lID0gXCJcIjtcclxuXHJcblx0XHRcdH1cclxuXHRcdFx0ZWxzZXtcclxuXHRcdFx0XHQkKFwiI2VkaXRTdGF0dXNcIikudGV4dCgnSW52YWxpZCBpdGVtIG9yIGR1cGxpY2F0ZSEnKTtcclxuXHRcdFx0XHRhbGVydChpc0l0ZW1WYWxpZChpdGVtKS50b1N0cmluZygpICtcIiAmJiDvvIEoXCIrIGNoZWNrRm9yRHVwbGljYXRlcyhmdWxsTGlzdCxpdGVtKS50b1N0cmluZygpK1wiICYmICEoXCIrZnVsbExpc3RbaW5kZXhdLmthbmppK1wiICE9PSBcIitpdGVtLmthbmppK1wiKVwiKTtcclxuXHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdGNhdGNoIChlKSB7XHJcblx0XHRcdCQoXCIjZWRpdFN0YXR1c1wiKS50ZXh0KGUpO1xyXG5cdFx0fVxyXG5cdH1cclxufSk7XHJcblxyXG4kKFwiI0VkaXREZWxldGVCdG5cIikuY2xpY2soZnVuY3Rpb24gKCkge1xyXG5cdC8vc2VsZWN0IG9wdGlvbnMgZWxlbWVudCB3aW5kb3dcclxuXHR2YXIgc2VsZWN0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJlZGl0V2luZG93XCIpO1xyXG5cclxuXHQvL2luZGV4IG9mIHNlbGVjdGVkIGl0ZW1cclxuXHR2YXIgaXRlbSA9IHNlbGVjdC5vcHRpb25zW3NlbGVjdC5zZWxlY3RlZEluZGV4XS52YWx1ZTtcclxuXHJcblx0Ly9mZXRjaCBKU09OIHN0cmluZ3MgZnJvbSBzdG9yYWdlIGFuZCBjb252ZXJ0IHRoZW0gaW50byBKYXZhc2NyaXB0IGxpdGVyYWxzXHJcblx0dmFyIHZvY2FiTGlzdCA9IGdldEZ1bGxMaXN0KCk7XHJcblxyXG5cdC8vc3RhcnRpbmcgYXQgc2VsZWN0ZWQgaW5kZXgsIHJlbW92ZSAxIGVudHJ5ICh0aGUgc2VsZWN0ZWQgaW5kZXgpLlxyXG5cdGlmIChpdGVtID4gLTEpIHtcclxuXHRcdGlmICh2b2NhYkxpc3QgIT09IG51bGwpe1xyXG5cdFx0XHR2b2NhYkxpc3Quc3BsaWNlKGl0ZW0sIDEpO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0Ly95dWNrXHJcblx0aWYgKHZvY2FiTGlzdC5sZW5ndGggIT09IDApIHtcclxuXHRcdGxvY2FsU2V0KCdVc2VyLVZvY2FiJywgdm9jYWJMaXN0KTtcclxuXHR9XHJcblx0ZWxzZSB7XHJcblx0XHRsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbSgnVXNlci1Wb2NhYicpO1xyXG5cdH1cclxuXHJcblx0dXBkYXRlRWRpdEdVSSgpO1xyXG5cclxuXHQkKFwiI2VkaXRTdGF0dXNcIikudGV4dCgnSXRlbSBkZWxldGVkIScpO1xyXG59KTtcclxuXHJcbiQoXCIjRWRpdERlbGV0ZUFsbEJ0blwiKS5jbGljayhmdW5jdGlvbiAoKSB7XHJcblx0dmFyIGRlbGV0ZUFsbCA9IGNvbmZpcm0oXCJBcmUgeW91IHN1cmUgeW91IHdhbnQgdG8gZGVsZXRlIGFsbCBlbnRyaWVzP1wiKTtcclxuXHRpZiAoZGVsZXRlQWxsKSB7XHJcblxyXG5cdFx0Ly9kcm9wIGxvY2FsIHN0b3JhZ2VcclxuXHRcdGxvY2FsU3RvcmFnZS5yZW1vdmVJdGVtKCdVc2VyLVZvY2FiJyk7XHJcblxyXG5cclxuXHRcdHVwZGF0ZUVkaXRHVUkoKTtcclxuXHJcblx0XHQkKFwiI2VkaXRTdGF0dXNcIikudGV4dCgnQWxsIGl0ZW1zIGRlbGV0ZWQhJyk7XHJcblx0fVxyXG59KTtcclxuXHJcblxyXG4kKFwiI0VkaXRDbG9zZUJ0blwiKS5jbGljayhmdW5jdGlvbiAoKSB7XHJcblx0JChcIiNlZGl0XCIpLmhpZGUoKTtcclxuXHQkKFwiI2VkaXRGb3JtXCIpWzBdLnJlc2V0KCk7XHJcblx0JChcIiNlZGl0U3RhdHVzXCIpLnRleHQoJ1JlYWR5IHRvIGVkaXQuLicpO1xyXG59KTtcclxuXHJcbi8qXHJcbiogIEV4cG9ydFxyXG4qL1xyXG53aW5kb3cuV0tTU19leHBvcnQgPSBmdW5jdGlvbiAoKSB7XHJcblx0JChcIiNleHBvcnRcIikuc2hvdygpO1xyXG5cdC8vaGlkZSBvdGhlciB3aW5kb3dzXHJcblx0JChcIiNhZGRcIikuaGlkZSgpO1xyXG5cdCQoXCIjaW1wb3J0XCIpLmhpZGUoKTtcclxuXHQkKFwiI2VkaXRcIikuaGlkZSgpO1xyXG5cdCQoXCIjc2VsZnN0dWR5XCIpLmhpZGUoKTtcclxufTtcclxuXHJcbiQoXCJib2R5XCIpLmFwcGVuZCgnICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcXHJcbjxkaXYgaWQ9XCJleHBvcnRcIiBjbGFzcz1cIldLU1NcIj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcXHJcbjxmb3JtIGlkPVwiZXhwb3J0Rm9ybVwiPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXFxcclxuPGJ1dHRvbiBpZD1cIkV4cG9ydENsb3NlQnRuXCIgY2xhc3M9XCJ3a3NzLWNsb3NlXCIgdHlwZT1cImJ1dHRvblwiPjxpIGNsYXNzPVwiaWNvbi1yZW1vdmVcIj48L2k+PC9idXR0b24+XFxcclxuPGgxPkV4cG9ydCBJdGVtczwvaDE+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXFxcclxuPHRleHRhcmVhIGNvbHM9XCI1MFwiIHJvd3M9XCIxOFwiIGlkPVwiZXhwb3J0QXJlYVwiIHBsYWNlaG9sZGVyPVwiRXhwb3J0IHlvdXIgc3R1ZmYhIFNoYXJpbmcgaXMgY2FyaW5nIDspXCI+PC90ZXh0YXJlYT4gICAgICAgICAgICAgICAgICAgICAgICAgICBcXFxyXG5cXFxyXG48cCBpZD1cImV4cG9ydFN0YXR1c1wiPlJlYWR5IHRvIGV4cG9ydC4uPC9wPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXFxyXG48YnV0dG9uIGlkPVwiRXhwb3J0SXRlbXNCdG5cIiB0eXBlPVwiYnV0dG9uXCI+RXhwb3J0IEl0ZW1zPC9idXR0b24+XFxcclxuPGJ1dHRvbiBpZD1cIkV4cG9ydFNlbGVjdEFsbEJ0blwiIHR5cGU9XCJidXR0b25cIj5TZWxlY3QgQWxsPC9idXR0b24+XFxcclxuPGJ1dHRvbiBpZD1cIkV4cG9ydENzdkJ0blwiIHR5cGU9XCJidXR0b25cIj5FeHBvcnQgQ1NWPC9idXR0b24+XFxcclxuPC9mb3JtPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXFxyXG48L2Rpdj4nKTtcclxuJChcIiNleHBvcnRcIikuaGlkZSgpO1xyXG5cclxuXHJcbiQoXCIjRXhwb3J0SXRlbXNCdG5cIikuY2xpY2soZnVuY3Rpb24gKCkge1xyXG5cclxuXHRpZiAobG9jYWxTdG9yYWdlLmdldEl0ZW0oJ1VzZXItVm9jYWInKSkge1xyXG5cdFx0JChcIiNleHBvcnRGb3JtXCIpWzBdLnJlc2V0KCk7XHJcblx0XHR2YXIgdm9jYWJMaXN0ID0gU3RvcmFnZVV0aWwuZ2V0Vm9jTGlzdCgpO1xyXG5cdFx0JChcIiNleHBvcnRBcmVhXCIpLnRleHQoSlNPTi5zdHJpbmdpZnkodm9jYWJMaXN0KSk7XHJcblx0XHQkKFwiI2V4cG9ydFN0YXR1c1wiKS50ZXh0KFwiQ29weSB0aGlzIHRleHQgYW5kIHNoYXJlIGl0IHdpdGggb3RoZXJzIVwiKTtcclxuXHR9XHJcblx0ZWxzZSB7XHJcblx0XHQkKFwiI2V4cG9ydFN0YXR1c1wiKS50ZXh0KFwiTm90aGluZyB0byBleHBvcnQgeWV0IDooXCIpO1xyXG5cdH1cclxufSk7XHJcblxyXG4kKFwiI0V4cG9ydFNlbGVjdEFsbEJ0blwiKS5jbGljayhmdW5jdGlvbiAoKSB7XHJcblx0aWYgKCQoXCIjZXhwb3J0QXJlYVwiKS52YWwoKS5sZW5ndGggIT09IDApIHtcclxuXHRcdHNlbGVjdF9hbGwoXCJleHBvcnRBcmVhXCIpO1xyXG5cdFx0JChcIiNleHBvcnRTdGF0dXNcIikudGV4dChcIkRvbid0IGZvcmdldCB0byBDVFJMICsgQyFcIik7XHJcblx0fVxyXG59KTtcclxuXHJcbiQoXCIjRXhwb3J0Q3N2QnRuXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcclxuXHR2YXIgdm9jYWJMaXN0ID0gZ2V0RnVsbExpc3QoKTtcclxuXHR2YXIgQ3N2RmlsZSA9IGNyZWF0ZUNTVih2b2NhYkxpc3QpO1xyXG5cdHdpbmRvdy5vcGVuKENzdkZpbGUpO1xyXG59KTtcclxuXHJcbiQoXCIjRXhwb3J0Q2xvc2VCdG5cIikuY2xpY2soXHJcblx0ZnVuY3Rpb24gKCkge1xyXG5cdFx0JChcIiNleHBvcnRcIikuaGlkZSgpO1xyXG5cdFx0JChcIiNleHBvcnRGb3JtXCIpWzBdLnJlc2V0KCk7XHJcblx0XHQkKFwiI2V4cG9ydEFyZWFcIikudGV4dChcIlwiKTtcclxuXHRcdCQoXCIjZXhwb3J0U3RhdHVzXCIpLnRleHQoJ1JlYWR5IHRvIGV4cG9ydC4uJyk7XHJcblx0fVxyXG4pO1xyXG5cclxuLypcclxuKiAgSW1wb3J0XHJcbiovXHJcbndpbmRvdy5XS1NTX2ltcG9ydCA9IGZ1bmN0aW9uICgpIHtcclxuXHQkKFwiI2ltcG9ydFwiKS5zaG93KCk7XHJcblx0Ly9oaWRlIG90aGVyIHdpbmRvd3NcclxuXHQkKFwiI2FkZFwiKS5oaWRlKCk7XHJcblx0JChcIiNleHBvcnRcIikuaGlkZSgpO1xyXG5cdCQoXCIjZWRpdFwiKS5oaWRlKCk7XHJcblx0JChcIiNzZWxmc3R1ZHlcIikuaGlkZSgpO1xyXG59O1xyXG5cclxuJChcImJvZHlcIikuYXBwZW5kKCcgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXFxcclxuPGRpdiBpZD1cImltcG9ydFwiIGNsYXNzPVwiV0tTU1wiPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXFxcclxuPGZvcm0gaWQ9XCJpbXBvcnRGb3JtXCI+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXFxyXG48YnV0dG9uIGlkPVwiSW1wb3J0Q2xvc2VCdG5cIiBjbGFzcz1cIndrc3MtY2xvc2VcIiB0eXBlPVwicmVzZXRcIj48aSBjbGFzcz1cImljb24tcmVtb3ZlXCI+PC9pPjwvYnV0dG9uPlxcXHJcbjxoMT5JbXBvcnQgSXRlbXM8L2gxPlxcXHJcbjx0ZXh0YXJlYSBjb2xzPVwiNTBcIiByb3dzPVwiMThcIiBpZD1cImltcG9ydEFyZWFcIiBwbGFjZWhvbGRlcj1cIlBhc3RlIHlvdXIgc3R1ZmYgYW5kIGhpdCB0aGUgaW1wb3J0IGJ1dHRvbiEgVXNlIHdpdGggY2F1dGlvbiFcIj48L3RleHRhcmVhPiAgICAgICAgICAgICAgICAgICAgIFxcXHJcblxcXHJcbjxwIGlkPVwiaW1wb3J0U3RhdHVzXCI+UmVhZHkgdG8gaW1wb3J0Li48L3A+ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcXHJcbjxsYWJlbCBjbGFzcz1cImJ1dHRvblwiIGlkPVwiSW1wb3J0SXRlbXNCdG5cIiBzdHlsZT1cImRpc3BsYXk6aW5saW5lO1wiPkltcG9ydCBJdGVtczwvbGFiZWw+XFxcclxuXFxcclxuPGxhYmVsIGlkPVwiSW1wb3J0Q3N2QnRuXCIgY2xhc3M9XCJidXR0b25cIiBzdHlsZT1cImRpc3BsYXk6aW5saW5lO2N1cnNvcjogcG9pbnRlcjtcIj5JbXBvcnQgQ1NWICAgICAgICAgXFxcclxuXFxcclxuPGlucHV0IHR5cGU9XCJmaWxlXCIgaWQ9XCJ1cGxvYWRcIiBhY2NlcHQ9XCIuY3N2LC50c3ZcIiBzdHlsZT1cImhlaWdodDowcHg7d2lkdGg6MHB4O2JhY2tncm91bmQ6cmVkO29wYWNpdHk6MDtmaWx0ZXI6b3BhY2l0eSgxKTtcIiAvPlxcXHJcblxcXHJcbjwvbGFiZWw+XFxcclxuXFxcclxuPGxhYmVsIGNsYXNzPVwiYnV0dG9uXCIgaWQ9XCJJbXBvcnRXS0J0blwiIHN0eWxlPVwiZGlzcGxheTppbmxpbmU7XCI+PGkgY2xhc3M9XCJpY29uLWRvd25sb2FkLWFsdFwiPjwvaT4gV0s8L2xhYmVsPlxcXHJcbjwvZm9ybT4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXFxcclxuPC9kaXY+Jyk7XHJcbiQoXCIjaW1wb3J0XCIpLmhpZGUoKTtcclxuXHJcbmRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwidXBsb2FkXCIpICYmIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwidXBsb2FkXCIpLmFkZEV2ZW50TGlzdGVuZXIoJ2NoYW5nZScsIEltcG9ydFV0aWwuZmlsZVVwbG9hZCwgZmFsc2UpO1xyXG5cclxuXHJcbiQoXCIjSW1wb3J0Q3N2QnRuXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcclxufSk7XHJcblxyXG4kKFwiI0ltcG9ydFdLQnRuXCIpLmNsaWNrKGZ1bmN0aW9uKCl7XHJcblx0V2FuaWthbmlVdGlsLmdldFNlcnZlclJlc3AoQVBJa2V5LFwidm9jYWJ1bGFyeVwiKTtcclxuXHRkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwibWF5YmU/XCIpO1xyXG59KTtcclxuXHJcbiQoXCIjSW1wb3J0SXRlbXNCdG5cIikuY2xpY2soZnVuY3Rpb24gKCkge1xyXG5cclxuXHRpZiAoJChcIiNpbXBvcnRBcmVhXCIpLnZhbCgpLmxlbmd0aCAhPT0gMCkge1xyXG5cdFx0dHJ5IHtcclxuXHRcdFx0dmFyIGFkZCA9IEpTT04ucGFyc2UoJChcIiNpbXBvcnRBcmVhXCIpLnZhbCgpLnRvTG93ZXJDYXNlKCkpO1xyXG5cdFx0XHRhbGVydChKU09OLnN0cmluZ2lmeShhZGQpKTtcclxuXHRcdFx0aWYgKGNoZWNrQWRkKGFkZCkpIHtcclxuXHRcdFx0XHQkKFwiI2ltcG9ydFN0YXR1c1wiKS50ZXh0KFwiTm8gdmFsaWQgaW5wdXQgKGR1cGxpY2F0ZXM/KSFcIik7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR2YXIgbmV3bGlzdDtcclxuXHRcdFx0dmFyIHNyc2xpc3QgPSBbXTtcclxuXHRcdFx0aWYgKGxvY2FsU3RvcmFnZS5nZXRJdGVtKCdVc2VyLVZvY2FiJykpIHtcclxuXHRcdFx0XHR2YXIgdm9jYWJMaXN0ID0gU3RvcmFnZVV0aWwuZ2V0Vm9jTGlzdCgpO1xyXG5cdFx0XHRcdHNyc2xpc3QgPSBnZXRTcnNMaXN0KCk7XHJcblx0XHRcdFx0bmV3bGlzdCA9IHZvY2FiTGlzdC5jb25jYXQoYWRkKTtcclxuXHRcdFx0fVxyXG5cdFx0XHRlbHNlIHtcclxuXHRcdFx0XHRuZXdsaXN0ID0gYWRkO1xyXG5cclxuXHJcblx0XHRcdH1cclxuXHRcdFx0dmFyIGkgPSBhZGQubGVuZ3RoO1xyXG5cdFx0XHR3aGlsZShpLS0pe1xyXG5cdFx0XHRcdFN0b3JhZ2VVdGlsLnNldFZvY0l0ZW0oYWRkW2ldKTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0JChcIiNpbXBvcnRTdGF0dXNcIikudGV4dChcIkltcG9ydCBzdWNjZXNzZnVsIVwiKTtcclxuXHJcblx0XHRcdCQoXCIjaW1wb3J0Rm9ybVwiKVswXS5yZXNldCgpO1xyXG5cdFx0XHQkKFwiI2ltcG9ydEFyZWFcIikudGV4dChcIlwiKTtcclxuXHJcblx0XHR9XHJcblx0XHRjYXRjaCAoZSkge1xyXG5cdFx0XHQkKFwiI2ltcG9ydFN0YXR1c1wiKS50ZXh0KFwiUGFyc2luZyBFcnJvciFcIik7XHJcblx0XHRcdGRlYnVnZ2luZyYmY29uc29sZS5sb2coZSk7XHJcblx0XHR9XHJcblxyXG5cdH1cclxuXHRlbHNlIHtcclxuXHRcdCQoXCIjaW1wb3J0U3RhdHVzXCIpLnRleHQoXCJOb3RoaW5nIHRvIGltcG9ydCA6KCBQbGVhc2UgcGFzdGUgeW91ciBzdHVmZiBmaXJzdFwiKTtcclxuXHR9XHJcbn0pO1xyXG5cclxuJChcIiNJbXBvcnRDbG9zZUJ0blwiKS5jbGljayhmdW5jdGlvbiAoKSB7XHJcblx0JChcIiNpbXBvcnRcIikuaGlkZSgpO1xyXG5cdCQoXCIjaW1wb3J0Rm9ybVwiKVswXS5yZXNldCgpO1xyXG5cdCQoXCIjaW1wb3J0QXJlYVwiKS50ZXh0KFwiXCIpO1xyXG5cdCQoXCIjaW1wb3J0U3RhdHVzXCIpLnRleHQoJ1JlYWR5IHRvIGltcG9ydC4uJyk7XHJcbn0pO1xyXG5cclxuLypcclxuKiAgUmV2aWV3IEl0ZW1zXHJcbiovXHJcbndpbmRvdy5XS1NTX3JldmlldyA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0Ly9pcyB0aGVyZSBhIHNlc3Npb24gd2FpdGluZyBpbiBzdG9yYWdlP1xyXG5cdGlmKHNlc3Npb25TdG9yYWdlLmdldEl0ZW0oJ1VzZXItUmV2aWV3JykpIHtcclxuXHJcblx0XHQvL3Nob3cgdGhlIHNlbGZzdHVkeSB3aW5kb3dcclxuXHRcdCQoXCIjc2VsZnN0dWR5XCIpLnNob3coKTtcclxuXHJcblx0XHQvL2hpZGUgb3RoZXIgd2luZG93c1xyXG5cdFx0JChcIiNhZGRcIikuaGlkZSgpO1xyXG5cdFx0JChcIiNleHBvcnRcIikuaGlkZSgpO1xyXG5cdFx0JChcIiNlZGl0XCIpLmhpZGUoKTtcclxuXHRcdCQoXCIjaW1wb3J0XCIpLmhpZGUoKTtcclxuXHJcblx0XHRzdGFydFJldmlldygpO1xyXG5cdH1cclxufTtcclxuXHJcbiQoXCJib2R5XCIpLmFwcGVuZCgnICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcXHJcbjxkaXYgaWQ9XCJzZWxmc3R1ZHlcIiBjbGFzcz1cIldLU1NcIj5cXFxyXG48YnV0dG9uIGlkPVwiU2VsZnN0dWR5Q2xvc2VCdG5cIiBjbGFzcz1cIndrc3MtY2xvc2VcIiB0eXBlPVwiYnV0dG9uXCI+PGkgY2xhc3M9XCJpY29uLXJlbW92ZVwiPjwvaT48L2J1dHRvbj5cXFxyXG48aDE+UmV2aWV3PHNwYW4gaWQ9XCJSZXZOdW1cIj48L3NwYW4+PC9oMT5cXFxyXG48ZGl2IGlkPVwid2tzcy1rYW5qaVwiPlxcXHJcbjxzcGFuIGlkPVwicmV2LWthbmppXCI+PC9zcGFuPlxcXHJcbjwvZGl2PjxkaXYgaWQ9XCJ3a3NzLXR5cGVcIj5cXFxyXG48c3BhbiBpZD1cInJldi10eXBlXCI+PC9zcGFuPjxiciAvPlxcXHJcbjwvZGl2PjxkaXYgaWQ9XCJ3a3NzLXNvbHV0aW9uXCI+XFxcclxuPHNwYW4gaWQ9XCJyZXYtc29sdXRpb25cIj48L3NwYW4+XFxcclxuPC9kaXY+PGRpdiBpZD1cIndrc3MtaW5wdXRcIj5cXFxyXG48aW5wdXQgdHlwZT1cInRleHRcIiBpZD1cInJldi1pbnB1dFwiIHNpemU9XCI0MFwiIHBsYWNlaG9sZGVyPVwiXCI+XFxcclxuPC9kaXY+PHNwYW4gaWQ9XCJyZXYtaW5kZXhcIiBzdHlsZT1cImRpc3BsYXk6IGJsb2NrO1wiPjwvc3Bhbj5cXFxyXG5cXFxyXG48Zm9ybSBpZD1cImF1ZGlvLWZvcm1cIj5cXFxyXG48bGFiZWwgaWQ9XCJBdWRpb0J1dHRvblwiIGNsYXNzPVwiYnV0dG9uXCI+UGxheSBhdWRpbzwvbGFiZWw+XFxcclxuPGxhYmVsIGlkPVwiV3JhcFVwQnRuXCIgICBjbGFzcz1cImJ1dHRvblwiPldyYXAgVXA8L2xhYmVsPlxcXHJcbjwvZm9ybT5cXFxyXG48ZGl2IGlkPVwicmV2LWF1ZGlvXCIgc3R5bGU9XCJkaXNwbGF5Om5vbmU7XCI+PC9kaXY+XFxcclxuPC9kaXY+Jyk7XHJcbiQoXCIjc2VsZnN0dWR5XCIpLmhpZGUoKTtcclxuXHJcbiQoXCIjU2VsZnN0dWR5Q2xvc2VCdG5cIikuY2xpY2soZnVuY3Rpb24gKCkge1xyXG5cdCQoXCIjc2VsZnN0dWR5XCIpLmhpZGUoKTtcclxuXHQkKFwiI3Jldi1pbnB1dFwiKS52YWwoXCJcIik7XHJcblx0cmV2aWV3QWN0aXZlID0gZmFsc2U7XHJcbn0pO1xyXG5cclxuJChcIiNXcmFwVXBCdG5cIikuY2xpY2soZnVuY3Rpb24oKSB7XHJcblx0dmFyIHNlc3Npb25MaXN0ID0gc2Vzc2lvbkdldCgnVXNlci1SZXZpZXcnKXx8W107XHJcblx0dmFyIHN0YXRzTGlzdCA9IHNlc3Npb25HZXQoJ1VzZXItU3RhdHMnKXx8W107XHJcblx0Ly9pZiBhbiBpbmRleCBpbiBzZXNzaW9uTGlzdCBtYXRjaGVzIG9uZSBpbiBzdGF0c0xpc3QsIGRvbid0IGRlbGV0ZVxyXG5cdHZhciBzZXNzaW9uSSA9IHNlc3Npb25MaXN0Lmxlbmd0aDtcclxuXHR2YXIgaXRlbSA9IHNlc3Npb25HZXQoJ1dLU1MtaXRlbScpfHxbXTtcclxuXHR2YXIgYXJyMiA9IFtdO1xyXG5cdC8vZm9yIGV2ZXJ5IGl0ZW0gaW4gc2Vzc2lvbkxpc3QsIGxvb2sgZm9yIGluZGV4IGluIHN0YXRzTGlzdCxcclxuXHQvL2lmIG5vdCB0aGVyZSAoLTEpIGRlbGV0ZSBpdGVtIGZyb20gc2Vzc2lvbkxpc3RcclxuXHR3aGlsZSAoc2Vzc2lvbkktLSl7XHJcblx0XHR2YXIgaW5kZXggPSBmaW5kSW5kZXgoc3RhdHNMaXN0LHNlc3Npb25MaXN0W3Nlc3Npb25JXSk7XHJcblx0XHRpZiAoKE1hdGguc2lnbigxL2luZGV4KSAhPT0gLTEpfHwoc2Vzc2lvbkxpc3Rbc2Vzc2lvbkldLmluZGV4ID09IGl0ZW0uaW5kZXgpKXtcclxuXHJcblx0XHRcdGFycjIucHVzaChzZXNzaW9uTGlzdFtzZXNzaW9uSV0pO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblxyXG5cdGRlYnVnZ2luZyYmY29uc29sZS5sb2coYXJyMik7XHJcblx0c2Vzc2lvblNldCgnVXNlci1SZXZpZXcnLCBKU09OLnN0cmluZ2lmeShhcnIyKSk7XHJcbn0pO1xyXG5cclxuJChcIiNBdWRpb0J1dHRvblwiKS5jbGljayhmdW5jdGlvbiAoKSB7XHJcblx0b3BlbkluTmV3VGFiKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyZXYtYXVkaW8nKS5pbm5lckhUTUwpO1xyXG59KTtcclxuXHJcbiQoXCJib2R5XCIpLmFwcGVuZCgnICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcXHJcbjxkaXYgaWQ9XCJyZXN1bHR3aW5kb3dcIiBjbGFzcz1cIldLU1NcIj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXFxyXG48YnV0dG9uIGlkPVwiUmV2aWV3cmVzdWx0c0Nsb3NlQnRuXCIgY2xhc3M9XCJ3a3NzLWNsb3NlXCIgdHlwZT1cImJ1dHRvblwiPjxpIGNsYXNzPVwiaWNvbi1yZW1vdmVcIj48L2k+PC9idXR0b24+XFxcclxuPGgxPlJldmlldyBSZXN1bHRzPC9oMT5cXFxyXG48aDI+QWxsPC9oMj5cXFxyXG48ZGl2IGlkPVwic3RhdHMtYVwiPjwvZGl2PlxcXHJcbjwvZGl2PicpO1xyXG5cclxuJChcIiNyZXN1bHR3aW5kb3dcIikuaGlkZSgpO1xyXG5cclxuJChcIiNSZXZpZXdyZXN1bHRzQ2xvc2VCdG5cIikuY2xpY2soZnVuY3Rpb24gKCkge1xyXG5cdCQoXCIjcmVzdWx0d2luZG93XCIpLmhpZGUoKTtcclxuXHRkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInN0YXRzLWFcIikuaW5uZXJIVE1MID0gXCJcIjtcclxufSk7XHJcblxyXG4vL2RlY2xhcmUgZ2xvYmFsIHZhbHVlcyBmb3Iga2V5dXAgZXZlbnRcclxuLy9pcyBhbiBhbnN3ZXIgYmVpbmcgc3VibWl0dGVkP1xyXG52YXIgc3VibWl0ID0gdHJ1ZTtcclxuXHJcbi8vanF1ZXJ5IGtleXVwIGV2ZW50XHJcbiQoXCIjcmV2LWlucHV0XCIpLmtleXVwKGZ1bmN0aW9uIChlKSB7XHJcblx0Ly9mdW5jdGlvbnM6XHJcblx0Ly8gIGlucHV0Q29ycmVjdCgpXHJcblxyXG5cdC8vY2hlY2sgaWYga2V5IHByZXNzIHdhcyAnZW50ZXInIChrZXlDb2RlIDEzKSBvbiB0aGUgd2F5IHVwXHJcblx0Ly9hbmQga2V5c3RhdGUgdHJ1ZSAoYW5zd2VyIGJlaW5nIHN1Ym1pdHRlZClcclxuXHQvL2FuZCBjdXJzb3IgaXMgZm9jdXNlZCBpbiByZXZpZXdmaWVsZFxyXG5cdGlmIChlLmtleUNvZGUgPT0gMTMgJiYgc3VibWl0ID09PSB0cnVlKSB7XHJcblx0XHR2YXIgaW5wdXQgPSAkKFwiI3Jldi1pbnB1dFwiKS52YWwoKTtcclxuXHRcdHZhciByZXZpZXdMaXN0ID0gc2Vzc2lvbkdldCgnVXNlci1SZXZpZXcnKXx8W107XHJcblx0XHR2YXIgcm5kID0gc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbSgnV0tTUy1ybmQnKXx8MDtcclxuXHJcblx0XHR2YXIgaXRlbSA9IHNlc3Npb25HZXQoJ1dLU1MtaXRlbScpO1xyXG5cclxuXHRcdC8vLS0gc3RhcnRpbmcgaW1wbGVtZW50YXRpb24gb2YgZm9yZ2l2ZW5lc3MgcHJvdG9jb2xcclxuXHJcblx0XHRpdGVtLmZvcmdpdmUgPSBbXTsvL1wi44KG44KL44GZXCJdOyAvL3BsYWNlaG9sZGVyICjoqLHjgZkgdG8gZm9yZ2l2ZSlcclxuXHJcblxyXG5cdFx0aWYgKGl0ZW0gPT09IG51bGwpe1xyXG5cdFx0XHRhbGVydChcIkl0ZW0gTnVsbD8/XCIpO1xyXG5cdFx0XHRyZXZpZXdMaXN0LnNwbGljZShybmQsIDEpO1xyXG5cdFx0fWVsc2V7XHJcblx0XHRcdC8vaGFuZGxlIGdyYWRpbmcgYW5kIHN0b3Jpbmcgc29sdXRpb25cclxuXHJcblx0XHRcdC8vY2hlY2sgZm9yIGlucHV0LCBkbyBub3RoaW5nIGlmIG5vbmVcclxuXHRcdFx0aWYoaW5wdXQubGVuZ3RoID09PSAwKXtcclxuXHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vZGlzYWJsZSBpbnB1dCBhZnRlciBzdWJtaXNzaW9uXHJcblx0XHRcdC8vZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Jldi1pbnB1dCcpLmRpc2FibGVkID0gdHJ1ZTtcclxuXHJcblxyXG5cdFx0XHQvL3dhcyB0aGUgaW5wdXQgY29ycmVjdD9cclxuXHRcdFx0dmFyIGNvcnJlY3QgPSBpbnB1dENvcnJlY3QoKTtcclxuXHJcblx0XHRcdC8vd2FzIHRoZSBpbnB1dCBmb3JnaXZlbj9cclxuXHRcdFx0dmFyIGZvcmdpdmVuID0gKGl0ZW0uZm9yZ2l2ZS5pbmRleE9mKGlucHV0KSAhPT0gLTEpO1xyXG5cclxuXHRcdFx0aWYgKGNvcnJlY3QpIHtcclxuXHRcdFx0XHQvL2hpZ2hsaWdodCBpbiAoZGVmYXVsdCkgZ3JlZW5cclxuXHRcdFx0XHQkKFwiI3Jldi1pbnB1dFwiKS5hZGRDbGFzcyhcImNvcnJlY3RcIik7XHJcblx0XHRcdFx0Ly9zaG93IGFuc3dlclxyXG5cdFx0XHRcdCQoXCIjcmV2LXNvbHV0aW9uXCIpLmFkZENsYXNzKFwiaW5mb1wiKTtcclxuXHRcdFx0fSBlbHNlIGlmIChmb3JnaXZlbil7XHJcblx0XHRcdFx0JChcIiNyZXYtaW5wdXRcIikuYWRkQ2xhc3MoXCJjYXV0aW9uXCIpO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdC8vaGlnaGlnaHQgaW4gcmVkXHJcblx0XHRcdFx0JChcIiNyZXYtaW5wdXRcIikuYWRkQ2xhc3MoXCJlcnJvclwiKTtcclxuXHRcdFx0XHQvL3Nob3cgYW5zd2VyXHJcblx0XHRcdFx0JChcIiNyZXYtc29sdXRpb25cIikuYWRkQ2xhc3MoXCJpbmZvXCIpO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvL3JlbW92ZSBmcm9tIHNlc3Npb25MaXN0IGlmIGNvcnJlY3RcclxuXHRcdFx0aWYgKGNvcnJlY3QpIHtcclxuXHRcdFx0XHRkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwiY29ycmVjdCBhbnN3ZXJcIik7XHJcblx0XHRcdFx0aWYgKHJldmlld0xpc3QgIT09IG51bGwpe1xyXG5cdFx0XHRcdFx0dmFyIG9sZGxlbiA9IHJldmlld0xpc3QubGVuZ3RoO1xyXG5cclxuXHRcdFx0XHRcdHJldmlld0xpc3Quc3BsaWNlKHJuZCwgMSk7XHJcblx0XHRcdFx0XHRkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwic2Vzc2lvbkxpc3QubGVuZ3RoOiBcIisgb2xkbGVuICtcIiAtPiBcIityZXZpZXdMaXN0Lmxlbmd0aCk7XHJcblxyXG5cdFx0XHRcdFx0Ly9yZXBsYWNlIHNob3J0ZXIgKGJ5IG9uZSkgc2Vzc2lvbkxpc3QgdG8gc2Vzc2lvblxyXG5cdFx0XHRcdFx0aWYgKHJldmlld0xpc3QubGVuZ3RoICE9PSAwKSB7XHJcblx0XHRcdFx0XHRcdGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJzZXNzaW9uTGlzdC5sZW5ndGg6IFwiKyByZXZpZXdMaXN0Lmxlbmd0aCk7XHJcblx0XHRcdFx0XHRcdHNlc3Npb25TZXQoJ1VzZXItUmV2aWV3JywgSlNPTi5zdHJpbmdpZnkocmV2aWV3TGlzdCkpO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRcdC8vcmV2ZWl3IG92ZXIsIGRlbGV0ZSBzZXNzaW9ubGlzdCBmcm9tIHNlc3Npb25cclxuXHRcdFx0XHRcdFx0c2Vzc2lvblN0b3JhZ2UucmVtb3ZlSXRlbSgnVXNlci1SZXZpZXcnKTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9ZWxzZXtcclxuXHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoXCJFcnJvcjogbm8gcmV2aWV3IHNlc3Npb24gZm91bmRcIik7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9ZWxzZXtcclxuXHRcdFx0XHQvLyAgIGlmKGZvcmdpdmVuKXtcclxuXHRcdFx0XHQvLyAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhpbnB1dCArXCIgaGFzIGJlZW4gZm9yZ2l2ZW4uIFwiK2l0ZW0udHlwZSk7XHJcblx0XHRcdFx0Ly8gICByZXR1cm47XHJcblx0XHRcdFx0Ly99XHJcblx0XHRcdFx0ZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcIndyb25nIGFuc3dlclwiKTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aXRlbSA9IG1hcmtBbnN3ZXIoaXRlbSk7XHJcblxyXG5cdFx0XHRzZXNzaW9uU2V0KGl0ZW0uaW5kZXgsIGl0ZW0pO1xyXG5cclxuXHJcblx0XHRcdHZhciBsaXN0ID0gSlNPTi5wYXJzZShzZXNzaW9uU3RvcmFnZS5nZXRJdGVtKFwiVXNlci1TdGF0c1wiKSl8fFtdO1xyXG5cdFx0XHR2YXIgZm91bmQgPSBmYWxzZTtcclxuXHJcblx0XHRcdGlmIChsaXN0KXtcclxuXHRcdFx0XHR2YXIgaSA9IGxpc3QubGVuZ3RoO1xyXG5cdFx0XHRcdHdoaWxlKGktLSl7XHJcblx0XHRcdFx0XHRpZiAobGlzdFtpXS5pbmRleCA9PSBpdGVtLmluZGV4KSB7XHJcblx0XHRcdFx0XHRcdGxpc3RbaV0gPSBpdGVtO1x0XHRcdFx0XHRcdFx0XHQvL3JlcGxhY2UgaXRlbSBpZiBpdCBleGlzdHNcclxuXHRcdFx0XHRcdFx0Zm91bmQgPSB0cnVlO1xyXG5cdFx0XHRcdFx0XHRicmVhaztcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0aWYoIWZvdW5kKXtcclxuXHRcdFx0XHRcdGxpc3QgPSBzYXZlVG9Tb3J0ZWRMaXN0KGxpc3QsaXRlbSk7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRsaXN0ID0gW2l0ZW1dO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRzZXNzaW9uU2V0KFwiVXNlci1TdGF0c1wiLCBKU09OLnN0cmluZ2lmeShsaXN0KSk7XHJcblx0XHRcdC8vcGxheUF1ZGlvKCk7XHJcblxyXG5cdFx0XHQvL2Fuc3dlciBzdWJtaXR0ZWQsIG5leHQgJ2VudGVyJyBwcm9jZWVkcyB3aXRoIHNjcmlwdFxyXG5cdFx0XHRzdWJtaXQgPSBmYWxzZTtcclxuXHRcdH0vL251bGwgZ2FyYmFnZSBjb2xsZWN0aW9uXHJcblx0fVxyXG5cdGVsc2UgaWYgKGUua2V5Q29kZSA9PSAxMyAmJiBzdWJtaXQgPT09IGZhbHNlKSB7XHJcblx0XHRkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwia2V5c3RhdCA9IFwiICsgc3VibWl0KTtcclxuXHJcblx0XHQvL3RoZXJlIGFyZSBzdGlsbCBtb3JlIHJldmlld3MgaW4gc2Vzc2lvbj9cclxuXHRcdGlmIChzZXNzaW9uU3RvcmFnZS5nZXRJdGVtKCdVc2VyLVJldmlldycpKSB7XHJcblx0XHRcdC8vIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJmb3VuZCBhICdVc2VyLVJldmlldyc6IFwiICsgc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbSgnVXNlci1SZXZpZXcnKSk7XHJcblxyXG5cdFx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0XHRkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwicmVmcmVzaGluZyByZXZpZXdMaXN0IGZyb20gc3RvcmFnZVwiKTtcclxuXHRcdFx0XHR2YXIgcmV2aWV3TGlzdCA9IEpTT04ucGFyc2Uoc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbSgnVXNlci1SZXZpZXcnKSk7XHJcblxyXG5cdFx0XHRcdC8vY3VlIHVwIGZpcnN0IHJlbWFpbmluZyByZXZpZXdcclxuXHRcdFx0XHRuZXh0UmV2aWV3KHJldmlld0xpc3QpO1xyXG5cdFx0XHRcdGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJjaGVja2luZyBmb3IgZW1wdHkgcmV2aWV3TGlzdFwiKTtcclxuXHRcdFx0XHRpZiAocmV2aWV3TGlzdC5sZW5ndGggPT09IDApe1xyXG5cclxuXHRcdFx0XHRcdGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJzZXNzaW9uIG92ZXIuIHJldmlld0xpc3Q6IFwiK0pTT04uc3RyaW5naWZ5KHJldmlld0xpc3QpKTtcclxuXHRcdFx0XHRcdHNlc3Npb25TdG9yYWdlLnJlbW92ZUl0ZW0oXCJVc2VyLVJldmlld1wiKTtcclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Jldi1pbnB1dCcpLmRpc2FibGVkID0gdHJ1ZTtcclxuXHRcdFx0XHQkKFwiI3Jldi1zb2x1dGlvblwiKS5yZW1vdmVDbGFzcyhcImluZm9cIik7XHJcblx0XHRcdFx0JChcIiNzZWxmc3R1ZHlcIikuaGlkZSgpLmZhZGVJbignZmFzdCcpO1xyXG5cclxuXHRcdFx0fSwgMSk7XHJcblx0XHR9XHJcblx0XHRlbHNlIHtcclxuXHRcdFx0Ly8gbm8gcmV2aWV3IHN0b3JlZCBpbiBzZXNzaW9uLCByZXZpZXcgaXMgb3ZlclxyXG5cdFx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRcdFx0JChcIiNzZWxmc3R1ZHlcIikuaGlkZSgpO1xyXG5cdFx0XHRcdC8vZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Jldi1pbnB1dCcpLmRpc2FibGVkID0gZmFsc2U7XHJcblx0XHRcdFx0JChcIiNyZXYtc29sdXRpb25cIikucmVtb3ZlQ2xhc3MoXCJpbmZvXCIpO1xyXG5cdFx0XHRcdGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJzaG93UmVzdWx0c1wiKTtcclxuXHRcdFx0XHRzaG93UmVzdWx0cygpO1xyXG5cdFx0XHRcdCQoXCIjcmVzdWx0d2luZG93XCIpLnNob3coKTtcclxuXHRcdFx0XHRkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwic2hvd1Jlc3VsdHMgY29tcGxldGVkXCIpO1xyXG5cclxuXHRcdFx0XHQvLyovICAvL2NsZWFyIHNlc3Npb25cclxuXHRcdFx0XHRzZXNzaW9uU3RvcmFnZS5jbGVhcigpO1xyXG5cdFx0XHRcdHJldmlld0FjdGl2ZSA9IGZhbHNlO1xyXG5cclxuXHJcblx0XHRcdH0sIDEpO1xyXG5cdFx0fVxyXG5cdFx0c3VibWl0ID0gdHJ1ZTtcclxuXHJcblx0fVxyXG59KTtcclxuXHQvKiogcG9wdWxhdGUgcmV2aWV3cyB3aGVuIG1lbnUgYnV0dG9uIHByZXNzZWRcclxuXHQqL1xyXG4gICAgd2luZG93LmdlbmVyYXRlUmV2aWV3TGlzdCA9IGZ1bmN0aW9uKCkge1xyXG4gICAgICAgIC8vaWYgbWVudSBpcyBpbnZpc2libGUsIGl0IGlzIGFib3V0IHRvIGJlIHZpc2libGVcclxuICAgICAgICBpZiAoICQoXCIjV0tTU19kcm9wZG93blwiKS5pcyhcIjpoaWRkZW5cIikgKXtcclxuICAgICAgICAgICAgLy9UaGlzIGlzIHJlYWxseSB0aGUgb25seSB0aW1lIGl0IG5lZWRzIHRvIHJ1blxyXG4gICAgICAgICAgICAvL3VubGVzcyB3ZSB3YW50IHRvIHN0YXJ0IHVwZGF0aW5nIGluIHJlYWx0aW1lIGJ5IGtlZXBpbmcgdHJhY2sgb2YgdGhlIHNvb25lc3QgaXRlbVxyXG4gICAgICAgICAgICBnZW5lcmF0ZVJldmlld0xpc3QocmV2aWV3QWN0aXZlKTtcclxuICAgICAgICB9XHJcbiAgICB9O1xyXG5cdC8qKiAgQWRkIEl0ZW06IGV2ZW50IGZ1bmN0aW9uIHRvIG9wZW4gXCJhZGQgd2luZG93XCIgYW5kIGNsb3NlIGFueSBvdGhlciB3aW5kb3cgdGhhdCBtaWdodCBiZSBvcGVuIGF0IHRoZSB0aW1lLlxyXG5cdCovXHJcbiAgICB3aW5kb3cuV0tTU19hZGQgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgLy9zaG93IHRoZSBhZGQgd2luZG93XHJcbiAgICAgICAgJChcIiNhZGRcIikuc2hvdygpO1xyXG4gICAgICAgIC8vaGlkZSBvdGhlciB3aW5kb3dzXHJcbiAgICAgICAgJChcIiNleHBvcnRcIikuaGlkZSgpO1xyXG4gICAgICAgICQoXCIjaW1wb3J0XCIpLmhpZGUoKTtcclxuICAgICAgICAkKFwiI2VkaXRcIikuaGlkZSgpO1xyXG4gICAgICAgICQoXCIjc2VsZnN0dWR5XCIpLmhpZGUoKTtcclxuICAgIH07XHJcblx0XHJcblx0dmFyIGFkZEVsZW1lbnQgPSByZXF1aXJlKCcuL2FkZGVsZW1lbnQuanMnKTtcclxuXHQvL2FkZCBodG1sIHRvIHBhZ2Ugc291cmNlXHJcbiAgICAkKFwiYm9keVwiKS5hcHBlbmQoYWRkRWxlbWVudCk7XHJcbiAgICAvL2hpZGUgYWRkIHdpbmRvdyAoXCJkaXYgYWRkXCIgY29kZSB0aGF0IHdhcyBqdXN0IGFwcGVuZGVkKVxyXG4gICAgJChcIiNhZGRcIikuaGlkZSgpO1xyXG5cclxuICAgIHZhciBoYW5kbGVBZGRDbGljayA9IHJlcXVpcmUoJy4vaGFuZGxlQWRkQ2xpY2suanMnKTtcclxuXHRcclxuICAgIC8vZnVuY3Rpb24gdG8gZmlyZSBvbiBjbGljayBldmVudCBmb3IgXCJBZGQgbmV3IEl0ZW1cIlxyXG4gICAgJChcIiNBZGRJdGVtQnRuXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICBoYW5kbGVBZGRDbGljaygpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgJChcIiNBZGRDbG9zZUJ0blwiKS5jbGljayhmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgJChcIiNhZGRcIikuaGlkZSgpO1xyXG4gICAgICAgICQoXCIjYWRkRm9ybVwiKVswXS5yZXNldCgpO1xyXG4gICAgICAgICQoXCIjYWRkU3RhdHVzXCIpLnRleHQoJ1JlYWR5IHRvIGFkZC4uJyk7XHJcbiAgICAgICAgJChcIiNhZGRLYW5qaVwiKS5yZW1vdmVDbGFzcyhcImVycm9yXCIpO1xyXG4gICAgICAgICQoXCIjYWRkTWVhbmluZ1wiKS5yZW1vdmVDbGFzcyhcImVycm9yXCIpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLyoqIEtlZXBzIGxlZ2FjeSBzcnNMaXN0IHVwZGF0ZWQuXHJcblx0KiBAZGVwcmVjaWF0ZVxyXG5cdCogQHBhcmFtIHtTcnNJdGVtfSBzcnNpdGVtXHJcblx0KiBAcGFyYW0ge0FycmF5LjxTcnNJdGVtPn0gc3JzTGlzdFxyXG5cdCogQHJldHVybnMge0FycmF5LjxTcnNJdGVtPn0gVGhlIHNycyBkYXRhIGZvciBhIHRhc2suIE9yIG51bGwgaWYgbm8gc3JzTGlzdCB3YXMgcHJvdmlkZWQuXHJcblx0Ki9cclxuICAgIHZhciB1cGRhdGVTcnNJbkxpc3QgPSBmdW5jdGlvbihzcnNpdGVtLCBzcnNMaXN0KXtcclxuICAgICAgICB2YXIgaW5kZXggPSBzcnNpdGVtLmk7XHJcbiAgICAgICAgaWYoc3JzTGlzdCl7XHJcbiAgICAgICAgICAgIGlmKHNyc0xpc3RbaW5kZXhdLmthbmppPT09c3JzaXRlbS5rYW5qaSl7Ly8gdHJ5IHNlYXJjaCBieSBpbmRleFxyXG4gICAgICAgICAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcInN1Y2Nlc3M6IFwiK3Nyc2l0ZW0ua2FuamkrXCIgZm91bmQgYXQgaW5kZXggXCIrIGluZGV4KTtcclxuICAgICAgICAgICAgICAgIC8vcmVwbGFjZSBvbmx5IHRoZSBzcnMgcGFydHMgb2YgdGhlIGl0ZW1cclxuICAgICAgICAgICAgICAgIHNyc0xpc3RbaW5kZXhdLmRhdGUgPSBzcnNpdGVtLmRhdGU7XHJcbiAgICAgICAgICAgICAgICBzcnNMaXN0W2luZGV4XS5sZXZlbCA9IHNyc2l0ZW0ubGV2ZWw7XHJcbiAgICAgICAgICAgICAgICBzcnNMaXN0W2luZGV4XS5sb2NrZWQgPSBzcnNpdGVtLmxvY2tlZDtcclxuICAgICAgICAgICAgICAgIHNyc0xpc3RbaW5kZXhdLm1hbnVhbExvY2sgPSBzcnNpdGVtLm1hbnVhbExvY2s7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgcmV0dXJuIHNyc0xpc3Q7XHJcbiAgICAgICAgfVxyXG5cdFx0ZWxzZXtcclxuXHRcdFx0cmV0dXJuIG51bGw7XHJcblx0XHR9XHJcbiAgICB9O1xyXG4gICAgLyoqIENoZWNrcyBpZiBhbiBpdGVtJ3Mga2FuamkgaXMgcmVwcmVzZW50ZWQgaW4gYSBsaXN0XHJcblx0KiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHQqL1xyXG4gICAgdmFyIGNoZWNrRm9yRHVwbGljYXRlcyA9IGZ1bmN0aW9uKGxpc3QsIGl0ZW0pe1xyXG5cdFx0cmV0dXJuIGxpc3Quc29tZShmdW5jdGlvbihhKXtyZXR1cm4gYS5rYW5qaSA9PT0gaXRlbS5rYW5qaTt9KTtcclxuXHR9O1xyXG5cclxuXHQvKiogQ3JlYXRlcyBhIGxvb2t1cCBhcnJheSBmb3IgZWFjaCBrYW5qaSB3aXRoIGl0cyBzcnMgbGV2ZWwuIFVzZWQgZm9yIGRpc3BsYXlpbmcgY29tcG9uZW50IGxldmVscy5cclxuXHQqIEBwYXJhbSBpdGVtXHJcblx0KiBAcGFyYW0ga2FuamlsaXN0XHJcblx0KiBAcmV0dXJucyBBbiBhcnJheSBvZiB0aGUga2Fuamkgd2l0aCBTUlMgdmFsdWVzIGZvciBlYWNoIGthbmppIGNvbXBvbmVudC5cclxuXHQqIEBleGFtcGxlXHJcbiAgICAgICAgZWcuIOaKmOOCiue0mTpcclxuICAgICAgICBjb21wU1JTID0gW3tcImthbmppXCI6IFwi5oqYXCIsIFwic3JzXCI6IFwiZ3VydVwifSwge1wia2FuamlcIjogXCLntJlcIiwgXCJzcnNcIjogXCJhcHByZW50aWNlXCJ9XVxyXG5cdCovXHJcbiAgICB2YXIgZ2V0Q29tcEthbmppID0gZnVuY3Rpb24oaXRlbSwga2FuamlMaXN0KXtcclxuICAgICAgICBpZiAoIWthbmppTGlzdCl7XHJcbiAgICAgICAgICAgIGthbmppTGlzdCA9IFtdO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwiZ2V0Q29tcEthbmppKGl0ZW0sIGthbmppTGlzdClcIik7XHJcblxyXG4gICAgICAgIHZhciBjb21wU1JTID0gW107XHJcbiAgICAgICAgdmFyIGthbmppUmVhZHkgPSBmYWxzZTsgLy9pbmRpY2F0ZXMgaWYgdGhlIGthbmppTGlzdCBoYXMgYmVlbiBwb3B1bGF0ZWRcclxuICAgICAgICB2YXIgdXNlckd1cHB5ID0gZmFsc2U7IC8vaW5kaWNhdGVzIGlmIGthbmppTGlzdCBoYXMgbGVzcyB0aGFuIDEwMCBpdGVtc1xyXG4gICAgICAgIHZhciBrYW5qaU9iaiA9IHt9O1xyXG5cclxuICAgICAgICAvL2hhcyB0aGUgc2VydmVyIHJlc3BvbmRlZCB5ZXRcclxuICAgICAgICBpZiAoa2FuamlMaXN0Lmxlbmd0aCA+IDApe1xyXG4gICAgICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwia2FuamlMaXN0IGlzID4gMFwiKTtcclxuICAgICAgICAgICAga2FuamlSZWFkeSA9IHRydWU7XHJcblxyXG4gICAgICAgICAgICAvL2NyZWF0ZSBsb29rdXAgb2JqZWN0XHJcbiAgICAgICAgICAgIGZvciAodmFyIGs9MDtrPGthbmppTGlzdC5sZW5ndGg7aysrKXtcclxuICAgICAgICAgICAgICAgIGthbmppT2JqW2thbmppTGlzdFtrXS5jaGFyYWN0ZXJdID0ga2FuamlMaXN0W2tdO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAvL2lzIHRoZXJlIGxlc3MgdGhhbiAxMDAga2FuamkgaW4gdGhlIHJlc3BvbnNlXHJcbiAgICAgICAgICAgIGlmIChrYW5qaUxpc3QubGVuZ3RoIDwgMTAwKXtcclxuICAgICAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJrYW5qaUxpc3QgaXMgPCAxMDBcIik7XHJcbiAgICAgICAgICAgICAgICB1c2VyR3VwcHkgPSB0cnVlO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSAgICBcclxuXHJcbiAgICAgICAgdmFyIGNvbXBvbmVudHMgPSBpdGVtLmNvbXBvbmVudHM7XHJcbiAgICAgICAgLy9mb3IgZWFjaCBrYW5qaSBjaGFyYWN0ZXIgY29tcG9uZW50XHJcbiAgICAgICAgLy8gICAgdGhpcyBpcyB0aGUgb3V0ZXIgbG9vcCBzaW5jZSB0aGVyZSB3aWxsIGJlIGZhciBsZXNzIG9mIHRoZW0gdGhhbiBrYW5qaUxpc3RcclxuICAgICAgICBmb3IodmFyIGkgPSAwOyBpIDwgY29tcG9uZW50cy5sZW5ndGg7IGkrKyl7XHJcblxyXG4gICAgICAgICAgICB2YXIgbWF0Y2hlZCA9IGZhbHNlO1xyXG4gICAgICAgICAgICAvL2ZvciBlYWNoIGthbmppIHJldHVybmVkIGJ5IHRoZSBzZXJ2ZXJcclxuICAgICAgICAgICAgLy8gZm9yKHZhciBqPTA7IGo8a2FuamlMaXN0Lmxlbmd0aDsgaisrKXtcclxuXHJcbiAgICAgICAgICAgIC8vaWYgdGhlIGthbmppIHJldHVybmVkIGJ5IHRoZSBzZXJ2ZXIgbWF0Y2hlcyB0aGUgY2hhcmFjdGVyIGluIHRoZSBpdGVtXHJcbiAgICAgICAgICAgIGlmICh0eXBlb2Yga2FuamlPYmpbY29tcG9uZW50c1tpXV0gIT09ICd1bmRlZmluZWQnKXtcclxuICAgICAgICAgICAgICAgIC8vICAgICAgaWYgKGthbmppTGlzdFtqXS5jaGFyYWN0ZXIgPT0gY29tcG9uZW50c1tpXSl7XHJcbiAgICAgICAgICAgICAgICBjb21wU1JTW2ldID0ge1wia2FuamlcIjogY29tcG9uZW50c1tpXSwgXCJzcnNcIjoga2FuamlPYmpbY29tcG9uZW50c1tpXV0uc3JzfTtcclxuICAgICAgICAgICAgICAgIG1hdGNoZWQgPSB0cnVlO1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIGJyZWFrOyAvL2thbmppIGZvdW5kOiAnaScgaXMgaXRzIHBvc2l0aW9uIGluIGl0ZW0gY29tcG9uZW50czsgJ2onIGlzIGl0cyBwb3N0aW9uIGluIHRoZSAna2FuamlMaXN0JyBzZXJ2ZXIgcmVzcG9uc2VcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAvLyB9XHJcblxyXG4gICAgICAgICAgICBpZiAobWF0Y2hlZCA9PT0gZmFsc2UpeyAvLyBjaGFyYWN0ZXIgZ290IGFsbCB0aGUgd2F5IHRocm91Z2gga2FuamlMaXN0IHdpdGhvdXQgYSBtYXRjaC5cclxuICAgICAgICAgICAgICAgIGlmIChrYW5qaVJlYWR5KXsgLy93YXMgdGhlcmUgYSBzZXJ2ZXIgcmVzcG9uc2U/XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHVzZXJHdXBweSl7IC8vaXMgdGhlIHVzZXIgYSBndXBweSAoa2FuamkgcHJvYmFibHkgbWF0Y2hlcyBhIHR1cnRsZXMgcmVzcG9uc2UpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJtYXRjaGVkPWZhbHNlLCBrYW5qaUxpc3QubGVuZ3RoOiBcIitrYW5qaUxpc3QubGVuZ3RoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29tcFNSU1tpXSA9IHtcImthbmppXCI6IGNvbXBvbmVudHNbaV0sIFwic3JzXCI6IFwibm9NYXRjaEd1cHB5XCJ9O1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHRcdFx0XHRcdGVsc2V7IC8vdXNlciBpcyBhIHR1cnRsZSwga2FuamkgbXVzdCBub3QgaGF2ZSBiZWVuIGFkZGVkIHRvIFdLICh5ZXQpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJtYXRjaGVkPWZhbHNlLCBrYW5qaUxpc3QubGVuZ3RoOiBcIitrYW5qaUxpc3QubGVuZ3RoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgY29tcFNSU1tpXSA9IHtcImthbmppXCI6IGNvbXBvbmVudHNbaV0sIFwic3JzXCI6IFwibm9NYXRjaFdLXCJ9O1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuXHRcdFx0XHRlbHNle1xyXG4gICAgICAgICAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJtYXRjaGVkPWZhbHNlLCBrYW5qaVJlYWR5PWZhbHNlLCBub1NlcnZlclJlc3BcIik7XHJcbiAgICAgICAgICAgICAgICAgICAgY29tcFNSU1tpXSA9IHtcImthbmppXCI6IGNvbXBvbmVudHNbaV0sIFwic3JzXCI6IFwibm9TZXJ2ZXJSZXNwXCJ9O1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBjb21wU1JTO1xyXG4gICAgfTtcclxuXHJcblxyXG4gICAgdmFyIGlzS2FuamlMb2NrZWQgPSBmdW5jdGlvbihzcnNpdGVtLCBrYW5qaUxpc3QsIGxvY2tzT24pe1xyXG4gICAgICAgIC8vaXRlbSB1bmxvY2tlZCBieSBkZWZhdWx0XHJcbiAgICAgICAgLy9tYXkgaGF2ZSBubyBrYW5qaSwgb25seSB1bmxvY2tlZCBrYW5qaSB3aWxsIGdldCB0aHJvdWdoIHRoZSBjb2RlIHVuZmxhZ2dlZFxyXG5cclxuXHRcdC8vIEVudW1lcmF0aW9uIFwieWVzXCIsIFwibm9cIiwgXCJEQlwiXHJcbiAgICAgICAgdmFyIGxvY2tlZCA9IFwibm9cIjtcclxuICAgICAgICBpZiAobG9ja3NPbil7XHJcbiAgICAgICAgICAgIC8vZ2V0IHRoZSBrYW5qaSBjaGFyYWN0ZXJzIGluIHRoZSB3b3JkLlxyXG4gICAgICAgICAgICB2YXIgY29tcG9uZW50TGlzdCA9IGdldENvbXBLYW5qaShzcnNpdGVtLCBrYW5qaUxpc3QpO1xyXG4gICAgICAgICAgICAvLyBlZzogY29tcG9uZW50TGlzdCA9IGdldENvbXBLYW5qaShcIuaKmOOCiue0mVwiLCBrYW5qaUxpc3QpO1xyXG4gICAgICAgICAgICAvLyBjb21wb25lbnRMaXN0ID0gW3tcImthbmppXCI6IFwi5oqYXCIsIFwic3JzXCI6IFwiZ3VydVwifSwge1wia2FuamlcIjogXCLntJlcIiwgXCJzcnNcIjogXCJhcHByZW50aWNlXCJ9XVxyXG5cclxuXHJcbiAgICAgICAgICAgIHZhciBjID0gY29tcG9uZW50TGlzdC5sZW5ndGg7XHJcbiAgICAgICAgICAgIHdoaWxlKGMtLSl7XHJcbiAgICAgICAgICAgICAgICAvL2xvb2sgZm9yIGxvY2tlZCBrYW5qaSBpbiBsaXN0XHJcbiAgICAgICAgICAgICAgICBpZiAoY29tcG9uZW50TGlzdFtjXS5zcnMgPT0gXCJhcHByZW50aWNlXCIgfHxcclxuICAgICAgICAgICAgICAgICAgICBjb21wb25lbnRMaXN0W2NdLnNycyA9PSBcIm5vU2VydmVyUmVzcFwifHxcclxuICAgICAgICAgICAgICAgICAgICBjb21wb25lbnRMaXN0W2NdLnNycyA9PSBcInVucmVhY2hlZFwiXHJcbiAgICAgICAgICAgICAgICAgICApe1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLy0tLS1jb3VsZCBiZSBhcHByZW50aWNlIGV0Yy5cclxuICAgICAgICAgICAgICAgICAgICAvL1NpbXBsZTogbG9jayBpcyAneWVzJ1xyXG4gICAgICAgICAgICAgICAgICAgIGxvY2tlZCA9IFwieWVzXCI7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gXCJ5ZXNcIjpcdGl0ZW0gd2lsbCBiZSBsb2NrZWQgd2hpbGUgdGhlcmUgaXMgbm8gZGF0YWJhc2UgY29ubmVjdGlvbi5cclxuICAgICAgICAgICAgICAgICAgICAvL1x0XHRcdGlmIHRoZSBzZXJ2ZXIgcmVzcG9uc2UgaW5kaWNhdGVzIHRoYXQgaXQgaGFzIGJlZW4gdW5sb2NrZWQsIG9ubHkgdGhlbiB3aWxsIGl0IGJlIGF2YWlsYWJsZSBmb3IgcmV2aWV3XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJ0ZXN0IHNycyBmb3IgYXBwcmVudGljZSBldGMuICdsb2NrZWQnOiBcIisgbG9ja2VkKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhjb21wb25lbnRMaXN0W2NdLmthbmppICtcIjogXCIrY29tcG9uZW50TGlzdFtjXS5zcnMgK1wiIC0+IFwiKyBsb2NrZWQpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICBicmVhazsgLy8gYXMgc29vbiBhcyBvbmUga2FuamkgaXMgbG9ja2VkLCB0aGUgd2hvbGUgaXRlbSBpcyBsb2NrZWRcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAvL0RCIGxvY2tzIGdldCBzcGVjaWFsIHN0YXRlXHJcbiAgICAgICAgICAgICAgICBpZiAoY29tcG9uZW50TGlzdFtjXS5zcnMgPT0gXCJub01hdGNoV0tcIiB8fCBjb21wb25lbnRMaXN0W2NdLnNycyA9PSBcIm5vTWF0Y2hHdXBweVwiKXtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgbG9ja2VkID0gXCJEQlwiO1xyXG4gICAgICAgICAgICAgICAgICAgIC8vXCJEQlwiXHQ6IGRhdGFiYXNlIGxpbWl0YXRpb25zLCBvbmUgb2YgdHdvIHRoaW5nc1xyXG4gICAgICAgICAgICAgICAgICAgIC8vYS4gdGhlIGthbmppIGlzbid0IGluIHRoZSBkYXRhYmFzZSBhbmQgdGhlIHVzZXIgaXMgYSBndXBweSAtLWNvdWxkIGNoYW5nZSBpZiB1c2VyIHN1YnNjcmliZXMgb3IgZmlyc3QgdHdvIGxldmVscyBjaGFuZ2UvZXhwYW5kXHJcbiAgICAgICAgICAgICAgICAgICAgLy9iLiB0aGUga2FuamkgaXNuJ3QgaW4gdGhlIGRhdGFiYXNlIGFuZCB0aGUgdXNlciBpcyBhIHR1cnRsZSAtLWNvdWxkIGNoYW5nZSBpZiBtb3JlIGthbmppIGFkZGVkLlxyXG5cclxuICAgICAgICAgICAgICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwidGVzdCBzcnMgZm9yIHVubWF0Y2hlZCBrYW5qaS4gJ2xvY2tlZCc6IFwiKyBsb2NrZWQpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKGNvbXBvbmVudExpc3RbY10ua2FuamkgK1wiOiBcIitjb21wb25lbnRMaXN0W2NdLnNycyArXCIgLT4gXCIrIGxvY2tlZCk7XHJcblxyXG5cclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIH0gLy9mb3IgY2hhciBpbiBjb21wb25lbnRMaXN0XHJcbiAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJvdXQgb2YgY2hhcmFjdGVyIGxvb3BcIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8vbG9ja2VkIHdpbGwgYmUgZWl0aGVyIFwieWVzXCIsXCJub1wiLCBvciBcIkRCXCJcclxuICAgICAgICByZXR1cm4gW2xvY2tlZF07XHJcbiAgICB9O1xyXG5cclxuICAgIC8qKiBHZXRzIHRoZSBLYW5qaSBjaGFyYWN0ZXJzIGluIGEgZ2l2ZW4gc3RyaW5nLlxyXG5cdCogQHBhcmFtIHtzdHJpbmd9IHZvY2FiU3RyaW5nIC1cclxuXHQqIEByZXR1cm4ge0FycmF5LjxzdHJpbmc+fSBBbiBhcnJheSBvZiB0aGUga2FuamkgY29tcG9uZW50cyBpbiB0aGUgZ2l2ZW4gc3RyaW5nXHJcblx0Ki9cclxuICAgIHZhciBnZXRDb21wb25lbnRzID0gZnVuY3Rpb24odm9jYWJTdHJpbmcpe1xyXG4gICAgICAgIHJldHVybiBBcnJheS5wcm90b3R5cGUuZmlsdGVyLmNhbGwodm9jYWJTdHJpbmcsIGZ1bmN0aW9uKGNoKXtcclxuICAgICAgICAgICAgcmV0dXJuIC9eW1xcdTRlMDAtXFx1OWZhZl0rJC8udGVzdChjaCk7XHJcbiAgICAgICAgfSwgdGhpcyk7XHJcbiAgICB9O1xyXG5cclxuICAgIC8qKiBNYW5hZ2VzIHRoZSBsb2NrZWQgYW5kIG1hbnVhbExvY2sgcHJvcGVydGllcyBvZiBzcnNpdGVtLiBUaGlzIGlzIHRvIHN0b3AgaXRlbXMgYmVpbmcgbG9ja2VkIGFnYWluIGFmdGVyIHRoZXkgaGF2ZSBiZWVuIHVubG9ja2VkIGlmIGFueSBvZiB0aGUga2FuamkgdXNlZCBmYWxscyBiZWxvdyB0aGUgdW5sb2NrIHRocmVzaG9sZCAoZWcuIGlmIHRoZSDli4kgaW4g5YuJ5by3IGZhbGxzIGJhY2sgdG8gYXBwcmVudGljZSwgd2UgZG8gbm90IHdhbnQgdG8gbG9jayB1cCDli4nlvLcgYWdhaW4uKVxyXG5cdCogQHBhcmFtIHtPYmplY3R9IGl0ZW1cclxuXHQqIEBwYXJhbSB7c3RyaW5nfSBpdGVtLmxvY2tlZCAtIChTdHJpbmcgZW51bWVyYXRpb24pIEEgcmVhbCB0aW1lIGV2YWx1YXRpb24gb2YgdGhlIGl0ZW0gKGlzIGFueSBvZiB0aGUga2FuamkgaW4gdGhlIHdvcmQgbG9ja2VkPylcclxuXHQqIEBwYXJhbSB7c3RyaW5nfSBpdGVtLm1hbnVhbExvY2sgLSAoU3RyaW5nIGVudW1lcmF0aW9uKSBXaWxsIHJldHVybiAnbm8nIGlmIC5sb2NrZWQgaGFzIGV2ZXIgcmV0dXJuZWQgJ25vJy5cclxuXHQqIEByZXR1cm5zIHtJVGFza30gaXRlbVxyXG5cdCovXHJcbiAgICB2YXIgc2V0TG9ja3MgPSBmdW5jdGlvbihpdGVtKXtcclxuICAgICAgICAvL29uY2UgbWFudWFsTG9jayBpcyBcIm5vXCIgaXQgc3RheXMgXCJub1wiXHJcbiAgICAgICAgaWYgKGl0ZW0ubWFudWFsTG9jayAhPT0gZmFsc2UgJiYgaXRlbS5tYW51YWxMb2NrICE9PSBcIm5vXCIgJiYgaXRlbS5tYW51YWxMb2NrICE9PSBcIm5cIil7XHJcblxyXG4gICAgICAgICAgICB2YXIga2FuamlMaXN0ID0gbG9jYWxHZXQoJ1VzZXItS2FuamlMaXN0Jyl8fFtdO1xyXG5cclxuICAgICAgICAgICAgaXRlbS5jb21wb25lbnRzID0gZ2V0Q29tcG9uZW50cyhpdGVtLmthbmppKTtcclxuXHJcbiAgICAgICAgICAgIHZhciBrYW5qaUxvY2tlZFJlc3VsdCA9IGlzS2FuamlMb2NrZWQoaXRlbSwga2FuamlMaXN0LCBsb2Nrc09uKTtcclxuICAgICAgICAgICAgaXRlbS5sb2NrZWQgPSBrYW5qaUxvY2tlZFJlc3VsdFswXTtcclxuXHJcbiAgICAgICAgICAgIGl0ZW0ubWFudWFsTG9jayA9IGl0ZW0ubG9ja2VkO1xyXG4gICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICBpdGVtLm1hbnVhbExvY2sgPSBmYWxzZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJzZXR0aW5nIGxvY2tzIGZvciBcIisgaXRlbS5rYW5qaSArXCI6IGxvY2tlZDogXCIraXRlbS5sb2NrZWQrXCIsIG1hbnVhbExvY2s6IFwiKyBpdGVtLm1hbnVhbExvY2spO1xyXG5cclxuICAgICAgICByZXR1cm4gaXRlbTtcclxuICAgIH07XHJcbiAgICAvKiogQ29udmVydHMgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBpbnRvIGEgcmVhZGFibGUgc3RyaW5nXHJcblx0KiBAcGFyYW0ge251bWJlcn0gbWlsbGlzZWNvbmRzIC0gVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gYXBwcm94aW1hdGVcclxuXHQqIEByZXR1cm5zIHtzdHJpbmd9IFJlYWRhYmxlIHRpbWUgZnJhbWUgKCcyIG1vbnRocycsICczIGhvdXJzJywgJzEgd2VlaycgZXRjKS5cclxuXHQqL1xyXG5cdHZhciBtczJzdHIgPSBmdW5jdGlvbihtaWxsaXNlY29uZHMpe1xyXG4gICAgICAgIHZhciBudW07IC8vbnVtYmVyIG9mIG1vbnRocyB3ZWVrcyBob3VycyBldGNcclxuICAgICAgICAvL21vcmUgdGltZSBoYXMgZWxhcHNlZCB0aGFuIHJlcXVpcmVkIGZvciB0aGUgbGV2ZWxcclxuICAgICAgICBpZihtaWxsaXNlY29uZHMgPD0gMCkge1xyXG4gICAgICAgICAgICByZXR1cm4gXCJOb3dcIiA7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmKG1pbGxpc2Vjb25kcyA+IDI2MjgwMDAwMDApIHsvL0Fib3V0IGEgbW9udGhcclxuICAgICAgICAgICAgbnVtID0gTWF0aC5mbG9vcihtaWxsaXNlY29uZHMvMjYyODAwMDAwMCkudG9TdHJpbmcoKStcIiBtb250aFwiO1xyXG4gICAgICAgICAgICBpZiAobnVtICE9PSBcIjEgbW9udGhcIil7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVtK1wic1wiO1xyXG4gICAgICAgICAgICB9ZWxzZXtcclxuICAgICAgICAgICAgICAgIHJldHVybiBudW07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaWYobWlsbGlzZWNvbmRzID4gNjA0ODAwMDAwKSB7Ly9BIHdlZWtcclxuICAgICAgICAgICAgbnVtID0gTWF0aC5mbG9vcihtaWxsaXNlY29uZHMvNjA0ODAwMDAwKS50b1N0cmluZygpK1wiIHdlZWtcIjtcclxuICAgICAgICAgICAgaWYgKG51bSAhPT0gXCIxIHdlZWtcIil7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVtK1wic1wiO1xyXG4gICAgICAgICAgICB9ZWxzZXtcclxuICAgICAgICAgICAgICAgIHJldHVybiBudW07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaWYobWlsbGlzZWNvbmRzID4gODY0MDAwMDApIHsvL0EgZGF5XHJcbiAgICAgICAgICAgIG51bSA9IE1hdGguZmxvb3IobWlsbGlzZWNvbmRzLzg2NDAwMDAwKS50b1N0cmluZygpK1wiIGRheVwiO1xyXG4gICAgICAgICAgICBpZiAobnVtICE9PSBcIjEgZGF5XCIpe1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bStcInNcIjtcclxuICAgICAgICAgICAgfWVsc2V7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVtO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmKG1pbGxpc2Vjb25kcyA+IDM2MDAwMDApIHsvL0FuIGhvdXJcclxuICAgICAgICAgICAgbnVtID0gTWF0aC5mbG9vcihtaWxsaXNlY29uZHMvMzYwMDAwMCkudG9TdHJpbmcoKStcIiBob3VyXCI7XHJcbiAgICAgICAgICAgIGlmIChudW0gIT09IFwiMSBob3VyXCIpe1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bStcInNcIjtcclxuICAgICAgICAgICAgfWVsc2V7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVtO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmKG1pbGxpc2Vjb25kcyA+IDYwMDAwKSB7Ly9BIG1pbnV0ZVxyXG4gICAgICAgICAgICBudW0gPSBNYXRoLmZsb29yKG1pbGxpc2Vjb25kcy82MDAwMCkudG9TdHJpbmcoKStcIiBtaW51dGVcIjtcclxuICAgICAgICAgICAgaWYgKG51bSAhPT0gXCIxIG1pbnV0ZVwiKXtcclxuICAgICAgICAgICAgICAgIHJldHVybiBudW0rXCJzXCI7XHJcbiAgICAgICAgICAgIH1lbHNle1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBpZihtaWxsaXNlY29uZHMgPiAwKSB7Ly9BIHNlY29uZCBpcyAxMDAwLCBidXQgbmVlZCB0byByZXR1cm4gc29tZXRoaW5nIGZvciBsZXNzIHRoYW4gb25lIHRvb1xyXG4gICAgICAgICAgICBudW0gPSBNYXRoLmZsb29yKG1pbGxpc2Vjb25kcy8xMDAwKS50b1N0cmluZygpK1wiIHNlY29uZFwiO1xyXG4gICAgICAgICAgICBpZiAobnVtICE9PSBcIjEgc2Vjb25kXCIpe1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bStcInNcIjtcclxuICAgICAgICAgICAgfWVsc2V7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVtO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxuICAgIC8qKiBSZXRyaWV2ZXMgdmFsdWVzIGZyb20gc3RvcmFnZSB0byBwb3B1bGF0ZSAnZWRpdEl0ZW1zJyBtZW51XHJcblx0Ki9cclxuICAgIHZhciBnZW5lcmF0ZUVkaXRPcHRpb25zID0gZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgdmFyIHNlbGVjdCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdlZGl0V2luZG93Jyk7XHJcbiAgICAgICAgLy9jbGVhciB0aGUgZWRpdFdpbmRvd1xyXG4gICAgICAgIHdoaWxlIChzZWxlY3QuZmlyc3RDaGlsZCkge1xyXG4gICAgICAgICAgICBzZWxlY3QucmVtb3ZlQ2hpbGQoc2VsZWN0LmZpcnN0Q2hpbGQpO1xyXG4gICAgICAgIH1cclxuICAgICAgICAvL2NoZWNrIGZvciBpdGVtcyB0byBhZGRcclxuICAgICAgICBpZiAobG9jYWxTdG9yYWdlLmdldEl0ZW0oJ1VzZXItVm9jYWInKSkge1xyXG5cclxuICAgICAgICAgICAgLy9yZXRyaWV2ZSBmcm9tIGxvY2FsIHN0b3JhZ2VcclxuICAgICAgICAgICAgdmFyIHZvY2FiTGlzdCA9IFN0b3JhZ2VVdGlsLmdldFZvY0xpc3QoKTtcclxuICAgICAgICAgICAgdmFyIHNyc2xpc3QgPSAgU3RvcmFnZVV0aWwuZ2V0Vm9jTGlzdCgpO1xyXG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9IFtdO1xyXG4gICAgICAgICAgICAvL2J1aWxkIG9wdGlvbiBzdHJpbmdcclxuICAgICAgICAgICAgLy92YXIgaSA9IHZvY2FiTGlzdC5sZW5ndGg7XHJcbiAgICAgICAgICAgIC8vd2hpbGUgKGktLSl7XHJcblx0XHRcdHZvY2FiTGlzdC5mb3JFYWNoKGZ1bmN0aW9uKHRhc2spe1xyXG4gICAgICAgICAgICAgICAgLy9mb3JtIGVsZW1lbnQgdG8gc2F2ZSBzdHJpbmdcclxuICAgICAgICAgICAgICAgIHZhciBvcHQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdvcHRpb24nKTtcclxuXHJcbiAgICAgICAgICAgICAgICAvL2R5bmFtaWMgY29tcG9uZW50cyBvZiBzdHJpbmdcclxuXHJcbiAgICAgICAgICAgICAgICAvL3doZW4gaXMgdGhpcyBpdGVtIHVwIGZvciByZXZpZXdcclxuICAgICAgICAgICAgICAgIHZhciBkdWUgPSB0YXNrLmR1ZXx8dGFzay5kYXRlICsgc3JzT2JqZWN0W3Rhc2subGV2ZWxdLmR1cmF0aW9uO1xyXG4gICAgICAgICAgICAgICAgdmFyIHJldmlldyA9IFwiXCI7XHJcblxyXG4gICAgICAgICAgICAgICAgLy9ubyBmdXR1cmUgcmV2aWV3cyBpZiBidXJuZWRcclxuICAgICAgICAgICAgICAgIGlmKHRhc2subGV2ZWwgPj0gOSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHJldmlldyA9IFwiTmV2ZXJcIjtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAvL2NhbGN1bGF0ZSBuZXh0IHJlbGF0aXZlIHJldmlldyB0aW1lXHJcbiAgICAgICAgICAgICAgICAvL2N1cnJlbnQgdGltZXN0YW1wIGlzIHBhc3QgZHVlIGRhdGUuXHJcbiAgICAgICAgICAgICAgICBlbHNlIGlmKERhdGUubm93KCkgPj0gZHVlKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgcmV2aWV3ID0gXCJOb3dcIiA7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICAgICAgICByZXZpZXcgPSBtczJzdHIoZHVlIC0gRGF0ZS5ub3coKSk7XHJcbiAgICAgICAgICAgICAgICB9Ly9lbmQgaWYgcmV2aWV3IGlzIG5vdCAnbmV2ZXInIG9yICdub3cnXHJcblxyXG4gICAgICAgICAgICAgICAgdmFyIHRleHQgPSB0YXNrLmthbmppICsgXCIgJiBcIiArXHJcbiAgICAgICAgICAgICAgICAgICAgdGFzay5yZWFkaW5nICsgXCIgJiBcIiArXHJcbiAgICAgICAgICAgICAgICAgICAgdGFzay5tZWFuaW5nICsgXCIgKFwiICtcclxuXHRcdFx0XHRcdHNyc09iamVjdFt0YXNrLmxldmVsXS5yYW5rICtcclxuXHRcdFx0XHRcdFwiIC0gUmV2aWV3OiBcIiArXHJcbiAgICAgICAgICAgICAgICAgICAgcmV2aWV3ICsgXCIpIExvY2tlZDogXCIgK1xyXG4gICAgICAgICAgICAgICAgICAgIHRhc2subWFudWFsTG9jaztcclxuXHJcbiAgICAgICAgICAgICAgICBvcHQudmFsdWUgPSBpO1xyXG4gICAgICAgICAgICAgICAgb3B0LmlubmVySFRNTCA9IHRleHQ7XHJcbiAgICAgICAgICAgICAgICBvcHRpb25zLnB1c2gob3B0KTsvL2ZvciBmdXR1cmUgdXNlIChzb3J0aW5nIGRhdGEgZXRjKVxyXG4gICAgICAgICAgICAgICAgc2VsZWN0LmFwcGVuZENoaWxkKG9wdCk7Ly9leHBvcnQgaXRlbSB0byBvcHRpb24gbWVudVxyXG4gICAgICAgICAgICB9LCB0aGlzKTtcclxuICAgICAgICB9XHJcbiAgICB9O1xyXG4gICAgLyoqIEVkaXQgSXRlbXNcclxuXHQqL1xyXG4gICAgd2luZG93LldLU1NfZWRpdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICBnZW5lcmF0ZUVkaXRPcHRpb25zKCk7XHJcbiAgICAgICAgJChcIiNlZGl0XCIpLnNob3coKTtcclxuICAgICAgICAvL2hpZGUgb3RoZXIgd2luZG93c1xyXG4gICAgICAgICQoXCIjZXhwb3J0XCIpLmhpZGUoKTtcclxuICAgICAgICAkKFwiI2ltcG9ydFwiKS5oaWRlKCk7XHJcbiAgICAgICAgJChcIiNhZGRcIikuaGlkZSgpO1xyXG4gICAgICAgICQoXCIjc2VsZnN0dWR5XCIpLmhpZGUoKTtcclxuICAgIH07XHJcblx0dmFyIGJ1aWxkTm9kZSA9IHJlcXVpcmUoJy4vYnVpbGRub2RlLmpzJyk7XHJcblxyXG5cdHZhciBidWlsZFdpbmRvdyA9IHJlcXVpcmUoJy4vYnVpbGR3aW5kb3cuanMnKTtcclxuXHRcclxuXHQvKnZhciBhZGRFZGl0V2luZG93ID0gZnVuY3Rpb24oKSB7XHJcblx0XHR2YXIgZWRpdFdpbmRvdyA9IGJ1aWxkTm9kZSgnZGl2Jywge2lkOiBcIldLU1MtZWRpdFwiLCBjbGFzc05hbWU6IFwiV0tTU1wifSk7XHJcblx0XHR2YXIgZWRpdEZvcm0gPSBidWlsZE5vZGUoJ2Zvcm0nLCB7aWQ6IFwiV0tTUy1lZGl0Rm9ybVwifSk7XHJcblx0XHRlZGl0V2luZG93LmFwcGVuZENoaWxkKGVkaXRGb3JtKTtcclxuXHRcdHZhciBlZGl0Q2xvc2VCdXR0b24gPSBidWlsZE5vZGUoJ2J1dHRvbicsIHtpZDogXCJXS1NTLWVkaXRDbG9zZUJ0blwiLCBjbGFzc05hbWU6IFwiV0tTUy1jbG9zZVwifSk7XHJcblx0XHRlZGl0Rm9ybS5hcHBlbmRDaGlsZChlZGl0Q2xvc2VCdXR0b24pO1xyXG5cdFx0XHJcblx0XHRlZGl0Q2xvc2VCdXR0b24uYXBwZW5kQ2hpbGQoYnVpbGROb2RlKCdpJywge2NsYXNzTmFtZTogXCJpY29uLXJlbW92ZVwifSkpO1xyXG5cdFx0dmFyIGgxRWxlbWVudCA9IGJ1aWxkTm9kZSgnaDEnKTtcclxuXHRcdGVkaXRGb3JtLmFwcGVuZENoaWxkKGgxRWxlbWVudCk7XHJcblx0XHRoMUVsZW1lbnQuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoXCJFZGl0IHlvdXIgVm9jYWJcIikpO1xyXG5cdFx0dmFyIHNlbGVjdEVsZW1lbnQgPSBidWlsZE5vZGUoJ3NlbGVjdCcsIHtpZDogXCJlZGl0V2luZG93XCIsIHNpemU6IFwiOFwifSk7XHJcblx0XHRlZGl0Rm9ybS5hcHBlbmRDaGlsZChzZWxlY3RFbGVtZW50KTtcclxuXHRcdHZhciBlZGl0SXRlbVRleHQgPSBidWlsZE5vZGUoJ2lucHV0Jywge3R5cGU6IFwidGV4dFwiIGlkOiBcImVkaXRJdGVtXCIgbmFtZTogXCJcIiBzaXplOiBcIjQwXCIgcGxhY2Vob2xkZXI6IFwiU2VsZWN0IHZvY2FiLCBjbGljayBlZGl0LCBjaGFuZ2UgYW5kIHNhdmUhXCJ9KTtcclxuXHRcdGVkaXRGb3JtLmFwcGVuZENoaWxkKGVkaXRJdGVtVGV4dCk7XHJcblx0XHR2YXIgZWRpdFN0YXR1cyA9IGJ1aWxkTm9kZSgncCcsIHtpZDogXCJlZGl0U3RhdHVzXCJ9KTtcclxuXHRcdGVkaXRGb3JtLmFwcGVuZENoaWxkKGVkaXRTdGF0dXMpO1xyXG5cdFx0ZWRpdFN0YXR1cy5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShcIlJlYWR5IHRvIGVkaXQuLlwiKSk7XHJcblx0XHRcclxuXHRcdHZhciBlZGl0QnV0dG9uID0gYnVpbGROb2RlKCdidXR0b24nLCB7aWQ6IFwiRWRpdEVkaXRCdG5cIiwgdHlwZTogXCJidXR0b25cIn0pO1xyXG5cdFx0ZWRpdEZvcm0uYXBwZW5kQ2hpbGQoZWRpdEJ1dHRvbik7XHJcblx0XHRlZGl0QnV0dG9uLmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKFwiRWRpdFwiKSk7XHJcblx0XHR2YXIgZWRpdFNhdmUgPSBidWlsZE5vZGUoJ2J1dHRvbicsIHtpZDogXCJFZGl0U2F2ZUJ0blwiLCB0eXBlOiBcImJ1dHRvblwifSk7XHJcblx0XHRlZGl0Rm9ybS5hcHBlbmRDaGlsZChlZGl0U2F2ZSk7XHJcblx0XHRlZGl0U2F2ZS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShcIlNhdmVcIikpO1xyXG5cdFx0dmFyIGVkaXREZWxldGUgPSBidWlsZE5vZGUoJ2J1dHRvbicsIHtpZDogXCJFZGl0RGVsZXRlQnRuXCIsIHR5cGU6IFwiYnV0dG9uXCIsIHRpdGxlOiBcIkRlbGV0ZSBzZWxlY3RlZCBpdGVtXCJ9KTtcclxuXHRcdGVkaXRGb3JtLmFwcGVuZENoaWxkKGVkaXREZWxldGUpO1xyXG5cdFx0ZWRpdERlbGV0ZS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShcIkRlbGV0ZVwiKSk7XHJcblx0XHR2YXIgZWRpdERlbGV0ZUFsbCA9IGJ1aWxkTm9kZSgnYnV0dG9uJywge2lkOiBcIkVkaXREZWxldGVBbGxCdG5cIiwgdHlwZTogXCJidXR0b25cIiwgdGl0bGU6IFwi5pys5b2T44Gr44KE44KL44Gu77yfXCJ9KTtcclxuXHRcdGVkaXRGb3JtLmFwcGVuZENoaWxkKGVkaXREZWxldGVBbGwpO1xyXG5cdFx0ZWRpdERlbGV0ZUFsbC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShcIkRlbGV0ZSBBbGxcIikpO1xyXG5cdFx0dmFyIGVkaXRSZXNldExldmVscyA9IGJ1aWxkTm9kZSgnYnV0dG9uJywge2lkOiBcIlJlc2V0TGV2ZWxzQnRuXCIsIHR5cGU6IFwiYnV0dG9uXCJ9KTtcclxuXHRcdGVkaXRGb3JtLmFwcGVuZENoaWxkKGVkaXRSZXNldExldmVscyk7XHJcblx0XHRlZGl0UmVzZXRMZXZlbHMuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoXCJSZXNldCBsZXZlbHNcIikpO1xyXG5cdFx0XHJcblx0XHRyZXR1cm4gZWRpdFdpbmRvdztcclxuXHR9O1xyXG5cdCovXHJcblx0dmFyIGVkaXRXaW5kb3dTdHJ1Y3R1cmUgPSB7XHJcblx0aWQ6IFwiV0tTUy1lZGl0XCIsXHJcblx0Y2xhc3NOYW1lOiBcIldLU1NcIixcclxuXHRjaGlsZE5vZGVzOlt7XHJcblx0XHR0YWc6ICdmb3JtJyxcclxuXHRcdGlkOiBcIldLU1MtZWRpdEZvcm1cIixcclxuXHRcdGNoaWxkTm9kZXM6W3tcclxuXHRcdFx0dGFnOiAnYnV0dG9uJyxcclxuXHRcdFx0aWQ6IFwiV0tTUy1lZGl0Q2xvc2VCdG5cIixcclxuXHRcdFx0Y2xhc3NOYW1lOiBcIldLU1MtY2xvc2VcIixcclxuXHRcdFx0Y2hpbGROb2Rlczpbe1xyXG5cdFx0XHRcdHRhZzogJ2knLFxyXG5cdFx0XHRcdGNsYXNzTmFtZTogXCJpY29uLXJlbW92ZVwiXHJcblx0XHRcdH1dXHJcblx0XHR9LHtcclxuXHRcdFx0dGFnOiAnaDEnLFxyXG5cdFx0XHRjaGlsZE5vZGVzOltcIkVkaXQgeW91ciBWb2NhYlwiXVxyXG5cdFx0fSx7XHJcblx0XHRcdHRhZzogJ3NlbGVjdCcsXHJcblx0XHRcdGlkOiBcImVkaXRXaW5kb3dcIixcclxuXHRcdFx0b3RoZXI6IHtzaXplOiBcIjhcIn1cclxuXHRcdH0se1xyXG5cdFx0XHR0YWc6ICdpbnB1dCcsIFxyXG5cdFx0XHRvdGhlcjp7XHJcblx0XHRcdFx0dHlwZTogXCJ0ZXh0XCIsXHJcblx0XHRcdFx0bmFtZTogXCJcIixcclxuXHRcdFx0XHRzaXplOiBcIjQwXCIsXHJcblx0XHRcdFx0cGxhY2Vob2xkZXI6IFwiU2VsZWN0IHZvY2FiLCBjbGljayBlZGl0LCBjaGFuZ2UgYW5kIHNhdmUhXCJcclxuXHRcdFx0fSxcclxuXHRcdFx0aWQ6IFwiZWRpdEl0ZW1cIlxyXG5cdFx0fSx7XHJcblx0XHRcdHRhZzogJ3AnLCBcclxuXHRcdFx0aWQ6IFwiZWRpdFN0YXR1c1wiLFxyXG5cdFx0XHRjaGlsZE5vZGVzOltcIlJlYWR5IHRvIGVkaXQuLi5cIl1cclxuXHRcdH0se1xyXG5cdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRpZDogXCJFZGl0RWRpdEJ0blwiLFxyXG5cdFx0XHRvdGhlcjoge3R5cGU6IFwiYnV0dG9uXCJ9LFxyXG5cdFx0XHRjaGlsZE5vZGVzOltcIkVkaXRcIl1cclxuXHRcdH0se1xyXG5cdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRpZDogXCJFZGl0U2F2ZUJ0blwiLFxyXG5cdFx0XHRvdGhlcjp7dHlwZTogXCJidXR0b25cIn0sXHJcblx0XHRcdGNoaWxkTm9kZXM6W1wiU2F2ZVwiXVxyXG5cdFx0fSx7XHJcblx0XHRcdHRhZzogJ2J1dHRvbicsXHJcblx0XHRcdGlkOiBcIkVkaXREZWxldGVCdG5cIixcclxuXHRcdFx0b3RoZXI6IHt0eXBlOiBcImJ1dHRvblwiLCB0aXRsZTogXCJEZWxldGUgc2VsZWN0ZWQgaXRlbVwifSxcclxuXHRcdFx0Y2hpbGROb2RlczpbXCJEZWxldGVcIl1cclxuXHRcdH0se1xyXG5cdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRpZDogXCJFZGl0RGVsZXRlQWxsQnRuXCIsXHJcblx0XHRcdG90aGVyOiB7dHlwZTogXCJidXR0b25cIiwgdGl0bGU6IFwi5pys5b2T44Gr44KE44KL44Gu77yfXCJ9LFxyXG5cdFx0XHRjaGlsZE5vZGVzOltcIkRlbGV0ZSBBbGxcIl1cclxuXHRcdH0se1xyXG5cdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRpZDogXCJSZXNldExldmVsc0J0blwiLFxyXG5cdFx0XHRvdGhlcjoge3R5cGU6IFwiYnV0dG9uXCJ9LFxyXG5cdFx0XHRjaGlsZE5vZGVzOltcIlJlc2V0IGxldmVsc1wiXVxyXG5cdFx0fV1cclxuXHR9XVxyXG59O1xyXG5cclxuICAgIHZhciBhZGRFZGl0V2luZG93ID0gYnVpbGRXaW5kb3coZWRpdFdpbmRvd1N0cnVjdHVyZSk7XHJcblx0JChcImJvZHlcIikuYXBwZW5kKGFkZEVkaXRXaW5kb3cpO1xyXG4gICAgJChcIiNXS1NTLWVkaXRcIikuaGlkZSgpO1xyXG5cclxuXHQvKiogUmVzZXRzIHRoZSBsZXZlbHMgb2YgYWxsIHRhc2tzIGFuZCByZS1pbmRleGVzIHRoZW0gaW4gc3RvcmFnZS5cclxuXHQqIEBwYXJhbSB7RXZlbnR9IGV2dCAtIENsaWNrIGV2ZW50IChub3QgdXNlZClcclxuXHQqL1xyXG5cdHZhciByZXNldExldmVscyA9IGZ1bmN0aW9uIChldnQpIHtcclxuXHRcdHZhciB2b2NMaXN0ID0gU3RvcmFnZVV0aWwuZ2V0Vm9jTGlzdCgpLm1hcChmdW5jdGlvbih2b2NJdGVtLCBpKXtcclxuXHRcdFx0dm9jSXRlbS5sZXZlbCA9IDA7XHJcblx0XHRcdGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJ2b2NMaXN0W2ldLmkgYmVmb3JlOiBcIit2b2NJdGVtLmkpO1xyXG5cdFx0XHR2b2NJdGVtLmk9aTtcclxuXHRcdFx0ZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcInZvY0xpc3RbaV0uaSBhZnRlcjogXCIrdm9jSXRlbS5pKTtcclxuXHRcdFx0cmV0dXJuIHZvY0l0ZW07XHJcblx0XHR9LCB0aGlzKTtcclxuXHRcdFN0b3JhZ2VVdGlsLnNldFZvY0xpc3Qodm9jTGlzdCk7XHJcbiAgICB9O1xyXG4gICAgJChcIiNSZXNldExldmVsc0J0blwiKS5jbGljayhyZXNldExldmVscyk7XHJcblxyXG4gICAgJChcIiNFZGl0RWRpdEJ0blwiKS5jbGljayhmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgLy9nZXQgaGFuZGxlIGZvciAnc2VsZWN0JyBhcmVhXHJcbiAgICAgICAgdmFyIHNlbGVjdCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwiZWRpdFdpbmRvd1wiKTtcclxuXHJcbiAgICAgICAgLy9nZXQgdGhlIGluZGV4IGZvciB0aGUgY3VycmVudGx5IHNlbGVjdGVkIGl0ZW1cclxuICAgICAgICB2YXIgaW5kZXggPSBzZWxlY3Quc2VsZWN0ZWRJbmRleDsgLy9zZWxlY3Qub3B0aW9uc1tzZWxlY3Quc2VsZWN0ZWRJbmRleF0udmFsdWUgaXMgbm90IHJlcXVpcmVkLCBvcHRpb24gdmFsdWVzIGFyZSBzZXQgdG8gaW5kZXhcclxuICAgICAgICB2YXIgdm9jYWJMaXN0ID0gU3RvcmFnZVV0aWwuZ2V0Vm9jTGlzdCgpO1xyXG4gICAgICAgIHZvY2FiTGlzdCA9IHZvY2FiTGlzdC5yZXZlcnNlKCk7XHJcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJlZGl0SXRlbVwiKS52YWx1ZSA9IEpTT04uc3RyaW5naWZ5KHZvY2FiTGlzdFtpbmRleF0pO1xyXG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwiZWRpdEl0ZW1cIikubmFtZSA9IGluZGV4OyAvL3VzaW5nIG5hbWUgdG8gc2F2ZSB0aGUgaW5kZXhcclxuICAgICAgICAkKFwiI2VkaXRTdGF0dXNcIikudGV4dCgnTG9hZGVkIGl0ZW0gdG8gZWRpdCcpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgdmFyIGlzRW1wdHkgPSBmdW5jdGlvbih2YWx1ZSkge1xyXG4gICAgICAgIHJldHVybiAodmFsdWUgPT09IHZvaWQgMCB8fCB2YWx1ZSA9PT0gbnVsbCk7XHJcbiAgICB9O1xyXG5cdFxyXG5cdHZhciBpc0FycmF5ID0gZnVuY3Rpb24oYXJnKXtcclxuXHRcdHJldHVybiBBcnJheS5pc0FycmF5ID8gQXJyYXkuaXNBcnJheShhcmcpIDogT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGFyZykgPT09ICdbb2JqZWN0IEFycmF5XSc7XHJcblx0fTtcclxuXHJcbiAgICAvKiogVmFsaWRhdGVzIGEgdGFzayBvYmplY3RcclxuXHQqIEBwYXJhbSB7VGFza30gYWRkIC0gVGhlIFRhc2sgYmVpbmcgdmVyaWZpZWRcclxuXHQqIEByZXR1cm5zIHtCb29sZWFufSBJZiB0aGUgcHJvdmlkZWQgdGFzayBoYXMgYWxsIHRoZSBuZWNlc3NhcnkgcHJvcGVydGllcyB0byBiZSBhZGRlZCB0byB0aGUgcmV2aWV3IGxpc3QuXHJcblx0Ki9cclxuXHR2YXIgaXNJdGVtVmFsaWQgPSBmdW5jdGlvbihhZGQpIHtcclxuICAgICAgICByZXR1cm4gKCFpc0VtcHR5KGFkZC5rYW5qaSkgJiYgLy9rYW5qaSBwcm9wZXJ0eSBleGlzdHNcclxuXHRcdFx0IWlzRW1wdHkoYWRkLm1lYW5pbmcpICYmIC8vbWVhbmluZyBwcm9wZXJ0eSBleGlzdHNcclxuXHRcdFx0IWlzRW1wdHkoYWRkLnJlYWRpbmcpICYmIC8vcmVhZGluZyBwcm9wZXJ0eSBleGlzdHNcclxuXHRcdFx0aXNBcnJheShhZGQubWVhbmluZykgJiYvL21lYW5pbmcgaXMgYW4gYXJyYXlcclxuXHRcdFx0aXNBcnJheShhZGQucmVhZGluZykpOy8vcmVhZGluZyBpcyBhbiBhcnJheVxyXG4gICAgfTtcclxuXHJcbiAgICAkKFwiI0VkaXRTYXZlQnRuXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcclxuXHRcdC8vLS0gYmUgYXdhcmVcclxuXHRcdC8vZGVsZXRpbmcgb25lIGl0ZW0gbWF5IGNhdXNlIG1pc21hdGNoIGlmIGkgaXMgcHJvcGVydHkgb2YgaXRlbSBpbiBsaXN0XHJcblx0XHR0cnkge1xyXG5cdFx0XHRpZiAoJChcIiNlZGl0SXRlbVwiKS52YWwoKS5sZW5ndGggIT09IDApIHtcclxuXHRcdFx0XHR2YXIgZWRpdEl0ZW0gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImVkaXRJdGVtXCIpO1xyXG4gICAgICAgICAgICAgICAgdmFyIGluZGV4ID0gZWRpdEl0ZW0ubmFtZTtcclxuXHRcdFx0XHR2YXIgaXRlbSA9IEpTT04ucGFyc2UoZWRpdEl0ZW0udmFsdWUudG9Mb3dlckNhc2UoKSk7XHJcbiAgICAgICAgICAgICAgICAvLyBNYWtlIHN1cmUgdGhhdCB0aGUgd29yZCAnbWVhbmluZycgaXMgaW1tdXRhYmxlLCBzbyBpdCBleGlzdHMgdG8gdHJpbVxyXG5cdFx0XHRcdFxyXG5cdFx0XHRcdGlmIChpdGVtLm1lYW5pbmcpe1xyXG5cdFx0XHRcdFx0aXRlbS5tZWFuaW5nLmZvckVhY2goZnVuY3Rpb24obWVhbmluZywgbSwgbWVhbmluZ3Mpe1xyXG5cdFx0XHRcdFx0XHRpZiAobWVhbmluZyA9PT0gXCJcIil7XHJcblx0XHRcdFx0XHRcdFx0ZGVsZXRlIG1lYW5pbmdzW21dO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9LCB0aGlzKTtcclxuXHRcdFx0XHR9XHJcbiAgICAgICAgICAgICAgICB2YXIgZnVsbExpc3QgPSBTdG9yYWdlVXRpbC5nZXRWb2NMaXN0KCkucmV2ZXJzZSgpO1xyXG5cclxuICAgICAgICAgICAgICAgIGlmIChpc0l0ZW1WYWxpZChpdGVtKSAmJi8vaXRlbSBpcyB2YWxpZFxyXG4gICAgICAgICAgICAgICAgICAgICEoY2hlY2tGb3JEdXBsaWNhdGVzKGZ1bGxMaXN0LGl0ZW0pICYmIC8va2FuamkgKGlmIGNoYW5nZWQpIGlzIG5vdCBhbHJlYWR5IGluIHRoZSBsaXN0XHJcbiAgICAgICAgICAgICAgICAgICAgICBmdWxsTGlzdFtpbmRleF0ua2FuamkgIT09IGl0ZW0ua2FuamkpKSB7Ly91bmxlc3MgaXQgaXMgdGhlIGl0ZW0gYmVpbmcgZWRpdGVkXHJcblxyXG4gICAgICAgICAgICAgICAgICAgIHZhciBzcnNsaXN0ID0gU3RvcmFnZVV0aWwuZ2V0Vm9jTGlzdCgpLnJldmVyc2UoKTtcclxuICAgICAgICAgICAgICAgICAgICAvL2dldCBzcnMgY29tcG9uZW50cyBvZiBpdGVtKGxpc3QpXHJcbiAgICAgICAgICAgICAgICAgICAgZnVsbExpc3RbaW5kZXhdID0gaXRlbTsvL2RvZXMgbm90IGhhdmUgc3JzIHN0dWZmLCByZS1hZGQgaXQgbm93XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIGZ1bGxMaXN0W2luZGV4XS5kYXRlID0gc3JzbGlzdFtpbmRleF0uZGF0ZTtcclxuICAgICAgICAgICAgICAgICAgICBmdWxsTGlzdFtpbmRleF0ubGV2ZWwgPSBzcnNsaXN0W2luZGV4XS5sZXZlbDtcclxuICAgICAgICAgICAgICAgICAgICBmdWxsTGlzdFtpbmRleF0ubG9ja2VkID0gc3JzbGlzdFtpbmRleF0ubG9ja2VkO1xyXG4gICAgICAgICAgICAgICAgICAgIGZ1bGxMaXN0W2luZGV4XS5tYW51YWxMb2NrID0gc3JzbGlzdFtpbmRleF0ubWFudWFsTG9jaztcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgZnVsbExpc3QgPSBmdWxsTGlzdC5yZXZlcnNlKCk7IC8vcmVzZXQgb3JkZXIgb2YgYXJyYXlcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgbG9jYWxTZXQoJ1VzZXItVm9jYWInLCBmdWxsTGlzdCk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIGdlbmVyYXRlRWRpdE9wdGlvbnMoKTtcclxuICAgICAgICAgICAgICAgICAgICAkKFwiI2VkaXRTdGF0dXNcIikuaHRtbCgnU2F2ZWQgY2hhbmdlcyEnKTtcclxuICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImVkaXRJdGVtXCIpLnZhbHVlID0gXCJcIjtcclxuICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImVkaXRJdGVtXCIpLm5hbWUgPSBcIlwiO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRlbHNle1xyXG4gICAgICAgICAgICAgICAgICAgICQoXCIjZWRpdFN0YXR1c1wiKS50ZXh0KCdJbnZhbGlkIGl0ZW0gb3IgZHVwbGljYXRlIScpO1xyXG4gICAgICAgICAgICAgICAgICAgIGFsZXJ0KGlzSXRlbVZhbGlkKGl0ZW0pLnRvU3RyaW5nKCkgK1wiICYmIO+8gShcIisgY2hlY2tGb3JEdXBsaWNhdGVzKGZ1bGxMaXN0LGl0ZW0pLnRvU3RyaW5nKCkrXCIgJiYgIShcIitmdWxsTGlzdFtpbmRleF0ua2FuamkrXCIgIT09IFwiK2l0ZW0ua2FuamkrXCIpXCIpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRjYXRjaCAoZSkge1xyXG5cdFx0XHQkKFwiI2VkaXRTdGF0dXNcIikudGV4dChlKTtcclxuXHRcdH1cclxuICAgIH0pO1xyXG5cclxuICAgIHZhciB1cGRhdGVFZGl0R1VJID0gZnVuY3Rpb24oKXtcclxuICAgICAgICBnZW5lcmF0ZUVkaXRPcHRpb25zKCk7XHJcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJlZGl0SXRlbVwiKS52YWx1ZSA9IFwiXCI7XHJcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJlZGl0SXRlbVwiKS5uYW1lID0gXCJcIjtcclxuICAgIH07XHJcblx0dmFyIGVkaXREZWxldGUgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgLy9zZWxlY3Qgb3B0aW9ucyBlbGVtZW50IHdpbmRvd1xyXG4gICAgICAgIHZhciBzZWxlY3QgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcImVkaXRXaW5kb3dcIik7XHJcblxyXG4gICAgICAgIC8vaW5kZXggb2Ygc2VsZWN0ZWQgaXRlbVxyXG4gICAgICAgIHZhciBpdGVtID0gc2VsZWN0Lm9wdGlvbnNbc2VsZWN0LnNlbGVjdGVkSW5kZXhdLnZhbHVlO1xyXG5cclxuICAgICAgICAvL2ZldGNoIEpTT04gc3RyaW5ncyBmcm9tIHN0b3JhZ2UgYW5kIGNvbnZlcnQgdGhlbSBpbnRvIEphdmFzY3JpcHQgbGl0ZXJhbHNcclxuICAgICAgICB2YXIgdm9jYWJMaXN0ID0gU3RvcmFnZVV0aWwuZ2V0Vm9jTGlzdCgpO1xyXG5cclxuICAgICAgICAvL3N0YXJ0aW5nIGF0IHNlbGVjdGVkIGluZGV4LCByZW1vdmUgMSBlbnRyeSAodGhlIHNlbGVjdGVkIGluZGV4KS5cclxuICAgICAgICBpZiAoaXRlbSA+IC0xKSB7XHJcbiAgICAgICAgICAgIGlmICh2b2NhYkxpc3QgIT09IG51bGwpe1xyXG4gICAgICAgICAgICAgICAgdm9jYWJMaXN0LnNwbGljZShpdGVtLCAxKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy95dWNrXHJcbiAgICAgICAgaWYgKHZvY2FiTGlzdC5sZW5ndGggIT09IDApIHtcclxuICAgICAgICAgICAgbG9jYWxTZXQoJ1VzZXItVm9jYWInLCB2b2NhYkxpc3QpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgbG9jYWxTdG9yYWdlLnJlbW92ZUl0ZW0oJ1VzZXItVm9jYWInKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHVwZGF0ZUVkaXRHVUkoKTtcclxuXHJcbiAgICAgICAgJChcIiNlZGl0U3RhdHVzXCIpLnRleHQoJ0l0ZW0gZGVsZXRlZCEnKTtcclxuICAgIH07XHJcbiAgICAkKFwiI0VkaXREZWxldGVCdG5cIikuY2xpY2soZWRpdERlbGV0ZSk7XHJcblxyXG5cdHZhciBlZGl0RGVsZXRlQWxsID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIHZhciBkZWxldGVBbGwgPSBjb25maXJtKFwiQXJlIHlvdSBzdXJlIHlvdSB3YW50IHRvIGRlbGV0ZSBhbGwgZW50cmllcz9cIik7XHJcbiAgICAgICAgaWYgKGRlbGV0ZUFsbCkge1xyXG4gICAgICAgICAgICAvL2Ryb3AgbG9jYWwgc3RvcmFnZVxyXG4gICAgICAgICAgICBsb2NhbFN0b3JhZ2UucmVtb3ZlSXRlbSgnVXNlci1Wb2NhYicpO1xyXG4gICAgICAgICAgICB1cGRhdGVFZGl0R1VJKCk7XHJcbiAgICAgICAgICAgICQoXCIjZWRpdFN0YXR1c1wiKS50ZXh0KCdBbGwgaXRlbXMgZGVsZXRlZCEnKTtcclxuICAgICAgICB9XHJcbiAgICB9O1xyXG4gICAgJChcIiNFZGl0RGVsZXRlQWxsQnRuXCIpLmNsaWNrKGVkaXREZWxldGVBbGwpO1xyXG5cclxuICAgICQoXCIjRWRpdENsb3NlQnRuXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAkKFwiI2VkaXRcIikuaGlkZSgpO1xyXG4gICAgICAgICQoXCIjZWRpdEZvcm1cIilbMF0ucmVzZXQoKTtcclxuICAgICAgICAkKFwiI2VkaXRTdGF0dXNcIikudGV4dCgnUmVhZHkgdG8gZWRpdC4uJyk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvKiogRXhwb3J0XHJcblx0Ki9cclxuICAgIHdpbmRvdy5XS1NTX2V4cG9ydCA9IGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAkKFwiI2V4cG9ydFwiKS5zaG93KCk7XHJcbiAgICAgICAgLy9oaWRlIG90aGVyIHdpbmRvd3NcclxuICAgICAgICAkKFwiI2FkZFwiKS5oaWRlKCk7XHJcbiAgICAgICAgJChcIiNpbXBvcnRcIikuaGlkZSgpO1xyXG4gICAgICAgICQoXCIjZWRpdFwiKS5oaWRlKCk7XHJcbiAgICAgICAgJChcIiNzZWxmc3R1ZHlcIikuaGlkZSgpO1xyXG4gICAgfTtcclxuXHJcblx0dmFyIGV4cG9ydFdpbmRvd1N0cnVjdHVyZSA9IHtcclxuXHRcdGlkOiBcIldLU1MtZXhwb3J0XCIsXHJcblx0XHRjbGFzc05hbWU6IFwiV0tTU1wiLFxyXG5cdFx0Y2hpbGROb2Rlczpbe1xyXG5cdFx0XHR0YWc6ICdmb3JtJyxcclxuXHRcdFx0aWQ6IFwiV0tTUy1leHBvcnRGb3JtXCIsXHJcblx0XHRcdGNoaWxkTm9kZXM6W1xyXG5cdFx0XHRcdHtcclxuXHRcdFx0XHRcdHRhZzogJ2J1dHRvbicsXHJcblx0XHRcdFx0XHRpZDogXCJXS1NTLWV4cG9ydENsb3NlQnRuXCIsXHJcblx0XHRcdFx0XHRjbGFzc05hbWU6IFwiV0tTUy1jbG9zZVwiLFxyXG5cdFx0XHRcdFx0Y2hpbGROb2Rlczpbe1xyXG5cdFx0XHRcdFx0XHR0YWc6ICdpJyxcclxuXHRcdFx0XHRcdFx0Y2xhc3NOYW1lOiBcImljb24tcmVtb3ZlXCJcclxuXHRcdFx0XHRcdH1dXHJcblx0XHRcdFx0fSxcclxuXHRcdFx0XHR7XHJcblx0XHRcdFx0XHR0YWc6ICdoMScsXHJcblx0XHRcdFx0XHRjaGlsZE5vZGVzOltcIkV4cG9ydCBJdGVtc1wiXVxyXG5cdFx0XHRcdH0sXHJcblx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0dGFnOiAndGV4dGFyZWEnLFxyXG5cdFx0XHRcdFx0aWQ6IFwiZXhwb3J0QXJlYVwiLFxyXG5cdFx0XHRcdFx0b3RoZXI6IHtjb2xzOiBcIjUwXCIsIHJvd3M6IFwiMThcIiwgcGxhY2Vob2xkZXI6IFwiRXhwb3J0IHlvdXIgc3R1ZmYhIFNoYXJpbmcgaXMgY2FyaW5nIDspXCJ9XHJcblx0XHRcdFx0fSxcclxuXHRcdFx0XHR7XHJcblx0XHRcdFx0XHR0YWc6ICdwJywgXHJcblx0XHRcdFx0XHRpZDogXCJleHBvcnRTdGF0dXNcIixcclxuXHRcdFx0XHRcdGNoaWxkTm9kZXM6W1wiUmVhZHkgdG8gZXhwb3J0Li4uXCJdXHJcblx0XHRcdFx0fSxcclxuXHRcdFx0XHR7XHJcblx0XHRcdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRcdFx0aWQ6IFwiRXhwb3J0SXRlbXNCdG5cIixcclxuXHRcdFx0XHRcdG90aGVyOiB7dHlwZTogXCJidXR0b25cIn0sXHJcblx0XHRcdFx0XHRjaGlsZE5vZGVzOltcIkV4cG9ydCBJdGVtc1wiXVxyXG5cdFx0XHRcdH0sXHJcblx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0dGFnOiAnYnV0dG9uJyxcclxuXHRcdFx0XHRcdGlkOiBcIkV4cG9ydFNlbGVjdEFsbEJ0blwiLFxyXG5cdFx0XHRcdFx0b3RoZXI6e3R5cGU6IFwiYnV0dG9uXCJ9LFxyXG5cdFx0XHRcdFx0Y2hpbGROb2RlczpbXCJTZWxlY3QgQWxsXCJdXHJcblx0XHRcdFx0fSxcclxuXHRcdFx0XHR7XHJcblx0XHRcdFx0XHR0YWc6ICdidXR0b24nLFxyXG5cdFx0XHRcdFx0aWQ6IFwiRXhwb3J0Q3N2QnRuXCIsXHJcblx0XHRcdFx0XHRvdGhlcjoge3R5cGU6IFwiYnV0dG9uXCJ9LFxyXG5cdFx0XHRcdFx0Y2hpbGROb2RlczpbXCJFeHBvcnQgQ1NWXCJdXHJcblx0XHRcdFx0fVxyXG5cdFx0XHRdXHJcblx0XHR9XVxyXG5cdH07XHJcblx0dmFyIGV4cG9ydFdpbmRvdyA9IGJ1aWxkV2luZG93KGV4cG9ydFdpbmRvd1N0cnVjdHVyZSk7XHJcblxyXG4gICAgJChcImJvZHlcIikuYXBwZW5kKGV4cG9ydFdpbmRvdyk7XHJcbiAgICAkKFwiI1dLU1MtZXhwb3J0XCIpLmhpZGUoKTtcclxuXHJcblxyXG4gICAgJChcIiNFeHBvcnRJdGVtc0J0blwiKS5jbGljayhmdW5jdGlvbiAoKSB7XHJcblxyXG4gICAgICAgIGlmIChsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnVXNlci1Wb2NhYicpKSB7XHJcbiAgICAgICAgICAgICQoXCIjZXhwb3J0Rm9ybVwiKVswXS5yZXNldCgpO1xyXG4gICAgICAgICAgICB2YXIgdm9jYWJMaXN0ID0gU3RvcmFnZVV0aWwuZ2V0Vm9jTGlzdCgpO1xyXG4gICAgICAgICAgICAkKFwiI2V4cG9ydEFyZWFcIikudGV4dChKU09OLnN0cmluZ2lmeSh2b2NhYkxpc3QpKTtcclxuICAgICAgICAgICAgJChcIiNleHBvcnRTdGF0dXNcIikudGV4dChcIkNvcHkgdGhpcyB0ZXh0IGFuZCBzaGFyZSBpdCB3aXRoIG90aGVycyFcIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVsc2Uge1xyXG4gICAgICAgICAgICAkKFwiI2V4cG9ydFN0YXR1c1wiKS50ZXh0KFwiTm90aGluZyB0byBleHBvcnQgeWV0IDooXCIpO1xyXG4gICAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuXHR2YXIgc2VsZWN0X2FsbCA9IGZ1bmN0aW9uKHN0cikge1xyXG4gICAgICAgIHZhciB0ZXh0X3ZhbCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHN0cik7XHJcbiAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyh0ZXh0X3ZhbCk7XHJcbiAgICAgICAgdGV4dF92YWwuZm9jdXMoKTtcclxuICAgICAgICB0ZXh0X3ZhbC5zZWxlY3QoKTtcclxuICAgIH07XHJcblxyXG4gICAgJChcIiNFeHBvcnRTZWxlY3RBbGxCdG5cIikuY2xpY2soZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIGlmICgkKFwiI2V4cG9ydEFyZWFcIikudmFsKCkubGVuZ3RoICE9PSAwKSB7XHJcbiAgICAgICAgICAgIHNlbGVjdF9hbGwoXCJleHBvcnRBcmVhXCIpO1xyXG4gICAgICAgICAgICAkKFwiI2V4cG9ydFN0YXR1c1wiKS50ZXh0KFwiRG9uJ3QgZm9yZ2V0IHRvIENUUkwgKyBDIVwiKTtcclxuICAgICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICB2YXIgY3JlYXRlQ1NWID0gZnVuY3Rpb24oSlNPTnN0cmluZyl7XHJcbiAgICAgICAgdmFyIEpTT05vYmplY3QgPSAodHlwZW9mIEpTT05zdHJpbmcgPT09ICdzdHJpbmcnKSA/IEpTT04ucGFyc2UoSlNPTnN0cmluZykgOiBKU09Oc3RyaW5nO1xyXG4gICAgICAgIHZhciBrZXk7XHJcbiAgICAgICAgdmFyIENTVmFycmF5ID0gW107XHJcbiAgICAgICAgdmFyIGhlYWRlciA9IFtdOyAgXHJcbiAgICAgICAgdmFyIGlkID0gSlNPTm9iamVjdC5sZW5ndGg7XHJcbiAgICAgICAgaWYgKGlkKXsvL29iamVjdCBub3QgZW1wdHlcclxuICAgICAgICAgICAgZm9yIChrZXkgaW4gSlNPTm9iamVjdFswXSl7XHJcbiAgICAgICAgICAgICAgICBpZiAoSlNPTm9iamVjdFswXS5oYXNPd25Qcm9wZXJ0eShrZXkpKXtcclxuICAgICAgICAgICAgICAgICAgICBoZWFkZXIucHVzaChrZXkpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIENTVmFycmF5LnB1c2goaGVhZGVyLmpvaW4oJywnKSk7XHJcblxyXG4gICAgICAgIHdoaWxlKGlkLS0pe1xyXG4gICAgICAgICAgICB2YXIgbGluZSA9IFtdO1xyXG4gICAgICAgICAgICB2YXIgaCA9IGhlYWRlci5sZW5ndGg7XHJcbiAgICAgICAgICAgIHdoaWxlKGgtLSl7Ly8gb25seSBkbyBrZXlzIGluIGhlYWRlciwgaW4gdGhlIGhlYWRlcidzIG9yZGVyLiAvL0pTT05vYmplY3RbaWRdKXtcclxuICAgICAgICAgICAgICAgIGtleSA9IGhlYWRlcltoXTtcclxuICAgICAgICAgICAgICAgIGlmKEpTT05vYmplY3RbaWRdW2tleV0gIT09IHVuZGVmaW5lZCl7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkoSlNPTm9iamVjdFtpZF1ba2V5XSkpe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAvL3BhcnNlIGFycmF5IGhlcmVcclxuICAgICAgICAgICAgICAgICAgICAgICAgbGluZS5wdXNoKEpTT05vYmplY3RbaWRdW2tleV0uam9pbihcIlxcdFwiKSk7XHJcbiAgICAgICAgICAgICAgICAgICAgfWVsc2V7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGxpbmUucHVzaChKU09Ob2JqZWN0W2lkXVtrZXldKTtcclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1saW5lID0gbGluZS5yZXZlcnNlKCk7XHJcbiAgICAgICAgICAgIENTVmFycmF5LnB1c2gobGluZS5qb2luKCcsJykpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB2YXIgQ1NWc3RyaW5nID0gQ1NWYXJyYXkuam9pbihcIlxcclxcblwiKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIGVuY29kZVVSSShcImRhdGE6dGV4dC9jc3Y7Y2hhcnNldD11dGYtOCxcIiArIENTVnN0cmluZyk7XHJcbiAgICB9O1xyXG5cclxuICAgICQoXCIjRXhwb3J0Q3N2QnRuXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICB2YXIgdm9jYWJMaXN0ID0gU3RvcmFnZVV0aWwuZ2V0Vm9jTGlzdCgpO1xyXG4gICAgICAgIHZhciBDc3ZGaWxlID0gY3JlYXRlQ1NWKHZvY2FiTGlzdCk7XHJcbiAgICAgICAgd2luZG93Lm9wZW4oQ3N2RmlsZSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAkKFwiI0V4cG9ydENsb3NlQnRuXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcclxuXHRcdCQoXCIjZXhwb3J0XCIpLmhpZGUoKTtcclxuXHRcdCQoXCIjZXhwb3J0Rm9ybVwiKVswXS5yZXNldCgpO1xyXG5cdFx0JChcIiNleHBvcnRBcmVhXCIpLnRleHQoXCJcIik7XHJcblx0XHQkKFwiI2V4cG9ydFN0YXR1c1wiKS50ZXh0KCdSZWFkeSB0byBleHBvcnQuLicpO1xyXG5cdH0pO1xyXG5cclxuICAgIC8qKiBJbXBvcnRcclxuXHQqL1xyXG4gICAgd2luZG93LldLU1NfaW1wb3J0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICQoXCIjaW1wb3J0XCIpLnNob3coKTtcclxuICAgICAgICAvL2hpZGUgb3RoZXIgd2luZG93c1xyXG4gICAgICAgICQoXCIjYWRkXCIpLmhpZGUoKTtcclxuICAgICAgICAkKFwiI2V4cG9ydFwiKS5oaWRlKCk7XHJcbiAgICAgICAgJChcIiNlZGl0XCIpLmhpZGUoKTtcclxuICAgICAgICAkKFwiI3NlbGZzdHVkeVwiKS5oaWRlKCk7XHJcbiAgICB9O1xyXG5cclxuIFx0dmFyIGltcG9ydFdpbmRvd1N0cnVjdHVyZSA9IHtcclxuXHRcdGlkOiBcIldLU1MtaW1wb3J0XCIsXHJcblx0XHRjbGFzc05hbWU6IFwiV0tTU1wiLFxyXG5cdFx0Y2hpbGROb2Rlczpbe1xyXG5cdFx0XHR0YWc6ICdmb3JtJyxcclxuXHRcdFx0aWQ6IFwiV0tTUy1pbXBvcnRGb3JtXCIsXHJcblx0XHRcdGNoaWxkTm9kZXM6W1xyXG5cdFx0XHRcdHtcclxuXHRcdFx0XHRcdHRhZzogJ2J1dHRvbicsXHJcblx0XHRcdFx0XHRpZDogXCJXS1NTLWltcG9ydENsb3NlQnRuXCIsXHJcblx0XHRcdFx0XHRjbGFzc05hbWU6IFwiV0tTUy1jbG9zZVwiLFxyXG5cdFx0XHRcdFx0Y2hpbGROb2Rlczpbe1xyXG5cdFx0XHRcdFx0XHR0YWc6ICdpJyxcclxuXHRcdFx0XHRcdFx0Y2xhc3NOYW1lOiBcImljb24tcmVtb3ZlXCJcclxuXHRcdFx0XHRcdH1dXHJcblx0XHRcdFx0fSxcclxuXHRcdFx0XHR7XHJcblx0XHRcdFx0XHR0YWc6ICdoMScsXHJcblx0XHRcdFx0XHRjaGlsZE5vZGVzOltcIkltcG9ydCBJdGVtc1wiXVxyXG5cdFx0XHRcdH0sXHJcblx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0dGFnOiAndGV4dGFyZWEnLFxyXG5cdFx0XHRcdFx0aWQ6IFwiaW1wb3J0QXJlYVwiLFxyXG5cdFx0XHRcdFx0b3RoZXI6IHtjb2xzOiBcIjUwXCIsIHJvd3M6IFwiMThcIiwgcGxhY2Vob2xkZXI6IFwiUGFzdGUgeW91ciBzdHVmZiBhbmQgaGl0IHRoZSBpbXBvcnQgYnV0dG9uISBVc2Ugd2l0aCBjYXV0aW9uIVwifVxyXG5cdFx0XHRcdH0sXHJcblx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0dGFnOiAncCcsIFxyXG5cdFx0XHRcdFx0aWQ6IFwiaW1wb3J0U3RhdHVzXCIsXHJcblx0XHRcdFx0XHRjaGlsZE5vZGVzOltcIlJlYWR5IHRvIGltcG9ydC4uLlwiXVxyXG5cdFx0XHRcdH0sXHJcblx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0dGFnOiAnbGFiZWwnLFxyXG5cdFx0XHRcdFx0aWQ6IFwiSW1wb3J0SXRlbXNCdG5cIixcclxuXHRcdFx0XHRcdGNsYXNzTmFtZTogXCJidXR0b25cIixcclxuXHRcdFx0XHRcdG90aGVyOiB7dHlwZTogXCJidXR0b25cIiwgc3R5bGU6IFwiZGlzcGxheTppbmxpbmU7XCJ9LFxyXG5cdFx0XHRcdFx0Y2hpbGROb2RlczpbXCJJbXBvcnQgSXRlbXNcIl1cclxuXHRcdFx0XHR9LFxyXG5cdFx0XHRcdHtcclxuXHRcdFx0XHRcdHRhZzogJ2xhYmVsJyxcclxuXHRcdFx0XHRcdGlkOiBcIkltcG9ydENzdkJ0blwiLFxyXG5cdFx0XHRcdFx0Y2xhc3NOYW1lOiBcImJ1dHRvblwiLFxyXG5cdFx0XHRcdFx0b3RoZXI6IHtzdHlsZTpcImRpc3BsYXk6aW5saW5lOyBjdXJzb3I6IHBvaW50ZXI7XCJ9LFxyXG5cdFx0XHRcdFx0Y2hpbGROb2RlczpbXCJJbXBvcnQgQ1NWXCIsXHJcblx0XHRcdFx0XHRcdHtcclxuXHRcdFx0XHRcdFx0XHR0YWc6ICdpbnB1dCcsXHJcblx0XHRcdFx0XHRcdFx0aWQ6IFwidXBsb2FkXCIsXHJcblx0XHRcdFx0XHRcdFx0b3RoZXI6IHtcclxuXHRcdFx0XHRcdFx0XHRcdHR5cGU6IFwiZmlsZVwiLCBhY2NlcHQ6IFwiLmNzdiwgLnRzdlwiLFxyXG5cdFx0XHRcdFx0XHRcdFx0c3R5bGU6IFwiaGVpZ2h0OjBweDt3aWR0aDowcHg7YmFja2dyb3VuZDpyZWQ7b3BhY2l0eTowO2ZpbHRlcjpvcGFjaXR5KDEpO1wiXHJcblx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRdXHJcblx0XHRcdFx0fSxcclxuXHRcdFx0XHR7XHJcblx0XHRcdFx0XHR0YWc6ICdsYWJlbCcsXHJcblx0XHRcdFx0XHRpZDogXCJJbXBvcnRXS0J0blwiLFxyXG5cdFx0XHRcdFx0Y2xhc3NOYW1lOiBcImJ1dHRvblwiLFxyXG5cdFx0XHRcdFx0b3RoZXI6IHtzdHlsZTogXCJkaXNwbGF5OmlubGluZTtcIn0sXHJcblx0XHRcdFx0XHRjaGlsZE5vZGVzOltcclxuXHRcdFx0XHRcdFx0e1xyXG5cdFx0XHRcdFx0XHRcdHRhZzonaScsXHJcblx0XHRcdFx0XHRcdFx0Y2xhc3NOYW1lOiBcImljb24tZG93bmxvYWQtYWx0XCJcclxuXHRcdFx0XHRcdFx0fSxcclxuXHRcdFx0XHRcdFx0XCJXS1wiXHJcblx0XHRcdFx0XHRdXHJcblx0XHRcdFx0fVxyXG5cdFx0XHRdXHJcblx0XHR9XVxyXG5cdH07XHJcblx0dmFyIGltcG9ydFdpbmRvdyA9IGJ1aWxkV2luZG93KGltcG9ydFdpbmRvd1N0cnVjdHVyZSk7XHJcblxyXG4gICAgJChcImJvZHlcIikuYXBwZW5kKGltcG9ydFdpbmRvdyk7XHJcbiAgICQoXCIjaW1wb3J0XCIpLmhpZGUoKTtcclxuXHJcblx0dmFyIGNoZWNrQWRkID0gZnVuY3Rpb24oYWRkKSB7XHJcbiAgICAgICAgLy90YWtlIGEgSlNPTiBvYmplY3QgKHBhcnNlZCBmcm9tIGltcG9ydCB3aW5kb3cpIGFuZCBjaGVjayB3aXRoIHN0b3JlZCBpdGVtcyBmb3IgYW55IGR1cGxpY2F0ZXNcclxuICAgICAgICAvLyBSZXR1cm5zIHRydWUgaWYgZWFjaCBpdGVtIGluICdhZGQnIGFycmF5IGlzIHZhbGlkIGFuZFxyXG4gICAgICAgIC8vYXQgbGVhc3Qgb25lIG9mIHRoZW0gYWxyZWFkeSBleGlzdHMgaW4gc3RvcmFnZVxyXG4gICAgICAgIHZhciBpID0gYWRkLmxlbmd0aDtcclxuICAgICAgICBpZihsb2NhbFN0b3JhZ2UuZ2V0SXRlbSgnVXNlci1Wb2NhYicpKSB7ICAgIFxyXG4gICAgICAgICAgICB2YXIgdm9jYWJMaXN0ID0gU3RvcmFnZVV0aWwuZ2V0Vm9jTGlzdCgpO1xyXG4gICAgICAgICAgICB3aGlsZShpLS0pe1xyXG4gICAgICAgICAgICAgICAgaWYgKGlzSXRlbVZhbGlkKGFkZFtpXSkgJiZcclxuICAgICAgICAgICAgICAgICAgICBjaGVja0ZvckR1cGxpY2F0ZXModm9jYWJMaXN0LGFkZFtpXSkpXHJcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfTtcclxuXHJcbiAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInVwbG9hZFwiKSAmJiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInVwbG9hZFwiKS5hZGRFdmVudExpc3RlbmVyKCdjaGFuZ2UnLCBJbXBvcnRVdGlsLmZpbGVVcGxvYWQsIGZhbHNlKTtcclxuXHJcblx0dmFyIHJlZnJlc2hMb2NrcyA9IGZ1bmN0aW9uKCl7XHJcblx0XHR2YXIgdm9jTGlzdCA9IFN0b3JhZ2VVdGlsLmdldFZvY0xpc3QoKS5tYXAoZnVuY3Rpb24odm9jSXRlbSl7XHJcblx0XHRcdGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJ2b2NMaXN0W2ldID0gc2V0TG9ja3Modm9jTGlzdFtpXSk7XCIpO1xyXG5cdFx0XHR2b2NJdGVtID0gc2V0TG9ja3Modm9jSXRlbSk7ICBcclxuXHRcdFx0cmV0dXJuIHZvY0l0ZW07XHJcblx0XHR9LCB0aGlzKTtcclxuXHRcdGNvbnNvbGUuZ3JvdXBFbmQoKTtcclxuXHRcdFN0b3JhZ2VVdGlsLnNldFZvY0xpc3Qodm9jTGlzdCk7XHJcbiAgICB9O1xyXG5cclxuICAgIFxyXG4gICAgJChcIiNJbXBvcnRXS0J0blwiKS5jbGljayhmdW5jdGlvbigpe1xyXG4gICAgICAgIFdhbmlrYW5pVXRpbC5nZXRTZXJ2ZXJSZXNwKEFQSWtleSxcInZvY2FidWxhcnlcIik7XHJcbiAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcIm1heWJlP1wiKTtcclxuICAgIH0pO1xyXG5cclxuICAgICQoXCIjSW1wb3J0SXRlbXNCdG5cIikuY2xpY2soZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIGlmICgkKFwiI2ltcG9ydEFyZWFcIikudmFsKCkubGVuZ3RoICE9PSAwKSB7XHJcbiAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICB2YXIgYWRkID0gSlNPTi5wYXJzZSgkKFwiI2ltcG9ydEFyZWFcIikudmFsKCkudG9Mb3dlckNhc2UoKSk7XHJcbiAgICAgICAgICAgICAgICBhbGVydChKU09OLnN0cmluZ2lmeShhZGQpKTtcclxuICAgICAgICAgICAgICAgIGlmIChjaGVja0FkZChhZGQpKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgJChcIiNpbXBvcnRTdGF0dXNcIikudGV4dChcIk5vIHZhbGlkIGlucHV0IChkdXBsaWNhdGVzPykhXCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICB2YXIgbmV3bGlzdDtcclxuICAgICAgICAgICAgICAgIHZhciBzcnNsaXN0ID0gW107XHJcbiAgICAgICAgICAgICAgICBpZiAobG9jYWxTdG9yYWdlLmdldEl0ZW0oJ1VzZXItVm9jYWInKSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciB2b2NhYkxpc3QgPSBTdG9yYWdlVXRpbC5nZXRWb2NMaXN0KCk7XHJcbiAgICAgICAgICAgICAgICAgICAgc3JzbGlzdCA9IFN0b3JhZ2VVdGlsLmdldFZvY0xpc3QoKTtcclxuICAgICAgICAgICAgICAgICAgICBuZXdsaXN0ID0gdm9jYWJMaXN0LmNvbmNhdChhZGQpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgbmV3bGlzdCA9IGFkZDtcclxuXHJcblxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgdmFyIGkgPSBhZGQubGVuZ3RoO1xyXG4gICAgICAgICAgICAgICAgd2hpbGUoaS0tKXtcclxuICAgICAgICAgICAgICAgICAgICBTdG9yYWdlVXRpbC5zZXRWb2NJdGVtKGFkZFtpXSk7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgJChcIiNpbXBvcnRTdGF0dXNcIikudGV4dChcIkltcG9ydCBzdWNjZXNzZnVsIVwiKTtcclxuXHJcbiAgICAgICAgICAgICAgICAkKFwiI2ltcG9ydEZvcm1cIilbMF0ucmVzZXQoKTtcclxuICAgICAgICAgICAgICAgICQoXCIjaW1wb3J0QXJlYVwiKS50ZXh0KFwiXCIpO1xyXG5cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBjYXRjaCAoZSkge1xyXG4gICAgICAgICAgICAgICAgJChcIiNpbXBvcnRTdGF0dXNcIikudGV4dChcIlBhcnNpbmcgRXJyb3IhXCIpO1xyXG4gICAgICAgICAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhlKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICQoXCIjaW1wb3J0U3RhdHVzXCIpLnRleHQoXCJOb3RoaW5nIHRvIGltcG9ydCA6KCBQbGVhc2UgcGFzdGUgeW91ciBzdHVmZiBmaXJzdFwiKTtcclxuICAgICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAkKFwiI0ltcG9ydENsb3NlQnRuXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcclxuICAgICAgICAkKFwiI2ltcG9ydFwiKS5oaWRlKCk7XHJcbiAgICAgICAgJChcIiNpbXBvcnRGb3JtXCIpWzBdLnJlc2V0KCk7XHJcbiAgICAgICAgJChcIiNpbXBvcnRBcmVhXCIpLnRleHQoXCJcIik7XHJcbiAgICAgICAgJChcIiNpbXBvcnRTdGF0dXNcIikudGV4dCgnUmVhZHkgdG8gaW1wb3J0Li4nKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHZhciBwbGF5QXVkaW8gPSBmdW5jdGlvbigpIHtcclxuICAgICAgICB2YXIga2FuamkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmV2LWthbmppJykuaW5uZXJIVE1MO1xyXG4gICAgICAgIHZhciBrYW5hID0gKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyZXYtc29sdXRpb24nKS5pbm5lckhUTUwuc3BsaXQoL1ss44CBXStcXHMqLykpWzBdO1xyXG5cclxuICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmV2LWF1ZGlvJykuaW5uZXJIVE1MID0gXCJcIjtcclxuICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYXVkaW8tZm9ybScpLmFjdGlvbiA9IFwiXCI7XHJcbiAgICAgICAgLy9kb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnQXVkaW9CdXR0b24nKS5kaXNhYmxlZCA9IHRydWU7XHJcblxyXG4gICAgICAgIGlmKCAha2FuamkubWF0Y2goL1thLXpBLVpdKy9pKSAmJiAha2FuYS5tYXRjaCgvW2EtekEtWl0rL2kpKSB7XHJcblxyXG4gICAgICAgICAgICBrYW5qaSA9IGVuY29kZVVSSUNvbXBvbmVudChrYW5qaSk7XHJcbiAgICAgICAgICAgIGthbmEgPSBlbmNvZGVVUklDb21wb25lbnQoa2FuYSk7XHJcbiAgICAgICAgICAgIHZhciBpO1xyXG5cclxuICAgICAgICAgICAgdmFyIG5ld2thbmppID0gXCJcIjtcclxuICAgICAgICAgICAgZm9yKGkgPSAxOyBpIDwga2FuamkubGVuZ3RoOyBpID0gaSszKSB7XHJcbiAgICAgICAgICAgICAgICBuZXdrYW5qaSA9IG5ld2thbmppLmNvbmNhdChrYW5qaVtpLTFdKTtcclxuICAgICAgICAgICAgICAgIG5ld2thbmppID0gbmV3a2FuamkuY29uY2F0KCcyJyk7XHJcbiAgICAgICAgICAgICAgICBuZXdrYW5qaSA9IG5ld2thbmppLmNvbmNhdCgnNScpO1xyXG4gICAgICAgICAgICAgICAgbmV3a2FuamkgPSBuZXdrYW5qaS5jb25jYXQoa2FuamlbaV0pO1xyXG4gICAgICAgICAgICAgICAgbmV3a2FuamkgPSBuZXdrYW5qaS5jb25jYXQoa2FuamlbaSsxXSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIHZhciBuZXdrYW5hID0gXCJcIjtcclxuICAgICAgICAgICAgZm9yKGkgPSAxOyBpIDwga2FuYS5sZW5ndGg7IGkgPSBpKzMpIHtcclxuICAgICAgICAgICAgICAgIG5ld2thbmEgPSBuZXdrYW5hLmNvbmNhdChrYW5hW2ktMV0pO1xyXG4gICAgICAgICAgICAgICAgbmV3a2FuYSA9IG5ld2thbmEuY29uY2F0KCcyJyk7XHJcbiAgICAgICAgICAgICAgICBuZXdrYW5hID0gbmV3a2FuYS5jb25jYXQoJzUnKTtcclxuICAgICAgICAgICAgICAgIG5ld2thbmEgPSBuZXdrYW5hLmNvbmNhdChrYW5hW2ldKTtcclxuICAgICAgICAgICAgICAgIG5ld2thbmEgPSBuZXdrYW5hLmNvbmNhdChrYW5hW2krMV0pO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICB2YXIgdXJsID0gXCJodHRwOi8vd3d3LmNzc2UubW9uYXNoLmVkdS5hdS9+andiL2F1ZGlvY2suc3dmP3U9a2FuYT1cIiArIG5ld2thbmEgKyBcIiUyNmthbmppPVwiICsgbmV3a2Fuamk7XHJcblxyXG4gICAgICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwiQXVkaW8gVVJMOiBcIiArIHVybCk7XHJcblxyXG4gICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnQXVkaW9CdXR0b24nKS5kaXNhYmxlZCA9IGZhbHNlO1xyXG5cclxuICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Jldi1hdWRpbycpLmlubmVySFRNTCA9IHVybDtcclxuXHJcbiAgICAgICAgfVxyXG5cclxuICAgIH07XHJcblxyXG4gICAgdmFyIG5leHRSZXZpZXcgPSBmdW5jdGlvbihyZXZpZXdMaXN0KSB7XHJcbiAgICAgICAgLy9zZXRzIHVwIHRoZSBuZXh0IGl0ZW0gZm9yIHJldmlld1xyXG4gICAgICAgIC8vdXNlcyBmdW5jdGlvbnM6XHJcbiAgICAgICAgLy8gICAgd2FuYWthbmEuYmluZC91bmJpbmRcclxuXHJcbiAgICAgICAgdmFyIHJuZCA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSpyZXZpZXdMaXN0Lmxlbmd0aCk7XHJcbiAgICAgICAgdmFyIGl0ZW0gPSByZXZpZXdMaXN0W3JuZF07XHJcbiAgICAgICAgc2Vzc2lvblNldCgnV0tTUy1pdGVtJywgSlNPTi5zdHJpbmdpZnkoaXRlbSkpO1xyXG4gICAgICAgIHNlc3Npb25TZXQoJ1dLU1Mtcm5kJywgcm5kKTtcclxuICAgICAgICBpZiAoc2Vzc2lvblN0b3JhZ2UuZ2V0SXRlbSgnVXNlci1TdGF0cycpKXtcclxuICAgICAgICAgICAgJChcIiNSZXZOdW1cIikuaW5uZXJIdG1sID0gc2Vzc2lvbkdldCgnVXNlci1TdGF0cycpLmxlbmd0aDtcclxuICAgICAgICB9XHJcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Jldi1rYW5qaScpLmlubmVySFRNTCA9IGl0ZW0ucHJvbXB0O1xyXG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyZXYtdHlwZScpLmlubmVySFRNTCA9IGl0ZW0udHlwZTtcclxuICAgICAgICB2YXIgdHlwZUJnQ29sb3IgPSAnZ3JleSc7XHJcbiAgICAgICAgaWYgKGl0ZW0udHlwZS50b0xvd2VyQ2FzZSgpID09ICdtZWFuaW5nJyl7XHJcbiAgICAgICAgICAgIHR5cGVCZ0NvbG9yID0gJ2JsdWUnO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoaXRlbS50eXBlLnRvTG93ZXJDYXNlKCkgPT0gJ3JlYWRpbmcnKXtcclxuICAgICAgICAgICAgdHlwZUJnQ29sb3IgPSAnb3JhbmdlJztcclxuICAgICAgICB9IGVsc2UgaWYgKGl0ZW0udHlwZS50b0xvd2VyQ2FzZSgpID09ICdyZXZlcnNlJyl7XHJcbiAgICAgICAgICAgIHR5cGVCZ0NvbG9yID0gJ29yYW5nZSc7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd3a3NzLXR5cGUnKS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IgPSB0eXBlQmdDb2xvcjtcclxuICAgICAgICAkKFwiI3Jldi1zb2x1dGlvblwiKS5yZW1vdmVDbGFzcyhcImluZm9cIik7XHJcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Jldi1zb2x1dGlvbicpLmlubmVySFRNTCA9IGl0ZW0uc29sdXRpb247XHJcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Jldi1pbmRleCcpLmlubmVySFRNTCA9IGl0ZW0uaW5kZXg7XHJcblxyXG4gICAgICAgIC8vaW5pdGlhbGlzZSB0aGUgaW5wdXQgZmllbGRcclxuICAgICAgICAkKFwiI3Jldi1pbnB1dFwiKS5mb2N1cygpO1xyXG4gICAgICAgICQoXCIjcmV2LWlucHV0XCIpLnJlbW92ZUNsYXNzKFwiY2F1dGlvblwiKTtcclxuICAgICAgICAkKFwiI3Jldi1pbnB1dFwiKS5yZW1vdmVDbGFzcyhcImVycm9yXCIpO1xyXG4gICAgICAgICQoXCIjcmV2LWlucHV0XCIpLnJlbW92ZUNsYXNzKFwiY29ycmVjdFwiKTtcclxuICAgICAgICAkKFwiI3Jldi1pbnB1dFwiKS52YWwoXCJcIik7XHJcblxyXG4gICAgICAgIC8vY2hlY2sgZm9yIGFscGhhYmV0IGxldHRlcnMgYW5kIGRlY2lkZSB0byBiaW5kIG9yIHVuYmluZCB3YW5ha2FuYVxyXG4gICAgICAgIGlmIChpdGVtLnNvbHV0aW9uWzBdLm1hdGNoKC9bYS16QS1aXSsvaSkpIHtcclxuICAgICAgICAgICAgd2FuYWthbmEudW5iaW5kKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdyZXYtaW5wdXQnKSk7XHJcbiAgICAgICAgICAgICQoJyNyZXYtaW5wdXQnKS5hdHRyKCdwbGFjZWhvbGRlcicsJ1lvdXIgcmVzcG9uc2UnKTtcclxuICAgICAgICAgICAgJCgnI3Jldi1pbnB1dCcpLmF0dHIoJ2xhbmcnLCdlbicpO1xyXG5cclxuICAgICAgICB9XHJcbiAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgIHdhbmFrYW5hLmJpbmQoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Jldi1pbnB1dCcpKTtcclxuICAgICAgICAgICAgJCgnI3Jldi1pbnB1dCcpLmF0dHIoJ3BsYWNlaG9sZGVyJywn562U44GIJyk7XHJcbiAgICAgICAgICAgICQoJyNyZXYtaW5wdXQnKS5hdHRyKCdsYW5nJywnamEnKTtcclxuXHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBwbGF5QXVkaW8oKTtcclxuICAgIH07XHJcblxyXG5cdC8vZ2xvYmFsIHRvIGtlZXAgdHJhY2sgb2Ygd2hlbiBhIHJldmlldyBpcyBpbiBzZXNzaW9uLlxyXG4gICAgdmFyIHJldmlld0FjdGl2ZSA9IGZhbHNlO1xyXG5cclxuICAgIHZhciBzdGFydFJldmlldyA9IGZ1bmN0aW9uKCkge1xyXG4gICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJzdGFydFJldmlldygpXCIpO1xyXG4gICAgICAgIHN1Ym1pdCA9IHRydWU7XHJcbiAgICAgICAgcmV2aWV3QWN0aXZlID0gdHJ1ZTtcclxuICAgICAgICAvL2dldCB0aGUgcmV2aWV3ICdsaXN0JyBmcm9tIHNlc3Npb24gc3RvcmFnZSwgbGluZSB1cCB0aGUgZmlyc3QgaXRlbSBpbiBxdWV1ZVxyXG4gICAgICAgIHZhciByZXZpZXdMaXN0ID0gc2Vzc2lvbkdldCgnVXNlci1SZXZpZXcnKXx8W107XHJcbiAgICAgICAgbmV4dFJldmlldyhyZXZpZXdMaXN0KTtcclxuICAgIH07XHJcblxyXG4gICAgLyoqIFJldmlldyBJdGVtc1xyXG5cdCovXHJcbiAgICB3aW5kb3cuV0tTU19yZXZpZXcgPSBmdW5jdGlvbiAoKSB7XHJcblxyXG4gICAgICAgIC8vaXMgdGhlcmUgYSBzZXNzaW9uIHdhaXRpbmcgaW4gc3RvcmFnZT9cclxuICAgICAgICBpZihzZXNzaW9uU3RvcmFnZS5nZXRJdGVtKCdVc2VyLVJldmlldycpKSB7XHJcblxyXG4gICAgICAgICAgICAvL3Nob3cgdGhlIHNlbGZzdHVkeSB3aW5kb3dcclxuICAgICAgICAgICAgJChcIiNzZWxmc3R1ZHlcIikuc2hvdygpO1xyXG5cclxuICAgICAgICAgICAgLy9oaWRlIG90aGVyIHdpbmRvd3NcclxuICAgICAgICAgICAgJChcIiNhZGRcIikuaGlkZSgpO1xyXG4gICAgICAgICAgICAkKFwiI2V4cG9ydFwiKS5oaWRlKCk7XHJcbiAgICAgICAgICAgICQoXCIjZWRpdFwiKS5oaWRlKCk7XHJcbiAgICAgICAgICAgICQoXCIjaW1wb3J0XCIpLmhpZGUoKTtcclxuXHJcbiAgICAgICAgICAgIHN0YXJ0UmV2aWV3KCk7XHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICAkKFwiYm9keVwiKS5hcHBlbmQoJyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXFxyXG48ZGl2IGlkPVwic2VsZnN0dWR5XCIgY2xhc3M9XCJXS1NTXCI+XFxcclxuPGJ1dHRvbiBpZD1cIlNlbGZzdHVkeUNsb3NlQnRuXCIgY2xhc3M9XCJ3a3NzLWNsb3NlXCIgdHlwZT1cImJ1dHRvblwiPjxpIGNsYXNzPVwiaWNvbi1yZW1vdmVcIj48L2k+PC9idXR0b24+XFxcclxuPGgxPlJldmlldzxzcGFuIGlkPVwiUmV2TnVtXCI+PC9zcGFuPjwvaDE+XFxcclxuPGRpdiBpZD1cIndrc3Mta2FuamlcIj5cXFxyXG48c3BhbiBpZD1cInJldi1rYW5qaVwiPjwvc3Bhbj5cXFxyXG48L2Rpdj48ZGl2IGlkPVwid2tzcy10eXBlXCI+XFxcclxuPHNwYW4gaWQ9XCJyZXYtdHlwZVwiPjwvc3Bhbj48YnIgLz5cXFxyXG48L2Rpdj48ZGl2IGlkPVwid2tzcy1zb2x1dGlvblwiPlxcXHJcbjxzcGFuIGlkPVwicmV2LXNvbHV0aW9uXCI+PC9zcGFuPlxcXHJcbjwvZGl2PjxkaXYgaWQ9XCJ3a3NzLWlucHV0XCI+XFxcclxuPGlucHV0IHR5cGU9XCJ0ZXh0XCIgaWQ9XCJyZXYtaW5wdXRcIiBzaXplPVwiNDBcIiBwbGFjZWhvbGRlcj1cIlwiPlxcXHJcbjwvZGl2PjxzcGFuIGlkPVwicmV2LWluZGV4XCIgc3R5bGU9XCJkaXNwbGF5OiBibG9jaztcIj48L3NwYW4+XFxcclxuXFxcclxuPGZvcm0gaWQ9XCJhdWRpby1mb3JtXCI+XFxcclxuPGxhYmVsIGlkPVwiQXVkaW9CdXR0b25cIiBjbGFzcz1cImJ1dHRvblwiPlBsYXkgYXVkaW88L2xhYmVsPlxcXHJcbjxsYWJlbCBpZD1cIldyYXBVcEJ0blwiICAgY2xhc3M9XCJidXR0b25cIj5XcmFwIFVwPC9sYWJlbD5cXFxyXG48L2Zvcm0+XFxcclxuPGRpdiBpZD1cInJldi1hdWRpb1wiIHN0eWxlPVwiZGlzcGxheTpub25lO1wiPjwvZGl2PlxcXHJcbjwvZGl2PicpO1xyXG4gICAgJChcIiNzZWxmc3R1ZHlcIikuaGlkZSgpO1xyXG5cclxuICAgICQoXCIjU2VsZnN0dWR5Q2xvc2VCdG5cIikuY2xpY2soZnVuY3Rpb24gKCkge1xyXG4gICAgICAgICQoXCIjc2VsZnN0dWR5XCIpLmhpZGUoKTtcclxuICAgICAgICAkKFwiI3Jldi1pbnB1dFwiKS52YWwoXCJcIik7XHJcbiAgICAgICAgcmV2aWV3QWN0aXZlID0gZmFsc2U7XHJcbiAgICB9KTtcclxuXHJcbiAgICB2YXIgYmluYXJ5U2VhcmNoID0gZnVuY3Rpb24odmFsdWVzLCB0YXJnZXQsIHN0YXJ0LCBlbmQpIHtcclxuICAgICAgICAvL2RlYnVnZ2luZyYmY29uc29sZS5sb2coXCJiaW5hcnlTZWFyY2godmFsdWVzOiAsdGFyZ2V0OiAsIHN0YXJ0OiBcIitzdGFydCtcIiwgZW5kOiBcIitlbmQrXCIpXCIpO1xyXG5cclxuICAgICAgICBpZiAoc3RhcnQgPiBlbmQpIHtcclxuICAgICAgICAgICAgLy9zdGFydCBoYXMgaGlnaGVyIHZhbHVlIHRoYW4gdGFyZ2V0LCBlbmQgaGFzIGxvd2VyIHZhbHVlXHJcbiAgICAgICAgICAgIC8vaXRlbSBiZWxvbmdzIGJldHdlZW5cclxuICAgICAgICAgICAgLy8gbmVlZCB0byByZXR1cm4gJ3N0YXJ0JyB3aXRoIGEgZmxhZyB0aGF0IGl0IGhhc24ndCBiZWVuIGZvdW5kXHJcbiAgICAgICAgICAgIC8vaW52ZXJ0IHNpZ24gOilcclxuICAgICAgICAgICAgcmV0dXJuIC0oc3RhcnQpO1xyXG5cclxuXHJcbiAgICAgICAgICAgIC8vZm9yIHRlc3RpbmcgdHJ1dGhzXHJcbiAgICAgICAgICAgIC8vICAgIHJldHVybiBTdHJpbmcoZW5kKStcIiA8IFwiK2l0ZW0uaW5kZXgrXCIgPCBcIitTdHJpbmcoc3RhcnQpO1xyXG5cclxuICAgICAgICB9IC8vZG9lcyBub3QgZXhpc3RcclxuXHJcblxyXG4gICAgICAgIHZhciBtaWRkbGUgPSBNYXRoLmZsb29yKChzdGFydCArIGVuZCkgLyAyKTtcclxuICAgICAgICB2YXIgdmFsdWUgPSB2YWx1ZXNbbWlkZGxlXTtcclxuICAgICAgICAvKmRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJzdGFydC5pbmRleDogXCIrdmFsdWVzW3N0YXJ0XS5pbmRleCk7XHJcbiAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcIm1pZGRsZS5pbmRleDogXCIrdmFsdWVzW21pZGRsZV0uaW5kZXgpO1xyXG4gICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJlbmQuaW5kZXg6IFwiK3ZhbHVlc1tlbmRdLmluZGV4KTtcclxuICAgICAqL1xyXG4gICAgICAgIGlmIChOdW1iZXIodmFsdWUuaW5kZXgpID4gTnVtYmVyKHRhcmdldC5pbmRleCkpIHtcclxuXHRcdFx0cmV0dXJuIGJpbmFyeVNlYXJjaCh2YWx1ZXMsIHRhcmdldCwgc3RhcnQsIG1pZGRsZS0xKTtcclxuXHRcdH1cclxuICAgICAgICBpZiAoTnVtYmVyKHZhbHVlLmluZGV4KSA8IE51bWJlcih0YXJnZXQuaW5kZXgpKSB7XHJcblx0XHRcdHJldHVybiBiaW5hcnlTZWFyY2godmFsdWVzLCB0YXJnZXQsIG1pZGRsZSsxLCBlbmQpO1xyXG5cdFx0fVxyXG4gICAgICAgIHJldHVybiBtaWRkbGU7IC8vZm91bmQhXHJcbiAgICB9O1xyXG5cclxuXHR2YXIgZmluZEluZGV4ID0gZnVuY3Rpb24odmFsdWVzLCB0YXJnZXQpIHtcclxuICAgICAgICByZXR1cm4gYmluYXJ5U2VhcmNoKHZhbHVlcywgdGFyZ2V0LCAwLCB2YWx1ZXMubGVuZ3RoIC0gMSk7XHJcblx0fTtcclxuXHJcbiAgICAkKFwiI1dyYXBVcEJ0blwiKS5jbGljayhmdW5jdGlvbigpIHtcclxuICAgICAgICB2YXIgc2Vzc2lvbkxpc3QgPSBzZXNzaW9uR2V0KCdVc2VyLVJldmlldycpfHxbXTtcclxuICAgICAgICB2YXIgc3RhdHNMaXN0ID0gc2Vzc2lvbkdldCgnVXNlci1TdGF0cycpfHxbXTtcclxuICAgICAgICAvL2lmIGFuIGluZGV4IGluIHNlc3Npb25MaXN0IG1hdGNoZXMgb25lIGluIHN0YXRzTGlzdCwgZG9uJ3QgZGVsZXRlXHJcbiAgICAgICAgdmFyIHNlc3Npb25JID0gc2Vzc2lvbkxpc3QubGVuZ3RoO1xyXG4gICAgICAgIHZhciBpdGVtID0gc2Vzc2lvbkdldCgnV0tTUy1pdGVtJyl8fFtdO1xyXG4gICAgICAgIHZhciBhcnIyID0gW107XHJcbiAgICAgICAgLy9mb3IgZXZlcnkgaXRlbSBpbiBzZXNzaW9uTGlzdCwgbG9vayBmb3IgaW5kZXggaW4gc3RhdHNMaXN0LFxyXG4gICAgICAgIC8vaWYgbm90IHRoZXJlICgtMSkgZGVsZXRlIGl0ZW0gZnJvbSBzZXNzaW9uTGlzdFxyXG4gICAgICAgIHdoaWxlIChzZXNzaW9uSS0tKXtcclxuICAgICAgICAgICAgdmFyIGluZGV4ID0gZmluZEluZGV4KHN0YXRzTGlzdCxzZXNzaW9uTGlzdFtzZXNzaW9uSV0pO1xyXG4gICAgICAgICAgICBpZiAoKE1hdGguc2lnbigxL2luZGV4KSAhPT0gLTEpfHwoc2Vzc2lvbkxpc3Rbc2Vzc2lvbkldLmluZGV4ID09IGl0ZW0uaW5kZXgpKXtcclxuXHJcbiAgICAgICAgICAgICAgICBhcnIyLnB1c2goc2Vzc2lvbkxpc3Rbc2Vzc2lvbkldKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKGFycjIpO1xyXG4gICAgICAgIHNlc3Npb25TZXQoJ1VzZXItUmV2aWV3JywgSlNPTi5zdHJpbmdpZnkoYXJyMikpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLyoqIFNhdmUgdG8gbGlzdCBiYXNlZCBvbiAuaW5kZXggcHJvcGVydHlcclxuXHQqIEBwYXJhbSB7QXJyYXkuPHRhc2s+fSBlTGlzdFxyXG5cdCogQHBhcmFtIHt0YXNrfSBlSXRlbVxyXG5cdCovXHJcbiAgICB2YXIgc2F2ZVRvU29ydGVkTGlzdCA9IGZ1bmN0aW9uKGVMaXN0LGVJdGVtKXtcclxuICAgICAgICB2YXIgZ2V0ID0gZmluZEluZGV4KGVMaXN0LGVJdGVtKTtcclxuICAgICAgICBpZiAoTWF0aC5zaWduKDEvZ2V0KSA9PT0gLTEpe1xyXG4gICAgICAgICAgICBlTGlzdC5zcGxpY2UoLWdldCwwLGVJdGVtKTtcclxuICAgICAgICB9XHJcblx0XHRyZXR1cm4gZUxpc3Q7XHJcbiAgICB9O1xyXG5cclxuICAgIC8vLS0tLS0tLVxyXG4gICAgdmFyIG9wZW5Jbk5ld1RhYiA9IGZ1bmN0aW9uKHVybCkge1xyXG4gICAgICAgIHZhciB3aW49d2luZG93Lm9wZW4odXJsLCAnX2JsYW5rJyk7XHJcbiAgICAgICAgd2luLmZvY3VzKCk7XHJcbiAgICB9O1xyXG5cclxuICAgICQoXCIjQXVkaW9CdXR0b25cIikuY2xpY2soZnVuY3Rpb24gKCkge1xyXG4gICAgICAgIG9wZW5Jbk5ld1RhYihkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmV2LWF1ZGlvJykuaW5uZXJIVE1MKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHZhciBSZXZfSXRlbSA9IGZ1bmN0aW9uKHByb21wdCwga2FuamksIHR5cGUsIHNvbHV0aW9uLCBpbmRleCl7XHJcbiAgICAgICAgdGhpcy5wcm9tcHQgPSBwcm9tcHQ7XHJcbiAgICAgICAgdGhpcy5rYW5qaSA9IGthbmppO1xyXG4gICAgICAgIHRoaXMudHlwZSA9IHR5cGU7XHJcbiAgICAgICAgdGhpcy5zb2x1dGlvbiA9IHNvbHV0aW9uO1xyXG4gICAgICAgIHRoaXMuaW5kZXggPSBpbmRleDtcclxuICAgIH07XHJcblxyXG4gICAgdmFyIHVwZGF0ZVNSUyA9IGZ1bmN0aW9uKHN0YXRzLCB2b2NsaXN0KSB7XHJcbiAgICAgICAgdmFyIG5vdyA9IERhdGUubm93KCk7XHJcbiAgICAgICAgaWYgKHZvY2xpc3Rbc3RhdHMuaW5kZXhdLmR1ZSA8IG5vdyl7IC8vZG91YmxlIGNoZWNrIHRoYXQgdGhlIGl0ZW0gd2FzIHJlYWxseSB1cCBmb3IgcmV2aWV3LlxyXG4gICAgICAgICAgICBpZighc3RhdHMubnVtV3JvbmcgJiYgdm9jbGlzdFtzdGF0cy5pbmRleF0ubGV2ZWwgPCA5KSB7Ly9hbGwgY29ycmVjdCAobm9uZSB3cm9uZylcclxuICAgICAgICAgICAgICAgIHZvY2xpc3Rbc3RhdHMuaW5kZXhdLmxldmVsKys7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgZWxzZSB7XHJcbiAgICAgICAgICAgICAgICBzdGF0cy5udW1Xcm9uZyA9IHt9O1xyXG4gICAgICAgICAgICAgICAgLy9BZGFwdGVkIGZyb20gV2FuaUthbmkncyBzcnMgdG8gYXV0aGVudGljYWxseSBtaW1pYyBsZXZlbCBkb3duc1xyXG4gICAgICAgICAgICAgICAgdmFyIG8gPSAoc3RhdHMubnVtV3JvbmcuTWVhbmluZ3x8MCkrKHN0YXRzLm51bVdyb25nLlJlYWRpbmd8fDApKyhzdGF0cy5udW1Xcm9uZy5SZXZlcnNlfHwwKTtcclxuICAgICAgICAgICAgICAgIHZhciB0ID0gdm9jbGlzdFtzdGF0cy5pbmRleF0ubGV2ZWw7XHJcbiAgICAgICAgICAgICAgICB2YXIgcj10Pj01PzIqTWF0aC5yb3VuZChvLzIpOjEqTWF0aC5yb3VuZChvLzIpO1xyXG4gICAgICAgICAgICAgICAgdmFyIG49dC1yPDE/MTp0LXI7XHJcblxyXG4gICAgICAgICAgICAgICAgdm9jbGlzdFtzdGF0cy5pbmRleF0ubGV2ZWwgPSBuOy8vZG9uJ3Qgc3RheSBvbiAnc3RhcnRlZCdcclxuXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgdm9jbGlzdFtzdGF0cy5pbmRleF0uZGF0ZSA9IG5vdztcclxuICAgICAgICAgICAgdm9jbGlzdFtzdGF0cy5pbmRleF0uZHVlID0gbm93ICsgc3JzT2JqZWN0W3ZvY2xpc3Rbc3RhdHMuaW5kZXhdLmxldmVsXS5kdXJhdGlvbjtcclxuICAgICAgICAgICAgY29uc29sZS5sb2coXCJOZXh0IHJldmlldyBpbiBcIittczJzdHIoc3JzT2JqZWN0W3ZvY2xpc3Rbc3RhdHMuaW5kZXhdLmxldmVsXS5kdXJhdGlvbikpO1xyXG5cclxuICAgICAgICAgICAgcmV0dXJuIHZvY2xpc3Q7XHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB2YXIgc2hvd1Jlc3VsdHMgPSBmdW5jdGlvbigpIHtcclxuXHJcbiAgICAgICAgdmFyIHN0YXRzTGlzdCA9IHNlc3Npb25HZXQoJ1VzZXItU3RhdHMnKXx8W107XHJcbiAgICAgICAgc2Vzc2lvblN0b3JhZ2UuY2xlYXIoKTtcclxuXHJcbiAgICAgICAgY29uc29sZS5sb2coXCJzdGF0c2xpc3RcIiwgc3RhdHNMaXN0KTtcclxuICAgICAgICB2YXIgdm9jbGlzdCA9IFN0b3JhZ2VVdGlsLmdldFZvY0xpc3QoKTtcclxuICAgICAgICBcclxuXHRcdHN0YXRzTGlzdC5mb3JFYWNoKGZ1bmN0aW9uKHN0YXRzLCBpLCBzdGF0c0xpc3Qpe1xyXG4gICAgICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwic3RhdHNcIixzdGF0cyk7XHJcbiAgICAgICAgICAgIHZhciBhbHRUZXh0ID0gdm9jbGlzdFtzdGF0cy5pbmRleF0ubGV2ZWw7Ly8rc3RhdHMudHlwZTtcclxuXHJcbiAgICAgICAgICAgIGlmIChzdGF0cy5udW1Xcm9uZykge1xyXG4gICAgICAgICAgICAgICAgaWYgKHN0YXRzLm51bVdyb25nLk1lYW5pbmcpXHJcbiAgICAgICAgICAgICAgICAgICAgYWx0VGV4dCA9IGFsdFRleHQgKyBcIiBNZWFuaW5nIFdyb25nIHhcIitzdGF0cy5udW1Xcm9uZy5NZWFuaW5nICtcIlxcblwiO1xyXG4gICAgICAgICAgICAgICAgaWYgKHN0YXRzLm51bVdyb25nLlJlYWRpbmcpXHJcbiAgICAgICAgICAgICAgICAgICAgYWx0VGV4dCA9IGFsdFRleHQgKyBcIiBSZWFkaW5nIFdyb25nIHhcIitzdGF0cy5udW1Xcm9uZy5SZWFkaW5nICtcIlxcblwiO1xyXG4gICAgICAgICAgICAgICAgaWYgKHN0YXRzLm51bVdyb25nLlJldmVyc2UpXHJcbiAgICAgICAgICAgICAgICAgICAgYWx0VGV4dCA9IGFsdFRleHQgKyBcIiBSZXZlcnNlIFdyb25nIHhcIitzdGF0cy5udW1Xcm9uZy5SZXZlcnNlICtcIlxcblwiO1xyXG5cdFx0XHR9XHJcblx0XHRcdGlmIChzdGF0cy5udW1Db3JyZWN0KXtcclxuXHRcdFx0XHRpZiAoc3RhdHMubnVtQ29ycmVjdC5NZWFuaW5nKVxyXG5cdFx0XHRcdFx0YWx0VGV4dCA9IGFsdFRleHQgKyBcIiBNZWFuaW5nIENvcnJlY3QgeFwiK3N0YXRzLm51bUNvcnJlY3QuTWVhbmluZyArXCJcXG5cIjtcclxuXHRcdFx0XHRpZiAoc3RhdHMubnVtQ29ycmVjdC5SZWFkaW5nKVxyXG5cdFx0XHRcdFx0YWx0VGV4dCA9IGFsdFRleHQgKyBcIiBSZWFkaW5nIENvcnJlY3QgeFwiK3N0YXRzLm51bUNvcnJlY3QuUmVhZGluZyArXCJcXG5cIjtcclxuXHRcdFx0XHRpZiAoc3RhdHMubnVtQ29ycmVjdC5SZXZlcnNlKVxyXG5cdFx0XHRcdFx0YWx0VGV4dCA9IGFsdFRleHQgKyBcIiBSZXZlcnNlIENvcnJlY3QgeFwiK3N0YXRzLm51bUNvcnJlY3QuUmV2ZXJzZSArXCJcXG5cIjtcclxuXHRcdFx0fVxyXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhzdGF0cyk7XHJcblxyXG5cdFx0XHQvL1RPRE8gc29ydCBpbnRvIGFwcHJlbnRpY2UsIGd1cnUsIGV0Y1xyXG5cdFx0XHRkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcInN0YXRzLWFcIikuaW5uZXJIVE1MICs9XHJcblx0XHRcdFx0XCI8c3BhbiBjbGFzcz1cIiArXHJcblx0XHRcdFx0KHN0YXRzLm51bVdyb25nPyBcIlxcXCJyZXYtZXJyb3JcXFwiXCI6XCJcXFwicmV2LWNvcnJlY3RcXFwiXCIpICtcclxuXHRcdFx0XHRcIiB0aXRsZT0nXCIrYWx0VGV4dCtcIic+XCIgKyBzdGF0cy5rYW5qaSArIFwiPC9zcGFuPlwiO1xyXG5cdFx0XHRcclxuXHRcdFx0Ly9tYXAgd2l0aCBzaWRlIGVmZmVjdHM/XHJcbiAgICAgICAgICAgIHN0YXRzTGlzdFtpXSA9IHVwZGF0ZVNSUyhzdGF0cywgdm9jbGlzdCk7XHJcblxyXG4gICAgICAgIH0sIHRoaXMpO1xyXG4gICAgICAgIHNlc3Npb25TZXQoXCJVc2VyLVN0YXRzXCIsc3RhdHNMaXN0KTtcclxuICAgICAgICBsb2NhbFNldChcIlVzZXItVm9jYWJcIiwgdm9jbGlzdCk7XHJcbiAgICB9O1xyXG5cclxuICAgICQoXCJib2R5XCIpLmFwcGVuZCgnICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxcXHJcbjxkaXYgaWQ9XCJyZXN1bHR3aW5kb3dcIiBjbGFzcz1cIldLU1NcIj4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcXFxyXG48YnV0dG9uIGlkPVwiUmV2aWV3cmVzdWx0c0Nsb3NlQnRuXCIgY2xhc3M9XCJ3a3NzLWNsb3NlXCIgdHlwZT1cImJ1dHRvblwiPjxpIGNsYXNzPVwiaWNvbi1yZW1vdmVcIj48L2k+PC9idXR0b24+XFxcclxuPGgxPlJldmlldyBSZXN1bHRzPC9oMT5cXFxyXG48aDI+QWxsPC9oMj5cXFxyXG48ZGl2IGlkPVwic3RhdHMtYVwiPjwvZGl2PlxcXHJcbjwvZGl2PicpO1xyXG5cclxuICAgICQoXCIjcmVzdWx0d2luZG93XCIpLmhpZGUoKTtcclxuXHJcbiAgICAkKFwiI1Jldmlld3Jlc3VsdHNDbG9zZUJ0blwiKS5jbGljayhmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgJChcIiNyZXN1bHR3aW5kb3dcIikuaGlkZSgpO1xyXG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwic3RhdHMtYVwiKS5pbm5lckhUTUwgPSBcIlwiO1xyXG4gICAgfSk7XHJcblxyXG5cdHZhciBtYXJrQW5zd2VyID0gZnVuY3Rpb24oaXRlbSkge1xyXG4gICAgICAgIC8vZXZhbHVhdGUgJ2l0ZW0nIGFnYWluc3QgdGhlIHF1ZXN0aW9uLlxyXG4gICAgICAgIC8vIG1hdGNoIGJ5IGluZGV4XHJcbiAgICAgICAgLy8gZ2V0IHR5cGUgb2YgcXVlc3Rpb25cclxuICAgICAgICAvLyBkZXRlcm1pbmUgaWYgcmlnaHQgb3Igd3JvbmcgYW5kIHJldHVybiByZXN1bHQgYXBwcm9wcmlhdGVseVxyXG5cclxuICAgICAgICAvL2dldCB0aGUgcXVlc3Rpb25cclxuICAgICAgICAvL3ZhciBwcm9tcHQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmV2LWthbmppJykuaW5uZXJIVE1MLnRyaW0oKTtcclxuICAgICAgICAvL2dldCB0aGUgYW5zd2VyXHJcbiAgICAgICAgdmFyIGFuc3dlciA9ICQoXCIjcmV2LWlucHV0XCIpLnZhbCgpLnRvTG93ZXJDYXNlKCk7XHJcbiAgICAgICAgLy9nZXQgdGhlIGluZGV4XHJcbiAgICAgICAgdmFyIGluZGV4ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Jldi1pbmRleCcpLmlubmVySFRNTC50cmltKCk7XHJcbiAgICAgICAgLy9nZXQgdGhlIHF1ZXN0aW9uIHR5cGVcclxuICAgICAgICB2YXIgdHlwZSAgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmV2LXR5cGUnKS5pbm5lckhUTUwudHJpbSgpO1xyXG5cclxuICAgICAgICAvL3ZhciB2b2NhYiA9IGxvY2FsR2V0KFwiVXNlci1Wb2NhYlwiKTtcclxuXHJcbiAgICAgICAgLy9nZXQgdGhlIGl0ZW0gaWYgaXQgaXMgaW4gdGhlIGN1cnJlbnQgc2Vzc2lvblxyXG4gICAgICAgIHZhciBzdG9yZWRJdGVtID0gc2Vzc2lvbkdldChpdGVtLmluZGV4KTtcclxuICAgICAgICBpZiAoc3RvcmVkSXRlbSl7XHJcblxyXG4gICAgICAgICAgICBpdGVtLm51bUNvcnJlY3QgPSBzdG9yZWRJdGVtLm51bUNvcnJlY3Q7XHJcbiAgICAgICAgICAgIGl0ZW0ubnVtV3JvbmcgPSBzdG9yZWRJdGVtLm51bVdyb25nO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKGluZGV4ID09IGl0ZW0uaW5kZXgpey8vLS0tLS0tLS0tLS0tLVxyXG4gICAgICAgICAgICBpZiAoaW5wdXRDb3JyZWN0KCkpe1xyXG4gICAgICAgICAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhhbnN3ZXIrXCIvXCIraXRlbS5zb2x1dGlvblswXSk7XHJcbiAgICAgICAgICAgICAgICBpZiAoIWl0ZW0ubnVtQ29ycmVjdCl7XHJcbiAgICAgICAgICAgICAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcImluaXRpYWxpc2luZyBudW1Db3JyZWN0XCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIGl0ZW0ubnVtQ29ycmVjdD17fTtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwiQ29ycmVjdDogXCIrIHR5cGUpO1xyXG4gICAgICAgICAgICAgICAgaWYgKHR5cGUgPT0gXCJNZWFuaW5nXCIpe1xyXG4gICAgICAgICAgICAgICAgICAgIGlmICghaXRlbS5udW1Db3JyZWN0Lk1lYW5pbmcpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW0ubnVtQ29ycmVjdC5NZWFuaW5nID0gMDtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgaXRlbS5udW1Db3JyZWN0Lk1lYW5pbmcrKztcclxuXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICBpZiAodHlwZSA9PSBcIlJlYWRpbmdcIil7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFpdGVtLm51bUNvcnJlY3QuUmVhZGluZylcclxuICAgICAgICAgICAgICAgICAgICAgICAgaXRlbS5udW1Db3JyZWN0LlJlYWRpbmcgPSAwO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICBpdGVtLm51bUNvcnJlY3QuUmVhZGluZysrO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIGlmICh0eXBlID09IFwiUmV2ZXJzZVwiKXtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoIWl0ZW0ubnVtQ29ycmVjdC5SZXZlcnNlKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpdGVtLm51bUNvcnJlY3QuUmV2ZXJzZSA9IDA7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIGl0ZW0ubnVtQ29ycmVjdC5SZXZlcnNlKys7XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICB9ZWxzZXtcclxuICAgICAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coYW5zd2VyK1wiIT1cIitpdGVtLnNvbHV0aW9uKTtcclxuICAgICAgICAgICAgICAgIGlmICghaXRlbS5udW1Xcm9uZyl7XHJcbiAgICAgICAgICAgICAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcImluaXRpYWxpc2luZyBudW1Db3JyZWN0XCIpO1xyXG4gICAgICAgICAgICAgICAgICAgIGl0ZW0ubnVtV3Jvbmc9e307XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcIldyb25nOiBcIisgdHlwZSk7XHJcbiAgICAgICAgICAgICAgICBpZiAodHlwZSA9PSBcIk1lYW5pbmdcIil7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFpdGVtLm51bVdyb25nLk1lYW5pbmcpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW0ubnVtV3JvbmcuTWVhbmluZyA9IDA7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIGl0ZW0ubnVtV3JvbmcuTWVhbmluZysrO1xyXG5cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIGlmICh0eXBlID09IFwiUmVhZGluZ1wiKXtcclxuICAgICAgICAgICAgICAgICAgICBpZiAoIWl0ZW0ubnVtV3JvbmcuUmVhZGluZylcclxuICAgICAgICAgICAgICAgICAgICAgICAgaXRlbS5udW1Xcm9uZy5SZWFkaW5nID0gMDtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgaXRlbS5udW1Xcm9uZy5SZWFkaW5nKys7XHJcblxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgaWYgKHR5cGUgPT0gXCJSZXZlcnNlXCIpe1xyXG4gICAgICAgICAgICAgICAgICAgIGlmICghaXRlbS5udW1Xcm9uZy5SZXZlcnNlKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpdGVtLm51bVdyb25nLlJldmVyc2UgPSAwO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICBpdGVtLm51bVdyb25nLlJldmVyc2UrKztcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHRcdGVsc2Uge1xyXG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRXJyb3I6IGluZGV4ZXMgZG9uJ3QgbWF0Y2hcIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBpdGVtO1xyXG4gICAgfTtcclxuXHJcblx0XHJcbiAgICAvL2pxdWVyeSBrZXl1cCBldmVudFxyXG4gICAgJChcIiNyZXYtaW5wdXRcIikua2V5dXAoUmV2aWV3VXRpbC5zdWJtaXRSZXNwb25zZSk7XHJcblxyXG5cclxuICAgIC8qKiBBZGRzIHRoZSBCdXR0b25cclxuXHQqL1xyXG4gICAgdmFyIGFkZFVzZXJWb2NhYkJ1dHRvbiA9IGZ1bmN0aW9uKCkge1xyXG4gICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJhZGRVc2VyVm9jYWJCdXR0b24oKVwiKTtcclxuICAgICAgICAvL0Z1bmN0aW9ucyAoaW5kaXJlY3QpXHJcbiAgICAgICAgLy8gICAgV0tTU19hZGQoKVxyXG4gICAgICAgIC8vICAgIFdLU1NfZWRpdCgpXHJcbiAgICAgICAgLy8gICAgV0tTU19leHBvcnQoKVxyXG4gICAgICAgIC8vICAgIFdLU1NfaW1wb3J0KClcclxuICAgICAgICAvLyAgICBXS1NTX2xvY2soKVxyXG4gICAgICAgIC8vICAgIFdLU1NfcmV2aWV3KClcclxuXHJcbiAgICAgICAgdmFyIG5hdiA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUoJ25hdicpO1xyXG4gICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJnZW5lcmF0aW5nIHJldmlldyBsaXN0IGJlY2F1c2U6IGluaXRpYWxpc2luZyBzY3JpcHQgYW5kIHBvcHVsYXRpbmcgcmV2aWV3c1wiKTtcclxuXHJcblxyXG4gICAgICAgIGlmIChuYXYmJm5hdi5sZW5ndGg+Mikge1xyXG4gICAgICAgICAgICBuYXZbMl0uaW5uZXJIVE1MID0gbmF2WzJdLmlubmVySFRNTCArIFwiXFxuXFxcclxuPGxpIGNsYXNzPVxcXCJkcm9wZG93biBjdXN0b21cXFwiPlxcblxcXHJcbjxhIGNsYXNzPVxcXCJkcm9wZG93bi10b2dnbGUgY3VzdG9tXFxcIiBkYXRhLXRvZ2dsZT1cXFwiZHJvcGRvd25cXFwiIGhyZWY9XFxcIiNcXFwiIG9uY2xpY2s9XFxcImdlbmVyYXRlUmV2aWV3TGlzdCgpO1xcXCI+XFxuXFxcclxuPHNwYW4gbGFuZz1cXFwiamFcXFwiPuiHque/kjwvc3Bhbj5cXG5cXFxyXG5TZWxmLVN0dWR5IDxpIGNsYXNzPVxcXCJpY29uLWNoZXZyb24tZG93blxcXCI+PC9pPlxcblxcXHJcbjwvYT5cXG5cXFxyXG48dWwgY2xhc3M9XFxcImRyb3Bkb3duLW1lbnVcXFwiIGlkPVxcXCJXS1NTX2Ryb3Bkb3duXFxcIj5cXG5cXFxyXG48bGkgY2xhc3M9XFxcIm5hdi1oZWFkZXJcXFwiPkN1c3RvbWl6ZTwvbGk+XFxuXFxcclxuPGxpPjxhIGlkPVxcXCJjbGlja1xcXCIgaHJlZj1cXFwiI1xcXCIgb25jbGljaz1cXFwiV0tTU19hZGQoKTtcXFwiPkFkZDwvYT48L2xpPlxcblxcXHJcbjxsaT48YSBocmVmPVxcXCIjXFxcIiBvbmNsaWNrPVxcXCJXS1NTX2VkaXQoKTtcXFwiPkVkaXQ8L2E+PC9saT5cXG5cXFxyXG48bGk+PGEgaHJlZj1cXFwiI1xcXCIgb25jbGljaz1cXFwiV0tTU19leHBvcnQoKTtcXFwiPkV4cG9ydDwvYT48L2xpPlxcblxcXHJcbjxsaT48YSBocmVmPVxcXCIjXFxcIiBvbmNsaWNrPVxcXCJXS1NTX2ltcG9ydCgpO1xcXCI+SW1wb3J0PC9hPjwvbGk+XFxuXFxcclxuPCEtLS8vICAgPGxpPjxhIGhyZWY9XFxcIiNcXFwiIG9uY2xpY2s9XFxcIldLU1NfbG9jaygpO1xcXCI+U2VydmVyIFNldHRpbmdzPC9hPjwvbGk+Ly8tLT5cXG5cXFxyXG48bGkgY2xhc3M9XFxcIm5hdi1oZWFkZXJcXFwiPkxlYXJuPC9saT5cXG5cXFxyXG48bGk+PGEgaWQ9XFxcInVzZXItcmV2aWV3XFxcIiBocmVmPVxcXCIjXFxcIiBvbmNsaWNrPVxcXCJXS1NTX3JldmlldygpO1xcXCI+UGxlYXNlIHdhaXQuLi48L2E+PC9saT5cXG5cXFxyXG48L3VsPlxcblxcXHJcbjwvbGk+XCI7XHJcblxyXG5cclxuICAgICAgICB9ZWxzZXtcclxuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcImNvdWxkIG5vdCBmaW5kIG5hdlwiLCBuYXYpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb25zb2xlLmxvZyhcImFkZFVzZXJWb2NhYlwiKTtcclxuICAgIH07XHJcblxyXG5cdCAgICAvKiogRXJyb3IgaGFuZGxpbmdcclxuXHQqIENhbiB1c2UgJ2Vycm9yLnN0YWNrJywgbm90IGNyb3NzLWJyb3dzZXIgKHRob3VnaCBpdCBzaG91bGQgd29yayBvbiBGaXJlZm94IGFuZCBDaHJvbWUpXHJcblx0Ki9cclxuICAgIHZhciBsb2dFcnJvciA9IGZ1bmN0aW9uKGVycm9yKSB7XHJcbiAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcImxvZ0Vycm9yKGVycm9yKVwiKTtcclxuICAgICAgICB2YXIgc3RhY2tNZXNzYWdlID0gXCJcIjtcclxuICAgICAgICBpZiAoXCJzdGFja1wiIGluIGVycm9yKVxyXG4gICAgICAgICAgICBzdGFja01lc3NhZ2UgPSBcIlxcblxcdFN0YWNrOiBcIiArIGVycm9yLnN0YWNrO1xyXG5cclxuICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUubG9nKFwiV0tTUzogRXJyb3I6IFwiICsgZXJyb3IubmFtZSArIFwiXFxuXFx0TWVzc2FnZTogXCIgKyBlcnJvci5tZXNzYWdlICsgc3RhY2tNZXNzYWdlKTtcclxuICAgICAgICBjb25zb2xlLmVycm9yKFwiV0tTUzogRXJyb3I6IFwiICsgZXJyb3IubmFtZSArIFwiXFxuXFx0TWVzc2FnZTogXCIgKyBlcnJvci5tZXNzYWdlICsgc3RhY2tNZXNzYWdlKTtcclxuICAgIH07XHJcblxyXG5cclxuICAgIC8qKiAgUHJlcGFyZXMgdGhlIHNjcmlwdFxyXG5cdCovXHJcbiAgICB2YXIgc2NyaXB0SW5pdCA9IGZ1bmN0aW9uKCkge1xyXG4gICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJzY3JpcHRJbml0KClcIik7XHJcbiAgICAgICAgLy9mdW5jdGlvbnM6XHJcbiAgICAgICAgLy8gICAgYWRkVXNlclZvY2FiQnV0dG9uKClcclxuICAgICAgICAvLyAgICBsb2dFcnJvcihlcnIpXHJcblxyXG4gICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJJbml0aWFsaXppbmcgV2FuaWthbmkgVXNlclZvY2FiIFNjcmlwdCFcIik7XHJcblxyXG4gICAgICAgIGdNX2FkZFN0eWxlKFwiLmN1c3RvbSAuZHJvcGRvd24tbWVudSB7YmFja2dyb3VuZC1jb2xvcjogI0RCQTkwMSAhaW1wb3J0YW50O31cIik7XHJcbiAgICAgICAgZ01fYWRkU3R5bGUoXCIuY3VzdG9tIC5kcm9wZG93bi1tZW51OmFmdGVyIHtib3JkZXItYm90dG9tLWNvbG9yOiAjREJBOTAxICFpbXBvcnRhbnQ7XCIpO1xyXG4gICAgICAgIGdNX2FkZFN0eWxlKFwiLmN1c3RvbSAuZHJvcGRvd24tbWVudTpiZWZvcmUge2JvcmRlci1ib3R0b20tY29sb3I6ICNEQkE5MDEgIWltcG9ydGFudDtcIik7XHJcbiAgICAgICAgZ01fYWRkU3R5bGUoXCIub3BlbiAuZHJvcGRvd24tdG9nZ2xlLmN1c3RvbSB7YmFja2dyb3VuZC1jb2xvcjogI0ZGQzQwMCAhaW1wb3J0YW50O31cIik7XHJcbiAgICAgICAgZ01fYWRkU3R5bGUoXCIuY3VzdG9tIC5kcm9wZG93bi1tZW51IGE6aG92ZXIge2JhY2tncm91bmQtY29sb3I6ICNBNjdGMDAgIWltcG9ydGFudDt9XCIpO1xyXG4gICAgICAgIGdNX2FkZFN0eWxlKFwiLmN1c3RvbTpob3ZlciB7Y29sb3I6ICNGRkM0MDAgIWltcG9ydGFudDt9XCIpO1xyXG4gICAgICAgIGdNX2FkZFN0eWxlKFwiLmN1c3RvbTpob3ZlciBzcGFuIHtib3JkZXItY29sb3I6ICNGRkM0MDAgIWltcG9ydGFudDt9XCIpO1xyXG4gICAgICAgIGdNX2FkZFN0eWxlKFwiLmN1c3RvbTpmb2N1cyB7Y29sb3I6ICNGRkM0MDAgIWltcG9ydGFudDt9XCIpO1xyXG4gICAgICAgIGdNX2FkZFN0eWxlKFwiLmN1c3RvbTpmb2N1cyBzcGFuIHtib3JkZXItY29sb3I6ICNGRkM0MDAgIWltcG9ydGFudDt9XCIpO1xyXG4gICAgICAgIGdNX2FkZFN0eWxlKFwiLm9wZW4gLmN1c3RvbSBzcGFuIHtib3JkZXItY29sb3I6ICNGRkZGRkYgIWltcG9ydGFudDt9XCIpO1xyXG4gICAgICAgIGdNX2FkZFN0eWxlKFwiLm9wZW4gLmN1c3RvbSB7Y29sb3I6ICNGRkZGRkYgIWltcG9ydGFudH1cIik7XHJcblxyXG5cdFx0dmFyIHdrU3R5bGVDU1MgPSByZXF1aXJlKCcuL3drc3R5bGUuanMnKTtcclxuICAgICAgICBnTV9hZGRTdHlsZSh3a1N0eWxlQ1NTKTtcclxuICAgICAgICAvLyBTZXQgdXAgYnV0dG9uc1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGlmICh0eXBlb2YgbG9jYWxTdG9yYWdlICE9PSBcInVuZGVmaW5lZFwiKSB7XHJcbiAgICAgICAgICAgICAgICBhZGRVc2VyVm9jYWJCdXR0b24oKTtcclxuXHJcbiAgICAgICAgICAgICAgICAvL3Byb3ZpZGUgd2FybmluZyB0byB1c2VycyB0cnlpbmcgdG8gdXNlIHRoZSAoaW5jb21wbGV0ZSkgc2NyaXB0LlxyXG4gICAgICAgICAgICAgICAgZGVidWdnaW5nJiZjb25zb2xlLmxvZyhcInRoaXMgc2NyaXB0IGlzIHN0aWxsIGluY29tcGxldGU6IFxcblxcXHJcbkl0IGlzIHByb3ZpZGVkIGFzIGlzIHdpdGhvdXQgd2FycmFudHkgZXhwcmVzcyBvciBpbXBsaWVkXFxuXFxcclxuaW4gdGhlIGhvcGUgdGhhdCB5b3UgbWF5IGZpbmQgaXQgdXNlZnVsLlwiKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJXYW5pa2FuaSBTZWxmLVN0dWR5OiBZb3VyIGJyb3dzZXIgZG9lcyBub3Qgc3VwcG9ydCBsb2NhbFN0b3JhZ2UuLiBTb3JyeSA6KFwiKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBjYXRjaCAoZXJyKSB7XHJcbiAgICAgICAgICAgIGxvZ0Vycm9yKGVycik7XHJcbiAgICAgICAgfVxyXG4gICAgfTtcclxuXHJcblx0Y29uc29sZS5pbmZvKGRvY3VtZW50LnJlYWR5U3RhdGUpO1xyXG4gICAgY29uc29sZS5sb2coXCJhZGRpbmcgRE9NIGxpc3RlbmVyXCIsIGRvY3VtZW50LnJlYWR5U3RhdGUpO1xyXG4gICAgLy8gQ2hlY2sgZm9yIGZpbGUgQVBJIHN1cHBvcnQuXHJcbiAgICBpZiAod2luZG93LkZpbGUgJiYgd2luZG93LkZpbGVSZWFkZXIgJiYgd2luZG93LkZpbGVMaXN0ICYmIHdpbmRvdy5CbG9iKSB7XHJcblxyXG4gICAgfVxyXG5cdGVsc2Uge1xyXG4gICAgICAgIGFsZXJ0KCdUaGUgRmlsZSBBUElzIGFyZSBub3QgZnVsbHkgc3VwcG9ydGVkIGluIHRoaXMgYnJvd3Nlci4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvKiogU3RhcnQgdGhlIHNjcmlwdFxyXG4gICAgKi9cclxuICAgIC8vdW5sZXNzIHRoZSB1c2VyIG5hdmlnYXRlZCBmcm9tIHRoZSByZXZpZXcgZGlyZWN0b3J5LCB0aGV5IGFyZSB1bmxpa2VseSB0byBoYXZlIHVubG9ja2VkIGFueSBrYW5qaVxyXG4gICAgdmFyIG5vTmV3U3R1ZmYgPSAvXmh0dHBzOlxcL1xcLy4qXFwud2FuaWthbmlcXC5jb21cXC8uKi8udGVzdChkb2N1bWVudC5yZWZlcnJlcikmJiEoL2h0dHBzOlxcL1xcLy4qXFwud2FuaWthbmlcXC5jb21cXC9yZXZpZXcuKi8udGVzdChkb2N1bWVudC5yZWZlcnJlcikpO1xyXG4gICAgdmFyIHVzaW5nSFRUUFMgPSAvXmh0dHBzOi8udGVzdCh3aW5kb3cubG9jYXRpb24uaHJlZik7XHJcbiAgICBjb25zb2xlLmluZm8odXNpbmdIVFRQUywgd2luZG93LmxvY2F0aW9uLmhyZWYpO1xyXG4gICAgaWYgKHVzaW5nSFRUUFMpe1xyXG4gICAgICAgIGlmICghbm9OZXdTdHVmZil7ICAvL0Rvbid0IHdhc3RlIHRpbWUgaWYgdXNlciBpcyBicm93c2luZyBzaXRlXHJcbiAgICAgICAgICAgIFdhbmlrYW5pVXRpbC5nZXRTZXJ2ZXJSZXNwKEFQSWtleSk7XHJcbiAgICAgICAgfWVsc2V7XHJcbiAgICAgICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS5sb2coXCJVc2VyIGlzIHVubGlrZWx5IHRvIGhhdmUgbmV3IGthbmppIHVubG9ja2VkXCIpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBkZWJ1Z2dpbmcmJmNvbnNvbGUuaW5mbyhcIldhbmlLYW5pIFNlbGYtU3R1ZHkgUGx1cyBpcyBhYm91dCB0byBzdGFydFwiKTtcclxuXHJcbiAgICAgICAgc2NyaXB0SW5pdCgpO1xyXG5cclxuICAgIH1lbHNle1xyXG4gICAgICAgIGRlYnVnZ2luZyYmY29uc29sZS53YXJuKFwiSXQgYXBwZWFycyB0aGF0IHlvdSBhcmUgbm90IHVzaW5nIGh0dHBzIHByb3RvY29sLiBBdHRlbXB0aW5nIHRvIHJlZGlyZWN0IHRvIGh0dHBzIG5vdy5cIik7XHJcbiAgICAgICAgd2luZG93LmxvY2F0aW9uLmhyZWYgPSB3aW5kb3cubG9jYXRpb24uaHJlZi5yZXBsYWNlKC9eaHR0cC8sIFwiaHR0cHNcIik7XHJcbiAgICB9XHJcbn1cclxuaWYgKGRvY3VtZW50LnJlYWR5U3RhdGUgPT09ICdjb21wbGV0ZScpe1xyXG4gICAgY29uc29sZS5pbmZvKFwiQWJvdXQgdG8gaW5pdGlhbGlzZSBXS1NTK1wiKTtcclxuICAgIG1haW4oKTtcclxufSBlbHNlIHtcclxuICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKFwibG9hZFwiLCBtYWluLCBmYWxzZSk7XHJcbn1cclxuIiwiLyoqIFV0aWxpdGllcyBmb3IgaW50ZXJhY3Rpb24gd2l0aCB0aGUgV2FuaWthbmkgQVBJIGFuZCBnZW5lcmFsIHdlYnNpdGUuXHJcbiovXHJcbnZhciBXYW5pa2FuaVV0aWwgPSB7XHJcblx0aGlqYWNrUmVxdWVzdHM6IHJlcXVpcmUoJy4vaGlqYWNrcmVxdWVzdHMuanMnKSxcclxuXHRjcmVhdGVDT1JTUmVxdWVzdDogZnVuY3Rpb24obWV0aG9kLCB1cmwpe1xyXG4gICAgICAgIHZhciB4aHIgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTtcclxuICAgICAgICBpZiAoXCJ3aXRoQ3JlZGVudGlhbHNcIiBpbiB4aHIpe1xyXG4gICAgICAgICAgICB4aHIub3BlbihtZXRob2QsIHVybCwgdHJ1ZSk7XHJcbiAgICAgICAgfVxyXG5cdFx0ZWxzZSBpZiAodHlwZW9mIFhEb21haW5SZXF1ZXN0ICE9PSBcInVuZGVmaW5lZFwiKXtcclxuICAgICAgICAgICAgeGhyID0gbmV3IFhEb21haW5SZXF1ZXN0KCk7XHJcbiAgICAgICAgICAgIHhoci5vcGVuKG1ldGhvZCwgdXJsKTtcclxuICAgICAgICB9XHJcblx0XHRlbHNlIHtcclxuICAgICAgICAgICAgeGhyID0gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHhocjtcclxuICAgIH0sXHJcblx0LyoqIEdldHMgdGhlIHVzZXIgaW5mb3JtYXRpb24gdXNpbmcgdGhlIFdhbmlrYW5pIEFQSSBhbmQgc3RvcmVzIHRoZW0gZGlyZWN0bHkgaW50byBicm93c2VyIHN0b3JhZ2UuXHJcblx0KiBAcGFyYW1cclxuXHQqIEBwYXJhbVxyXG5cdCovXHJcblx0Z2V0U2VydmVyUmVzcDogZnVuY3Rpb24oQVBJa2V5LCByZXF1ZXN0ZWRJdGVtKXtcclxuXHJcbiAgICAgICAgcmVxdWVzdGVkSXRlbSA9IHJlcXVlc3RlZEl0ZW0gPT09IHZvaWQgMCA/ICdrYW5qaScgOnJlcXVlc3RlZEl0ZW07XHJcblxyXG4gICAgICAgIGlmIChBUElrZXkgIT09IFwidGVzdFwiKXtcclxuICAgICAgICAgICAgdmFyIGxldmVscyA9IChyZXF1ZXN0ZWRJdGVtID09PVwia2FuamlcIik/IFwiLzEsMiwzLDQsNSw2LDcsOCw5LDEwLDExLDEyLDEzLDE0LDE1LDE2LDE3LDE4LDE5LDIwLDIxLDIyLDIzLDI0LDI1LDI2LDI3LDI4LDI5LDMwLDMxLDMyLDMzLDM0LDM1LDM2LDM3LDM4LDM5LDQwLDQxLDQyLDQzLDQ0LDQ1LDQ2LDQ3LDQ4LDQ5LDUwXCI6XHJcbiAgICAgICAgICAgIFwiLzEsMiwzLDQsNSw2LDcsOCw5LDEwXCI7XHJcbiAgICAgICAgICAgIHZhciB4aHJrID0gdGhpcy5jcmVhdGVDT1JTUmVxdWVzdChcImdldFwiLCBcImh0dHBzOi8vd3d3LndhbmlrYW5pLmNvbS9hcGkvdXNlci9cIiArIEFQSWtleSArIFwiL1wiICsgcmVxdWVzdGVkSXRlbSArIGxldmVscyk7XHJcbiAgICAgICAgICAgIGlmICghaXNFbXB0eSh4aHJrKSl7XHJcbiAgICAgICAgICAgICAgICB4aHJrLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uKCkge1xyXG4gICAgICAgICAgICAgICAgICAgIGlmICh4aHJrLnJlYWR5U3RhdGUgPT0gNCl7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBrYW5qaUxpc3QgPSB0aGlzLmhhbmRsZVJlYWR5U3RhdGVGb3VyKHhocmsscmVxdWVzdGVkSXRlbSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVxdWVzdGVkSXRlbSA9PT0gJ2thbmppJyl7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2NhbFNldCgnVXNlci1LYW5qaUxpc3QnLCBrYW5qaUxpc3QpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJrYW5qaUxpc3QgZnJvbSBzZXJ2ZXJcIiwga2FuamlMaXN0KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vdXBkYXRlIGxvY2tzIGluIGxvY2FsU3RvcmFnZSBcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vcGFzcyBrYW5qaWxpc3QgaW50byB0aGlzIGZ1bmN0aW9uXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyhkb24ndCBzaGlmdCB0aGluZ3MgdGhyb3VnaCBzdG9yYWdlIHVuZWNlc3NhcmlseSlcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlZnJlc2hMb2NrcygpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcblx0XHRcdFx0XHRcdGVsc2V7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdiA9IGthbmppTGlzdC5sZW5ndGg7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyh2ICsgXCIgaXRlbXMgZm91bmQsIGF0dGVtcHRpbmcgdG8gaW1wb3J0XCIpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKHYtLSl7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU3RvcmFnZVV0aWwuc2V0Vm9jSXRlbShrYW5qaUxpc3Rbdl0pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgICAgICB4aHJrLnNlbmQoKTtcclxuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiYmVsb3dcIik7ICBcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHRcdGVsc2Uge1xyXG4gICAgICAgICAgICAvL2R1bW15IHNlcnZlciByZXNwb25zZSBmb3IgdGVzdGluZy5cclxuICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XHJcbiAgICAgICAgICAgICAgICB2YXIga2FuamlMaXN0ID0gW107XHJcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcImNyZWF0aW5nIGR1bW15IHJlc3BvbnNlXCIpO1xyXG4gICAgICAgICAgICAgICAga2FuamlMaXN0LnB1c2goe1wiY2hhcmFjdGVyXCI6IFwi54yrXCIsIFwic3JzXCI6IFwibm9TZXJ2ZXJSZXNwXCJ9KTtcclxuICAgICAgICAgICAgICAgIHZhciBTUlMgPSBcImFwcHJlbnRpY2VcIjsgLy9wcm9tcHQoXCJlbnRlciBTUlMgZm9yIOWtkFwiLCBcImd1cnVcIik7XHJcbiAgICAgICAgICAgICAgICBrYW5qaUxpc3QucHVzaCh7XCJjaGFyYWN0ZXJcIjogXCLlrZBcIiwgXCJzcnNcIjogU1JTfSk7XHJcbiAgICAgICAgICAgICAgICBrYW5qaUxpc3QucHVzaCh7XCJjaGFyYWN0ZXJcIjogXCLlk4FcIiwgXCJzcnNcIjogXCJndXJ1XCJ9KTtcclxuICAgICAgICAgICAgICAgIGthbmppTGlzdC5wdXNoKHtcImNoYXJhY3RlclwiOiBcIuS+m1wiLCBcInNyc1wiOiBcImd1cnVcIn0pO1xyXG4gICAgICAgICAgICAgICAga2FuamlMaXN0LnB1c2goe1wiY2hhcmFjdGVyXCI6IFwi5pysXCIsIFwic3JzXCI6IFwiZ3VydVwifSk7XHJcbiAgICAgICAgICAgICAgICBrYW5qaUxpc3QucHVzaCh7XCJjaGFyYWN0ZXJcIjogXCLogZ5cIiwgXCJzcnNcIjogXCJhcHByZW50aWNlXCJ9KTtcclxuICAgICAgICAgICAgICAgIGthbmppTGlzdC5wdXNoKHtcImNoYXJhY3RlclwiOiBcIuS6ulwiLCBcInNyc1wiOiBcImVubGlnaHRlbmVkXCJ9KTtcclxuICAgICAgICAgICAgICAgIGthbmppTGlzdC5wdXNoKHtcImNoYXJhY3RlclwiOiBcIualvVwiLCBcInNyc1wiOiBcImJ1cm5lZFwifSk7XHJcbiAgICAgICAgICAgICAgICBrYW5qaUxpc3QucHVzaCh7XCJjaGFyYWN0ZXJcIjogXCLnm7hcIiwgXCJzcnNcIjogXCJndXJ1XCJ9KTtcclxuICAgICAgICAgICAgICAgIGthbmppTGlzdC5wdXNoKHtcImNoYXJhY3RlclwiOiBcIuWNklwiLCBcInNyc1wiOiBcIm5vTWF0Y2hXS1wifSk7XHJcbiAgICAgICAgICAgICAgICBrYW5qaUxpc3QucHVzaCh7XCJjaGFyYWN0ZXJcIjogXCLnhKFcIiwgXCJzcnNcIjogXCJub01hdGNoR3VwcHlcIn0pO1xyXG5cclxuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiU2VydmVyIHJlc3BvbmRlZCB3aXRoIGR1bW15IGthbmppTGlzdDogXFxuXCIrSlNPTi5zdHJpbmdpZnkoa2FuamlMaXN0KSk7XHJcblxyXG4gICAgICAgICAgICAgICAgbG9jYWxTZXQoJ1VzZXItS2FuamlMaXN0Jywga2FuamlMaXN0KTtcclxuXHJcbiAgICAgICAgICAgICAgICAvL3VwZGF0ZSBsb2NrcyBpbiBsb2NhbFN0b3JhZ2VcclxuICAgICAgICAgICAgICAgIHJlZnJlc2hMb2NrcygpO1xyXG4gICAgICAgICAgICB9LCAxMDAwMCk7XHJcbiAgICAgICAgfSAgIFxyXG4gICAgfSxcclxuXHRcclxuXHRoYW5kbGVSZWFkeVN0YXRlRm91cjogZnVuY3Rpb24oeGhyaywgcmVxdWVzdGVkSXRlbSl7XHJcblxyXG4gICAgICAgIHZhciBsb2NhbGthbmppTGlzdCA9IFtdO1xyXG4gICAgICAgIGNvbnNvbGUubG9nKFwicmVhZHlzdGF0ZTogXCIrIHhocmsucmVhZHlTdGF0ZSk7XHJcbiAgICAgICAgdmFyIHJlc3AgPSBKU09OLnBhcnNlKHhocmsucmVzcG9uc2VUZXh0KTtcclxuICAgICAgICBjb25zb2xlLmxvZyhcImFib3V0IHRvIGxvb3AgdGhyb3VnaCByZXF1ZXN0ZWQgaW5mb3JtYXRpb25cIik7IFxyXG5cdFx0aWYgKHJlc3AucmVxdWVzdGVkX2luZm9ybWF0aW9uICYmIHJlc3AucmVxdWVzdGVkX2luZm9ybWF0aW9uLmxlbmd0aCl7XHJcblx0XHRcdFxyXG5cdFx0XHRsb2NhbGthbmppTGlzdCA9IHJlc3AucmVxdWVzdGVkX2luZm9ybWF0aW9uLm1hcChmdW5jdGlvbihyZXF1ZXN0ZWRUYXNrKXtcclxuXHRcdFx0XHRpZiAocmVxdWVzdGVkSXRlbSA9PT0gXCJrYW5qaVwiKXtcclxuXHRcdFx0XHRcdGlmIChyZXF1ZXN0ZWRUYXNrLnVzZXJfc3BlY2lmaWMgIT09IG51bGwpe1xyXG5cdFx0XHRcdFx0XHRyZXR1cm4ge1xyXG5cdFx0XHRcdFx0XHRcdGNoYXJhY3RlcjogcmVxdWVzdGVkVGFzay5jaGFyYWN0ZXIsXHJcblx0XHRcdFx0XHRcdFx0c3JzOiByZXF1ZXN0ZWRUYXNrLnVzZXJfc3BlY2lmaWMuc3JzLFxyXG5cdFx0XHRcdFx0XHRcdHJlYWRpbmc6IHJlcXVlc3RlZFRhc2tbcmVxdWVzdGVkVGFzay5pbXBvcnRhbnRfcmVhZGluZ10uc3BsaXQoXCIsXCIpWzBdLFxyXG5cdFx0XHRcdFx0XHRcdG1lYW5pbmc6IHJlcXVlc3RlZFRhc2subWVhbmluZy5zcGxpdChcIixcIilbMF1cclxuXHRcdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdGVsc2V7XHJcblx0XHRcdFx0XHRcdHJldHVybiB7XHJcblx0XHRcdFx0XHRcdFx0Y2hhcmFjdGVyOiByZXF1ZXN0ZWRUYXNrLmNoYXJhY3RlcixcclxuXHRcdFx0XHRcdFx0XHRzcnM6IFwidW5yZWFjaGVkXCJcclxuXHRcdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0ZWxzZSBpZihyZXF1ZXN0ZWRJdGVtID09PSBcInZvY2FidWxhcnlcIil7XHJcblx0XHRcdFx0XHRpZiAocmVxdWVzdGVkVGFzay51c2VyX3NwZWNpZmljICE9PSBudWxsfHx0cnVlKXsgLy8tLVxyXG5cdFx0XHRcdFx0XHQvL2J1aWxkIHZvY2FibGlzdFxyXG5cdFx0XHRcdFx0XHRyZXR1cm4ge1xyXG5cdFx0XHRcdFx0XHRcdGthbmppOiByZXF1ZXN0ZWRUYXNrLmNoYXJhY3RlcixcclxuXHRcdFx0XHRcdFx0XHRyZWFkaW5nOiByZXF1ZXN0ZWRUYXNrLmthbmEuc3BsaXQoXCIsXCIpLFxyXG5cdFx0XHRcdFx0XHRcdG1lYW5pbmc6IHJlcXVlc3RlZFRhc2subWVhbmluZy5zcGxpdChcIixcIilcclxuXHRcdFx0XHRcdFx0fTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH0sIHRoaXMpO1xyXG5cdFx0fVxyXG4gICAgICAgIC8vcmV0dXJuIGthbmppTGlzdFxyXG4gICAgICAgIC8vICBjb25zb2xlLmxvZyhcIlNlcnZlciByZXNwb25kZWQgd2l0aCBuZXcga2FuamlMaXN0OiBcXG5cIitKU09OLnN0cmluZ2lmeShrYW5qaUxpc3QpKTtcclxuICAgICAgICByZXR1cm4gbG9jYWxrYW5qaUxpc3Q7XHJcbiAgICB9XHJcblxyXG59OyIsIi8vIFdpbmRvdyBDb25maWdzXHJcbm1vZHVsZS5leHBvcnRzID0ge1xyXG5cdGFkZDp7aGVpZ2h0OiBcIjMwMHB4XCIsIHdpZHRoOiBcIjMwMHB4XCJ9LFxyXG5cdGV4cG9ydEltcG9ydDp7aGVpZ2h0OiBcIjI3NXB4XCIsIHdpZHRoOiBcIjM5MHB4XCJ9LFxyXG5cdGVkaXQ6e2hlaWdodDogXCIzODBweFwiLCB3aWR0aDogXCI4MDBweFwifSxcclxuXHRzdHVkeTp7aGVpZ2h0OiBcImF1dG9cIiwgd2lkdGg6IFwiNjAwcHhcIn0sIC8vaGVpZ2h0IDogYXV0b1xyXG5cdHJlc3VsdDp7aGVpZ2h0OiBcIjUwMHB4XCIsIHdpZHRoOiBcIjcwMHB4XCJ9XHJcbn07IiwiLyoganNoaW50IG11bHRpc3RyOiB0cnVlICovXHJcbi8vIENvbmZpZyBmb3Igd2luZG93IHNpemVzIGluIHBpeGVsc1xyXG52YXIgd2luZG93Q29uZmlnID0gcmVxdWlyZSgnLi93aW5kb3djb25maWcuanMnKTtcclxuXHJcbi8vLldLU1NcclxudmFyIGNsYXNzV0tTUyA9IFtcclxuXHR7cG9zaXRpb246IFwiZml4ZWRcIn0sXHJcblx0e3pJbmRleDogXCIyXCJ9LFxyXG5cdHt0b3A6IFwiMTI1cHhcIn0sXHJcblx0e2xlZnQ6IFwiNTAlXCJ9LFxyXG5cdHttYXJnaW46IFwiMHB4XCJ9LFxyXG5cdHtiYWNrZ3JvdW5kOiBcIiNGRkZcIn0sXHJcblx0e3BhZGRpbmc6IFwiNXB4XCJ9LFxyXG5cdHtmb250OiBcIjEycHggXFxcIuODkuODqeOCruODjuinkuOCtCBQcm8gVzNcXFwiLCBcXFwiSGlyYWdpbm8gS2FrdSBHb3RoaWMgUHJvXFxcIixPc2FrYSwgXFxcIuODoeOCpOODquOCqlxcXCIsIE1laXJ5bywgXFxcIu+8re+8syDvvLDjgrTjgrfjg4Pjgq9cXFwiLCBcXFwiTVMgUEdvdGhpY1xcXCIsIHNhbnMtc2VyaWZcIn0sXHJcblx0e2NvbG9yOiBcIiM4ODhcIn0sXHJcblx0e3RleHRTaGFkb3c6IFwiMXB4IDFweCAxcHggI0ZGRlwifSxcclxuXHR7Ym9yZGVyOiBcIjFweCBzb2xpZCAjREREXCJ9LFxyXG5cdHtib3JkZXJSYWRpdXM6IFwiNXB4XCJ9LFxyXG5cdHtXZWJraXRCb3JkZXJSYWRpdXM6IFwiNXB4XCJ9LFxyXG5cdHtNb3pCb3JkZXJSYWRpdXM6IFwiNXB4XCJ9LFxyXG5cdHtib3hTaGFkb3c6IFwiMTBweCAxMHB4IDVweCAjODg4ODg4XCJ9XHJcbl07XHJcblxyXG4vLy5XS1NTIGgxXHJcbnZhciBjbGFzc1dLU1NfaDEgPSBbXHJcblx0e2ZvbnQ6IFwiMjVweCBcXFwi44OS44Op44Ku44OO6KeS44K0IFBybyBXM1xcXCIsIFxcXCJIaXJhZ2lubyBLYWt1IEdvdGhpYyBQcm9cXFwiLE9zYWthLCBcXFwi44Oh44Kk44Oq44KqXFxcIiwgTWVpcnlvLCBcXFwi77yt77yzIO+8sOOCtOOCt+ODg+OCr1xcXCIsIFxcXCJNUyBQR290aGljXFxcIiwgc2Fucy1zZXJpZlwifSxcclxuXHR7cGFkZGluZ0xlZnQ6IFwiNXB4XCJ9LFxyXG5cdHtkaXNwbGF5OiBcImJsb2NrXCJ9LFxyXG5cdHtib3JkZXJCb3R0b206IFwiMXB4IHNvbGlkICNEQURBREFcIn0sXHJcblx0e21hcmdpbjogXCIwcHhcIn0sXHJcblx0e2NvbG9yOiBcIiM4ODhcIn1cclxuXTtcclxuXHJcbi8vLldLU1MgaDEgPiBzcGFuXHJcbnZhciBjbGFzc1dLU1NfaDFfZGlyZWN0X1NwYW4gPSBbXHJcblx0e2Rpc3BsYXk6IFwiYmxvY2tcIn0sXHJcblx0e2ZvbnRTaXplOiBcIjExcHhcIn1cclxuXTtcclxuXHJcbi8vLldLU1MgbGFiZWxcclxudmFyIHcgPSBbXHJcblx0e2Rpc3BsYXk6IFwiYmxvY2tcIn0sXHJcblx0e21hcmdpbjogXCIwcHggMHB4IDVweFwifSxcclxuXTtcclxuXHJcbi8vLldLU1MgbGFiZWw+c3BhblxyXG53ID0gW1xyXG5cdHtmbG9hdDogXCJsZWZ0XCJ9LFxyXG5cdHt3aWR0aDogXCI4MHB4XCJ9LFxyXG5cdHt0ZXh0QWxpZ246IFwicmlnaHRcIn0sXHJcblx0e3BhZGRpbmdSaWdodDogXCIxMHB4XCJ9LFxyXG5cdHttYXJnaW5Ub3A6IFwiMTBweFwifSxcclxuXHR7Y29sb3I6IFwiIzMzM1wifSxcclxuXHR7Zm9udEZhbWlseTogXCJcXFwi44OS44Op44Ku44OO6KeS44K0IFBybyBXM1xcXCIsIFxcXCJIaXJhZ2lubyBLYWt1IEdvdGhpYyBQcm9cXFwiLE9zYWthLCBcXFwi44Oh44Kk44Oq44KqXFxcIiwgTWVpcnlvLCBcXFwi77yt77yzIO+8sOOCtOOCt+ODg+OCr1xcXCIsIFxcXCJNUyBQR290aGljXFxcIiwgc2Fucy1zZXJpZlwifSxcclxuXHR7Zm9udFdlaWdodDogXCJib2xkXCJ9XHJcbl07XHJcblxyXG4vLy5XS1NTIGlucHV0W3R5cGU9XFxcInRleHRcXFwiXSwgLldLU1MgaW5wdXRbdHlwZT1cXFwiZW1haWxcXFwiXSwgLldLU1MgdGV4dGFyZWEgXHJcbncgPSBbXHJcblx0e2JvcmRlcjogXCIxcHggc29saWQgI0NDQ1wifSxcclxuXHR7Y29sb3I6IFwiIzg4OFwifSxcclxuXHR7aGVpZ2h0OiBcIjIwcHhcIn0sXHJcblx0e21hcmdpbkJvdHRvbTogXCIxNnB4XCJ9LFxyXG5cdHttYXJnaW5SaWdodDogXCI2cHhcIn0sXHJcblx0e21hcmdpblRvcDogXCIycHhcIn0sXHJcblx0e291dGxpbmU6IFwiMCBub25lXCJ9LFxyXG5cdHtwYWRkaW5nOiBcIjZweCAxMnB4XCJ9LFxyXG5cdHt3aWR0aDogXCI4MCVcIn0sXHJcblx0e2JvcmRlclJhZGl1czogXCI0cHhcIn0sXHJcblx0e2xpbmVIZWlnaHQ6IFwibm9ybWFsICFpbXBvcnRhbnRcIn0sXHJcblx0e1dlYmtpdEJvcmRlclJhZGl1czogXCI0cHhcIn0sXHJcblx0e01vekJvcmRlclJhZGl1czogXCI0cHhcIn0sXHJcblx0e2ZvbnQ6IFwibm9ybWFsIDE0cHgvMTRweCBcXFwi44OS44Op44Ku44OO6KeS44K0IFBybyBXM1xcXCIsIFxcXCJIaXJhZ2lubyBLYWt1IEdvdGhpYyBQcm9cXFwiLE9zYWthLCBcXFwi44Oh44Kk44Oq44KqXFxcIiwgTWVpcnlvLCBcXFwi77yt77yzIO+8sOOCtOOCt+ODg+OCr1xcXCIsIFxcXCJNUyBQR290aGljXFxcIiwgc2Fucy1zZXJpZlwifSxcclxuXHR7V2Via2l0Qm94U2hhZG93OiBcImluc2V0IDAgMXB4IDFweCByZ2JhKDAsIDAsIDAsIDAuMDc1KVwifSxcclxuXHR7Ym94U2hhZG93OiBcImluc2V0IDAgMXB4IDFweCByZ2JhKDAsIDAsIDAsIDAuMDc1KVwifSxcclxuXHR7TW96Qm94U2hhZG93OiBcImluc2V0IDAgMXB4IDFweCByZ2JhKDAsIDAsIDAsIDAuMDc1KVwifVxyXG5dO1xyXG5cclxuLy8uV0tTUyBzZWxlY3RcclxudyA9IFtcclxuXHR7Ym9yZGVyOiBcIjFweCBzb2xpZCBcXFwiI0NDQ1xcXCJcIn0sXHJcblx0e2NvbG9yOiBcIiM4ODhcIn0sXHJcblx0e291dGxpbmU6IFwiMCBub25lXCJ9LFxyXG5cdHtwYWRkaW5nOiBcIjZweCAxMnB4XCJ9LFxyXG5cdHtoZWlnaHQ6IFwiMTYwcHggIWltcG9ydGFudFwifSxcclxuXHR7d2lkdGg6IFwiOTUlXCJ9LFxyXG5cdHtib3JkZXJSYWRpdXM6IFwiNHB4XCJ9LFxyXG5cdHtXZWJraXRCb3JkZXJSYWRpdXM6IFwiNHB4XCJ9LFxyXG5cdHtNb3pCb3JkZXJSYWRpdXM6IFwiNHB4XCJ9LFxyXG5cdHtmb250OiBcIm5vcm1hbCAxNHB4LzE0cHggXFxcIuODkuODqeOCruODjuinkuOCtCBQcm8gVzNcXFwiLCBcXFwiSGlyYWdpbm8gS2FrdSBHb3RoaWMgUHJvXFxcIixPc2FrYSwgXFxcIuODoeOCpOODquOCqlxcXCIsIE1laXJ5bywgXFxcIu+8re+8syDvvLDjgrTjgrfjg4Pjgq9cXFwiLCBcXFwiTVMgUEdvdGhpY1xcXCIsIHNhbnMtc2VyaWZcIn0sXHJcblx0e1dlYmtpdEJveFNoYWRvdzogXCJpbnNldCAwIDFweCAxcHggcmdiYSgwLCAwLCAwLCAwLjA3NSlcIn0sXHJcblx0e2JveFNoYWRvdzogXCJpbnNldCAwIDFweCAxcHggcmdiYSgwLCAwLCAwLCAwLjA3NSlcIn0sXHJcblx0e01vekJveFNoYWRvdzogXCJpbnNldCAwIDFweCAxcHggcmdiYSgwLCAwLCAwLCAwLjA3NSlcIn0sXHJcblx0e2JhY2tncm91bmQ6IFwiI0ZGRiB1cmwoJ2Rvd24tYXJyb3cucG5nJykgbm8tcmVwZWF0IHJpZ2h0XCJ9LFxyXG5cdHthcHBlYXJhbmNlOiBcIm5vbmVcIn0sXHJcblx0e1dlYmtpdEFwcGVhcmFuY2U6IFwibm9uZVwifSxcclxuXHR7TW96QXBwZWFyYW5jZTogXCJub25lXCJ9LFxyXG5cdHt0ZXh0SW5kZW50OiBcIjAuMDFweFwifSxcclxuXHR7dGV4dE92ZXJmbG93OiBcIicnXCJ9XHJcbl07XHJcblxyXG4vLy5XS1NTIHRleHRhcmVhXHJcbncgPSBbXHJcblx0e2hlaWdodDogXCIxMDBweFwifVxyXG5dO1xyXG5cclxuLy8uV0tTUyBidXR0b24sIC5idXR0b25cclxudyA9IFtcclxuXHR7cG9zaXRpb246IFwicmVsYXRpdmVcIn0sXHJcblx0e2JhY2tncm91bmQ6IFwiI0ZGRlwifSxcclxuXHR7Ym9yZGVyOiBcIjFweCBzb2xpZCAjQ0NDXCJ9LFxyXG5cdHtwYWRkaW5nOiBcIjEwcHggMjVweCAxMHB4IDI1cHhcIn0sXHJcblx0e2NvbG9yOiBcIiMzMzNcIn0sXHJcblx0e2JvcmRlclJhZGl1czogXCI0cHhcIn0sXHJcblx0e2Rpc3BsYXk6IFwiaW5saW5lICFpbXBvcnRhbnRcIn1cclxuXTtcclxuXHJcbi8vLldLU1MgYnV0dG9uOmRpc2FibGVkXHJcbncgPSBbXHJcblx0e2JhY2tncm91bmQ6IFwiI0VCRUJFQlwifSxcclxuXHR7Ym9yZGVyOiBcIjFweCBzb2xpZCAjQ0NDXCJ9LFxyXG5cdHtwYWRkaW5nOiBcIjEwcHggMjVweCAxMHB4IDI1cHhcIn0sXHJcblx0e2NvbG9yOiBcIiMzMzNcIn0sXHJcblx0e2JvcmRlclJhZGl1czogXCI0cHhcIn1cclxuXTtcclxuXHJcbi8vLldLU1MgLmJ1dHRvbjpob3ZlciwgYnV0dG9uOmhvdmVyOmVuYWJsZWRcclxudyA9IFtcclxuXHR7Y29sb3I6IFwiIzMzM1wifSxcclxuXHR7YmFja2dyb3VuZENvbG9yOiBcIiNFQkVCRUJcIn0sXHJcblx0e2JvcmRlckNvbG9yOiBcIiNBREFEQURcIn1cclxuXTtcclxuXHJcbi8vLldLU1MgYnV0dG9uOmhvdmVyOmRpc2FibGVkXHJcbncgPSBbXHJcblx0e2N1cnNvcjogXCJkZWZhdWx0XCJ9ICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcclxuXTtcclxuXHJcbi8vLmVycm9yXHJcbncgPSBbXHJcblx0e2JvcmRlckNvbG9yOlwiI0YwMCAhaW1wb3J0YW50XCJ9LFxyXG5cdHtjb2xvcjogXCIjRjAwICFpbXBvcnRhbnRcIn1cclxuXTtcclxuXHJcbi8vLmNhdXRpb25cclxudyA9IFtcclxuXHR7Ym9yZGVyQ29sb3I6IFwiI0Y5MCAhaW1wb3J0YW50XCJ9LFxyXG5cdHtjb2xvcjogXCIjRjkwICFpbXBvcnRhbnRcIn1cclxuXTtcclxuXHJcbi8vLmNvcnJlY3RcclxudyA9IFtcclxuXHR7Ym9yZGVyQ29sb3I6IFwiIzBGMCAhaW1wb3J0YW50XCJ9LFxyXG5cdHtjb2xvcjogXCIjMEYwICFpbXBvcnRhbnRcIn1cclxuXTtcclxuXHJcbi8vLmluZm9cclxudyA9IFtcclxuXHR7Ym9yZGVyQ29sb3I6IFwiIzY5Njk2OSAhaW1wb3J0YW50XCJ9LFxyXG5cdHtjb2xvcjogXCIjNjk2OTY5ICFpbXBvcnRhbnRcIn1cclxuXTtcclxuXHJcbi8vLnJldi1lcnJvclxyXG53ID0gW1xyXG5cdHt0ZXh0U2hhZG93OiBcIm5vbmVcIn0sXHJcblx0e2JvcmRlcjogXCIxcHggc29saWQgI0YwMCAhaW1wb3J0YW50XCJ9LFxyXG5cdHtib3JkZXJSYWRpdXM6IFwiMTBweFwifSxcclxuXHR7YmFja2dyb3VuZENvbG9yOiBcIiNGMDBcIn0sXHJcblx0e3BhZGRpbmc6IFwiNHB4XCJ9LFxyXG5cdHttYXJnaW46IFwiNHB4XCJ9LFxyXG5cdHtjb2xvcjogXCIjRkZGRkZGXCJ9LFxyXG5cdHtmb250OiBcIm5vcm1hbCAxOHB4IFxcXCLjg5Ljg6njgq7jg47op5LjgrQgUHJvIFczXFxcIiwgXFxcIkhpcmFnaW5vIEtha3UgR290aGljIFByb1xcXCIsT3Nha2EsIFxcXCLjg6HjgqTjg6rjgqpcXFwiLCBNZWlyeW8sIFxcXCLvvK3vvLMg77yw44K044K344OD44KvXFxcIiwgXFxcIk1TIFBHb3RoaWNcXFwiLCBzYW5zLXNlcmlmXCJ9XHJcbl07XHJcblxyXG4vLy5yZXYtY29ycmVjdFxyXG53ID0gW1xyXG5cdHt0ZXh0U2hhZG93Olwibm9uZVwifSxcclxuXHR7Ym9yZGVyOiBcIjFweFwifSxcclxuXHR7c29saWQ6IFwiIzA4OEEwOCAhaW1wb3J0YW50XCJ9LFxyXG5cdHtib3JkZXJSYWRpdXM6IFwiMTBweFwifSxcclxuXHR7YmFja2dyb3VuZENvbG9yOiBcIiMwODhBMDhcIn0sXHJcblx0e3BhZGRpbmc6IFwiNHB4XCJ9LFxyXG5cdHttYXJnaW46XCI0cHhcIn0sXHJcblx0e2NvbG9yOiBcIiNGRkZGRkZcIn0sXHJcblx0e2ZvbnQ6IFwibm9ybWFsIDE4cHggXFxcIuODkuODqeOCruODjuinkuOCtCBQcm8gVzNcXFwiLCBcXFwiSGlyYWdpbm8gS2FrdSBHb3RoaWMgUHJvXFxcIixPc2FrYSwgXFxcIuODoeOCpOODquOCqlxcXCIsIE1laXJ5bywgXFxcIu+8re+8syDvvLDjgrTjgrfjg4Pjgq9cXFwiLCBcXFwiTVMgUEdvdGhpY1xcXCIsIHNhbnMtc2VyaWZcIn1cclxuXTtcclxuXHJcbi8vI2FkZFxyXG53ID0gW1xyXG5cdHt3aWR0aDogd2luZG93Q29uZmlnLmFkZC53aWR0aH0sXHJcblx0e2hlaWdodDogd2luZG93Q29uZmlnLmFkZC5oZWlnaHR9LFxyXG5cdHttYXJnaW5MZWZ0OiAtd2luZG93Q29uZmlnLmFkZC53aWR0aC8yfVxyXG5dO1xyXG5cclxuLy8jZXhwb3J0LCAjaW1wb3J0XHJcbncgPSBbXHJcbntiYWNrZ3JvdW5kOiBcIiNmZmZcIn0sXHJcblx0e3dpZHRoOiB3aW5kb3dDb25maWcuZXhwb3J0SW1wb3J0LndpZHRofSxcclxuXHR7aGVpZ2h0OiB3aW5kb3dDb25maWcuZXhwb3J0SW1wb3J0LmhlaWdodH0sXHJcblx0e21hcmdpbkxlZnQ6IC13aW5kb3dDb25maWcuZXhwb3J0SW1wb3J0LndpZHRoLzJ9XHJcbl07XHJcblxyXG4vLyNlZGl0XHJcbncgPSBbXHJcblx0e3dpZHRoOiB3aW5kb3dDb25maWcuZWRpdC53aWR0aH0sXHJcblx0e2hlaWdodDogd2luZG93Q29uZmlnLmVkaXQuaGVpZ2h0fSxcclxuXHR7bWFyZ2luTGVmdDogLXdpbmRvd0NvbmZpZy5lZGl0LndpZHRoLzJ9XHJcbl07XHJcblxyXG4vLyNzZWxmc3R1ZHlcclxudyA9IFtcclxuXHR7bGVmdDogXCI1MCVcIn0sXHJcblx0e3dpZHRoOiB3aW5kb3dDb25maWcuc3R1ZHkud2lkdGh9LFxyXG5cdHtoZWlnaHQ6IHdpbmRvd0NvbmZpZy5zdHVkeS5oZWlnaHR9LFxyXG5cdHttYXJnaW5MZWZ0OiAtd2luZG93Q29uZmlnLnN0dWR5LndpZHRoLzJ9XHJcbl07XHJcblxyXG4vLyNyZXN1bHR3aW5kb3dcclxudyA9IFtcclxuXHR7bGVmdDpcIjUwJVwifSxcclxuXHR7d2lkdGg6IHdpbmRvd0NvbmZpZy5yZXN1bHQud2lkdGggKyBcInB4XCJ9LFxyXG5cdHtoZWlnaHQ6IHdpbmRvd0NvbmZpZy5yZXN1bHQuaGVpZ2h0ICsgXCJweFwifSxcclxuXHR7bWFyZ2luTGVmdDogLXdpbmRvd0NvbmZpZy5yZXN1bHQud2lkdGgvMiArIFwicHhcIn1cclxuXTtcclxuXHJcbi8vI0F1ZGlvQnV0dG9uXHJcbncgPSBbXHJcblx0e21hcmdpblRvcDogXCIzNXB4XCJ9LFxyXG5cdHtwb3NpdGlvbjogXCJyZWxhdGl2ZVwifSxcclxuXHR7ZGlzcGxheTogXCJpbmxpbmUgIWltcG9ydGFudFwifSxcclxuXHR7V2Via2l0TWFyZ2luQmVmb3JlOiBcIjUwcHhcIn1cclxuXTtcclxuXHJcbi8vYnV0dG9uLndrc3MtY2xvc2VcclxudyA9IFtcclxuXHR7ZmxvYXQ6IFwicmlnaHRcIn0sXHJcblx0e2JhY2tncm91bmRDb2xvcjogXCIjZmY0MDQwXCJ9LFxyXG5cdHtjb2xvcjogXCIjZmZmXCJ9LFxyXG5cdHtwYWRkaW5nOiBcIjBweFwifSxcclxuXHR7aGVpZ2h0OiBcIjI3cHhcIn0sXHJcblx0e3dpZHRoOiBcIjI3cHhcIn1cclxuXTtcclxuXHJcbi8vI3drc3MtY2xvc2VcclxudyA9IFtcclxuXHR7ZmxvYXQ6IFwicmlnaHRcIn0sXHJcblx0e2JhY2tncm91bmRDb2xvcjogXCIjZmY0MDQwXCJ9LFxyXG5cdHtjb2xvcjogXCIjZmZmXCJ9LFxyXG5cdHtwYWRkaW5nOiBcIjBweFwifSxcclxuXHR7aGVpZ2h0OiBcIjI3cHhcIn0sXHJcblx0e3dpZHRoOiBcIjI3cHhcIn1cclxuXTtcclxuXHJcbi8vI3drc3Mta2FuamksICNyZXYta2FuamlcclxudyA9IFtcclxuXHR7dGV4dEFsaWduOiBcImNlbnRlciAhaW1wb3J0YW50XCJ9LFxyXG5cdHtmb250U2l6ZTogXCI1MHB4ICFpbXBvcnRhbnRcIn0sXHJcblx0e2JhY2tncm91bmRDb2xvcjogXCIjOTQwMEQzICFpbXBvcnRhbnRcIn0sXHJcblx0e2NvbG9yOiBcIiNGRkZGRkYgIWltcG9ydGFudFwifSxcclxuXHR7Ym9yZGVyUmFkaXVzOiBcIjEwcHggMTBweCAwcHggMHB4XCJ9XHJcbl07XHJcblxyXG4vLyN3a3NzLXNvbHV0aW9uLCAjcmV2LXNvbHV0aW9uXHJcbncgPSBbXHJcblx0e3RleHRBbGlnbjogXCJjZW50ZXIgIWltcG9ydGFudFwifSxcclxuXHR7Zm9udFNpemU6IFwiMzBweCAhaW1wb3J0YW50XCJ9LFxyXG5cdHtjb2xvcjogXCIjRkZGRkZGXCJ9LFxyXG5cdHtwYWRkaW5nOiBcIjJweFwifVxyXG5dO1xyXG5cclxuLy8jd2tzcy10eXBlXHJcbncgPSBbXHJcblx0e3RleHRBbGlnbjogXCJjZW50ZXIgIWltcG9ydGFudFwifSxcclxuXHR7Zm9udFNpemU6IFwiMjRweCAhaW1wb3J0YW50XCJ9LFxyXG5cdHtiYWNrZ3JvdW5kQ29sb3I6IFwiIzY5Njk2OVwifSxcclxuXHR7Y29sb3I6IFwiI0ZGRkZGRiAhaW1wb3J0YW50XCJ9LFxyXG5cdHtib3JkZXJSYWRpdXM6IFwiMHB4IDBweCAxMHB4IDEwcHhcIn1cclxuXTtcclxuXHJcbi8vI3Jldi10eXBlXHJcbncgPSBbXHJcblx0e3RleHRBbGlnbjogXCJjZW50ZXIgIWltcG9ydGFudFwifSxcclxuXHR7Zm9udFNpemU6IFwiMjRweCAhaW1wb3J0YW50XCJ9LFxyXG5cdHtjb2xvcjogXCIjRkZGRkZGICFpbXBvcnRhbnRcIn0sXHJcblx0e2JvcmRlclJhZGl1czogXCIwcHggMHB4IDEwcHggMTBweFwifVxyXG5dO1xyXG4vLyN3a3NzLWlucHV0XHJcbncgPSBbXHJcblx0e3RleHRBbGlnbjogXCJjZW50ZXIgIWltcG9ydGFudFwifSxcclxuXHR7Zm9udFNpemU6IFwiNDBweCAhaW1wb3J0YW50XCJ9LFxyXG5cdHtoZWlnaHQ6IFwiODBweCAhaW1wb3J0YW50XCJ9LFxyXG5cdHtsaW5lSGVpZ2h0OiBcIm5vcm1hbCAhaW1wb3J0YW50XCJ9XHJcbl07XHJcblxyXG4vLyNyZXYtaW5wdXRcclxudyA9IFtcclxuXHR7dGV4dEFsaWduOiBcImNlbnRlciAhaW1wb3J0YW50XCJ9LFxyXG5cdHtmb250U2l6ZTogXCI0MHB4ICFpbXBvcnRhbnRcIn0sXHJcblx0e2hlaWdodDogXCI2MHB4ICFpbXBvcnRhbnRcIn0sXHJcblx0e2xpbmVIZWlnaHQ6IFwibm9ybWFsICFpbXBvcnRhbnRcIn1cclxuXTtcclxuXHJcbi8vLS0tLVxyXG5tb2R1bGUuZXhwb3J0cyA9IGNsYXNzV0tTUztcclxuLy9tb2R1bGUuZXhwb3J0cyA9IHdrc3R5bGVDU1M7Il19