You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
easy-markdown-editor/debug/simplemde.debug.js

14193 lines
1.3 MiB

/**
* simplemde v1.8.2
* Copyright Next Step Webs, Inc.
* @link https://github.com/NextStepWebs/simplemde-markdown-editor
* @license MIT
*/
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.SimpleMDE = f()}})(function(){var define,module,exports;return (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){
(function (global){
; Typo = global.Typo = require("D:\\My Web Sites\\simplemde-markdown-editor\\node_modules\\codemirror-spell-checker\\src\\js\\typo.js");
CodeMirror = global.CodeMirror = require("codemirror");
; var __browserify_shim_require__=require;(function browserifyShim(module, define, require) {
// Initialize data globally to reduce memory consumption
var num_loaded = 0;
var aff_loading = false;
var dic_loading = false;
var aff_data = "";
var dic_data = "";
var typo;
CodeMirror.defineMode("spell-checker", function(config, parserConfig) {
// Load AFF/DIC data
if(!aff_loading){
aff_loading = true;
var xhr_aff = new XMLHttpRequest();
xhr_aff.open("GET", "https://cdn.jsdelivr.net/codemirror.spell-checker/latest/en_US.aff", true);
xhr_aff.onload = function (e) {
if (xhr_aff.readyState === 4 && xhr_aff.status === 200) {
aff_data = xhr_aff.responseText;
num_loaded++;
if(num_loaded == 2){
typo = new Typo("en_US", aff_data, dic_data, {
platform: 'any'
});
}
}
};
xhr_aff.send(null);
}
if(!dic_loading){
dic_loading = true;
var xhr_dic = new XMLHttpRequest();
xhr_dic.open("GET", "https://cdn.jsdelivr.net/codemirror.spell-checker/latest/en_US.dic", true);
xhr_dic.onload = function (e) {
if (xhr_dic.readyState === 4 && xhr_dic.status === 200) {
dic_data = xhr_dic.responseText;
num_loaded++;
if(num_loaded == 2){
typo = new Typo("en_US", aff_data, dic_data, {
platform: 'any'
});
}
}
};
xhr_dic.send(null);
}
// Define what separates a word
var rx_word = "!\"#$%&()*+,-./:;<=>?@[\\]^_`{|}~ ";
// Create the overlay and such
var overlay = {
token: function(stream, state) {
var ch = stream.peek();
var word = "";
if(rx_word.includes(ch)) {
stream.next();
return null;
}
while((ch = stream.peek()) != null && !rx_word.includes(ch)) {
word += ch;
stream.next();
}
if(typo && !typo.check(word))
return "spell-error"; // CSS class: cm-spell-error
return null;
}
};
var mode = CodeMirror.getMode(
config, config.backdrop || "text/plain"
);
return CodeMirror.overlayMode(mode, overlay, true);
});
// Because some browsers don't support this functionality yet
if(!String.prototype.includes) {
String.prototype.includes = function() {'use strict';
return String.prototype.indexOf.apply(this, arguments) !== -1;
};
}
}).call(global, module, undefined, undefined);
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"D:\\My Web Sites\\simplemde-markdown-editor\\node_modules\\codemirror-spell-checker\\src\\js\\typo.js":2,"codemirror":6}],2:[function(require,module,exports){
(function (global){
; var __browserify_shim_require__=require;(function browserifyShim(module, exports, require, define, browserify_shim__define__module__export__) {
'use strict';
/**
* Typo is a JavaScript implementation of a spellchecker using hunspell-style
* dictionaries.
*/
/**
* Typo constructor.
*
* @param {String} [dictionary] The locale code of the dictionary being used. e.g.,
* "en_US". This is only used to auto-load dictionaries.
* @param {String} [affData] The data from the dictionary's .aff file. If omitted
* and the first argument is supplied, in "chrome" platform,
* the .aff file will be loaded automatically from
* lib/typo/dictionaries/[dictionary]/[dictionary].aff
* In other platform, it will be loaded from
* [setting.path]/dictionaries/[dictionary]/[dictionary].aff
* @param {String} [wordsData] The data from the dictionary's .dic file. If omitted,
* and the first argument is supplied, in "chrome" platform,
* the .dic file will be loaded automatically from
* lib/typo/dictionaries/[dictionary]/[dictionary].dic
* In other platform, it will be loaded from
* [setting.path]/dictionaries/[dictionary]/[dictionary].dic
* @param {Object} [settings] Constructor settings. Available properties are:
* {String} [platform]: "chrome" for Chrome Extension or other
* value for the usual web.
* {String} [dictionaryPath]: path to load dictionary from in non-chrome
* environment.
* {Object} [flags]: flag information.
*
*
* @returns {Typo} A Typo object.
*/
var Typo = function (dictionary, affData, wordsData, settings) {
settings = settings || {};
/** Determines the method used for auto-loading .aff and .dic files. **/
this.platform = settings.platform || "chrome";
this.dictionary = null;
this.rules = {};
this.dictionaryTable = {};
this.compoundRules = [];
this.compoundRuleCodes = {};
this.replacementTable = [];
this.flags = settings.flags || {};
if (dictionary) {
this.dictionary = dictionary;
if (this.platform == "chrome") {
if (!affData) affData = this._readFile(chrome.extension.getURL("lib/typo/dictionaries/" + dictionary + "/" + dictionary + ".aff"));
if (!wordsData) wordsData = this._readFile(chrome.extension.getURL("lib/typo/dictionaries/" + dictionary + "/" + dictionary + ".dic"));
} else {
var path = settings.dictionaryPath || '';
if (!affData) affData = this._readFile(path + "/" + dictionary + "/" + dictionary + ".aff");
if (!wordsData) wordsData = this._readFile(path + "/" + dictionary + "/" + dictionary + ".dic");
}
this.rules = this._parseAFF(affData);
// Save the rule codes that are used in compound rules.
this.compoundRuleCodes = {};
for (var i = 0, _len = this.compoundRules.length; i < _len; i++) {
var rule = this.compoundRules[i];
for (var j = 0, _jlen = rule.length; j < _jlen; j++) {
this.compoundRuleCodes[rule[j]] = [];
}
}
// If we add this ONLYINCOMPOUND flag to this.compoundRuleCodes, then _parseDIC
// will do the work of saving the list of words that are compound-only.
if ("ONLYINCOMPOUND" in this.flags) {
this.compoundRuleCodes[this.flags.ONLYINCOMPOUND] = [];
}
this.dictionaryTable = this._parseDIC(wordsData);
// Get rid of any codes from the compound rule codes that are never used
// (or that were special regex characters). Not especially necessary...
for (var i in this.compoundRuleCodes) {
if (this.compoundRuleCodes[i].length == 0) {
delete this.compoundRuleCodes[i];
}
}
// Build the full regular expressions for each compound rule.
// I have a feeling (but no confirmation yet) that this method of
// testing for compound words is probably slow.
for (var i = 0, _len = this.compoundRules.length; i < _len; i++) {
var ruleText = this.compoundRules[i];
var expressionText = "";
for (var j = 0, _jlen = ruleText.length; j < _jlen; j++) {
var character = ruleText[j];
if (character in this.compoundRuleCodes) {
expressionText += "(" + this.compoundRuleCodes[character].join("|") + ")";
}
else {
expressionText += character;
}
}
this.compoundRules[i] = new RegExp(expressionText, "i");
}
}
return this;
};
Typo.prototype = {
/**
* Loads a Typo instance from a hash of all of the Typo properties.
*
* @param object obj A hash of Typo properties, probably gotten from a JSON.parse(JSON.stringify(typo_instance)).
*/
load : function (obj) {
for (var i in obj) {
this[i] = obj[i];
}
return this;
},
/**
* Read the contents of a file.
*
* @param {String} path The path (relative) to the file.
* @param {String} [charset="ISO8859-1"] The expected charset of the file
* @returns string The file data.
*/
_readFile : function (path, charset) {
if (!charset) charset = "ISO8859-1";
var req = new XMLHttpRequest();
req.open("GET", path, false);
if (req.overrideMimeType)
req.overrideMimeType("text/plain; charset=" + charset);
req.send(null);
return req.responseText;
},
/**
* Parse the rules out from a .aff file.
*
* @param {String} data The contents of the affix file.
* @returns object The rules from the file.
*/
_parseAFF : function (data) {
var rules = {};
// Remove comment lines
data = this._removeAffixComments(data);
var lines = data.split("\n");
for (var i = 0, _len = lines.length; i < _len; i++) {
var line = lines[i];
var definitionParts = line.split(/\s+/);
var ruleType = definitionParts[0];
if (ruleType == "PFX" || ruleType == "SFX") {
var ruleCode = definitionParts[1];
var combineable = definitionParts[2];
var numEntries = parseInt(definitionParts[3], 10);
var entries = [];
for (var j = i + 1, _jlen = i + 1 + numEntries; j < _jlen; j++) {
var line = lines[j];
var lineParts = line.split(/\s+/);
var charactersToRemove = lineParts[2];
var additionParts = lineParts[3].split("/");
var charactersToAdd = additionParts[0];
if (charactersToAdd === "0") charactersToAdd = "";
var continuationClasses = this.parseRuleCodes(additionParts[1]);
var regexToMatch = lineParts[4];
var entry = {};
entry.add = charactersToAdd;
if (continuationClasses.length > 0) entry.continuationClasses = continuationClasses;
if (regexToMatch !== ".") {
if (ruleType === "SFX") {
entry.match = new RegExp(regexToMatch + "$");
}
else {
entry.match = new RegExp("^" + regexToMatch);
}
}
if (charactersToRemove != "0") {
if (ruleType === "SFX") {
entry.remove = new RegExp(charactersToRemove + "$");
}
else {
entry.remove = charactersToRemove;
}
}
entries.push(entry);
}
rules[ruleCode] = { "type" : ruleType, "combineable" : (combineable == "Y"), "entries" : entries };
i += numEntries;
}
else if (ruleType === "COMPOUNDRULE") {
var numEntries = parseInt(definitionParts[1], 10);
for (var j = i + 1, _jlen = i + 1 + numEntries; j < _jlen; j++) {
var line = lines[j];
var lineParts = line.split(/\s+/);
this.compoundRules.push(lineParts[1]);
}
i += numEntries;
}
else if (ruleType === "REP") {
var lineParts = line.split(/\s+/);
if (lineParts.length === 3) {
this.replacementTable.push([ lineParts[1], lineParts[2] ]);
}
}
else {
// ONLYINCOMPOUND
// COMPOUNDMIN
// FLAG
// KEEPCASE
// NEEDAFFIX
this.flags[ruleType] = definitionParts[1];
}
}
return rules;
},
/**
* Removes comment lines and then cleans up blank lines and trailing whitespace.
*
* @param {String} data The data from an affix file.
* @return {String} The cleaned-up data.
*/
_removeAffixComments : function (data) {
// Remove comments
data = data.replace(/#.*$/mg, "");
// Trim each line
data = data.replace(/^\s\s*/m, '').replace(/\s\s*$/m, '');
// Remove blank lines.
data = data.replace(/\n{2,}/g, "\n");
// Trim the entire string
data = data.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
return data;
},
/**
* Parses the words out from the .dic file.
*
* @param {String} data The data from the dictionary file.
* @returns object The lookup table containing all of the words and
* word forms from the dictionary.
*/
_parseDIC : function (data) {
data = this._removeDicComments(data);
var lines = data.split("\n");
var dictionaryTable = {};
function addWord(word, rules) {
// Some dictionaries will list the same word multiple times with different rule sets.
if (!(word in dictionaryTable) || typeof dictionaryTable[word] != 'object') {
dictionaryTable[word] = [];
}
dictionaryTable[word].push(rules);
}
// The first line is the number of words in the dictionary.
for (var i = 1, _len = lines.length; i < _len; i++) {
var line = lines[i];
var parts = line.split("/", 2);
var word = parts[0];
// Now for each affix rule, generate that form of the word.
if (parts.length > 1) {
var ruleCodesArray = this.parseRuleCodes(parts[1]);
// Save the ruleCodes for compound word situations.
if (!("NEEDAFFIX" in this.flags) || ruleCodesArray.indexOf(this.flags.NEEDAFFIX) == -1) {
addWord(word, ruleCodesArray);
}
for (var j = 0, _jlen = ruleCodesArray.length; j < _jlen; j++) {
var code = ruleCodesArray[j];
var rule = this.rules[code];
if (rule) {
var newWords = this._applyRule(word, rule);
for (var ii = 0, _iilen = newWords.length; ii < _iilen; ii++) {
var newWord = newWords[ii];
addWord(newWord, []);
if (rule.combineable) {
for (var k = j + 1; k < _jlen; k++) {
var combineCode = ruleCodesArray[k];
var combineRule = this.rules[combineCode];
if (combineRule) {
if (combineRule.combineable && (rule.type != combineRule.type)) {
var otherNewWords = this._applyRule(newWord, combineRule);
for (var iii = 0, _iiilen = otherNewWords.length; iii < _iiilen; iii++) {
var otherNewWord = otherNewWords[iii];
addWord(otherNewWord, []);
}
}
}
}
}
}
}
if (code in this.compoundRuleCodes) {
this.compoundRuleCodes[code].push(word);
}
}
}
else {
addWord(word.trim(), []);
}
}
return dictionaryTable;
},
/**
* Removes comment lines and then cleans up blank lines and trailing whitespace.
*
* @param {String} data The data from a .dic file.
* @return {String} The cleaned-up data.
*/
_removeDicComments : function (data) {
// I can't find any official documentation on it, but at least the de_DE
// dictionary uses tab-indented lines as comments.
// Remove comments
data = data.replace(/^\t.*$/mg, "");
return data;
// Trim each line
data = data.replace(/^\s\s*/m, '').replace(/\s\s*$/m, '');
// Remove blank lines.
data = data.replace(/\n{2,}/g, "\n");
// Trim the entire string
data = data.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
return data;
},
parseRuleCodes : function (textCodes) {
if (!textCodes) {
return [];
}
else if (!("FLAG" in this.flags)) {
return textCodes.split("");
}
else if (this.flags.FLAG === "long") {
var flags = [];
for (var i = 0, _len = textCodes.length; i < _len; i += 2) {
flags.push(textCodes.substr(i, 2));
}
return flags;
}
else if (this.flags.FLAG === "num") {
return textCode.split(",");
}
},
/**
* Applies an affix rule to a word.
*
* @param {String} word The base word.
* @param {Object} rule The affix rule.
* @returns {String[]} The new words generated by the rule.
*/
_applyRule : function (word, rule) {
var entries = rule.entries;
var newWords = [];
for (var i = 0, _len = entries.length; i < _len; i++) {
var entry = entries[i];
if (!entry.match || word.match(entry.match)) {
var newWord = word;
if (entry.remove) {
newWord = newWord.replace(entry.remove, "");
}
if (rule.type === "SFX") {
newWord = newWord + entry.add;
}
else {
newWord = entry.add + newWord;
}
newWords.push(newWord);
if ("continuationClasses" in entry) {
for (var j = 0, _jlen = entry.continuationClasses.length; j < _jlen; j++) {
var continuationRule = this.rules[entry.continuationClasses[j]];
if (continuationRule) {
newWords = newWords.concat(this._applyRule(newWord, continuationRule));
}
/*
else {
// This shouldn't happen, but it does, at least in the de_DE dictionary.
// I think the author mistakenly supplied lower-case rule codes instead
// of upper-case.
}
*/
}
}
}
}
return newWords;
},
/**
* Checks whether a word or a capitalization variant exists in the current dictionary.
* The word is trimmed and several variations of capitalizations are checked.
* If you want to check a word without any changes made to it, call checkExact()
*
* @see http://blog.stevenlevithan.com/archives/faster-trim-javascript re:trimming function
*
* @param {String} aWord The word to check.
* @returns {Boolean}
*/
check : function (aWord) {
// Remove leading and trailing whitespace
var trimmedWord = aWord.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
if (this.checkExact(trimmedWord)) {
return true;
}
// The exact word is not in the dictionary.
if (trimmedWord.toUpperCase() === trimmedWord) {
// The word was supplied in all uppercase.
// Check for a capitalized form of the word.
var capitalizedWord = trimmedWord[0] + trimmedWord.substring(1).toLowerCase();
if (this.hasFlag(capitalizedWord, "KEEPCASE")) {
// Capitalization variants are not allowed for this word.
return false;
}
if (this.checkExact(capitalizedWord)) {
return true;
}
}
var lowercaseWord = trimmedWord.toLowerCase();
if (lowercaseWord !== trimmedWord) {
if (this.hasFlag(lowercaseWord, "KEEPCASE")) {
// Capitalization variants are not allowed for this word.
return false;
}
// Check for a lowercase form
if (this.checkExact(lowercaseWord)) {
return true;
}
}
return false;
},
/**
* Checks whether a word exists in the current dictionary.
*
* @param {String} word The word to check.
* @returns {Boolean}
*/
checkExact : function (word) {
var ruleCodes = this.dictionaryTable[word];
if (typeof ruleCodes === 'undefined') {
// Check if this might be a compound word.
if ("COMPOUNDMIN" in this.flags && word.length >= this.flags.COMPOUNDMIN) {
for (var i = 0, _len = this.compoundRules.length; i < _len; i++) {
if (word.match(this.compoundRules[i])) {
return true;
}
}
}
return false;
}
else {
for (var i = 0, _len = ruleCodes.length; i < _len; i++) {
if (!this.hasFlag(word, "ONLYINCOMPOUND", ruleCodes[i])) {
return true;
}
}
return false;
}
},
/**
* Looks up whether a given word is flagged with a given flag.
*
* @param {String} word The word in question.
* @param {String} flag The flag in question.
* @return {Boolean}
*/
hasFlag : function (word, flag, wordFlags) {
if (flag in this.flags) {
if (typeof wordFlags === 'undefined') {
var wordFlags = Array.prototype.concat.apply([], this.dictionaryTable[word]);
}
if (wordFlags && wordFlags.indexOf(this.flags[flag]) !== -1) {
return true;
}
}
return false;
},
/**
* Returns a list of suggestions for a misspelled word.
*
* @see http://www.norvig.com/spell-correct.html for the basis of this suggestor.
* This suggestor is primitive, but it works.
*
* @param {String} word The misspelling.
* @param {Number} [limit=5] The maximum number of suggestions to return.
* @returns {String[]} The array of suggestions.
*/
alphabet : "",
suggest : function (word, limit) {
if (!limit) limit = 5;
if (this.check(word)) return [];
// Check the replacement table.
for (var i = 0, _len = this.replacementTable.length; i < _len; i++) {
var replacementEntry = this.replacementTable[i];
if (word.indexOf(replacementEntry[0]) !== -1) {
var correctedWord = word.replace(replacementEntry[0], replacementEntry[1]);
if (this.check(correctedWord)) {
return [ correctedWord ];
}
}
}
var self = this;
self.alphabet = "abcdefghijklmnopqrstuvwxyz";
/*
if (!self.alphabet) {
// Use the alphabet as implicitly defined by the words in the dictionary.
var alphaHash = {};
for (var i in self.dictionaryTable) {
for (var j = 0, _len = i.length; j < _len; j++) {
alphaHash[i[j]] = true;
}
}
for (var i in alphaHash) {
self.alphabet += i;
}
var alphaArray = self.alphabet.split("");
alphaArray.sort();
self.alphabet = alphaArray.join("");
}
*/
function edits1(words) {
var rv = [];
for (var ii = 0, _iilen = words.length; ii < _iilen; ii++) {
var word = words[ii];
var splits = [];
for (var i = 0, _len = word.length + 1; i < _len; i++) {
splits.push([ word.substring(0, i), word.substring(i, word.length) ]);
}
var deletes = [];
for (var i = 0, _len = splits.length; i < _len; i++) {
var s = splits[i];
if (s[1]) {
deletes.push(s[0] + s[1].substring(1));
}
}
var transposes = [];
for (var i = 0, _len = splits.length; i < _len; i++) {
var s = splits[i];
if (s[1].length > 1) {
transposes.push(s[0] + s[1][1] + s[1][0] + s[1].substring(2));
}
}
var replaces = [];
for (var i = 0, _len = splits.length; i < _len; i++) {
var s = splits[i];
if (s[1]) {
for (var j = 0, _jlen = self.alphabet.length; j < _jlen; j++) {
replaces.push(s[0] + self.alphabet[j] + s[1].substring(1));
}
}
}
var inserts = [];
for (var i = 0, _len = splits.length; i < _len; i++) {
var s = splits[i];
if (s[1]) {
for (var j = 0, _jlen = self.alphabet.length; j < _jlen; j++) {
replaces.push(s[0] + self.alphabet[j] + s[1]);
}
}
}
rv = rv.concat(deletes);
rv = rv.concat(transposes);
rv = rv.concat(replaces);
rv = rv.concat(inserts);
}
return rv;
}
function known(words) {
var rv = [];
for (var i = 0; i < words.length; i++) {
if (self.check(words[i])) {
rv.push(words[i]);
}
}
return rv;
}
function correct(word) {
// Get the edit-distance-1 and edit-distance-2 forms of this word.
var ed1 = edits1([word]);
var ed2 = edits1(ed1);
var corrections = known(ed1).concat(known(ed2));
// Sort the edits based on how many different ways they were created.
var weighted_corrections = {};
for (var i = 0, _len = corrections.length; i < _len; i++) {
if (!(corrections[i] in weighted_corrections)) {
weighted_corrections[corrections[i]] = 1;
}
else {
weighted_corrections[corrections[i]] += 1;
}
}
var sorted_corrections = [];
for (var i in weighted_corrections) {
sorted_corrections.push([ i, weighted_corrections[i] ]);
}
function sorter(a, b) {
if (a[1] < b[1]) {
return -1;
}
return 1;
}
sorted_corrections.sort(sorter).reverse();
var rv = [];
for (var i = 0, _len = Math.min(limit, sorted_corrections.length); i < _len; i++) {
if (!self.hasFlag(sorted_corrections[i][0], "NOSUGGEST")) {
rv.push(sorted_corrections[i][0]);
}
}
return rv;
}
return correct(word);
}
};
; browserify_shim__define__module__export__(typeof Typo != "undefined" ? Typo : window.Typo);
}).call(global, undefined, undefined, undefined, undefined, function defineExport(ex) { module.exports = ex; });
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],3:[function(require,module,exports){
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineOption("fullScreen", false, function(cm, val, old) {
if (old == CodeMirror.Init) old = false;
if (!old == !val) return;
if (val) setFullscreen(cm);
else setNormal(cm);
});
function setFullscreen(cm) {
var wrap = cm.getWrapperElement();
cm.state.fullScreenRestore = {scrollTop: window.pageYOffset, scrollLeft: window.pageXOffset,
width: wrap.style.width, height: wrap.style.height};
wrap.style.width = "";
wrap.style.height = "auto";
wrap.className += " CodeMirror-fullscreen";
document.documentElement.style.overflow = "hidden";
cm.refresh();
}
function setNormal(cm) {
var wrap = cm.getWrapperElement();
wrap.className = wrap.className.replace(/\s*CodeMirror-fullscreen\b/, "");
document.documentElement.style.overflow = "";
var info = cm.state.fullScreenRestore;
wrap.style.width = info.width; wrap.style.height = info.height;
window.scrollTo(info.scrollLeft, info.scrollTop);
cm.refresh();
}
});
},{"../../lib/codemirror":6}],4:[function(require,module,exports){
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var listRE = /^(\s*)(>[> ]*|[*+-]\s|(\d+)([.)]))(\s*)/,
emptyListRE = /^(\s*)(>[> ]*|[*+-]|(\d+)[.)])(\s*)$/,
unorderedListRE = /[*+-]\s/;
CodeMirror.commands.newlineAndIndentContinueMarkdownList = function(cm) {
if (cm.getOption("disableInput")) return CodeMirror.Pass;
var ranges = cm.listSelections(), replacements = [];
for (var i = 0; i < ranges.length; i++) {
var pos = ranges[i].head;
var eolState = cm.getStateAfter(pos.line);
var inList = eolState.list !== false;
var inQuote = eolState.quote !== 0;
var line = cm.getLine(pos.line), match = listRE.exec(line);
if (!ranges[i].empty() || (!inList && !inQuote) || !match) {
cm.execCommand("newlineAndIndent");
return;
}
if (emptyListRE.test(line)) {
cm.replaceRange("", {
line: pos.line, ch: 0
}, {
line: pos.line, ch: pos.ch + 1
});
replacements[i] = "\n";
} else {
var indent = match[1], after = match[5];
var bullet = unorderedListRE.test(match[2]) || match[2].indexOf(">") >= 0
? match[2]
: (parseInt(match[3], 10) + 1) + match[4];
replacements[i] = "\n" + indent + bullet + after;
}
}
cm.replaceSelections(replacements);
};
});
},{"../../lib/codemirror":6}],5:[function(require,module,exports){
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// Utility function that allows modes to be combined. The mode given
// as the base argument takes care of most of the normal mode
// functionality, but a second (typically simple) mode is used, which
// can override the style of text. Both modes get to parse all of the
// text, but when both assign a non-null style to a piece of code, the
// overlay wins, unless the combine argument was true and not overridden,
// or state.overlay.combineTokens was true, in which case the styles are
// combined.
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.overlayMode = function(base, overlay, combine) {
return {
startState: function() {
return {
base: CodeMirror.startState(base),
overlay: CodeMirror.startState(overlay),
basePos: 0, baseCur: null,
overlayPos: 0, overlayCur: null,
streamSeen: null
};
},
copyState: function(state) {
return {
base: CodeMirror.copyState(base, state.base),
overlay: CodeMirror.copyState(overlay, state.overlay),
basePos: state.basePos, baseCur: null,
overlayPos: state.overlayPos, overlayCur: null
};
},
token: function(stream, state) {
if (stream != state.streamSeen ||
Math.min(state.basePos, state.overlayPos) < stream.start) {
state.streamSeen = stream;
state.basePos = state.overlayPos = stream.start;
}
if (stream.start == state.basePos) {
state.baseCur = base.token(stream, state.base);
state.basePos = stream.pos;
}
if (stream.start == state.overlayPos) {
stream.pos = stream.start;
state.overlayCur = overlay.token(stream, state.overlay);
state.overlayPos = stream.pos;
}
stream.pos = Math.min(state.basePos, state.overlayPos);
// state.overlay.combineTokens always takes precedence over combine,
// unless set to null
if (state.overlayCur == null) return state.baseCur;
else if (state.baseCur != null &&
state.overlay.combineTokens ||
combine && state.overlay.combineTokens == null)
return state.baseCur + " " + state.overlayCur;
else return state.overlayCur;
},
indent: base.indent && function(state, textAfter) {
return base.indent(state.base, textAfter);
},
electricChars: base.electricChars,
innerMode: function(state) { return {state: state.base, mode: base}; },
blankLine: function(state) {
if (base.blankLine) base.blankLine(state.base);
if (overlay.blankLine) overlay.blankLine(state.overlay);
}
};
};
});
},{"../../lib/codemirror":6}],6:[function(require,module,exports){
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
// This is CodeMirror (http://codemirror.net), a code editor
// implemented in JavaScript on top of the browser's DOM.
//
// You can find some technical background for some of the code below
// at http://marijnhaverbeke.nl/blog/#cm-internals .
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
module.exports = mod();
else if (typeof define == "function" && define.amd) // AMD
return define([], mod);
else // Plain browser env
this.CodeMirror = mod();
})(function() {
"use strict";
// BROWSER SNIFFING
// Kludges for bugs and behavior differences that can't be feature
// detected are enabled based on userAgent etc sniffing.
var userAgent = navigator.userAgent;
var platform = navigator.platform;
var gecko = /gecko\/\d/i.test(userAgent);
var ie_upto10 = /MSIE \d/.test(userAgent);
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
var ie = ie_upto10 || ie_11up;
var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : ie_11up[1]);
var webkit = /WebKit\//.test(userAgent);
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
var chrome = /Chrome\//.test(userAgent);
var presto = /Opera\//.test(userAgent);
var safari = /Apple Computer/.test(navigator.vendor);
var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
var phantom = /PhantomJS/.test(userAgent);
var ios = /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
// This is woefully incomplete. Suggestions for alternative methods welcome.
var mobile = ios || /Android|webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
var mac = ios || /Mac/.test(platform);
var windows = /win/i.test(platform);
var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
if (presto_version) presto_version = Number(presto_version[1]);
if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
var captureRightClick = gecko || (ie && ie_version >= 9);
// Optimize some code when these features are not used.
var sawReadOnlySpans = false, sawCollapsedSpans = false;
// EDITOR CONSTRUCTOR
// A CodeMirror instance represents an editor. This is the object
// that user code is usually dealing with.
function CodeMirror(place, options) {
if (!(this instanceof CodeMirror)) return new CodeMirror(place, options);
this.options = options = options ? copyObj(options) : {};
// Determine effective options based on given values and defaults.
copyObj(defaults, options, false);
setGuttersForLineNumbers(options);
var doc = options.value;
if (typeof doc == "string") doc = new Doc(doc, options.mode, null, options.lineSeparator);
this.doc = doc;
var input = new CodeMirror.inputStyles[options.inputStyle](this);
var display = this.display = new Display(place, doc, input);
display.wrapper.CodeMirror = this;
updateGutters(this);
themeChanged(this);
if (options.lineWrapping)
this.display.wrapper.className += " CodeMirror-wrap";
if (options.autofocus && !mobile) display.input.focus();
initScrollbars(this);
this.state = {
keyMaps: [], // stores maps added by addKeyMap
overlays: [], // highlighting overlays, as added by addOverlay
modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
overwrite: false,
delayingBlurEvent: false,
focused: false,
suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
selectingText: false,
draggingText: false,
highlight: new Delayed(), // stores highlight worker timeout
keySeq: null, // Unfinished key sequence
specialChars: null
};
var cm = this;
// Override magic textarea content restore that IE sometimes does
// on our hidden textarea on reload
if (ie && ie_version < 11) setTimeout(function() { cm.display.input.reset(true); }, 20);
registerEventHandlers(this);
ensureGlobalHandlers();
startOperation(this);
this.curOp.forceUpdate = true;
attachDoc(this, doc);
if ((options.autofocus && !mobile) || cm.hasFocus())
setTimeout(bind(onFocus, this), 20);
else
onBlur(this);
for (var opt in optionHandlers) if (optionHandlers.hasOwnProperty(opt))
optionHandlers[opt](this, options[opt], Init);
maybeUpdateLineNumberWidth(this);
if (options.finishInit) options.finishInit(this);
for (var i = 0; i < initHooks.length; ++i) initHooks[i](this);
endOperation(this);
// Suppress optimizelegibility in Webkit, since it breaks text
// measuring on line wrapping boundaries.
if (webkit && options.lineWrapping &&
getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
display.lineDiv.style.textRendering = "auto";
}
// DISPLAY CONSTRUCTOR
// The display handles the DOM integration, both for input reading
// and content drawing. It holds references to DOM nodes and
// display-related state.
function Display(place, doc, input) {
var d = this;
this.input = input;
// Covers bottom-right square when both scrollbars are present.
d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
d.scrollbarFiller.setAttribute("cm-not-content", "true");
// Covers bottom of gutter when coverGutterNextToScrollbar is on
// and h scrollbar is present.
d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
d.gutterFiller.setAttribute("cm-not-content", "true");
// Will contain the actual code, positioned to cover the viewport.
d.lineDiv = elt("div", null, "CodeMirror-code");
// Elements are added to these to represent selection and cursors.
d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
d.cursorDiv = elt("div", null, "CodeMirror-cursors");
// A visibility: hidden element used to find the size of things.
d.measure = elt("div", null, "CodeMirror-measure");
// When lines outside of the viewport are measured, they are drawn in this.
d.lineMeasure = elt("div", null, "CodeMirror-measure");
// Wraps everything that needs to exist inside the vertically-padded coordinate system
d.lineSpace = elt("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
null, "position: relative; outline: none");
// Moved around its parent to cover visible view.
d.mover = elt("div", [elt("div", [d.lineSpace], "CodeMirror-lines")], null, "position: relative");
// Set to the height of the document, allowing scrolling.
d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
d.sizerWidth = null;
// Behavior of elts with overflow: auto and padding is
// inconsistent across browsers. This is used to ensure the
// scrollable area is big enough.
d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
// Will contain the gutters, if any.
d.gutters = elt("div", null, "CodeMirror-gutters");
d.lineGutter = null;
// Actual scrollable element.
d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
d.scroller.setAttribute("tabIndex", "-1");
// The element in which the editor lives.
d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
// Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
if (!webkit && !(gecko && mobile)) d.scroller.draggable = true;
if (place) {
if (place.appendChild) place.appendChild(d.wrapper);
else place(d.wrapper);
}
// Current rendered range (may be bigger than the view window).
d.viewFrom = d.viewTo = doc.first;
d.reportedViewFrom = d.reportedViewTo = doc.first;
// Information about the rendered lines.
d.view = [];
d.renderedView = null;
// Holds info about a single rendered line when it was rendered
// for measurement, while not in view.
d.externalMeasured = null;
// Empty space (in pixels) above the view
d.viewOffset = 0;
d.lastWrapHeight = d.lastWrapWidth = 0;
d.updateLineNumbers = null;
d.nativeBarWidth = d.barHeight = d.barWidth = 0;
d.scrollbarsClipped = false;
// Used to only resize the line number gutter when necessary (when
// the amount of lines crosses a boundary that makes its width change)
d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
// Set to true when a non-horizontal-scrolling line widget is
// added. As an optimization, line widget aligning is skipped when
// this is false.
d.alignWidgets = false;
d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
// Tracks the maximum line length so that the horizontal scrollbar
// can be kept static when scrolling.
d.maxLine = null;
d.maxLineLength = 0;
d.maxLineChanged = false;
// Used for measuring wheel scrolling granularity
d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
// True when shift is held down.
d.shift = false;
// Used to track whether anything happened since the context menu
// was opened.
d.selForContextMenu = null;
d.activeTouch = null;
input.init(d);
}
// STATE UPDATES
// Used to get the editor into a consistent state again when options change.
function loadMode(cm) {
cm.doc.mode = CodeMirror.getMode(cm.options, cm.doc.modeOption);
resetModeState(cm);
}
function resetModeState(cm) {
cm.doc.iter(function(line) {
if (line.stateAfter) line.stateAfter = null;
if (line.styles) line.styles = null;
});
cm.doc.frontier = cm.doc.first;
startWorker(cm, 100);
cm.state.modeGen++;
if (cm.curOp) regChange(cm);
}
function wrappingChanged(cm) {
if (cm.options.lineWrapping) {
addClass(cm.display.wrapper, "CodeMirror-wrap");
cm.display.sizer.style.minWidth = "";
cm.display.sizerWidth = null;
} else {
rmClass(cm.display.wrapper, "CodeMirror-wrap");
findMaxLine(cm);
}
estimateLineHeights(cm);
regChange(cm);
clearCaches(cm);
setTimeout(function(){updateScrollbars(cm);}, 100);
}
// Returns a function that estimates the height of a line, to use as
// first approximation until the line becomes visible (and is thus
// properly measurable).
function estimateHeight(cm) {
var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
return function(line) {
if (lineIsHidden(cm.doc, line)) return 0;
var widgetsHeight = 0;
if (line.widgets) for (var i = 0; i < line.widgets.length; i++) {
if (line.widgets[i].height) widgetsHeight += line.widgets[i].height;
}
if (wrapping)
return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th;
else
return widgetsHeight + th;
};
}
function estimateLineHeights(cm) {
var doc = cm.doc, est = estimateHeight(cm);
doc.iter(function(line) {
var estHeight = est(line);
if (estHeight != line.height) updateLineHeight(line, estHeight);
});
}
function themeChanged(cm) {
cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
clearCaches(cm);
}
function guttersChanged(cm) {
updateGutters(cm);
regChange(cm);
setTimeout(function(){alignHorizontally(cm);}, 20);
}
// Rebuild the gutter elements, ensure the margin to the left of the
// code matches their width.
function updateGutters(cm) {
var gutters = cm.display.gutters, specs = cm.options.gutters;
removeChildren(gutters);
for (var i = 0; i < specs.length; ++i) {
var gutterClass = specs[i];
var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
if (gutterClass == "CodeMirror-linenumbers") {
cm.display.lineGutter = gElt;
gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
}
}
gutters.style.display = i ? "" : "none";
updateGutterSpace(cm);
}
function updateGutterSpace(cm) {
var width = cm.display.gutters.offsetWidth;
cm.display.sizer.style.marginLeft = width + "px";
}
// Compute the character length of a line, taking into account
// collapsed ranges (see markText) that might hide parts, and join
// other lines onto it.
function lineLength(line) {
if (line.height == 0) return 0;
var len = line.text.length, merged, cur = line;
while (merged = collapsedSpanAtStart(cur)) {
var found = merged.find(0, true);
cur = found.from.line;
len += found.from.ch - found.to.ch;
}
cur = line;
while (merged = collapsedSpanAtEnd(cur)) {
var found = merged.find(0, true);
len -= cur.text.length - found.from.ch;
cur = found.to.line;
len += cur.text.length - found.to.ch;
}
return len;
}
// Find the longest line in the document.
function findMaxLine(cm) {
var d = cm.display, doc = cm.doc;
d.maxLine = getLine(doc, doc.first);
d.maxLineLength = lineLength(d.maxLine);
d.maxLineChanged = true;
doc.iter(function(line) {
var len = lineLength(line);
if (len > d.maxLineLength) {
d.maxLineLength = len;
d.maxLine = line;
}
});
}
// Make sure the gutters options contains the element
// "CodeMirror-linenumbers" when the lineNumbers option is true.
function setGuttersForLineNumbers(options) {
var found = indexOf(options.gutters, "CodeMirror-linenumbers");
if (found == -1 && options.lineNumbers) {
options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
} else if (found > -1 && !options.lineNumbers) {
options.gutters = options.gutters.slice(0);
options.gutters.splice(found, 1);
}
}
// SCROLLBARS
// Prepare DOM reads needed to update the scrollbars. Done in one
// shot to minimize update/measure roundtrips.
function measureForScrollbars(cm) {
var d = cm.display, gutterW = d.gutters.offsetWidth;
var docH = Math.round(cm.doc.height + paddingVert(cm.display));
return {
clientHeight: d.scroller.clientHeight,
viewHeight: d.wrapper.clientHeight,
scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
viewWidth: d.wrapper.clientWidth,
barLeft: cm.options.fixedGutter ? gutterW : 0,
docHeight: docH,
scrollHeight: docH + scrollGap(cm) + d.barHeight,
nativeBarWidth: d.nativeBarWidth,
gutterWidth: gutterW
};
}
function NativeScrollbars(place, scroll, cm) {
this.cm = cm;
var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
place(vert); place(horiz);
on(vert, "scroll", function() {
if (vert.clientHeight) scroll(vert.scrollTop, "vertical");
});
on(horiz, "scroll", function() {
if (horiz.clientWidth) scroll(horiz.scrollLeft, "horizontal");
});
this.checkedZeroWidth = false;
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
if (ie && ie_version < 8) this.horiz.style.minHeight = this.vert.style.minWidth = "18px";
}
NativeScrollbars.prototype = copyObj({
update: function(measure) {
var needsH = measure.scrollWidth > measure.clientWidth + 1;
var needsV = measure.scrollHeight > measure.clientHeight + 1;
var sWidth = measure.nativeBarWidth;
if (needsV) {
this.vert.style.display = "block";
this.vert.style.bottom = needsH ? sWidth + "px" : "0";
var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
// A bug in IE8 can cause this value to be negative, so guard it.
this.vert.firstChild.style.height =
Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
} else {
this.vert.style.display = "";
this.vert.firstChild.style.height = "0";
}
if (needsH) {
this.horiz.style.display = "block";
this.horiz.style.right = needsV ? sWidth + "px" : "0";
this.horiz.style.left = measure.barLeft + "px";
var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
this.horiz.firstChild.style.width =
(measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
} else {
this.horiz.style.display = "";
this.horiz.firstChild.style.width = "0";
}
if (!this.checkedZeroWidth && measure.clientHeight > 0) {
if (sWidth == 0) this.zeroWidthHack();
this.checkedZeroWidth = true;
}
return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0};
},
setScrollLeft: function(pos) {
if (this.horiz.scrollLeft != pos) this.horiz.scrollLeft = pos;
if (this.disableHoriz) this.enableZeroWidthBar(this.horiz, this.disableHoriz);
},
setScrollTop: function(pos) {
if (this.vert.scrollTop != pos) this.vert.scrollTop = pos;
if (this.disableVert) this.enableZeroWidthBar(this.vert, this.disableVert);
},
zeroWidthHack: function() {
var w = mac && !mac_geMountainLion ? "12px" : "18px";
this.horiz.style.height = this.vert.style.width = w;
this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
this.disableHoriz = new Delayed;
this.disableVert = new Delayed;
},
enableZeroWidthBar: function(bar, delay) {
bar.style.pointerEvents = "auto";
function maybeDisable() {
// To find out whether the scrollbar is still visible, we
// check whether the element under the pixel in the bottom
// left corner of the scrollbar box is the scrollbar box
// itself (when the bar is still visible) or its filler child
// (when the bar is hidden). If it is still visible, we keep
// it enabled, if it's hidden, we disable pointer events.
var box = bar.getBoundingClientRect();
var elt = document.elementFromPoint(box.left + 1, box.bottom - 1);
if (elt != bar) bar.style.pointerEvents = "none";
else delay.set(1000, maybeDisable);
}
delay.set(1000, maybeDisable);
},
clear: function() {
var parent = this.horiz.parentNode;
parent.removeChild(this.horiz);
parent.removeChild(this.vert);
}
}, NativeScrollbars.prototype);
function NullScrollbars() {}
NullScrollbars.prototype = copyObj({
update: function() { return {bottom: 0, right: 0}; },
setScrollLeft: function() {},
setScrollTop: function() {},
clear: function() {}
}, NullScrollbars.prototype);
CodeMirror.scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
function initScrollbars(cm) {
if (cm.display.scrollbars) {
cm.display.scrollbars.clear();
if (cm.display.scrollbars.addClass)
rmClass(cm.display.wrapper, cm.display.scrollbars.addClass);
}
cm.display.scrollbars = new CodeMirror.scrollbarModel[cm.options.scrollbarStyle](function(node) {
cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
// Prevent clicks in the scrollbars from killing focus
on(node, "mousedown", function() {
if (cm.state.focused) setTimeout(function() { cm.display.input.focus(); }, 0);
});
node.setAttribute("cm-not-content", "true");
}, function(pos, axis) {
if (axis == "horizontal") setScrollLeft(cm, pos);
else setScrollTop(cm, pos);
}, cm);
if (cm.display.scrollbars.addClass)
addClass(cm.display.wrapper, cm.display.scrollbars.addClass);
}
function updateScrollbars(cm, measure) {
if (!measure) measure = measureForScrollbars(cm);
var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
updateScrollbarsInner(cm, measure);
for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
updateHeightsInViewport(cm);
updateScrollbarsInner(cm, measureForScrollbars(cm));
startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
}
}
// Re-synchronize the fake scrollbars with the actual size of the
// content.
function updateScrollbarsInner(cm, measure) {
var d = cm.display;
var sizes = d.scrollbars.update(measure);
d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
if (sizes.right && sizes.bottom) {
d.scrollbarFiller.style.display = "block";
d.scrollbarFiller.style.height = sizes.bottom + "px";
d.scrollbarFiller.style.width = sizes.right + "px";
} else d.scrollbarFiller.style.display = "";
if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
d.gutterFiller.style.display = "block";
d.gutterFiller.style.height = sizes.bottom + "px";
d.gutterFiller.style.width = measure.gutterWidth + "px";
} else d.gutterFiller.style.display = "";
}
// Compute the lines that are visible in a given viewport (defaults
// the the current scroll position). viewport may contain top,
// height, and ensure (see op.scrollToPos) properties.
function visibleLines(display, doc, viewport) {
var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
top = Math.floor(top - paddingTop(display));
var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
// Ensure is a {from: {line, ch}, to: {line, ch}} object, and
// forces those lines into the viewport (if possible).
if (viewport && viewport.ensure) {
var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
if (ensureFrom < from) {
from = ensureFrom;
to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
} else if (Math.min(ensureTo, doc.lastLine()) >= to) {
from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
to = ensureTo;
}
}
return {from: from, to: Math.max(to, from + 1)};
}
// LINE NUMBERS
// Re-align line numbers and gutter marks to compensate for
// horizontal scrolling.
function alignHorizontally(cm) {
var display = cm.display, view = display.view;
if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) return;
var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
var gutterW = display.gutters.offsetWidth, left = comp + "px";
for (var i = 0; i < view.length; i++) if (!view[i].hidden) {
if (cm.options.fixedGutter && view[i].gutter)
view[i].gutter.style.left = left;
var align = view[i].alignable;
if (align) for (var j = 0; j < align.length; j++)
align[j].style.left = left;
}
if (cm.options.fixedGutter)
display.gutters.style.left = (comp + gutterW) + "px";
}
// Used to ensure that the line number gutter is still the right
// size for the current document size. Returns true when an update
// is needed.
function maybeUpdateLineNumberWidth(cm) {
if (!cm.options.lineNumbers) return false;
var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
if (last.length != display.lineNumChars) {
var test = display.measure.appendChild(elt("div", [elt("div", last)],
"CodeMirror-linenumber CodeMirror-gutter-elt"));
var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
display.lineGutter.style.width = "";
display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
display.lineNumWidth = display.lineNumInnerWidth + padding;
display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
display.lineGutter.style.width = display.lineNumWidth + "px";
updateGutterSpace(cm);
return true;
}
return false;
}
function lineNumberFor(options, i) {
return String(options.lineNumberFormatter(i + options.firstLineNumber));
}
// Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
// but using getBoundingClientRect to get a sub-pixel-accurate
// result.
function compensateForHScroll(display) {
return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left;
}
// DISPLAY DRAWING
function DisplayUpdate(cm, viewport, force) {
var display = cm.display;
this.viewport = viewport;
// Store some values that we'll need later (but don't want to force a relayout for)
this.visible = visibleLines(display, cm.doc, viewport);
this.editorIsHidden = !display.wrapper.offsetWidth;
this.wrapperHeight = display.wrapper.clientHeight;
this.wrapperWidth = display.wrapper.clientWidth;
this.oldDisplayWidth = displayWidth(cm);
this.force = force;
this.dims = getDimensions(cm);
this.events = [];
}
DisplayUpdate.prototype.signal = function(emitter, type) {
if (hasHandler(emitter, type))
this.events.push(arguments);
};
DisplayUpdate.prototype.finish = function() {
for (var i = 0; i < this.events.length; i++)
signal.apply(null, this.events[i]);
};
function maybeClipScrollbars(cm) {
var display = cm.display;
if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
display.heightForcer.style.height = scrollGap(cm) + "px";
display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
display.scrollbarsClipped = true;
}
}
// Does the actual updating of the line display. Bails out
// (returning false) when there is nothing to be done and forced is
// false.
function updateDisplayIfNeeded(cm, update) {
var display = cm.display, doc = cm.doc;
if (update.editorIsHidden) {
resetView(cm);
return false;
}
// Bail out if the visible area is already rendered and nothing changed.
if (!update.force &&
update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
display.renderedView == display.view && countDirtyView(cm) == 0)
return false;
if (maybeUpdateLineNumberWidth(cm)) {
resetView(cm);
update.dims = getDimensions(cm);
}
// Compute a suitable new viewport (from & to)
var end = doc.first + doc.size;
var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
if (display.viewFrom < from && from - display.viewFrom < 20) from = Math.max(doc.first, display.viewFrom);
if (display.viewTo > to && display.viewTo - to < 20) to = Math.min(end, display.viewTo);
if (sawCollapsedSpans) {
from = visualLineNo(cm.doc, from);
to = visualLineEndNo(cm.doc, to);
}
var different = from != display.viewFrom || to != display.viewTo ||
display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
adjustView(cm, from, to);
display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
// Position the mover div to align with the current scroll position
cm.display.mover.style.top = display.viewOffset + "px";
var toUpdate = countDirtyView(cm);
if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
return false;
// For big changes, we hide the enclosing element during the
// update, since that speeds up the operations on most browsers.
var focused = activeElt();
if (toUpdate > 4) display.lineDiv.style.display = "none";
patchDisplay(cm, display.updateLineNumbers, update.dims);
if (toUpdate > 4) display.lineDiv.style.display = "";
display.renderedView = display.view;
// There might have been a widget with a focused element that got
// hidden or updated, if so re-focus it.
if (focused && activeElt() != focused && focused.offsetHeight) focused.focus();
// Prevent selection and cursors from interfering with the scroll
// width and height.
removeChildren(display.cursorDiv);
removeChildren(display.selectionDiv);
display.gutters.style.height = display.sizer.style.minHeight = 0;
if (different) {
display.lastWrapHeight = update.wrapperHeight;
display.lastWrapWidth = update.wrapperWidth;
startWorker(cm, 400);
}
display.updateLineNumbers = null;
return true;
}
function postUpdateDisplay(cm, update) {
var viewport = update.viewport;
for (var first = true;; first = false) {
if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
// Clip forced viewport to actual scrollable area.
if (viewport && viewport.top != null)
viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)};
// Updated line heights might result in the drawn area not
// actually covering the viewport. Keep looping until it does.
update.visible = visibleLines(cm.display, cm.doc, viewport);
if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
break;
}
if (!updateDisplayIfNeeded(cm, update)) break;
updateHeightsInViewport(cm);
var barMeasure = measureForScrollbars(cm);
updateSelection(cm);
setDocumentHeight(cm, barMeasure);
updateScrollbars(cm, barMeasure);
}
update.signal(cm, "update", cm);
if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
}
}
function updateDisplaySimple(cm, viewport) {
var update = new DisplayUpdate(cm, viewport);
if (updateDisplayIfNeeded(cm, update)) {
updateHeightsInViewport(cm);
postUpdateDisplay(cm, update);
var barMeasure = measureForScrollbars(cm);
updateSelection(cm);
setDocumentHeight(cm, barMeasure);
updateScrollbars(cm, barMeasure);
update.finish();
}
}
function setDocumentHeight(cm, measure) {
cm.display.sizer.style.minHeight = measure.docHeight + "px";
var total = measure.docHeight + cm.display.barHeight;
cm.display.heightForcer.style.top = total + "px";
cm.display.gutters.style.height = Math.max(total + scrollGap(cm), measure.clientHeight) + "px";
}
// Read the actual heights of the rendered lines, and update their
// stored heights to match.
function updateHeightsInViewport(cm) {
var display = cm.display;
var prevBottom = display.lineDiv.offsetTop;
for (var i = 0; i < display.view.length; i++) {
var cur = display.view[i], height;
if (cur.hidden) continue;
if (ie && ie_version < 8) {
var bot = cur.node.offsetTop + cur.node.offsetHeight;
height = bot - prevBottom;
prevBottom = bot;
} else {
var box = cur.node.getBoundingClientRect();
height = box.bottom - box.top;
}
var diff = cur.line.height - height;
if (height < 2) height = textHeight(display);
if (diff > .001 || diff < -.001) {
updateLineHeight(cur.line, height);
updateWidgetHeight(cur.line);
if (cur.rest) for (var j = 0; j < cur.rest.length; j++)
updateWidgetHeight(cur.rest[j]);
}
}
}
// Read and store the height of line widgets associated with the
// given line.
function updateWidgetHeight(line) {
if (line.widgets) for (var i = 0; i < line.widgets.length; ++i)
line.widgets[i].height = line.widgets[i].node.parentNode.offsetHeight;
}
// Do a bulk-read of the DOM positions and sizes needed to draw the
// view, so that we don't interleave reading and writing to the DOM.
function getDimensions(cm) {
var d = cm.display, left = {}, width = {};
var gutterLeft = d.gutters.clientLeft;
for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
width[cm.options.gutters[i]] = n.clientWidth;
}
return {fixedPos: compensateForHScroll(d),
gutterTotalWidth: d.gutters.offsetWidth,
gutterLeft: left,
gutterWidth: width,
wrapperWidth: d.wrapper.clientWidth};
}
// Sync the actual display DOM structure with display.view, removing
// nodes for lines that are no longer in view, and creating the ones
// that are not there yet, and updating the ones that are out of
// date.
function patchDisplay(cm, updateNumbersFrom, dims) {
var display = cm.display, lineNumbers = cm.options.lineNumbers;
var container = display.lineDiv, cur = container.firstChild;
function rm(node) {
var next = node.nextSibling;
// Works around a throw-scroll bug in OS X Webkit
if (webkit && mac && cm.display.currentWheelTarget == node)
node.style.display = "none";
else
node.parentNode.removeChild(node);
return next;
}
var view = display.view, lineN = display.viewFrom;
// Loop over the elements in the view, syncing cur (the DOM nodes
// in display.lineDiv) with the view as we go.
for (var i = 0; i < view.length; i++) {
var lineView = view[i];
if (lineView.hidden) {
} else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
var node = buildLineElement(cm, lineView, lineN, dims);
container.insertBefore(node, cur);
} else { // Already drawn
while (cur != lineView.node) cur = rm(cur);
var updateNumber = lineNumbers && updateNumbersFrom != null &&
updateNumbersFrom <= lineN && lineView.lineNumber;
if (lineView.changes) {
if (indexOf(lineView.changes, "gutter") > -1) updateNumber = false;
updateLineForChanges(cm, lineView, lineN, dims);
}
if (updateNumber) {
removeChildren(lineView.lineNumber);
lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
}
cur = lineView.node.nextSibling;
}
lineN += lineView.size;
}
while (cur) cur = rm(cur);
}
// When an aspect of a line changes, a string is added to
// lineView.changes. This updates the relevant part of the line's
// DOM structure.
function updateLineForChanges(cm, lineView, lineN, dims) {
for (var j = 0; j < lineView.changes.length; j++) {
var type = lineView.changes[j];
if (type == "text") updateLineText(cm, lineView);
else if (type == "gutter") updateLineGutter(cm, lineView, lineN, dims);
else if (type == "class") updateLineClasses(lineView);
else if (type == "widget") updateLineWidgets(cm, lineView, dims);
}
lineView.changes = null;
}
// Lines with gutter elements, widgets or a background class need to
// be wrapped, and have the extra elements added to the wrapper div
function ensureLineWrapped(lineView) {
if (lineView.node == lineView.text) {
lineView.node = elt("div", null, null, "position: relative");
if (lineView.text.parentNode)
lineView.text.parentNode.replaceChild(lineView.node, lineView.text);
lineView.node.appendChild(lineView.text);
if (ie && ie_version < 8) lineView.node.style.zIndex = 2;
}
return lineView.node;
}
function updateLineBackground(lineView) {
var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
if (cls) cls += " CodeMirror-linebackground";
if (lineView.background) {
if (cls) lineView.background.className = cls;
else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
} else if (cls) {
var wrap = ensureLineWrapped(lineView);
lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
}
}
// Wrapper around buildLineContent which will reuse the structure
// in display.externalMeasured when possible.
function getLineContent(cm, lineView) {
var ext = cm.display.externalMeasured;
if (ext && ext.line == lineView.line) {
cm.display.externalMeasured = null;
lineView.measure = ext.measure;
return ext.built;
}
return buildLineContent(cm, lineView);
}
// Redraw the line's text. Interacts with the background and text
// classes because the mode may output tokens that influence these
// classes.
function updateLineText(cm, lineView) {
var cls = lineView.text.className;
var built = getLineContent(cm, lineView);
if (lineView.text == lineView.node) lineView.node = built.pre;
lineView.text.parentNode.replaceChild(built.pre, lineView.text);
lineView.text = built.pre;
if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
lineView.bgClass = built.bgClass;
lineView.textClass = built.textClass;
updateLineClasses(lineView);
} else if (cls) {
lineView.text.className = cls;
}
}
function updateLineClasses(lineView) {
updateLineBackground(lineView);
if (lineView.line.wrapClass)
ensureLineWrapped(lineView).className = lineView.line.wrapClass;
else if (lineView.node != lineView.text)
lineView.node.className = "";
var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
lineView.text.className = textClass || "";
}
function updateLineGutter(cm, lineView, lineN, dims) {
if (lineView.gutter) {
lineView.node.removeChild(lineView.gutter);
lineView.gutter = null;
}
if (lineView.gutterBackground) {
lineView.node.removeChild(lineView.gutterBackground);
lineView.gutterBackground = null;
}
if (lineView.line.gutterClass) {
var wrap = ensureLineWrapped(lineView);
lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
"left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) +
"px; width: " + dims.gutterTotalWidth + "px");
wrap.insertBefore(lineView.gutterBackground, lineView.text);
}
var markers = lineView.line.gutterMarkers;
if (cm.options.lineNumbers || markers) {
var wrap = ensureLineWrapped(lineView);
var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", "left: " +
(cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px");
cm.display.input.setUneditable(gutterWrap);
wrap.insertBefore(gutterWrap, lineView.text);
if (lineView.line.gutterClass)
gutterWrap.className += " " + lineView.line.gutterClass;
if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
lineView.lineNumber = gutterWrap.appendChild(
elt("div", lineNumberFor(cm.options, lineN),
"CodeMirror-linenumber CodeMirror-gutter-elt",
"left: " + dims.gutterLeft["CodeMirror-linenumbers"] + "px; width: "
+ cm.display.lineNumInnerWidth + "px"));
if (markers) for (var k = 0; k < cm.options.gutters.length; ++k) {
var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
if (found)
gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt", "left: " +
dims.gutterLeft[id] + "px; width: " + dims.gutterWidth[id] + "px"));
}
}
}
function updateLineWidgets(cm, lineView, dims) {
if (lineView.alignable) lineView.alignable = null;
for (var node = lineView.node.firstChild, next; node; node = next) {
var next = node.nextSibling;
if (node.className == "CodeMirror-linewidget")
lineView.node.removeChild(node);
}
insertLineWidgets(cm, lineView, dims);
}
// Build a line's DOM representation from scratch
function buildLineElement(cm, lineView, lineN, dims) {
var built = getLineContent(cm, lineView);
lineView.text = lineView.node = built.pre;
if (built.bgClass) lineView.bgClass = built.bgClass;
if (built.textClass) lineView.textClass = built.textClass;
updateLineClasses(lineView);
updateLineGutter(cm, lineView, lineN, dims);
insertLineWidgets(cm, lineView, dims);
return lineView.node;
}
// A lineView may contain multiple logical lines (when merged by
// collapsed spans). The widgets for all of them need to be drawn.
function insertLineWidgets(cm, lineView, dims) {
insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false);
}
function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
if (!line.widgets) return;
var wrap = ensureLineWrapped(lineView);
for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
if (!widget.handleMouseEvents) node.setAttribute("cm-ignore-events", "true");
positionLineWidget(widget, node, lineView, dims);
cm.display.input.setUneditable(node);
if (allowAbove && widget.above)
wrap.insertBefore(node, lineView.gutter || lineView.text);
else
wrap.appendChild(node);
signalLater(widget, "redraw");
}
}
function positionLineWidget(widget, node, lineView, dims) {
if (widget.noHScroll) {
(lineView.alignable || (lineView.alignable = [])).push(node);
var width = dims.wrapperWidth;
node.style.left = dims.fixedPos + "px";
if (!widget.coverGutter) {
width -= dims.gutterTotalWidth;
node.style.paddingLeft = dims.gutterTotalWidth + "px";
}
node.style.width = width + "px";
}
if (widget.coverGutter) {
node.style.zIndex = 5;
node.style.position = "relative";
if (!widget.noHScroll) node.style.marginLeft = -dims.gutterTotalWidth + "px";
}
}
// POSITION OBJECT
// A Pos instance represents a position within the text.
var Pos = CodeMirror.Pos = function(line, ch) {
if (!(this instanceof Pos)) return new Pos(line, ch);
this.line = line; this.ch = ch;
};
// Compare two positions, return 0 if they are the same, a negative
// number when a is less, and a positive number otherwise.
var cmp = CodeMirror.cmpPos = function(a, b) { return a.line - b.line || a.ch - b.ch; };
function copyPos(x) {return Pos(x.line, x.ch);}
function maxPos(a, b) { return cmp(a, b) < 0 ? b : a; }
function minPos(a, b) { return cmp(a, b) < 0 ? a : b; }
// INPUT HANDLING
function ensureFocus(cm) {
if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
}
function isReadOnly(cm) {
return cm.options.readOnly || cm.doc.cantEdit;
}
// This will be set to an array of strings when copying, so that,
// when pasting, we know what kind of selections the copied text
// was made out of.
var lastCopied = null;
function applyTextInput(cm, inserted, deleted, sel, origin) {
var doc = cm.doc;
cm.display.shift = false;
if (!sel) sel = doc.sel;
var paste = cm.state.pasteIncoming || origin == "paste";
var textLines = doc.splitLines(inserted), multiPaste = null;
// When pasing N lines into N selections, insert one line per selection
if (paste && sel.ranges.length > 1) {
if (lastCopied && lastCopied.join("\n") == inserted) {
if (sel.ranges.length % lastCopied.length == 0) {
multiPaste = [];
for (var i = 0; i < lastCopied.length; i++)
multiPaste.push(doc.splitLines(lastCopied[i]));
}
} else if (textLines.length == sel.ranges.length) {
multiPaste = map(textLines, function(l) { return [l]; });
}
}
// Normal behavior is to insert the new text into every selection
for (var i = sel.ranges.length - 1; i >= 0; i--) {
var range = sel.ranges[i];
var from = range.from(), to = range.to();
if (range.empty()) {
if (deleted && deleted > 0) // Handle deletion
from = Pos(from.line, from.ch - deleted);
else if (cm.state.overwrite && !paste) // Handle overwrite
to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length));
}
var updateInput = cm.curOp.updateInput;
var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i % multiPaste.length] : textLines,
origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
makeChange(cm.doc, changeEvent);
signalLater(cm, "inputRead", cm, changeEvent);
}
if (inserted && !paste)
triggerElectric(cm, inserted);
ensureCursorVisible(cm);
cm.curOp.updateInput = updateInput;
cm.curOp.typing = true;
cm.state.pasteIncoming = cm.state.cutIncoming = false;
}
function handlePaste(e, cm) {
var pasted = e.clipboardData && e.clipboardData.getData("text/plain");
if (pasted) {
e.preventDefault();
if (!isReadOnly(cm) && !cm.options.disableInput)
runInOp(cm, function() { applyTextInput(cm, pasted, 0, null, "paste"); });
return true;
}
}
function triggerElectric(cm, inserted) {
// When an 'electric' character is inserted, immediately trigger a reindent
if (!cm.options.electricChars || !cm.options.smartIndent) return;
var sel = cm.doc.sel;
for (var i = sel.ranges.length - 1; i >= 0; i--) {
var range = sel.ranges[i];
if (range.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range.head.line)) continue;
var mode = cm.getModeAt(range.head);
var indented = false;
if (mode.electricChars) {
for (var j = 0; j < mode.electricChars.length; j++)
if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
indented = indentLine(cm, range.head.line, "smart");
break;
}
} else if (mode.electricInput) {
if (mode.electricInput.test(getLine(cm.doc, range.head.line).text.slice(0, range.head.ch)))
indented = indentLine(cm, range.head.line, "smart");
}
if (indented) signalLater(cm, "electricInput", cm, range.head.line);
}
}
function copyableRanges(cm) {
var text = [], ranges = [];
for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
var line = cm.doc.sel.ranges[i].head.line;
var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
ranges.push(lineRange);
text.push(cm.getRange(lineRange.anchor, lineRange.head));
}
return {text: text, ranges: ranges};
}
function disableBrowserMagic(field) {
field.setAttribute("autocorrect", "off");
field.setAttribute("autocapitalize", "off");
field.setAttribute("spellcheck", "false");
}
// TEXTAREA INPUT STYLE
function TextareaInput(cm) {
this.cm = cm;
// See input.poll and input.reset
this.prevInput = "";
// Flag that indicates whether we expect input to appear real soon
// now (after some event like 'keypress' or 'input') and are
// polling intensively.
this.pollingFast = false;
// Self-resetting timeout for the poller
this.polling = new Delayed();
// Tracks when input.reset has punted to just putting a short
// string into the textarea instead of the full selection.
this.inaccurateSelection = false;
// Used to work around IE issue with selection being forgotten when focus moves away from textarea
this.hasSelection = false;
this.composing = null;
};
function hiddenTextarea() {
var te = elt("textarea", null, null, "position: absolute; padding: 0; width: 1px; height: 1em; outline: none");
var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
// The textarea is kept positioned near the cursor to prevent the
// fact that it'll be scrolled into view on input from scrolling
// our fake cursor out of view. On webkit, when wrap=off, paste is
// very slow. So make the area wide instead.
if (webkit) te.style.width = "1000px";
else te.setAttribute("wrap", "off");
// If border: 0; -- iOS fails to open keyboard (issue #1287)
if (ios) te.style.border = "1px solid black";
disableBrowserMagic(te);
return div;
}
TextareaInput.prototype = copyObj({
init: function(display) {
var input = this, cm = this.cm;
// Wraps and hides input textarea
var div = this.wrapper = hiddenTextarea();
// The semihidden textarea that is focused when the editor is
// focused, and receives input.
var te = this.textarea = div.firstChild;
display.wrapper.insertBefore(div, display.wrapper.firstChild);
// Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
if (ios) te.style.width = "0px";
on(te, "input", function() {
if (ie && ie_version >= 9 && input.hasSelection) input.hasSelection = null;
input.poll();
});
on(te, "paste", function(e) {
if (handlePaste(e, cm)) return true;
cm.state.pasteIncoming = true;
input.fastPoll();
});
function prepareCopyCut(e) {
if (cm.somethingSelected()) {
lastCopied = cm.getSelections();
if (input.inaccurateSelection) {
input.prevInput = "";
input.inaccurateSelection = false;
te.value = lastCopied.join("\n");
selectInput(te);
}
} else if (!cm.options.lineWiseCopyCut) {
return;
} else {
var ranges = copyableRanges(cm);
lastCopied = ranges.text;
if (e.type == "cut") {
cm.setSelections(ranges.ranges, null, sel_dontScroll);
} else {
input.prevInput = "";
te.value = ranges.text.join("\n");
selectInput(te);
}
}
if (e.type == "cut") cm.state.cutIncoming = true;
}
on(te, "cut", prepareCopyCut);
on(te, "copy", prepareCopyCut);
on(display.scroller, "paste", function(e) {
if (eventInWidget(display, e)) return;
cm.state.pasteIncoming = true;
input.focus();
});
// Prevent normal selection in the editor (we handle our own)
on(display.lineSpace, "selectstart", function(e) {
if (!eventInWidget(display, e)) e_preventDefault(e);
});
on(te, "compositionstart", function() {
var start = cm.getCursor("from");
if (input.composing) input.composing.range.clear()
input.composing = {
start: start,
range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
};
});
on(te, "compositionend", function() {
if (input.composing) {
input.poll();
input.composing.range.clear();
input.composing = null;
}
});
},
prepareSelection: function() {
// Redraw the selection and/or cursor
var cm = this.cm, display = cm.display, doc = cm.doc;
var result = prepareSelection(cm);
// Move the hidden textarea near the cursor to prevent scrolling artifacts
if (cm.options.moveInputWithCursor) {
var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
headPos.top + lineOff.top - wrapOff.top));
result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
headPos.left + lineOff.left - wrapOff.left));
}
return result;
},
showSelection: function(drawn) {
var cm = this.cm, display = cm.display;
removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
removeChildrenAndAdd(display.selectionDiv, drawn.selection);
if (drawn.teTop != null) {
this.wrapper.style.top = drawn.teTop + "px";
this.wrapper.style.left = drawn.teLeft + "px";
}
},
// Reset the input to correspond to the selection (or to be empty,
// when not typing and nothing is selected)
reset: function(typing) {
if (this.contextMenuPending) return;
var minimal, selected, cm = this.cm, doc = cm.doc;
if (cm.somethingSelected()) {
this.prevInput = "";
var range = doc.sel.primary();
minimal = hasCopyEvent &&
(range.to().line - range.from().line > 100 || (selected = cm.getSelection()).length > 1000);
var content = minimal ? "-" : selected || cm.getSelection();
this.textarea.value = content;
if (cm.state.focused) selectInput(this.textarea);
if (ie && ie_version >= 9) this.hasSelection = content;
} else if (!typing) {
this.prevInput = this.textarea.value = "";
if (ie && ie_version >= 9) this.hasSelection = null;
}
this.inaccurateSelection = minimal;
},
getField: function() { return this.textarea; },
supportsTouch: function() { return false; },
focus: function() {
if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
try { this.textarea.focus(); }
catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
}
},
blur: function() { this.textarea.blur(); },
resetPosition: function() {
this.wrapper.style.top = this.wrapper.style.left = 0;
},
receivedFocus: function() { this.slowPoll(); },
// Poll for input changes, using the normal rate of polling. This
// runs as long as the editor is focused.
slowPoll: function() {
var input = this;
if (input.pollingFast) return;
input.polling.set(this.cm.options.pollInterval, function() {
input.poll();
if (input.cm.state.focused) input.slowPoll();
});
},
// When an event has just come in that is likely to add or change
// something in the input textarea, we poll faster, to ensure that
// the change appears on the screen quickly.
fastPoll: function() {
var missed = false, input = this;
input.pollingFast = true;
function p() {
var changed = input.poll();
if (!changed && !missed) {missed = true; input.polling.set(60, p);}
else {input.pollingFast = false; input.slowPoll();}
}
input.polling.set(20, p);
},
// Read input from the textarea, and update the document to match.
// When something is selected, it is present in the textarea, and
// selected (unless it is huge, in which case a placeholder is
// used). When nothing is selected, the cursor sits after previously
// seen text (can be empty), which is stored in prevInput (we must
// not reset the textarea when typing, because that breaks IME).
poll: function() {
var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
// Since this is called a *lot*, try to bail out as cheaply as
// possible when it is clear that nothing happened. hasSelection
// will be the case when there is a lot of text in the textarea,
// in which case reading its value would be expensive.
if (this.contextMenuPending || !cm.state.focused ||
(hasSelection(input) && !prevInput && !this.composing) ||
isReadOnly(cm) || cm.options.disableInput || cm.state.keySeq)
return false;
var text = input.value;
// If nothing changed, bail.
if (text == prevInput && !cm.somethingSelected()) return false;
// Work around nonsensical selection resetting in IE9/10, and
// inexplicable appearance of private area unicode characters on
// some key combos in Mac (#2689).
if (ie && ie_version >= 9 && this.hasSelection === text ||
mac && /[\uf700-\uf7ff]/.test(text)) {
cm.display.input.reset();
return false;
}
if (cm.doc.sel == cm.display.selForContextMenu) {
var first = text.charCodeAt(0);
if (first == 0x200b && !prevInput) prevInput = "\u200b";
if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo"); }
}
// Find the part of the input that is actually new
var same = 0, l = Math.min(prevInput.length, text.length);
while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) ++same;
var self = this;
runInOp(cm, function() {
applyTextInput(cm, text.slice(same), prevInput.length - same,
null, self.composing ? "*compose" : null);
// Don't leave long text in the textarea, since it makes further polling slow
if (text.length > 1000 || text.indexOf("\n") > -1) input.value = self.prevInput = "";
else self.prevInput = text;
if (self.composing) {
self.composing.range.clear();
self.composing.range = cm.markText(self.composing.start, cm.getCursor("to"),
{className: "CodeMirror-composing"});
}
});
return true;
},
ensurePolled: function() {
if (this.pollingFast && this.poll()) this.pollingFast = false;
},
onKeyPress: function() {
if (ie && ie_version >= 9) this.hasSelection = null;
this.fastPoll();
},
onContextMenu: function(e) {
var input = this, cm = input.cm, display = cm.display, te = input.textarea;
var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
if (!pos || presto) return; // Opera is difficult.
// Reset the current text selection only if the click is done outside of the selection
// and 'resetSelectionOnContextMenu' option is true.
var reset = cm.options.resetSelectionOnContextMenu;
if (reset && cm.doc.sel.contains(pos) == -1)
operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll);
var oldCSS = te.style.cssText;
input.wrapper.style.position = "absolute";
te.style.cssText = "position: fixed; width: 30px; height: 30px; top: " + (e.clientY - 5) +
"px; left: " + (e.clientX - 5) + "px; z-index: 1000; background: " +
(ie ? "rgba(255, 255, 255, .05)" : "transparent") +
"; outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
if (webkit) var oldScrollY = window.scrollY; // Work around Chrome issue (#2712)
display.input.focus();
if (webkit) window.scrollTo(null, oldScrollY);
display.input.reset();
// Adds "Select all" to context menu in FF
if (!cm.somethingSelected()) te.value = input.prevInput = " ";
input.contextMenuPending = true;
display.selForContextMenu = cm.doc.sel;
clearTimeout(display.detectingSelectAll);
// Select-all will be greyed out if there's nothing to select, so
// this adds a zero-width space so that we can later check whether
// it got selected.
function prepareSelectAllHack() {
if (te.selectionStart != null) {
var selected = cm.somethingSelected();
var extval = "\u200b" + (selected ? te.value : "");
te.value = "\u21da"; // Used to catch context-menu undo
te.value = extval;
input.prevInput = selected ? "" : "\u200b";
te.selectionStart = 1; te.selectionEnd = extval.length;
// Re-set this, in case some other handler touched the
// selection in the meantime.
display.selForContextMenu = cm.doc.sel;
}
}
function rehide() {
input.contextMenuPending = false;
input.wrapper.style.position = "relative";
te.style.cssText = oldCSS;
if (ie && ie_version < 9) display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos);
// Try to detect the user choosing select-all
if (te.selectionStart != null) {
if (!ie || (ie && ie_version < 9)) prepareSelectAllHack();
var i = 0, poll = function() {
if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
te.selectionEnd > 0 && input.prevInput == "\u200b")
operation(cm, commands.selectAll)(cm);
else if (i++ < 10) display.detectingSelectAll = setTimeout(poll, 500);
else display.input.reset();
};
display.detectingSelectAll = setTimeout(poll, 200);
}
}
if (ie && ie_version >= 9) prepareSelectAllHack();
if (captureRightClick) {
e_stop(e);
var mouseup = function() {
off(window, "mouseup", mouseup);
setTimeout(rehide, 20);
};
on(window, "mouseup", mouseup);
} else {
setTimeout(rehide, 50);
}
},
readOnlyChanged: function(val) {
if (!val) this.reset();
},
setUneditable: nothing,
needsContentAttribute: false
}, TextareaInput.prototype);
// CONTENTEDITABLE INPUT STYLE
function ContentEditableInput(cm) {
this.cm = cm;
this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
this.polling = new Delayed();
this.gracePeriod = false;
}
ContentEditableInput.prototype = copyObj({
init: function(display) {
var input = this, cm = input.cm;
var div = input.div = display.lineDiv;
disableBrowserMagic(div);
on(div, "paste", function(e) { handlePaste(e, cm); })
on(div, "compositionstart", function(e) {
var data = e.data;
input.composing = {sel: cm.doc.sel, data: data, startData: data};
if (!data) return;
var prim = cm.doc.sel.primary();
var line = cm.getLine(prim.head.line);
var found = line.indexOf(data, Math.max(0, prim.head.ch - data.length));
if (found > -1 && found <= prim.head.ch)
input.composing.sel = simpleSelection(Pos(prim.head.line, found),
Pos(prim.head.line, found + data.length));
});
on(div, "compositionupdate", function(e) {
input.composing.data = e.data;
});
on(div, "compositionend", function(e) {
var ours = input.composing;
if (!ours) return;
if (e.data != ours.startData && !/\u200b/.test(e.data))
ours.data = e.data;
// Need a small delay to prevent other code (input event,
// selection polling) from doing damage when fired right after
// compositionend.
setTimeout(function() {
if (!ours.handled)
input.applyComposition(ours);
if (input.composing == ours)
input.composing = null;
}, 50);
});
on(div, "touchstart", function() {
input.forceCompositionEnd();
});
on(div, "input", function() {
if (input.composing) return;
if (isReadOnly(cm) || !input.pollContent())
runInOp(input.cm, function() {regChange(cm);});
});
function onCopyCut(e) {
if (cm.somethingSelected()) {
lastCopied = cm.getSelections();
if (e.type == "cut") cm.replaceSelection("", null, "cut");
} else if (!cm.options.lineWiseCopyCut) {
return;
} else {
var ranges = copyableRanges(cm);
lastCopied = ranges.text;
if (e.type == "cut") {
cm.operation(function() {
cm.setSelections(ranges.ranges, 0, sel_dontScroll);
cm.replaceSelection("", null, "cut");
});
}
}
// iOS exposes the clipboard API, but seems to discard content inserted into it
if (e.clipboardData && !ios) {
e.preventDefault();
e.clipboardData.clearData();
e.clipboardData.setData("text/plain", lastCopied.join("\n"));
} else {
// Old-fashioned briefly-focus-a-textarea hack
var kludge = hiddenTextarea(), te = kludge.firstChild;
cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
te.value = lastCopied.join("\n");
var hadFocus = document.activeElement;
selectInput(te);
setTimeout(function() {
cm.display.lineSpace.removeChild(kludge);
hadFocus.focus();
}, 50);
}
}
on(div, "copy", onCopyCut);
on(div, "cut", onCopyCut);
},
prepareSelection: function() {
var result = prepareSelection(this.cm, false);
result.focus = this.cm.state.focused;
return result;
},
showSelection: function(info) {
if (!info || !this.cm.display.view.length) return;
if (info.focus) this.showPrimarySelection();
this.showMultipleSelections(info);
},
showPrimarySelection: function() {
var sel = window.getSelection(), prim = this.cm.doc.sel.primary();
var curAnchor = domToPos(this.cm, sel.anchorNode, sel.anchorOffset);
var curFocus = domToPos(this.cm, sel.focusNode, sel.focusOffset);
if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
cmp(minPos(curAnchor, curFocus), prim.from()) == 0 &&
cmp(maxPos(curAnchor, curFocus), prim.to()) == 0)
return;
var start = posToDOM(this.cm, prim.from());
var end = posToDOM(this.cm, prim.to());
if (!start && !end) return;
var view = this.cm.display.view;
var old = sel.rangeCount && sel.getRangeAt(0);
if (!start) {
start = {node: view[0].measure.map[2], offset: 0};
} else if (!end) { // FIXME dangerously hacky
var measure = view[view.length - 1].measure;
var map = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
end = {node: map[map.length - 1], offset: map[map.length - 2] - map[map.length - 3]};
}
try { var rng = range(start.node, start.offset, end.offset, end.node); }
catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
if (rng) {
sel.removeAllRanges();
sel.addRange(rng);
if (old && sel.anchorNode == null) sel.addRange(old);
else if (gecko) this.startGracePeriod();
}
this.rememberSelection();
},
startGracePeriod: function() {
var input = this;
clearTimeout(this.gracePeriod);
this.gracePeriod = setTimeout(function() {
input.gracePeriod = false;
if (input.selectionChanged())
input.cm.operation(function() { input.cm.curOp.selectionChanged = true; });
}, 20);
},
showMultipleSelections: function(info) {
removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
},
rememberSelection: function() {
var sel = window.getSelection();
this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
},
selectionInEditor: function() {
var sel = window.getSelection();
if (!sel.rangeCount) return false;
var node = sel.getRangeAt(0).commonAncestorContainer;
return contains(this.div, node);
},
focus: function() {
if (this.cm.options.readOnly != "nocursor") this.div.focus();
},
blur: function() { this.div.blur(); },
getField: function() { return this.div; },
supportsTouch: function() { return true; },
receivedFocus: function() {
var input = this;
if (this.selectionInEditor())
this.pollSelection();
else
runInOp(this.cm, function() { input.cm.curOp.selectionChanged = true; });
function poll() {
if (input.cm.state.focused) {
input.pollSelection();
input.polling.set(input.cm.options.pollInterval, poll);
}
}
this.polling.set(this.cm.options.pollInterval, poll);
},
selectionChanged: function() {
var sel = window.getSelection();
return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset;
},
pollSelection: function() {
if (!this.composing && !this.gracePeriod && this.selectionChanged()) {
var sel = window.getSelection(), cm = this.cm;
this.rememberSelection();
var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
var head = domToPos(cm, sel.focusNode, sel.focusOffset);
if (anchor && head) runInOp(cm, function() {
setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
if (anchor.bad || head.bad) cm.curOp.selectionChanged = true;
});
}
},
pollContent: function() {
var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
var from = sel.from(), to = sel.to();
if (from.line < display.viewFrom || to.line > display.viewTo - 1) return false;
var fromIndex;
if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
var fromLine = lineNo(display.view[0].line);
var fromNode = display.view[0].node;
} else {
var fromLine = lineNo(display.view[fromIndex].line);
var fromNode = display.view[fromIndex - 1].node.nextSibling;
}
var toIndex = findViewIndex(cm, to.line);
if (toIndex == display.view.length - 1) {
var toLine = display.viewTo - 1;
var toNode = display.lineDiv.lastChild;
} else {
var toLine = lineNo(display.view[toIndex + 1].line) - 1;
var toNode = display.view[toIndex + 1].node.previousSibling;
}
var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
while (newText.length > 1 && oldText.length > 1) {
if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
else break;
}
var cutFront = 0, cutEnd = 0;
var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
++cutFront;
var newBot = lst(newText), oldBot = lst(oldText);
var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
oldBot.length - (oldText.length == 1 ? cutFront : 0));
while (cutEnd < maxCutEnd &&
newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
++cutEnd;
newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd);
newText[0] = newText[0].slice(cutFront);
var chFrom = Pos(fromLine, cutFront);
var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
replaceRange(cm.doc, newText, chFrom, chTo, "+input");
return true;
}
},
ensurePolled: function() {
this.forceCompositionEnd();
},
reset: function() {
this.forceCompositionEnd();
},
forceCompositionEnd: function() {
if (!this.composing || this.composing.handled) return;
this.applyComposition(this.composing);
this.composing.handled = true;
this.div.blur();
this.div.focus();
},
applyComposition: function(composing) {
if (isReadOnly(this.cm))
operation(this.cm, regChange)(this.cm)
else if (composing.data && composing.data != composing.startData)
operation(this.cm, applyTextInput)(this.cm, composing.data, 0, composing.sel);
},
setUneditable: function(node) {
node.contentEditable = "false"
},
onKeyPress: function(e) {
e.preventDefault();
if (!isReadOnly(this.cm))
operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0);
},
readOnlyChanged: function(val) {
this.div.contentEditable = String(val != "nocursor")
},
onContextMenu: nothing,
resetPosition: nothing,
needsContentAttribute: true
}, ContentEditableInput.prototype);
function posToDOM(cm, pos) {
var view = findViewForLine(cm, pos.line);
if (!view || view.hidden) return null;
var line = getLine(cm.doc, pos.line);
var info = mapFromLineView(view, line, pos.line);
var order = getOrder(line), side = "left";
if (order) {
var partPos = getBidiPartAt(order, pos.ch);
side = partPos % 2 ? "right" : "left";
}
var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
result.offset = result.collapse == "right" ? result.end : result.start;
return result;
}
function badPos(pos, bad) { if (bad) pos.bad = true; return pos; }
function domToPos(cm, node, offset) {
var lineNode;
if (node == cm.display.lineDiv) {
lineNode = cm.display.lineDiv.childNodes[offset];
if (!lineNode) return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true);
node = null; offset = 0;
} else {
for (lineNode = node;; lineNode = lineNode.parentNode) {
if (!lineNode || lineNode == cm.display.lineDiv) return null;
if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) break;
}
}
for (var i = 0; i < cm.display.view.length; i++) {
var lineView = cm.display.view[i];
if (lineView.node == lineNode)
return locateNodeInLineView(lineView, node, offset);
}
}
function locateNodeInLineView(lineView, node, offset) {
var wrapper = lineView.text.firstChild, bad = false;
if (!node || !contains(wrapper, node)) return badPos(Pos(lineNo(lineView.line), 0), true);
if (node == wrapper) {
bad = true;
node = wrapper.childNodes[offset];
offset = 0;
if (!node) {
var line = lineView.rest ? lst(lineView.rest) : lineView.line;
return badPos(Pos(lineNo(line), line.text.length), bad);
}
}
var textNode = node.nodeType == 3 ? node : null, topNode = node;
if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
textNode = node.firstChild;
if (offset) offset = textNode.nodeValue.length;
}
while (topNode.parentNode != wrapper) topNode = topNode.parentNode;
var measure = lineView.measure, maps = measure.maps;
function find(textNode, topNode, offset) {
for (var i = -1; i < (maps ? maps.length : 0); i++) {
var map = i < 0 ? measure.map : maps[i];
for (var j = 0; j < map.length; j += 3) {
var curNode = map[j + 2];
if (curNode == textNode || curNode == topNode) {
var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
var ch = map[j] + offset;
if (offset < 0 || curNode != textNode) ch = map[j + (offset ? 1 : 0)];
return Pos(line, ch);
}
}
}
}
var found = find(textNode, topNode, offset);
if (found) return badPos(found, bad);
// FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
found = find(after, after.firstChild, 0);
if (found)
return badPos(Pos(found.line, found.ch - dist), bad);
else
dist += after.textContent.length;
}
for (var before = topNode.previousSibling, dist = offset; before; before = before.previousSibling) {
found = find(before, before.firstChild, -1);
if (found)
return badPos(Pos(found.line, found.ch + dist), bad);
else
dist += after.textContent.length;
}
}
function domTextBetween(cm, from, to, fromLine, toLine) {
var text = "", closing = false, lineSep = cm.doc.lineSeparator();
function recognizeMarker(id) { return function(marker) { return marker.id == id; }; }
function walk(node) {
if (node.nodeType == 1) {
var cmText = node.getAttribute("cm-text");
if (cmText != null) {
if (cmText == "") cmText = node.textContent.replace(/\u200b/g, "");
text += cmText;
return;
}
var markerID = node.getAttribute("cm-marker"), range;
if (markerID) {
var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
if (found.length && (range = found[0].find()))
text += getBetween(cm.doc, range.from, range.to).join(lineSep);
return;
}
if (node.getAttribute("contenteditable") == "false") return;
for (var i = 0; i < node.childNodes.length; i++)
walk(node.childNodes[i]);
if (/^(pre|div|p)$/i.test(node.nodeName))
closing = true;
} else if (node.nodeType == 3) {
var val = node.nodeValue;
if (!val) return;
if (closing) {
text += lineSep;
closing = false;
}
text += val;
}
}
for (;;) {
walk(from);
if (from == to) break;
from = from.nextSibling;
}
return text;
}
CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
// SELECTION / CURSOR
// Selection objects are immutable. A new one is created every time
// the selection changes. A selection is one or more non-overlapping
// (and non-touching) ranges, sorted, and an integer that indicates
// which one is the primary selection (the one that's scrolled into
// view, that getCursor returns, etc).
function Selection(ranges, primIndex) {
this.ranges = ranges;
this.primIndex = primIndex;
}
Selection.prototype = {
primary: function() { return this.ranges[this.primIndex]; },
equals: function(other) {
if (other == this) return true;
if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) return false;
for (var i = 0; i < this.ranges.length; i++) {
var here = this.ranges[i], there = other.ranges[i];
if (cmp(here.anchor, there.anchor) != 0 || cmp(here.head, there.head) != 0) return false;
}
return true;
},
deepCopy: function() {
for (var out = [], i = 0; i < this.ranges.length; i++)
out[i] = new Range(copyPos(this.ranges[i].anchor), copyPos(this.ranges[i].head));
return new Selection(out, this.primIndex);
},
somethingSelected: function() {
for (var i = 0; i < this.ranges.length; i++)
if (!this.ranges[i].empty()) return true;
return false;
},
contains: function(pos, end) {
if (!end) end = pos;
for (var i = 0; i < this.ranges.length; i++) {
var range = this.ranges[i];
if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
return i;
}
return -1;
}
};
function Range(anchor, head) {
this.anchor = anchor; this.head = head;
}
Range.prototype = {
from: function() { return minPos(this.anchor, this.head); },
to: function() { return maxPos(this.anchor, this.head); },
empty: function() {
return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch;
}
};
// Take an unsorted, potentially overlapping set of ranges, and
// build a selection out of it. 'Consumes' ranges array (modifying
// it).
function normalizeSelection(ranges, primIndex) {
var prim = ranges[primIndex];
ranges.sort(function(a, b) { return cmp(a.from(), b.from()); });
primIndex = indexOf(ranges, prim);
for (var i = 1; i < ranges.length; i++) {
var cur = ranges[i], prev = ranges[i - 1];
if (cmp(prev.to(), cur.from()) >= 0) {
var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
if (i <= primIndex) --primIndex;
ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
}
}
return new Selection(ranges, primIndex);
}
function simpleSelection(anchor, head) {
return new Selection([new Range(anchor, head || anchor)], 0);
}
// Most of the external API clips given positions to make sure they
// actually exist within the document.
function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1));}
function clipPos(doc, pos) {
if (pos.line < doc.first) return Pos(doc.first, 0);
var last = doc.first + doc.size - 1;
if (pos.line > last) return Pos(last, getLine(doc, last).text.length);
return clipToLen(pos, getLine(doc, pos.line).text.length);
}
function clipToLen(pos, linelen) {
var ch = pos.ch;
if (ch == null || ch > linelen) return Pos(pos.line, linelen);
else if (ch < 0) return Pos(pos.line, 0);
else return pos;
}
function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size;}
function clipPosArray(doc, array) {
for (var out = [], i = 0; i < array.length; i++) out[i] = clipPos(doc, array[i]);
return out;
}
// SELECTION UPDATES
// The 'scroll' parameter given to many of these indicated whether
// the new cursor position should be scrolled into view after
// modifying the selection.
// If shift is held or the extend flag is set, extends a range to
// include a given position (and optionally a second position).
// Otherwise, simply returns the range between the given positions.
// Used for cursor motion and such.
function extendRange(doc, range, head, other) {
if (doc.cm && doc.cm.display.shift || doc.extend) {
var anchor = range.anchor;
if (other) {
var posBefore = cmp(head, anchor) < 0;
if (posBefore != (cmp(other, anchor) < 0)) {
anchor = head;
head = other;
} else if (posBefore != (cmp(head, other) < 0)) {
head = other;
}
}
return new Range(anchor, head);
} else {
return new Range(other || head, head);
}
}
// Extend the primary selection range, discard the rest.
function extendSelection(doc, head, other, options) {
setSelection(doc, new Selection([extendRange(doc, doc.sel.primary(), head, other)], 0), options);
}
// Extend all selections (pos is an array of selections with length
// equal the number of selections)
function extendSelections(doc, heads, options) {
for (var out = [], i = 0; i < doc.sel.ranges.length; i++)
out[i] = extendRange(doc, doc.sel.ranges[i], heads[i], null);
var newSel = normalizeSelection(out, doc.sel.primIndex);
setSelection(doc, newSel, options);
}
// Updates a single range in the selection.
function replaceOneSelection(doc, i, range, options) {
var ranges = doc.sel.ranges.slice(0);
ranges[i] = range;
setSelection(doc, normalizeSelection(ranges, doc.sel.primIndex), options);
}
// Reset the selection to a single range.
function setSimpleSelection(doc, anchor, head, options) {
setSelection(doc, simpleSelection(anchor, head), options);
}
// Give beforeSelectionChange handlers a change to influence a
// selection update.
function filterSelectionChange(doc, sel) {
var obj = {
ranges: sel.ranges,
update: function(ranges) {
this.ranges = [];
for (var i = 0; i < ranges.length; i++)
this.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
clipPos(doc, ranges[i].head));
}
};
signal(doc, "beforeSelectionChange", doc, obj);
if (doc.cm) signal(doc.cm, "beforeSelectionChange", doc.cm, obj);
if (obj.ranges != sel.ranges) return normalizeSelection(obj.ranges, obj.ranges.length - 1);
else return sel;
}
function setSelectionReplaceHistory(doc, sel, options) {
var done = doc.history.done, last = lst(done);
if (last && last.ranges) {
done[done.length - 1] = sel;
setSelectionNoUndo(doc, sel, options);
} else {
setSelection(doc, sel, options);
}
}
// Set a new selection.
function setSelection(doc, sel, options) {
setSelectionNoUndo(doc, sel, options);
addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
}
function setSelectionNoUndo(doc, sel, options) {
if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
sel = filterSelectionChange(doc, sel);
var bias = options && options.bias ||
(cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
if (!(options && options.scroll === false) && doc.cm)
ensureCursorVisible(doc.cm);
}
function setSelectionInner(doc, sel) {
if (sel.equals(doc.sel)) return;
doc.sel = sel;
if (doc.cm) {
doc.cm.curOp.updateInput = doc.cm.curOp.selectionChanged = true;
signalCursorActivity(doc.cm);
}
signalLater(doc, "cursorActivity", doc);
}
// Verify that the selection does not partially select any atomic
// marked ranges.
function reCheckSelection(doc) {
setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false), sel_dontScroll);
}
// Return a selection that does not partially select any atomic
// ranges.
function skipAtomicInSelection(doc, sel, bias, mayClear) {
var out;
for (var i = 0; i < sel.ranges.length; i++) {
var range = sel.ranges[i];
var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
if (out || newAnchor != range.anchor || newHead != range.head) {
if (!out) out = sel.ranges.slice(0, i);
out[i] = new Range(newAnchor, newHead);
}
}
return out ? normalizeSelection(out, sel.primIndex) : sel;
}
function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
var line = getLine(doc, pos.line);
if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
var sp = line.markedSpans[i], m = sp.marker;
if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
(sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
if (mayClear) {
signal(m, "beforeCursorEnter");
if (m.explicitlyCleared) {
if (!line.markedSpans) break;
else {--i; continue;}
}
}
if (!m.atomic) continue;
if (oldPos) {
var near = m.find(dir < 0 ? 1 : -1), diff;
if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft) near = movePos(doc, near, -dir, line);
if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
return skipAtomicInner(doc, near, pos, dir, mayClear);
}
var far = m.find(dir < 0 ? -1 : 1);
if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight) far = movePos(doc, far, dir, line);
return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null;
}
}
return pos;
}
// Ensure a given position is not inside an atomic range.
function skipAtomic(doc, pos, oldPos, bias, mayClear) {
var dir = bias || 1;
var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
(!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
(!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
if (!found) {
doc.cantEdit = true;
return Pos(doc.first, 0);
}
return found;
}
function movePos(doc, pos, dir, line) {
if (dir < 0 && pos.ch == 0) {
if (pos.line > doc.first) return clipPos(doc, Pos(pos.line - 1));
else return null;
} else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
if (pos.line < doc.first + doc.size - 1) return Pos(pos.line + 1, 0);
else return null;
} else {
return new Pos(pos.line, pos.ch + dir);
}
}
// SELECTION DRAWING
function updateSelection(cm) {
cm.display.input.showSelection(cm.display.input.prepareSelection());
}
function prepareSelection(cm, primary) {
var doc = cm.doc, result = {};
var curFragment = result.cursors = document.createDocumentFragment();
var selFragment = result.selection = document.createDocumentFragment();
for (var i = 0; i < doc.sel.ranges.length; i++) {
if (primary === false && i == doc.sel.primIndex) continue;
var range = doc.sel.ranges[i];
var collapsed = range.empty();
if (collapsed || cm.options.showCursorWhenSelecting)
drawSelectionCursor(cm, range.head, curFragment);
if (!collapsed)
drawSelectionRange(cm, range, selFragment);
}
return result;
}
// Draws a cursor for the given range
function drawSelectionCursor(cm, head, output) {
var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
cursor.style.left = pos.left + "px";
cursor.style.top = pos.top + "px";
cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
if (pos.other) {
// Secondary cursor, shown when on a 'jump' in bi-directional text
var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
otherCursor.style.display = "";
otherCursor.style.left = pos.other.left + "px";
otherCursor.style.top = pos.other.top + "px";
otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
}
}
// Draws the given range as a highlighted selection
function drawSelectionRange(cm, range, output) {
var display = cm.display, doc = cm.doc;
var fragment = document.createDocumentFragment();
var padding = paddingH(cm.display), leftSide = padding.left;
var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
function add(left, top, width, bottom) {
if (top < 0) top = 0;
top = Math.round(top);
bottom = Math.round(bottom);
fragment.appendChild(elt("div", null, "CodeMirror-selected", "position: absolute; left: " + left +
"px; top: " + top + "px; width: " + (width == null ? rightSide - left : width) +
"px; height: " + (bottom - top) + "px"));
}
function drawForLine(line, fromArg, toArg) {
var lineObj = getLine(doc, line);
var lineLen = lineObj.text.length;
var start, end;
function coords(ch, bias) {
return charCoords(cm, Pos(line, ch), "div", lineObj, bias);
}
iterateBidiSections(getOrder(lineObj), fromArg || 0, toArg == null ? lineLen : toArg, function(from, to, dir) {
var leftPos = coords(from, "left"), rightPos, left, right;
if (from == to) {
rightPos = leftPos;
left = right = leftPos.left;
} else {
rightPos = coords(to - 1, "right");
if (dir == "rtl") { var tmp = leftPos; leftPos = rightPos; rightPos = tmp; }
left = leftPos.left;
right = rightPos.right;
}
if (fromArg == null && from == 0) left = leftSide;
if (rightPos.top - leftPos.top > 3) { // Different lines, draw top part
add(left, leftPos.top, null, leftPos.bottom);
left = leftSide;
if (leftPos.bottom < rightPos.top) add(left, leftPos.bottom, null, rightPos.top);
}
if (toArg == null && to == lineLen) right = rightSide;
if (!start || leftPos.top < start.top || leftPos.top == start.top && leftPos.left < start.left)
start = leftPos;
if (!end || rightPos.bottom > end.bottom || rightPos.bottom == end.bottom && rightPos.right > end.right)
end = rightPos;
if (left < leftSide + 1) left = leftSide;
add(left, rightPos.top, right - left, rightPos.bottom);
});
return {start: start, end: end};
}
var sFrom = range.from(), sTo = range.to();
if (sFrom.line == sTo.line) {
drawForLine(sFrom.line, sFrom.ch, sTo.ch);
} else {
var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
var singleVLine = visualLine(fromLine) == visualLine(toLine);
var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
if (singleVLine) {
if (leftEnd.top < rightStart.top - 2) {
add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
} else {
add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
}
}
if (leftEnd.bottom < rightStart.top)
add(leftSide, leftEnd.bottom, null, rightStart.top);
}
output.appendChild(fragment);
}
// Cursor-blinking
function restartBlink(cm) {
if (!cm.state.focused) return;
var display = cm.display;
clearInterval(display.blinker);
var on = true;
display.cursorDiv.style.visibility = "";
if (cm.options.cursorBlinkRate > 0)
display.blinker = setInterval(function() {
display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden";
}, cm.options.cursorBlinkRate);
else if (cm.options.cursorBlinkRate < 0)
display.cursorDiv.style.visibility = "hidden";
}
// HIGHLIGHT WORKER
function startWorker(cm, time) {
if (cm.doc.mode.startState && cm.doc.frontier < cm.display.viewTo)
cm.state.highlight.set(time, bind(highlightWorker, cm));
}
function highlightWorker(cm) {
var doc = cm.doc;
if (doc.frontier < doc.first) doc.frontier = doc.first;
if (doc.frontier >= cm.display.viewTo) return;
var end = +new Date + cm.options.workTime;
var state = copyState(doc.mode, getStateBefore(cm, doc.frontier));
var changedLines = [];
doc.iter(doc.frontier, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function(line) {
if (doc.frontier >= cm.display.viewFrom) { // Visible
var oldStyles = line.styles, tooLong = line.text.length > cm.options.maxHighlightLength;
var highlighted = highlightLine(cm, line, tooLong ? copyState(doc.mode, state) : state, true);
line.styles = highlighted.styles;
var oldCls = line.styleClasses, newCls = highlighted.classes;
if (newCls) line.styleClasses = newCls;
else if (oldCls) line.styleClasses = null;
var ischange = !oldStyles || oldStyles.length != line.styles.length ||
oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
for (var i = 0; !ischange && i < oldStyles.length; ++i) ischange = oldStyles[i] != line.styles[i];
if (ischange) changedLines.push(doc.frontier);
line.stateAfter = tooLong ? state : copyState(doc.mode, state);
} else {
if (line.text.length <= cm.options.maxHighlightLength)
processLine(cm, line.text, state);
line.stateAfter = doc.frontier % 5 == 0 ? copyState(doc.mode, state) : null;
}
++doc.frontier;
if (+new Date > end) {
startWorker(cm, cm.options.workDelay);
return true;
}
});
if (changedLines.length) runInOp(cm, function() {
for (var i = 0; i < changedLines.length; i++)
regLineChange(cm, changedLines[i], "text");
});
}
// Finds the line to start with when starting a parse. Tries to
// find a line with a stateAfter, so that it can start with a
// valid state. If that fails, it returns the line with the
// smallest indentation, which tends to need the least context to
// parse correctly.
function findStartLine(cm, n, precise) {
var minindent, minline, doc = cm.doc;
var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
for (var search = n; search > lim; --search) {
if (search <= doc.first) return doc.first;
var line = getLine(doc, search - 1);
if (line.stateAfter && (!precise || search <= doc.frontier)) return search;
var indented = countColumn(line.text, null, cm.options.tabSize);
if (minline == null || minindent > indented) {
minline = search - 1;
minindent = indented;
}
}
return minline;
}
function getStateBefore(cm, n, precise) {
var doc = cm.doc, display = cm.display;
if (!doc.mode.startState) return true;
var pos = findStartLine(cm, n, precise), state = pos > doc.first && getLine(doc, pos-1).stateAfter;
if (!state) state = startState(doc.mode);
else state = copyState(doc.mode, state);
doc.iter(pos, n, function(line) {
processLine(cm, line.text, state);
var save = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo;
line.stateAfter = save ? copyState(doc.mode, state) : null;
++pos;
});
if (precise) doc.frontier = pos;
return state;
}
// POSITION MEASUREMENT
function paddingTop(display) {return display.lineSpace.offsetTop;}
function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight;}
function paddingH(display) {
if (display.cachedPaddingH) return display.cachedPaddingH;
var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
if (!isNaN(data.left) && !isNaN(data.right)) display.cachedPaddingH = data;
return data;
}
function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth; }
function displayWidth(cm) {
return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth;
}
function displayHeight(cm) {
return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight;
}
// Ensure the lineView.wrapping.heights array is populated. This is
// an array of bottom offsets for the lines that make up a drawn
// line. When lineWrapping is on, there might be more than one
// height.
function ensureLineHeights(cm, lineView, rect) {
var wrapping = cm.options.lineWrapping;
var curWidth = wrapping && displayWidth(cm);
if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
var heights = lineView.measure.heights = [];
if (wrapping) {
lineView.measure.width = curWidth;
var rects = lineView.text.firstChild.getClientRects();
for (var i = 0; i < rects.length - 1; i++) {
var cur = rects[i], next = rects[i + 1];
if (Math.abs(cur.bottom - next.bottom) > 2)
heights.push((cur.bottom + next.top) / 2 - rect.top);
}
}
heights.push(rect.bottom - rect.top);
}
}
// Find a line map (mapping character offsets to text nodes) and a
// measurement cache for the given line number. (A line view might
// contain multiple lines when collapsed ranges are present.)
function mapFromLineView(lineView, line, lineN) {
if (lineView.line == line)
return {map: lineView.measure.map, cache: lineView.measure.cache};
for (var i = 0; i < lineView.rest.length; i++)
if (lineView.rest[i] == line)
return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]};
for (var i = 0; i < lineView.rest.length; i++)
if (lineNo(lineView.rest[i]) > lineN)
return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i], before: true};
}
// Render a line into the hidden node display.externalMeasured. Used
// when measurement is needed for a line that's not in the viewport.
function updateExternalMeasurement(cm, line) {
line = visualLine(line);
var lineN = lineNo(line);
var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
view.lineN = lineN;
var built = view.built = buildLineContent(cm, view);
view.text = built.pre;
removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
return view;
}
// Get a {top, bottom, left, right} box (in line-local coordinates)
// for a given character.
function measureChar(cm, line, ch, bias) {
return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias);
}
// Find a line view that corresponds to the given line number.
function findViewForLine(cm, lineN) {
if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
return cm.display.view[findViewIndex(cm, lineN)];
var ext = cm.display.externalMeasured;
if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
return ext;
}
// Measurement can be split in two steps, the set-up work that
// applies to the whole line, and the measurement of the actual
// character. Functions like coordsChar, that need to do a lot of
// measurements in a row, can thus ensure that the set-up work is
// only done once.
function prepareMeasureForLine(cm, line) {
var lineN = lineNo(line);
var view = findViewForLine(cm, lineN);
if (view && !view.text) {
view = null;
} else if (view && view.changes) {
updateLineForChanges(cm, view, lineN, getDimensions(cm));
cm.curOp.forceUpdate = true;
}
if (!view)
view = updateExternalMeasurement(cm, line);
var info = mapFromLineView(view, line, lineN);
return {
line: line, view: view, rect: null,
map: info.map, cache: info.cache, before: info.before,
hasHeights: false
};
}
// Given a prepared measurement object, measures the position of an
// actual character (or fetches it from the cache).
function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
if (prepared.before) ch = -1;
var key = ch + (bias || ""), found;
if (prepared.cache.hasOwnProperty(key)) {
found = prepared.cache[key];
} else {
if (!prepared.rect)
prepared.rect = prepared.view.text.getBoundingClientRect();
if (!prepared.hasHeights) {
ensureLineHeights(cm, prepared.view, prepared.rect);
prepared.hasHeights = true;
}
found = measureCharInner(cm, prepared, ch, bias);
if (!found.bogus) prepared.cache[key] = found;
}
return {left: found.left, right: found.right,
top: varHeight ? found.rtop : found.top,
bottom: varHeight ? found.rbottom : found.bottom};
}
var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
function nodeAndOffsetInLineMap(map, ch, bias) {
var node, start, end, collapse;
// First, search the line map for the text node corresponding to,
// or closest to, the target character.
for (var i = 0; i < map.length; i += 3) {
var mStart = map[i], mEnd = map[i + 1];
if (ch < mStart) {
start = 0; end = 1;
collapse = "left";
} else if (ch < mEnd) {
start = ch - mStart;
end = start + 1;
} else if (i == map.length - 3 || ch == mEnd && map[i + 3] > ch) {
end = mEnd - mStart;
start = end - 1;
if (ch >= mEnd) collapse = "right";
}
if (start != null) {
node = map[i + 2];
if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
collapse = bias;
if (bias == "left" && start == 0)
while (i && map[i - 2] == map[i - 3] && map[i - 1].insertLeft) {
node = map[(i -= 3) + 2];
collapse = "left";
}
if (bias == "right" && start == mEnd - mStart)
while (i < map.length - 3 && map[i + 3] == map[i + 4] && !map[i + 5].insertLeft) {
node = map[(i += 3) + 2];
collapse = "right";
}
break;
}
}
return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd};
}
function measureCharInner(cm, prepared, ch, bias) {
var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
var rect;
if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
for (var i = 0; i < 4; i++) { // Retry a maximum of 4 times when nonsense rectangles are returned
while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) --start;
while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) ++end;
if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart) {
rect = node.parentNode.getBoundingClientRect();
} else if (ie && cm.options.lineWrapping) {
var rects = range(node, start, end).getClientRects();
if (rects.length)
rect = rects[bias == "right" ? rects.length - 1 : 0];
else
rect = nullRect;
} else {
rect = range(node, start, end).getBoundingClientRect() || nullRect;
}
if (rect.left || rect.right || start == 0) break;
end = start;
start = start - 1;
collapse = "right";
}
if (ie && ie_version < 11) rect = maybeUpdateRectForZooming(cm.display.measure, rect);
} else { // If it is a widget, simply get the box for the whole widget.
if (start > 0) collapse = bias = "right";
var rects;
if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
rect = rects[bias == "right" ? rects.length - 1 : 0];
else
rect = node.getBoundingClientRect();
}
if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
var rSpan = node.parentNode.getClientRects()[0];
if (rSpan)
rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom};
else
rect = nullRect;
}
var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
var mid = (rtop + rbot) / 2;
var heights = prepared.view.measure.heights;
for (var i = 0; i < heights.length - 1; i++)
if (mid < heights[i]) break;
var top = i ? heights[i - 1] : 0, bot = heights[i];
var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
top: top, bottom: bot};
if (!rect.left && !rect.right) result.bogus = true;
if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
return result;
}
// Work around problem with bounding client rects on ranges being
// returned incorrectly when zoomed on IE10 and below.
function maybeUpdateRectForZooming(measure, rect) {
if (!window.screen || screen.logicalXDPI == null ||
screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
return rect;
var scaleX = screen.logicalXDPI / screen.deviceXDPI;
var scaleY = screen.logicalYDPI / screen.deviceYDPI;
return {left: rect.left * scaleX, right: rect.right * scaleX,
top: rect.top * scaleY, bottom: rect.bottom * scaleY};
}
function clearLineMeasurementCacheFor(lineView) {
if (lineView.measure) {
lineView.measure.cache = {};
lineView.measure.heights = null;
if (lineView.rest) for (var i = 0; i < lineView.rest.length; i++)
lineView.measure.caches[i] = {};
}
}
function clearLineMeasurementCache(cm) {
cm.display.externalMeasure = null;
removeChildren(cm.display.lineMeasure);
for (var i = 0; i < cm.display.view.length; i++)
clearLineMeasurementCacheFor(cm.display.view[i]);
}
function clearCaches(cm) {
clearLineMeasurementCache(cm);
cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
if (!cm.options.lineWrapping) cm.display.maxLineChanged = true;
cm.display.lineNumChars = null;
}
function pageScrollX() { return window.pageXOffset || (document.documentElement || document.body).scrollLeft; }
function pageScrollY() { return window.pageYOffset || (document.documentElement || document.body).scrollTop; }
// Converts a {top, bottom, left, right} box from line-local
// coordinates into another coordinate system. Context may be one of
// "line", "div" (display.lineDiv), "local"/null (editor), "window",
// or "page".
function intoCoordSystem(cm, lineObj, rect, context) {
if (lineObj.widgets) for (var i = 0; i < lineObj.widgets.length; ++i) if (lineObj.widgets[i].above) {
var size = widgetHeight(lineObj.widgets[i]);
rect.top += size; rect.bottom += size;
}
if (context == "line") return rect;
if (!context) context = "local";
var yOff = heightAtLine(lineObj);
if (context == "local") yOff += paddingTop(cm.display);
else yOff -= cm.display.viewOffset;
if (context == "page" || context == "window") {
var lOff = cm.display.lineSpace.getBoundingClientRect();
yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
rect.left += xOff; rect.right += xOff;
}
rect.top += yOff; rect.bottom += yOff;
return rect;
}
// Coverts a box from "div" coords to another coordinate system.
// Context may be "window", "page", "div", or "local"/null.
function fromCoordSystem(cm, coords, context) {
if (context == "div") return coords;
var left = coords.left, top = coords.top;
// First move into "page" coordinate system
if (context == "page") {
left -= pageScrollX();
top -= pageScrollY();
} else if (context == "local" || !context) {
var localBox = cm.display.sizer.getBoundingClientRect();
left += localBox.left;
top += localBox.top;
}
var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top};
}
function charCoords(cm, pos, context, lineObj, bias) {
if (!lineObj) lineObj = getLine(cm.doc, pos.line);
return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context);
}
// Returns a box for a given cursor position, which may have an
// 'other' property containing the position of the secondary cursor
// on a bidi boundary.
function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
lineObj = lineObj || getLine(cm.doc, pos.line);
if (!preparedMeasure) preparedMeasure = prepareMeasureForLine(cm, lineObj);
function get(ch, right) {
var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
if (right) m.left = m.right; else m.right = m.left;
return intoCoordSystem(cm, lineObj, m, context);
}
function getBidi(ch, partPos) {
var part = order[partPos], right = part.level % 2;
if (ch == bidiLeft(part) && partPos && part.level < order[partPos - 1].level) {
part = order[--partPos];
ch = bidiRight(part) - (part.level % 2 ? 0 : 1);
right = true;
} else if (ch == bidiRight(part) && partPos < order.length - 1 && part.level < order[partPos + 1].level) {
part = order[++partPos];
ch = bidiLeft(part) - part.level % 2;
right = false;
}
if (right && ch == part.to && ch > part.from) return get(ch - 1);
return get(ch, right);
}
var order = getOrder(lineObj), ch = pos.ch;
if (!order) return get(ch);
var partPos = getBidiPartAt(order, ch);
var val = getBidi(ch, partPos);
if (bidiOther != null) val.other = getBidi(ch, bidiOther);
return val;
}
// Used to cheaply estimate the coordinates for a position. Used for
// intermediate scroll updates.
function estimateCoords(cm, pos) {
var left = 0, pos = clipPos(cm.doc, pos);
if (!cm.options.lineWrapping) left = charWidth(cm.display) * pos.ch;
var lineObj = getLine(cm.doc, pos.line);
var top = heightAtLine(lineObj) + paddingTop(cm.display);
return {left: left, right: left, top: top, bottom: top + lineObj.height};
}
// Positions returned by coordsChar contain some extra information.
// xRel is the relative x position of the input coordinates compared
// to the found position (so xRel > 0 means the coordinates are to
// the right of the character position, for example). When outside
// is true, that means the coordinates lie outside the line's
// vertical range.
function PosWithInfo(line, ch, outside, xRel) {
var pos = Pos(line, ch);
pos.xRel = xRel;
if (outside) pos.outside = true;
return pos;
}
// Compute the character position closest to the given coordinates.
// Input must be lineSpace-local ("div" coordinate system).
function coordsChar(cm, x, y) {
var doc = cm.doc;
y += cm.display.viewOffset;
if (y < 0) return PosWithInfo(doc.first, 0, true, -1);
var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
if (lineN > last)
return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, true, 1);
if (x < 0) x = 0;
var lineObj = getLine(doc, lineN);
for (;;) {
var found = coordsCharInner(cm, lineObj, lineN, x, y);
var merged = collapsedSpanAtEnd(lineObj);
var mergedPos = merged && merged.find(0, true);
if (merged && (found.ch > mergedPos.from.ch || found.ch == mergedPos.from.ch && found.xRel > 0))
lineN = lineNo(lineObj = mergedPos.to.line);
else
return found;
}
}
function coordsCharInner(cm, lineObj, lineNo, x, y) {
var innerOff = y - heightAtLine(lineObj);
var wrongLine = false, adjust = 2 * cm.display.wrapper.clientWidth;
var preparedMeasure = prepareMeasureForLine(cm, lineObj);
function getX(ch) {
var sp = cursorCoords(cm, Pos(lineNo, ch), "line", lineObj, preparedMeasure);
wrongLine = true;
if (innerOff > sp.bottom) return sp.left - adjust;
else if (innerOff < sp.top) return sp.left + adjust;
else wrongLine = false;
return sp.left;
}
var bidi = getOrder(lineObj), dist = lineObj.text.length;
var from = lineLeft(lineObj), to = lineRight(lineObj);
var fromX = getX(from), fromOutside = wrongLine, toX = getX(to), toOutside = wrongLine;
if (x > toX) return PosWithInfo(lineNo, to, toOutside, 1);
// Do a binary search between these bounds.
for (;;) {
if (bidi ? to == from || to == moveVisually(lineObj, from, 1) : to - from <= 1) {
var ch = x < fromX || x - fromX <= toX - x ? from : to;
var xDiff = x - (ch == from ? fromX : toX);
while (isExtendingChar(lineObj.text.charAt(ch))) ++ch;
var pos = PosWithInfo(lineNo, ch, ch == from ? fromOutside : toOutside,
xDiff < -1 ? -1 : xDiff > 1 ? 1 : 0);
return pos;
}
var step = Math.ceil(dist / 2), middle = from + step;
if (bidi) {
middle = from;
for (var i = 0; i < step; ++i) middle = moveVisually(lineObj, middle, 1);
}
var middleX = getX(middle);
if (middleX > x) {to = middle; toX = middleX; if (toOutside = wrongLine) toX += 1000; dist = step;}
else {from = middle; fromX = middleX; fromOutside = wrongLine; dist -= step;}
}
}
var measureText;
// Compute the default text height.
function textHeight(display) {
if (display.cachedTextHeight != null) return display.cachedTextHeight;
if (measureText == null) {
measureText = elt("pre");
// Measure a bunch of lines, for browsers that compute
// fractional heights.
for (var i = 0; i < 49; ++i) {
measureText.appendChild(document.createTextNode("x"));
measureText.appendChild(elt("br"));
}
measureText.appendChild(document.createTextNode("x"));
}
removeChildrenAndAdd(display.measure, measureText);
var height = measureText.offsetHeight / 50;
if (height > 3) display.cachedTextHeight = height;
removeChildren(display.measure);
return height || 1;
}
// Compute the default character width.
function charWidth(display) {
if (display.cachedCharWidth != null) return display.cachedCharWidth;
var anchor = elt("span", "xxxxxxxxxx");
var pre = elt("pre", [anchor]);
removeChildrenAndAdd(display.measure, pre);
var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
if (width > 2) display.cachedCharWidth = width;
return width || 10;
}
// OPERATIONS
// Operations are used to wrap a series of changes to the editor
// state in such a way that each change won't have to update the
// cursor and display (which would be awkward, slow, and
// error-prone). Instead, display updates are batched and then all
// combined and executed at once.
var operationGroup = null;
var nextOpId = 0;
// Start a new operation.
function startOperation(cm) {
cm.curOp = {
cm: cm,
viewChanged: false, // Flag that indicates that lines might need to be redrawn
startHeight: cm.doc.height, // Used to detect need to update scrollbar
forceUpdate: false, // Used to force a redraw
updateInput: null, // Whether to reset the input textarea
typing: false, // Whether this reset should be careful to leave existing text (for compositing)
changeObjs: null, // Accumulated changes, for firing change events
cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
selectionChanged: false, // Whether the selection needs to be redrawn
updateMaxLine: false, // Set when the widest line needs to be determined anew
scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
scrollToPos: null, // Used to scroll to a specific position
focus: false,
id: ++nextOpId // Unique ID
};
if (operationGroup) {
operationGroup.ops.push(cm.curOp);
} else {
cm.curOp.ownsGroup = operationGroup = {
ops: [cm.curOp],
delayedCallbacks: []
};
}
}
function fireCallbacksForOps(group) {
// Calls delayed callbacks and cursorActivity handlers until no
// new ones appear
var callbacks = group.delayedCallbacks, i = 0;
do {
for (; i < callbacks.length; i++)
callbacks[i].call(null);
for (var j = 0; j < group.ops.length; j++) {
var op = group.ops[j];
if (op.cursorActivityHandlers)
while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm);
}
} while (i < callbacks.length);
}
// Finish an operation, updating the display and signalling delayed events
function endOperation(cm) {
var op = cm.curOp, group = op.ownsGroup;
if (!group) return;
try { fireCallbacksForOps(group); }
finally {
operationGroup = null;
for (var i = 0; i < group.ops.length; i++)
group.ops[i].cm.curOp = null;
endOperations(group);
}
}
// The DOM updates done when an operation finishes are batched so
// that the minimum number of relayouts are required.
function endOperations(group) {
var ops = group.ops;
for (var i = 0; i < ops.length; i++) // Read DOM
endOperation_R1(ops[i]);
for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
endOperation_W1(ops[i]);
for (var i = 0; i < ops.length; i++) // Read DOM
endOperation_R2(ops[i]);
for (var i = 0; i < ops.length; i++) // Write DOM (maybe)
endOperation_W2(ops[i]);
for (var i = 0; i < ops.length; i++) // Read DOM
endOperation_finish(ops[i]);
}
function endOperation_R1(op) {
var cm = op.cm, display = cm.display;
maybeClipScrollbars(cm);
if (op.updateMaxLine) findMaxLine(cm);
op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
op.scrollToPos.to.line >= display.viewTo) ||
display.maxLineChanged && cm.options.lineWrapping;
op.update = op.mustUpdate &&
new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
}
function endOperation_W1(op) {
op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
}
function endOperation_R2(op) {
var cm = op.cm, display = cm.display;
if (op.updatedDisplay) updateHeightsInViewport(cm);
op.barMeasure = measureForScrollbars(cm);
// If the max line changed since it was last measured, measure it,
// and ensure the document's width matches it.
// updateDisplay_W2 will use these properties to do the actual resizing
if (display.maxLineChanged && !cm.options.lineWrapping) {
op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
cm.display.sizerWidth = op.adjustWidthTo;
op.barMeasure.scrollWidth =
Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
}
if (op.updatedDisplay || op.selectionChanged)
op.preparedSelection = display.input.prepareSelection();
}
function endOperation_W2(op) {
var cm = op.cm;
if (op.adjustWidthTo != null) {
cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
if (op.maxScrollLeft < cm.doc.scrollLeft)
setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true);
cm.display.maxLineChanged = false;
}
if (op.preparedSelection)
cm.display.input.showSelection(op.preparedSelection);
if (op.updatedDisplay)
setDocumentHeight(cm, op.barMeasure);
if (op.updatedDisplay || op.startHeight != cm.doc.height)
updateScrollbars(cm, op.barMeasure);
if (op.selectionChanged) restartBlink(cm);
if (cm.state.focused && op.updateInput)
cm.display.input.reset(op.typing);
if (op.focus && op.focus == activeElt() && (!document.hasFocus || document.hasFocus()))
ensureFocus(op.cm);
}
function endOperation_finish(op) {
var cm = op.cm, display = cm.display, doc = cm.doc;
if (op.updatedDisplay) postUpdateDisplay(cm, op.update);
// Abort mouse wheel delta measurement, when scrolling explicitly
if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
display.wheelStartX = display.wheelStartY = null;
// Propagate the scroll position to the actual DOM scroller
if (op.scrollTop != null && (display.scroller.scrollTop != op.scrollTop || op.forceScroll)) {
doc.scrollTop = Math.max(0, Math.min(display.scroller.scrollHeight - display.scroller.clientHeight, op.scrollTop));
display.scrollbars.setScrollTop(doc.scrollTop);
display.scroller.scrollTop = doc.scrollTop;
}
if (op.scrollLeft != null && (display.scroller.scrollLeft != op.scrollLeft || op.forceScroll)) {
doc.scrollLeft = Math.max(0, Math.min(display.scroller.scrollWidth - displayWidth(cm), op.scrollLeft));
display.scrollbars.setScrollLeft(doc.scrollLeft);
display.scroller.scrollLeft = doc.scrollLeft;
alignHorizontally(cm);
}
// If we need to scroll a specific position into view, do so.
if (op.scrollToPos) {
var coords = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
if (op.scrollToPos.isCursor && cm.state.focused) maybeScrollWindow(cm, coords);
}
// Fire events for markers that are hidden/unidden by editing or
// undoing
var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
if (hidden) for (var i = 0; i < hidden.length; ++i)
if (!hidden[i].lines.length) signal(hidden[i], "hide");
if (unhidden) for (var i = 0; i < unhidden.length; ++i)
if (unhidden[i].lines.length) signal(unhidden[i], "unhide");
if (display.wrapper.offsetHeight)
doc.scrollTop = cm.display.scroller.scrollTop;
// Fire change events, and delayed event handlers
if (op.changeObjs)
signal(cm, "changes", cm, op.changeObjs);
if (op.update)
op.update.finish();
}
// Run the given function in an operation
function runInOp(cm, f) {
if (cm.curOp) return f();
startOperation(cm);
try { return f(); }
finally { endOperation(cm); }
}
// Wraps a function in an operation. Returns the wrapped function.
function operation(cm, f) {
return function() {
if (cm.curOp) return f.apply(cm, arguments);
startOperation(cm);
try { return f.apply(cm, arguments); }
finally { endOperation(cm); }
};
}
// Used to add methods to editor and doc instances, wrapping them in
// operations.
function methodOp(f) {
return function() {
if (this.curOp) return f.apply(this, arguments);
startOperation(this);
try { return f.apply(this, arguments); }
finally { endOperation(this); }
};
}
function docMethodOp(f) {
return function() {
var cm = this.cm;
if (!cm || cm.curOp) return f.apply(this, arguments);
startOperation(cm);
try { return f.apply(this, arguments); }
finally { endOperation(cm); }
};
}
// VIEW TRACKING
// These objects are used to represent the visible (currently drawn)
// part of the document. A LineView may correspond to multiple
// logical lines, if those are connected by collapsed ranges.
function LineView(doc, line, lineN) {
// The starting line
this.line = line;
// Continuing lines, if any
this.rest = visualLineContinued(line);
// Number of logical lines in this visual line
this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
this.node = this.text = null;
this.hidden = lineIsHidden(doc, line);
}
// Create a range of LineView objects for the given lines.
function buildViewArray(cm, from, to) {
var array = [], nextPos;
for (var pos = from; pos < to; pos = nextPos) {
var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
nextPos = pos + view.size;
array.push(view);
}
return array;
}
// Updates the display.view data structure for a given change to the
// document. From and to are in pre-change coordinates. Lendiff is
// the amount of lines added or subtracted by the change. This is
// used for changes that span multiple lines, or change the way
// lines are divided into visual lines. regLineChange (below)
// registers single-line changes.
function regChange(cm, from, to, lendiff) {
if (from == null) from = cm.doc.first;
if (to == null) to = cm.doc.first + cm.doc.size;
if (!lendiff) lendiff = 0;
var display = cm.display;
if (lendiff && to < display.viewTo &&
(display.updateLineNumbers == null || display.updateLineNumbers > from))
display.updateLineNumbers = from;
cm.curOp.viewChanged = true;
if (from >= display.viewTo) { // Change after
if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
resetView(cm);
} else if (to <= display.viewFrom) { // Change before
if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
resetView(cm);
} else {
display.viewFrom += lendiff;
display.viewTo += lendiff;
}
} else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
resetView(cm);
} else if (from <= display.viewFrom) { // Top overlap
var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
if (cut) {
display.view = display.view.slice(cut.index);
display.viewFrom = cut.lineN;
display.viewTo += lendiff;
} else {
resetView(cm);
}
} else if (to >= display.viewTo) { // Bottom overlap
var cut = viewCuttingPoint(cm, from, from, -1);
if (cut) {
display.view = display.view.slice(0, cut.index);
display.viewTo = cut.lineN;
} else {
resetView(cm);
}
} else { // Gap in the middle
var cutTop = viewCuttingPoint(cm, from, from, -1);
var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
if (cutTop && cutBot) {
display.view = display.view.slice(0, cutTop.index)
.concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
.concat(display.view.slice(cutBot.index));
display.viewTo += lendiff;
} else {
resetView(cm);
}
}
var ext = display.externalMeasured;
if (ext) {
if (to < ext.lineN)
ext.lineN += lendiff;
else if (from < ext.lineN + ext.size)
display.externalMeasured = null;
}
}
// Register a change to a single line. Type must be one of "text",
// "gutter", "class", "widget"
function regLineChange(cm, line, type) {
cm.curOp.viewChanged = true;
var display = cm.display, ext = cm.display.externalMeasured;
if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
display.externalMeasured = null;
if (line < display.viewFrom || line >= display.viewTo) return;
var lineView = display.view[findViewIndex(cm, line)];
if (lineView.node == null) return;
var arr = lineView.changes || (lineView.changes = []);
if (indexOf(arr, type) == -1) arr.push(type);
}
// Clear the view.
function resetView(cm) {
cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
cm.display.view = [];
cm.display.viewOffset = 0;
}
// Find the view element corresponding to a given line. Return null
// when the line isn't visible.
function findViewIndex(cm, n) {
if (n >= cm.display.viewTo) return null;
n -= cm.display.viewFrom;
if (n < 0) return null;
var view = cm.display.view;
for (var i = 0; i < view.length; i++) {
n -= view[i].size;
if (n < 0) return i;
}
}
function viewCuttingPoint(cm, oldN, newN, dir) {
var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
return {index: index, lineN: newN};
for (var i = 0, n = cm.display.viewFrom; i < index; i++)
n += view[i].size;
if (n != oldN) {
if (dir > 0) {
if (index == view.length - 1) return null;
diff = (n + view[index].size) - oldN;
index++;
} else {
diff = n - oldN;
}
oldN += diff; newN += diff;
}
while (visualLineNo(cm.doc, newN) != newN) {
if (index == (dir < 0 ? 0 : view.length - 1)) return null;
newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
index += dir;
}
return {index: index, lineN: newN};
}
// Force the view to cover a given range, adding empty view element
// or clipping off existing ones as needed.
function adjustView(cm, from, to) {
var display = cm.display, view = display.view;
if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
display.view = buildViewArray(cm, from, to);
display.viewFrom = from;
} else {
if (display.viewFrom > from)
display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view);
else if (display.viewFrom < from)
display.view = display.view.slice(findViewIndex(cm, from));
display.viewFrom = from;
if (display.viewTo < to)
display.view = display.view.concat(buildViewArray(cm, display.viewTo, to));
else if (display.viewTo > to)
display.view = display.view.slice(0, findViewIndex(cm, to));
}
display.viewTo = to;
}
// Count the number of lines in the view whose DOM representation is
// out of date (or nonexistent).
function countDirtyView(cm) {
var view = cm.display.view, dirty = 0;
for (var i = 0; i < view.length; i++) {
var lineView = view[i];
if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty;
}
return dirty;
}
// EVENT HANDLERS
// Attach the necessary event handlers when initializing the editor
function registerEventHandlers(cm) {
var d = cm.display;
on(d.scroller, "mousedown", operation(cm, onMouseDown));
// Older IE's will not fire a second mousedown for a double click
if (ie && ie_version < 11)
on(d.scroller, "dblclick", operation(cm, function(e) {
if (signalDOMEvent(cm, e)) return;
var pos = posFromMouse(cm, e);
if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) return;
e_preventDefault(e);
var word = cm.findWordAt(pos);
extendSelection(cm.doc, word.anchor, word.head);
}));
else
on(d.scroller, "dblclick", function(e) { signalDOMEvent(cm, e) || e_preventDefault(e); });
// Some browsers fire contextmenu *after* opening the menu, at
// which point we can't mess with it anymore. Context menu is
// handled in onMouseDown for these browsers.
if (!captureRightClick) on(d.scroller, "contextmenu", function(e) {onContextMenu(cm, e);});
// Used to suppress mouse event handling when a touch happens
var touchFinished, prevTouch = {end: 0};
function finishTouch() {
if (d.activeTouch) {
touchFinished = setTimeout(function() {d.activeTouch = null;}, 1000);
prevTouch = d.activeTouch;
prevTouch.end = +new Date;
}
};
function isMouseLikeTouchEvent(e) {
if (e.touches.length != 1) return false;
var touch = e.touches[0];
return touch.radiusX <= 1 && touch.radiusY <= 1;
}
function farAway(touch, other) {
if (other.left == null) return true;
var dx = other.left - touch.left, dy = other.top - touch.top;
return dx * dx + dy * dy > 20 * 20;
}
on(d.scroller, "touchstart", function(e) {
if (!isMouseLikeTouchEvent(e)) {
clearTimeout(touchFinished);
var now = +new Date;
d.activeTouch = {start: now, moved: false,
prev: now - prevTouch.end <= 300 ? prevTouch : null};
if (e.touches.length == 1) {
d.activeTouch.left = e.touches[0].pageX;
d.activeTouch.top = e.touches[0].pageY;
}
}
});
on(d.scroller, "touchmove", function() {
if (d.activeTouch) d.activeTouch.moved = true;
});
on(d.scroller, "touchend", function(e) {
var touch = d.activeTouch;
if (touch && !eventInWidget(d, e) && touch.left != null &&
!touch.moved && new Date - touch.start < 300) {
var pos = cm.coordsChar(d.activeTouch, "page"), range;
if (!touch.prev || farAway(touch, touch.prev)) // Single tap
range = new Range(pos, pos);
else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
range = cm.findWordAt(pos);
else // Triple tap
range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0)));
cm.setSelection(range.anchor, range.head);
cm.focus();
e_preventDefault(e);
}
finishTouch();
});
on(d.scroller, "touchcancel", finishTouch);
// Sync scrolling between fake scrollbars and real scrollable
// area, ensure viewport is updated when scrolling.
on(d.scroller, "scroll", function() {
if (d.scroller.clientHeight) {
setScrollTop(cm, d.scroller.scrollTop);
setScrollLeft(cm, d.scroller.scrollLeft, true);
signal(cm, "scroll", cm);
}
});
// Listen to wheel events in order to try and update the viewport on time.
on(d.scroller, "mousewheel", function(e){onScrollWheel(cm, e);});
on(d.scroller, "DOMMouseScroll", function(e){onScrollWheel(cm, e);});
// Prevent wrapper from ever scrolling
on(d.wrapper, "scroll", function() { d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
d.dragFunctions = {
enter: function(e) {if (!signalDOMEvent(cm, e)) e_stop(e);},
over: function(e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
start: function(e){onDragStart(cm, e);},
drop: operation(cm, onDrop),
leave: function() {clearDragCursor(cm);}
};
var inp = d.input.getField();
on(inp, "keyup", function(e) { onKeyUp.call(cm, e); });
on(inp, "keydown", operation(cm, onKeyDown));
on(inp, "keypress", operation(cm, onKeyPress));
on(inp, "focus", bind(onFocus, cm));
on(inp, "blur", bind(onBlur, cm));
}
function dragDropChanged(cm, value, old) {
var wasOn = old && old != CodeMirror.Init;
if (!value != !wasOn) {
var funcs = cm.display.dragFunctions;
var toggle = value ? on : off;
toggle(cm.display.scroller, "dragstart", funcs.start);
toggle(cm.display.scroller, "dragenter", funcs.enter);
toggle(cm.display.scroller, "dragover", funcs.over);
toggle(cm.display.scroller, "dragleave", funcs.leave);
toggle(cm.display.scroller, "drop", funcs.drop);
}
}
// Called when the window resizes
function onResize(cm) {
var d = cm.display;
if (d.lastWrapHeight == d.wrapper.clientHeight && d.lastWrapWidth == d.wrapper.clientWidth)
return;
// Might be a text scaling operation, clear size caches.
d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
d.scrollbarsClipped = false;
cm.setSize();
}
// MOUSE EVENTS
// Return true when the given mouse event happened in a widget
function eventInWidget(display, e) {
for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
(n.parentNode == display.sizer && n != display.mover))
return true;
}
}
// Given a mouse event, find the corresponding position. If liberal
// is false, it checks whether a gutter or scrollbar was clicked,
// and returns null if it was. forRect is used by rectangular
// selections, and tries to estimate a character position even for
// coordinates beyond the right of the text.
function posFromMouse(cm, e, liberal, forRect) {
var display = cm.display;
if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") return null;
var x, y, space = display.lineSpace.getBoundingClientRect();
// Fails unpredictably on IE[67] when mouse is dragged around quickly.
try { x = e.clientX - space.left; y = e.clientY - space.top; }
catch (e) { return null; }
var coords = coordsChar(cm, x, y), line;
if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
}
return coords;
}
// A mouse down can be a single click, double click, triple click,
// start of selection drag, start of text drag, new cursor
// (ctrl-click), rectangle drag (alt-drag), or xwin
// middle-click-paste. Or it might be a click on something we should
// not interfere with, such as a scrollbar or widget.
function onMouseDown(e) {
var cm = this, display = cm.display;
if (display.activeTouch && display.input.supportsTouch() || signalDOMEvent(cm, e)) return;
display.shift = e.shiftKey;
if (eventInWidget(display, e)) {
if (!webkit) {
// Briefly turn off draggability, to allow widgets to do
// normal dragging things.
display.scroller.draggable = false;
setTimeout(function(){display.scroller.draggable = true;}, 100);
}
return;
}
if (clickInGutter(cm, e)) return;
var start = posFromMouse(cm, e);
window.focus();
switch (e_button(e)) {
case 1:
// #3261: make sure, that we're not starting a second selection
if (cm.state.selectingText)
cm.state.selectingText(e);
else if (start)
leftButtonDown(cm, e, start);
else if (e_target(e) == display.scroller)
e_preventDefault(e);
break;
case 2:
if (webkit) cm.state.lastMiddleDown = +new Date;
if (start) extendSelection(cm.doc, start);
setTimeout(function() {display.input.focus();}, 20);
e_preventDefault(e);
break;
case 3:
if (captureRightClick) onContextMenu(cm, e);
else delayBlurEvent(cm);
break;
}
}
var lastClick, lastDoubleClick;
function leftButtonDown(cm, e, start) {
if (ie) setTimeout(bind(ensureFocus, cm), 0);
else cm.curOp.focus = activeElt();
var now = +new Date, type;
if (lastDoubleClick && lastDoubleClick.time > now - 400 && cmp(lastDoubleClick.pos, start) == 0) {
type = "triple";
} else if (lastClick && lastClick.time > now - 400 && cmp(lastClick.pos, start) == 0) {
type = "double";
lastDoubleClick = {time: now, pos: start};
} else {
type = "single";
lastClick = {time: now, pos: start};
}
var sel = cm.doc.sel, modifier = mac ? e.metaKey : e.ctrlKey, contained;
if (cm.options.dragDrop && dragAndDrop && !isReadOnly(cm) &&
type == "single" && (contained = sel.contains(start)) > -1 &&
(cmp((contained = sel.ranges[contained]).from(), start) < 0 || start.xRel > 0) &&
(cmp(contained.to(), start) > 0 || start.xRel < 0))
leftButtonStartDrag(cm, e, start, modifier);
else
leftButtonSelect(cm, e, start, type, modifier);
}
// Start a text drag. When it ends, see if any dragging actually
// happen, and treat as a click if it didn't.
function leftButtonStartDrag(cm, e, start, modifier) {
var display = cm.display, startTime = +new Date;
var dragEnd = operation(cm, function(e2) {
if (webkit) display.scroller.draggable = false;
cm.state.draggingText = false;
off(document, "mouseup", dragEnd);
off(display.scroller, "drop", dragEnd);
if (Math.abs(e.clientX - e2.clientX) + Math.abs(e.clientY - e2.clientY) < 10) {
e_preventDefault(e2);
if (!modifier && +new Date - 200 < startTime)
extendSelection(cm.doc, start);
// Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
if (webkit || ie && ie_version == 9)
setTimeout(function() {document.body.focus(); display.input.focus();}, 20);
else
display.input.focus();
}
});
// Let the drag handler handle this.
if (webkit) display.scroller.draggable = true;
cm.state.draggingText = dragEnd;
// IE's approach to draggable
if (display.scroller.dragDrop) display.scroller.dragDrop();
on(document, "mouseup", dragEnd);
on(display.scroller, "drop", dragEnd);
}
// Normal selection, as opposed to text dragging.
function leftButtonSelect(cm, e, start, type, addNew) {
var display = cm.display, doc = cm.doc;
e_preventDefault(e);
var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
if (addNew && !e.shiftKey) {
ourIndex = doc.sel.contains(start);
if (ourIndex > -1)
ourRange = ranges[ourIndex];
else
ourRange = new Range(start, start);
} else {
ourRange = doc.sel.primary();
ourIndex = doc.sel.primIndex;
}
if (e.altKey) {
type = "rect";
if (!addNew) ourRange = new Range(start, start);
start = posFromMouse(cm, e, true, true);
ourIndex = -1;
} else if (type == "double") {
var word = cm.findWordAt(start);
if (cm.display.shift || doc.extend)
ourRange = extendRange(doc, ourRange, word.anchor, word.head);
else
ourRange = word;
} else if (type == "triple") {
var line = new Range(Pos(start.line, 0), clipPos(doc, Pos(start.line + 1, 0)));
if (cm.display.shift || doc.extend)
ourRange = extendRange(doc, ourRange, line.anchor, line.head);
else
ourRange = line;
} else {
ourRange = extendRange(doc, ourRange, start);
}
if (!addNew) {
ourIndex = 0;
setSelection(doc, new Selection([ourRange], 0), sel_mouse);
startSel = doc.sel;
} else if (ourIndex == -1) {
ourIndex = ranges.length;
setSelection(doc, normalizeSelection(ranges.concat([ourRange]), ourIndex),
{scroll: false, origin: "*mouse"});
} else if (ranges.length > 1 && ranges[ourIndex].empty() && type == "single" && !e.shiftKey) {
setSelection(doc, normalizeSelection(ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
{scroll: false, origin: "*mouse"});
startSel = doc.sel;
} else {
replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
}
var lastPos = start;
function extendTo(pos) {
if (cmp(lastPos, pos) == 0) return;
lastPos = pos;
if (type == "rect") {
var ranges = [], tabSize = cm.options.tabSize;
var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
line <= end; line++) {
var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
if (left == right)
ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos)));
else if (text.length > leftPos)
ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize))));
}
if (!ranges.length) ranges.push(new Range(start, start));
setSelection(doc, normalizeSelection(startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
{origin: "*mouse", scroll: false});
cm.scrollIntoView(pos);
} else {
var oldRange = ourRange;
var anchor = oldRange.anchor, head = pos;
if (type != "single") {
if (type == "double")
var range = cm.findWordAt(pos);
else
var range = new Range(Pos(pos.line, 0), clipPos(doc, Pos(pos.line + 1, 0)));
if (cmp(range.anchor, anchor) > 0) {
head = range.head;
anchor = minPos(oldRange.from(), range.anchor);
} else {
head = range.anchor;
anchor = maxPos(oldRange.to(), range.head);
}
}
var ranges = startSel.ranges.slice(0);
ranges[ourIndex] = new Range(clipPos(doc, anchor), head);
setSelection(doc, normalizeSelection(ranges, ourIndex), sel_mouse);
}
}
var editorSize = display.wrapper.getBoundingClientRect();
// Used to ensure timeout re-tries don't fire when another extend
// happened in the meantime (clearTimeout isn't reliable -- at
// least on Chrome, the timeouts still happen even when cleared,
// if the clear happens after their scheduled firing time).
var counter = 0;
function extend(e) {
var curCount = ++counter;
var cur = posFromMouse(cm, e, true, type == "rect");
if (!cur) return;
if (cmp(cur, lastPos) != 0) {
cm.curOp.focus = activeElt();
extendTo(cur);
var visible = visibleLines(display, doc);
if (cur.line >= visible.to || cur.line < visible.from)
setTimeout(operation(cm, function(){if (counter == curCount) extend(e);}), 150);
} else {
var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
if (outside) setTimeout(operation(cm, function() {
if (counter != curCount) return;
display.scroller.scrollTop += outside;
extend(e);
}), 50);
}
}
function done(e) {
cm.state.selectingText = false;
counter = Infinity;
e_preventDefault(e);
display.input.focus();
off(document, "mousemove", move);
off(document, "mouseup", up);
doc.history.lastSelOrigin = null;
}
var move = operation(cm, function(e) {
if (!e_button(e)) done(e);
else extend(e);
});
var up = operation(cm, done);
cm.state.selectingText = up;
on(document, "mousemove", move);
on(document, "mouseup", up);
}
// Determines whether an event happened in the gutter, and fires the
// handlers for the corresponding event.
function gutterEvent(cm, e, type, prevent) {
try { var mX = e.clientX, mY = e.clientY; }
catch(e) { return false; }
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) return false;
if (prevent) e_preventDefault(e);
var display = cm.display;
var lineBox = display.lineDiv.getBoundingClientRect();
if (mY > lineBox.bottom || !hasHandler(cm, type)) return e_defaultPrevented(e);
mY -= lineBox.top - display.viewOffset;
for (var i = 0; i < cm.options.gutters.length; ++i) {
var g = display.gutters.childNodes[i];
if (g && g.getBoundingClientRect().right >= mX) {
var line = lineAtHeight(cm.doc, mY);
var gutter = cm.options.gutters[i];
signal(cm, type, cm, line, gutter, e);
return e_defaultPrevented(e);
}
}
}
function clickInGutter(cm, e) {
return gutterEvent(cm, e, "gutterClick", true);
}
// Kludge to work around strange IE behavior where it'll sometimes
// re-fire a series of drag-related events right after the drop (#1551)
var lastDrop = 0;
function onDrop(e) {
var cm = this;
clearDragCursor(cm);
if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
return;
e_preventDefault(e);
if (ie) lastDrop = +new Date;
var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
if (!pos || isReadOnly(cm)) return;
// Might be a file drop, in which case we simply extract the text
// and insert it.
if (files && files.length && window.FileReader && window.File) {
var n = files.length, text = Array(n), read = 0;
var loadFile = function(file, i) {
if (cm.options.allowDropFileTypes &&
indexOf(cm.options.allowDropFileTypes, file.type) == -1)
return;
var reader = new FileReader;
reader.onload = operation(cm, function() {
var content = reader.result;
if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "";
text[i] = content;
if (++read == n) {
pos = clipPos(cm.doc, pos);
var change = {from: pos, to: pos,
text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
origin: "paste"};
makeChange(cm.doc, change);
setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
}
});
reader.readAsText(file);
};
for (var i = 0; i < n; ++i) loadFile(files[i], i);
} else { // Normal drop
// Don't do a replace if the drop happened inside of the selected text.
if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
cm.state.draggingText(e);
// Ensure the editor is re-focused
setTimeout(function() {cm.display.input.focus();}, 20);
return;
}
try {
var text = e.dataTransfer.getData("Text");
if (text) {
if (cm.state.draggingText && !(mac ? e.altKey : e.ctrlKey))
var selected = cm.listSelections();
setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
if (selected) for (var i = 0; i < selected.length; ++i)
replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag");
cm.replaceSelection(text, "around", "paste");
cm.display.input.focus();
}
}
catch(e){}
}
}
function onDragStart(cm, e) {
if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return; }
if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return;
e.dataTransfer.setData("Text", cm.getSelection());
// Use dummy image instead of default browsers image.
// Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
if (e.dataTransfer.setDragImage && !safari) {
var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
if (presto) {
img.width = img.height = 1;
cm.display.wrapper.appendChild(img);
// Force a relayout, or Opera won't use our image for some obscure reason
img._top = img.offsetTop;
}
e.dataTransfer.setDragImage(img, 0, 0);
if (presto) img.parentNode.removeChild(img);
}
}
function onDragOver(cm, e) {
var pos = posFromMouse(cm, e);
if (!pos) return;
var frag = document.createDocumentFragment();
drawSelectionCursor(cm, pos, frag);
if (!cm.display.dragCursor) {
cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
}
removeChildrenAndAdd(cm.display.dragCursor, frag);
}
function clearDragCursor(cm) {
if (cm.display.dragCursor) {
cm.display.lineSpace.removeChild(cm.display.dragCursor);
cm.display.dragCursor = null;
}
}
// SCROLL EVENTS
// Sync the scrollable area and scrollbars, ensure the viewport
// covers the visible area.
function setScrollTop(cm, val) {
if (Math.abs(cm.doc.scrollTop - val) < 2) return;
cm.doc.scrollTop = val;
if (!gecko) updateDisplaySimple(cm, {top: val});
if (cm.display.scroller.scrollTop != val) cm.display.scroller.scrollTop = val;
cm.display.scrollbars.setScrollTop(val);
if (gecko) updateDisplaySimple(cm);
startWorker(cm, 100);
}
// Sync scroller and scrollbar, ensure the gutter elements are
// aligned.
function setScrollLeft(cm, val, isScroller) {
if (isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) return;
val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
cm.doc.scrollLeft = val;
alignHorizontally(cm);
if (cm.display.scroller.scrollLeft != val) cm.display.scroller.scrollLeft = val;
cm.display.scrollbars.setScrollLeft(val);
}
// Since the delta values reported on mouse wheel events are
// unstandardized between browsers and even browser versions, and
// generally horribly unpredictable, this code starts by measuring
// the scroll effect that the first few mouse wheel events have,
// and, from that, detects the way it can convert deltas to pixel
// offsets afterwards.
//
// The reason we want to know the amount a wheel event will scroll
// is that it gives us a chance to update the display before the
// actual scrolling happens, reducing flickering.
var wheelSamples = 0, wheelPixelsPerUnit = null;
// Fill in a browser-detected starting value on browsers where we
// know one. These don't have to be accurate -- the result of them
// being wrong would just be a slight flicker on the first wheel
// scroll (if it is large enough).
if (ie) wheelPixelsPerUnit = -.53;
else if (gecko) wheelPixelsPerUnit = 15;
else if (chrome) wheelPixelsPerUnit = -.7;
else if (safari) wheelPixelsPerUnit = -1/3;
var wheelEventDelta = function(e) {
var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) dx = e.detail;
if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) dy = e.detail;
else if (dy == null) dy = e.wheelDelta;
return {x: dx, y: dy};
};
CodeMirror.wheelEventPixels = function(e) {
var delta = wheelEventDelta(e);
delta.x *= wheelPixelsPerUnit;
delta.y *= wheelPixelsPerUnit;
return delta;
};
function onScrollWheel(cm, e) {
var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
var display = cm.display, scroll = display.scroller;
// Quit if there's nothing to scroll here
var canScrollX = scroll.scrollWidth > scroll.clientWidth;
var canScrollY = scroll.scrollHeight > scroll.clientHeight;
if (!(dx && canScrollX || dy && canScrollY)) return;
// Webkit browsers on OS X abort momentum scrolls when the target
// of the scroll event is removed from the scrollable element.
// This hack (see related code in patchDisplay) makes sure the
// element is kept around.
if (dy && mac && webkit) {
outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
for (var i = 0; i < view.length; i++) {
if (view[i].node == cur) {
cm.display.currentWheelTarget = cur;
break outer;
}
}
}
}
// On some browsers, horizontal scrolling will cause redraws to
// happen before the gutter has been realigned, causing it to
// wriggle around in a most unseemly way. When we have an
// estimated pixels/delta value, we just handle horizontal
// scrolling entirely here. It'll be slightly off from native, but
// better than glitching out.
if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
if (dy && canScrollY)
setScrollTop(cm, Math.max(0, Math.min(scroll.scrollTop + dy * wheelPixelsPerUnit, scroll.scrollHeight - scroll.clientHeight)));
setScrollLeft(cm, Math.max(0, Math.min(scroll.scrollLeft + dx * wheelPixelsPerUnit, scroll.scrollWidth - scroll.clientWidth)));
// Only prevent default scrolling if vertical scrolling is
// actually possible. Otherwise, it causes vertical scroll
// jitter on OSX trackpads when deltaX is small and deltaY
// is large (issue #3579)
if (!dy || (dy && canScrollY))
e_preventDefault(e);
display.wheelStartX = null; // Abort measurement, if in progress
return;
}
// 'Project' the visible viewport to cover the area that is being
// scrolled into view (if we know enough to estimate it).
if (dy && wheelPixelsPerUnit != null) {
var pixels = dy * wheelPixelsPerUnit;
var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
if (pixels < 0) top = Math.max(0, top + pixels - 50);
else bot = Math.min(cm.doc.height, bot + pixels + 50);
updateDisplaySimple(cm, {top: top, bottom: bot});
}
if (wheelSamples < 20) {
if (display.wheelStartX == null) {
display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
display.wheelDX = dx; display.wheelDY = dy;
setTimeout(function() {
if (display.wheelStartX == null) return;
var movedX = scroll.scrollLeft - display.wheelStartX;
var movedY = scroll.scrollTop - display.wheelStartY;
var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
(movedX && display.wheelDX && movedX / display.wheelDX);
display.wheelStartX = display.wheelStartY = null;
if (!sample) return;
wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
++wheelSamples;
}, 200);
} else {
display.wheelDX += dx; display.wheelDY += dy;
}
}
}
// KEY EVENTS
// Run a handler that was bound to a key.
function doHandleBinding(cm, bound, dropShift) {
if (typeof bound == "string") {
bound = commands[bound];
if (!bound) return false;
}
// Ensure previous input has been read, so that the handler sees a
// consistent view of the document
cm.display.input.ensurePolled();
var prevShift = cm.display.shift, done = false;
try {
if (isReadOnly(cm)) cm.state.suppressEdits = true;
if (dropShift) cm.display.shift = false;
done = bound(cm) != Pass;
} finally {
cm.display.shift = prevShift;
cm.state.suppressEdits = false;
}
return done;
}
function lookupKeyForEditor(cm, name, handle) {
for (var i = 0; i < cm.state.keyMaps.length; i++) {
var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
if (result) return result;
}
return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
|| lookupKey(name, cm.options.keyMap, handle, cm);
}
var stopSeq = new Delayed;
function dispatchKey(cm, name, e, handle) {
var seq = cm.state.keySeq;
if (seq) {
if (isModifierKey(name)) return "handled";
stopSeq.set(50, function() {
if (cm.state.keySeq == seq) {
cm.state.keySeq = null;
cm.display.input.reset();
}
});
name = seq + " " + name;
}
var result = lookupKeyForEditor(cm, name, handle);
if (result == "multi")
cm.state.keySeq = name;
if (result == "handled")
signalLater(cm, "keyHandled", cm, name, e);
if (result == "handled" || result == "multi") {
e_preventDefault(e);
restartBlink(cm);
}
if (seq && !result && /\'$/.test(name)) {
e_preventDefault(e);
return true;
}
return !!result;
}
// Handle a key from the keydown event.
function handleKeyBinding(cm, e) {
var name = keyName(e, true);
if (!name) return false;
if (e.shiftKey && !cm.state.keySeq) {
// First try to resolve full name (including 'Shift-'). Failing
// that, see if there is a cursor-motion command (starting with
// 'go') bound to the keyname without 'Shift-'.
return dispatchKey(cm, "Shift-" + name, e, function(b) {return doHandleBinding(cm, b, true);})
|| dispatchKey(cm, name, e, function(b) {
if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
return doHandleBinding(cm, b);
});
} else {
return dispatchKey(cm, name, e, function(b) { return doHandleBinding(cm, b); });
}
}
// Handle a key from the keypress event
function handleCharBinding(cm, e, ch) {
return dispatchKey(cm, "'" + ch + "'", e,
function(b) { return doHandleBinding(cm, b, true); });
}
var lastStoppedKey = null;
function onKeyDown(e) {
var cm = this;
cm.curOp.focus = activeElt();
if (signalDOMEvent(cm, e)) return;
// IE does strange things with escape.
if (ie && ie_version < 11 && e.keyCode == 27) e.returnValue = false;
var code = e.keyCode;
cm.display.shift = code == 16 || e.shiftKey;
var handled = handleKeyBinding(cm, e);
if (presto) {
lastStoppedKey = handled ? code : null;
// Opera has no cut event... we try to at least catch the key combo
if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
cm.replaceSelection("", null, "cut");
}
// Turn mouse into crosshair when Alt is held on Mac.
if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
showCrossHair(cm);
}
function showCrossHair(cm) {
var lineDiv = cm.display.lineDiv;
addClass(lineDiv, "CodeMirror-crosshair");
function up(e) {
if (e.keyCode == 18 || !e.altKey) {
rmClass(lineDiv, "CodeMirror-crosshair");
off(document, "keyup", up);
off(document, "mouseover", up);
}
}
on(document, "keyup", up);
on(document, "mouseover", up);
}
function onKeyUp(e) {
if (e.keyCode == 16) this.doc.sel.shift = false;
signalDOMEvent(this, e);
}
function onKeyPress(e) {
var cm = this;
if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) return;
var keyCode = e.keyCode, charCode = e.charCode;
if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return;}
if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) return;
var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
if (handleCharBinding(cm, e, ch)) return;
cm.display.input.onKeyPress(e);
}
// FOCUS/BLUR EVENTS
function delayBlurEvent(cm) {
cm.state.delayingBlurEvent = true;
setTimeout(function() {
if (cm.state.delayingBlurEvent) {
cm.state.delayingBlurEvent = false;
onBlur(cm);
}
}, 100);
}
function onFocus(cm) {
if (cm.state.delayingBlurEvent) cm.state.delayingBlurEvent = false;
if (cm.options.readOnly == "nocursor") return;
if (!cm.state.focused) {
signal(cm, "focus", cm);
cm.state.focused = true;
addClass(cm.display.wrapper, "CodeMirror-focused");
// This test prevents this from firing when a context
// menu is closed (since the input reset would kill the
// select-all detection hack)
if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
cm.display.input.reset();
if (webkit) setTimeout(function() { cm.display.input.reset(true); }, 20); // Issue #1730
}
cm.display.input.receivedFocus();
}
restartBlink(cm);
}
function onBlur(cm) {
if (cm.state.delayingBlurEvent) return;
if (cm.state.focused) {
signal(cm, "blur", cm);
cm.state.focused = false;
rmClass(cm.display.wrapper, "CodeMirror-focused");
}
clearInterval(cm.display.blinker);
setTimeout(function() {if (!cm.state.focused) cm.display.shift = false;}, 150);
}
// CONTEXT MENU HANDLING
// To make the context menu work, we need to briefly unhide the
// textarea (making it as unobtrusive as possible) to let the
// right-click take effect on it.
function onContextMenu(cm, e) {
if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) return;
if (signalDOMEvent(cm, e, "contextmenu")) return;
cm.display.input.onContextMenu(e);
}
function contextMenuInGutter(cm, e) {
if (!hasHandler(cm, "gutterContextMenu")) return false;
return gutterEvent(cm, e, "gutterContextMenu", false);
}
// UPDATING
// Compute the position of the end of a change (its 'to' property
// refers to the pre-change end).
var changeEnd = CodeMirror.changeEnd = function(change) {
if (!change.text) return change.to;
return Pos(change.from.line + change.text.length - 1,
lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0));
};
// Adjust a position to refer to the post-change position of the
// same text, or the end of the change if the change covers it.
function adjustForChange(pos, change) {
if (cmp(pos, change.from) < 0) return pos;
if (cmp(pos, change.to) <= 0) return changeEnd(change);
var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
if (pos.line == change.to.line) ch += changeEnd(change).ch - change.to.ch;
return Pos(line, ch);
}
function computeSelAfterChange(doc, change) {
var out = [];
for (var i = 0; i < doc.sel.ranges.length; i++) {
var range = doc.sel.ranges[i];
out.push(new Range(adjustForChange(range.anchor, change),
adjustForChange(range.head, change)));
}
return normalizeSelection(out, doc.sel.primIndex);
}
function offsetPos(pos, old, nw) {
if (pos.line == old.line)
return Pos(nw.line, pos.ch - old.ch + nw.ch);
else
return Pos(nw.line + (pos.line - old.line), pos.ch);
}
// Used by replaceSelections to allow moving the selection to the
// start or around the replaced test. Hint may be "start" or "around".
function computeReplacedSel(doc, changes, hint) {
var out = [];
var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
for (var i = 0; i < changes.length; i++) {
var change = changes[i];
var from = offsetPos(change.from, oldPrev, newPrev);
var to = offsetPos(changeEnd(change), oldPrev, newPrev);
oldPrev = change.to;
newPrev = to;
if (hint == "around") {
var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
out[i] = new Range(inv ? to : from, inv ? from : to);
} else {
out[i] = new Range(from, from);
}
}
return new Selection(out, doc.sel.primIndex);
}
// Allow "beforeChange" event handlers to influence a change
function filterChange(doc, change, update) {
var obj = {
canceled: false,
from: change.from,
to: change.to,
text: change.text,
origin: change.origin,
cancel: function() { this.canceled = true; }
};
if (update) obj.update = function(from, to, text, origin) {
if (from) this.from = clipPos(doc, from);
if (to) this.to = clipPos(doc, to);
if (text) this.text = text;
if (origin !== undefined) this.origin = origin;
};
signal(doc, "beforeChange", doc, obj);
if (doc.cm) signal(doc.cm, "beforeChange", doc.cm, obj);
if (obj.canceled) return null;
return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin};
}
// Apply a change to a document, and add it to the document's
// history, and propagating it to all linked documents.
function makeChange(doc, change, ignoreReadOnly) {
if (doc.cm) {
if (!doc.cm.curOp) return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly);
if (doc.cm.state.suppressEdits) return;
}
if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
change = filterChange(doc, change, true);
if (!change) return;
}
// Possibly split or suppress the update based on the presence
// of read-only spans in its range.
var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
if (split) {
for (var i = split.length - 1; i >= 0; --i)
makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text});
} else {
makeChangeInner(doc, change);
}
}
function makeChangeInner(doc, change) {
if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) return;
var selAfter = computeSelAfterChange(doc, change);
addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
var rebased = [];
linkedDocs(doc, function(doc, sharedHist) {
if (!sharedHist && indexOf(rebased, doc.history) == -1) {
rebaseHist(doc.history, change);
rebased.push(doc.history);
}
makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
});
}
// Revert a change stored in a document's history.
function makeChangeFromHistory(doc, type, allowSelectionOnly) {
if (doc.cm && doc.cm.state.suppressEdits) return;
var hist = doc.history, event, selAfter = doc.sel;
var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
// Verify that there is a useable event (so that ctrl-z won't
// needlessly clear selection events)
for (var i = 0; i < source.length; i++) {
event = source[i];
if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
break;
}
if (i == source.length) return;
hist.lastOrigin = hist.lastSelOrigin = null;
for (;;) {
event = source.pop();
if (event.ranges) {
pushSelectionToHistory(event, dest);
if (allowSelectionOnly && !event.equals(doc.sel)) {
setSelection(doc, event, {clearRedo: false});
return;
}
selAfter = event;
}
else break;
}
// Build up a reverse change object to add to the opposite history
// stack (redo when undoing, and vice versa).
var antiChanges = [];
pushSelectionToHistory(selAfter, dest);
dest.push({changes: antiChanges, generation: hist.generation});
hist.generation = event.generation || ++hist.maxGeneration;
var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
for (var i = event.changes.length - 1; i >= 0; --i) {
var change = event.changes[i];
change.origin = type;
if (filter && !filterChange(doc, change, false)) {
source.length = 0;
return;
}
antiChanges.push(historyChangeFromChange(doc, change));
var after = i ? computeSelAfterChange(doc, change) : lst(source);
makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
if (!i && doc.cm) doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)});
var rebased = [];
// Propagate to the linked documents
linkedDocs(doc, function(doc, sharedHist) {
if (!sharedHist && indexOf(rebased, doc.history) == -1) {
rebaseHist(doc.history, change);
rebased.push(doc.history);
}
makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
});
}
}
// Sub-views need their line numbers shifted when text is added
// above or below them in the parent document.
function shiftDoc(doc, distance) {
if (distance == 0) return;
doc.first += distance;
doc.sel = new Selection(map(doc.sel.ranges, function(range) {
return new Range(Pos(range.anchor.line + distance, range.anchor.ch),
Pos(range.head.line + distance, range.head.ch));
}), doc.sel.primIndex);
if (doc.cm) {
regChange(doc.cm, doc.first, doc.first - distance, distance);
for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
regLineChange(doc.cm, l, "gutter");
}
}
// More lower-level change function, handling only a single document
// (not linked ones).
function makeChangeSingleDoc(doc, change, selAfter, spans) {
if (doc.cm && !doc.cm.curOp)
return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans);
if (change.to.line < doc.first) {
shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
return;
}
if (change.from.line > doc.lastLine()) return;
// Clip the change to the size of this doc
if (change.from.line < doc.first) {
var shift = change.text.length - 1 - (doc.first - change.from.line);
shiftDoc(doc, shift);
change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
text: [lst(change.text)], origin: change.origin};
}
var last = doc.lastLine();
if (change.to.line > last) {
change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
text: [change.text[0]], origin: change.origin};
}
change.removed = getBetween(doc, change.from, change.to);
if (!selAfter) selAfter = computeSelAfterChange(doc, change);
if (doc.cm) makeChangeSingleDocInEditor(doc.cm, change, spans);
else updateDoc(doc, change, spans);
setSelectionNoUndo(doc, selAfter, sel_dontScroll);
}
// Handle the interaction of a change to a document with the editor
// that this document is part of.
function makeChangeSingleDocInEditor(cm, change, spans) {
var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
var recomputeMaxLength = false, checkWidthStart = from.line;
if (!cm.options.lineWrapping) {
checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
doc.iter(checkWidthStart, to.line + 1, function(line) {
if (line == display.maxLine) {
recomputeMaxLength = true;
return true;
}
});
}
if (doc.sel.contains(change.from, change.to) > -1)
signalCursorActivity(cm);
updateDoc(doc, change, spans, estimateHeight(cm));
if (!cm.options.lineWrapping) {
doc.iter(checkWidthStart, from.line + change.text.length, function(line) {
var len = lineLength(line);
if (len > display.maxLineLength) {
display.maxLine = line;
display.maxLineLength = len;
display.maxLineChanged = true;
recomputeMaxLength = false;
}
});
if (recomputeMaxLength) cm.curOp.updateMaxLine = true;
}
// Adjust frontier, schedule worker
doc.frontier = Math.min(doc.frontier, from.line);
startWorker(cm, 400);
var lendiff = change.text.length - (to.line - from.line) - 1;
// Remember that these lines changed, for updating the display
if (change.full)
regChange(cm);
else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
regLineChange(cm, from.line, "text");
else
regChange(cm, from.line, to.line + 1, lendiff);
var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
if (changeHandler || changesHandler) {
var obj = {
from: from, to: to,
text: change.text,
removed: change.removed,
origin: change.origin
};
if (changeHandler) signalLater(cm, "change", cm, obj);
if (changesHandler) (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj);
}
cm.display.selForContextMenu = null;
}
function replaceRange(doc, code, from, to, origin) {
if (!to) to = from;
if (cmp(to, from) < 0) { var tmp = to; to = from; from = tmp; }
if (typeof code == "string") code = doc.splitLines(code);
makeChange(doc, {from: from, to: to, text: code, origin: origin});
}
// SCROLLING THINGS INTO VIEW
// If an editor sits on the top or bottom of the window, partially
// scrolled out of view, this ensures that the cursor is visible.
function maybeScrollWindow(cm, coords) {
if (signalDOMEvent(cm, "scrollCursorIntoView")) return;
var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
if (coords.top + box.top < 0) doScroll = true;
else if (coords.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) doScroll = false;
if (doScroll != null && !phantom) {
var scrollNode = elt("div", "\u200b", null, "position: absolute; top: " +
(coords.top - display.viewOffset - paddingTop(cm.display)) + "px; height: " +
(coords.bottom - coords.top + scrollGap(cm) + display.barHeight) + "px; left: " +
coords.left + "px; width: 2px;");
cm.display.lineSpace.appendChild(scrollNode);
scrollNode.scrollIntoView(doScroll);
cm.display.lineSpace.removeChild(scrollNode);
}
}
// Scroll a given position into view (immediately), verifying that
// it actually became visible (as line heights are accurately
// measured, the position of something may 'drift' during drawing).
function scrollPosIntoView(cm, pos, end, margin) {
if (margin == null) margin = 0;
for (var limit = 0; limit < 5; limit++) {
var changed = false, coords = cursorCoords(cm, pos);
var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
var scrollPos = calculateScrollPos(cm, Math.min(coords.left, endCoords.left),
Math.min(coords.top, endCoords.top) - margin,
Math.max(coords.left, endCoords.left),
Math.max(coords.bottom, endCoords.bottom) + margin);
var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
if (scrollPos.scrollTop != null) {
setScrollTop(cm, scrollPos.scrollTop);
if (Math.abs(cm.doc.scrollTop - startTop) > 1) changed = true;
}
if (scrollPos.scrollLeft != null) {
setScrollLeft(cm, scrollPos.scrollLeft);
if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) changed = true;
}
if (!changed) break;
}
return coords;
}
// Scroll a given set of coordinates into view (immediately).
function scrollIntoView(cm, x1, y1, x2, y2) {
var scrollPos = calculateScrollPos(cm, x1, y1, x2, y2);
if (scrollPos.scrollTop != null) setScrollTop(cm, scrollPos.scrollTop);
if (scrollPos.scrollLeft != null) setScrollLeft(cm, scrollPos.scrollLeft);
}
// Calculate a new scroll position needed to scroll the given
// rectangle into view. Returns an object with scrollTop and
// scrollLeft properties. When these are undefined, the
// vertical/horizontal position does not need to be adjusted.
function calculateScrollPos(cm, x1, y1, x2, y2) {
var display = cm.display, snapMargin = textHeight(cm.display);
if (y1 < 0) y1 = 0;
var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
var screen = displayHeight(cm), result = {};
if (y2 - y1 > screen) y2 = y1 + screen;
var docBottom = cm.doc.height + paddingVert(display);
var atTop = y1 < snapMargin, atBottom = y2 > docBottom - snapMargin;
if (y1 < screentop) {
result.scrollTop = atTop ? 0 : y1;
} else if (y2 > screentop + screen) {
var newTop = Math.min(y1, (atBottom ? docBottom : y2) - screen);
if (newTop != screentop) result.scrollTop = newTop;
}
var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
var tooWide = x2 - x1 > screenw;
if (tooWide) x2 = x1 + screenw;
if (x1 < 10)
result.scrollLeft = 0;
else if (x1 < screenleft)
result.scrollLeft = Math.max(0, x1 - (tooWide ? 0 : 10));
else if (x2 > screenw + screenleft - 3)
result.scrollLeft = x2 + (tooWide ? 0 : 10) - screenw;
return result;
}
// Store a relative adjustment to the scroll position in the current
// operation (to be applied when the operation finishes).
function addToScrollPos(cm, left, top) {
if (left != null || top != null) resolveScrollToPos(cm);
if (left != null)
cm.curOp.scrollLeft = (cm.curOp.scrollLeft == null ? cm.doc.scrollLeft : cm.curOp.scrollLeft) + left;
if (top != null)
cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
}
// Make sure that at the end of the operation the current cursor is
// shown.
function ensureCursorVisible(cm) {
resolveScrollToPos(cm);
var cur = cm.getCursor(), from = cur, to = cur;
if (!cm.options.lineWrapping) {
from = cur.ch ? Pos(cur.line, cur.ch - 1) : cur;
to = Pos(cur.line, cur.ch + 1);
}
cm.curOp.scrollToPos = {from: from, to: to, margin: cm.options.cursorScrollMargin, isCursor: true};
}
// When an operation has its scrollToPos property set, and another
// scroll action is applied before the end of the operation, this
// 'simulates' scrolling that position into view in a cheap way, so
// that the effect of intermediate scroll commands is not ignored.
function resolveScrollToPos(cm) {
var range = cm.curOp.scrollToPos;
if (range) {
cm.curOp.scrollToPos = null;
var from = estimateCoords(cm, range.from), to = estimateCoords(cm, range.to);
var sPos = calculateScrollPos(cm, Math.min(from.left, to.left),
Math.min(from.top, to.top) - range.margin,
Math.max(from.right, to.right),
Math.max(from.bottom, to.bottom) + range.margin);
cm.scrollTo(sPos.scrollLeft, sPos.scrollTop);
}
}
// API UTILITIES
// Indent the given line. The how parameter can be "smart",
// "add"/null, "subtract", or "prev". When aggressive is false
// (typically set to true for forced single-line indents), empty
// lines are not indented, and places where the mode returns Pass
// are left alone.
function indentLine(cm, n, how, aggressive) {
var doc = cm.doc, state;
if (how == null) how = "add";
if (how == "smart") {
// Fall back to "prev" when the mode doesn't have an indentation
// method.
if (!doc.mode.indent) how = "prev";
else state = getStateBefore(cm, n);
}
var tabSize = cm.options.tabSize;
var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
if (line.stateAfter) line.stateAfter = null;
var curSpaceString = line.text.match(/^\s*/)[0], indentation;
if (!aggressive && !/\S/.test(line.text)) {
indentation = 0;
how = "not";
} else if (how == "smart") {
indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
if (indentation == Pass || indentation > 150) {
if (!aggressive) return;
how = "prev";
}
}
if (how == "prev") {
if (n > doc.first) indentation = countColumn(getLine(doc, n-1).text, null, tabSize);
else indentation = 0;
} else if (how == "add") {
indentation = curSpace + cm.options.indentUnit;
} else if (how == "subtract") {
indentation = curSpace - cm.options.indentUnit;
} else if (typeof how == "number") {
indentation = curSpace + how;
}
indentation = Math.max(0, indentation);
var indentString = "", pos = 0;
if (cm.options.indentWithTabs)
for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";}
if (pos < indentation) indentString += spaceStr(indentation - pos);
if (indentString != curSpaceString) {
replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
line.stateAfter = null;
return true;
} else {
// Ensure that, if the cursor was in the whitespace at the start
// of the line, it is moved to the end of that space.
for (var i = 0; i < doc.sel.ranges.length; i++) {
var range = doc.sel.ranges[i];
if (range.head.line == n && range.head.ch < curSpaceString.length) {
var pos = Pos(n, curSpaceString.length);
replaceOneSelection(doc, i, new Range(pos, pos));
break;
}
}
}
}
// Utility for applying a change to a line by handle or number,
// returning the number and optionally registering the line as
// changed.
function changeLine(doc, handle, changeType, op) {
var no = handle, line = handle;
if (typeof handle == "number") line = getLine(doc, clipLine(doc, handle));
else no = lineNo(handle);
if (no == null) return null;
if (op(line, no) && doc.cm) regLineChange(doc.cm, no, changeType);
return line;
}
// Helper for deleting text near the selection(s), used to implement
// backspace, delete, and similar functionality.
function deleteNearSelection(cm, compute) {
var ranges = cm.doc.sel.ranges, kill = [];
// Build up a set of ranges to kill first, merging overlapping
// ranges.
for (var i = 0; i < ranges.length; i++) {
var toKill = compute(ranges[i]);
while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
var replaced = kill.pop();
if (cmp(replaced.from, toKill.from) < 0) {
toKill.from = replaced.from;
break;
}
}
kill.push(toKill);
}
// Next, remove those actual ranges.
runInOp(cm, function() {
for (var i = kill.length - 1; i >= 0; i--)
replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete");
ensureCursorVisible(cm);
});
}
// Used for horizontal relative motion. Dir is -1 or 1 (left or
// right), unit can be "char", "column" (like char, but doesn't
// cross line boundaries), "word" (across next word), or "group" (to
// the start of next group of word or non-word-non-whitespace
// chars). The visually param controls whether, in right-to-left
// text, direction 1 means to move towards the next index in the
// string, or towards the character to the right of the current
// position. The resulting position will have a hitSide=true
// property if it reached the end of the document.
function findPosH(doc, pos, dir, unit, visually) {
var line = pos.line, ch = pos.ch, origDir = dir;
var lineObj = getLine(doc, line);
var possible = true;
function findNextLine() {
var l = line + dir;
if (l < doc.first || l >= doc.first + doc.size) return (possible = false);
line = l;
return lineObj = getLine(doc, l);
}
function moveOnce(boundToLine) {
var next = (visually ? moveVisually : moveLogically)(lineObj, ch, dir, true);
if (next == null) {
if (!boundToLine && findNextLine()) {
if (visually) ch = (dir < 0 ? lineRight : lineLeft)(lineObj);
else ch = dir < 0 ? lineObj.text.length : 0;
} else return (possible = false);
} else ch = next;
return true;
}
if (unit == "char") moveOnce();
else if (unit == "column") moveOnce(true);
else if (unit == "word" || unit == "group") {
var sawType = null, group = unit == "group";
var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
for (var first = true;; first = false) {
if (dir < 0 && !moveOnce(!first)) break;
var cur = lineObj.text.charAt(ch) || "\n";
var type = isWordChar(cur, helper) ? "w"
: group && cur == "\n" ? "n"
: !group || /\s/.test(cur) ? null
: "p";
if (group && !first && !type) type = "s";
if (sawType && sawType != type) {
if (dir < 0) {dir = 1; moveOnce();}
break;
}
if (type) sawType = type;
if (dir > 0 && !moveOnce(!first)) break;
}
}
var result = skipAtomic(doc, Pos(line, ch), pos, origDir, true);
if (!possible) result.hitSide = true;
return result;
}
// For relative vertical movement. Dir may be -1 or 1. Unit can be
// "page" or "line". The resulting position will have a hitSide=true
// property if it reached the end of the document.
function findPosV(cm, pos, dir, unit) {
var doc = cm.doc, x = pos.left, y;
if (unit == "page") {
var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
y = pos.top + dir * (pageSize - (dir < 0 ? 1.5 : .5) * textHeight(cm.display));
} else if (unit == "line") {
y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
}
for (;;) {
var target = coordsChar(cm, x, y);
if (!target.outside) break;
if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break; }
y += dir * 5;
}
return target;
}
// EDITOR METHODS
// The publicly visible API. Note that methodOp(f) means
// 'wrap f in an operation, performed on its `this` parameter'.
// This is not the complete set of editor methods. Most of the
// methods defined on the Doc type are also injected into
// CodeMirror.prototype, for backwards compatibility and
// convenience.
CodeMirror.prototype = {
constructor: CodeMirror,
focus: function(){window.focus(); this.display.input.focus();},
setOption: function(option, value) {
var options = this.options, old = options[option];
if (options[option] == value && option != "mode") return;
options[option] = value;
if (optionHandlers.hasOwnProperty(option))
operation(this, optionHandlers[option])(this, value, old);
},
getOption: function(option) {return this.options[option];},
getDoc: function() {return this.doc;},
addKeyMap: function(map, bottom) {
this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map));
},
removeKeyMap: function(map) {
var maps = this.state.keyMaps;
for (var i = 0; i < maps.length; ++i)
if (maps[i] == map || maps[i].name == map) {
maps.splice(i, 1);
return true;
}
},
addOverlay: methodOp(function(spec, options) {
var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
if (mode.startState) throw new Error("Overlays may not be stateful.");
this.state.overlays.push({mode: mode, modeSpec: spec, opaque: options && options.opaque});
this.state.modeGen++;
regChange(this);
}),
removeOverlay: methodOp(function(spec) {
var overlays = this.state.overlays;
for (var i = 0; i < overlays.length; ++i) {
var cur = overlays[i].modeSpec;
if (cur == spec || typeof spec == "string" && cur.name == spec) {
overlays.splice(i, 1);
this.state.modeGen++;
regChange(this);
return;
}
}
}),
indentLine: methodOp(function(n, dir, aggressive) {
if (typeof dir != "string" && typeof dir != "number") {
if (dir == null) dir = this.options.smartIndent ? "smart" : "prev";
else dir = dir ? "add" : "subtract";
}
if (isLine(this.doc, n)) indentLine(this, n, dir, aggressive);
}),
indentSelection: methodOp(function(how) {
var ranges = this.doc.sel.ranges, end = -1;
for (var i = 0; i < ranges.length; i++) {
var range = ranges[i];
if (!range.empty()) {
var from = range.from(), to = range.to();
var start = Math.max(end, from.line);
end = Math.min(this.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
for (var j = start; j < end; ++j)
indentLine(this, j, how);
var newRanges = this.doc.sel.ranges;
if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
replaceOneSelection(this.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll);
} else if (range.head.line > end) {
indentLine(this, range.head.line, how, true);
end = range.head.line;
if (i == this.doc.sel.primIndex) ensureCursorVisible(this);
}
}
}),
// Fetch the parser token for a given character. Useful for hacks
// that want to inspect the mode state (say, for completion).
getTokenAt: function(pos, precise) {
return takeToken(this, pos, precise);
},
getLineTokens: function(line, precise) {
return takeToken(this, Pos(line), precise, true);
},
getTokenTypeAt: function(pos) {
pos = clipPos(this.doc, pos);
var styles = getLineStyles(this, getLine(this.doc, pos.line));
var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
var type;
if (ch == 0) type = styles[2];
else for (;;) {
var mid = (before + after) >> 1;
if ((mid ? styles[mid * 2 - 1] : 0) >= ch) after = mid;
else if (styles[mid * 2 + 1] < ch) before = mid + 1;
else { type = styles[mid * 2 + 2]; break; }
}
var cut = type ? type.indexOf("cm-overlay ") : -1;
return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1);
},
getModeAt: function(pos) {
var mode = this.doc.mode;
if (!mode.innerMode) return mode;
return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode;
},
getHelper: function(pos, type) {
return this.getHelpers(pos, type)[0];
},
getHelpers: function(pos, type) {
var found = [];
if (!helpers.hasOwnProperty(type)) return found;
var help = helpers[type], mode = this.getModeAt(pos);
if (typeof mode[type] == "string") {
if (help[mode[type]]) found.push(help[mode[type]]);
} else if (mode[type]) {
for (var i = 0; i < mode[type].length; i++) {
var val = help[mode[type][i]];
if (val) found.push(val);
}
} else if (mode.helperType && help[mode.helperType]) {
found.push(help[mode.helperType]);
} else if (help[mode.name]) {
found.push(help[mode.name]);
}
for (var i = 0; i < help._global.length; i++) {
var cur = help._global[i];
if (cur.pred(mode, this) && indexOf(found, cur.val) == -1)
found.push(cur.val);
}
return found;
},
getStateAfter: function(line, precise) {
var doc = this.doc;
line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
return getStateBefore(this, line + 1, precise);
},
cursorCoords: function(start, mode) {
var pos, range = this.doc.sel.primary();
if (start == null) pos = range.head;
else if (typeof start == "object") pos = clipPos(this.doc, start);
else pos = start ? range.from() : range.to();
return cursorCoords(this, pos, mode || "page");
},
charCoords: function(pos, mode) {
return charCoords(this, clipPos(this.doc, pos), mode || "page");
},
coordsChar: function(coords, mode) {
coords = fromCoordSystem(this, coords, mode || "page");
return coordsChar(this, coords.left, coords.top);
},
lineAtHeight: function(height, mode) {
height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
return lineAtHeight(this.doc, height + this.display.viewOffset);
},
heightAtLine: function(line, mode) {
var end = false, lineObj;
if (typeof line == "number") {
var last = this.doc.first + this.doc.size - 1;
if (line < this.doc.first) line = this.doc.first;
else if (line > last) { line = last; end = true; }
lineObj = getLine(this.doc, line);
} else {
lineObj = line;
}
return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page").top +
(end ? this.doc.height - heightAtLine(lineObj) : 0);
},
defaultTextHeight: function() { return textHeight(this.display); },
defaultCharWidth: function() { return charWidth(this.display); },
setGutterMarker: methodOp(function(line, gutterID, value) {
return changeLine(this.doc, line, "gutter", function(line) {
var markers = line.gutterMarkers || (line.gutterMarkers = {});
markers[gutterID] = value;
if (!value && isEmpty(markers)) line.gutterMarkers = null;
return true;
});
}),
clearGutter: methodOp(function(gutterID) {
var cm = this, doc = cm.doc, i = doc.first;
doc.iter(function(line) {
if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
line.gutterMarkers[gutterID] = null;
regLineChange(cm, i, "gutter");
if (isEmpty(line.gutterMarkers)) line.gutterMarkers = null;
}
++i;
});
}),
lineInfo: function(line) {
if (typeof line == "number") {
if (!isLine(this.doc, line)) return null;
var n = line;
line = getLine(this.doc, line);
if (!line) return null;
} else {
var n = lineNo(line);
if (n == null) return null;
}
return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
widgets: line.widgets};
},
getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo};},
addWidget: function(pos, node, scroll, vert, horiz) {
var display = this.display;
pos = cursorCoords(this, clipPos(this.doc, pos));
var top = pos.bottom, left = pos.left;
node.style.position = "absolute";
node.setAttribute("cm-ignore-events", "true");
this.display.input.setUneditable(node);
display.sizer.appendChild(node);
if (vert == "over") {
top = pos.top;
} else if (vert == "above" || vert == "near") {
var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
// Default to positioning above (if specified and possible); otherwise default to positioning below
if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
top = pos.top - node.offsetHeight;
else if (pos.bottom + node.offsetHeight <= vspace)
top = pos.bottom;
if (left + node.offsetWidth > hspace)
left = hspace - node.offsetWidth;
}
node.style.top = top + "px";
node.style.left = node.style.right = "";
if (horiz == "right") {
left = display.sizer.clientWidth - node.offsetWidth;
node.style.right = "0px";
} else {
if (horiz == "left") left = 0;
else if (horiz == "middle") left = (display.sizer.clientWidth - node.offsetWidth) / 2;
node.style.left = left + "px";
}
if (scroll)
scrollIntoView(this, left, top, left + node.offsetWidth, top + node.offsetHeight);
},
triggerOnKeyDown: methodOp(onKeyDown),
triggerOnKeyPress: methodOp(onKeyPress),
triggerOnKeyUp: onKeyUp,
execCommand: function(cmd) {
if (commands.hasOwnProperty(cmd))
return commands[cmd].call(null, this);
},
triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
findPosH: function(from, amount, unit, visually) {
var dir = 1;
if (amount < 0) { dir = -1; amount = -amount; }
for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
cur = findPosH(this.doc, cur, dir, unit, visually);
if (cur.hitSide) break;
}
return cur;
},
moveH: methodOp(function(dir, unit) {
var cm = this;
cm.extendSelectionsBy(function(range) {
if (cm.display.shift || cm.doc.extend || range.empty())
return findPosH(cm.doc, range.head, dir, unit, cm.options.rtlMoveVisually);
else
return dir < 0 ? range.from() : range.to();
}, sel_move);
}),
deleteH: methodOp(function(dir, unit) {
var sel = this.doc.sel, doc = this.doc;
if (sel.somethingSelected())
doc.replaceSelection("", null, "+delete");
else
deleteNearSelection(this, function(range) {
var other = findPosH(doc, range.head, dir, unit, false);
return dir < 0 ? {from: other, to: range.head} : {from: range.head, to: other};
});
}),
findPosV: function(from, amount, unit, goalColumn) {
var dir = 1, x = goalColumn;
if (amount < 0) { dir = -1; amount = -amount; }
for (var i = 0, cur = clipPos(this.doc, from); i < amount; ++i) {
var coords = cursorCoords(this, cur, "div");
if (x == null) x = coords.left;
else coords.left = x;
cur = findPosV(this, coords, dir, unit);
if (cur.hitSide) break;
}
return cur;
},
moveV: methodOp(function(dir, unit) {
var cm = this, doc = this.doc, goals = [];
var collapse = !cm.display.shift && !doc.extend && doc.sel.somethingSelected();
doc.extendSelectionsBy(function(range) {
if (collapse)
return dir < 0 ? range.from() : range.to();
var headPos = cursorCoords(cm, range.head, "div");
if (range.goalColumn != null) headPos.left = range.goalColumn;
goals.push(headPos.left);
var pos = findPosV(cm, headPos, dir, unit);
if (unit == "page" && range == doc.sel.primary())
addToScrollPos(cm, null, charCoords(cm, pos, "div").top - headPos.top);
return pos;
}, sel_move);
if (goals.length) for (var i = 0; i < doc.sel.ranges.length; i++)
doc.sel.ranges[i].goalColumn = goals[i];
}),
// Find the word at the given position (as returned by coordsChar).
findWordAt: function(pos) {
var doc = this.doc, line = getLine(doc, pos.line).text;
var start = pos.ch, end = pos.ch;
if (line) {
var helper = this.getHelper(pos, "wordChars");
if ((pos.xRel < 0 || end == line.length) && start) --start; else ++end;
var startChar = line.charAt(start);
var check = isWordChar(startChar, helper)
? function(ch) { return isWordChar(ch, helper); }
: /\s/.test(startChar) ? function(ch) {return /\s/.test(ch);}
: function(ch) {return !/\s/.test(ch) && !isWordChar(ch);};
while (start > 0 && check(line.charAt(start - 1))) --start;
while (end < line.length && check(line.charAt(end))) ++end;
}
return new Range(Pos(pos.line, start), Pos(pos.line, end));
},
toggleOverwrite: function(value) {
if (value != null && value == this.state.overwrite) return;
if (this.state.overwrite = !this.state.overwrite)
addClass(this.display.cursorDiv, "CodeMirror-overwrite");
else
rmClass(this.display.cursorDiv, "CodeMirror-overwrite");
signal(this, "overwriteToggle", this, this.state.overwrite);
},
hasFocus: function() { return this.display.input.getField() == activeElt(); },
scrollTo: methodOp(function(x, y) {
if (x != null || y != null) resolveScrollToPos(this);
if (x != null) this.curOp.scrollLeft = x;
if (y != null) this.curOp.scrollTop = y;
}),
getScrollInfo: function() {
var scroller = this.display.scroller;
return {left: scroller.scrollLeft, top: scroller.scrollTop,
height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
clientHeight: displayHeight(this), clientWidth: displayWidth(this)};
},
scrollIntoView: methodOp(function(range, margin) {
if (range == null) {
range = {from: this.doc.sel.primary().head, to: null};
if (margin == null) margin = this.options.cursorScrollMargin;
} else if (typeof range == "number") {
range = {from: Pos(range, 0), to: null};
} else if (range.from == null) {
range = {from: range, to: null};
}
if (!range.to) range.to = range.from;
range.margin = margin || 0;
if (range.from.line != null) {
resolveScrollToPos(this);
this.curOp.scrollToPos = range;
} else {
var sPos = calculateScrollPos(this, Math.min(range.from.left, range.to.left),
Math.min(range.from.top, range.to.top) - range.margin,
Math.max(range.from.right, range.to.right),
Math.max(range.from.bottom, range.to.bottom) + range.margin);
this.scrollTo(sPos.scrollLeft, sPos.scrollTop);
}
}),
setSize: methodOp(function(width, height) {
var cm = this;
function interpret(val) {
return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val;
}
if (width != null) cm.display.wrapper.style.width = interpret(width);
if (height != null) cm.display.wrapper.style.height = interpret(height);
if (cm.options.lineWrapping) clearLineMeasurementCache(this);
var lineNo = cm.display.viewFrom;
cm.doc.iter(lineNo, cm.display.viewTo, function(line) {
if (line.widgets) for (var i = 0; i < line.widgets.length; i++)
if (line.widgets[i].noHScroll) { regLineChange(cm, lineNo, "widget"); break; }
++lineNo;
});
cm.curOp.forceUpdate = true;
signal(cm, "refresh", this);
}),
operation: function(f){return runInOp(this, f);},
refresh: methodOp(function() {
var oldHeight = this.display.cachedTextHeight;
regChange(this);
this.curOp.forceUpdate = true;
clearCaches(this);
this.scrollTo(this.doc.scrollLeft, this.doc.scrollTop);
updateGutterSpace(this);
if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
estimateLineHeights(this);
signal(this, "refresh", this);
}),
swapDoc: methodOp(function(doc) {
var old = this.doc;
old.cm = null;
attachDoc(this, doc);
clearCaches(this);
this.display.input.reset();
this.scrollTo(doc.scrollLeft, doc.scrollTop);
this.curOp.forceScroll = true;
signalLater(this, "swapDoc", this, old);
return old;
}),
getInputField: function(){return this.display.input.getField();},
getWrapperElement: function(){return this.display.wrapper;},
getScrollerElement: function(){return this.display.scroller;},
getGutterElement: function(){return this.display.gutters;}
};
eventMixin(CodeMirror);
// OPTION DEFAULTS
// The default configuration options.
var defaults = CodeMirror.defaults = {};
// Functions to run when options are changed.
var optionHandlers = CodeMirror.optionHandlers = {};
function option(name, deflt, handle, notOnInit) {
CodeMirror.defaults[name] = deflt;
if (handle) optionHandlers[name] =
notOnInit ? function(cm, val, old) {if (old != Init) handle(cm, val, old);} : handle;
}
// Passed to option handlers when there is no old value.
var Init = CodeMirror.Init = {toString: function(){return "CodeMirror.Init";}};
// These two are, on init, called from the constructor because they
// have to be initialized before the editor can start at all.
option("value", "", function(cm, val) {
cm.setValue(val);
}, true);
option("mode", null, function(cm, val) {
cm.doc.modeOption = val;
loadMode(cm);
}, true);
option("indentUnit", 2, loadMode, true);
option("indentWithTabs", false);
option("smartIndent", true);
option("tabSize", 4, function(cm) {
resetModeState(cm);
clearCaches(cm);
regChange(cm);
}, true);
option("lineSeparator", null, function(cm, val) {
cm.doc.lineSep = val;
if (!val) return;
var newBreaks = [], lineNo = cm.doc.first;
cm.doc.iter(function(line) {
for (var pos = 0;;) {
var found = line.text.indexOf(val, pos);
if (found == -1) break;
pos = found + val.length;
newBreaks.push(Pos(lineNo, found));
}
lineNo++;
});
for (var i = newBreaks.length - 1; i >= 0; i--)
replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length))
});
option("specialChars", /[\t\u0000-\u0019\u00ad\u200b-\u200f\u2028\u2029\ufeff]/g, function(cm, val, old) {
cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
if (old != CodeMirror.Init) cm.refresh();
});
option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function(cm) {cm.refresh();}, true);
option("electricChars", true);
option("inputStyle", mobile ? "contenteditable" : "textarea", function() {
throw new Error("inputStyle can not (yet) be changed in a running editor"); // FIXME
}, true);
option("rtlMoveVisually", !windows);
option("wholeLineUpdateBefore", true);
option("theme", "default", function(cm) {
themeChanged(cm);
guttersChanged(cm);
}, true);
option("keyMap", "default", function(cm, val, old) {
var next = getKeyMap(val);
var prev = old != CodeMirror.Init && getKeyMap(old);
if (prev && prev.detach) prev.detach(cm, next);
if (next.attach) next.attach(cm, prev || null);
});
option("extraKeys", null);
option("lineWrapping", false, wrappingChanged, true);
option("gutters", [], function(cm) {
setGuttersForLineNumbers(cm.options);
guttersChanged(cm);
}, true);
option("fixedGutter", true, function(cm, val) {
cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
cm.refresh();
}, true);
option("coverGutterNextToScrollbar", false, function(cm) {updateScrollbars(cm);}, true);
option("scrollbarStyle", "native", function(cm) {
initScrollbars(cm);
updateScrollbars(cm);
cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
}, true);
option("lineNumbers", false, function(cm) {
setGuttersForLineNumbers(cm.options);
guttersChanged(cm);
}, true);
option("firstLineNumber", 1, guttersChanged, true);
option("lineNumberFormatter", function(integer) {return integer;}, guttersChanged, true);
option("showCursorWhenSelecting", false, updateSelection, true);
option("resetSelectionOnContextMenu", true);
option("lineWiseCopyCut", true);
option("readOnly", false, function(cm, val) {
if (val == "nocursor") {
onBlur(cm);
cm.display.input.blur();
cm.display.disabled = true;
} else {
cm.display.disabled = false;
}
cm.display.input.readOnlyChanged(val)
});
option("disableInput", false, function(cm, val) {if (!val) cm.display.input.reset();}, true);
option("dragDrop", true, dragDropChanged);
option("allowDropFileTypes", null);
option("cursorBlinkRate", 530);
option("cursorScrollMargin", 0);
option("cursorHeight", 1, updateSelection, true);
option("singleCursorHeightPerLine", true, updateSelection, true);
option("workTime", 100);
option("workDelay", 100);
option("flattenSpans", true, resetModeState, true);
option("addModeClass", false, resetModeState, true);
option("pollInterval", 100);
option("undoDepth", 200, function(cm, val){cm.doc.history.undoDepth = val;});
option("historyEventDelay", 1250);
option("viewportMargin", 10, function(cm){cm.refresh();}, true);
option("maxHighlightLength", 10000, resetModeState, true);
option("moveInputWithCursor", true, function(cm, val) {
if (!val) cm.display.input.resetPosition();
});
option("tabindex", null, function(cm, val) {
cm.display.input.getField().tabIndex = val || "";
});
option("autofocus", null);
// MODE DEFINITION AND QUERYING
// Known modes, by name and by MIME
var modes = CodeMirror.modes = {}, mimeModes = CodeMirror.mimeModes = {};
// Extra arguments are stored as the mode's dependencies, which is
// used by (legacy) mechanisms like loadmode.js to automatically
// load a mode. (Preferred mechanism is the require/define calls.)
CodeMirror.defineMode = function(name, mode) {
if (!CodeMirror.defaults.mode && name != "null") CodeMirror.defaults.mode = name;
if (arguments.length > 2)
mode.dependencies = Array.prototype.slice.call(arguments, 2);
modes[name] = mode;
};
CodeMirror.defineMIME = function(mime, spec) {
mimeModes[mime] = spec;
};
// Given a MIME type, a {name, ...options} config object, or a name
// string, return a mode config object.
CodeMirror.resolveMode = function(spec) {
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
spec = mimeModes[spec];
} else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
var found = mimeModes[spec.name];
if (typeof found == "string") found = {name: found};
spec = createObj(found, spec);
spec.name = found.name;
} else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
return CodeMirror.resolveMode("application/xml");
}
if (typeof spec == "string") return {name: spec};
else return spec || {name: "null"};
};
// Given a mode spec (anything that resolveMode accepts), find and
// initialize an actual mode object.
CodeMirror.getMode = function(options, spec) {
var spec = CodeMirror.resolveMode(spec);
var mfactory = modes[spec.name];
if (!mfactory) return CodeMirror.getMode(options, "text/plain");
var modeObj = mfactory(options, spec);
if (modeExtensions.hasOwnProperty(spec.name)) {
var exts = modeExtensions[spec.name];
for (var prop in exts) {
if (!exts.hasOwnProperty(prop)) continue;
if (modeObj.hasOwnProperty(prop)) modeObj["_" + prop] = modeObj[prop];
modeObj[prop] = exts[prop];
}
}
modeObj.name = spec.name;
if (spec.helperType) modeObj.helperType = spec.helperType;
if (spec.modeProps) for (var prop in spec.modeProps)
modeObj[prop] = spec.modeProps[prop];
return modeObj;
};
// Minimal default mode.
CodeMirror.defineMode("null", function() {
return {token: function(stream) {stream.skipToEnd();}};
});
CodeMirror.defineMIME("text/plain", "null");
// This can be used to attach properties to mode objects from
// outside the actual mode definition.
var modeExtensions = CodeMirror.modeExtensions = {};
CodeMirror.extendMode = function(mode, properties) {
var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
copyObj(properties, exts);
};
// EXTENSIONS
CodeMirror.defineExtension = function(name, func) {
CodeMirror.prototype[name] = func;
};
CodeMirror.defineDocExtension = function(name, func) {
Doc.prototype[name] = func;
};
CodeMirror.defineOption = option;
var initHooks = [];
CodeMirror.defineInitHook = function(f) {initHooks.push(f);};
var helpers = CodeMirror.helpers = {};
CodeMirror.registerHelper = function(type, name, value) {
if (!helpers.hasOwnProperty(type)) helpers[type] = CodeMirror[type] = {_global: []};
helpers[type][name] = value;
};
CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
CodeMirror.registerHelper(type, name, value);
helpers[type]._global.push({pred: predicate, val: value});
};
// MODE STATE HANDLING
// Utility functions for working with state. Exported because nested
// modes need to do this for their inner modes.
var copyState = CodeMirror.copyState = function(mode, state) {
if (state === true) return state;
if (mode.copyState) return mode.copyState(state);
var nstate = {};
for (var n in state) {
var val = state[n];
if (val instanceof Array) val = val.concat([]);
nstate[n] = val;
}
return nstate;
};
var startState = CodeMirror.startState = function(mode, a1, a2) {
return mode.startState ? mode.startState(a1, a2) : true;
};
// Given a mode and a state (for that mode), find the inner mode and
// state at the position that the state refers to.
CodeMirror.innerMode = function(mode, state) {
while (mode.innerMode) {
var info = mode.innerMode(state);
if (!info || info.mode == mode) break;
state = info.state;
mode = info.mode;
}
return info || {mode: mode, state: state};
};
// STANDARD COMMANDS
// Commands are parameter-less actions that can be performed on an
// editor, mostly used for keybindings.
var commands = CodeMirror.commands = {
selectAll: function(cm) {cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);},
singleSelection: function(cm) {
cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll);
},
killLine: function(cm) {
deleteNearSelection(cm, function(range) {
if (range.empty()) {
var len = getLine(cm.doc, range.head.line).text.length;
if (range.head.ch == len && range.head.line < cm.lastLine())
return {from: range.head, to: Pos(range.head.line + 1, 0)};
else
return {from: range.head, to: Pos(range.head.line, len)};
} else {
return {from: range.from(), to: range.to()};
}
});
},
deleteLine: function(cm) {
deleteNearSelection(cm, function(range) {
return {from: Pos(range.from().line, 0),
to: clipPos(cm.doc, Pos(range.to().line + 1, 0))};
});
},
delLineLeft: function(cm) {
deleteNearSelection(cm, function(range) {
return {from: Pos(range.from().line, 0), to: range.from()};
});
},
delWrappedLineLeft: function(cm) {
deleteNearSelection(cm, function(range) {
var top = cm.charCoords(range.head, "div").top + 5;
var leftPos = cm.coordsChar({left: 0, top: top}, "div");
return {from: leftPos, to: range.from()};
});
},
delWrappedLineRight: function(cm) {
deleteNearSelection(cm, function(range) {
var top = cm.charCoords(range.head, "div").top + 5;
var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
return {from: range.from(), to: rightPos };
});
},
undo: function(cm) {cm.undo();},
redo: function(cm) {cm.redo();},
undoSelection: function(cm) {cm.undoSelection();},
redoSelection: function(cm) {cm.redoSelection();},
goDocStart: function(cm) {cm.extendSelection(Pos(cm.firstLine(), 0));},
goDocEnd: function(cm) {cm.extendSelection(Pos(cm.lastLine()));},
goLineStart: function(cm) {
cm.extendSelectionsBy(function(range) { return lineStart(cm, range.head.line); },
{origin: "+move", bias: 1});
},
goLineStartSmart: function(cm) {
cm.extendSelectionsBy(function(range) {
return lineStartSmart(cm, range.head);
}, {origin: "+move", bias: 1});
},
goLineEnd: function(cm) {
cm.extendSelectionsBy(function(range) { return lineEnd(cm, range.head.line); },
{origin: "+move", bias: -1});
},
goLineRight: function(cm) {
cm.extendSelectionsBy(function(range) {
var top = cm.charCoords(range.head, "div").top + 5;
return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
}, sel_move);
},
goLineLeft: function(cm) {
cm.extendSelectionsBy(function(range) {
var top = cm.charCoords(range.head, "div").top + 5;
return cm.coordsChar({left: 0, top: top}, "div");
}, sel_move);
},
goLineLeftSmart: function(cm) {
cm.extendSelectionsBy(function(range) {
var top = cm.charCoords(range.head, "div").top + 5;
var pos = cm.coordsChar({left: 0, top: top}, "div");
if (pos.ch < cm.getLine(pos.line).search(/\S/)) return lineStartSmart(cm, range.head);
return pos;
}, sel_move);
},
goLineUp: function(cm) {cm.moveV(-1, "line");},
goLineDown: function(cm) {cm.moveV(1, "line");},
goPageUp: function(cm) {cm.moveV(-1, "page");},
goPageDown: function(cm) {cm.moveV(1, "page");},
goCharLeft: function(cm) {cm.moveH(-1, "char");},
goCharRight: function(cm) {cm.moveH(1, "char");},
goColumnLeft: function(cm) {cm.moveH(-1, "column");},
goColumnRight: function(cm) {cm.moveH(1, "column");},
goWordLeft: function(cm) {cm.moveH(-1, "word");},
goGroupRight: function(cm) {cm.moveH(1, "group");},
goGroupLeft: function(cm) {cm.moveH(-1, "group");},
goWordRight: function(cm) {cm.moveH(1, "word");},
delCharBefore: function(cm) {cm.deleteH(-1, "char");},
delCharAfter: function(cm) {cm.deleteH(1, "char");},
delWordBefore: function(cm) {cm.deleteH(-1, "word");},
delWordAfter: function(cm) {cm.deleteH(1, "word");},
delGroupBefore: function(cm) {cm.deleteH(-1, "group");},
delGroupAfter: function(cm) {cm.deleteH(1, "group");},
indentAuto: function(cm) {cm.indentSelection("smart");},
indentMore: function(cm) {cm.indentSelection("add");},
indentLess: function(cm) {cm.indentSelection("subtract");},
insertTab: function(cm) {cm.replaceSelection("\t");},
insertSoftTab: function(cm) {
var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
for (var i = 0; i < ranges.length; i++) {
var pos = ranges[i].from();
var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
spaces.push(new Array(tabSize - col % tabSize + 1).join(" "));
}
cm.replaceSelections(spaces);
},
defaultTab: function(cm) {
if (cm.somethingSelected()) cm.indentSelection("add");
else cm.execCommand("insertTab");
},
transposeChars: function(cm) {
runInOp(cm, function() {
var ranges = cm.listSelections(), newSel = [];
for (var i = 0; i < ranges.length; i++) {
var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
if (line) {
if (cur.ch == line.length) cur = new Pos(cur.line, cur.ch - 1);
if (cur.ch > 0) {
cur = new Pos(cur.line, cur.ch + 1);
cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
Pos(cur.line, cur.ch - 2), cur, "+transpose");
} else if (cur.line > cm.doc.first) {
var prev = getLine(cm.doc, cur.line - 1).text;
if (prev)
cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
prev.charAt(prev.length - 1),
Pos(cur.line - 1, prev.length - 1), Pos(cur.line, 1), "+transpose");
}
}
newSel.push(new Range(cur, cur));
}
cm.setSelections(newSel);
});
},
newlineAndIndent: function(cm) {
runInOp(cm, function() {
var len = cm.listSelections().length;
for (var i = 0; i < len; i++) {
var range = cm.listSelections()[i];
cm.replaceRange(cm.doc.lineSeparator(), range.anchor, range.head, "+input");
cm.indentLine(range.from().line + 1, null, true);
}
ensureCursorVisible(cm);
});
},
toggleOverwrite: function(cm) {cm.toggleOverwrite();}
};
// STANDARD KEYMAPS
var keyMap = CodeMirror.keyMap = {};
keyMap.basic = {
"Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
"End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
"Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
"Tab": "defaultTab", "Shift-Tab": "indentAuto",
"Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
"Esc": "singleSelection"
};
// Note that the save and find-related commands aren't defined by
// default. User code or addons can define them. Unknown commands
// are simply ignored.
keyMap.pcDefault = {
"Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
"Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
"Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
"Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
"Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
"Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
"Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
fallthrough: "basic"
};
// Very basic readline/emacs-style bindings, which are standard on Mac.
keyMap.emacsy = {
"Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
"Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
"Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
"Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars"
};
keyMap.macDefault = {
"Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
"Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
"Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
"Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
"Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
"Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
"Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
fallthrough: ["basic", "emacsy"]
};
keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
// KEYMAP DISPATCH
function normalizeKeyName(name) {
var parts = name.split(/-(?!$)/), name = parts[parts.length - 1];
var alt, ctrl, shift, cmd;
for (var i = 0; i < parts.length - 1; i++) {
var mod = parts[i];
if (/^(cmd|meta|m)$/i.test(mod)) cmd = true;
else if (/^a(lt)?$/i.test(mod)) alt = true;
else if (/^(c|ctrl|control)$/i.test(mod)) ctrl = true;
else if (/^s(hift)$/i.test(mod)) shift = true;
else throw new Error("Unrecognized modifier name: " + mod);
}
if (alt) name = "Alt-" + name;
if (ctrl) name = "Ctrl-" + name;
if (cmd) name = "Cmd-" + name;
if (shift) name = "Shift-" + name;
return name;
}
// This is a kludge to keep keymaps mostly working as raw objects
// (backwards compatibility) while at the same time support features
// like normalization and multi-stroke key bindings. It compiles a
// new normalized keymap, and then updates the old object to reflect
// this.
CodeMirror.normalizeKeyMap = function(keymap) {
var copy = {};
for (var keyname in keymap) if (keymap.hasOwnProperty(keyname)) {
var value = keymap[keyname];
if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) continue;
if (value == "...") { delete keymap[keyname]; continue; }
var keys = map(keyname.split(" "), normalizeKeyName);
for (var i = 0; i < keys.length; i++) {
var val, name;
if (i == keys.length - 1) {
name = keys.join(" ");
val = value;
} else {
name = keys.slice(0, i + 1).join(" ");
val = "...";
}
var prev = copy[name];
if (!prev) copy[name] = val;
else if (prev != val) throw new Error("Inconsistent bindings for " + name);
}
delete keymap[keyname];
}
for (var prop in copy) keymap[prop] = copy[prop];
return keymap;
};
var lookupKey = CodeMirror.lookupKey = function(key, map, handle, context) {
map = getKeyMap(map);
var found = map.call ? map.call(key, context) : map[key];
if (found === false) return "nothing";
if (found === "...") return "multi";
if (found != null && handle(found)) return "handled";
if (map.fallthrough) {
if (Object.prototype.toString.call(map.fallthrough) != "[object Array]")
return lookupKey(key, map.fallthrough, handle, context);
for (var i = 0; i < map.fallthrough.length; i++) {
var result = lookupKey(key, map.fallthrough[i], handle, context);
if (result) return result;
}
}
};
// Modifier key presses don't count as 'real' key presses for the
// purpose of keymap fallthrough.
var isModifierKey = CodeMirror.isModifierKey = function(value) {
var name = typeof value == "string" ? value : keyNames[value.keyCode];
return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod";
};
// Look up the name of a key as indicated by an event object.
var keyName = CodeMirror.keyName = function(event, noShift) {
if (presto && event.keyCode == 34 && event["char"]) return false;
var base = keyNames[event.keyCode], name = base;
if (name == null || event.altGraphKey) return false;
if (event.altKey && base != "Alt") name = "Alt-" + name;
if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") name = "Ctrl-" + name;
if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") name = "Cmd-" + name;
if (!noShift && event.shiftKey && base != "Shift") name = "Shift-" + name;
return name;
};
function getKeyMap(val) {
return typeof val == "string" ? keyMap[val] : val;
}
// FROMTEXTAREA
CodeMirror.fromTextArea = function(textarea, options) {
options = options ? copyObj(options) : {};
options.value = textarea.value;
if (!options.tabindex && textarea.tabIndex)
options.tabindex = textarea.tabIndex;
if (!options.placeholder && textarea.placeholder)
options.placeholder = textarea.placeholder;
// Set autofocus to true if this textarea is focused, or if it has
// autofocus and no other element is focused.
if (options.autofocus == null) {
var hasFocus = activeElt();
options.autofocus = hasFocus == textarea ||
textarea.getAttribute("autofocus") != null && hasFocus == document.body;
}
function save() {textarea.value = cm.getValue();}
if (textarea.form) {
on(textarea.form, "submit", save);
// Deplorable hack to make the submit method do the right thing.
if (!options.leaveSubmitMethodAlone) {
var form = textarea.form, realSubmit = form.submit;
try {
var wrappedSubmit = form.submit = function() {
save();
form.submit = realSubmit;
form.submit();
form.submit = wrappedSubmit;
};
} catch(e) {}
}
}
options.finishInit = function(cm) {
cm.save = save;
cm.getTextArea = function() { return textarea; };
cm.toTextArea = function() {
cm.toTextArea = isNaN; // Prevent this from being ran twice
save();
textarea.parentNode.removeChild(cm.getWrapperElement());
textarea.style.display = "";
if (textarea.form) {
off(textarea.form, "submit", save);
if (typeof textarea.form.submit == "function")
textarea.form.submit = realSubmit;
}
};
};
textarea.style.display = "none";
var cm = CodeMirror(function(node) {
textarea.parentNode.insertBefore(node, textarea.nextSibling);
}, options);
return cm;
};
// STRING STREAM
// Fed to the mode parsers, provides helper functions to make
// parsers more succinct.
var StringStream = CodeMirror.StringStream = function(string, tabSize) {
this.pos = this.start = 0;
this.string = string;
this.tabSize = tabSize || 8;
this.lastColumnPos = this.lastColumnValue = 0;
this.lineStart = 0;
};
StringStream.prototype = {
eol: function() {return this.pos >= this.string.length;},
sol: function() {return this.pos == this.lineStart;},
peek: function() {return this.string.charAt(this.pos) || undefined;},
next: function() {
if (this.pos < this.string.length)
return this.string.charAt(this.pos++);
},
eat: function(match) {
var ch = this.string.charAt(this.pos);
if (typeof match == "string") var ok = ch == match;
else var ok = ch && (match.test ? match.test(ch) : match(ch));
if (ok) {++this.pos; return ch;}
},
eatWhile: function(match) {
var start = this.pos;
while (this.eat(match)){}
return this.pos > start;
},
eatSpace: function() {
var start = this.pos;
while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) ++this.pos;
return this.pos > start;
},
skipToEnd: function() {this.pos = this.string.length;},
skipTo: function(ch) {
var found = this.string.indexOf(ch, this.pos);
if (found > -1) {this.pos = found; return true;}
},
backUp: function(n) {this.pos -= n;},
column: function() {
if (this.lastColumnPos < this.start) {
this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
this.lastColumnPos = this.start;
}
return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
},
indentation: function() {
return countColumn(this.string, null, this.tabSize) -
(this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0);
},
match: function(pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
var cased = function(str) {return caseInsensitive ? str.toLowerCase() : str;};
var substr = this.string.substr(this.pos, pattern.length);
if (cased(substr) == cased(pattern)) {
if (consume !== false) this.pos += pattern.length;
return true;
}
} else {
var match = this.string.slice(this.pos).match(pattern);
if (match && match.index > 0) return null;
if (match && consume !== false) this.pos += match[0].length;
return match;
}
},
current: function(){return this.string.slice(this.start, this.pos);},
hideFirstChars: function(n, inner) {
this.lineStart += n;
try { return inner(); }
finally { this.lineStart -= n; }
}
};
// TEXTMARKERS
// Created with markText and setBookmark methods. A TextMarker is a
// handle that can be used to clear or find a marked position in the
// document. Line objects hold arrays (markedSpans) containing
// {from, to, marker} object pointing to such marker objects, and
// indicating that such a marker is present on that line. Multiple
// lines may point to the same marker when it spans across lines.
// The spans will have null for their from/to properties when the
// marker continues beyond the start/end of the line. Markers have
// links back to the lines they currently touch.
var nextMarkerId = 0;
var TextMarker = CodeMirror.TextMarker = function(doc, type) {
this.lines = [];
this.type = type;
this.doc = doc;
this.id = ++nextMarkerId;
};
eventMixin(TextMarker);
// Clear the marker.
TextMarker.prototype.clear = function() {
if (this.explicitlyCleared) return;
var cm = this.doc.cm, withOp = cm && !cm.curOp;
if (withOp) startOperation(cm);
if (hasHandler(this, "clear")) {
var found = this.find();
if (found) signalLater(this, "clear", found.from, found.to);
}
var min = null, max = null;
for (var i = 0; i < this.lines.length; ++i) {
var line = this.lines[i];
var span = getMarkedSpanFor(line.markedSpans, this);
if (cm && !this.collapsed) regLineChange(cm, lineNo(line), "text");
else if (cm) {
if (span.to != null) max = lineNo(line);
if (span.from != null) min = lineNo(line);
}
line.markedSpans = removeMarkedSpan(line.markedSpans, span);
if (span.from == null && this.collapsed && !lineIsHidden(this.doc, line) && cm)
updateLineHeight(line, textHeight(cm.display));
}
if (cm && this.collapsed && !cm.options.lineWrapping) for (var i = 0; i < this.lines.length; ++i) {
var visual = visualLine(this.lines[i]), len = lineLength(visual);
if (len > cm.display.maxLineLength) {
cm.display.maxLine = visual;
cm.display.maxLineLength = len;
cm.display.maxLineChanged = true;
}
}
if (min != null && cm && this.collapsed) regChange(cm, min, max + 1);
this.lines.length = 0;
this.explicitlyCleared = true;
if (this.atomic && this.doc.cantEdit) {
this.doc.cantEdit = false;
if (cm) reCheckSelection(cm.doc);
}
if (cm) signalLater(cm, "markerCleared", cm, this);
if (withOp) endOperation(cm);
if (this.parent) this.parent.clear();
};
// Find the position of the marker in the document. Returns a {from,
// to} object by default. Side can be passed to get a specific side
// -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
// Pos objects returned contain a line object, rather than a line
// number (used to prevent looking up the same line twice).
TextMarker.prototype.find = function(side, lineObj) {
if (side == null && this.type == "bookmark") side = 1;
var from, to;
for (var i = 0; i < this.lines.length; ++i) {
var line = this.lines[i];
var span = getMarkedSpanFor(line.markedSpans, this);
if (span.from != null) {
from = Pos(lineObj ? line : lineNo(line), span.from);
if (side == -1) return from;
}
if (span.to != null) {
to = Pos(lineObj ? line : lineNo(line), span.to);
if (side == 1) return to;
}
}
return from && {from: from, to: to};
};
// Signals that the marker's widget changed, and surrounding layout
// should be recomputed.
TextMarker.prototype.changed = function() {
var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
if (!pos || !cm) return;
runInOp(cm, function() {
var line = pos.line, lineN = lineNo(pos.line);
var view = findViewForLine(cm, lineN);
if (view) {
clearLineMeasurementCacheFor(view);
cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
}
cm.curOp.updateMaxLine = true;
if (!lineIsHidden(widget.doc, line) && widget.height != null) {
var oldHeight = widget.height;
widget.height = null;
var dHeight = widgetHeight(widget) - oldHeight;
if (dHeight)
updateLineHeight(line, line.height + dHeight);
}
});
};
TextMarker.prototype.attachLine = function(line) {
if (!this.lines.length && this.doc.cm) {
var op = this.doc.cm.curOp;
if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
(op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this);
}
this.lines.push(line);
};
TextMarker.prototype.detachLine = function(line) {
this.lines.splice(indexOf(this.lines, line), 1);
if (!this.lines.length && this.doc.cm) {
var op = this.doc.cm.curOp;
(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
}
};
// Collapsed markers have unique ids, in order to be able to order
// them, which is needed for uniquely determining an outer marker
// when they overlap (they may nest, but not partially overlap).
var nextMarkerId = 0;
// Create a marker, wire it up to the right lines, and
function markText(doc, from, to, options, type) {
// Shared markers (across linked documents) are handled separately
// (markTextShared will call out to this again, once per
// document).
if (options && options.shared) return markTextShared(doc, from, to, options, type);
// Ensure we are in an operation.
if (doc.cm && !doc.cm.curOp) return operation(doc.cm, markText)(doc, from, to, options, type);
var marker = new TextMarker(doc, type), diff = cmp(from, to);
if (options) copyObj(options, marker, false);
// Don't connect empty markers unless clearWhenEmpty is false
if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
return marker;
if (marker.replacedWith) {
// Showing up as a widget implies collapsed (widget replaces text)
marker.collapsed = true;
marker.widgetNode = elt("span", [marker.replacedWith], "CodeMirror-widget");
if (!options.handleMouseEvents) marker.widgetNode.setAttribute("cm-ignore-events", "true");
if (options.insertLeft) marker.widgetNode.insertLeft = true;
}
if (marker.collapsed) {
if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
throw new Error("Inserting collapsed marker partially overlapping an existing one");
sawCollapsedSpans = true;
}
if (marker.addToHistory)
addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN);
var curLine = from.line, cm = doc.cm, updateMaxLine;
doc.iter(curLine, to.line + 1, function(line) {
if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
updateMaxLine = true;
if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0);
addMarkedSpan(line, new MarkedSpan(marker,
curLine == from.line ? from.ch : null,
curLine == to.line ? to.ch : null));
++curLine;
});
// lineIsHidden depends on the presence of the spans, so needs a second pass
if (marker.collapsed) doc.iter(from.line, to.line + 1, function(line) {
if (lineIsHidden(doc, line)) updateLineHeight(line, 0);
});
if (marker.clearOnEnter) on(marker, "beforeCursorEnter", function() { marker.clear(); });
if (marker.readOnly) {
sawReadOnlySpans = true;
if (doc.history.done.length || doc.history.undone.length)
doc.clearHistory();
}
if (marker.collapsed) {
marker.id = ++nextMarkerId;
marker.atomic = true;
}
if (cm) {
// Sync editor state
if (updateMaxLine) cm.curOp.updateMaxLine = true;
if (marker.collapsed)
regChange(cm, from.line, to.line + 1);
else if (marker.className || marker.title || marker.startStyle || marker.endStyle || marker.css)
for (var i = from.line; i <= to.line; i++) regLineChange(cm, i, "text");
if (marker.atomic) reCheckSelection(cm.doc);
signalLater(cm, "markerAdded", cm, marker);
}
return marker;
}
// SHARED TEXTMARKERS
// A shared marker spans multiple linked documents. It is
// implemented as a meta-marker-object controlling multiple normal
// markers.
var SharedTextMarker = CodeMirror.SharedTextMarker = function(markers, primary) {
this.markers = markers;
this.primary = primary;
for (var i = 0; i < markers.length; ++i)
markers[i].parent = this;
};
eventMixin(SharedTextMarker);
SharedTextMarker.prototype.clear = function() {
if (this.explicitlyCleared) return;
this.explicitlyCleared = true;
for (var i = 0; i < this.markers.length; ++i)
this.markers[i].clear();
signalLater(this, "clear");
};
SharedTextMarker.prototype.find = function(side, lineObj) {
return this.primary.find(side, lineObj);
};
function markTextShared(doc, from, to, options, type) {
options = copyObj(options);
options.shared = false;
var markers = [markText(doc, from, to, options, type)], primary = markers[0];
var widget = options.widgetNode;
linkedDocs(doc, function(doc) {
if (widget) options.widgetNode = widget.cloneNode(true);
markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
for (var i = 0; i < doc.linked.length; ++i)
if (doc.linked[i].isParent) return;
primary = lst(markers);
});
return new SharedTextMarker(markers, primary);
}
function findSharedMarkers(doc) {
return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())),
function(m) { return m.parent; });
}
function copySharedMarkers(doc, markers) {
for (var i = 0; i < markers.length; i++) {
var marker = markers[i], pos = marker.find();
var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
if (cmp(mFrom, mTo)) {
var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
marker.markers.push(subMark);
subMark.parent = marker;
}
}
}
function detachSharedMarkers(markers) {
for (var i = 0; i < markers.length; i++) {
var marker = markers[i], linked = [marker.primary.doc];;
linkedDocs(marker.primary.doc, function(d) { linked.push(d); });
for (var j = 0; j < marker.markers.length; j++) {
var subMarker = marker.markers[j];
if (indexOf(linked, subMarker.doc) == -1) {
subMarker.parent = null;
marker.markers.splice(j--, 1);
}
}
}
}
// TEXTMARKER SPANS
function MarkedSpan(marker, from, to) {
this.marker = marker;
this.from = from; this.to = to;
}
// Search an array of spans for a span matching the given marker.
function getMarkedSpanFor(spans, marker) {
if (spans) for (var i = 0; i < spans.length; ++i) {
var span = spans[i];
if (span.marker == marker) return span;
}
}
// Remove a span from an array, returning undefined if no spans are
// left (we don't store arrays for lines without spans).
function removeMarkedSpan(spans, span) {
for (var r, i = 0; i < spans.length; ++i)
if (spans[i] != span) (r || (r = [])).push(spans[i]);
return r;
}
// Add a span to a line.
function addMarkedSpan(line, span) {
line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
span.marker.attachLine(line);
}
// Used for the algorithm that adjusts markers for a change in the
// document. These functions cut an array of spans at a given
// character position, returning an array of remaining chunks (or
// undefined if nothing remains).
function markedSpansBefore(old, startCh, isInsert) {
if (old) for (var i = 0, nw; i < old.length; ++i) {
var span = old[i], marker = span.marker;
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh);
(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
}
}
return nw;
}
function markedSpansAfter(old, endCh, isInsert) {
if (old) for (var i = 0, nw; i < old.length; ++i) {
var span = old[i], marker = span.marker;
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh);
(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
span.to == null ? null : span.to - endCh));
}
}
return nw;
}
// Given a change object, compute the new set of marker spans that
// cover the line in which the change took place. Removes spans
// entirely within the change, reconnects spans belonging to the
// same marker that appear on both sides of the change, and cuts off
// spans partially within the change. Returns an array of span
// arrays with one element for each line in (after) the change.
function stretchSpansOverChange(doc, change) {
if (change.full) return null;
var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
if (!oldFirst && !oldLast) return null;
var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
// Get the spans that 'stick out' on both sides
var first = markedSpansBefore(oldFirst, startCh, isInsert);
var last = markedSpansAfter(oldLast, endCh, isInsert);
// Next, merge those two ends
var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
if (first) {
// Fix up .to properties of first
for (var i = 0; i < first.length; ++i) {
var span = first[i];
if (span.to == null) {
var found = getMarkedSpanFor(last, span.marker);
if (!found) span.to = startCh;
else if (sameLine) span.to = found.to == null ? null : found.to + offset;
}
}
}
if (last) {
// Fix up .from in last (or move them into first in case of sameLine)
for (var i = 0; i < last.length; ++i) {
var span = last[i];
if (span.to != null) span.to += offset;
if (span.from == null) {
var found = getMarkedSpanFor(first, span.marker);
if (!found) {
span.from = offset;
if (sameLine) (first || (first = [])).push(span);
}
} else {
span.from += offset;
if (sameLine) (first || (first = [])).push(span);
}
}
}
// Make sure we didn't create any zero-length spans
if (first) first = clearEmptySpans(first);
if (last && last != first) last = clearEmptySpans(last);
var newMarkers = [first];
if (!sameLine) {
// Fill gap with whole-line-spans
var gap = change.text.length - 2, gapMarkers;
if (gap > 0 && first)
for (var i = 0; i < first.length; ++i)
if (first[i].to == null)
(gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i].marker, null, null));
for (var i = 0; i < gap; ++i)
newMarkers.push(gapMarkers);
newMarkers.push(last);
}
return newMarkers;
}
// Remove spans that are empty and don't have a clearWhenEmpty
// option of false.
function clearEmptySpans(spans) {
for (var i = 0; i < spans.length; ++i) {
var span = spans[i];
if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
spans.splice(i--, 1);
}
if (!spans.length) return null;
return spans;
}
// Used for un/re-doing changes from the history. Combines the
// result of computing the existing spans with the set of spans that
// existed in the history (so that deleting around a span and then
// undoing brings back the span).
function mergeOldSpans(doc, change) {
var old = getOldSpans(doc, change);
var stretched = stretchSpansOverChange(doc, change);
if (!old) return stretched;
if (!stretched) return old;
for (var i = 0; i < old.length; ++i) {
var oldCur = old[i], stretchCur = stretched[i];
if (oldCur && stretchCur) {
spans: for (var j = 0; j < stretchCur.length; ++j) {
var span = stretchCur[j];
for (var k = 0; k < oldCur.length; ++k)
if (oldCur[k].marker == span.marker) continue spans;
oldCur.push(span);
}
} else if (stretchCur) {
old[i] = stretchCur;
}
}
return old;
}
// Used to 'clip' out readOnly ranges when making a change.
function removeReadOnlyRanges(doc, from, to) {
var markers = null;
doc.iter(from.line, to.line + 1, function(line) {
if (line.markedSpans) for (var i = 0; i < line.markedSpans.length; ++i) {
var mark = line.markedSpans[i].marker;
if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
(markers || (markers = [])).push(mark);
}
});
if (!markers) return null;
var parts = [{from: from, to: to}];
for (var i = 0; i < markers.length; ++i) {
var mk = markers[i], m = mk.find(0);
for (var j = 0; j < parts.length; ++j) {
var p = parts[j];
if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) continue;
var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
newParts.push({from: p.from, to: m.from});
if (dto > 0 || !mk.inclusiveRight && !dto)
newParts.push({from: m.to, to: p.to});
parts.splice.apply(parts, newParts);
j += newParts.length - 1;
}
}
return parts;
}
// Connect or disconnect spans from a line.
function detachMarkedSpans(line) {
var spans = line.markedSpans;
if (!spans) return;
for (var i = 0; i < spans.length; ++i)
spans[i].marker.detachLine(line);
line.markedSpans = null;
}
function attachMarkedSpans(line, spans) {
if (!spans) return;
for (var i = 0; i < spans.length; ++i)
spans[i].marker.attachLine(line);
line.markedSpans = spans;
}
// Helpers used when computing which overlapping collapsed span
// counts as the larger one.
function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0; }
function extraRight(marker) { return marker.inclusiveRight ? 1 : 0; }
// Returns a number indicating which of two overlapping collapsed
// spans is larger (and thus includes the other). Falls back to
// comparing ids when the spans cover exactly the same range.
function compareCollapsedMarkers(a, b) {
var lenDiff = a.lines.length - b.lines.length;
if (lenDiff != 0) return lenDiff;
var aPos = a.find(), bPos = b.find();
var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
if (fromCmp) return -fromCmp;
var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
if (toCmp) return toCmp;
return b.id - a.id;
}
// Find out whether a line ends or starts in a collapsed span. If
// so, return the marker for that span.
function collapsedSpanAtSide(line, start) {
var sps = sawCollapsedSpans && line.markedSpans, found;
if (sps) for (var sp, i = 0; i < sps.length; ++i) {
sp = sps[i];
if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
(!found || compareCollapsedMarkers(found, sp.marker) < 0))
found = sp.marker;
}
return found;
}
function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true); }
function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false); }
// Test whether there exists a collapsed span that partially
// overlaps (covers the start or end, but not both) of a new span.
// Such overlap is not allowed.
function conflictingCollapsedRange(doc, lineNo, from, to, marker) {
var line = getLine(doc, lineNo);
var sps = sawCollapsedSpans && line.markedSpans;
if (sps) for (var i = 0; i < sps.length; ++i) {
var sp = sps[i];
if (!sp.marker.collapsed) continue;
var found = sp.marker.find(0);
var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) continue;
if (fromCmp <= 0 && (cmp(found.to, from) > 0 || (sp.marker.inclusiveRight && marker.inclusiveLeft)) ||
fromCmp >= 0 && (cmp(found.from, to) < 0 || (sp.marker.inclusiveLeft && marker.inclusiveRight)))
return true;
}
}
// A visual line is a line as drawn on the screen. Folding, for
// example, can cause multiple logical lines to appear on the same
// visual line. This finds the start of the visual line that the
// given line is part of (usually that is the line itself).
function visualLine(line) {
var merged;
while (merged = collapsedSpanAtStart(line))
line = merged.find(-1, true).line;
return line;
}
// Returns an array of logical lines that continue the visual line
// started by the argument, or undefined if there are no such lines.
function visualLineContinued(line) {
var merged, lines;
while (merged = collapsedSpanAtEnd(line)) {
line = merged.find(1, true).line;
(lines || (lines = [])).push(line);
}
return lines;
}
// Get the line number of the start of the visual line that the
// given line number is part of.
function visualLineNo(doc, lineN) {
var line = getLine(doc, lineN), vis = visualLine(line);
if (line == vis) return lineN;
return lineNo(vis);
}
// Get the line number of the start of the next visual line after
// the given line.
function visualLineEndNo(doc, lineN) {
if (lineN > doc.lastLine()) return lineN;
var line = getLine(doc, lineN), merged;
if (!lineIsHidden(doc, line)) return lineN;
while (merged = collapsedSpanAtEnd(line))
line = merged.find(1, true).line;
return lineNo(line) + 1;
}
// Compute whether a line is hidden. Lines count as hidden when they
// are part of a visual line that starts with another line, or when
// they are entirely covered by collapsed, non-widget span.
function lineIsHidden(doc, line) {
var sps = sawCollapsedSpans && line.markedSpans;
if (sps) for (var sp, i = 0; i < sps.length; ++i) {
sp = sps[i];
if (!sp.marker.collapsed) continue;
if (sp.from == null) return true;
if (sp.marker.widgetNode) continue;
if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
return true;
}
}
function lineIsHiddenInner(doc, line, span) {
if (span.to == null) {
var end = span.marker.find(1, true);
return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker));
}
if (span.marker.inclusiveRight && span.to == line.text.length)
return true;
for (var sp, i = 0; i < line.markedSpans.length; ++i) {
sp = line.markedSpans[i];
if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
(sp.to == null || sp.to != span.from) &&
(sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
lineIsHiddenInner(doc, line, sp)) return true;
}
}
// LINE WIDGETS
// Line widgets are block elements displayed above or below a line.
var LineWidget = CodeMirror.LineWidget = function(doc, node, options) {
if (options) for (var opt in options) if (options.hasOwnProperty(opt))
this[opt] = options[opt];
this.doc = doc;
this.node = node;
};
eventMixin(LineWidget);
function adjustScrollWhenAboveVisible(cm, line, diff) {
if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
addToScrollPos(cm, null, diff);
}
LineWidget.prototype.clear = function() {
var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
if (no == null || !ws) return;
for (var i = 0; i < ws.length; ++i) if (ws[i] == this) ws.splice(i--, 1);
if (!ws.length) line.widgets = null;
var height = widgetHeight(this);
updateLineHeight(line, Math.max(0, line.height - height));
if (cm) runInOp(cm, function() {
adjustScrollWhenAboveVisible(cm, line, -height);
regLineChange(cm, no, "widget");
});
};
LineWidget.prototype.changed = function() {
var oldH = this.height, cm = this.doc.cm, line = this.line;
this.height = null;
var diff = widgetHeight(this) - oldH;
if (!diff) return;
updateLineHeight(line, line.height + diff);
if (cm) runInOp(cm, function() {
cm.curOp.forceUpdate = true;
adjustScrollWhenAboveVisible(cm, line, diff);
});
};
function widgetHeight(widget) {
if (widget.height != null) return widget.height;
var cm = widget.doc.cm;
if (!cm) return 0;
if (!contains(document.body, widget.node)) {
var parentStyle = "position: relative;";
if (widget.coverGutter)
parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;";
if (widget.noHScroll)
parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;";
removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
}
return widget.height = widget.node.parentNode.offsetHeight;
}
function addLineWidget(doc, handle, node, options) {
var widget = new LineWidget(doc, node, options);
var cm = doc.cm;
if (cm && widget.noHScroll) cm.display.alignWidgets = true;
changeLine(doc, handle, "widget", function(line) {
var widgets = line.widgets || (line.widgets = []);
if (widget.insertAt == null) widgets.push(widget);
else widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget);
widget.line = line;
if (cm && !lineIsHidden(doc, line)) {
var aboveVisible = heightAtLine(line) < doc.scrollTop;
updateLineHeight(line, line.height + widgetHeight(widget));
if (aboveVisible) addToScrollPos(cm, null, widget.height);
cm.curOp.forceUpdate = true;
}
return true;
});
return widget;
}
// LINE DATA STRUCTURE
// Line objects. These hold state related to a line, including
// highlighting info (the styles array).
var Line = CodeMirror.Line = function(text, markedSpans, estimateHeight) {
this.text = text;
attachMarkedSpans(this, markedSpans);
this.height = estimateHeight ? estimateHeight(this) : 1;
};
eventMixin(Line);
Line.prototype.lineNo = function() { return lineNo(this); };
// Change the content (text, markers) of a line. Automatically
// invalidates cached information and tries to re-estimate the
// line's height.
function updateLine(line, text, markedSpans, estimateHeight) {
line.text = text;
if (line.stateAfter) line.stateAfter = null;
if (line.styles) line.styles = null;
if (line.order != null) line.order = null;
detachMarkedSpans(line);
attachMarkedSpans(line, markedSpans);
var estHeight = estimateHeight ? estimateHeight(line) : 1;
if (estHeight != line.height) updateLineHeight(line, estHeight);
}
// Detach a line from the document tree and its markers.
function cleanUpLine(line) {
line.parent = null;
detachMarkedSpans(line);
}
function extractLineClasses(type, output) {
if (type) for (;;) {
var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
if (!lineClass) break;
type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
var prop = lineClass[1] ? "bgClass" : "textClass";
if (output[prop] == null)
output[prop] = lineClass[2];
else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
output[prop] += " " + lineClass[2];
}
return type;
}
function callBlankLine(mode, state) {
if (mode.blankLine) return mode.blankLine(state);
if (!mode.innerMode) return;
var inner = CodeMirror.innerMode(mode, state);
if (inner.mode.blankLine) return inner.mode.blankLine(inner.state);
}
function readToken(mode, stream, state, inner) {
for (var i = 0; i < 10; i++) {
if (inner) inner[0] = CodeMirror.innerMode(mode, state).mode;
var style = mode.token(stream, state);
if (stream.pos > stream.start) return style;
}
throw new Error("Mode " + mode.name + " failed to advance stream.");
}
// Utility for getTokenAt and getLineTokens
function takeToken(cm, pos, precise, asArray) {
function getObj(copy) {
return {start: stream.start, end: stream.pos,
string: stream.current(),
type: style || null,
state: copy ? copyState(doc.mode, state) : state};
}
var doc = cm.doc, mode = doc.mode, style;
pos = clipPos(doc, pos);
var line = getLine(doc, pos.line), state = getStateBefore(cm, pos.line, precise);
var stream = new StringStream(line.text, cm.options.tabSize), tokens;
if (asArray) tokens = [];
while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
stream.start = stream.pos;
style = readToken(mode, stream, state);
if (asArray) tokens.push(getObj(true));
}
return asArray ? tokens : getObj();
}
// Run the given mode's parser over a line, calling f for each token.
function runMode(cm, text, mode, state, f, lineClasses, forceToEnd) {
var flattenSpans = mode.flattenSpans;
if (flattenSpans == null) flattenSpans = cm.options.flattenSpans;
var curStart = 0, curStyle = null;
var stream = new StringStream(text, cm.options.tabSize), style;
var inner = cm.options.addModeClass && [null];
if (text == "") extractLineClasses(callBlankLine(mode, state), lineClasses);
while (!stream.eol()) {
if (stream.pos > cm.options.maxHighlightLength) {
flattenSpans = false;
if (forceToEnd) processLine(cm, text, state, stream.pos);
stream.pos = text.length;
style = null;
} else {
style = extractLineClasses(readToken(mode, stream, state, inner), lineClasses);
}
if (inner) {
var mName = inner[0].name;
if (mName) style = "m-" + (style ? mName + " " + style : mName);
}
if (!flattenSpans || curStyle != style) {
while (curStart < stream.start) {
curStart = Math.min(stream.start, curStart + 50000);
f(curStart, curStyle);
}
curStyle = style;
}
stream.start = stream.pos;
}
while (curStart < stream.pos) {
// Webkit seems to refuse to render text nodes longer than 57444 characters
var pos = Math.min(stream.pos, curStart + 50000);
f(pos, curStyle);
curStart = pos;
}
}
// Compute a style array (an array starting with a mode generation
// -- for invalidation -- followed by pairs of end positions and
// style strings), which is used to highlight the tokens on the
// line.
function highlightLine(cm, line, state, forceToEnd) {
// A styles array always starts with a number identifying the
// mode/overlays that it is based on (for easy invalidation).
var st = [cm.state.modeGen], lineClasses = {};
// Compute the base array of styles
runMode(cm, line.text, cm.doc.mode, state, function(end, style) {
st.push(end, style);
}, lineClasses, forceToEnd);
// Run overlays, adjust style array.
for (var o = 0; o < cm.state.overlays.length; ++o) {
var overlay = cm.state.overlays[o], i = 1, at = 0;
runMode(cm, line.text, overlay.mode, true, function(end, style) {
var start = i;
// Ensure there's a token end at the current position, and that i points at it
while (at < end) {
var i_end = st[i];
if (i_end > end)
st.splice(i, 1, end, st[i+1], i_end);
i += 2;
at = Math.min(end, i_end);
}
if (!style) return;
if (overlay.opaque) {
st.splice(start, i - start, end, "cm-overlay " + style);
i = start + 2;
} else {
for (; start < i; start += 2) {
var cur = st[start+1];
st[start+1] = (cur ? cur + " " : "") + "cm-overlay " + style;
}
}
}, lineClasses);
}
return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null};
}
function getLineStyles(cm, line, updateFrontier) {
if (!line.styles || line.styles[0] != cm.state.modeGen) {
var state = getStateBefore(cm, lineNo(line));
var result = highlightLine(cm, line, line.text.length > cm.options.maxHighlightLength ? copyState(cm.doc.mode, state) : state);
line.stateAfter = state;
line.styles = result.styles;
if (result.classes) line.styleClasses = result.classes;
else if (line.styleClasses) line.styleClasses = null;
if (updateFrontier === cm.doc.frontier) cm.doc.frontier++;
}
return line.styles;
}
// Lightweight form of highlight -- proceed over this line and
// update state, but don't save a style array. Used for lines that
// aren't currently visible.
function processLine(cm, text, state, startAt) {
var mode = cm.doc.mode;
var stream = new StringStream(text, cm.options.tabSize);
stream.start = stream.pos = startAt || 0;
if (text == "") callBlankLine(mode, state);
while (!stream.eol()) {
readToken(mode, stream, state);
stream.start = stream.pos;
}
}
// Convert a style as returned by a mode (either null, or a string
// containing one or more styles) to a CSS style. This is cached,
// and also looks for line-wide styles.
var styleToClassCache = {}, styleToClassCacheWithMode = {};
function interpretTokenStyle(style, options) {
if (!style || /^\s*$/.test(style)) return null;
var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
return cache[style] ||
(cache[style] = style.replace(/\S+/g, "cm-$&"));
}
// Render the DOM representation of the text of a line. Also builds
// up a 'line map', which points at the DOM nodes that represent
// specific stretches of text, and is used by the measuring code.
// The returned object contains the DOM node, this map, and
// information about line-wide styles that were set by the mode.
function buildLineContent(cm, lineView) {
// The padding-right forces the element to have a 'border', which
// is needed on Webkit to be able to get line-level bounding
// rectangles for it (in measureChar).
var content = elt("span", null, null, webkit ? "padding-right: .1px" : null);
var builder = {pre: elt("pre", [content], "CodeMirror-line"), content: content,
col: 0, pos: 0, cm: cm,
splitSpaces: (ie || webkit) && cm.getOption("lineWrapping")};
lineView.measure = {};
// Iterate over the logical lines that make up this visual line.
for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
var line = i ? lineView.rest[i - 1] : lineView.line, order;
builder.pos = 0;
builder.addToken = buildToken;
// Optionally wire in some hacks into the token-rendering
// algorithm, to deal with browser quirks.
if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line)))
builder.addToken = buildTokenBadBidi(builder.addToken, order);
builder.map = [];
var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
if (line.styleClasses) {
if (line.styleClasses.bgClass)
builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || "");
if (line.styleClasses.textClass)
builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || "");
}
// Ensure at least a single node is present, for measuring.
if (builder.map.length == 0)
builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure)));
// Store the map and a cache object for the current logical line
if (i == 0) {
lineView.measure.map = builder.map;
lineView.measure.cache = {};
} else {
(lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map);
(lineView.measure.caches || (lineView.measure.caches = [])).push({});
}
}
// See issue #2901
if (webkit && /\bcm-tab\b/.test(builder.content.lastChild.className))
builder.content.className = "cm-tab-wrap-hack";
signal(cm, "renderLine", cm, lineView.line, builder.pre);
if (builder.pre.className)
builder.textClass = joinClasses(builder.pre.className, builder.textClass || "");
return builder;
}
function defaultSpecialCharPlaceholder(ch) {
var token = elt("span", "\u2022", "cm-invalidchar");
token.title = "\\u" + ch.charCodeAt(0).toString(16);
token.setAttribute("aria-label", token.title);
return token;
}
// Build up the DOM representation for a single token, and add it to
// the line map. Takes care to render special characters separately.
function buildToken(builder, text, style, startStyle, endStyle, title, css) {
if (!text) return;
var displayText = builder.splitSpaces ? text.replace(/ {3,}/g, splitSpaces) : text;
var special = builder.cm.state.specialChars, mustWrap = false;
if (!special.test(text)) {
builder.col += text.length;
var content = document.createTextNode(displayText);
builder.map.push(builder.pos, builder.pos + text.length, content);
if (ie && ie_version < 9) mustWrap = true;
builder.pos += text.length;
} else {
var content = document.createDocumentFragment(), pos = 0;
while (true) {
special.lastIndex = pos;
var m = special.exec(text);
var skipped = m ? m.index - pos : text.length - pos;
if (skipped) {
var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
else content.appendChild(txt);
builder.map.push(builder.pos, builder.pos + skipped, txt);
builder.col += skipped;
builder.pos += skipped;
}
if (!m) break;
pos += skipped + 1;
if (m[0] == "\t") {
var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
var txt = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
txt.setAttribute("role", "presentation");
txt.setAttribute("cm-text", "\t");
builder.col += tabWidth;
} else if (m[0] == "\r" || m[0] == "\n") {
var txt = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
txt.setAttribute("cm-text", m[0]);
builder.col += 1;
} else {
var txt = builder.cm.options.specialCharPlaceholder(m[0]);
txt.setAttribute("cm-text", m[0]);
if (ie && ie_version < 9) content.appendChild(elt("span", [txt]));
else content.appendChild(txt);
builder.col += 1;
}
builder.map.push(builder.pos, builder.pos + 1, txt);
builder.pos++;
}
}
if (style || startStyle || endStyle || mustWrap || css) {
var fullStyle = style || "";
if (startStyle) fullStyle += startStyle;
if (endStyle) fullStyle += endStyle;
var token = elt("span", [content], fullStyle, css);
if (title) token.title = title;
return builder.content.appendChild(token);
}
builder.content.appendChild(content);
}
function splitSpaces(old) {
var out = " ";
for (var i = 0; i < old.length - 2; ++i) out += i % 2 ? " " : "\u00a0";
out += " ";
return out;
}
// Work around nonsense dimensions being reported for stretches of
// right-to-left text.
function buildTokenBadBidi(inner, order) {
return function(builder, text, style, startStyle, endStyle, title, css) {
style = style ? style + " cm-force-border" : "cm-force-border";
var start = builder.pos, end = start + text.length;
for (;;) {
// Find the part that overlaps with the start of this text
for (var i = 0; i < order.length; i++) {
var part = order[i];
if (part.to > start && part.from <= start) break;
}
if (part.to >= end) return inner(builder, text, style, startStyle, endStyle, title, css);
inner(builder, text.slice(0, part.to - start), style, startStyle, null, title, css);
startStyle = null;
text = text.slice(part.to - start);
start = part.to;
}
};
}
function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
var widget = !ignoreWidget && marker.widgetNode;
if (widget) builder.map.push(builder.pos, builder.pos + size, widget);
if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
if (!widget)
widget = builder.content.appendChild(document.createElement("span"));
widget.setAttribute("cm-marker", marker.id);
}
if (widget) {
builder.cm.display.input.setUneditable(widget);
builder.content.appendChild(widget);
}
builder.pos += size;
}
// Outputs a number of spans to make up a line, taking highlighting
// and marked text into account.
function insertLineContent(line, builder, styles) {
var spans = line.markedSpans, allText = line.text, at = 0;
if (!spans) {
for (var i = 1; i < styles.length; i+=2)
builder.addToken(builder, allText.slice(at, at = styles[i]), interpretTokenStyle(styles[i+1], builder.cm.options));
return;
}
var len = allText.length, pos = 0, i = 1, text = "", style, css;
var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, title, collapsed;
for (;;) {
if (nextChange == pos) { // Update current marker set
spanStyle = spanEndStyle = spanStartStyle = title = css = "";
collapsed = null; nextChange = Infinity;
var foundBookmarks = [];
for (var j = 0; j < spans.length; ++j) {
var sp = spans[j], m = sp.marker;
if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
foundBookmarks.push(m);
} else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
if (sp.to != null && sp.to != pos && nextChange > sp.to) {
nextChange = sp.to;
spanEndStyle = "";
}
if (m.className) spanStyle += " " + m.className;
if (m.css) css = (css ? css + ";" : "") + m.css;
if (m.startStyle && sp.from == pos) spanStartStyle += " " + m.startStyle;
if (m.endStyle && sp.to == nextChange) spanEndStyle += " " + m.endStyle;
if (m.title && !title) title = m.title;
if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
collapsed = sp;
} else if (sp.from > pos && nextChange > sp.from) {
nextChange = sp.from;
}
}
if (collapsed && (collapsed.from || 0) == pos) {
buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
collapsed.marker, collapsed.from == null);
if (collapsed.to == null) return;
if (collapsed.to == pos) collapsed = false;
}
if (!collapsed && foundBookmarks.length) for (var j = 0; j < foundBookmarks.length; ++j)
buildCollapsedSpan(builder, 0, foundBookmarks[j]);
}
if (pos >= len) break;
var upto = Math.min(len, nextChange);
while (true) {
if (text) {
var end = pos + text.length;
if (!collapsed) {
var tokenText = end > upto ? text.slice(0, upto - pos) : text;
builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", title, css);
}
if (end >= upto) {text = text.slice(upto - pos); pos = upto; break;}
pos = end;
spanStartStyle = "";
}
text = allText.slice(at, at = styles[i++]);
style = interpretTokenStyle(styles[i++], builder.cm.options);
}
}
}
// DOCUMENT DATA STRUCTURE
// By default, updates that start and end at the beginning of a line
// are treated specially, in order to make the association of line
// widgets and marker elements with the text behave more intuitive.
function isWholeLineUpdate(doc, change) {
return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
(!doc.cm || doc.cm.options.wholeLineUpdateBefore);
}
// Perform a change on the document data structure.
function updateDoc(doc, change, markedSpans, estimateHeight) {
function spansFor(n) {return markedSpans ? markedSpans[n] : null;}
function update(line, text, spans) {
updateLine(line, text, spans, estimateHeight);
signalLater(line, "change", line, change);
}
function linesFor(start, end) {
for (var i = start, result = []; i < end; ++i)
result.push(new Line(text[i], spansFor(i), estimateHeight));
return result;
}
var from = change.from, to = change.to, text = change.text;
var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
// Adjust the line structure
if (change.full) {
doc.insert(0, linesFor(0, text.length));
doc.remove(text.length, doc.size - text.length);
} else if (isWholeLineUpdate(doc, change)) {
// This is a whole-line replace. Treated specially to make
// sure line objects move the way they are supposed to.
var added = linesFor(0, text.length - 1);
update(lastLine, lastLine.text, lastSpans);
if (nlines) doc.remove(from.line, nlines);
if (added.length) doc.insert(from.line, added);
} else if (firstLine == lastLine) {
if (text.length == 1) {
update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
} else {
var added = linesFor(1, text.length - 1);
added.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight));
update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
doc.insert(from.line + 1, added);
}
} else if (text.length == 1) {
update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
doc.remove(from.line + 1, nlines);
} else {
update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
var added = linesFor(1, text.length - 1);
if (nlines > 1) doc.remove(from.line + 1, nlines - 1);
doc.insert(from.line + 1, added);
}
signalLater(doc, "change", doc, change);
}
// The document is represented as a BTree consisting of leaves, with
// chunk of lines in them, and branches, with up to ten leaves or
// other branch nodes below them. The top node is always a branch
// node, and is the document object itself (meaning it has
// additional methods and properties).
//
// All nodes have parent links. The tree is used both to go from
// line numbers to line objects, and to go from objects to numbers.
// It also indexes by height, and is used to convert between height
// and line object, and to find the total height of the document.
//
// See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
function LeafChunk(lines) {
this.lines = lines;
this.parent = null;
for (var i = 0, height = 0; i < lines.length; ++i) {
lines[i].parent = this;
height += lines[i].height;
}
this.height = height;
}
LeafChunk.prototype = {
chunkSize: function() { return this.lines.length; },
// Remove the n lines at offset 'at'.
removeInner: function(at, n) {
for (var i = at, e = at + n; i < e; ++i) {
var line = this.lines[i];
this.height -= line.height;
cleanUpLine(line);
signalLater(line, "delete");
}
this.lines.splice(at, n);
},
// Helper used to collapse a small branch into a single leaf.
collapse: function(lines) {
lines.push.apply(lines, this.lines);
},
// Insert the given array of lines at offset 'at', count them as
// having the given height.
insertInner: function(at, lines, height) {
this.height += height;
this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
for (var i = 0; i < lines.length; ++i) lines[i].parent = this;
},
// Used to iterate over a part of the tree.
iterN: function(at, n, op) {
for (var e = at + n; at < e; ++at)
if (op(this.lines[at])) return true;
}
};
function BranchChunk(children) {
this.children = children;
var size = 0, height = 0;
for (var i = 0; i < children.length; ++i) {
var ch = children[i];
size += ch.chunkSize(); height += ch.height;
ch.parent = this;
}
this.size = size;
this.height = height;
this.parent = null;
}
BranchChunk.prototype = {
chunkSize: function() { return this.size; },
removeInner: function(at, n) {
this.size -= n;
for (var i = 0; i < this.children.length; ++i) {
var child = this.children[i], sz = child.chunkSize();
if (at < sz) {
var rm = Math.min(n, sz - at), oldHeight = child.height;
child.removeInner(at, rm);
this.height -= oldHeight - child.height;
if (sz == rm) { this.children.splice(i--, 1); child.parent = null; }
if ((n -= rm) == 0) break;
at = 0;
} else at -= sz;
}
// If the result is smaller than 25 lines, ensure that it is a
// single leaf node.
if (this.size - n < 25 &&
(this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
var lines = [];
this.collapse(lines);
this.children = [new LeafChunk(lines)];
this.children[0].parent = this;
}
},
collapse: function(lines) {
for (var i = 0; i < this.children.length; ++i) this.children[i].collapse(lines);
},
insertInner: function(at, lines, height) {
this.size += lines.length;
this.height += height;
for (var i = 0; i < this.children.length; ++i) {
var child = this.children[i], sz = child.chunkSize();
if (at <= sz) {
child.insertInner(at, lines, height);
if (child.lines && child.lines.length > 50) {
while (child.lines.length > 50) {
var spilled = child.lines.splice(child.lines.length - 25, 25);
var newleaf = new LeafChunk(spilled);
child.height -= newleaf.height;
this.children.splice(i + 1, 0, newleaf);
newleaf.parent = this;
}
this.maybeSpill();
}
break;
}
at -= sz;
}
},
// When a node has grown, check whether it should be split.
maybeSpill: function() {
if (this.children.length <= 10) return;
var me = this;
do {
var spilled = me.children.splice(me.children.length - 5, 5);
var sibling = new BranchChunk(spilled);
if (!me.parent) { // Become the parent node
var copy = new BranchChunk(me.children);
copy.parent = me;
me.children = [copy, sibling];
me = copy;
} else {
me.size -= sibling.size;
me.height -= sibling.height;
var myIndex = indexOf(me.parent.children, me);
me.parent.children.splice(myIndex + 1, 0, sibling);
}
sibling.parent = me.parent;
} while (me.children.length > 10);
me.parent.maybeSpill();
},
iterN: function(at, n, op) {
for (var i = 0; i < this.children.length; ++i) {
var child = this.children[i], sz = child.chunkSize();
if (at < sz) {
var used = Math.min(n, sz - at);
if (child.iterN(at, used, op)) return true;
if ((n -= used) == 0) break;
at = 0;
} else at -= sz;
}
}
};
var nextDocId = 0;
var Doc = CodeMirror.Doc = function(text, mode, firstLine, lineSep) {
if (!(this instanceof Doc)) return new Doc(text, mode, firstLine, lineSep);
if (firstLine == null) firstLine = 0;
BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
this.first = firstLine;
this.scrollTop = this.scrollLeft = 0;
this.cantEdit = false;
this.cleanGeneration = 1;
this.frontier = firstLine;
var start = Pos(firstLine, 0);
this.sel = simpleSelection(start);
this.history = new History(null);
this.id = ++nextDocId;
this.modeOption = mode;
this.lineSep = lineSep;
this.extend = false;
if (typeof text == "string") text = this.splitLines(text);
updateDoc(this, {from: start, to: start, text: text});
setSelection(this, simpleSelection(start), sel_dontScroll);
};
Doc.prototype = createObj(BranchChunk.prototype, {
constructor: Doc,
// Iterate over the document. Supports two forms -- with only one
// argument, it calls that for each line in the document. With
// three, it iterates over the range given by the first two (with
// the second being non-inclusive).
iter: function(from, to, op) {
if (op) this.iterN(from - this.first, to - from, op);
else this.iterN(this.first, this.first + this.size, from);
},
// Non-public interface for adding and removing lines.
insert: function(at, lines) {
var height = 0;
for (var i = 0; i < lines.length; ++i) height += lines[i].height;
this.insertInner(at - this.first, lines, height);
},
remove: function(at, n) { this.removeInner(at - this.first, n); },
// From here, the methods are part of the public interface. Most
// are also available from CodeMirror (editor) instances.
getValue: function(lineSep) {
var lines = getLines(this, this.first, this.first + this.size);
if (lineSep === false) return lines;
return lines.join(lineSep || this.lineSeparator());
},
setValue: docMethodOp(function(code) {
var top = Pos(this.first, 0), last = this.first + this.size - 1;
makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
text: this.splitLines(code), origin: "setValue", full: true}, true);
setSelection(this, simpleSelection(top));
}),
replaceRange: function(code, from, to, origin) {
from = clipPos(this, from);
to = to ? clipPos(this, to) : from;
replaceRange(this, code, from, to, origin);
},
getRange: function(from, to, lineSep) {
var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
if (lineSep === false) return lines;
return lines.join(lineSep || this.lineSeparator());
},
getLine: function(line) {var l = this.getLineHandle(line); return l && l.text;},
getLineHandle: function(line) {if (isLine(this, line)) return getLine(this, line);},
getLineNumber: function(line) {return lineNo(line);},
getLineHandleVisualStart: function(line) {
if (typeof line == "number") line = getLine(this, line);
return visualLine(line);
},
lineCount: function() {return this.size;},
firstLine: function() {return this.first;},
lastLine: function() {return this.first + this.size - 1;},
clipPos: function(pos) {return clipPos(this, pos);},
getCursor: function(start) {
var range = this.sel.primary(), pos;
if (start == null || start == "head") pos = range.head;
else if (start == "anchor") pos = range.anchor;
else if (start == "end" || start == "to" || start === false) pos = range.to();
else pos = range.from();
return pos;
},
listSelections: function() { return this.sel.ranges; },
somethingSelected: function() {return this.sel.somethingSelected();},
setCursor: docMethodOp(function(line, ch, options) {
setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
}),
setSelection: docMethodOp(function(anchor, head, options) {
setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
}),
extendSelection: docMethodOp(function(head, other, options) {
extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
}),
extendSelections: docMethodOp(function(heads, options) {
extendSelections(this, clipPosArray(this, heads, options));
}),
extendSelectionsBy: docMethodOp(function(f, options) {
extendSelections(this, map(this.sel.ranges, f), options);
}),
setSelections: docMethodOp(function(ranges, primary, options) {
if (!ranges.length) return;
for (var i = 0, out = []; i < ranges.length; i++)
out[i] = new Range(clipPos(this, ranges[i].anchor),
clipPos(this, ranges[i].head));
if (primary == null) primary = Math.min(ranges.length - 1, this.sel.primIndex);
setSelection(this, normalizeSelection(out, primary), options);
}),
addSelection: docMethodOp(function(anchor, head, options) {
var ranges = this.sel.ranges.slice(0);
ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
setSelection(this, normalizeSelection(ranges, ranges.length - 1), options);
}),
getSelection: function(lineSep) {
var ranges = this.sel.ranges, lines;
for (var i = 0; i < ranges.length; i++) {
var sel = getBetween(this, ranges[i].from(), ranges[i].to());
lines = lines ? lines.concat(sel) : sel;
}
if (lineSep === false) return lines;
else return lines.join(lineSep || this.lineSeparator());
},
getSelections: function(lineSep) {
var parts = [], ranges = this.sel.ranges;
for (var i = 0; i < ranges.length; i++) {
var sel = getBetween(this, ranges[i].from(), ranges[i].to());
if (lineSep !== false) sel = sel.join(lineSep || this.lineSeparator());
parts[i] = sel;
}
return parts;
},
replaceSelection: function(code, collapse, origin) {
var dup = [];
for (var i = 0; i < this.sel.ranges.length; i++)
dup[i] = code;
this.replaceSelections(dup, collapse, origin || "+input");
},
replaceSelections: docMethodOp(function(code, collapse, origin) {
var changes = [], sel = this.sel;
for (var i = 0; i < sel.ranges.length; i++) {
var range = sel.ranges[i];
changes[i] = {from: range.from(), to: range.to(), text: this.splitLines(code[i]), origin: origin};
}
var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
for (var i = changes.length - 1; i >= 0; i--)
makeChange(this, changes[i]);
if (newSel) setSelectionReplaceHistory(this, newSel);
else if (this.cm) ensureCursorVisible(this.cm);
}),
undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
setExtending: function(val) {this.extend = val;},
getExtending: function() {return this.extend;},
historySize: function() {
var hist = this.history, done = 0, undone = 0;
for (var i = 0; i < hist.done.length; i++) if (!hist.done[i].ranges) ++done;
for (var i = 0; i < hist.undone.length; i++) if (!hist.undone[i].ranges) ++undone;
return {undo: done, redo: undone};
},
clearHistory: function() {this.history = new History(this.history.maxGeneration);},
markClean: function() {
this.cleanGeneration = this.changeGeneration(true);
},
changeGeneration: function(forceSplit) {
if (forceSplit)
this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null;
return this.history.generation;
},
isClean: function (gen) {
return this.history.generation == (gen || this.cleanGeneration);
},
getHistory: function() {
return {done: copyHistoryArray(this.history.done),
undone: copyHistoryArray(this.history.undone)};
},
setHistory: function(histData) {
var hist = this.history = new History(this.history.maxGeneration);
hist.done = copyHistoryArray(histData.done.slice(0), null, true);
hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
},
addLineClass: docMethodOp(function(handle, where, cls) {
return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
var prop = where == "text" ? "textClass"
: where == "background" ? "bgClass"
: where == "gutter" ? "gutterClass" : "wrapClass";
if (!line[prop]) line[prop] = cls;
else if (classTest(cls).test(line[prop])) return false;
else line[prop] += " " + cls;
return true;
});
}),
removeLineClass: docMethodOp(function(handle, where, cls) {
return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function(line) {
var prop = where == "text" ? "textClass"
: where == "background" ? "bgClass"
: where == "gutter" ? "gutterClass" : "wrapClass";
var cur = line[prop];
if (!cur) return false;
else if (cls == null) line[prop] = null;
else {
var found = cur.match(classTest(cls));
if (!found) return false;
var end = found.index + found[0].length;
line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
}
return true;
});
}),
addLineWidget: docMethodOp(function(handle, node, options) {
return addLineWidget(this, handle, node, options);
}),
removeLineWidget: function(widget) { widget.clear(); },
markText: function(from, to, options) {
return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range");
},
setBookmark: function(pos, options) {
var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
insertLeft: options && options.insertLeft,
clearWhenEmpty: false, shared: options && options.shared,
handleMouseEvents: options && options.handleMouseEvents};
pos = clipPos(this, pos);
return markText(this, pos, pos, realOpts, "bookmark");
},
findMarksAt: function(pos) {
pos = clipPos(this, pos);
var markers = [], spans = getLine(this, pos.line).markedSpans;
if (spans) for (var i = 0; i < spans.length; ++i) {
var span = spans[i];
if ((span.from == null || span.from <= pos.ch) &&
(span.to == null || span.to >= pos.ch))
markers.push(span.marker.parent || span.marker);
}
return markers;
},
findMarks: function(from, to, filter) {
from = clipPos(this, from); to = clipPos(this, to);
var found = [], lineNo = from.line;
this.iter(from.line, to.line + 1, function(line) {
var spans = line.markedSpans;
if (spans) for (var i = 0; i < spans.length; i++) {
var span = spans[i];
if (!(lineNo == from.line && from.ch > span.to ||
span.from == null && lineNo != from.line||
lineNo == to.line && span.from > to.ch) &&
(!filter || filter(span.marker)))
found.push(span.marker.parent || span.marker);
}
++lineNo;
});
return found;
},
getAllMarks: function() {
var markers = [];
this.iter(function(line) {
var sps = line.markedSpans;
if (sps) for (var i = 0; i < sps.length; ++i)
if (sps[i].from != null) markers.push(sps[i].marker);
});
return markers;
},
posFromIndex: function(off) {
var ch, lineNo = this.first;
this.iter(function(line) {
var sz = line.text.length + 1;
if (sz > off) { ch = off; return true; }
off -= sz;
++lineNo;
});
return clipPos(this, Pos(lineNo, ch));
},
indexFromPos: function (coords) {
coords = clipPos(this, coords);
var index = coords.ch;
if (coords.line < this.first || coords.ch < 0) return 0;
this.iter(this.first, coords.line, function (line) {
index += line.text.length + 1;
});
return index;
},
copy: function(copyHistory) {
var doc = new Doc(getLines(this, this.first, this.first + this.size),
this.modeOption, this.first, this.lineSep);
doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
doc.sel = this.sel;
doc.extend = false;
if (copyHistory) {
doc.history.undoDepth = this.history.undoDepth;
doc.setHistory(this.getHistory());
}
return doc;
},
linkedDoc: function(options) {
if (!options) options = {};
var from = this.first, to = this.first + this.size;
if (options.from != null && options.from > from) from = options.from;
if (options.to != null && options.to < to) to = options.to;
var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep);
if (options.sharedHist) copy.history = this.history;
(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
copySharedMarkers(copy, findSharedMarkers(this));
return copy;
},
unlinkDoc: function(other) {
if (other instanceof CodeMirror) other = other.doc;
if (this.linked) for (var i = 0; i < this.linked.length; ++i) {
var link = this.linked[i];
if (link.doc != other) continue;
this.linked.splice(i, 1);
other.unlinkDoc(this);
detachSharedMarkers(findSharedMarkers(this));
break;
}
// If the histories were shared, split them again
if (other.history == this.history) {
var splitIds = [other.id];
linkedDocs(other, function(doc) {splitIds.push(doc.id);}, true);
other.history = new History(null);
other.history.done = copyHistoryArray(this.history.done, splitIds);
other.history.undone = copyHistoryArray(this.history.undone, splitIds);
}
},
iterLinkedDocs: function(f) {linkedDocs(this, f);},
getMode: function() {return this.mode;},
getEditor: function() {return this.cm;},
splitLines: function(str) {
if (this.lineSep) return str.split(this.lineSep);
return splitLinesAuto(str);
},
lineSeparator: function() { return this.lineSep || "\n"; }
});
// Public alias.
Doc.prototype.eachLine = Doc.prototype.iter;
// Set up methods on CodeMirror's prototype to redirect to the editor's document.
var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
for (var prop in Doc.prototype) if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
CodeMirror.prototype[prop] = (function(method) {
return function() {return method.apply(this.doc, arguments);};
})(Doc.prototype[prop]);
eventMixin(Doc);
// Call f for all linked documents.
function linkedDocs(doc, f, sharedHistOnly) {
function propagate(doc, skip, sharedHist) {
if (doc.linked) for (var i = 0; i < doc.linked.length; ++i) {
var rel = doc.linked[i];
if (rel.doc == skip) continue;
var shared = sharedHist && rel.sharedHist;
if (sharedHistOnly && !shared) continue;
f(rel.doc, shared);
propagate(rel.doc, doc, shared);
}
}
propagate(doc, null, true);
}
// Attach a document to an editor.
function attachDoc(cm, doc) {
if (doc.cm) throw new Error("This document is already in use.");
cm.doc = doc;
doc.cm = cm;
estimateLineHeights(cm);
loadMode(cm);
if (!cm.options.lineWrapping) findMaxLine(cm);
cm.options.mode = doc.modeOption;
regChange(cm);
}
// LINE UTILITIES
// Find the line object corresponding to the given line number.
function getLine(doc, n) {
n -= doc.first;
if (n < 0 || n >= doc.size) throw new Error("There is no line " + (n + doc.first) + " in the document.");
for (var chunk = doc; !chunk.lines;) {
for (var i = 0;; ++i) {
var child = chunk.children[i], sz = child.chunkSize();
if (n < sz) { chunk = child; break; }
n -= sz;
}
}
return chunk.lines[n];
}
// Get the part of a document between two positions, as an array of
// strings.
function getBetween(doc, start, end) {
var out = [], n = start.line;
doc.iter(start.line, end.line + 1, function(line) {
var text = line.text;
if (n == end.line) text = text.slice(0, end.ch);
if (n == start.line) text = text.slice(start.ch);
out.push(text);
++n;
});
return out;
}
// Get the lines between from and to, as array of strings.
function getLines(doc, from, to) {
var out = [];
doc.iter(from, to, function(line) { out.push(line.text); });
return out;
}
// Update the height of a line, propagating the height change
// upwards to parent nodes.
function updateLineHeight(line, height) {
var diff = height - line.height;
if (diff) for (var n = line; n; n = n.parent) n.height += diff;
}
// Given a line object, find its line number by walking up through
// its parent links.
function lineNo(line) {
if (line.parent == null) return null;
var cur = line.parent, no = indexOf(cur.lines, line);
for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
for (var i = 0;; ++i) {
if (chunk.children[i] == cur) break;
no += chunk.children[i].chunkSize();
}
}
return no + cur.first;
}
// Find the line at the given vertical position, using the height
// information in the document tree.
function lineAtHeight(chunk, h) {
var n = chunk.first;
outer: do {
for (var i = 0; i < chunk.children.length; ++i) {
var child = chunk.children[i], ch = child.height;
if (h < ch) { chunk = child; continue outer; }
h -= ch;
n += child.chunkSize();
}
return n;
} while (!chunk.lines);
for (var i = 0; i < chunk.lines.length; ++i) {
var line = chunk.lines[i], lh = line.height;
if (h < lh) break;
h -= lh;
}
return n + i;
}
// Find the height above the given line.
function heightAtLine(lineObj) {
lineObj = visualLine(lineObj);
var h = 0, chunk = lineObj.parent;
for (var i = 0; i < chunk.lines.length; ++i) {
var line = chunk.lines[i];
if (line == lineObj) break;
else h += line.height;
}
for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
for (var i = 0; i < p.children.length; ++i) {
var cur = p.children[i];
if (cur == chunk) break;
else h += cur.height;
}
}
return h;
}
// Get the bidi ordering for the given line (and cache it). Returns
// false for lines that are fully left-to-right, and an array of
// BidiSpan objects otherwise.
function getOrder(line) {
var order = line.order;
if (order == null) order = line.order = bidiOrdering(line.text);
return order;
}
// HISTORY
function History(startGen) {
// Arrays of change events and selections. Doing something adds an
// event to done and clears undo. Undoing moves events from done
// to undone, redoing moves them in the other direction.
this.done = []; this.undone = [];
this.undoDepth = Infinity;
// Used to track when changes can be merged into a single undo
// event
this.lastModTime = this.lastSelTime = 0;
this.lastOp = this.lastSelOp = null;
this.lastOrigin = this.lastSelOrigin = null;
// Used by the isClean() method
this.generation = this.maxGeneration = startGen || 1;
}
// Create a history change event from an updateDoc-style change
// object.
function historyChangeFromChange(doc, change) {
var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
linkedDocs(doc, function(doc) {attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);}, true);
return histChange;
}
// Pop all selection events off the end of a history array. Stop at
// a change event.
function clearSelectionEvents(array) {
while (array.length) {
var last = lst(array);
if (last.ranges) array.pop();
else break;
}
}
// Find the top change event in the history. Pop off selection
// events that are in the way.
function lastChangeEvent(hist, force) {
if (force) {
clearSelectionEvents(hist.done);
return lst(hist.done);
} else if (hist.done.length && !lst(hist.done).ranges) {
return lst(hist.done);
} else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
hist.done.pop();
return lst(hist.done);
}
}
// Register a change in the history. Merges changes that are within
// a single operation, ore are close together with an origin that
// allows merging (starting with "+") into a single event.
function addChangeToHistory(doc, change, selAfter, opId) {
var hist = doc.history;
hist.undone.length = 0;
var time = +new Date, cur;
if ((hist.lastOp == opId ||
hist.lastOrigin == change.origin && change.origin &&
((change.origin.charAt(0) == "+" && doc.cm && hist.lastModTime > time - doc.cm.options.historyEventDelay) ||
change.origin.charAt(0) == "*")) &&
(cur = lastChangeEvent(hist, hist.lastOp == opId))) {
// Merge this change into the last event
var last = lst(cur.changes);
if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
// Optimized case for simple insertion -- don't want to add
// new changesets for every character typed
last.to = changeEnd(change);
} else {
// Add new sub-event
cur.changes.push(historyChangeFromChange(doc, change));
}
} else {
// Can not be merged, start a new event.
var before = lst(hist.done);
if (!before || !before.ranges)
pushSelectionToHistory(doc.sel, hist.done);
cur = {changes: [historyChangeFromChange(doc, change)],
generation: hist.generation};
hist.done.push(cur);
while (hist.done.length > hist.undoDepth) {
hist.done.shift();
if (!hist.done[0].ranges) hist.done.shift();
}
}
hist.done.push(selAfter);
hist.generation = ++hist.maxGeneration;
hist.lastModTime = hist.lastSelTime = time;
hist.lastOp = hist.lastSelOp = opId;
hist.lastOrigin = hist.lastSelOrigin = change.origin;
if (!last) signal(doc, "historyAdded");
}
function selectionEventCanBeMerged(doc, origin, prev, sel) {
var ch = origin.charAt(0);
return ch == "*" ||
ch == "+" &&
prev.ranges.length == sel.ranges.length &&
prev.somethingSelected() == sel.somethingSelected() &&
new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500);
}
// Called whenever the selection changes, sets the new selection as
// the pending selection in the history, and pushes the old pending
// selection into the 'done' array when it was significantly
// different (in number of selected ranges, emptiness, or time).
function addSelectionToHistory(doc, sel, opId, options) {
var hist = doc.history, origin = options && options.origin;
// A new event is started when the previous origin does not match
// the current, or the origins don't allow matching. Origins
// starting with * are always merged, those starting with + are
// merged when similar and close together in time.
if (opId == hist.lastSelOp ||
(origin && hist.lastSelOrigin == origin &&
(hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
hist.done[hist.done.length - 1] = sel;
else
pushSelectionToHistory(sel, hist.done);
hist.lastSelTime = +new Date;
hist.lastSelOrigin = origin;
hist.lastSelOp = opId;
if (options && options.clearRedo !== false)
clearSelectionEvents(hist.undone);
}
function pushSelectionToHistory(sel, dest) {
var top = lst(dest);
if (!(top && top.ranges && top.equals(sel)))
dest.push(sel);
}
// Used to store marked span information in the history.
function attachLocalSpans(doc, change, from, to) {
var existing = change["spans_" + doc.id], n = 0;
doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function(line) {
if (line.markedSpans)
(existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans;
++n;
});
}
// When un/re-doing restores text containing marked spans, those
// that have been explicitly cleared should not be restored.
function removeClearedSpans(spans) {
if (!spans) return null;
for (var i = 0, out; i < spans.length; ++i) {
if (spans[i].marker.explicitlyCleared) { if (!out) out = spans.slice(0, i); }
else if (out) out.push(spans[i]);
}
return !out ? spans : out.length ? out : null;
}
// Retrieve and filter the old marked spans stored in a change event.
function getOldSpans(doc, change) {
var found = change["spans_" + doc.id];
if (!found) return null;
for (var i = 0, nw = []; i < change.text.length; ++i)
nw.push(removeClearedSpans(found[i]));
return nw;
}
// Used both to provide a JSON-safe object in .getHistory, and, when
// detaching a document, to split the history in two
function copyHistoryArray(events, newGroup, instantiateSel) {
for (var i = 0, copy = []; i < events.length; ++i) {
var event = events[i];
if (event.ranges) {
copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
continue;
}
var changes = event.changes, newChanges = [];
copy.push({changes: newChanges});
for (var j = 0; j < changes.length; ++j) {
var change = changes[j], m;
newChanges.push({from: change.from, to: change.to, text: change.text});
if (newGroup) for (var prop in change) if (m = prop.match(/^spans_(\d+)$/)) {
if (indexOf(newGroup, Number(m[1])) > -1) {
lst(newChanges)[prop] = change[prop];
delete change[prop];
}
}
}
}
return copy;
}
// Rebasing/resetting history to deal with externally-sourced changes
function rebaseHistSelSingle(pos, from, to, diff) {
if (to < pos.line) {
pos.line += diff;
} else if (from < pos.line) {
pos.line = from;
pos.ch = 0;
}
}
// Tries to rebase an array of history events given a change in the
// document. If the change touches the same lines as the event, the
// event, and everything 'behind' it, is discarded. If the change is
// before the event, the event's positions are updated. Uses a
// copy-on-write scheme for the positions, to avoid having to
// reallocate them all on every rebase, but also avoid problems with
// shared position objects being unsafely updated.
function rebaseHistArray(array, from, to, diff) {
for (var i = 0; i < array.length; ++i) {
var sub = array[i], ok = true;
if (sub.ranges) {
if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
for (var j = 0; j < sub.ranges.length; j++) {
rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
}
continue;
}
for (var j = 0; j < sub.changes.length; ++j) {
var cur = sub.changes[j];
if (to < cur.from.line) {
cur.from = Pos(cur.from.line + diff, cur.from.ch);
cur.to = Pos(cur.to.line + diff, cur.to.ch);
} else if (from <= cur.to.line) {
ok = false;
break;
}
}
if (!ok) {
array.splice(0, i + 1);
i = 0;
}
}
}
function rebaseHist(hist, change) {
var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
rebaseHistArray(hist.done, from, to, diff);
rebaseHistArray(hist.undone, from, to, diff);
}
// EVENT UTILITIES
// Due to the fact that we still support jurassic IE versions, some
// compatibility wrappers are needed.
var e_preventDefault = CodeMirror.e_preventDefault = function(e) {
if (e.preventDefault) e.preventDefault();
else e.returnValue = false;
};
var e_stopPropagation = CodeMirror.e_stopPropagation = function(e) {
if (e.stopPropagation) e.stopPropagation();
else e.cancelBubble = true;
};
function e_defaultPrevented(e) {
return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false;
}
var e_stop = CodeMirror.e_stop = function(e) {e_preventDefault(e); e_stopPropagation(e);};
function e_target(e) {return e.target || e.srcElement;}
function e_button(e) {
var b = e.which;
if (b == null) {
if (e.button & 1) b = 1;
else if (e.button & 2) b = 3;
else if (e.button & 4) b = 2;
}
if (mac && e.ctrlKey && b == 1) b = 3;
return b;
}
// EVENT HANDLING
// Lightweight event framework. on/off also work on DOM nodes,
// registering native DOM handlers.
var on = CodeMirror.on = function(emitter, type, f) {
if (emitter.addEventListener)
emitter.addEventListener(type, f, false);
else if (emitter.attachEvent)
emitter.attachEvent("on" + type, f);
else {
var map = emitter._handlers || (emitter._handlers = {});
var arr = map[type] || (map[type] = []);
arr.push(f);
}
};
var noHandlers = []
function getHandlers(emitter, type, copy) {
var arr = emitter._handlers && emitter._handlers[type]
if (copy) return arr && arr.length > 0 ? arr.slice() : noHandlers
else return arr || noHandlers
}
var off = CodeMirror.off = function(emitter, type, f) {
if (emitter.removeEventListener)
emitter.removeEventListener(type, f, false);
else if (emitter.detachEvent)
emitter.detachEvent("on" + type, f);
else {
var handlers = getHandlers(emitter, type, false)
for (var i = 0; i < handlers.length; ++i)
if (handlers[i] == f) { handlers.splice(i, 1); break; }
}
};
var signal = CodeMirror.signal = function(emitter, type /*, values...*/) {
var handlers = getHandlers(emitter, type, true)
if (!handlers.length) return;
var args = Array.prototype.slice.call(arguments, 2);
for (var i = 0; i < handlers.length; ++i) handlers[i].apply(null, args);
};
var orphanDelayedCallbacks = null;
// Often, we want to signal events at a point where we are in the
// middle of some work, but don't want the handler to start calling
// other methods on the editor, which might be in an inconsistent
// state or simply not expect any other events to happen.
// signalLater looks whether there are any handlers, and schedules
// them to be executed when the last operation ends, or, if no
// operation is active, when a timeout fires.
function signalLater(emitter, type /*, values...*/) {
var arr = getHandlers(emitter, type, false)
if (!arr.length) return;
var args = Array.prototype.slice.call(arguments, 2), list;
if (operationGroup) {
list = operationGroup.delayedCallbacks;
} else if (orphanDelayedCallbacks) {
list = orphanDelayedCallbacks;
} else {
list = orphanDelayedCallbacks = [];
setTimeout(fireOrphanDelayed, 0);
}
function bnd(f) {return function(){f.apply(null, args);};};
for (var i = 0; i < arr.length; ++i)
list.push(bnd(arr[i]));
}
function fireOrphanDelayed() {
var delayed = orphanDelayedCallbacks;
orphanDelayedCallbacks = null;
for (var i = 0; i < delayed.length; ++i) delayed[i]();
}
// The DOM events that CodeMirror handles can be overridden by
// registering a (non-DOM) handler on the editor for the event name,
// and preventDefault-ing the event in that handler.
function signalDOMEvent(cm, e, override) {
if (typeof e == "string")
e = {type: e, preventDefault: function() { this.defaultPrevented = true; }};
signal(cm, override || e.type, cm, e);
return e_defaultPrevented(e) || e.codemirrorIgnore;
}
function signalCursorActivity(cm) {
var arr = cm._handlers && cm._handlers.cursorActivity;
if (!arr) return;
var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
for (var i = 0; i < arr.length; ++i) if (indexOf(set, arr[i]) == -1)
set.push(arr[i]);
}
function hasHandler(emitter, type) {
return getHandlers(emitter, type).length > 0
}
// Add on and off methods to a constructor's prototype, to make
// registering events on such objects more convenient.
function eventMixin(ctor) {
ctor.prototype.on = function(type, f) {on(this, type, f);};
ctor.prototype.off = function(type, f) {off(this, type, f);};
}
// MISC UTILITIES
// Number of pixels added to scroller and sizer to hide scrollbar
var scrollerGap = 30;
// Returned or thrown by various protocols to signal 'I'm not
// handling this'.
var Pass = CodeMirror.Pass = {toString: function(){return "CodeMirror.Pass";}};
// Reused option objects for setSelection & friends
var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
function Delayed() {this.id = null;}
Delayed.prototype.set = function(ms, f) {
clearTimeout(this.id);
this.id = setTimeout(f, ms);
};
// Counts the column offset in a string, taking tabs into account.
// Used mostly to find indentation.
var countColumn = CodeMirror.countColumn = function(string, end, tabSize, startIndex, startValue) {
if (end == null) {
end = string.search(/[^\s\u00a0]/);
if (end == -1) end = string.length;
}
for (var i = startIndex || 0, n = startValue || 0;;) {
var nextTab = string.indexOf("\t", i);
if (nextTab < 0 || nextTab >= end)
return n + (end - i);
n += nextTab - i;
n += tabSize - (n % tabSize);
i = nextTab + 1;
}
};
// The inverse of countColumn -- find the offset that corresponds to
// a particular column.
var findColumn = CodeMirror.findColumn = function(string, goal, tabSize) {
for (var pos = 0, col = 0;;) {
var nextTab = string.indexOf("\t", pos);
if (nextTab == -1) nextTab = string.length;
var skipped = nextTab - pos;
if (nextTab == string.length || col + skipped >= goal)
return pos + Math.min(skipped, goal - col);
col += nextTab - pos;
col += tabSize - (col % tabSize);
pos = nextTab + 1;
if (col >= goal) return pos;
}
}
var spaceStrs = [""];
function spaceStr(n) {
while (spaceStrs.length <= n)
spaceStrs.push(lst(spaceStrs) + " ");
return spaceStrs[n];
}
function lst(arr) { return arr[arr.length-1]; }
var selectInput = function(node) { node.select(); };
if (ios) // Mobile Safari apparently has a bug where select() is broken.
selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; };
else if (ie) // Suppress mysterious IE10 errors
selectInput = function(node) { try { node.select(); } catch(_e) {} };
function indexOf(array, elt) {
for (var i = 0; i < array.length; ++i)
if (array[i] == elt) return i;
return -1;
}
function map(array, f) {
var out = [];
for (var i = 0; i < array.length; i++) out[i] = f(array[i], i);
return out;
}
function nothing() {}
function createObj(base, props) {
var inst;
if (Object.create) {
inst = Object.create(base);
} else {
nothing.prototype = base;
inst = new nothing();
}
if (props) copyObj(props, inst);
return inst;
};
function copyObj(obj, target, overwrite) {
if (!target) target = {};
for (var prop in obj)
if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
target[prop] = obj[prop];
return target;
}
function bind(f) {
var args = Array.prototype.slice.call(arguments, 1);
return function(){return f.apply(null, args);};
}
var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
var isWordCharBasic = CodeMirror.isWordChar = function(ch) {
return /\w/.test(ch) || ch > "\x80" &&
(ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch));
};
function isWordChar(ch, helper) {
if (!helper) return isWordCharBasic(ch);
if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) return true;
return helper.test(ch);
}
function isEmpty(obj) {
for (var n in obj) if (obj.hasOwnProperty(n) && obj[n]) return false;
return true;
}
// Extending unicode characters. A series of a non-extending char +
// any number of extending chars is treated as a single unit as far
// as editing and measuring is concerned. This is not fully correct,
// since some scripts/fonts/browsers also treat other configurations
// of code points as a group.
var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch); }
// DOM UTILITIES
function elt(tag, content, className, style) {
var e = document.createElement(tag);
if (className) e.className = className;
if (style) e.style.cssText = style;
if (typeof content == "string") e.appendChild(document.createTextNode(content));
else if (content) for (var i = 0; i < content.length; ++i) e.appendChild(content[i]);
return e;
}
var range;
if (document.createRange) range = function(node, start, end, endNode) {
var r = document.createRange();
r.setEnd(endNode || node, end);
r.setStart(node, start);
return r;
};
else range = function(node, start, end) {
var r = document.body.createTextRange();
try { r.moveToElementText(node.parentNode); }
catch(e) { return r; }
r.collapse(true);
r.moveEnd("character", end);
r.moveStart("character", start);
return r;
};
function removeChildren(e) {
for (var count = e.childNodes.length; count > 0; --count)
e.removeChild(e.firstChild);
return e;
}
function removeChildrenAndAdd(parent, e) {
return removeChildren(parent).appendChild(e);
}
var contains = CodeMirror.contains = function(parent, child) {
if (child.nodeType == 3) // Android browser always returns false when child is a textnode
child = child.parentNode;
if (parent.contains)
return parent.contains(child);
do {
if (child.nodeType == 11) child = child.host;
if (child == parent) return true;
} while (child = child.parentNode);
};
function activeElt() {
var activeElement = document.activeElement;
while (activeElement && activeElement.root && activeElement.root.activeElement)
activeElement = activeElement.root.activeElement;
return activeElement;
}
// Older versions of IE throws unspecified error when touching
// document.activeElement in some cases (during loading, in iframe)
if (ie && ie_version < 11) activeElt = function() {
try { return document.activeElement; }
catch(e) { return document.body; }
};
function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*"); }
var rmClass = CodeMirror.rmClass = function(node, cls) {
var current = node.className;
var match = classTest(cls).exec(current);
if (match) {
var after = current.slice(match.index + match[0].length);
node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
}
};
var addClass = CodeMirror.addClass = function(node, cls) {
var current = node.className;
if (!classTest(cls).test(current)) node.className += (current ? " " : "") + cls;
};
function joinClasses(a, b) {
var as = a.split(" ");
for (var i = 0; i < as.length; i++)
if (as[i] && !classTest(as[i]).test(b)) b += " " + as[i];
return b;
}
// WINDOW-WIDE EVENTS
// These must be handled carefully, because naively registering a
// handler for each editor will cause the editors to never be
// garbage collected.
function forEachCodeMirror(f) {
if (!document.body.getElementsByClassName) return;
var byClass = document.body.getElementsByClassName("CodeMirror");
for (var i = 0; i < byClass.length; i++) {
var cm = byClass[i].CodeMirror;
if (cm) f(cm);
}
}
var globalsRegistered = false;
function ensureGlobalHandlers() {
if (globalsRegistered) return;
registerGlobalHandlers();
globalsRegistered = true;
}
function registerGlobalHandlers() {
// When the window resizes, we need to refresh active editors.
var resizeTimer;
on(window, "resize", function() {
if (resizeTimer == null) resizeTimer = setTimeout(function() {
resizeTimer = null;
forEachCodeMirror(onResize);
}, 100);
});
// When the window loses focus, we want to show the editor as blurred
on(window, "blur", function() {
forEachCodeMirror(onBlur);
});
}
// FEATURE DETECTION
// Detect drag-and-drop
var dragAndDrop = function() {
// There is *some* kind of drag-and-drop support in IE6-8, but I
// couldn't get it to work yet.
if (ie && ie_version < 9) return false;
var div = elt('div');
return "draggable" in div || "dragDrop" in div;
}();
var zwspSupported;
function zeroWidthElement(measure) {
if (zwspSupported == null) {
var test = elt("span", "\u200b");
removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
if (measure.firstChild.offsetHeight != 0)
zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8);
}
var node = zwspSupported ? elt("span", "\u200b") :
elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
node.setAttribute("cm-text", "");
return node;
}
// Feature-detect IE's crummy client rect reporting for bidi text
var badBidiRects;
function hasBadBidiRects(measure) {
if (badBidiRects != null) return badBidiRects;
var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
var r0 = range(txt, 0, 1).getBoundingClientRect();
if (!r0 || r0.left == r0.right) return false; // Safari returns null in some cases (#2780)
var r1 = range(txt, 1, 2).getBoundingClientRect();
return badBidiRects = (r1.right - r0.right < 3);
}
// See if "".split is the broken IE version, if so, provide an
// alternative way to split lines.
var splitLinesAuto = CodeMirror.splitLines = "\n\nb".split(/\n/).length != 3 ? function(string) {
var pos = 0, result = [], l = string.length;
while (pos <= l) {
var nl = string.indexOf("\n", pos);
if (nl == -1) nl = string.length;
var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
var rt = line.indexOf("\r");
if (rt != -1) {
result.push(line.slice(0, rt));
pos += rt + 1;
} else {
result.push(line);
pos = nl + 1;
}
}
return result;
} : function(string){return string.split(/\r\n?|\n/);};
var hasSelection = window.getSelection ? function(te) {
try { return te.selectionStart != te.selectionEnd; }
catch(e) { return false; }
} : function(te) {
try {var range = te.ownerDocument.selection.createRange();}
catch(e) {}
if (!range || range.parentElement() != te) return false;
return range.compareEndPoints("StartToEnd", range) != 0;
};
var hasCopyEvent = (function() {
var e = elt("div");
if ("oncopy" in e) return true;
e.setAttribute("oncopy", "return;");
return typeof e.oncopy == "function";
})();
var badZoomedRects = null;
function hasBadZoomedRects(measure) {
if (badZoomedRects != null) return badZoomedRects;
var node = removeChildrenAndAdd(measure, elt("span", "x"));
var normal = node.getBoundingClientRect();
var fromRange = range(node, 0, 1).getBoundingClientRect();
return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1;
}
// KEY NAMES
var keyNames = CodeMirror.keyNames = {
3: "Enter", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete",
173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
};
(function() {
// Number keys
for (var i = 0; i < 10; i++) keyNames[i + 48] = keyNames[i + 96] = String(i);
// Alphabetic keys
for (var i = 65; i <= 90; i++) keyNames[i] = String.fromCharCode(i);
// Function keys
for (var i = 1; i <= 12; i++) keyNames[i + 111] = keyNames[i + 63235] = "F" + i;
})();
// BIDI HELPERS
function iterateBidiSections(order, from, to, f) {
if (!order) return f(from, to, "ltr");
var found = false;
for (var i = 0; i < order.length; ++i) {
var part = order[i];
if (part.from < to && part.to > from || from == to && part.to == from) {
f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr");
found = true;
}
}
if (!found) f(from, to, "ltr");
}
function bidiLeft(part) { return part.level % 2 ? part.to : part.from; }
function bidiRight(part) { return part.level % 2 ? part.from : part.to; }
function lineLeft(line) { var order = getOrder(line); return order ? bidiLeft(order[0]) : 0; }
function lineRight(line) {
var order = getOrder(line);
if (!order) return line.text.length;
return bidiRight(lst(order));
}
function lineStart(cm, lineN) {
var line = getLine(cm.doc, lineN);
var visual = visualLine(line);
if (visual != line) lineN = lineNo(visual);
var order = getOrder(visual);
var ch = !order ? 0 : order[0].level % 2 ? lineRight(visual) : lineLeft(visual);
return Pos(lineN, ch);
}
function lineEnd(cm, lineN) {
var merged, line = getLine(cm.doc, lineN);
while (merged = collapsedSpanAtEnd(line)) {
line = merged.find(1, true).line;
lineN = null;
}
var order = getOrder(line);
var ch = !order ? line.text.length : order[0].level % 2 ? lineLeft(line) : lineRight(line);
return Pos(lineN == null ? lineNo(line) : lineN, ch);
}
function lineStartSmart(cm, pos) {
var start = lineStart(cm, pos.line);
var line = getLine(cm.doc, start.line);
var order = getOrder(line);
if (!order || order[0].level == 0) {
var firstNonWS = Math.max(0, line.text.search(/\S/));
var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
return Pos(start.line, inWS ? 0 : firstNonWS);
}
return start;
}
function compareBidiLevel(order, a, b) {
var linedir = order[0].level;
if (a == linedir) return true;
if (b == linedir) return false;
return a < b;
}
var bidiOther;
function getBidiPartAt(order, pos) {
bidiOther = null;
for (var i = 0, found; i < order.length; ++i) {
var cur = order[i];
if (cur.from < pos && cur.to > pos) return i;
if ((cur.from == pos || cur.to == pos)) {
if (found == null) {
found = i;
} else if (compareBidiLevel(order, cur.level, order[found].level)) {
if (cur.from != cur.to) bidiOther = found;
return i;
} else {
if (cur.from != cur.to) bidiOther = i;
return found;
}
}
}
return found;
}
function moveInLine(line, pos, dir, byUnit) {
if (!byUnit) return pos + dir;
do pos += dir;
while (pos > 0 && isExtendingChar(line.text.charAt(pos)));
return pos;
}
// This is needed in order to move 'visually' through bi-directional
// text -- i.e., pressing left should make the cursor go left, even
// when in RTL text. The tricky part is the 'jumps', where RTL and
// LTR text touch each other. This often requires the cursor offset
// to move more than one unit, in order to visually move one unit.
function moveVisually(line, start, dir, byUnit) {
var bidi = getOrder(line);
if (!bidi) return moveLogically(line, start, dir, byUnit);
var pos = getBidiPartAt(bidi, start), part = bidi[pos];
var target = moveInLine(line, start, part.level % 2 ? -dir : dir, byUnit);
for (;;) {
if (target > part.from && target < part.to) return target;
if (target == part.from || target == part.to) {
if (getBidiPartAt(bidi, target) == pos) return target;
part = bidi[pos += dir];
return (dir > 0) == part.level % 2 ? part.to : part.from;
} else {
part = bidi[pos += dir];
if (!part) return null;
if ((dir > 0) == part.level % 2)
target = moveInLine(line, part.to, -1, byUnit);
else
target = moveInLine(line, part.from, 1, byUnit);
}
}
}
function moveLogically(line, start, dir, byUnit) {
var target = start + dir;
if (byUnit) while (target > 0 && isExtendingChar(line.text.charAt(target))) target += dir;
return target < 0 || target > line.text.length ? null : target;
}
// Bidirectional ordering algorithm
// See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
// that this (partially) implements.
// One-char codes used for character types:
// L (L): Left-to-Right
// R (R): Right-to-Left
// r (AL): Right-to-Left Arabic
// 1 (EN): European Number
// + (ES): European Number Separator
// % (ET): European Number Terminator
// n (AN): Arabic Number
// , (CS): Common Number Separator
// m (NSM): Non-Spacing Mark
// b (BN): Boundary Neutral
// s (B): Paragraph Separator
// t (S): Segment Separator
// w (WS): Whitespace
// N (ON): Other Neutrals
// Returns null if characters are ordered as they appear
// (left-to-right), or an array of sections ({from, to, level}
// objects) in the order in which they occur visually.
var bidiOrdering = (function() {
// Character types for codepoints 0 to 0xff
var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
// Character types for codepoints 0x600 to 0x6ff
var arabicTypes = "rrrrrrrrrrrr,rNNmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmrrrrrrrnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmNmmmm";
function charType(code) {
if (code <= 0xf7) return lowTypes.charAt(code);
else if (0x590 <= code && code <= 0x5f4) return "R";
else if (0x600 <= code && code <= 0x6ed) return arabicTypes.charAt(code - 0x600);
else if (0x6ee <= code && code <= 0x8ac) return "r";
else if (0x2000 <= code && code <= 0x200b) return "w";
else if (code == 0x200c) return "b";
else return "L";
}
var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
// Browsers seem to always treat the boundaries of block elements as being L.
var outerType = "L";
function BidiSpan(level, from, to) {
this.level = level;
this.from = from; this.to = to;
}
return function(str) {
if (!bidiRE.test(str)) return false;
var len = str.length, types = [];
for (var i = 0, type; i < len; ++i)
types.push(type = charType(str.charCodeAt(i)));
// W1. Examine each non-spacing mark (NSM) in the level run, and
// change the type of the NSM to the type of the previous
// character. If the NSM is at the start of the level run, it will
// get the type of sor.
for (var i = 0, prev = outerType; i < len; ++i) {
var type = types[i];
if (type == "m") types[i] = prev;
else prev = type;
}
// W2. Search backwards from each instance of a European number
// until the first strong type (R, L, AL, or sor) is found. If an
// AL is found, change the type of the European number to Arabic
// number.
// W3. Change all ALs to R.
for (var i = 0, cur = outerType; i < len; ++i) {
var type = types[i];
if (type == "1" && cur == "r") types[i] = "n";
else if (isStrong.test(type)) { cur = type; if (type == "r") types[i] = "R"; }
}
// W4. A single European separator between two European numbers
// changes to a European number. A single common separator between
// two numbers of the same type changes to that type.
for (var i = 1, prev = types[0]; i < len - 1; ++i) {
var type = types[i];
if (type == "+" && prev == "1" && types[i+1] == "1") types[i] = "1";
else if (type == "," && prev == types[i+1] &&
(prev == "1" || prev == "n")) types[i] = prev;
prev = type;
}
// W5. A sequence of European terminators adjacent to European
// numbers changes to all European numbers.
// W6. Otherwise, separators and terminators change to Other
// Neutral.
for (var i = 0; i < len; ++i) {
var type = types[i];
if (type == ",") types[i] = "N";
else if (type == "%") {
for (var end = i + 1; end < len && types[end] == "%"; ++end) {}
var replace = (i && types[i-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
for (var j = i; j < end; ++j) types[j] = replace;
i = end - 1;
}
}
// W7. Search backwards from each instance of a European number
// until the first strong type (R, L, or sor) is found. If an L is
// found, then change the type of the European number to L.
for (var i = 0, cur = outerType; i < len; ++i) {
var type = types[i];
if (cur == "L" && type == "1") types[i] = "L";
else if (isStrong.test(type)) cur = type;
}
// N1. A sequence of neutrals takes the direction of the
// surrounding strong text if the text on both sides has the same
// direction. European and Arabic numbers act as if they were R in
// terms of their influence on neutrals. Start-of-level-run (sor)
// and end-of-level-run (eor) are used at level run boundaries.
// N2. Any remaining neutrals take the embedding direction.
for (var i = 0; i < len; ++i) {
if (isNeutral.test(types[i])) {
for (var end = i + 1; end < len && isNeutral.test(types[end]); ++end) {}
var before = (i ? types[i-1] : outerType) == "L";
var after = (end < len ? types[end] : outerType) == "L";
var replace = before || after ? "L" : "R";
for (var j = i; j < end; ++j) types[j] = replace;
i = end - 1;
}
}
// Here we depart from the documented algorithm, in order to avoid
// building up an actual levels array. Since there are only three
// levels (0, 1, 2) in an implementation that doesn't take
// explicit embedding into account, we can build up the order on
// the fly, without following the level-based algorithm.
var order = [], m;
for (var i = 0; i < len;) {
if (countsAsLeft.test(types[i])) {
var start = i;
for (++i; i < len && countsAsLeft.test(types[i]); ++i) {}
order.push(new BidiSpan(0, start, i));
} else {
var pos = i, at = order.length;
for (++i; i < len && types[i] != "L"; ++i) {}
for (var j = pos; j < i;) {
if (countsAsNum.test(types[j])) {
if (pos < j) order.splice(at, 0, new BidiSpan(1, pos, j));
var nstart = j;
for (++j; j < i && countsAsNum.test(types[j]); ++j) {}
order.splice(at, 0, new BidiSpan(2, nstart, j));
pos = j;
} else ++j;
}
if (pos < i) order.splice(at, 0, new BidiSpan(1, pos, i));
}
}
if (order[0].level == 1 && (m = str.match(/^\s+/))) {
order[0].from = m[0].length;
order.unshift(new BidiSpan(0, 0, m[0].length));
}
if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
lst(order).to -= m[0].length;
order.push(new BidiSpan(0, len - m[0].length, len));
}
if (order[0].level == 2)
order.unshift(new BidiSpan(1, order[0].to, order[0].to));
if (order[0].level != lst(order).level)
order.push(new BidiSpan(order[0].level, len, len));
return order;
};
})();
// THE END
CodeMirror.version = "5.9.1";
return CodeMirror;
});
},{}],7:[function(require,module,exports){
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../markdown/markdown"), require("../../addon/mode/overlay"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../markdown/markdown", "../../addon/mode/overlay"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
var urlRE = /^((?:(?:aaas?|about|acap|adiumxtra|af[ps]|aim|apt|attachment|aw|beshare|bitcoin|bolo|callto|cap|chrome(?:-extension)?|cid|coap|com-eventbrite-attendee|content|crid|cvs|data|dav|dict|dlna-(?:playcontainer|playsingle)|dns|doi|dtn|dvb|ed2k|facetime|feed|file|finger|fish|ftp|geo|gg|git|gizmoproject|go|gopher|gtalk|h323|hcp|https?|iax|icap|icon|im|imap|info|ipn|ipp|irc[6s]?|iris(?:\.beep|\.lwz|\.xpc|\.xpcs)?|itms|jar|javascript|jms|keyparc|lastfm|ldaps?|magnet|mailto|maps|market|message|mid|mms|ms-help|msnim|msrps?|mtqp|mumble|mupdate|mvn|news|nfs|nih?|nntp|notes|oid|opaquelocktoken|palm|paparazzi|platform|pop|pres|proxy|psyc|query|res(?:ource)?|rmi|rsync|rtmp|rtsp|secondlife|service|session|sftp|sgn|shttp|sieve|sips?|skype|sm[bs]|snmp|soap\.beeps?|soldat|spotify|ssh|steam|svn|tag|teamspeak|tel(?:net)?|tftp|things|thismessage|tip|tn3270|tv|udp|unreal|urn|ut2004|vemmi|ventrilo|view-source|webcal|wss?|wtai|wyciwyg|xcon(?:-userid)?|xfire|xmlrpc\.beeps?|xmpp|xri|ymsgr|z39\.50[rs]?):(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]|\([^\s()<>]*\))+(?:\([^\s()<>]*\)|[^\s`*!()\[\]{};:'".,<>?«»“”‘’]))/i
CodeMirror.defineMode("gfm", function(config, modeConfig) {
var codeDepth = 0;
function blankLine(state) {
state.code = false;
return null;
}
var gfmOverlay = {
startState: function() {
return {
code: false,
codeBlock: false,
ateSpace: false
};
},
copyState: function(s) {
return {
code: s.code,
codeBlock: s.codeBlock,
ateSpace: s.ateSpace
};
},
token: function(stream, state) {
state.combineTokens = null;
// Hack to prevent formatting override inside code blocks (block and inline)
if (state.codeBlock) {
if (stream.match(/^```+/)) {
state.codeBlock = false;
return null;
}
stream.skipToEnd();
return null;
}
if (stream.sol()) {
state.code = false;
}
if (stream.sol() && stream.match(/^```+/)) {
stream.skipToEnd();
state.codeBlock = true;
return null;
}
// If this block is changed, it may need to be updated in Markdown mode
if (stream.peek() === '`') {
stream.next();
var before = stream.pos;
stream.eatWhile('`');
var difference = 1 + stream.pos - before;
if (!state.code) {
codeDepth = difference;
state.code = true;
} else {
if (difference === codeDepth) { // Must be exact
state.code = false;
}
}
return null;
} else if (state.code) {
stream.next();
return null;
}
// Check if space. If so, links can be formatted later on
if (stream.eatSpace()) {
state.ateSpace = true;
return null;
}
if (stream.sol() || state.ateSpace) {
state.ateSpace = false;
if (modeConfig.gitHubSpice !== false) {
if(stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+@)?(?:[a-f0-9]{7,40}\b)/)) {
// User/Project@SHA
// User@SHA
// SHA
state.combineTokens = true;
return "link";
} else if (stream.match(/^(?:[a-zA-Z0-9\-_]+\/)?(?:[a-zA-Z0-9\-_]+)?#[0-9]+\b/)) {
// User/Project#Num
// User#Num
// #Num
state.combineTokens = true;
return "link";
}
}
}
if (stream.match(urlRE) &&
stream.string.slice(stream.start - 2, stream.start) != "](" &&
(stream.start == 0 || /\W/.test(stream.string.charAt(stream.start - 1)))) {
// URLs
// Taken from http://daringfireball.net/2010/07/improved_regex_for_matching_urls
// And then (issue #1160) simplified to make it not crash the Chrome Regexp engine
// And then limited url schemes to the CommonMark list, so foo:bar isn't matched as a URL
state.combineTokens = true;
return "link";
}
stream.next();
return null;
},
blankLine: blankLine
};
var markdownConfig = {
underscoresBreakWords: false,
taskLists: true,
fencedCodeBlocks: '```',
strikethrough: true
};
for (var attr in modeConfig) {
markdownConfig[attr] = modeConfig[attr];
}
markdownConfig.name = "markdown";
return CodeMirror.overlayMode(CodeMirror.getMode(config, markdownConfig), gfmOverlay);
}, "markdown");
CodeMirror.defineMIME("text/x-gfm", "gfm");
});
},{"../../addon/mode/overlay":5,"../../lib/codemirror":6,"../markdown/markdown":8}],8:[function(require,module,exports){
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../xml/xml"), require("../meta"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../xml/xml", "../meta"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("markdown", function(cmCfg, modeCfg) {
var htmlFound = CodeMirror.modes.hasOwnProperty("xml");
var htmlMode = CodeMirror.getMode(cmCfg, htmlFound ? {name: "xml", htmlMode: true} : "text/plain");
function getMode(name) {
if (CodeMirror.findModeByName) {
var found = CodeMirror.findModeByName(name);
if (found) name = found.mime || found.mimes[0];
}
var mode = CodeMirror.getMode(cmCfg, name);
return mode.name == "null" ? null : mode;
}
// Should characters that affect highlighting be highlighted separate?
// Does not include characters that will be output (such as `1.` and `-` for lists)
if (modeCfg.highlightFormatting === undefined)
modeCfg.highlightFormatting = false;
// Maximum number of nested blockquotes. Set to 0 for infinite nesting.
// Excess `>` will emit `error` token.
if (modeCfg.maxBlockquoteDepth === undefined)
modeCfg.maxBlockquoteDepth = 0;
// Should underscores in words open/close em/strong?
if (modeCfg.underscoresBreakWords === undefined)
modeCfg.underscoresBreakWords = true;
// Use `fencedCodeBlocks` to configure fenced code blocks. false to
// disable, string to specify a precise regexp that the fence should
// match, and true to allow three or more backticks or tildes (as
// per CommonMark).
// Turn on task lists? ("- [ ] " and "- [x] ")
if (modeCfg.taskLists === undefined) modeCfg.taskLists = false;
// Turn on strikethrough syntax
if (modeCfg.strikethrough === undefined)
modeCfg.strikethrough = false;
// Allow token types to be overridden by user-provided token types.
if (modeCfg.tokenTypeOverrides === undefined)
modeCfg.tokenTypeOverrides = {};
var codeDepth = 0;
var tokenTypes = {
header: "header",
code: "comment",
quote: "quote",
list1: "variable-2",
list2: "variable-3",
list3: "keyword",
hr: "hr",
image: "tag",
formatting: "formatting",
linkInline: "link",
linkEmail: "link",
linkText: "link",
linkHref: "string",
em: "em",
strong: "strong",
strikethrough: "strikethrough"
};
for (var tokenType in tokenTypes) {
if (tokenTypes.hasOwnProperty(tokenType) && modeCfg.tokenTypeOverrides[tokenType]) {
tokenTypes[tokenType] = modeCfg.tokenTypeOverrides[tokenType];
}
}
var hrRE = /^([*\-_])(?:\s*\1){2,}\s*$/
, ulRE = /^[*\-+]\s+/
, olRE = /^[0-9]+([.)])\s+/
, taskListRE = /^\[(x| )\](?=\s)/ // Must follow ulRE or olRE
, atxHeaderRE = modeCfg.allowAtxHeaderWithoutSpace ? /^(#+)/ : /^(#+)(?: |$)/
, setextHeaderRE = /^ *(?:\={1,}|-{1,})\s*$/
, textRE = /^[^#!\[\]*_\\<>` "'(~]+/
, fencedCodeRE = new RegExp("^(" + (modeCfg.fencedCodeBlocks === true ? "~~~+|```+" : modeCfg.fencedCodeBlocks) +
")[ \\t]*([\\w+#]*)");
function switchInline(stream, state, f) {
state.f = state.inline = f;
return f(stream, state);
}
function switchBlock(stream, state, f) {
state.f = state.block = f;
return f(stream, state);
}
function lineIsEmpty(line) {
return !line || !/\S/.test(line.string)
}
// Blocks
function blankLine(state) {
// Reset linkTitle state
state.linkTitle = false;
// Reset EM state
state.em = false;
// Reset STRONG state
state.strong = false;
// Reset strikethrough state
state.strikethrough = false;
// Reset state.quote
state.quote = 0;
// Reset state.indentedCode
state.indentedCode = false;
if (!htmlFound && state.f == htmlBlock) {
state.f = inlineNormal;
state.block = blockNormal;
}
// Reset state.trailingSpace
state.trailingSpace = 0;
state.trailingSpaceNewLine = false;
// Mark this line as blank
state.prevLine = state.thisLine
state.thisLine = null
return null;
}
function blockNormal(stream, state) {
var sol = stream.sol();
var prevLineIsList = state.list !== false,
prevLineIsIndentedCode = state.indentedCode;
state.indentedCode = false;
if (prevLineIsList) {
if (state.indentationDiff >= 0) { // Continued list
if (state.indentationDiff < 4) { // Only adjust indentation if *not* a code block
state.indentation -= state.indentationDiff;
}
state.list = null;
} else if (state.indentation > 0) {
state.list = null;
state.listDepth = Math.floor(state.indentation / 4);
} else { // No longer a list
state.list = false;
state.listDepth = 0;
}
}
var match = null;
if (state.indentationDiff >= 4) {
stream.skipToEnd();
if (prevLineIsIndentedCode || lineIsEmpty(state.prevLine)) {
state.indentation -= 4;
state.indentedCode = true;
return tokenTypes.code;
} else {
return null;
}
} else if (stream.eatSpace()) {
return null;
} else if ((match = stream.match(atxHeaderRE)) && match[1].length <= 6) {
state.header = match[1].length;
if (modeCfg.highlightFormatting) state.formatting = "header";
state.f = state.inline;
return getType(state);
} else if (!lineIsEmpty(state.prevLine) && !state.quote && !prevLineIsList &&
!prevLineIsIndentedCode && (match = stream.match(setextHeaderRE))) {
state.header = match[0].charAt(0) == '=' ? 1 : 2;
if (modeCfg.highlightFormatting) state.formatting = "header";
state.f = state.inline;
return getType(state);
} else if (stream.eat('>')) {
state.quote = sol ? 1 : state.quote + 1;
if (modeCfg.highlightFormatting) state.formatting = "quote";
stream.eatSpace();
return getType(state);
} else if (stream.peek() === '[') {
return switchInline(stream, state, footnoteLink);
} else if (stream.match(hrRE, true)) {
state.hr = true;
return tokenTypes.hr;
} else if ((lineIsEmpty(state.prevLine) || prevLineIsList) && (stream.match(ulRE, false) || stream.match(olRE, false))) {
var listType = null;
if (stream.match(ulRE, true)) {
listType = 'ul';
} else {
stream.match(olRE, true);
listType = 'ol';
}
state.indentation = stream.column() + stream.current().length;
state.list = true;
state.listDepth++;
if (modeCfg.taskLists && stream.match(taskListRE, false)) {
state.taskList = true;
}
state.f = state.inline;
if (modeCfg.highlightFormatting) state.formatting = ["list", "list-" + listType];
return getType(state);
} else if (modeCfg.fencedCodeBlocks && (match = stream.match(fencedCodeRE, true))) {
state.fencedChars = match[1]
// try switching mode
state.localMode = getMode(match[2]);
if (state.localMode) state.localState = state.localMode.startState();
state.f = state.block = local;
if (modeCfg.highlightFormatting) state.formatting = "code-block";
state.code = true;
return getType(state);
}
return switchInline(stream, state, state.inline);
}
function htmlBlock(stream, state) {
var style = htmlMode.token(stream, state.htmlState);
if ((htmlFound && state.htmlState.tagStart === null &&
(!state.htmlState.context && state.htmlState.tokenize.isInText)) ||
(state.md_inside && stream.current().indexOf(">") > -1)) {
state.f = inlineNormal;
state.block = blockNormal;
state.htmlState = null;
}
return style;
}
function local(stream, state) {
if (stream.sol() && state.fencedChars && stream.match(state.fencedChars, false)) {
state.localMode = state.localState = null;
state.f = state.block = leavingLocal;
return null;
} else if (state.localMode) {
return state.localMode.token(stream, state.localState);
} else {
stream.skipToEnd();
return tokenTypes.code;
}
}
function leavingLocal(stream, state) {
stream.match(state.fencedChars);
state.block = blockNormal;
state.f = inlineNormal;
state.fencedChars = null;
if (modeCfg.highlightFormatting) state.formatting = "code-block";
state.code = true;
var returnType = getType(state);
state.code = false;
return returnType;
}
// Inline
function getType(state) {
var styles = [];
if (state.formatting) {
styles.push(tokenTypes.formatting);
if (typeof state.formatting === "string") state.formatting = [state.formatting];
for (var i = 0; i < state.formatting.length; i++) {
styles.push(tokenTypes.formatting + "-" + state.formatting[i]);
if (state.formatting[i] === "header") {
styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.header);
}
// Add `formatting-quote` and `formatting-quote-#` for blockquotes
// Add `error` instead if the maximum blockquote nesting depth is passed
if (state.formatting[i] === "quote") {
if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
styles.push(tokenTypes.formatting + "-" + state.formatting[i] + "-" + state.quote);
} else {
styles.push("error");
}
}
}
}
if (state.taskOpen) {
styles.push("meta");
return styles.length ? styles.join(' ') : null;
}
if (state.taskClosed) {
styles.push("property");
return styles.length ? styles.join(' ') : null;
}
if (state.linkHref) {
styles.push(tokenTypes.linkHref, "url");
} else { // Only apply inline styles to non-url text
if (state.strong) { styles.push(tokenTypes.strong); }
if (state.em) { styles.push(tokenTypes.em); }
if (state.strikethrough) { styles.push(tokenTypes.strikethrough); }
if (state.linkText) { styles.push(tokenTypes.linkText); }
if (state.code) { styles.push(tokenTypes.code); }
}
if (state.header) { styles.push(tokenTypes.header, tokenTypes.header + "-" + state.header); }
if (state.quote) {
styles.push(tokenTypes.quote);
// Add `quote-#` where the maximum for `#` is modeCfg.maxBlockquoteDepth
if (!modeCfg.maxBlockquoteDepth || modeCfg.maxBlockquoteDepth >= state.quote) {
styles.push(tokenTypes.quote + "-" + state.quote);
} else {
styles.push(tokenTypes.quote + "-" + modeCfg.maxBlockquoteDepth);
}
}
if (state.list !== false) {
var listMod = (state.listDepth - 1) % 3;
if (!listMod) {
styles.push(tokenTypes.list1);
} else if (listMod === 1) {
styles.push(tokenTypes.list2);
} else {
styles.push(tokenTypes.list3);
}
}
if (state.trailingSpaceNewLine) {
styles.push("trailing-space-new-line");
} else if (state.trailingSpace) {
styles.push("trailing-space-" + (state.trailingSpace % 2 ? "a" : "b"));
}
return styles.length ? styles.join(' ') : null;
}
function handleText(stream, state) {
if (stream.match(textRE, true)) {
return getType(state);
}
return undefined;
}
function inlineNormal(stream, state) {
var style = state.text(stream, state);
if (typeof style !== 'undefined')
return style;
if (state.list) { // List marker (*, +, -, 1., etc)
state.list = null;
return getType(state);
}
if (state.taskList) {
var taskOpen = stream.match(taskListRE, true)[1] !== "x";
if (taskOpen) state.taskOpen = true;
else state.taskClosed = true;
if (modeCfg.highlightFormatting) state.formatting = "task";
state.taskList = false;
return getType(state);
}
state.taskOpen = false;
state.taskClosed = false;
if (state.header && stream.match(/^#+$/, true)) {
if (modeCfg.highlightFormatting) state.formatting = "header";
return getType(state);
}
// Get sol() value now, before character is consumed
var sol = stream.sol();
var ch = stream.next();
if (ch === '\\') {
stream.next();
if (modeCfg.highlightFormatting) {
var type = getType(state);
var formattingEscape = tokenTypes.formatting + "-escape";
return type ? type + " " + formattingEscape : formattingEscape;
}
}
// Matches link titles present on next line
if (state.linkTitle) {
state.linkTitle = false;
var matchCh = ch;
if (ch === '(') {
matchCh = ')';
}
matchCh = (matchCh+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
var regex = '^\\s*(?:[^' + matchCh + '\\\\]+|\\\\\\\\|\\\\.)' + matchCh;
if (stream.match(new RegExp(regex), true)) {
return tokenTypes.linkHref;
}
}
// If this block is changed, it may need to be updated in GFM mode
if (ch === '`') {
var previousFormatting = state.formatting;
if (modeCfg.highlightFormatting) state.formatting = "code";
var t = getType(state);
var before = stream.pos;
stream.eatWhile('`');
var difference = 1 + stream.pos - before;
if (!state.code) {
codeDepth = difference;
state.code = true;
return getType(state);
} else {
if (difference === codeDepth) { // Must be exact
state.code = false;
return t;
}
state.formatting = previousFormatting;
return getType(state);
}
} else if (state.code) {
return getType(state);
}
if (ch === '!' && stream.match(/\[[^\]]*\] ?(?:\(|\[)/, false)) {
stream.match(/\[[^\]]*\]/);
state.inline = state.f = linkHref;
return tokenTypes.image;
}
if (ch === '[' && stream.match(/.*\](\(.*\)| ?\[.*\])/, false)) {
state.linkText = true;
if (modeCfg.highlightFormatting) state.formatting = "link";
return getType(state);
}
if (ch === ']' && state.linkText && stream.match(/\(.*\)| ?\[.*\]/, false)) {
if (modeCfg.highlightFormatting) state.formatting = "link";
var type = getType(state);
state.linkText = false;
state.inline = state.f = linkHref;
return type;
}
if (ch === '<' && stream.match(/^(https?|ftps?):\/\/(?:[^\\>]|\\.)+>/, false)) {
state.f = state.inline = linkInline;
if (modeCfg.highlightFormatting) state.formatting = "link";
var type = getType(state);
if (type){
type += " ";
} else {
type = "";
}
return type + tokenTypes.linkInline;
}
if (ch === '<' && stream.match(/^[^> \\]+@(?:[^\\>]|\\.)+>/, false)) {
state.f = state.inline = linkInline;
if (modeCfg.highlightFormatting) state.formatting = "link";
var type = getType(state);
if (type){
type += " ";
} else {
type = "";
}
return type + tokenTypes.linkEmail;
}
if (ch === '<' && stream.match(/^(!--|\w)/, false)) {
var end = stream.string.indexOf(">", stream.pos);
if (end != -1) {
var atts = stream.string.substring(stream.start, end);
if (/markdown\s*=\s*('|"){0,1}1('|"){0,1}/.test(atts)) state.md_inside = true;
}
stream.backUp(1);
state.htmlState = CodeMirror.startState(htmlMode);
return switchBlock(stream, state, htmlBlock);
}
if (ch === '<' && stream.match(/^\/\w*?>/)) {
state.md_inside = false;
return "tag";
}
var ignoreUnderscore = false;
if (!modeCfg.underscoresBreakWords) {
if (ch === '_' && stream.peek() !== '_' && stream.match(/(\w)/, false)) {
var prevPos = stream.pos - 2;
if (prevPos >= 0) {
var prevCh = stream.string.charAt(prevPos);
if (prevCh !== '_' && prevCh.match(/(\w)/, false)) {
ignoreUnderscore = true;
}
}
}
}
if (ch === '*' || (ch === '_' && !ignoreUnderscore)) {
if (sol && stream.peek() === ' ') {
// Do nothing, surrounded by newline and space
} else if (state.strong === ch && stream.eat(ch)) { // Remove STRONG
if (modeCfg.highlightFormatting) state.formatting = "strong";
var t = getType(state);
state.strong = false;
return t;
} else if (!state.strong && stream.eat(ch)) { // Add STRONG
state.strong = ch;
if (modeCfg.highlightFormatting) state.formatting = "strong";
return getType(state);
} else if (state.em === ch) { // Remove EM
if (modeCfg.highlightFormatting) state.formatting = "em";
var t = getType(state);
state.em = false;
return t;
} else if (!state.em) { // Add EM
state.em = ch;
if (modeCfg.highlightFormatting) state.formatting = "em";
return getType(state);
}
} else if (ch === ' ') {
if (stream.eat('*') || stream.eat('_')) { // Probably surrounded by spaces
if (stream.peek() === ' ') { // Surrounded by spaces, ignore
return getType(state);
} else { // Not surrounded by spaces, back up pointer
stream.backUp(1);
}
}
}
if (modeCfg.strikethrough) {
if (ch === '~' && stream.eatWhile(ch)) {
if (state.strikethrough) {// Remove strikethrough
if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
var t = getType(state);
state.strikethrough = false;
return t;
} else if (stream.match(/^[^\s]/, false)) {// Add strikethrough
state.strikethrough = true;
if (modeCfg.highlightFormatting) state.formatting = "strikethrough";
return getType(state);
}
} else if (ch === ' ') {
if (stream.match(/^~~/, true)) { // Probably surrounded by space
if (stream.peek() === ' ') { // Surrounded by spaces, ignore
return getType(state);
} else { // Not surrounded by spaces, back up pointer
stream.backUp(2);
}
}
}
}
if (ch === ' ') {
if (stream.match(/ +$/, false)) {
state.trailingSpace++;
} else if (state.trailingSpace) {
state.trailingSpaceNewLine = true;
}
}
return getType(state);
}
function linkInline(stream, state) {
var ch = stream.next();
if (ch === ">") {
state.f = state.inline = inlineNormal;
if (modeCfg.highlightFormatting) state.formatting = "link";
var type = getType(state);
if (type){
type += " ";
} else {
type = "";
}
return type + tokenTypes.linkInline;
}
stream.match(/^[^>]+/, true);
return tokenTypes.linkInline;
}
function linkHref(stream, state) {
// Check if space, and return NULL if so (to avoid marking the space)
if(stream.eatSpace()){
return null;
}
var ch = stream.next();
if (ch === '(' || ch === '[') {
state.f = state.inline = getLinkHrefInside(ch === "(" ? ")" : "]");
if (modeCfg.highlightFormatting) state.formatting = "link-string";
state.linkHref = true;
return getType(state);
}
return 'error';
}
function getLinkHrefInside(endChar) {
return function(stream, state) {
var ch = stream.next();
if (ch === endChar) {
state.f = state.inline = inlineNormal;
if (modeCfg.highlightFormatting) state.formatting = "link-string";
var returnState = getType(state);
state.linkHref = false;
return returnState;
}
if (stream.match(inlineRE(endChar), true)) {
stream.backUp(1);
}
state.linkHref = true;
return getType(state);
};
}
function footnoteLink(stream, state) {
if (stream.match(/^[^\]]*\]:/, false)) {
state.f = footnoteLinkInside;
stream.next(); // Consume [
if (modeCfg.highlightFormatting) state.formatting = "link";
state.linkText = true;
return getType(state);
}
return switchInline(stream, state, inlineNormal);
}
function footnoteLinkInside(stream, state) {
if (stream.match(/^\]:/, true)) {
state.f = state.inline = footnoteUrl;
if (modeCfg.highlightFormatting) state.formatting = "link";
var returnType = getType(state);
state.linkText = false;
return returnType;
}
stream.match(/^[^\]]+/, true);
return tokenTypes.linkText;
}
function footnoteUrl(stream, state) {
// Check if space, and return NULL if so (to avoid marking the space)
if(stream.eatSpace()){
return null;
}
// Match URL
stream.match(/^[^\s]+/, true);
// Check for link title
if (stream.peek() === undefined) { // End of line, set flag to check next line
state.linkTitle = true;
} else { // More content on line, check if link title
stream.match(/^(?:\s+(?:"(?:[^"\\]|\\\\|\\.)+"|'(?:[^'\\]|\\\\|\\.)+'|\((?:[^)\\]|\\\\|\\.)+\)))?/, true);
}
state.f = state.inline = inlineNormal;
return tokenTypes.linkHref + " url";
}
var savedInlineRE = [];
function inlineRE(endChar) {
if (!savedInlineRE[endChar]) {
// Escape endChar for RegExp (taken from http://stackoverflow.com/a/494122/526741)
endChar = (endChar+'').replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1");
// Match any non-endChar, escaped character, as well as the closing
// endChar.
savedInlineRE[endChar] = new RegExp('^(?:[^\\\\]|\\\\.)*?(' + endChar + ')');
}
return savedInlineRE[endChar];
}
var mode = {
startState: function() {
return {
f: blockNormal,
prevLine: null,
thisLine: null,
block: blockNormal,
htmlState: null,
indentation: 0,
inline: inlineNormal,
text: handleText,
formatting: false,
linkText: false,
linkHref: false,
linkTitle: false,
em: false,
strong: false,
header: 0,
hr: false,
taskList: false,
list: false,
listDepth: 0,
quote: 0,
trailingSpace: 0,
trailingSpaceNewLine: false,
strikethrough: false,
fencedChars: null
};
},
copyState: function(s) {
return {
f: s.f,
prevLine: s.prevLine,
thisLine: s.thisLine,
block: s.block,
htmlState: s.htmlState && CodeMirror.copyState(htmlMode, s.htmlState),
indentation: s.indentation,
localMode: s.localMode,
localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null,
inline: s.inline,
text: s.text,
formatting: false,
linkTitle: s.linkTitle,
code: s.code,
em: s.em,
strong: s.strong,
strikethrough: s.strikethrough,
header: s.header,
hr: s.hr,
taskList: s.taskList,
list: s.list,
listDepth: s.listDepth,
quote: s.quote,
indentedCode: s.indentedCode,
trailingSpace: s.trailingSpace,
trailingSpaceNewLine: s.trailingSpaceNewLine,
md_inside: s.md_inside,
fencedChars: s.fencedChars
};
},
token: function(stream, state) {
// Reset state.formatting
state.formatting = false;
if (stream != state.thisLine) {
var forceBlankLine = state.header || state.hr;
// Reset state.header and state.hr
state.header = 0;
state.hr = false;
if (stream.match(/^\s*$/, true) || forceBlankLine) {
blankLine(state);
if (!forceBlankLine) return null
state.prevLine = null
}
state.prevLine = state.thisLine
state.thisLine = stream
// Reset state.taskList
state.taskList = false;
// Reset state.trailingSpace
state.trailingSpace = 0;
state.trailingSpaceNewLine = false;
state.f = state.block;
var indentation = stream.match(/^\s*/, true)[0].replace(/\t/g, ' ').length;
var difference = Math.floor((indentation - state.indentation) / 4) * 4;
if (difference > 4) difference = 4;
var adjustedIndentation = state.indentation + difference;
state.indentationDiff = adjustedIndentation - state.indentation;
state.indentation = adjustedIndentation;
if (indentation > 0) return null;
}
return state.f(stream, state);
},
innerMode: function(state) {
if (state.block == htmlBlock) return {state: state.htmlState, mode: htmlMode};
if (state.localState) return {state: state.localState, mode: state.localMode};
return {state: state, mode: mode};
},
blankLine: blankLine,
getType: getType,
fold: "markdown"
};
return mode;
}, "xml");
CodeMirror.defineMIME("text/x-markdown", "markdown");
});
},{"../../lib/codemirror":6,"../meta":9,"../xml/xml":10}],9:[function(require,module,exports){
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.modeInfo = [
{name: "APL", mime: "text/apl", mode: "apl", ext: ["dyalog", "apl"]},
{name: "PGP", mimes: ["application/pgp", "application/pgp-keys", "application/pgp-signature"], mode: "asciiarmor", ext: ["pgp"]},
{name: "ASN.1", mime: "text/x-ttcn-asn", mode: "asn.1", ext: ["asn", "asn1"]},
{name: "Asterisk", mime: "text/x-asterisk", mode: "asterisk", file: /^extensions\.conf$/i},
{name: "Brainfuck", mime: "text/x-brainfuck", mode: "brainfuck", ext: ["b", "bf"]},
{name: "C", mime: "text/x-csrc", mode: "clike", ext: ["c", "h"]},
{name: "C++", mime: "text/x-c++src", mode: "clike", ext: ["cpp", "c++", "cc", "cxx", "hpp", "h++", "hh", "hxx"], alias: ["cpp"]},
{name: "Cobol", mime: "text/x-cobol", mode: "cobol", ext: ["cob", "cpy"]},
{name: "C#", mime: "text/x-csharp", mode: "clike", ext: ["cs"], alias: ["csharp"]},
{name: "Clojure", mime: "text/x-clojure", mode: "clojure", ext: ["clj"]},
{name: "Closure Stylesheets (GSS)", mime: "text/x-gss", mode: "css", ext: ["gss"]},
{name: "CMake", mime: "text/x-cmake", mode: "cmake", ext: ["cmake", "cmake.in"], file: /^CMakeLists.txt$/},
{name: "CoffeeScript", mime: "text/x-coffeescript", mode: "coffeescript", ext: ["coffee"], alias: ["coffee", "coffee-script"]},
{name: "Common Lisp", mime: "text/x-common-lisp", mode: "commonlisp", ext: ["cl", "lisp", "el"], alias: ["lisp"]},
{name: "Cypher", mime: "application/x-cypher-query", mode: "cypher", ext: ["cyp", "cypher"]},
{name: "Cython", mime: "text/x-cython", mode: "python", ext: ["pyx", "pxd", "pxi"]},
{name: "CSS", mime: "text/css", mode: "css", ext: ["css"]},
{name: "CQL", mime: "text/x-cassandra", mode: "sql", ext: ["cql"]},
{name: "D", mime: "text/x-d", mode: "d", ext: ["d"]},
{name: "Dart", mimes: ["application/dart", "text/x-dart"], mode: "dart", ext: ["dart"]},
{name: "diff", mime: "text/x-diff", mode: "diff", ext: ["diff", "patch"]},
{name: "Django", mime: "text/x-django", mode: "django"},
{name: "Dockerfile", mime: "text/x-dockerfile", mode: "dockerfile", file: /^Dockerfile$/},
{name: "DTD", mime: "application/xml-dtd", mode: "dtd", ext: ["dtd"]},
{name: "Dylan", mime: "text/x-dylan", mode: "dylan", ext: ["dylan", "dyl", "intr"]},
{name: "EBNF", mime: "text/x-ebnf", mode: "ebnf"},
{name: "ECL", mime: "text/x-ecl", mode: "ecl", ext: ["ecl"]},
{name: "Eiffel", mime: "text/x-eiffel", mode: "eiffel", ext: ["e"]},
{name: "Elm", mime: "text/x-elm", mode: "elm", ext: ["elm"]},
{name: "Embedded Javascript", mime: "application/x-ejs", mode: "htmlembedded", ext: ["ejs"]},
{name: "Embedded Ruby", mime: "application/x-erb", mode: "htmlembedded", ext: ["erb"]},
{name: "Erlang", mime: "text/x-erlang", mode: "erlang", ext: ["erl"]},
{name: "Factor", mime: "text/x-factor", mode: "factor", ext: ["factor"]},
{name: "Forth", mime: "text/x-forth", mode: "forth", ext: ["forth", "fth", "4th"]},
{name: "Fortran", mime: "text/x-fortran", mode: "fortran", ext: ["f", "for", "f77", "f90"]},
{name: "F#", mime: "text/x-fsharp", mode: "mllike", ext: ["fs"], alias: ["fsharp"]},
{name: "Gas", mime: "text/x-gas", mode: "gas", ext: ["s"]},
{name: "Gherkin", mime: "text/x-feature", mode: "gherkin", ext: ["feature"]},
{name: "GitHub Flavored Markdown", mime: "text/x-gfm", mode: "gfm", file: /^(readme|contributing|history).md$/i},
{name: "Go", mime: "text/x-go", mode: "go", ext: ["go"]},
{name: "Groovy", mime: "text/x-groovy", mode: "groovy", ext: ["groovy"]},
{name: "HAML", mime: "text/x-haml", mode: "haml", ext: ["haml"]},
{name: "Haskell", mime: "text/x-haskell", mode: "haskell", ext: ["hs"]},
{name: "Haxe", mime: "text/x-haxe", mode: "haxe", ext: ["hx"]},
{name: "HXML", mime: "text/x-hxml", mode: "haxe", ext: ["hxml"]},
{name: "ASP.NET", mime: "application/x-aspx", mode: "htmlembedded", ext: ["aspx"], alias: ["asp", "aspx"]},
{name: "HTML", mime: "text/html", mode: "htmlmixed", ext: ["html", "htm"], alias: ["xhtml"]},
{name: "HTTP", mime: "message/http", mode: "http"},
{name: "IDL", mime: "text/x-idl", mode: "idl", ext: ["pro"]},
{name: "Jade", mime: "text/x-jade", mode: "jade", ext: ["jade"]},
{name: "Java", mime: "text/x-java", mode: "clike", ext: ["java"]},
{name: "Java Server Pages", mime: "application/x-jsp", mode: "htmlembedded", ext: ["jsp"], alias: ["jsp"]},
{name: "JavaScript", mimes: ["text/javascript", "text/ecmascript", "application/javascript", "application/x-javascript", "application/ecmascript"],
mode: "javascript", ext: ["js"], alias: ["ecmascript", "js", "node"]},
{name: "JSON", mimes: ["application/json", "application/x-json"], mode: "javascript", ext: ["json", "map"], alias: ["json5"]},
{name: "JSON-LD", mime: "application/ld+json", mode: "javascript", ext: ["jsonld"], alias: ["jsonld"]},
{name: "Jinja2", mime: "null", mode: "jinja2"},
{name: "Julia", mime: "text/x-julia", mode: "julia", ext: ["jl"]},
{name: "Kotlin", mime: "text/x-kotlin", mode: "clike", ext: ["kt"]},
{name: "LESS", mime: "text/x-less", mode: "css", ext: ["less"]},
{name: "LiveScript", mime: "text/x-livescript", mode: "livescript", ext: ["ls"], alias: ["ls"]},
{name: "Lua", mime: "text/x-lua", mode: "lua", ext: ["lua"]},
{name: "Markdown", mime: "text/x-markdown", mode: "markdown", ext: ["markdown", "md", "mkd"]},
{name: "mIRC", mime: "text/mirc", mode: "mirc"},
{name: "MariaDB SQL", mime: "text/x-mariadb", mode: "sql"},
{name: "Mathematica", mime: "text/x-mathematica", mode: "mathematica", ext: ["m", "nb"]},
{name: "Modelica", mime: "text/x-modelica", mode: "modelica", ext: ["mo"]},
{name: "MUMPS", mime: "text/x-mumps", mode: "mumps"},
{name: "MS SQL", mime: "text/x-mssql", mode: "sql"},
{name: "MySQL", mime: "text/x-mysql", mode: "sql"},
{name: "Nginx", mime: "text/x-nginx-conf", mode: "nginx", file: /nginx.*\.conf$/i},
{name: "NSIS", mime: "text/x-nsis", mode: "nsis", ext: ["nsh", "nsi"]},
{name: "NTriples", mime: "text/n-triples", mode: "ntriples", ext: ["nt"]},
{name: "Objective C", mime: "text/x-objectivec", mode: "clike", ext: ["m", "mm"]},
{name: "OCaml", mime: "text/x-ocaml", mode: "mllike", ext: ["ml", "mli", "mll", "mly"]},
{name: "Octave", mime: "text/x-octave", mode: "octave", ext: ["m"]},
{name: "Oz", mime: "text/x-oz", mode: "oz", ext: ["oz"]},
{name: "Pascal", mime: "text/x-pascal", mode: "pascal", ext: ["p", "pas"]},
{name: "PEG.js", mime: "null", mode: "pegjs", ext: ["jsonld"]},
{name: "Perl", mime: "text/x-perl", mode: "perl", ext: ["pl", "pm"]},
{name: "PHP", mime: "application/x-httpd-php", mode: "php", ext: ["php", "php3", "php4", "php5", "phtml"]},
{name: "Pig", mime: "text/x-pig", mode: "pig", ext: ["pig"]},
{name: "Plain Text", mime: "text/plain", mode: "null", ext: ["txt", "text", "conf", "def", "list", "log"]},
{name: "PLSQL", mime: "text/x-plsql", mode: "sql", ext: ["pls"]},
{name: "Properties files", mime: "text/x-properties", mode: "properties", ext: ["properties", "ini", "in"], alias: ["ini", "properties"]},
{name: "Python", mime: "text/x-python", mode: "python", ext: ["py", "pyw"]},
{name: "Puppet", mime: "text/x-puppet", mode: "puppet", ext: ["pp"]},
{name: "Q", mime: "text/x-q", mode: "q", ext: ["q"]},
{name: "R", mime: "text/x-rsrc", mode: "r", ext: ["r"], alias: ["rscript"]},
{name: "reStructuredText", mime: "text/x-rst", mode: "rst", ext: ["rst"], alias: ["rst"]},
{name: "RPM Changes", mime: "text/x-rpm-changes", mode: "rpm"},
{name: "RPM Spec", mime: "text/x-rpm-spec", mode: "rpm", ext: ["spec"]},
{name: "Ruby", mime: "text/x-ruby", mode: "ruby", ext: ["rb"], alias: ["jruby", "macruby", "rake", "rb", "rbx"]},
{name: "Rust", mime: "text/x-rustsrc", mode: "rust", ext: ["rs"]},
{name: "Sass", mime: "text/x-sass", mode: "sass", ext: ["sass"]},
{name: "Scala", mime: "text/x-scala", mode: "clike", ext: ["scala"]},
{name: "Scheme", mime: "text/x-scheme", mode: "scheme", ext: ["scm", "ss"]},
{name: "SCSS", mime: "text/x-scss", mode: "css", ext: ["scss"]},
{name: "Shell", mime: "text/x-sh", mode: "shell", ext: ["sh", "ksh", "bash"], alias: ["bash", "sh", "zsh"], file: /^PKGBUILD$/},
{name: "Sieve", mime: "application/sieve", mode: "sieve", ext: ["siv", "sieve"]},
{name: "Slim", mimes: ["text/x-slim", "application/x-slim"], mode: "slim", ext: ["slim"]},
{name: "Smalltalk", mime: "text/x-stsrc", mode: "smalltalk", ext: ["st"]},
{name: "Smarty", mime: "text/x-smarty", mode: "smarty", ext: ["tpl"]},
{name: "Solr", mime: "text/x-solr", mode: "solr"},
{name: "Soy", mime: "text/x-soy", mode: "soy", ext: ["soy"], alias: ["closure template"]},
{name: "SPARQL", mime: "application/sparql-query", mode: "sparql", ext: ["rq", "sparql"], alias: ["sparul"]},
{name: "Spreadsheet", mime: "text/x-spreadsheet", mode: "spreadsheet", alias: ["excel", "formula"]},
{name: "SQL", mime: "text/x-sql", mode: "sql", ext: ["sql"]},
{name: "Squirrel", mime: "text/x-squirrel", mode: "clike", ext: ["nut"]},
{name: "Swift", mime: "text/x-swift", mode: "swift", ext: ["swift"]},
{name: "MariaDB", mime: "text/x-mariadb", mode: "sql"},
{name: "sTeX", mime: "text/x-stex", mode: "stex"},
{name: "LaTeX", mime: "text/x-latex", mode: "stex", ext: ["text", "ltx"], alias: ["tex"]},
{name: "SystemVerilog", mime: "text/x-systemverilog", mode: "verilog", ext: ["v"]},
{name: "Tcl", mime: "text/x-tcl", mode: "tcl", ext: ["tcl"]},
{name: "Textile", mime: "text/x-textile", mode: "textile", ext: ["textile"]},
{name: "TiddlyWiki ", mime: "text/x-tiddlywiki", mode: "tiddlywiki"},
{name: "Tiki wiki", mime: "text/tiki", mode: "tiki"},
{name: "TOML", mime: "text/x-toml", mode: "toml", ext: ["toml"]},
{name: "Tornado", mime: "text/x-tornado", mode: "tornado"},
{name: "troff", mime: "troff", mode: "troff", ext: ["1", "2", "3", "4", "5", "6", "7", "8", "9"]},
{name: "TTCN", mime: "text/x-ttcn", mode: "ttcn", ext: ["ttcn", "ttcn3", "ttcnpp"]},
{name: "TTCN_CFG", mime: "text/x-ttcn-cfg", mode: "ttcn-cfg", ext: ["cfg"]},
{name: "Turtle", mime: "text/turtle", mode: "turtle", ext: ["ttl"]},
{name: "TypeScript", mime: "application/typescript", mode: "javascript", ext: ["ts"], alias: ["ts"]},
{name: "Twig", mime: "text/x-twig", mode: "twig"},
{name: "VB.NET", mime: "text/x-vb", mode: "vb", ext: ["vb"]},
{name: "VBScript", mime: "text/vbscript", mode: "vbscript", ext: ["vbs"]},
{name: "Velocity", mime: "text/velocity", mode: "velocity", ext: ["vtl"]},
{name: "Verilog", mime: "text/x-verilog", mode: "verilog", ext: ["v"]},
{name: "VHDL", mime: "text/x-vhdl", mode: "vhdl", ext: ["vhd", "vhdl"]},
{name: "XML", mimes: ["application/xml", "text/xml"], mode: "xml", ext: ["xml", "xsl", "xsd"], alias: ["rss", "wsdl", "xsd"]},
{name: "XQuery", mime: "application/xquery", mode: "xquery", ext: ["xy", "xquery"]},
{name: "YAML", mime: "text/x-yaml", mode: "yaml", ext: ["yaml", "yml"], alias: ["yml"]},
{name: "Z80", mime: "text/x-z80", mode: "z80", ext: ["z80"]},
{name: "mscgen", mime: "text/x-mscgen", mode: "mscgen", ext: ["mscgen", "mscin", "msc"]},
{name: "xu", mime: "text/x-xu", mode: "mscgen", ext: ["xu"]},
{name: "msgenny", mime: "text/x-msgenny", mode: "mscgen", ext: ["msgenny"]}
];
// Ensure all modes have a mime property for backwards compatibility
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
var info = CodeMirror.modeInfo[i];
if (info.mimes) info.mime = info.mimes[0];
}
CodeMirror.findModeByMIME = function(mime) {
mime = mime.toLowerCase();
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
var info = CodeMirror.modeInfo[i];
if (info.mime == mime) return info;
if (info.mimes) for (var j = 0; j < info.mimes.length; j++)
if (info.mimes[j] == mime) return info;
}
};
CodeMirror.findModeByExtension = function(ext) {
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
var info = CodeMirror.modeInfo[i];
if (info.ext) for (var j = 0; j < info.ext.length; j++)
if (info.ext[j] == ext) return info;
}
};
CodeMirror.findModeByFileName = function(filename) {
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
var info = CodeMirror.modeInfo[i];
if (info.file && info.file.test(filename)) return info;
}
var dot = filename.lastIndexOf(".");
var ext = dot > -1 && filename.substring(dot + 1, filename.length);
if (ext) return CodeMirror.findModeByExtension(ext);
};
CodeMirror.findModeByName = function(name) {
name = name.toLowerCase();
for (var i = 0; i < CodeMirror.modeInfo.length; i++) {
var info = CodeMirror.modeInfo[i];
if (info.name.toLowerCase() == name) return info;
if (info.alias) for (var j = 0; j < info.alias.length; j++)
if (info.alias[j].toLowerCase() == name) return info;
}
};
});
},{"../lib/codemirror":6}],10:[function(require,module,exports){
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("xml", function(config, parserConfig) {
var indentUnit = config.indentUnit;
var multilineTagIndentFactor = parserConfig.multilineTagIndentFactor || 1;
var multilineTagIndentPastTag = parserConfig.multilineTagIndentPastTag;
if (multilineTagIndentPastTag == null) multilineTagIndentPastTag = true;
var Kludges = parserConfig.htmlMode ? {
autoSelfClosers: {'area': true, 'base': true, 'br': true, 'col': true, 'command': true,
'embed': true, 'frame': true, 'hr': true, 'img': true, 'input': true,
'keygen': true, 'link': true, 'meta': true, 'param': true, 'source': true,
'track': true, 'wbr': true, 'menuitem': true},
implicitlyClosed: {'dd': true, 'li': true, 'optgroup': true, 'option': true, 'p': true,
'rp': true, 'rt': true, 'tbody': true, 'td': true, 'tfoot': true,
'th': true, 'tr': true},
contextGrabbers: {
'dd': {'dd': true, 'dt': true},
'dt': {'dd': true, 'dt': true},
'li': {'li': true},
'option': {'option': true, 'optgroup': true},
'optgroup': {'optgroup': true},
'p': {'address': true, 'article': true, 'aside': true, 'blockquote': true, 'dir': true,
'div': true, 'dl': true, 'fieldset': true, 'footer': true, 'form': true,
'h1': true, 'h2': true, 'h3': true, 'h4': true, 'h5': true, 'h6': true,
'header': true, 'hgroup': true, 'hr': true, 'menu': true, 'nav': true, 'ol': true,
'p': true, 'pre': true, 'section': true, 'table': true, 'ul': true},
'rp': {'rp': true, 'rt': true},
'rt': {'rp': true, 'rt': true},
'tbody': {'tbody': true, 'tfoot': true},
'td': {'td': true, 'th': true},
'tfoot': {'tbody': true},
'th': {'td': true, 'th': true},
'thead': {'tbody': true, 'tfoot': true},
'tr': {'tr': true}
},
doNotIndent: {"pre": true},
allowUnquoted: true,
allowMissing: true,
caseFold: true
} : {
autoSelfClosers: {},
implicitlyClosed: {},
contextGrabbers: {},
doNotIndent: {},
allowUnquoted: false,
allowMissing: false,
caseFold: false
};
var alignCDATA = parserConfig.alignCDATA;
// Return variables for tokenizers
var type, setStyle;
function inText(stream, state) {
function chain(parser) {
state.tokenize = parser;
return parser(stream, state);
}
var ch = stream.next();
if (ch == "<") {
if (stream.eat("!")) {
if (stream.eat("[")) {
if (stream.match("CDATA[")) return chain(inBlock("atom", "]]>"));
else return null;
} else if (stream.match("--")) {
return chain(inBlock("comment", "-->"));
} else if (stream.match("DOCTYPE", true, true)) {
stream.eatWhile(/[\w\._\-]/);
return chain(doctype(1));
} else {
return null;
}
} else if (stream.eat("?")) {
stream.eatWhile(/[\w\._\-]/);
state.tokenize = inBlock("meta", "?>");
return "meta";
} else {
type = stream.eat("/") ? "closeTag" : "openTag";
state.tokenize = inTag;
return "tag bracket";
}
} else if (ch == "&") {
var ok;
if (stream.eat("#")) {
if (stream.eat("x")) {
ok = stream.eatWhile(/[a-fA-F\d]/) && stream.eat(";");
} else {
ok = stream.eatWhile(/[\d]/) && stream.eat(";");
}
} else {
ok = stream.eatWhile(/[\w\.\-:]/) && stream.eat(";");
}
return ok ? "atom" : "error";
} else {
stream.eatWhile(/[^&<]/);
return null;
}
}
inText.isInText = true;
function inTag(stream, state) {
var ch = stream.next();
if (ch == ">" || (ch == "/" && stream.eat(">"))) {
state.tokenize = inText;
type = ch == ">" ? "endTag" : "selfcloseTag";
return "tag bracket";
} else if (ch == "=") {
type = "equals";
return null;
} else if (ch == "<") {
state.tokenize = inText;
state.state = baseState;
state.tagName = state.tagStart = null;
var next = state.tokenize(stream, state);
return next ? next + " tag error" : "tag error";
} else if (/[\'\"]/.test(ch)) {
state.tokenize = inAttribute(ch);
state.stringStartCol = stream.column();
return state.tokenize(stream, state);
} else {
stream.match(/^[^\s\u00a0=<>\"\']*[^\s\u00a0=<>\"\'\/]/);
return "word";
}
}
function inAttribute(quote) {
var closure = function(stream, state) {
while (!stream.eol()) {
if (stream.next() == quote) {
state.tokenize = inTag;
break;
}
}
return "string";
};
closure.isInAttribute = true;
return closure;
}
function inBlock(style, terminator) {
return function(stream, state) {
while (!stream.eol()) {
if (stream.match(terminator)) {
state.tokenize = inText;
break;
}
stream.next();
}
return style;
};
}
function doctype(depth) {
return function(stream, state) {
var ch;
while ((ch = stream.next()) != null) {
if (ch == "<") {
state.tokenize = doctype(depth + 1);
return state.tokenize(stream, state);
} else if (ch == ">") {
if (depth == 1) {
state.tokenize = inText;
break;
} else {
state.tokenize = doctype(depth - 1);
return state.tokenize(stream, state);
}
}
}
return "meta";
};
}
function Context(state, tagName, startOfLine) {
this.prev = state.context;
this.tagName = tagName;
this.indent = state.indented;
this.startOfLine = startOfLine;
if (Kludges.doNotIndent.hasOwnProperty(tagName) || (state.context && state.context.noIndent))
this.noIndent = true;
}
function popContext(state) {
if (state.context) state.context = state.context.prev;
}
function maybePopContext(state, nextTagName) {
var parentTagName;
while (true) {
if (!state.context) {
return;
}
parentTagName = state.context.tagName;
if (!Kludges.contextGrabbers.hasOwnProperty(parentTagName) ||
!Kludges.contextGrabbers[parentTagName].hasOwnProperty(nextTagName)) {
return;
}
popContext(state);
}
}
function baseState(type, stream, state) {
if (type == "openTag") {
state.tagStart = stream.column();
return tagNameState;
} else if (type == "closeTag") {
return closeTagNameState;
} else {
return baseState;
}
}
function tagNameState(type, stream, state) {
if (type == "word") {
state.tagName = stream.current();
setStyle = "tag";
return attrState;
} else {
setStyle = "error";
return tagNameState;
}
}
function closeTagNameState(type, stream, state) {
if (type == "word") {
var tagName = stream.current();
if (state.context && state.context.tagName != tagName &&
Kludges.implicitlyClosed.hasOwnProperty(state.context.tagName))
popContext(state);
if (state.context && state.context.tagName == tagName) {
setStyle = "tag";
return closeState;
} else {
setStyle = "tag error";
return closeStateErr;
}
} else {
setStyle = "error";
return closeStateErr;
}
}
function closeState(type, _stream, state) {
if (type != "endTag") {
setStyle = "error";
return closeState;
}
popContext(state);
return baseState;
}
function closeStateErr(type, stream, state) {
setStyle = "error";
return closeState(type, stream, state);
}
function attrState(type, _stream, state) {
if (type == "word") {
setStyle = "attribute";
return attrEqState;
} else if (type == "endTag" || type == "selfcloseTag") {
var tagName = state.tagName, tagStart = state.tagStart;
state.tagName = state.tagStart = null;
if (type == "selfcloseTag" ||
Kludges.autoSelfClosers.hasOwnProperty(tagName)) {
maybePopContext(state, tagName);
} else {
maybePopContext(state, tagName);
state.context = new Context(state, tagName, tagStart == state.indented);
}
return baseState;
}
setStyle = "error";
return attrState;
}
function attrEqState(type, stream, state) {
if (type == "equals") return attrValueState;
if (!Kludges.allowMissing) setStyle = "error";
return attrState(type, stream, state);
}
function attrValueState(type, stream, state) {
if (type == "string") return attrContinuedState;
if (type == "word" && Kludges.allowUnquoted) {setStyle = "string"; return attrState;}
setStyle = "error";
return attrState(type, stream, state);
}
function attrContinuedState(type, stream, state) {
if (type == "string") return attrContinuedState;
return attrState(type, stream, state);
}
return {
startState: function() {
return {tokenize: inText,
state: baseState,
indented: 0,
tagName: null, tagStart: null,
context: null};
},
token: function(stream, state) {
if (!state.tagName && stream.sol())
state.indented = stream.indentation();
if (stream.eatSpace()) return null;
type = null;
var style = state.tokenize(stream, state);
if ((style || type) && style != "comment") {
setStyle = null;
state.state = state.state(type || style, stream, state);
if (setStyle)
style = setStyle == "error" ? style + " error" : setStyle;
}
return style;
},
indent: function(state, textAfter, fullLine) {
var context = state.context;
// Indent multi-line strings (e.g. css).
if (state.tokenize.isInAttribute) {
if (state.tagStart == state.indented)
return state.stringStartCol + 1;
else
return state.indented + indentUnit;
}
if (context && context.noIndent) return CodeMirror.Pass;
if (state.tokenize != inTag && state.tokenize != inText)
return fullLine ? fullLine.match(/^(\s*)/)[0].length : 0;
// Indent the starts of attribute names.
if (state.tagName) {
if (multilineTagIndentPastTag)
return state.tagStart + state.tagName.length + 2;
else
return state.tagStart + indentUnit * multilineTagIndentFactor;
}
if (alignCDATA && /<!\[CDATA\[/.test(textAfter)) return 0;
var tagAfter = textAfter && /^<(\/)?([\w_:\.-]*)/.exec(textAfter);
if (tagAfter && tagAfter[1]) { // Closing tag spotted
while (context) {
if (context.tagName == tagAfter[2]) {
context = context.prev;
break;
} else if (Kludges.implicitlyClosed.hasOwnProperty(context.tagName)) {
context = context.prev;
} else {
break;
}
}
} else if (tagAfter) { // Opening tag spotted
while (context) {
var grabbers = Kludges.contextGrabbers[context.tagName];
if (grabbers && grabbers.hasOwnProperty(tagAfter[2]))
context = context.prev;
else
break;
}
}
while (context && !context.startOfLine)
context = context.prev;
if (context) return context.indent + indentUnit;
else return 0;
},
electricInput: /<\/[\s\w:]+>$/,
blockCommentStart: "<!--",
blockCommentEnd: "-->",
configuration: parserConfig.htmlMode ? "html" : "xml",
helperType: parserConfig.htmlMode ? "html" : "xml"
};
});
CodeMirror.defineMIME("text/xml", "xml");
CodeMirror.defineMIME("application/xml", "xml");
if (!CodeMirror.mimeModes.hasOwnProperty("text/html"))
CodeMirror.defineMIME("text/html", {name: "xml", htmlMode: true});
});
},{"../../lib/codemirror":6}],11:[function(require,module,exports){
(function (global){
/**
* marked - a markdown parser
* Copyright (c) 2011-2014, Christopher Jeffrey. (MIT Licensed)
* https://github.com/chjj/marked
*/
;(function() {
/**
* Block-Level Grammar
*/
var block = {
newline: /^\n+/,
code: /^( {4}[^\n]+\n*)+/,
fences: noop,
hr: /^( *[-*_]){3,} *(?:\n+|$)/,
heading: /^ *(#{1,6}) *([^\n]+?) *#* *(?:\n+|$)/,
nptable: noop,
lheading: /^([^\n]+)\n *(=|-){2,} *(?:\n+|$)/,
blockquote: /^( *>[^\n]+(\n(?!def)[^\n]+)*\n*)+/,
list: /^( *)(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?!\1bull )\n*|\s*$)/,
html: /^ *(?:comment *(?:\n|\s*$)|closed *(?:\n{2,}|\s*$)|closing *(?:\n{2,}|\s*$))/,
def: /^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +["(]([^\n]+)[")])? *(?:\n+|$)/,
table: noop,
paragraph: /^((?:[^\n]+\n?(?!hr|heading|lheading|blockquote|tag|def))+)\n*/,
text: /^[^\n]+/
};
block.bullet = /(?:[*+-]|\d+\.)/;
block.item = /^( *)(bull) [^\n]*(?:\n(?!\1bull )[^\n]*)*/;
block.item = replace(block.item, 'gm')
(/bull/g, block.bullet)
();
block.list = replace(block.list)
(/bull/g, block.bullet)
('hr', '\\n+(?=\\1?(?:[-*_] *){3,}(?:\\n+|$))')
('def', '\\n+(?=' + block.def.source + ')')
();
block.blockquote = replace(block.blockquote)
('def', block.def)
();
block._tag = '(?!(?:'
+ 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code'
+ '|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo'
+ '|span|br|wbr|ins|del|img)\\b)\\w+(?!:/|[^\\w\\s@]*@)\\b';
block.html = replace(block.html)
('comment', /<!--[\s\S]*?-->/)
('closed', /<(tag)[\s\S]+?<\/\1>/)
('closing', /<tag(?:"[^"]*"|'[^']*'|[^'">])*?>/)
(/tag/g, block._tag)
();
block.paragraph = replace(block.paragraph)
('hr', block.hr)
('heading', block.heading)
('lheading', block.lheading)
('blockquote', block.blockquote)
('tag', '<' + block._tag)
('def', block.def)
();
/**
* Normal Block Grammar
*/
block.normal = merge({}, block);
/**
* GFM Block Grammar
*/
block.gfm = merge({}, block.normal, {
fences: /^ *(`{3,}|~{3,})[ \.]*(\S+)? *\n([\s\S]*?)\s*\1 *(?:\n+|$)/,
paragraph: /^/,
heading: /^ *(#{1,6}) +([^\n]+?) *#* *(?:\n+|$)/
});
block.gfm.paragraph = replace(block.paragraph)
('(?!', '(?!'
+ block.gfm.fences.source.replace('\\1', '\\2') + '|'
+ block.list.source.replace('\\1', '\\3') + '|')
();
/**
* GFM + Tables Block Grammar
*/
block.tables = merge({}, block.gfm, {
nptable: /^ *(\S.*\|.*)\n *([-:]+ *\|[-| :]*)\n((?:.*\|.*(?:\n|$))*)\n*/,
table: /^ *\|(.+)\n *\|( *[-:]+[-| :]*)\n((?: *\|.*(?:\n|$))*)\n*/
});
/**
* Block Lexer
*/
function Lexer(options) {
this.tokens = [];
this.tokens.links = {};
this.options = options || marked.defaults;
this.rules = block.normal;
if (this.options.gfm) {
if (this.options.tables) {
this.rules = block.tables;
} else {
this.rules = block.gfm;
}
}
}
/**
* Expose Block Rules
*/
Lexer.rules = block;
/**
* Static Lex Method
*/
Lexer.lex = function(src, options) {
var lexer = new Lexer(options);
return lexer.lex(src);
};
/**
* Preprocessing
*/
Lexer.prototype.lex = function(src) {
src = src
.replace(/\r\n|\r/g, '\n')
.replace(/\t/g, ' ')
.replace(/\u00a0/g, ' ')
.replace(/\u2424/g, '\n');
return this.token(src, true);
};
/**
* Lexing
*/
Lexer.prototype.token = function(src, top, bq) {
var src = src.replace(/^ +$/gm, '')
, next
, loose
, cap
, bull
, b
, item
, space
, i
, l;
while (src) {
// newline
if (cap = this.rules.newline.exec(src)) {
src = src.substring(cap[0].length);
if (cap[0].length > 1) {
this.tokens.push({
type: 'space'
});
}
}
// code
if (cap = this.rules.code.exec(src)) {
src = src.substring(cap[0].length);
cap = cap[0].replace(/^ {4}/gm, '');
this.tokens.push({
type: 'code',
text: !this.options.pedantic
? cap.replace(/\n+$/, '')
: cap
});
continue;
}
// fences (gfm)
if (cap = this.rules.fences.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'code',
lang: cap[2],
text: cap[3] || ''
});
continue;
}
// heading
if (cap = this.rules.heading.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'heading',
depth: cap[1].length,
text: cap[2]
});
continue;
}
// table no leading pipe (gfm)
if (top && (cap = this.rules.nptable.exec(src))) {
src = src.substring(cap[0].length);
item = {
type: 'table',
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
cells: cap[3].replace(/\n$/, '').split('\n')
};
for (i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = 'right';
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = 'center';
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = 'left';
} else {
item.align[i] = null;
}
}
for (i = 0; i < item.cells.length; i++) {
item.cells[i] = item.cells[i].split(/ *\| */);
}
this.tokens.push(item);
continue;
}
// lheading
if (cap = this.rules.lheading.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'heading',
depth: cap[2] === '=' ? 1 : 2,
text: cap[1]
});
continue;
}
// hr
if (cap = this.rules.hr.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'hr'
});
continue;
}
// blockquote
if (cap = this.rules.blockquote.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'blockquote_start'
});
cap = cap[0].replace(/^ *> ?/gm, '');
// Pass `top` to keep the current
// "toplevel" state. This is exactly
// how markdown.pl works.
this.token(cap, top, true);
this.tokens.push({
type: 'blockquote_end'
});
continue;
}
// list
if (cap = this.rules.list.exec(src)) {
src = src.substring(cap[0].length);
bull = cap[2];
this.tokens.push({
type: 'list_start',
ordered: bull.length > 1
});
// Get each top-level item.
cap = cap[0].match(this.rules.item);
next = false;
l = cap.length;
i = 0;
for (; i < l; i++) {
item = cap[i];
// Remove the list item's bullet
// so it is seen as the next token.
space = item.length;
item = item.replace(/^ *([*+-]|\d+\.) +/, '');
// Outdent whatever the
// list item contains. Hacky.
if (~item.indexOf('\n ')) {
space -= item.length;
item = !this.options.pedantic
? item.replace(new RegExp('^ {1,' + space + '}', 'gm'), '')
: item.replace(/^ {1,4}/gm, '');
}
// Determine whether the next list item belongs here.
// Backpedal if it does not belong in this list.
if (this.options.smartLists && i !== l - 1) {
b = block.bullet.exec(cap[i + 1])[0];
if (bull !== b && !(bull.length > 1 && b.length > 1)) {
src = cap.slice(i + 1).join('\n') + src;
i = l - 1;
}
}
// Determine whether item is loose or not.
// Use: /(^|\n)(?! )[^\n]+\n\n(?!\s*$)/
// for discount behavior.
loose = next || /\n\n(?!\s*$)/.test(item);
if (i !== l - 1) {
next = item.charAt(item.length - 1) === '\n';
if (!loose) loose = next;
}
this.tokens.push({
type: loose
? 'loose_item_start'
: 'list_item_start'
});
// Recurse.
this.token(item, false, bq);
this.tokens.push({
type: 'list_item_end'
});
}
this.tokens.push({
type: 'list_end'
});
continue;
}
// html
if (cap = this.rules.html.exec(src)) {
src = src.substring(cap[0].length);
this.tokens.push({
type: this.options.sanitize
? 'paragraph'
: 'html',
pre: !this.options.sanitizer
&& (cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style'),
text: cap[0]
});
continue;
}
// def
if ((!bq && top) && (cap = this.rules.def.exec(src))) {
src = src.substring(cap[0].length);
this.tokens.links[cap[1].toLowerCase()] = {
href: cap[2],
title: cap[3]
};
continue;
}
// table (gfm)
if (top && (cap = this.rules.table.exec(src))) {
src = src.substring(cap[0].length);
item = {
type: 'table',
header: cap[1].replace(/^ *| *\| *$/g, '').split(/ *\| */),
align: cap[2].replace(/^ *|\| *$/g, '').split(/ *\| */),
cells: cap[3].replace(/(?: *\| *)?\n$/, '').split('\n')
};
for (i = 0; i < item.align.length; i++) {
if (/^ *-+: *$/.test(item.align[i])) {
item.align[i] = 'right';
} else if (/^ *:-+: *$/.test(item.align[i])) {
item.align[i] = 'center';
} else if (/^ *:-+ *$/.test(item.align[i])) {
item.align[i] = 'left';
} else {
item.align[i] = null;
}
}
for (i = 0; i < item.cells.length; i++) {
item.cells[i] = item.cells[i]
.replace(/^ *\| *| *\| *$/g, '')
.split(/ *\| */);
}
this.tokens.push(item);
continue;
}
// top-level paragraph
if (top && (cap = this.rules.paragraph.exec(src))) {
src = src.substring(cap[0].length);
this.tokens.push({
type: 'paragraph',
text: cap[1].charAt(cap[1].length - 1) === '\n'
? cap[1].slice(0, -1)
: cap[1]
});
continue;
}
// text
if (cap = this.rules.text.exec(src)) {
// Top-level should never reach here.
src = src.substring(cap[0].length);
this.tokens.push({
type: 'text',
text: cap[0]
});
continue;
}
if (src) {
throw new
Error('Infinite loop on byte: ' + src.charCodeAt(0));
}
}
return this.tokens;
};
/**
* Inline-Level Grammar
*/
var inline = {
escape: /^\\([\\`*{}\[\]()#+\-.!_>])/,
autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
url: noop,
tag: /^<!--[\s\S]*?-->|^<\/?\w+(?:"[^"]*"|'[^']*'|[^'">])*?>/,
link: /^!?\[(inside)\]\(href\)/,
reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
em: /^\b_((?:[^_]|__)+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
br: /^ {2,}\n(?!\s*$)/,
del: noop,
text: /^[\s\S]+?(?=[\\<!\[_*`]| {2,}\n|$)/
};
inline._inside = /(?:\[[^\]]*\]|[^\[\]]|\](?=[^\[]*\]))*/;
inline._href = /\s*<?([\s\S]*?)>?(?:\s+['"]([\s\S]*?)['"])?\s*/;
inline.link = replace(inline.link)
('inside', inline._inside)
('href', inline._href)
();
inline.reflink = replace(inline.reflink)
('inside', inline._inside)
();
/**
* Normal Inline Grammar
*/
inline.normal = merge({}, inline);
/**
* Pedantic Inline Grammar
*/
inline.pedantic = merge({}, inline.normal, {
strong: /^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,
em: /^_(?=\S)([\s\S]*?\S)_(?!_)|^\*(?=\S)([\s\S]*?\S)\*(?!\*)/
});
/**
* GFM Inline Grammar
*/
inline.gfm = merge({}, inline.normal, {
escape: replace(inline.escape)('])', '~|])')(),
url: /^(https?:\/\/[^\s<]+[^<.,:;"')\]\s])/,
del: /^~~(?=\S)([\s\S]*?\S)~~/,
text: replace(inline.text)
(']|', '~]|')
('|', '|https?://|')
()
});
/**
* GFM + Line Breaks Inline Grammar
*/
inline.breaks = merge({}, inline.gfm, {
br: replace(inline.br)('{2,}', '*')(),
text: replace(inline.gfm.text)('{2,}', '*')()
});
/**
* Inline Lexer & Compiler
*/
function InlineLexer(links, options) {
this.options = options || marked.defaults;
this.links = links;
this.rules = inline.normal;
this.renderer = this.options.renderer || new Renderer;
this.renderer.options = this.options;
if (!this.links) {
throw new
Error('Tokens array requires a `links` property.');
}
if (this.options.gfm) {
if (this.options.breaks) {
this.rules = inline.breaks;
} else {
this.rules = inline.gfm;
}
} else if (this.options.pedantic) {
this.rules = inline.pedantic;
}
}
/**
* Expose Inline Rules
*/
InlineLexer.rules = inline;
/**
* Static Lexing/Compiling Method
*/
InlineLexer.output = function(src, links, options) {
var inline = new InlineLexer(links, options);
return inline.output(src);
};
/**
* Lexing/Compiling
*/
InlineLexer.prototype.output = function(src) {
var out = ''
, link
, text
, href
, cap;
while (src) {
// escape
if (cap = this.rules.escape.exec(src)) {
src = src.substring(cap[0].length);
out += cap[1];
continue;
}
// autolink
if (cap = this.rules.autolink.exec(src)) {
src = src.substring(cap[0].length);
if (cap[2] === '@') {
text = cap[1].charAt(6) === ':'
? this.mangle(cap[1].substring(7))
: this.mangle(cap[1]);
href = this.mangle('mailto:') + text;
} else {
text = escape(cap[1]);
href = text;
}
out += this.renderer.link(href, null, text);
continue;
}
// url (gfm)
if (!this.inLink && (cap = this.rules.url.exec(src))) {
src = src.substring(cap[0].length);
text = escape(cap[1]);
href = text;
out += this.renderer.link(href, null, text);
continue;
}
// tag
if (cap = this.rules.tag.exec(src)) {
if (!this.inLink && /^<a /i.test(cap[0])) {
this.inLink = true;
} else if (this.inLink && /^<\/a>/i.test(cap[0])) {
this.inLink = false;
}
src = src.substring(cap[0].length);
out += this.options.sanitize
? this.options.sanitizer
? this.options.sanitizer(cap[0])
: escape(cap[0])
: cap[0]
continue;
}
// link
if (cap = this.rules.link.exec(src)) {
src = src.substring(cap[0].length);
this.inLink = true;
out += this.outputLink(cap, {
href: cap[2],
title: cap[3]
});
this.inLink = false;
continue;
}
// reflink, nolink
if ((cap = this.rules.reflink.exec(src))
|| (cap = this.rules.nolink.exec(src))) {
src = src.substring(cap[0].length);
link = (cap[2] || cap[1]).replace(/\s+/g, ' ');
link = this.links[link.toLowerCase()];
if (!link || !link.href) {
out += cap[0].charAt(0);
src = cap[0].substring(1) + src;
continue;
}
this.inLink = true;
out += this.outputLink(cap, link);
this.inLink = false;
continue;
}
// strong
if (cap = this.rules.strong.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.strong(this.output(cap[2] || cap[1]));
continue;
}
// em
if (cap = this.rules.em.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.em(this.output(cap[2] || cap[1]));
continue;
}
// code
if (cap = this.rules.code.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.codespan(escape(cap[2], true));
continue;
}
// br
if (cap = this.rules.br.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.br();
continue;
}
// del (gfm)
if (cap = this.rules.del.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.del(this.output(cap[1]));
continue;
}
// text
if (cap = this.rules.text.exec(src)) {
src = src.substring(cap[0].length);
out += this.renderer.text(escape(this.smartypants(cap[0])));
continue;
}
if (src) {
throw new
Error('Infinite loop on byte: ' + src.charCodeAt(0));
}
}
return out;
};
/**
* Compile Link
*/
InlineLexer.prototype.outputLink = function(cap, link) {
var href = escape(link.href)
, title = link.title ? escape(link.title) : null;
return cap[0].charAt(0) !== '!'
? this.renderer.link(href, title, this.output(cap[1]))
: this.renderer.image(href, title, escape(cap[1]));
};
/**
* Smartypants Transformations
*/
InlineLexer.prototype.smartypants = function(text) {
if (!this.options.smartypants) return text;
return text
// em-dashes
.replace(/---/g, '\u2014')
// en-dashes
.replace(/--/g, '\u2013')
// opening singles
.replace(/(^|[-\u2014/(\[{"\s])'/g, '$1\u2018')
// closing singles & apostrophes
.replace(/'/g, '\u2019')
// opening doubles
.replace(/(^|[-\u2014/(\[{\u2018\s])"/g, '$1\u201c')
// closing doubles
.replace(/"/g, '\u201d')
// ellipses
.replace(/\.{3}/g, '\u2026');
};
/**
* Mangle Links
*/
InlineLexer.prototype.mangle = function(text) {
if (!this.options.mangle) return text;
var out = ''
, l = text.length
, i = 0
, ch;
for (; i < l; i++) {
ch = text.charCodeAt(i);
if (Math.random() > 0.5) {
ch = 'x' + ch.toString(16);
}
out += '&#' + ch + ';';
}
return out;
};
/**
* Renderer
*/
function Renderer(options) {
this.options = options || {};
}
Renderer.prototype.code = function(code, lang, escaped) {
if (this.options.highlight) {
var out = this.options.highlight(code, lang);
if (out != null && out !== code) {
escaped = true;
code = out;
}
}
if (!lang) {
return '<pre><code>'
+ (escaped ? code : escape(code, true))
+ '\n</code></pre>';
}
return '<pre><code class="'
+ this.options.langPrefix
+ escape(lang, true)
+ '">'
+ (escaped ? code : escape(code, true))
+ '\n</code></pre>\n';
};
Renderer.prototype.blockquote = function(quote) {
return '<blockquote>\n' + quote + '</blockquote>\n';
};
Renderer.prototype.html = function(html) {
return html;
};
Renderer.prototype.heading = function(text, level, raw) {
return '<h'
+ level
+ ' id="'
+ this.options.headerPrefix
+ raw.toLowerCase().replace(/[^\w]+/g, '-')
+ '">'
+ text
+ '</h'
+ level
+ '>\n';
};
Renderer.prototype.hr = function() {
return this.options.xhtml ? '<hr/>\n' : '<hr>\n';
};
Renderer.prototype.list = function(body, ordered) {
var type = ordered ? 'ol' : 'ul';
return '<' + type + '>\n' + body + '</' + type + '>\n';
};
Renderer.prototype.listitem = function(text) {
return '<li>' + text + '</li>\n';
};
Renderer.prototype.paragraph = function(text) {
return '<p>' + text + '</p>\n';
};
Renderer.prototype.table = function(header, body) {
return '<table>\n'
+ '<thead>\n'
+ header
+ '</thead>\n'
+ '<tbody>\n'
+ body
+ '</tbody>\n'
+ '</table>\n';
};
Renderer.prototype.tablerow = function(content) {
return '<tr>\n' + content + '</tr>\n';
};
Renderer.prototype.tablecell = function(content, flags) {
var type = flags.header ? 'th' : 'td';
var tag = flags.align
? '<' + type + ' style="text-align:' + flags.align + '">'
: '<' + type + '>';
return tag + content + '</' + type + '>\n';
};
// span level renderer
Renderer.prototype.strong = function(text) {
return '<strong>' + text + '</strong>';
};
Renderer.prototype.em = function(text) {
return '<em>' + text + '</em>';
};
Renderer.prototype.codespan = function(text) {
return '<code>' + text + '</code>';
};
Renderer.prototype.br = function() {
return this.options.xhtml ? '<br/>' : '<br>';
};
Renderer.prototype.del = function(text) {
return '<del>' + text + '</del>';
};
Renderer.prototype.link = function(href, title, text) {
if (this.options.sanitize) {
try {
var prot = decodeURIComponent(unescape(href))
.replace(/[^\w:]/g, '')
.toLowerCase();
} catch (e) {
return '';
}
if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0) {
return '';
}
}
var out = '<a href="' + href + '"';
if (title) {
out += ' title="' + title + '"';
}
out += '>' + text + '</a>';
return out;
};
Renderer.prototype.image = function(href, title, text) {
var out = '<img src="' + href + '" alt="' + text + '"';
if (title) {
out += ' title="' + title + '"';
}
out += this.options.xhtml ? '/>' : '>';
return out;
};
Renderer.prototype.text = function(text) {
return text;
};
/**
* Parsing & Compiling
*/
function Parser(options) {
this.tokens = [];
this.token = null;
this.options = options || marked.defaults;
this.options.renderer = this.options.renderer || new Renderer;
this.renderer = this.options.renderer;
this.renderer.options = this.options;
}
/**
* Static Parse Method
*/
Parser.parse = function(src, options, renderer) {
var parser = new Parser(options, renderer);
return parser.parse(src);
};
/**
* Parse Loop
*/
Parser.prototype.parse = function(src) {
this.inline = new InlineLexer(src.links, this.options, this.renderer);
this.tokens = src.reverse();
var out = '';
while (this.next()) {
out += this.tok();
}
return out;
};
/**
* Next Token
*/
Parser.prototype.next = function() {
return this.token = this.tokens.pop();
};
/**
* Preview Next Token
*/
Parser.prototype.peek = function() {
return this.tokens[this.tokens.length - 1] || 0;
};
/**
* Parse Text Tokens
*/
Parser.prototype.parseText = function() {
var body = this.token.text;
while (this.peek().type === 'text') {
body += '\n' + this.next().text;
}
return this.inline.output(body);
};
/**
* Parse Current Token
*/
Parser.prototype.tok = function() {
switch (this.token.type) {
case 'space': {
return '';
}
case 'hr': {
return this.renderer.hr();
}
case 'heading': {
return this.renderer.heading(
this.inline.output(this.token.text),
this.token.depth,
this.token.text);
}
case 'code': {
return this.renderer.code(this.token.text,
this.token.lang,
this.token.escaped);
}
case 'table': {
var header = ''
, body = ''
, i
, row
, cell
, flags
, j;
// header
cell = '';
for (i = 0; i < this.token.header.length; i++) {
flags = { header: true, align: this.token.align[i] };
cell += this.renderer.tablecell(
this.inline.output(this.token.header[i]),
{ header: true, align: this.token.align[i] }
);
}
header += this.renderer.tablerow(cell);
for (i = 0; i < this.token.cells.length; i++) {
row = this.token.cells[i];
cell = '';
for (j = 0; j < row.length; j++) {
cell += this.renderer.tablecell(
this.inline.output(row[j]),
{ header: false, align: this.token.align[j] }
);
}
body += this.renderer.tablerow(cell);
}
return this.renderer.table(header, body);
}
case 'blockquote_start': {
var body = '';
while (this.next().type !== 'blockquote_end') {
body += this.tok();
}
return this.renderer.blockquote(body);
}
case 'list_start': {
var body = ''
, ordered = this.token.ordered;
while (this.next().type !== 'list_end') {
body += this.tok();
}
return this.renderer.list(body, ordered);
}
case 'list_item_start': {
var body = '';
while (this.next().type !== 'list_item_end') {
body += this.token.type === 'text'
? this.parseText()
: this.tok();
}
return this.renderer.listitem(body);
}
case 'loose_item_start': {
var body = '';
while (this.next().type !== 'list_item_end') {
body += this.tok();
}
return this.renderer.listitem(body);
}
case 'html': {
var html = !this.token.pre && !this.options.pedantic
? this.inline.output(this.token.text)
: this.token.text;
return this.renderer.html(html);
}
case 'paragraph': {
return this.renderer.paragraph(this.inline.output(this.token.text));
}
case 'text': {
return this.renderer.paragraph(this.parseText());
}
}
};
/**
* Helpers
*/
function escape(html, encode) {
return html
.replace(!encode ? /&(?!#?\w+;)/g : /&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;');
}
function unescape(html) {
return html.replace(/&([#\w]+);/g, function(_, n) {
n = n.toLowerCase();
if (n === 'colon') return ':';
if (n.charAt(0) === '#') {
return n.charAt(1) === 'x'
? String.fromCharCode(parseInt(n.substring(2), 16))
: String.fromCharCode(+n.substring(1));
}
return '';
});
}
function replace(regex, opt) {
regex = regex.source;
opt = opt || '';
return function self(name, val) {
if (!name) return new RegExp(regex, opt);
val = val.source || val;
val = val.replace(/(^|[^\[])\^/g, '$1');
regex = regex.replace(name, val);
return self;
};
}
function noop() {}
noop.exec = noop;
function merge(obj) {
var i = 1
, target
, key;
for (; i < arguments.length; i++) {
target = arguments[i];
for (key in target) {
if (Object.prototype.hasOwnProperty.call(target, key)) {
obj[key] = target[key];
}
}
}
return obj;
}
/**
* Marked
*/
function marked(src, opt, callback) {
if (callback || typeof opt === 'function') {
if (!callback) {
callback = opt;
opt = null;
}
opt = merge({}, marked.defaults, opt || {});
var highlight = opt.highlight
, tokens
, pending
, i = 0;
try {
tokens = Lexer.lex(src, opt)
} catch (e) {
return callback(e);
}
pending = tokens.length;
var done = function(err) {
if (err) {
opt.highlight = highlight;
return callback(err);
}
var out;
try {
out = Parser.parse(tokens, opt);
} catch (e) {
err = e;
}
opt.highlight = highlight;
return err
? callback(err)
: callback(null, out);
};
if (!highlight || highlight.length < 3) {
return done();
}
delete opt.highlight;
if (!pending) return done();
for (; i < tokens.length; i++) {
(function(token) {
if (token.type !== 'code') {
return --pending || done();
}
return highlight(token.text, token.lang, function(err, code) {
if (err) return done(err);
if (code == null || code === token.text) {
return --pending || done();
}
token.text = code;
token.escaped = true;
--pending || done();
});
})(tokens[i]);
}
return;
}
try {
if (opt) opt = merge({}, marked.defaults, opt);
return Parser.parse(Lexer.lex(src, opt), opt);
} catch (e) {
e.message += '\nPlease report this to https://github.com/chjj/marked.';
if ((opt || marked.defaults).silent) {
return '<p>An error occured:</p><pre>'
+ escape(e.message + '', true)
+ '</pre>';
}
throw e;
}
}
/**
* Options
*/
marked.options =
marked.setOptions = function(opt) {
merge(marked.defaults, opt);
return marked;
};
marked.defaults = {
gfm: true,
tables: true,
breaks: false,
pedantic: false,
sanitize: false,
sanitizer: null,
mangle: true,
smartLists: false,
silent: false,
highlight: null,
langPrefix: 'lang-',
smartypants: false,
headerPrefix: '',
renderer: new Renderer,
xhtml: false
};
/**
* Expose
*/
marked.Parser = Parser;
marked.parser = Parser.parse;
marked.Renderer = Renderer;
marked.Lexer = Lexer;
marked.lexer = Lexer.lex;
marked.InlineLexer = InlineLexer;
marked.inlineLexer = InlineLexer.output;
marked.parse = marked;
if (typeof module !== 'undefined' && typeof exports === 'object') {
module.exports = marked;
} else if (typeof define === 'function' && define.amd) {
define(function() { return marked; });
} else {
this.marked = marked;
}
}).call(function() {
return this || (typeof window !== 'undefined' ? window : global);
}());
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],12:[function(require,module,exports){
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: http://codemirror.net/LICENSE
var CodeMirror = require("codemirror");
CodeMirror.commands.tabAndIndentMarkdownList = function (cm) {
var ranges = cm.listSelections();
var pos = ranges[0].head;
var eolState = cm.getStateAfter(pos.line);
var inList = eolState.list !== false;
if (inList) {
cm.execCommand("indentMore");
return;
}
if (cm.options.indentWithTabs) {
cm.execCommand("insertTab");
}
else {
var spaces = Array(cm.options.tabSize + 1).join(" ");
cm.replaceSelection(spaces);
}
};
CodeMirror.commands.shiftTabAndUnindentMarkdownList = function (cm) {
var ranges = cm.listSelections();
var pos = ranges[0].head;
var eolState = cm.getStateAfter(pos.line);
var inList = eolState.list !== false;
if (inList) {
cm.execCommand("indentLess");
return;
}
if (cm.options.indentWithTabs) {
cm.execCommand("insertTab");
}
else {
var spaces = Array(cm.options.tabSize + 1).join(" ");
cm.replaceSelection(spaces);
}
};
},{"codemirror":6}],13:[function(require,module,exports){
/*global require,module*/
"use strict";
var CodeMirror = require("codemirror");
require("codemirror/addon/edit/continuelist.js");
require("./codemirror/tablist");
require("codemirror/addon/display/fullscreen.js");
require("codemirror/mode/markdown/markdown.js");
require("codemirror/addon/mode/overlay.js");
require("codemirror/mode/gfm/gfm.js");
require("codemirror/mode/xml/xml.js");
require("spell-checker");
var marked = require("marked");
// Some variables
var isMac = /Mac/.test(navigator.platform);
var shortcuts = {
"Cmd-B": toggleBold,
"Cmd-I": toggleItalic,
"Cmd-K": drawLink,
"Cmd-H": toggleHeadingSmaller,
"Shift-Cmd-H": toggleHeadingBigger,
"Cmd-Alt-I": drawImage,
"Cmd-'": toggleBlockquote,
"Cmd-Alt-L": toggleOrderedList,
"Cmd-L": toggleUnorderedList,
"Cmd-Alt-C": toggleCodeBlock,
"Cmd-P": togglePreview
};
var isMobile = function() {
var check = false;
(function(a) {
if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino|android|ipad|playbook|silk/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true;
})(navigator.userAgent || navigator.vendor || window.opera);
return check;
};
/**
* Fix shortcut. Mac use Command, others use Ctrl.
*/
function fixShortcut(name) {
if(isMac) {
name = name.replace("Ctrl", "Cmd");
} else {
name = name.replace("Cmd", "Ctrl");
}
return name;
}
/**
* Create icon element for toolbar.
*/
function createIcon(options, enableTooltips) {
options = options || {};
var el = document.createElement("a");
enableTooltips = (enableTooltips == undefined) ? true : enableTooltips;
if(options.title && enableTooltips) {
el.title = options.title;
if(isMac) {
el.title = el.title.replace("Ctrl", "⌘");
el.title = el.title.replace("Alt", "⌥");
}
}
el.className = options.className;
return el;
}
function createSep() {
var el = document.createElement("i");
el.className = "separator";
el.innerHTML = "|";
return el;
}
/**
* The state of CodeMirror at the given position.
*/
function getState(cm, pos) {
pos = pos || cm.getCursor("start");
var stat = cm.getTokenAt(pos);
if(!stat.type) return {};
var types = stat.type.split(" ");
var ret = {},
data, text;
for(var i = 0; i < types.length; i++) {
data = types[i];
if(data === "strong") {
ret.bold = true;
} else if(data === "variable-2") {
text = cm.getLine(pos.line);
if(/^\s*\d+\.\s/.test(text)) {
ret["ordered-list"] = true;
} else {
ret["unordered-list"] = true;
}
} else if(data === "atom") {
ret.quote = true;
} else if(data === "em") {
ret.italic = true;
} else if(data === "quote") {
ret.quote = true;
} else if(data === "strikethrough") {
ret.strikethrough = true;
} else if(data === "comment") {
ret.code = true;
}
}
return ret;
}
// Saved overflow setting
var saved_overflow = "";
/**
* Toggle full screen of the editor.
*/
function toggleFullScreen(editor) {
// Set fullscreen
var cm = editor.codemirror;
cm.setOption("fullScreen", !cm.getOption("fullScreen"));
// Prevent scrolling on body during fullscreen active
if(cm.getOption("fullScreen")) {
saved_overflow = document.body.style.overflow;
document.body.style.overflow = "hidden";
} else {
document.body.style.overflow = saved_overflow;
}
// Update toolbar class
var wrap = cm.getWrapperElement();
if(!/fullscreen/.test(wrap.previousSibling.className)) {
wrap.previousSibling.className += " fullscreen";
} else {
wrap.previousSibling.className = wrap.previousSibling.className.replace(/\s*fullscreen\b/, "");
}
// Update toolbar button
var toolbarButton = editor.toolbarElements.fullscreen;
if(!/active/.test(toolbarButton.className)) {
toolbarButton.className += " active";
} else {
toolbarButton.className = toolbarButton.className.replace(/\s*active\s*/g, "");
}
// Hide side by side if needed
var sidebyside = cm.getWrapperElement().nextSibling;
if(/editor-preview-active-side/.test(sidebyside.className))
toggleSideBySide(editor);
}
/**
* Action for toggling bold.
*/
function toggleBold(editor) {
_toggleBlock(editor, "bold", editor.options.blockStyles.bold);
}
/**
* Action for toggling italic.
*/
function toggleItalic(editor) {
_toggleBlock(editor, "italic", editor.options.blockStyles.italic);
}
/**
* Action for toggling strikethrough.
*/
function toggleStrikethrough(editor) {
_toggleBlock(editor, "strikethrough", "~~");
}
/**
* Action for toggling code block.
*/
function toggleCodeBlock(editor) {
_toggleBlock(editor, "code", "```\r\n", "\r\n```");
}
/**
* Action for toggling blockquote.
*/
function toggleBlockquote(editor) {
var cm = editor.codemirror;
_toggleLine(cm, "quote");
}
/**
* Action for toggling heading size: normal -> h1 -> h2 -> h3 -> h4 -> h5 -> h6 -> normal
*/
function toggleHeadingSmaller(editor) {
var cm = editor.codemirror;
_toggleHeading(cm, "smaller");
}
/**
* Action for toggling heading size: normal -> h6 -> h5 -> h4 -> h3 -> h2 -> h1 -> normal
*/
function toggleHeadingBigger(editor) {
var cm = editor.codemirror;
_toggleHeading(cm, "bigger");
}
/**
* Action for toggling heading size 1
*/
function toggleHeading1(editor) {
var cm = editor.codemirror;
_toggleHeading(cm, undefined, 1);
}
/**
* Action for toggling heading size 2
*/
function toggleHeading2(editor) {
var cm = editor.codemirror;
_toggleHeading(cm, undefined, 2);
}
/**
* Action for toggling heading size 3
*/
function toggleHeading3(editor) {
var cm = editor.codemirror;
_toggleHeading(cm, undefined, 3);
}
/**
* Action for toggling ul.
*/
function toggleUnorderedList(editor) {
var cm = editor.codemirror;
_toggleLine(cm, "unordered-list");
}
/**
* Action for toggling ol.
*/
function toggleOrderedList(editor) {
var cm = editor.codemirror;
_toggleLine(cm, "ordered-list");
}
/**
* Action for drawing a link.
*/
function drawLink(editor) {
var cm = editor.codemirror;
var stat = getState(cm);
var options = editor.options;
_replaceSelection(cm, stat.link, options.insertTexts.link);
}
/**
* Action for drawing an img.
*/
function drawImage(editor) {
var cm = editor.codemirror;
var stat = getState(cm);
var options = editor.options;
_replaceSelection(cm, stat.image, options.insertTexts.image);
}
/**
* Action for drawing a table.
*/
function drawTable(editor) {
var cm = editor.codemirror;
var stat = getState(cm);
var options = editor.options;
_replaceSelection(cm, stat.table, options.insertTexts.table);
}
/**
* Action for drawing a horizontal rule.
*/
function drawHorizontalRule(editor) {
var cm = editor.codemirror;
var stat = getState(cm);
var options = editor.options;
_replaceSelection(cm, stat.image, options.insertTexts.horizontalRule);
}
/**
* Undo action.
*/
function undo(editor) {
var cm = editor.codemirror;
cm.undo();
cm.focus();
}
/**
* Redo action.
*/
function redo(editor) {
var cm = editor.codemirror;
cm.redo();
cm.focus();
}
/**
* Toggle side by side preview
*/
function toggleSideBySide(editor) {
var cm = editor.codemirror;
var wrapper = cm.getWrapperElement();
var preview = wrapper.nextSibling;
var toolbarButton = editor.toolbarElements["side-by-side"];
if(/editor-preview-active-side/.test(preview.className)) {
preview.className = preview.className.replace(
/\s*editor-preview-active-side\s*/g, ""
);
toolbarButton.className = toolbarButton.className.replace(/\s*active\s*/g, "");
wrapper.className = wrapper.className.replace(/\s*CodeMirror-sided\s*/g, " ");
} else {
// When the preview button is clicked for the first time,
// give some time for the transition from editor.css to fire and the view to slide from right to left,
// instead of just appearing.
setTimeout(function() {
if(!cm.getOption("fullScreen"))
toggleFullScreen(editor);
preview.className += " editor-preview-active-side";
}, 1);
toolbarButton.className += " active";
wrapper.className += " CodeMirror-sided";
}
// Hide normal preview if active
var previewNormal = wrapper.lastChild;
if(/editor-preview-active/.test(previewNormal.className)) {
previewNormal.className = previewNormal.className.replace(
/\s*editor-preview-active\s*/g, ""
);
var toolbar = editor.toolbarElements.preview;
var toolbar_div = wrapper.previousSibling;
toolbar.className = toolbar.className.replace(/\s*active\s*/g, "");
toolbar_div.className = toolbar_div.className.replace(/\s*disabled-for-preview*/g, "");
}
// Start preview with the current text
preview.innerHTML = editor.options.previewRender(editor.value(), preview);
// Updates preview
cm.on("update", function() {
preview.innerHTML = editor.options.previewRender(editor.value(), preview);
});
}
/**
* Preview action.
*/
function togglePreview(editor) {
var cm = editor.codemirror;
var wrapper = cm.getWrapperElement();
var toolbar_div = wrapper.previousSibling;
var toolbar = editor.toolbarElements.preview;
var preview = wrapper.lastChild;
if(!preview || !/editor-preview/.test(preview.className)) {
preview = document.createElement("div");
preview.className = "editor-preview";
wrapper.appendChild(preview);
}
if(/editor-preview-active/.test(preview.className)) {
preview.className = preview.className.replace(
/\s*editor-preview-active\s*/g, ""
);
toolbar.className = toolbar.className.replace(/\s*active\s*/g, "");
toolbar_div.className = toolbar_div.className.replace(/\s*disabled-for-preview*/g, "");
} else {
// When the preview button is clicked for the first time,
// give some time for the transition from editor.css to fire and the view to slide from right to left,
// instead of just appearing.
setTimeout(function() {
preview.className += " editor-preview-active";
}, 1);
toolbar.className += " active";
toolbar_div.className += " disabled-for-preview";
}
preview.innerHTML = editor.options.previewRender(editor.value(), preview);
// Turn off side by side if needed
var sidebyside = cm.getWrapperElement().nextSibling;
if(/editor-preview-active-side/.test(sidebyside.className))
toggleSideBySide(editor);
}
function _replaceSelection(cm, active, startEnd) {
if(/editor-preview-active/.test(cm.getWrapperElement().lastChild.className))
return;
var text;
var start = startEnd[0];
var end = startEnd[1];
var startPoint = cm.getCursor("start");
var endPoint = cm.getCursor("end");
if(active) {
text = cm.getLine(startPoint.line);
start = text.slice(0, startPoint.ch);
end = text.slice(startPoint.ch);
cm.replaceRange(start + end, {
line: startPoint.line,
ch: 0
});
} else {
text = cm.getSelection();
cm.replaceSelection(start + text + end);
startPoint.ch += start.length;
if(startPoint !== endPoint) {
endPoint.ch += start.length;
}
}
cm.setSelection(startPoint, endPoint);
cm.focus();
}
function _toggleHeading(cm, direction, size) {
if(/editor-preview-active/.test(cm.getWrapperElement().lastChild.className))
return;
var startPoint = cm.getCursor("start");
var endPoint = cm.getCursor("end");
for(var i = startPoint.line; i <= endPoint.line; i++) {
(function(i) {
var text = cm.getLine(i);
var currHeadingLevel = text.search(/[^#]/);
if(direction !== undefined) {
if(currHeadingLevel <= 0) {
if(direction == "bigger") {
text = "###### " + text;
} else {
text = "# " + text;
}
} else if(currHeadingLevel == 6 && direction == "smaller") {
text = text.substr(7);
} else if(currHeadingLevel == 1 && direction == "bigger") {
text = text.substr(2);
} else {
if(direction == "bigger") {
text = text.substr(1);
} else {
text = "#" + text;
}
}
} else {
if(size == 1) {
if(currHeadingLevel <= 0) {
text = "# " + text;
} else if(currHeadingLevel == size) {
text = text.substr(currHeadingLevel + 1);
} else {
text = "# " + text.substr(currHeadingLevel + 1);
}
} else if(size == 2) {
if(currHeadingLevel <= 0) {
text = "## " + text;
} else if(currHeadingLevel == size) {
text = text.substr(currHeadingLevel + 1);
} else {
text = "## " + text.substr(currHeadingLevel + 1);
}
} else {
if(currHeadingLevel <= 0) {
text = "### " + text;
} else if(currHeadingLevel == size) {
text = text.substr(currHeadingLevel + 1);
} else {
text = "### " + text.substr(currHeadingLevel + 1);
}
}
}
cm.replaceRange(text, {
line: i,
ch: 0
}, {
line: i,
ch: 99999999999999
});
})(i);
}
cm.focus();
}
function _toggleLine(cm, name) {
if(/editor-preview-active/.test(cm.getWrapperElement().lastChild.className))
return;
var stat = getState(cm);
var startPoint = cm.getCursor("start");
var endPoint = cm.getCursor("end");
var repl = {
"quote": /^(\s*)\>\s+/,
"unordered-list": /^(\s*)(\*|\-|\+)\s+/,
"ordered-list": /^(\s*)\d+\.\s+/
};
var map = {
"quote": "> ",
"unordered-list": "* ",
"ordered-list": "1. "
};
for(var i = startPoint.line; i <= endPoint.line; i++) {
(function(i) {
var text = cm.getLine(i);
if(stat[name]) {
text = text.replace(repl[name], "$1");
} else {
text = map[name] + text;
}
cm.replaceRange(text, {
line: i,
ch: 0
}, {
line: i,
ch: 99999999999999
});
})(i);
}
cm.focus();
}
function _toggleBlock(editor, type, start_chars, end_chars) {
if(/editor-preview-active/.test(editor.codemirror.getWrapperElement().lastChild.className))
return;
end_chars = (typeof end_chars === "undefined") ? start_chars : end_chars;
var cm = editor.codemirror;
var stat = getState(cm);
var text;
var start = start_chars;
var end = end_chars;
var startPoint = cm.getCursor("start");
var endPoint = cm.getCursor("end");
if(stat[type]) {
text = cm.getLine(startPoint.line);
start = text.slice(0, startPoint.ch);
end = text.slice(startPoint.ch);
if(type == "bold") {
start = start.replace(/(\*\*|__)(?![\s\S]*(\*\*|__))/, "");
end = end.replace(/(\*\*|__)/, "");
} else if(type == "italic") {
start = start.replace(/(\*|_)(?![\s\S]*(\*|_))/, "");
end = end.replace(/(\*|_)/, "");
} else if(type == "strikethrough") {
start = start.replace(/(\*\*|~~)(?![\s\S]*(\*\*|~~))/, "");
end = end.replace(/(\*\*|~~)/, "");
}
cm.replaceRange(start + end, {
line: startPoint.line,
ch: 0
}, {
line: startPoint.line,
ch: 99999999999999
});
if(type == "bold" || type == "strikethrough") {
startPoint.ch -= 2;
if(startPoint !== endPoint) {
endPoint.ch -= 2;
}
} else if(type == "italic") {
startPoint.ch -= 1;
if(startPoint !== endPoint) {
endPoint.ch -= 1;
}
}
} else {
text = cm.getSelection();
if(type == "bold") {
text = text.split("**").join("");
text = text.split("__").join("");
} else if(type == "italic") {
text = text.split("*").join("");
text = text.split("_").join("");
} else if(type == "strikethrough") {
text = text.split("~~").join("");
}
cm.replaceSelection(start + text + end);
startPoint.ch += start_chars.length;
endPoint.ch = startPoint.ch + text.length;
}
cm.setSelection(startPoint, endPoint);
cm.focus();
}
// Merge the properties of one object into another.
function _mergeProperties(target, source) {
for(var property in source) {
if(source.hasOwnProperty(property)) {
if(source[property] instanceof Array) {
target[property] = source[property].concat(target[property] instanceof Array ? target[property] : []);
} else if(
source[property] !== null &&
typeof source[property] === "object" &&
source[property].constructor === Object
) {
target[property] = _mergeProperties(target[property] || {}, source[property]);
} else {
target[property] = source[property];
}
}
}
return target;
}
// Merge an arbitrary number of objects into one.
function extend(target) {
for(var i = 1; i < arguments.length; i++) {
target = _mergeProperties(target, arguments[i]);
}
return target;
}
/* The right word count in respect for CJK. */
function wordCount(data) {
var pattern = /[a-zA-Z0-9_\u0392-\u03c9]+|[\u4E00-\u9FFF\u3400-\u4dbf\uf900-\ufaff\u3040-\u309f\uac00-\ud7af]+/g;
var m = data.match(pattern);
var count = 0;
if(m === null) return count;
for(var i = 0; i < m.length; i++) {
if(m[i].charCodeAt(0) >= 0x4E00) {
count += m[i].length;
} else {
count += 1;
}
}
return count;
}
var toolbarBuiltInButtons = {
"bold": {
name: "bold",
action: toggleBold,
className: "fa fa-bold",
title: "Bold (Ctrl+B)"
},
"italic": {
name: "italic",
action: toggleItalic,
className: "fa fa-italic",
title: "Italic (Ctrl+I)"
},
"strikethrough": {
name: "strikethrough",
action: toggleStrikethrough,
className: "fa fa-strikethrough",
title: "Strikethrough"
},
"heading": {
name: "heading",
action: toggleHeadingSmaller,
className: "fa fa-header",
title: "Heading (Ctrl+H)"
},
"heading-smaller": {
name: "heading-smaller",
action: toggleHeadingSmaller,
className: "fa fa-header fa-header-x fa-header-smaller",
title: "Smaller Heading (Ctrl+H)"
},
"heading-bigger": {
name: "heading-bigger",
action: toggleHeadingBigger,
className: "fa fa-header fa-header-x fa-header-bigger",
title: "Bigger Heading (Shift+Ctrl+H)"
},
"heading-1": {
name: "heading-1",
action: toggleHeading1,
className: "fa fa-header fa-header-x fa-header-1",
title: "Big Heading"
},
"heading-2": {
name: "heading-2",
action: toggleHeading2,
className: "fa fa-header fa-header-x fa-header-2",
title: "Medium Heading"
},
"heading-3": {
name: "heading-3",
action: toggleHeading3,
className: "fa fa-header fa-header-x fa-header-3",
title: "Small Heading"
},
"code": {
name: "code",
action: toggleCodeBlock,
className: "fa fa-code",
title: "Code (Ctrl+Alt+C)"
},
"quote": {
name: "quote",
action: toggleBlockquote,
className: "fa fa-quote-left",
title: "Quote (Ctrl+')"
},
"unordered-list": {
name: "unordered-list",
action: toggleUnorderedList,
className: "fa fa-list-ul",
title: "Generic List (Ctrl+L)"
},
"ordered-list": {
name: "ordered-list",
action: toggleOrderedList,
className: "fa fa-list-ol",
title: "Numbered List (Ctrl+Alt+L)"
},
"link": {
name: "link",
action: drawLink,
className: "fa fa-link",
title: "Create Link (Ctrl+K)"
},
"image": {
name: "image",
action: drawImage,
className: "fa fa-picture-o",
title: "Insert Image (Ctrl+Alt+I)"
},
"table": {
name: "table",
action: drawTable,
className: "fa fa-table",
title: "Insert Table"
},
"horizontal-rule": {
name: "horizontal-rule",
action: drawHorizontalRule,
className: "fa fa-minus",
title: "Insert Horizontal Line"
},
"preview": {
name: "preview",
action: togglePreview,
className: "fa fa-eye no-disable",
title: "Toggle Preview (Ctrl+P)"
},
"side-by-side": {
name: "side-by-side",
action: toggleSideBySide,
className: "fa fa-columns no-disable no-mobile",
title: "Toggle Side by Side (F9)"
},
"fullscreen": {
name: "fullscreen",
action: toggleFullScreen,
className: "fa fa-arrows-alt no-disable no-mobile",
title: "Toggle Fullscreen (F11)"
},
"guide": {
name: "guide",
action: "http://nextstepwebs.github.io/simplemde-markdown-editor/markdown-guide",
className: "fa fa-question-circle",
title: "Markdown Guide"
}
};
var insertTexts = {
link: ["[", "](http://)"],
image: ["![](http://", ")"],
table: ["", "\n\n| Column 1 | Column 2 | Column 3 |\n| -------- | -------- | -------- |\n| Text | Text | Text |\n\n"],
horizontalRule: ["", "\n\n-----\n\n"]
};
var blockStyles = {
"bold": "**",
"italic": "*"
};
/**
* Interface of SimpleMDE.
*/
function SimpleMDE(options) {
// Handle options parameter
options = options || {};
// Used later to refer to it"s parent
options.parent = this;
// Check if Font Awesome needs to be auto downloaded
var autoDownloadFA = true;
if(options.autoDownloadFontAwesome === false) {
autoDownloadFA = false;
}
if(options.autoDownloadFontAwesome !== true) {
var styleSheets = document.styleSheets;
for(var i = 0; i < styleSheets.length; i++) {
if(!styleSheets[i].href)
continue;
if(styleSheets[i].href.indexOf("//maxcdn.bootstrapcdn.com/font-awesome/") > -1) {
autoDownloadFA = false;
}
}
}
if(autoDownloadFA) {
var link = document.createElement("link");
link.rel = "stylesheet";
link.href = "https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css";
document.getElementsByTagName("head")[0].appendChild(link);
}
// Find the textarea to use
if(options.element) {
this.element = options.element;
} else if(options.element === null) {
// This means that the element option was specified, but no element was found
console.log("SimpleMDE: Error. No element was found.");
return;
}
// Handle toolbar and status bar
if(options.toolbar !== false)
options.toolbar = options.toolbar || SimpleMDE.toolbar;
if(!options.hasOwnProperty("status")) {
options.status = ["autosave", "lines", "words", "cursor"];
}
// Add default preview rendering function
if(!options.previewRender) {
options.previewRender = function(plainText) {
// Note: "this" refers to the options object
return this.parent.markdown(plainText);
};
}
// Set default options for parsing config
options.parsingConfig = options.parsingConfig || {};
// Merging the insertTexts, with the given options
options.insertTexts = extend({}, insertTexts, options.insertTexts || {});
// Merging the blockStyles, with the given options
options.blockStyles = extend({}, blockStyles, options.blockStyles || {});
// Change unique_id to uniqueId for backwards compatibility
if(options.autosave != undefined && options.autosave.unique_id != undefined && options.autosave.unique_id != "")
options.autosave.uniqueId = options.autosave.unique_id;
// Update this options
this.options = options;
// Auto render
this.render();
// The codemirror component is only available after rendering
// so, the setter for the initialValue can only run after
// the element has been rendered
if(options.initialValue) {
this.value(options.initialValue);
}
}
/**
* Default toolbar elements.
*/
SimpleMDE.toolbar = ["bold", "italic", "heading", "|", "quote", "unordered-list", "ordered-list", "|", "link", "image", "|", "preview", "side-by-side", "fullscreen", "guide"];
/**
* Default markdown render.
*/
SimpleMDE.prototype.markdown = function(text) {
if(marked) {
// Initialize
var markedOptions = {};
// Update options
if(this.options && this.options.renderingConfig && this.options.renderingConfig.singleLineBreaks !== false) {
markedOptions.breaks = true;
}
if(this.options && this.options.renderingConfig && this.options.renderingConfig.codeSyntaxHighlighting === true && window.hljs) {
markedOptions.highlight = function(code) {
return window.hljs.highlightAuto(code).value;
};
}
// Set options
marked.setOptions(markedOptions);
// Return
return marked(text);
}
};
/**
* Render editor to the given element.
*/
SimpleMDE.prototype.render = function(el) {
if(!el) {
el = this.element || document.getElementsByTagName("textarea")[0];
}
if(this._rendered && this._rendered === el) {
// Already rendered.
return;
}
this.element = el;
var options = this.options;
var self = this;
var keyMaps = {};
for(var key in shortcuts) {
(function(key) {
keyMaps[fixShortcut(key)] = function() {
shortcuts[key](self);
};
})(key);
}
keyMaps["Enter"] = "newlineAndIndentContinueMarkdownList";
keyMaps["Tab"] = "tabAndIndentMarkdownList";
keyMaps["Shift-Tab"] = "shiftTabAndUnindentMarkdownList";
keyMaps["F11"] = function() {
toggleFullScreen(self);
};
keyMaps["F9"] = function() {
toggleSideBySide(self);
};
keyMaps["Esc"] = function(cm) {
if(cm.getOption("fullScreen")) toggleFullScreen(self);
};
var mode, backdrop;
if(options.spellChecker !== false) {
mode = "spell-checker";
backdrop = options.parsingConfig;
backdrop.name = "gfm";
backdrop.gitHubSpice = false;
} else {
mode = options.parsingConfig;
mode.name = "gfm";
mode.gitHubSpice = false;
}
this.codemirror = CodeMirror.fromTextArea(el, {
mode: mode,
backdrop: backdrop,
theme: "paper",
tabSize: (options.tabSize != undefined) ? options.tabSize : 2,
indentUnit: (options.tabSize != undefined) ? options.tabSize : 2,
indentWithTabs: (options.indentWithTabs === false) ? false : true,
lineNumbers: false,
autofocus: (options.autofocus === true) ? true : false,
extraKeys: keyMaps,
lineWrapping: (options.lineWrapping === false) ? false : true,
allowDropFileTypes: ["text/plain"]
});
if(options.toolbar !== false) {
this.createToolbar();
}
if(options.status !== false) {
this.createStatusbar();
}
if(options.autosave != undefined && options.autosave.enabled === true) {
this.autosave();
}
this.createSideBySide();
this._rendered = this.element;
};
SimpleMDE.prototype.autosave = function() {
if(localStorage) {
var simplemde = this;
if(this.options.autosave.uniqueId == undefined || this.options.autosave.uniqueId == "") {
console.log("SimpleMDE: You must set a uniqueId to use the autosave feature");
return;
}
if(simplemde.element.form != null && simplemde.element.form != undefined) {
simplemde.element.form.addEventListener("submit", function() {
localStorage.removeItem("smde_" + simplemde.options.autosave.uniqueId);
});
}
if(this.options.autosave.loaded !== true) {
if(typeof localStorage.getItem("smde_" + this.options.autosave.uniqueId) == "string" && localStorage.getItem("smde_" + this.options.autosave.uniqueId) != "")
this.codemirror.setValue(localStorage.getItem("smde_" + this.options.autosave.uniqueId));
this.options.autosave.loaded = true;
}
localStorage.setItem("smde_" + this.options.autosave.uniqueId, simplemde.value());
var el = document.getElementById("autosaved");
if(el != null && el != undefined && el != "") {
var d = new Date();
var hh = d.getHours();
var m = d.getMinutes();
var dd = "am";
var h = hh;
if(h >= 12) {
h = hh - 12;
dd = "pm";
}
if(h == 0) {
h = 12;
}
m = m < 10 ? "0" + m : m;
el.innerHTML = "Autosaved: " + h + ":" + m + " " + dd;
}
setTimeout(function() {
simplemde.autosave();
}, this.options.autosave.delay || 10000);
} else {
console.log("SimpleMDE: localStorage not available, cannot autosave");
}
};
SimpleMDE.prototype.clearAutosavedValue = function() {
if(localStorage) {
if(this.options.autosave.uniqueId == undefined || this.options.autosave.uniqueId == "") {
console.log("SimpleMDE: You must set a uniqueId to use the autosave feature");
return;
}
localStorage.removeItem("smde_" + this.options.autosave.uniqueId);
} else {
console.log("SimpleMDE: localStorage not available, cannot autosave");
}
};
SimpleMDE.prototype.createSideBySide = function() {
var cm = this.codemirror;
var wrapper = cm.getWrapperElement();
var preview = wrapper.nextSibling;
if(!preview || !/editor-preview-side/.test(preview.className)) {
preview = document.createElement("div");
preview.className = "editor-preview-side";
wrapper.parentNode.insertBefore(preview, wrapper.nextSibling);
}
// Syncs scroll editor -> preview
var cScroll = false;
var pScroll = false;
cm.on("scroll", function(v) {
if(cScroll) {
cScroll = false;
return;
}
pScroll = true;
var height = v.getScrollInfo().height - v.getScrollInfo().clientHeight;
var ratio = parseFloat(v.getScrollInfo().top) / height;
var move = (preview.scrollHeight - preview.clientHeight) * ratio;
preview.scrollTop = move;
});
// Syncs scroll preview -> editor
preview.onscroll = function() {
if(pScroll) {
pScroll = false;
return;
}
cScroll = true;
var height = preview.scrollHeight - preview.clientHeight;
var ratio = parseFloat(preview.scrollTop) / height;
var move = (cm.getScrollInfo().height - cm.getScrollInfo().clientHeight) * ratio;
cm.scrollTo(0, move);
};
return true;
};
SimpleMDE.prototype.createToolbar = function(items) {
items = items || this.options.toolbar;
if(!items || items.length === 0) {
return;
}
var i;
for(i = 0; i < items.length; i++) {
if(toolbarBuiltInButtons[items[i]] != undefined) {
items[i] = toolbarBuiltInButtons[items[i]];
}
}
var bar = document.createElement("div");
bar.className = "editor-toolbar";
var self = this;
var toolbar_data = {};
self.toolbar = items;
for(i = 0; i < items.length; i++) {
if(items[i].name == "guide" && self.options.toolbarGuideIcon === false)
continue;
if(self.options.hideIcons && self.options.hideIcons.indexOf(items[i].name) != -1)
continue;
// Fullscreen does not work well on mobile devices (even tablets)
// In the future, hopefully this can be resolved
if((items[i].name == "fullscreen" || items[i].name == "side-by-side") && isMobile())
continue;
(function(item) {
var el;
if(item === "|") {
el = createSep();
} else {
el = createIcon(item, self.options.toolbarTips);
}
// bind events, special for info
if(item.action) {
if(typeof item.action === "function") {
el.onclick = function() {
item.action(self);
};
} else if(typeof item.action === "string") {
el.href = item.action;
el.target = "_blank";
}
}
toolbar_data[item.name || item] = el;
bar.appendChild(el);
})(items[i]);
}
self.toolbarElements = toolbar_data;
var cm = this.codemirror;
cm.on("cursorActivity", function() {
var stat = getState(cm);
for(var key in toolbar_data) {
(function(key) {
var el = toolbar_data[key];
if(stat[key]) {
el.className += " active";
} else if(key != "fullscreen" && key != "side-by-side") {
el.className = el.className.replace(/\s*active\s*/g, "");
}
})(key);
}
});
var cmWrapper = cm.getWrapperElement();
cmWrapper.parentNode.insertBefore(bar, cmWrapper);
return bar;
};
SimpleMDE.prototype.createStatusbar = function(status) {
status = status || this.options.status;
var options = this.options;
if(!status || status.length === 0) return;
var bar = document.createElement("div");
bar.className = "editor-statusbar";
var pos, cm = this.codemirror;
for(var i = 0; i < status.length; i++) {
(function(name) {
var el = document.createElement("span");
el.className = name;
if(name === "words") {
el.innerHTML = "0";
cm.on("update", function() {
el.innerHTML = wordCount(cm.getValue());
});
} else if(name === "lines") {
el.innerHTML = "0";
cm.on("update", function() {
el.innerHTML = cm.lineCount();
});
} else if(name === "cursor") {
el.innerHTML = "0:0";
cm.on("cursorActivity", function() {
pos = cm.getCursor();
el.innerHTML = pos.line + ":" + pos.ch;
});
} else if(name === "autosave") {
if(options.autosave != undefined && options.autosave.enabled === true) {
el.setAttribute("id", "autosaved");
}
}
bar.appendChild(el);
})(status[i]);
}
var cmWrapper = this.codemirror.getWrapperElement();
cmWrapper.parentNode.insertBefore(bar, cmWrapper.nextSibling);
return bar;
};
/**
* Get or set the text content.
*/
SimpleMDE.prototype.value = function(val) {
if(val === undefined) {
return this.codemirror.getValue();
} else {
this.codemirror.getDoc().setValue(val);
return this;
}
};
/**
* Bind static methods for exports.
*/
SimpleMDE.toggleBold = toggleBold;
SimpleMDE.toggleItalic = toggleItalic;
SimpleMDE.toggleStrikethrough = toggleStrikethrough;
SimpleMDE.toggleBlockquote = toggleBlockquote;
SimpleMDE.toggleHeadingSmaller = toggleHeadingSmaller;
SimpleMDE.toggleHeadingBigger = toggleHeadingBigger;
SimpleMDE.toggleHeading1 = toggleHeading1;
SimpleMDE.toggleHeading2 = toggleHeading2;
SimpleMDE.toggleHeading3 = toggleHeading3;
SimpleMDE.toggleCodeBlock = toggleCodeBlock;
SimpleMDE.toggleUnorderedList = toggleUnorderedList;
SimpleMDE.toggleOrderedList = toggleOrderedList;
SimpleMDE.drawLink = drawLink;
SimpleMDE.drawImage = drawImage;
SimpleMDE.drawTable = drawTable;
SimpleMDE.drawHorizontalRule = drawHorizontalRule;
SimpleMDE.undo = undo;
SimpleMDE.redo = redo;
SimpleMDE.togglePreview = togglePreview;
SimpleMDE.toggleSideBySide = toggleSideBySide;
SimpleMDE.toggleFullScreen = toggleFullScreen;
/**
* Bind instance methods for exports.
*/
SimpleMDE.prototype.toggleBold = function() {
toggleBold(this);
};
SimpleMDE.prototype.toggleItalic = function() {
toggleItalic(this);
};
SimpleMDE.prototype.toggleStrikethrough = function() {
toggleStrikethrough(this);
};
SimpleMDE.prototype.toggleBlockquote = function() {
toggleBlockquote(this);
};
SimpleMDE.prototype.toggleHeadingSmaller = function() {
toggleHeadingSmaller(this);
};
SimpleMDE.prototype.toggleHeadingBigger = function() {
toggleHeadingBigger(this);
};
SimpleMDE.prototype.toggleHeading1 = function() {
toggleHeading1(this);
};
SimpleMDE.prototype.toggleHeading2 = function() {
toggleHeading2(this);
};
SimpleMDE.prototype.toggleHeading3 = function() {
toggleHeading3(this);
};
SimpleMDE.prototype.toggleCodeBlock = function() {
toggleCodeBlock(this);
};
SimpleMDE.prototype.toggleUnorderedList = function() {
toggleUnorderedList(this);
};
SimpleMDE.prototype.toggleOrderedList = function() {
toggleOrderedList(this);
};
SimpleMDE.prototype.drawLink = function() {
drawLink(this);
};
SimpleMDE.prototype.drawImage = function() {
drawImage(this);
};
SimpleMDE.prototype.drawTable = function() {
drawTable(this);
};
SimpleMDE.prototype.drawHorizontalRule = function() {
drawHorizontalRule(this);
};
SimpleMDE.prototype.undo = function() {
undo(this);
};
SimpleMDE.prototype.redo = function() {
redo(this);
};
SimpleMDE.prototype.togglePreview = function() {
togglePreview(this);
};
SimpleMDE.prototype.toggleSideBySide = function() {
toggleSideBySide(this);
};
SimpleMDE.prototype.toggleFullScreen = function() {
toggleFullScreen(this);
};
SimpleMDE.prototype.isPreviewActive = function() {
var cm = this.codemirror;
var wrapper = cm.getWrapperElement();
var preview = wrapper.lastChild;
return /editor-preview-active/.test(preview.className);
};
SimpleMDE.prototype.isSideBySideActive = function() {
var cm = this.codemirror;
var wrapper = cm.getWrapperElement();
var preview = wrapper.nextSibling;
return /editor-preview-active-side/.test(preview.className);
};
SimpleMDE.prototype.isFullscreenActive = function() {
var cm = this.codemirror;
return cm.getOption("fullScreen");
};
module.exports = SimpleMDE;
},{"./codemirror/tablist":12,"codemirror":6,"codemirror/addon/display/fullscreen.js":3,"codemirror/addon/edit/continuelist.js":4,"codemirror/addon/mode/overlay.js":5,"codemirror/mode/gfm/gfm.js":7,"codemirror/mode/markdown/markdown.js":8,"codemirror/mode/xml/xml.js":10,"marked":11,"spell-checker":1}]},{},[13])(13)
});
//# sourceMappingURL=data:application/json;charset:utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvY29kZW1pcnJvci1zcGVsbC1jaGVja2VyL3NyYy9qcy9zcGVsbC1jaGVja2VyLmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3Itc3BlbGwtY2hlY2tlci9zcmMvanMvdHlwby5qcyIsIm5vZGVfbW9kdWxlcy9jb2RlbWlycm9yL2FkZG9uL2Rpc3BsYXkvZnVsbHNjcmVlbi5qcyIsIm5vZGVfbW9kdWxlcy9jb2RlbWlycm9yL2FkZG9uL2VkaXQvY29udGludWVsaXN0LmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3IvYWRkb24vbW9kZS9vdmVybGF5LmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3IvbGliL2NvZGVtaXJyb3IuanMiLCJub2RlX21vZHVsZXMvY29kZW1pcnJvci9tb2RlL2dmbS9nZm0uanMiLCJub2RlX21vZHVsZXMvY29kZW1pcnJvci9tb2RlL21hcmtkb3duL21hcmtkb3duLmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3IvbW9kZS9tZXRhLmpzIiwibm9kZV9tb2R1bGVzL2NvZGVtaXJyb3IvbW9kZS94bWwveG1sLmpzIiwibm9kZV9tb2R1bGVzL21hcmtlZC9saWIvbWFya2VkLmpzIiwic3JjL2pzL2NvZGVtaXJyb3IvdGFibGlzdC5qcyIsInNyYy9qcy9zaW1wbGVtZGUuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUNqR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDbHdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlxUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ255QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUNqWUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ3J3Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoiZ2VuZXJhdGVkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXNDb250ZW50IjpbIihmdW5jdGlvbiBlKHQsbixyKXtmdW5jdGlvbiBzKG8sdSl7aWYoIW5bb10pe2lmKCF0W29dKXt2YXIgYT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2lmKCF1JiZhKXJldHVybiBhKG8sITApO2lmKGkpcmV0dXJuIGkobywhMCk7dmFyIGY9bmV3IEVycm9yKFwiQ2Fubm90IGZpbmQgbW9kdWxlICdcIitvK1wiJ1wiKTt0aHJvdyBmLmNvZGU9XCJNT0RVTEVfTk9UX0ZPVU5EXCIsZn12YXIgbD1uW29dPXtleHBvcnRzOnt9fTt0W29dWzBdLmNhbGwobC5leHBvcnRzLGZ1bmN0aW9uKGUpe3ZhciBuPXRbb11bMV1bZV07cmV0dXJuIHMobj9uOmUpfSxsLGwuZXhwb3J0cyxlLHQsbixyKX1yZXR1cm4gbltvXS5leHBvcnRzfXZhciBpPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7Zm9yKHZhciBvPTA7bzxyLmxlbmd0aDtvKyspcyhyW29dKTtyZXR1cm4gc30pIiwiXG47IFR5cG8gPSBnbG9iYWwuVHlwbyA9IHJlcXVpcmUoXCJEOlxcXFxNeSBXZWIgU2l0ZXNcXFxcc2ltcGxlbWRlLW1hcmtkb3duLWVkaXRvclxcXFxub2RlX21vZHVsZXNcXFxcY29kZW1pcnJvci1zcGVsbC1jaGVja2VyXFxcXHNyY1xcXFxqc1xcXFx0eXBvLmpzXCIpO1xuQ29kZU1pcnJvciA9IGdsb2JhbC5Db2RlTWlycm9yID0gcmVxdWlyZShcImNvZGVtaXJyb3JcIik7XG47IHZhciBfX2Jyb3dzZXJpZnlfc2hpbV9yZXF1aXJlX189cmVxdWlyZTsoZnVuY3Rpb24gYnJvd3NlcmlmeVNoaW0obW9kdWxlLCBkZWZpbmUsIHJlcXVpcmUpIHtcbi8vIEluaXRpYWxpemUgZGF0YSBnbG9iYWxseSB0byByZWR1Y2UgbWVtb3J5IGNvbnN1bXB0aW9uXHJcbnZhciBudW1fbG9hZGVkID0gMDtcclxudmFyIGFmZl9sb2FkaW5nID0gZmFsc2U7XHJcbnZhciBkaWNfbG9hZGluZyA9IGZhbHNlO1xyXG52YXIgYWZmX2RhdGEgPSBcIlwiO1xyXG52YXIgZGljX2RhdGEgPSBcIlwiO1xyXG52YXIgdHlwbztcclxuXHJcblxyXG5Db2RlTWlycm9yLmRlZmluZU1vZGUoXCJzcGVsbC1jaGVja2VyXCIsIGZ1bmN0aW9uKGNvbmZpZywgcGFyc2VyQ29uZmlnKSB7XHJcblx0Ly8gTG9hZCBBRkYvRElDIGRhdGFcclxuXHRpZighYWZmX2xvYWRpbmcpe1xyXG5cdFx0YWZmX2xvYWRpbmcgPSB0cnVlO1xyXG5cdFx0dmFyIHhocl9hZmYgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTtcclxuXHRcdHhocl9hZmYub3BlbihcIkdFVFwiLCBcImh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9jb2RlbWlycm9yLnNwZWxsLWNoZWNrZXIvbGF0ZXN0L2VuX1VTLmFmZlwiLCB0cnVlKTtcclxuXHRcdHhocl9hZmYub25sb2FkID0gZnVuY3Rpb24gKGUpIHtcclxuXHRcdFx0aWYgKHhocl9hZmYucmVhZHlTdGF0ZSA9PT0gNCAmJiB4aHJfYWZmLnN0YXR1cyA9PT0gMjAwKSB7XHJcblx0XHRcdFx0YWZmX2RhdGEgPSB4aHJfYWZmLnJlc3BvbnNlVGV4dDtcclxuXHRcdFx0XHRudW1fbG9hZGVkKys7XHJcblx0XHRcdFx0XHJcblx0XHRcdFx0aWYobnVtX2xvYWRlZCA9PSAyKXtcclxuXHRcdFx0XHRcdHR5cG8gPSBuZXcgVHlwbyhcImVuX1VTXCIsIGFmZl9kYXRhLCBkaWNfZGF0YSwge1xyXG5cdFx0XHRcdFx0XHRwbGF0Zm9ybTogJ2FueSdcclxuXHRcdFx0XHRcdH0pO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fTtcclxuXHRcdHhocl9hZmYuc2VuZChudWxsKTtcclxuXHR9XHJcblx0XHJcblx0aWYoIWRpY19sb2FkaW5nKXtcclxuXHRcdGRpY19sb2FkaW5nID0gdHJ1ZTtcclxuXHRcdHZhciB4aHJfZGljID0gbmV3IFhNTEh0dHBSZXF1ZXN0KCk7XHJcblx0XHR4aHJfZGljLm9wZW4oXCJHRVRcIiwgXCJodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvY29kZW1pcnJvci5zcGVsbC1jaGVja2VyL2xhdGVzdC9lbl9VUy5kaWNcIiwgdHJ1ZSk7XHJcblx0XHR4aHJfZGljLm9ubG9hZCA9IGZ1bmN0aW9uIChlKSB7XHJcblx0XHRcdGlmICh4aHJfZGljLnJlYWR5U3RhdGUgPT09IDQgJiYgeGhyX2RpYy5zdGF0dXMgPT09IDIwMCkge1xyXG5cdFx0XHRcdGRpY19kYXRhID0geGhyX2RpYy5yZXNwb25zZVRleHQ7XHJcblx0XHRcdFx0bnVtX2xvYWRlZCsrO1xyXG5cdFx0XHRcdFxyXG5cdFx0XHRcdGlmKG51bV9sb2FkZWQgPT0gMil7XHJcblx0XHRcdFx0XHR0eXBvID0gbmV3IFR5cG8oXCJlbl9VU1wiLCBhZmZfZGF0YSwgZGljX2RhdGEsIHtcclxuXHRcdFx0XHRcdFx0cGxhdGZvcm06ICdhbnknXHJcblx0XHRcdFx0XHR9KTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblx0XHR4aHJfZGljLnNlbmQobnVsbCk7XHJcblx0fVxyXG5cclxuXHRcclxuXHRcclxuXHQvLyBEZWZpbmUgd2hhdCBzZXBhcmF0ZXMgYSB3b3JkXHJcblx0dmFyIHJ4X3dvcmQgPSBcIiFcXFwiIyQlJigpKissLS4vOjs8PT4/QFtcXFxcXV5fYHt8fX4gXCI7XHJcblx0XHJcblx0XHJcblx0Ly8gQ3JlYXRlIHRoZSBvdmVybGF5IGFuZCBzdWNoXHJcblx0dmFyIG92ZXJsYXkgPSB7XHJcblx0XHR0b2tlbjogZnVuY3Rpb24oc3RyZWFtLCBzdGF0ZSkge1xyXG5cdFx0XHR2YXIgY2ggPSBzdHJlYW0ucGVlaygpO1xyXG5cdFx0XHR2YXIgd29yZCA9IFwiXCI7XHJcblxyXG5cdFx0XHRpZihyeF93b3JkLmluY2x1ZGVzKGNoKSkge1xyXG5cdFx0XHRcdHN0cmVhbS5uZXh0KCk7XHJcblx0XHRcdFx0cmV0dXJuIG51bGw7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHdoaWxlKChjaCA9IHN0cmVhbS5wZWVrKCkpICE9IG51bGwgJiYgIXJ4X3dvcmQuaW5jbHVkZXMoY2gpKSB7XHJcblx0XHRcdFx0d29yZCArPSBjaDtcclxuXHRcdFx0XHRzdHJlYW0ubmV4dCgpO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZih0eXBvICYmICF0eXBvLmNoZWNrKHdvcmQpKVxyXG5cdFx0XHRcdHJldHVybiBcInNwZWxsLWVycm9yXCI7IC8vIENTUyBjbGFzczogY20tc3BlbGwtZXJyb3JcclxuXHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cdFx0fVxyXG5cdH07XHJcblxyXG5cdHZhciBtb2RlID0gQ29kZU1pcnJvci5nZXRNb2RlKFxyXG5cdFx0Y29uZmlnLCBjb25maWcuYmFja2Ryb3AgfHwgXCJ0ZXh0L3BsYWluXCJcclxuXHQpO1xyXG5cclxuXHRyZXR1cm4gQ29kZU1pcnJvci5vdmVybGF5TW9kZShtb2RlLCBvdmVybGF5LCB0cnVlKTtcclxufSk7XHJcblxyXG5cclxuLy8gQmVjYXVzZSBzb21lIGJyb3dzZXJzIGRvbid0IHN1cHBvcnQgdGhpcyBmdW5jdGlvbmFsaXR5IHlldFxyXG5pZighU3RyaW5nLnByb3RvdHlwZS5pbmNsdWRlcykge1xyXG5cdFN0cmluZy5wcm90b3R5cGUuaW5jbHVkZXMgPSBmdW5jdGlvbigpIHsndXNlIHN0cmljdCc7XHJcblx0XHRyZXR1cm4gU3RyaW5nLnByb3RvdHlwZS5pbmRleE9mLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgIT09IC0xO1xyXG5cdH07XHJcbn1cbn0pLmNhbGwoZ2xvYmFsLCBtb2R1bGUsIHVuZGVmaW5lZCwgdW5kZWZpbmVkKTtcbiIsIjsgdmFyIF9fYnJvd3NlcmlmeV9zaGltX3JlcXVpcmVfXz1yZXF1aXJlOyhmdW5jdGlvbiBicm93c2VyaWZ5U2hpbShtb2R1bGUsIGV4cG9ydHMsIHJlcXVpcmUsIGRlZmluZSwgYnJvd3NlcmlmeV9zaGltX19kZWZpbmVfX21vZHVsZV9fZXhwb3J0X18pIHtcbid1c2Ugc3RyaWN0JztcclxuXHJcbi8qKlxyXG4gKiBUeXBvIGlzIGEgSmF2YVNjcmlwdCBpbXBsZW1lbnRhdGlvbiBvZiBhIHNwZWxsY2hlY2tlciB1c2luZyBodW5zcGVsbC1zdHlsZVxyXG4gKiBkaWN0aW9uYXJpZXMuXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIFR5cG8gY29uc3RydWN0b3IuXHJcbiAqXHJcbiAqIEBwYXJhbSB7U3RyaW5nfSBbZGljdGlvbmFyeV0gVGhlIGxvY2FsZSBjb2RlIG9mIHRoZSBkaWN0aW9uYXJ5IGJlaW5nIHVzZWQuIGUuZy4sXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJlbl9VU1wiLiBUaGlzIGlzIG9ubHkgdXNlZCB0byBhdXRvLWxvYWQgZGljdGlvbmFyaWVzLlxyXG4gKiBAcGFyYW0ge1N0cmluZ30gW2FmZkRhdGFdIFRoZSBkYXRhIGZyb20gdGhlIGRpY3Rpb25hcnkncyAuYWZmIGZpbGUuIElmIG9taXR0ZWRcclxuICogICAgICAgICAgICAgICAgICAgICAgICAgICBhbmQgdGhlIGZpcnN0IGFyZ3VtZW50IGlzIHN1cHBsaWVkLCBpbiBcImNocm9tZVwiIHBsYXRmb3JtLFxyXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoZSAuYWZmIGZpbGUgd2lsbCBiZSBsb2FkZWQgYXV0b21hdGljYWxseSBmcm9tXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgbGliL3R5cG8vZGljdGlvbmFyaWVzL1tkaWN0aW9uYXJ5XS9bZGljdGlvbmFyeV0uYWZmXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgSW4gb3RoZXIgcGxhdGZvcm0sIGl0IHdpbGwgYmUgbG9hZGVkIGZyb21cclxuICogICAgICAgICAgICAgICAgICAgICAgICAgICBbc2V0dGluZy5wYXRoXS9kaWN0aW9uYXJpZXMvW2RpY3Rpb25hcnldL1tkaWN0aW9uYXJ5XS5hZmZcclxuICogQHBhcmFtIHtTdHJpbmd9IFt3b3Jkc0RhdGFdIFRoZSBkYXRhIGZyb20gdGhlIGRpY3Rpb25hcnkncyAuZGljIGZpbGUuIElmIG9taXR0ZWQsXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgYW5kIHRoZSBmaXJzdCBhcmd1bWVudCBpcyBzdXBwbGllZCwgaW4gXCJjaHJvbWVcIiBwbGF0Zm9ybSxcclxuICogICAgICAgICAgICAgICAgICAgICAgICAgICB0aGUgLmRpYyBmaWxlIHdpbGwgYmUgbG9hZGVkIGF1dG9tYXRpY2FsbHkgZnJvbVxyXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgIGxpYi90eXBvL2RpY3Rpb25hcmllcy9bZGljdGlvbmFyeV0vW2RpY3Rpb25hcnldLmRpY1xyXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgIEluIG90aGVyIHBsYXRmb3JtLCBpdCB3aWxsIGJlIGxvYWRlZCBmcm9tXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgW3NldHRpbmcucGF0aF0vZGljdGlvbmFyaWVzL1tkaWN0aW9uYXJ5XS9bZGljdGlvbmFyeV0uZGljXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbc2V0dGluZ3NdIENvbnN0cnVjdG9yIHNldHRpbmdzLiBBdmFpbGFibGUgcHJvcGVydGllcyBhcmU6XHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtTdHJpbmd9IFtwbGF0Zm9ybV06IFwiY2hyb21lXCIgZm9yIENocm9tZSBFeHRlbnNpb24gb3Igb3RoZXJcclxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSBmb3IgdGhlIHVzdWFsIHdlYi5cclxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAge1N0cmluZ30gW2RpY3Rpb25hcnlQYXRoXTogcGF0aCB0byBsb2FkIGRpY3Rpb25hcnkgZnJvbSBpbiBub24tY2hyb21lXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW52aXJvbm1lbnQuXHJcbiAqICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtPYmplY3R9IFtmbGFnc106IGZsYWcgaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtUeXBvfSBBIFR5cG8gb2JqZWN0LlxyXG4gKi9cclxuXHJcbnZhciBUeXBvID0gZnVuY3Rpb24gKGRpY3Rpb25hcnksIGFmZkRhdGEsIHdvcmRzRGF0YSwgc2V0dGluZ3MpIHtcclxuXHRzZXR0aW5ncyA9IHNldHRpbmdzIHx8IHt9O1xyXG5cdFxyXG5cdC8qKiBEZXRlcm1pbmVzIHRoZSBtZXRob2QgdXNlZCBmb3IgYXV0by1sb2FkaW5nIC5hZmYgYW5kIC5kaWMgZmlsZXMuICoqL1xyXG5cdHRoaXMucGxhdGZvcm0gPSBzZXR0aW5ncy5wbGF0Zm9ybSB8fCBcImNocm9tZVwiO1xyXG5cdFxyXG5cdHRoaXMuZGljdGlvbmFyeSA9IG51bGw7XHJcblx0XHJcblx0dGhpcy5ydWxlcyA9IHt9O1xyXG5cdHRoaXMuZGljdGlvbmFyeVRhYmxlID0ge307XHJcblx0XHJcblx0dGhpcy5jb21wb3VuZFJ1bGVzID0gW107XHJcblx0dGhpcy5jb21wb3VuZFJ1bGVDb2RlcyA9IHt9O1xyXG5cdFxyXG5cdHRoaXMucmVwbGFjZW1lbnRUYWJsZSA9IFtdO1xyXG5cdFxyXG5cdHRoaXMuZmxhZ3MgPSBzZXR0aW5ncy5mbGFncyB8fCB7fTtcclxuXHRcclxuXHRpZiAoZGljdGlvbmFyeSkge1xyXG5cdFx0dGhpcy5kaWN0aW9uYXJ5ID0gZGljdGlvbmFyeTtcclxuXHRcdFxyXG5cdFx0aWYgKHRoaXMucGxhdGZvcm0gPT0gXCJjaHJvbWVcIikge1xyXG5cdFx0XHRpZiAoIWFmZkRhdGEpIGFmZkRhdGEgPSB0aGlzLl9yZWFkRmlsZShjaHJvbWUuZXh0ZW5zaW9uLmdldFVSTChcImxpYi90eXBvL2RpY3Rpb25hcmllcy9cIiArIGRpY3Rpb25hcnkgKyBcIi9cIiArIGRpY3Rpb25hcnkgKyBcIi5hZmZcIikpO1xyXG5cdFx0XHRpZiAoIXdvcmRzRGF0YSkgd29yZHNEYXRhID0gdGhpcy5fcmVhZEZpbGUoY2hyb21lLmV4dGVuc2lvbi5nZXRVUkwoXCJsaWIvdHlwby9kaWN0aW9uYXJpZXMvXCIgKyBkaWN0aW9uYXJ5ICsgXCIvXCIgKyBkaWN0aW9uYXJ5ICsgXCIuZGljXCIpKTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdHZhciBwYXRoID0gc2V0dGluZ3MuZGljdGlvbmFyeVBhdGggfHwgJyc7XHJcblx0XHRcdFxyXG5cdFx0XHRpZiAoIWFmZkRhdGEpIGFmZkRhdGEgPSB0aGlzLl9yZWFkRmlsZShwYXRoICsgXCIvXCIgKyBkaWN0aW9uYXJ5ICsgXCIvXCIgKyBkaWN0aW9uYXJ5ICsgXCIuYWZmXCIpO1xyXG5cdFx0XHRpZiAoIXdvcmRzRGF0YSkgd29yZHNEYXRhID0gdGhpcy5fcmVhZEZpbGUocGF0aCArIFwiL1wiICsgZGljdGlvbmFyeSArIFwiL1wiICsgZGljdGlvbmFyeSArIFwiLmRpY1wiKTtcclxuXHRcdH1cclxuXHRcdFxyXG5cdFx0dGhpcy5ydWxlcyA9IHRoaXMuX3BhcnNlQUZGKGFmZkRhdGEpO1xyXG5cdFx0XHJcblx0XHQvLyBTYXZlIHRoZSBydWxlIGNvZGVzIHRoYXQgYXJlIHVzZWQgaW4gY29tcG91bmQgcnVsZXMuXHJcblx0XHR0aGlzLmNvbXBvdW5kUnVsZUNvZGVzID0ge307XHJcblx0XHRcclxuXHRcdGZvciAodmFyIGkgPSAwLCBfbGVuID0gdGhpcy5jb21wb3VuZFJ1bGVzLmxlbmd0aDsgaSA8IF9sZW47IGkrKykge1xyXG5cdFx0XHR2YXIgcnVsZSA9IHRoaXMuY29tcG91bmRSdWxlc1tpXTtcclxuXHRcdFx0XHJcblx0XHRcdGZvciAodmFyIGogPSAwLCBfamxlbiA9IHJ1bGUubGVuZ3RoOyBqIDwgX2psZW47IGorKykge1xyXG5cdFx0XHRcdHRoaXMuY29tcG91bmRSdWxlQ29kZXNbcnVsZVtqXV0gPSBbXTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdFx0XHJcblx0XHQvLyBJZiB3ZSBhZGQgdGhpcyBPTkxZSU5DT01QT1VORCBmbGFnIHRvIHRoaXMuY29tcG91bmRSdWxlQ29kZXMsIHRoZW4gX3BhcnNlRElDXHJcblx0XHQvLyB3aWxsIGRvIHRoZSB3b3JrIG9mIHNhdmluZyB0aGUgbGlzdCBvZiB3b3JkcyB0aGF0IGFyZSBjb21wb3VuZC1vbmx5LlxyXG5cdFx0aWYgKFwiT05MWUlOQ09NUE9VTkRcIiBpbiB0aGlzLmZsYWdzKSB7XHJcblx0XHRcdHRoaXMuY29tcG91bmRSdWxlQ29kZXNbdGhpcy5mbGFncy5PTkxZSU5DT01QT1VORF0gPSBbXTtcclxuXHRcdH1cclxuXHRcdFxyXG5cdFx0dGhpcy5kaWN0aW9uYXJ5VGFibGUgPSB0aGlzLl9wYXJzZURJQyh3b3Jkc0RhdGEpO1xyXG5cdFx0XHJcblx0XHQvLyBHZXQgcmlkIG9mIGFueSBjb2RlcyBmcm9tIHRoZSBjb21wb3VuZCBydWxlIGNvZGVzIHRoYXQgYXJlIG5ldmVyIHVzZWRcclxuXHRcdC8vIChvciB0aGF0IHdlcmUgc3BlY2lhbCByZWdleCBjaGFyYWN0ZXJzKS4gIE5vdCBlc3BlY2lhbGx5IG5lY2Vzc2FyeS4uLlxyXG5cdFx0Zm9yICh2YXIgaSBpbiB0aGlzLmNvbXBvdW5kUnVsZUNvZGVzKSB7XHJcblx0XHRcdGlmICh0aGlzLmNvbXBvdW5kUnVsZUNvZGVzW2ldLmxlbmd0aCA9PSAwKSB7XHJcblx0XHRcdFx0ZGVsZXRlIHRoaXMuY29tcG91bmRSdWxlQ29kZXNbaV07XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdFxyXG5cdFx0Ly8gQnVpbGQgdGhlIGZ1bGwgcmVndWxhciBleHByZXNzaW9ucyBmb3IgZWFjaCBjb21wb3VuZCBydWxlLlxyXG5cdFx0Ly8gSSBoYXZlIGEgZmVlbGluZyAoYnV0IG5vIGNvbmZpcm1hdGlvbiB5ZXQpIHRoYXQgdGhpcyBtZXRob2Qgb2ZcclxuXHRcdC8vIHRlc3RpbmcgZm9yIGNvbXBvdW5kIHdvcmRzIGlzIHByb2JhYmx5IHNsb3cuXHJcblx0XHRmb3IgKHZhciBpID0gMCwgX2xlbiA9IHRoaXMuY29tcG91bmRSdWxlcy5sZW5ndGg7IGkgPCBfbGVuOyBpKyspIHtcclxuXHRcdFx0dmFyIHJ1bGVUZXh0ID0gdGhpcy5jb21wb3VuZFJ1bGVzW2ldO1xyXG5cdFx0XHRcclxuXHRcdFx0dmFyIGV4cHJlc3Npb25UZXh0ID0gXCJcIjtcclxuXHRcdFx0XHJcblx0XHRcdGZvciAodmFyIGogPSAwLCBfamxlbiA9IHJ1bGVUZXh0Lmxlbmd0aDsgaiA8IF9qbGVuOyBqKyspIHtcclxuXHRcdFx0XHR2YXIgY2hhcmFjdGVyID0gcnVsZVRleHRbal07XHJcblx0XHRcdFx0XHJcblx0XHRcdFx0aWYgKGNoYXJhY3RlciBpbiB0aGlzLmNvbXBvdW5kUnVsZUNvZGVzKSB7XHJcblx0XHRcdFx0XHRleHByZXNzaW9uVGV4dCArPSBcIihcIiArIHRoaXMuY29tcG91bmRSdWxlQ29kZXNbY2hhcmFjdGVyXS5qb2luKFwifFwiKSArIFwiKVwiO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHRlbHNlIHtcclxuXHRcdFx0XHRcdGV4cHJlc3Npb25UZXh0ICs9IGNoYXJhY3RlcjtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHRcdHRoaXMuY29tcG91bmRSdWxlc1tpXSA9IG5ldyBSZWdFeHAoZXhwcmVzc2lvblRleHQsIFwiaVwiKTtcclxuXHRcdH1cclxuXHR9XHJcblx0XHJcblx0cmV0dXJuIHRoaXM7XHJcbn07XHJcblxyXG5UeXBvLnByb3RvdHlwZSA9IHtcclxuXHQvKipcclxuXHQgKiBMb2FkcyBhIFR5cG8gaW5zdGFuY2UgZnJvbSBhIGhhc2ggb2YgYWxsIG9mIHRoZSBUeXBvIHByb3BlcnRpZXMuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gb2JqZWN0IG9iaiBBIGhhc2ggb2YgVHlwbyBwcm9wZXJ0aWVzLCBwcm9iYWJseSBnb3R0ZW4gZnJvbSBhIEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkodHlwb19pbnN0YW5jZSkpLlxyXG5cdCAqL1xyXG5cdFxyXG5cdGxvYWQgOiBmdW5jdGlvbiAob2JqKSB7XHJcblx0XHRmb3IgKHZhciBpIGluIG9iaikge1xyXG5cdFx0XHR0aGlzW2ldID0gb2JqW2ldO1xyXG5cdFx0fVxyXG5cdFx0XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cdFxyXG5cdC8qKlxyXG5cdCAqIFJlYWQgdGhlIGNvbnRlbnRzIG9mIGEgZmlsZS5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBwYXRoIFRoZSBwYXRoIChyZWxhdGl2ZSkgdG8gdGhlIGZpbGUuXHJcblx0ICogQHBhcmFtIHtTdHJpbmd9IFtjaGFyc2V0PVwiSVNPODg1OS0xXCJdIFRoZSBleHBlY3RlZCBjaGFyc2V0IG9mIHRoZSBmaWxlXHJcblx0ICogQHJldHVybnMgc3RyaW5nIFRoZSBmaWxlIGRhdGEuXHJcblx0ICovXHJcblx0XHJcblx0X3JlYWRGaWxlIDogZnVuY3Rpb24gKHBhdGgsIGNoYXJzZXQpIHtcclxuXHRcdGlmICghY2hhcnNldCkgY2hhcnNldCA9IFwiSVNPODg1OS0xXCI7XHJcblx0XHRcclxuXHRcdHZhciByZXEgPSBuZXcgWE1MSHR0cFJlcXVlc3QoKTtcclxuXHRcdHJlcS5vcGVuKFwiR0VUXCIsIHBhdGgsIGZhbHNlKTtcclxuXHRcdFxyXG5cdFx0aWYgKHJlcS5vdmVycmlkZU1pbWVUeXBlKVxyXG5cdFx0XHRyZXEub3ZlcnJpZGVNaW1lVHlwZShcInRleHQvcGxhaW47IGNoYXJzZXQ9XCIgKyBjaGFyc2V0KTtcclxuXHRcdFxyXG5cdFx0cmVxLnNlbmQobnVsbCk7XHJcblx0XHRcclxuXHRcdHJldHVybiByZXEucmVzcG9uc2VUZXh0O1xyXG5cdH0sXHJcblx0XHJcblx0LyoqXHJcblx0ICogUGFyc2UgdGhlIHJ1bGVzIG91dCBmcm9tIGEgLmFmZiBmaWxlLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtTdHJpbmd9IGRhdGEgVGhlIGNvbnRlbnRzIG9mIHRoZSBhZmZpeCBmaWxlLlxyXG5cdCAqIEByZXR1cm5zIG9iamVjdCBUaGUgcnVsZXMgZnJvbSB0aGUgZmlsZS5cclxuXHQgKi9cclxuXHRcclxuXHRfcGFyc2VBRkYgOiBmdW5jdGlvbiAoZGF0YSkge1xyXG5cdFx0dmFyIHJ1bGVzID0ge307XHJcblx0XHRcclxuXHRcdC8vIFJlbW92ZSBjb21tZW50IGxpbmVzXHJcblx0XHRkYXRhID0gdGhpcy5fcmVtb3ZlQWZmaXhDb21tZW50cyhkYXRhKTtcclxuXHRcdFxyXG5cdFx0dmFyIGxpbmVzID0gZGF0YS5zcGxpdChcIlxcblwiKTtcclxuXHRcdFxyXG5cdFx0Zm9yICh2YXIgaSA9IDAsIF9sZW4gPSBsaW5lcy5sZW5ndGg7IGkgPCBfbGVuOyBpKyspIHtcclxuXHRcdFx0dmFyIGxpbmUgPSBsaW5lc1tpXTtcclxuXHRcdFx0XHJcblx0XHRcdHZhciBkZWZpbml0aW9uUGFydHMgPSBsaW5lLnNwbGl0KC9cXHMrLyk7XHJcblx0XHRcdFxyXG5cdFx0XHR2YXIgcnVsZVR5cGUgPSBkZWZpbml0aW9uUGFydHNbMF07XHJcblx0XHRcdFxyXG5cdFx0XHRpZiAocnVsZVR5cGUgPT0gXCJQRlhcIiB8fCBydWxlVHlwZSA9PSBcIlNGWFwiKSB7XHJcblx0XHRcdFx0dmFyIHJ1bGVDb2RlID0gZGVmaW5pdGlvblBhcnRzWzFdO1xyXG5cdFx0XHRcdHZhciBjb21iaW5lYWJsZSA9IGRlZmluaXRpb25QYXJ0c1syXTtcclxuXHRcdFx0XHR2YXIgbnVtRW50cmllcyA9IHBhcnNlSW50KGRlZmluaXRpb25QYXJ0c1szXSwgMTApO1xyXG5cdFx0XHRcdFxyXG5cdFx0XHRcdHZhciBlbnRyaWVzID0gW107XHJcblx0XHRcdFx0XHJcblx0XHRcdFx0Zm9yICh2YXIgaiA9IGkgKyAxLCBfamxlbiA9IGkgKyAxICsgbnVtRW50cmllczsgaiA8IF9qbGVuOyBqKyspIHtcclxuXHRcdFx0XHRcdHZhciBsaW5lID0gbGluZXNbal07XHJcblx0XHRcdFx0XHRcclxuXHRcdFx0XHRcdHZhciBsaW5lUGFydHMgPSBsaW5lLnNwbGl0KC9cXHMrLyk7XHJcblx0XHRcdFx0XHR2YXIgY2hhcmFjdGVyc1RvUmVtb3ZlID0gbGluZVBhcnRzWzJdO1xyXG5cdFx0XHRcdFx0XHJcblx0XHRcdFx0XHR2YXIgYWRkaXRpb25QYXJ0cyA9IGxpbmVQYXJ0c1szXS5zcGxpdChcIi9cIik7XHJcblx0XHRcdFx0XHRcclxuXHRcdFx0XHRcdHZhciBjaGFyYWN0ZXJzVG9BZGQgPSBhZGRpdGlvblBhcnRzWzBdO1xyXG5cdFx0XHRcdFx0aWYgKGNoYXJhY3RlcnNUb0FkZCA9PT0gXCIwXCIpIGNoYXJhY3RlcnNUb0FkZCA9IFwiXCI7XHJcblx0XHRcdFx0XHRcclxuXHRcdFx0XHRcdHZhciBjb250aW51YXRpb25DbGFzc2VzID0gdGhpcy5wYXJzZVJ1bGVDb2RlcyhhZGRpdGlvblBhcnRzWzFdKTtcclxuXHRcdFx0XHRcdFxyXG5cdFx0XHRcdFx0dmFyIHJlZ2V4VG9NYXRjaCA9IGxpbmVQYXJ0c1s0XTtcclxuXHRcdFx0XHRcdFxyXG5cdFx0XHRcdFx0dmFyIGVudHJ5ID0ge307XHJcblx0XHRcdFx0XHRlbnRyeS5hZGQgPSBjaGFyYWN0ZXJzVG9BZGQ7XHJcblx0XHRcdFx0XHRcclxuXHRcdFx0XHRcdGlmIChjb250aW51YXRpb25DbGFzc2VzLmxlbmd0aCA+IDApIGVudHJ5LmNvbnRpbnVhdGlvbkNsYXNzZXMgPSBjb250aW51YXRpb25DbGFzc2VzO1xyXG5cdFx0XHRcdFx0XHJcblx0XHRcdFx0XHRpZiAocmVnZXhUb01hdGNoICE9PSBcIi5cIikge1xyXG5cdFx0XHRcdFx0XHRpZiAocnVsZVR5cGUgPT09IFwiU0ZYXCIpIHtcclxuXHRcdFx0XHRcdFx0XHRlbnRyeS5tYXRjaCA9IG5ldyBSZWdFeHAocmVnZXhUb01hdGNoICsgXCIkXCIpO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdGVsc2Uge1xyXG5cdFx0XHRcdFx0XHRcdGVudHJ5Lm1hdGNoID0gbmV3IFJlZ0V4cChcIl5cIiArIHJlZ2V4VG9NYXRjaCk7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFxyXG5cdFx0XHRcdFx0aWYgKGNoYXJhY3RlcnNUb1JlbW92ZSAhPSBcIjBcIikge1xyXG5cdFx0XHRcdFx0XHRpZiAocnVsZVR5cGUgPT09IFwiU0ZYXCIpIHtcclxuXHRcdFx0XHRcdFx0XHRlbnRyeS5yZW1vdmUgPSBuZXcgUmVnRXhwKGNoYXJhY3RlcnNUb1JlbW92ZSAgKyBcIiRcIik7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0ZWxzZSB7XHJcblx0XHRcdFx0XHRcdFx0ZW50cnkucmVtb3ZlID0gY2hhcmFjdGVyc1RvUmVtb3ZlO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcclxuXHRcdFx0XHRcdGVudHJpZXMucHVzaChlbnRyeSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdFxyXG5cdFx0XHRcdHJ1bGVzW3J1bGVDb2RlXSA9IHsgXCJ0eXBlXCIgOiBydWxlVHlwZSwgXCJjb21iaW5lYWJsZVwiIDogKGNvbWJpbmVhYmxlID09IFwiWVwiKSwgXCJlbnRyaWVzXCIgOiBlbnRyaWVzIH07XHJcblx0XHRcdFx0XHJcblx0XHRcdFx0aSArPSBudW1FbnRyaWVzO1xyXG5cdFx0XHR9XHJcblx0XHRcdGVsc2UgaWYgKHJ1bGVUeXBlID09PSBcIkNPTVBPVU5EUlVMRVwiKSB7XHJcblx0XHRcdFx0dmFyIG51bUVudHJpZXMgPSBwYXJzZUludChkZWZpbml0aW9uUGFydHNbMV0sIDEwKTtcclxuXHRcdFx0XHRcclxuXHRcdFx0XHRmb3IgKHZhciBqID0gaSArIDEsIF9qbGVuID0gaSArIDEgKyBudW1FbnRyaWVzOyBqIDwgX2psZW47IGorKykge1xyXG5cdFx0XHRcdFx0dmFyIGxpbmUgPSBsaW5lc1tqXTtcclxuXHRcdFx0XHRcdFxyXG5cdFx0XHRcdFx0dmFyIGxpbmVQYXJ0cyA9IGxpbmUuc3BsaXQoL1xccysvKTtcclxuXHRcdFx0XHRcdHRoaXMuY29tcG91bmRSdWxlcy5wdXNoKGxpbmVQYXJ0c1sxXSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdFxyXG5cdFx0XHRcdGkgKz0gbnVtRW50cmllcztcclxuXHRcdFx0fVxyXG5cdFx0XHRlbHNlIGlmIChydWxlVHlwZSA9PT0gXCJSRVBcIikge1xyXG5cdFx0XHRcdHZhciBsaW5lUGFydHMgPSBsaW5lLnNwbGl0KC9cXHMrLyk7XHJcblx0XHRcdFx0XHJcblx0XHRcdFx0aWYgKGxpbmVQYXJ0cy5sZW5ndGggPT09IDMpIHtcclxuXHRcdFx0XHRcdHRoaXMucmVwbGFjZW1lbnRUYWJsZS5wdXNoKFsgbGluZVBhcnRzWzFdLCBsaW5lUGFydHNbMl0gXSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdGVsc2Uge1xyXG5cdFx0XHRcdC8vIE9OTFlJTkNPTVBPVU5EXHJcblx0XHRcdFx0Ly8gQ09NUE9VTkRNSU5cclxuXHRcdFx0XHQvLyBGTEFHXHJcblx0XHRcdFx0Ly8gS0VFUENBU0VcclxuXHRcdFx0XHQvLyBORUVEQUZGSVhcclxuXHRcdFx0XHRcclxuXHRcdFx0XHR0aGlzLmZsYWdzW3J1bGVUeXBlXSA9IGRlZmluaXRpb25QYXJ0c1sxXTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdFx0XHJcblx0XHRyZXR1cm4gcnVsZXM7XHJcblx0fSxcclxuXHRcclxuXHQvKipcclxuXHQgKiBSZW1vdmVzIGNvbW1lbnQgbGluZXMgYW5kIHRoZW4gY2xlYW5zIHVwIGJsYW5rIGxpbmVzIGFuZCB0cmFpbGluZyB3aGl0ZXNwYWNlLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtTdHJpbmd9IGRhdGEgVGhlIGRhdGEgZnJvbSBhbiBhZmZpeCBmaWxlLlxyXG5cdCAqIEByZXR1cm4ge1N0cmluZ30gVGhlIGNsZWFuZWQtdXAgZGF0YS5cclxuXHQgKi9cclxuXHRcclxuXHRfcmVtb3ZlQWZmaXhDb21tZW50cyA6IGZ1bmN0aW9uIChkYXRhKSB7XHJcblx0XHQvLyBSZW1vdmUgY29tbWVudHNcclxuXHRcdGRhdGEgPSBkYXRhLnJlcGxhY2UoLyMuKiQvbWcsIFwiXCIpO1xyXG5cdFx0XHJcblx0XHQvLyBUcmltIGVhY2ggbGluZVxyXG5cdFx0ZGF0YSA9IGRhdGEucmVwbGFjZSgvXlxcc1xccyovbSwgJycpLnJlcGxhY2UoL1xcc1xccyokL20sICcnKTtcclxuXHRcdFxyXG5cdFx0Ly8gUmVtb3ZlIGJsYW5rIGxpbmVzLlxyXG5cdFx0ZGF0YSA9IGRhdGEucmVwbGFjZSgvXFxuezIsfS9nLCBcIlxcblwiKTtcclxuXHRcdFxyXG5cdFx0Ly8gVHJpbSB0aGUgZW50aXJlIHN0cmluZ1xyXG5cdFx0ZGF0YSA9IGRhdGEucmVwbGFjZSgvXlxcc1xccyovLCAnJykucmVwbGFjZSgvXFxzXFxzKiQvLCAnJyk7XHJcblx0XHRcclxuXHRcdHJldHVybiBkYXRhO1xyXG5cdH0sXHJcblx0XHJcblx0LyoqXHJcblx0ICogUGFyc2VzIHRoZSB3b3JkcyBvdXQgZnJvbSB0aGUgLmRpYyBmaWxlLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtTdHJpbmd9IGRhdGEgVGhlIGRhdGEgZnJvbSB0aGUgZGljdGlvbmFyeSBmaWxlLlxyXG5cdCAqIEByZXR1cm5zIG9iamVjdCBUaGUgbG9va3VwIHRhYmxlIGNvbnRhaW5pbmcgYWxsIG9mIHRoZSB3b3JkcyBhbmRcclxuXHQgKiAgICAgICAgICAgICAgICAgd29yZCBmb3JtcyBmcm9tIHRoZSBkaWN0aW9uYXJ5LlxyXG5cdCAqL1xyXG5cdFxyXG5cdF9wYXJzZURJQyA6IGZ1bmN0aW9uIChkYXRhKSB7XHJcblx0XHRkYXRhID0gdGhpcy5fcmVtb3ZlRGljQ29tbWVudHMoZGF0YSk7XHJcblx0XHRcclxuXHRcdHZhciBsaW5lcyA9IGRhdGEuc3BsaXQoXCJcXG5cIik7XHJcblx0XHR2YXIgZGljdGlvbmFyeVRhYmxlID0ge307XHJcblx0XHRcclxuXHRcdGZ1bmN0aW9uIGFkZFdvcmQod29yZCwgcnVsZXMpIHtcclxuXHRcdFx0Ly8gU29tZSBkaWN0aW9uYXJpZXMgd2lsbCBsaXN0IHRoZSBzYW1lIHdvcmQgbXVsdGlwbGUgdGltZXMgd2l0aCBkaWZmZXJlbnQgcnVsZSBzZXRzLlxyXG5cdFx0XHRpZiAoISh3b3JkIGluIGRpY3Rpb25hcnlUYWJsZSkgfHwgdHlwZW9mIGRpY3Rpb25hcnlUYWJsZVt3b3JkXSAhPSAnb2JqZWN0Jykge1xyXG5cdFx0XHRcdGRpY3Rpb25hcnlUYWJsZVt3b3JkXSA9IFtdO1xyXG5cdFx0XHR9XHJcblx0XHRcdFxyXG5cdFx0XHRkaWN0aW9uYXJ5VGFibGVbd29yZF0ucHVzaChydWxlcyk7XHJcblx0XHR9XHJcblx0XHRcclxuXHRcdC8vIFRoZSBmaXJzdCBsaW5lIGlzIHRoZSBudW1iZXIgb2Ygd29yZHMgaW4gdGhlIGRpY3Rpb25hcnkuXHJcblx0XHRmb3IgKHZhciBpID0gMSwgX2xlbiA9IGxpbmVzLmxlbmd0aDsgaSA8IF9sZW47IGkrKykge1xyXG5cdFx0XHR2YXIgbGluZSA9IGxpbmVzW2ldO1xyXG5cdFx0XHRcclxuXHRcdFx0dmFyIHBhcnRzID0gbGluZS5zcGxpdChcIi9cIiwgMik7XHJcblx0XHRcdFxyXG5cdFx0XHR2YXIgd29yZCA9IHBhcnRzWzBdO1xyXG5cclxuXHRcdFx0Ly8gTm93IGZvciBlYWNoIGFmZml4IHJ1bGUsIGdlbmVyYXRlIHRoYXQgZm9ybSBvZiB0aGUgd29yZC5cclxuXHRcdFx0aWYgKHBhcnRzLmxlbmd0aCA+IDEpIHtcclxuXHRcdFx0XHR2YXIgcnVsZUNvZGVzQXJyYXkgPSB0aGlzLnBhcnNlUnVsZUNvZGVzKHBhcnRzWzFdKTtcclxuXHRcdFx0XHRcclxuXHRcdFx0XHQvLyBTYXZlIHRoZSBydWxlQ29kZXMgZm9yIGNvbXBvdW5kIHdvcmQgc2l0dWF0aW9ucy5cclxuXHRcdFx0XHRpZiAoIShcIk5FRURBRkZJWFwiIGluIHRoaXMuZmxhZ3MpIHx8IHJ1bGVDb2Rlc0FycmF5LmluZGV4T2YodGhpcy5mbGFncy5ORUVEQUZGSVgpID09IC0xKSB7XHJcblx0XHRcdFx0XHRhZGRXb3JkKHdvcmQsIHJ1bGVDb2Rlc0FycmF5KTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0XHJcblx0XHRcdFx0Zm9yICh2YXIgaiA9IDAsIF9qbGVuID0gcnVsZUNvZGVzQXJyYXkubGVuZ3RoOyBqIDwgX2psZW47IGorKykge1xyXG5cdFx0XHRcdFx0dmFyIGNvZGUgPSBydWxlQ29kZXNBcnJheVtqXTtcclxuXHRcdFx0XHRcdFxyXG5cdFx0XHRcdFx0dmFyIHJ1bGUgPSB0aGlzLnJ1bGVzW2NvZGVdO1xyXG5cdFx0XHRcdFx0XHJcblx0XHRcdFx0XHRpZiAocnVsZSkge1xyXG5cdFx0XHRcdFx0XHR2YXIgbmV3V29yZHMgPSB0aGlzLl9hcHBseVJ1bGUod29yZCwgcnVsZSk7XHJcblx0XHRcdFx0XHRcdFxyXG5cdFx0XHRcdFx0XHRmb3IgKHZhciBpaSA9IDAsIF9paWxlbiA9IG5ld1dvcmRzLmxlbmd0aDsgaWkgPCBfaWlsZW47IGlpKyspIHtcclxuXHRcdFx0XHRcdFx0XHR2YXIgbmV3V29yZCA9IG5ld1dvcmRzW2lpXTtcclxuXHRcdFx0XHRcdFx0XHRcclxuXHRcdFx0XHRcdFx0XHRhZGRXb3JkKG5ld1dvcmQsIFtdKTtcclxuXHRcdFx0XHRcdFx0XHRcclxuXHRcdFx0XHRcdFx0XHRpZiAocnVsZS5jb21iaW5lYWJsZSkge1xyXG5cdFx0XHRcdFx0XHRcdFx0Zm9yICh2YXIgayA9IGogKyAxOyBrIDwgX2psZW47IGsrKykge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHR2YXIgY29tYmluZUNvZGUgPSBydWxlQ29kZXNBcnJheVtrXTtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHJcblx0XHRcdFx0XHRcdFx0XHRcdHZhciBjb21iaW5lUnVsZSA9IHRoaXMucnVsZXNbY29tYmluZUNvZGVdO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcclxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKGNvbWJpbmVSdWxlKSB7XHJcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKGNvbWJpbmVSdWxlLmNvbWJpbmVhYmxlICYmIChydWxlLnR5cGUgIT0gY29tYmluZVJ1bGUudHlwZSkpIHtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHZhciBvdGhlck5ld1dvcmRzID0gdGhpcy5fYXBwbHlSdWxlKG5ld1dvcmQsIGNvbWJpbmVSdWxlKTtcclxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Zm9yICh2YXIgaWlpID0gMCwgX2lpaWxlbiA9IG90aGVyTmV3V29yZHMubGVuZ3RoOyBpaWkgPCBfaWlpbGVuOyBpaWkrKykge1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR2YXIgb3RoZXJOZXdXb3JkID0gb3RoZXJOZXdXb3Jkc1tpaWldO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRhZGRXb3JkKG90aGVyTmV3V29yZCwgW10pO1xyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHJcblx0XHRcdFx0XHRpZiAoY29kZSBpbiB0aGlzLmNvbXBvdW5kUnVsZUNvZGVzKSB7XHJcblx0XHRcdFx0XHRcdHRoaXMuY29tcG91bmRSdWxlQ29kZXNbY29kZV0ucHVzaCh3b3JkKTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdFx0ZWxzZSB7XHJcblx0XHRcdFx0YWRkV29yZCh3b3JkLnRyaW0oKSwgW10pO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRcclxuXHRcdHJldHVybiBkaWN0aW9uYXJ5VGFibGU7XHJcblx0fSxcclxuXHRcclxuXHRcclxuXHQvKipcclxuXHQgKiBSZW1vdmVzIGNvbW1lbnQgbGluZXMgYW5kIHRoZW4gY2xlYW5zIHVwIGJsYW5rIGxpbmVzIGFuZCB0cmFpbGluZyB3aGl0ZXNwYWNlLlxyXG5cdCAqXHJcblx0ICogQHBhcmFtIHtTdHJpbmd9IGRhdGEgVGhlIGRhdGEgZnJvbSBhIC5kaWMgZmlsZS5cclxuXHQgKiBAcmV0dXJuIHtTdHJpbmd9IFRoZSBjbGVhbmVkLXVwIGRhdGEuXHJcblx0ICovXHJcblx0XHJcblx0X3JlbW92ZURpY0NvbW1lbnRzIDogZnVuY3Rpb24gKGRhdGEpIHtcclxuXHRcdC8vIEkgY2FuJ3QgZmluZCBhbnkgb2ZmaWNpYWwgZG9jdW1lbnRhdGlvbiBvbiBpdCwgYnV0IGF0IGxlYXN0IHRoZSBkZV9ERVxyXG5cdFx0Ly8gZGljdGlvbmFyeSB1c2VzIHRhYi1pbmRlbnRlZCBsaW5lcyBhcyBjb21tZW50cy5cclxuXHRcdFxyXG5cdFx0Ly8gUmVtb3ZlIGNvbW1lbnRzXHJcblx0XHRkYXRhID0gZGF0YS5yZXBsYWNlKC9eXFx0LiokL21nLCBcIlwiKTtcclxuXHRcdFxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblx0XHRcclxuXHRcdC8vIFRyaW0gZWFjaCBsaW5lXHJcblx0XHRkYXRhID0gZGF0YS5yZXBsYWNlKC9eXFxzXFxzKi9tLCAnJykucmVwbGFjZSgvXFxzXFxzKiQvbSwgJycpO1xyXG5cdFx0XHJcblx0XHQvLyBSZW1vdmUgYmxhbmsgbGluZXMuXHJcblx0XHRkYXRhID0gZGF0YS5yZXBsYWNlKC9cXG57Mix9L2csIFwiXFxuXCIpO1xyXG5cdFx0XHJcblx0XHQvLyBUcmltIHRoZSBlbnRpcmUgc3RyaW5nXHJcblx0XHRkYXRhID0gZGF0YS5yZXBsYWNlKC9eXFxzXFxzKi8sICcnKS5yZXBsYWNlKC9cXHNcXHMqJC8sICcnKTtcclxuXHRcdFxyXG5cdFx0cmV0dXJuIGRhdGE7XHJcblx0fSxcclxuXHRcclxuXHRwYXJzZVJ1bGVDb2RlcyA6IGZ1bmN0aW9uICh0ZXh0Q29kZXMpIHtcclxuXHRcdGlmICghdGV4dENvZGVzKSB7XHJcblx0XHRcdHJldHVybiBbXTtcclxuXHRcdH1cclxuXHRcdGVsc2UgaWYgKCEoXCJGTEFHXCIgaW4gdGhpcy5mbGFncykpIHtcclxuXHRcdFx0cmV0dXJuIHRleHRDb2Rlcy5zcGxpdChcIlwiKTtcclxuXHRcdH1cclxuXHRcdGVsc2UgaWYgKHRoaXMuZmxhZ3MuRkxBRyA9PT0gXCJsb25nXCIpIHtcclxuXHRcdFx0dmFyIGZsYWdzID0gW107XHJcblx0XHRcdFxyXG5cdFx0XHRmb3IgKHZhciBpID0gMCwgX2xlbiA9IHRleHRDb2Rlcy5sZW5ndGg7IGkgPCBfbGVuOyBpICs9IDIpIHtcclxuXHRcdFx0XHRmbGFncy5wdXNoKHRleHRDb2Rlcy5zdWJzdHIoaSwgMikpO1xyXG5cdFx0XHR9XHJcblx0XHRcdFxyXG5cdFx0XHRyZXR1cm4gZmxhZ3M7XHJcblx0XHR9XHJcblx0XHRlbHNlIGlmICh0aGlzLmZsYWdzLkZMQUcgPT09IFwibnVtXCIpIHtcclxuXHRcdFx0cmV0dXJuIHRleHRDb2RlLnNwbGl0KFwiLFwiKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cdFxyXG5cdC8qKlxyXG5cdCAqIEFwcGxpZXMgYW4gYWZmaXggcnVsZSB0byBhIHdvcmQuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge1N0cmluZ30gd29yZCBUaGUgYmFzZSB3b3JkLlxyXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBydWxlIFRoZSBhZmZpeCBydWxlLlxyXG5cdCAqIEByZXR1cm5zIHtTdHJpbmdbXX0gVGhlIG5ldyB3b3JkcyBnZW5lcmF0ZWQgYnkgdGhlIHJ1bGUuXHJcblx0ICovXHJcblx0XHJcblx0X2FwcGx5UnVsZSA6IGZ1bmN0aW9uICh3b3JkLCBydWxlKSB7XHJcblx0XHR2YXIgZW50cmllcyA9IHJ1bGUuZW50cmllcztcclxuXHRcdHZhciBuZXdXb3JkcyA9IFtdO1xyXG5cdFx0XHJcblx0XHRmb3IgKHZhciBpID0gMCwgX2xlbiA9IGVudHJpZXMubGVuZ3RoOyBpIDwgX2xlbjsgaSsrKSB7XHJcblx0XHRcdHZhciBlbnRyeSA9IGVudHJpZXNbaV07XHJcblx0XHRcdFxyXG5cdFx0XHRpZiAoIWVudHJ5Lm1hdGNoIHx8IHdvcmQubWF0Y2goZW50cnkubWF0Y2gpKSB7XHJcblx0XHRcdFx0dmFyIG5ld1dvcmQgPSB3b3JkO1xyXG5cdFx0XHRcdFxyXG5cdFx0XHRcdGlmIChlbnRyeS5yZW1vdmUpIHtcclxuXHRcdFx0XHRcdG5ld1dvcmQgPSBuZXdXb3JkLnJlcGxhY2UoZW50cnkucmVtb3ZlLCBcIlwiKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0XHJcblx0XHRcdFx0aWYgKHJ1bGUudHlwZSA9PT0gXCJTRlhcIikge1xyXG5cdFx0XHRcdFx0bmV3V29yZCA9IG5ld1dvcmQgKyBlbnRyeS5hZGQ7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGVsc2Uge1xyXG5cdFx0XHRcdFx0bmV3V29yZCA9IGVudHJ5LmFkZCArIG5ld1dvcmQ7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdFxyXG5cdFx0XHRcdG5ld1dvcmRzLnB1c2gobmV3V29yZCk7XHJcblx0XHRcdFx0XHJcblx0XHRcdFx0aWYgKFwiY29udGludWF0aW9uQ2xhc3Nlc1wiIGluIGVudHJ5KSB7XHJcblx0XHRcdFx0XHRmb3IgKHZhciBqID0gMCwgX2psZW4gPSBlbnRyeS5jb250aW51YXRpb25DbGFzc2VzLmxlbmd0aDsgaiA8IF9qbGVuOyBqKyspIHtcclxuXHRcdFx0XHRcdFx0dmFyIGNvbnRpbnVhdGlvblJ1bGUgPSB0aGlzLnJ1bGVzW2VudHJ5LmNvbnRpbnVhdGlvbkNsYXNzZXNbal1dO1xyXG5cdFx0XHRcdFx0XHRcclxuXHRcdFx0XHRcdFx0aWYgKGNvbnRpbnVhdGlvblJ1bGUpIHtcclxuXHRcdFx0XHRcdFx0XHRuZXdXb3JkcyA9IG5ld1dvcmRzLmNvbmNhdCh0aGlzLl9hcHBseVJ1bGUobmV3V29yZCwgY29udGludWF0aW9uUnVsZSkpO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdC8qXHJcblx0XHRcdFx0XHRcdGVsc2Uge1xyXG5cdFx0XHRcdFx0XHRcdC8vIFRoaXMgc2hvdWxkbid0IGhhcHBlbiwgYnV0IGl0IGRvZXMsIGF0IGxlYXN0IGluIHRoZSBkZV9ERSBkaWN0aW9uYXJ5LlxyXG5cdFx0XHRcdFx0XHRcdC8vIEkgdGhpbmsgdGhlIGF1dGhvciBtaXN0YWtlbmx5IHN1cHBsaWVkIGxvd2VyLWNhc2UgcnVsZSBjb2RlcyBpbnN0ZWFkXHJcblx0XHRcdFx0XHRcdFx0Ly8gb2YgdXBwZXItY2FzZS5cclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHQqL1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdFx0XHJcblx0XHRyZXR1cm4gbmV3V29yZHM7XHJcblx0fSxcclxuXHRcclxuXHQvKipcclxuXHQgKiBDaGVja3Mgd2hldGhlciBhIHdvcmQgb3IgYSBjYXBpdGFsaXphdGlvbiB2YXJpYW50IGV4aXN0cyBpbiB0aGUgY3VycmVudCBkaWN0aW9uYXJ5LlxyXG5cdCAqIFRoZSB3b3JkIGlzIHRyaW1tZWQgYW5kIHNldmVyYWwgdmFyaWF0aW9ucyBvZiBjYXBpdGFsaXphdGlvbnMgYXJlIGNoZWNrZWQuXHJcblx0ICogSWYgeW91IHdhbnQgdG8gY2hlY2sgYSB3b3JkIHdpdGhvdXQgYW55IGNoYW5nZXMgbWFkZSB0byBpdCwgY2FsbCBjaGVja0V4YWN0KClcclxuXHQgKlxyXG5cdCAqIEBzZWUgaHR0cDovL2Jsb2cuc3RldmVubGV2aXRoYW4uY29tL2FyY2hpdmVzL2Zhc3Rlci10cmltLWphdmFzY3JpcHQgcmU6dHJpbW1pbmcgZnVuY3Rpb25cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBhV29yZCBUaGUgd29yZCB0byBjaGVjay5cclxuXHQgKiBAcmV0dXJucyB7Qm9vbGVhbn1cclxuXHQgKi9cclxuXHRcclxuXHRjaGVjayA6IGZ1bmN0aW9uIChhV29yZCkge1xyXG5cdFx0Ly8gUmVtb3ZlIGxlYWRpbmcgYW5kIHRyYWlsaW5nIHdoaXRlc3BhY2VcclxuXHRcdHZhciB0cmltbWVkV29yZCA9IGFXb3JkLnJlcGxhY2UoL15cXHNcXHMqLywgJycpLnJlcGxhY2UoL1xcc1xccyokLywgJycpO1xyXG5cdFx0XHJcblx0XHRpZiAodGhpcy5jaGVja0V4YWN0KHRyaW1tZWRXb3JkKSkge1xyXG5cdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdH1cclxuXHRcdFxyXG5cdFx0Ly8gVGhlIGV4YWN0IHdvcmQgaXMgbm90IGluIHRoZSBkaWN0aW9uYXJ5LlxyXG5cdFx0aWYgKHRyaW1tZWRXb3JkLnRvVXBwZXJDYXNlKCkgPT09IHRyaW1tZWRXb3JkKSB7XHJcblx0XHRcdC8vIFRoZSB3b3JkIHdhcyBzdXBwbGllZCBpbiBhbGwgdXBwZXJjYXNlLlxyXG5cdFx0XHQvLyBDaGVjayBmb3IgYSBjYXBpdGFsaXplZCBmb3JtIG9mIHRoZSB3b3JkLlxyXG5cdFx0XHR2YXIgY2FwaXRhbGl6ZWRXb3JkID0gdHJpbW1lZFdvcmRbMF0gKyB0cmltbWVkV29yZC5zdWJzdHJpbmcoMSkudG9Mb3dlckNhc2UoKTtcclxuXHRcdFx0XHJcblx0XHRcdGlmICh0aGlzLmhhc0ZsYWcoY2FwaXRhbGl6ZWRXb3JkLCBcIktFRVBDQVNFXCIpKSB7XHJcblx0XHRcdFx0Ly8gQ2FwaXRhbGl6YXRpb24gdmFyaWFudHMgYXJlIG5vdCBhbGxvd2VkIGZvciB0aGlzIHdvcmQuXHJcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0XHR9XHJcblx0XHRcdFxyXG5cdFx0XHRpZiAodGhpcy5jaGVja0V4YWN0KGNhcGl0YWxpemVkV29yZCkpIHtcclxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdFx0XHJcblx0XHR2YXIgbG93ZXJjYXNlV29yZCA9IHRyaW1tZWRXb3JkLnRvTG93ZXJDYXNlKCk7XHJcblx0XHRcclxuXHRcdGlmIChsb3dlcmNhc2VXb3JkICE9PSB0cmltbWVkV29yZCkge1xyXG5cdFx0XHRpZiAodGhpcy5oYXNGbGFnKGxvd2VyY2FzZVdvcmQsIFwiS0VFUENBU0VcIikpIHtcclxuXHRcdFx0XHQvLyBDYXBpdGFsaXphdGlvbiB2YXJpYW50cyBhcmUgbm90IGFsbG93ZWQgZm9yIHRoaXMgd29yZC5cclxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHRcdC8vIENoZWNrIGZvciBhIGxvd2VyY2FzZSBmb3JtXHJcblx0XHRcdGlmICh0aGlzLmNoZWNrRXhhY3QobG93ZXJjYXNlV29yZCkpIHtcclxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdFx0XHJcblx0XHRyZXR1cm4gZmFsc2U7XHJcblx0fSxcclxuXHRcclxuXHQvKipcclxuXHQgKiBDaGVja3Mgd2hldGhlciBhIHdvcmQgZXhpc3RzIGluIHRoZSBjdXJyZW50IGRpY3Rpb25hcnkuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge1N0cmluZ30gd29yZCBUaGUgd29yZCB0byBjaGVjay5cclxuXHQgKiBAcmV0dXJucyB7Qm9vbGVhbn1cclxuXHQgKi9cclxuXHRcclxuXHRjaGVja0V4YWN0IDogZnVuY3Rpb24gKHdvcmQpIHtcclxuXHRcdHZhciBydWxlQ29kZXMgPSB0aGlzLmRpY3Rpb25hcnlUYWJsZVt3b3JkXTtcclxuXHRcdFxyXG5cdFx0aWYgKHR5cGVvZiBydWxlQ29kZXMgPT09ICd1bmRlZmluZWQnKSB7XHJcblx0XHRcdC8vIENoZWNrIGlmIHRoaXMgbWlnaHQgYmUgYSBjb21wb3VuZCB3b3JkLlxyXG5cdFx0XHRpZiAoXCJDT01QT1VORE1JTlwiIGluIHRoaXMuZmxhZ3MgJiYgd29yZC5sZW5ndGggPj0gdGhpcy5mbGFncy5DT01QT1VORE1JTikge1xyXG5cdFx0XHRcdGZvciAodmFyIGkgPSAwLCBfbGVuID0gdGhpcy5jb21wb3VuZFJ1bGVzLmxlbmd0aDsgaSA8IF9sZW47IGkrKykge1xyXG5cdFx0XHRcdFx0aWYgKHdvcmQubWF0Y2godGhpcy5jb21wb3VuZFJ1bGVzW2ldKSkge1xyXG5cdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdH1cclxuXHRcdGVsc2Uge1xyXG5cdFx0XHRmb3IgKHZhciBpID0gMCwgX2xlbiA9IHJ1bGVDb2Rlcy5sZW5ndGg7IGkgPCBfbGVuOyBpKyspIHtcclxuXHRcdFx0XHRpZiAoIXRoaXMuaGFzRmxhZyh3b3JkLCBcIk9OTFlJTkNPTVBPVU5EXCIsIHJ1bGVDb2Rlc1tpXSkpIHtcclxuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRcclxuXHRcdFx0cmV0dXJuIGZhbHNlO1xyXG5cdFx0fVxyXG5cdH0sXHJcblx0XHJcblx0LyoqXHJcblx0ICogTG9va3MgdXAgd2hldGhlciBhIGdpdmVuIHdvcmQgaXMgZmxhZ2dlZCB3aXRoIGEgZ2l2ZW4gZmxhZy5cclxuXHQgKlxyXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSB3b3JkIFRoZSB3b3JkIGluIHF1ZXN0aW9uLlxyXG5cdCAqIEBwYXJhbSB7U3RyaW5nfSBmbGFnIFRoZSBmbGFnIGluIHF1ZXN0aW9uLlxyXG5cdCAqIEByZXR1cm4ge0Jvb2xlYW59XHJcblx0ICovXHJcblx0IFxyXG5cdGhhc0ZsYWcgOiBmdW5jdGlvbiAod29yZCwgZmxhZywgd29yZEZsYWdzKSB7XHJcblx0XHRpZiAoZmxhZyBpbiB0aGlzLmZsYWdzKSB7XHJcblx0XHRcdGlmICh0eXBlb2Ygd29yZEZsYWdzID09PSAndW5kZWZpbmVkJykge1xyXG5cdFx0XHRcdHZhciB3b3JkRmxhZ3MgPSBBcnJheS5wcm90b3R5cGUuY29uY2F0LmFwcGx5KFtdLCB0aGlzLmRpY3Rpb25hcnlUYWJsZVt3b3JkXSk7XHJcblx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHRcdGlmICh3b3JkRmxhZ3MgJiYgd29yZEZsYWdzLmluZGV4T2YodGhpcy5mbGFnc1tmbGFnXSkgIT09IC0xKSB7XHJcblx0XHRcdFx0cmV0dXJuIHRydWU7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdFxyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH0sXHJcblx0XHJcblx0LyoqXHJcblx0ICogUmV0dXJucyBhIGxpc3Qgb2Ygc3VnZ2VzdGlvbnMgZm9yIGEgbWlzc3BlbGxlZCB3b3JkLlxyXG5cdCAqXHJcblx0ICogQHNlZSBodHRwOi8vd3d3Lm5vcnZpZy5jb20vc3BlbGwtY29ycmVjdC5odG1sIGZvciB0aGUgYmFzaXMgb2YgdGhpcyBzdWdnZXN0b3IuXHJcblx0ICogVGhpcyBzdWdnZXN0b3IgaXMgcHJpbWl0aXZlLCBidXQgaXQgd29ya3MuXHJcblx0ICpcclxuXHQgKiBAcGFyYW0ge1N0cmluZ30gd29yZCBUaGUgbWlzc3BlbGxpbmcuXHJcblx0ICogQHBhcmFtIHtOdW1iZXJ9IFtsaW1pdD01XSBUaGUgbWF4aW11bSBudW1iZXIgb2Ygc3VnZ2VzdGlvbnMgdG8gcmV0dXJuLlxyXG5cdCAqIEByZXR1cm5zIHtTdHJpbmdbXX0gVGhlIGFycmF5IG9mIHN1Z2dlc3Rpb25zLlxyXG5cdCAqL1xyXG5cdFxyXG5cdGFscGhhYmV0IDogXCJcIixcclxuXHRcclxuXHRzdWdnZXN0IDogZnVuY3Rpb24gKHdvcmQsIGxpbWl0KSB7XHJcblx0XHRpZiAoIWxpbWl0KSBsaW1pdCA9IDU7XHJcblx0XHRcclxuXHRcdGlmICh0aGlzLmNoZWNrKHdvcmQpKSByZXR1cm4gW107XHJcblx0XHRcclxuXHRcdC8vIENoZWNrIHRoZSByZXBsYWNlbWVudCB0YWJsZS5cclxuXHRcdGZvciAodmFyIGkgPSAwLCBfbGVuID0gdGhpcy5yZXBsYWNlbWVudFRhYmxlLmxlbmd0aDsgaSA8IF9sZW47IGkrKykge1xyXG5cdFx0XHR2YXIgcmVwbGFjZW1lbnRFbnRyeSA9IHRoaXMucmVwbGFjZW1lbnRUYWJsZVtpXTtcclxuXHRcdFx0XHJcblx0XHRcdGlmICh3b3JkLmluZGV4T2YocmVwbGFjZW1lbnRFbnRyeVswXSkgIT09IC0xKSB7XHJcblx0XHRcdFx0dmFyIGNvcnJlY3RlZFdvcmQgPSB3b3JkLnJlcGxhY2UocmVwbGFjZW1lbnRFbnRyeVswXSwgcmVwbGFjZW1lbnRFbnRyeVsxXSk7XHJcblx0XHRcdFx0XHJcblx0XHRcdFx0aWYgKHRoaXMuY2hlY2soY29ycmVjdGVkV29yZCkpIHtcclxuXHRcdFx0XHRcdHJldHVybiBbIGNvcnJlY3RlZFdvcmQgXTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdFxyXG5cdFx0dmFyIHNlbGYgPSB0aGlzO1xyXG5cdFx0c2VsZi5hbHBoYWJldCA9IFwiYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXpcIjtcclxuXHRcdFxyXG5cdFx0LypcclxuXHRcdGlmICghc2VsZi5hbHBoYWJldCkge1xyXG5cdFx0XHQvLyBVc2UgdGhlIGFscGhhYmV0IGFzIGltcGxpY2l0bHkgZGVmaW5lZCBieSB0aGUgd29yZHMgaW4gdGhlIGRpY3Rpb25hcnkuXHJcblx0XHRcdHZhciBhbHBoYUhhc2ggPSB7fTtcclxuXHRcdFx0XHJcblx0XHRcdGZvciAodmFyIGkgaW4gc2VsZi5kaWN0aW9uYXJ5VGFibGUpIHtcclxuXHRcdFx0XHRmb3IgKHZhciBqID0gMCwgX2xlbiA9IGkubGVuZ3RoOyBqIDwgX2xlbjsgaisrKSB7XHJcblx0XHRcdFx0XHRhbHBoYUhhc2hbaVtqXV0gPSB0cnVlO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cdFx0XHRcclxuXHRcdFx0Zm9yICh2YXIgaSBpbiBhbHBoYUhhc2gpIHtcclxuXHRcdFx0XHRzZWxmLmFscGhhYmV0ICs9IGk7XHJcblx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHRcdHZhciBhbHBoYUFycmF5ID0gc2VsZi5hbHBoYWJldC5zcGxpdChcIlwiKTtcclxuXHRcdFx0YWxwaGFBcnJheS5zb3J0KCk7XHJcblx0XHRcdHNlbGYuYWxwaGFiZXQgPSBhbHBoYUFycmF5LmpvaW4oXCJcIik7XHJcblx0XHR9XHJcblx0XHQqL1xyXG5cdFx0XHJcblx0XHRmdW5jdGlvbiBlZGl0czEod29yZHMpIHtcclxuXHRcdFx0dmFyIHJ2ID0gW107XHJcblx0XHRcdFxyXG5cdFx0XHRmb3IgKHZhciBpaSA9IDAsIF9paWxlbiA9IHdvcmRzLmxlbmd0aDsgaWkgPCBfaWlsZW47IGlpKyspIHtcclxuXHRcdFx0XHR2YXIgd29yZCA9IHdvcmRzW2lpXTtcclxuXHRcdFx0XHRcclxuXHRcdFx0XHR2YXIgc3BsaXRzID0gW107XHJcblx0XHRcdFxyXG5cdFx0XHRcdGZvciAodmFyIGkgPSAwLCBfbGVuID0gd29yZC5sZW5ndGggKyAxOyBpIDwgX2xlbjsgaSsrKSB7XHJcblx0XHRcdFx0XHRzcGxpdHMucHVzaChbIHdvcmQuc3Vic3RyaW5nKDAsIGkpLCB3b3JkLnN1YnN0cmluZyhpLCB3b3JkLmxlbmd0aCkgXSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcclxuXHRcdFx0XHR2YXIgZGVsZXRlcyA9IFtdO1xyXG5cdFx0XHRcclxuXHRcdFx0XHRmb3IgKHZhciBpID0gMCwgX2xlbiA9IHNwbGl0cy5sZW5ndGg7IGkgPCBfbGVuOyBpKyspIHtcclxuXHRcdFx0XHRcdHZhciBzID0gc3BsaXRzW2ldO1xyXG5cdFx0XHRcdFxyXG5cdFx0XHRcdFx0aWYgKHNbMV0pIHtcclxuXHRcdFx0XHRcdFx0ZGVsZXRlcy5wdXNoKHNbMF0gKyBzWzFdLnN1YnN0cmluZygxKSk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcclxuXHRcdFx0XHR2YXIgdHJhbnNwb3NlcyA9IFtdO1xyXG5cdFx0XHRcclxuXHRcdFx0XHRmb3IgKHZhciBpID0gMCwgX2xlbiA9IHNwbGl0cy5sZW5ndGg7IGkgPCBfbGVuOyBpKyspIHtcclxuXHRcdFx0XHRcdHZhciBzID0gc3BsaXRzW2ldO1xyXG5cdFx0XHRcdFxyXG5cdFx0XHRcdFx0aWYgKHNbMV0ubGVuZ3RoID4gMSkge1xyXG5cdFx0XHRcdFx0XHR0cmFuc3Bvc2VzLnB1c2goc1swXSArIHNbMV1bMV0gKyBzWzFdWzBdICsgc1sxXS5zdWJzdHJpbmcoMikpO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHRcdFx0dmFyIHJlcGxhY2VzID0gW107XHJcblx0XHRcdFxyXG5cdFx0XHRcdGZvciAodmFyIGkgPSAwLCBfbGVuID0gc3BsaXRzLmxlbmd0aDsgaSA8IF9sZW47IGkrKykge1xyXG5cdFx0XHRcdFx0dmFyIHMgPSBzcGxpdHNbaV07XHJcblx0XHRcdFx0XHJcblx0XHRcdFx0XHRpZiAoc1sxXSkge1xyXG5cdFx0XHRcdFx0XHRmb3IgKHZhciBqID0gMCwgX2psZW4gPSBzZWxmLmFscGhhYmV0Lmxlbmd0aDsgaiA8IF9qbGVuOyBqKyspIHtcclxuXHRcdFx0XHRcdFx0XHRyZXBsYWNlcy5wdXNoKHNbMF0gKyBzZWxmLmFscGhhYmV0W2pdICsgc1sxXS5zdWJzdHJpbmcoMSkpO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcclxuXHRcdFx0XHR2YXIgaW5zZXJ0cyA9IFtdO1xyXG5cdFx0XHRcclxuXHRcdFx0XHRmb3IgKHZhciBpID0gMCwgX2xlbiA9IHNwbGl0cy5sZW5ndGg7IGkgPCBfbGVuOyBpKyspIHtcclxuXHRcdFx0XHRcdHZhciBzID0gc3BsaXRzW2ldO1xyXG5cdFx0XHRcdFxyXG5cdFx0XHRcdFx0aWYgKHNbMV0pIHtcclxuXHRcdFx0XHRcdFx0Zm9yICh2YXIgaiA9IDAsIF9qbGVuID0gc2VsZi5hbHBoYWJldC5sZW5ndGg7IGogPCBfamxlbjsgaisrKSB7XHJcblx0XHRcdFx0XHRcdFx0cmVwbGFjZXMucHVzaChzWzBdICsgc2VsZi5hbHBoYWJldFtqXSArIHNbMV0pO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcclxuXHRcdFx0XHRydiA9IHJ2LmNvbmNhdChkZWxldGVzKTtcclxuXHRcdFx0XHRydiA9IHJ2LmNvbmNhdCh0cmFuc3Bvc2VzKTtcclxuXHRcdFx0XHRydiA9IHJ2LmNvbmNhdChyZXBsYWNlcyk7XHJcblx0XHRcdFx0cnYgPSBydi5jb25jYXQoaW5zZXJ0cyk7XHJcblx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHRcdHJldHVybiBydjtcclxuXHRcdH1cclxuXHRcdFxyXG5cdFx0ZnVuY3Rpb24ga25vd24od29yZHMpIHtcclxuXHRcdFx0dmFyIHJ2ID0gW107XHJcblx0XHRcdFxyXG5cdFx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHdvcmRzLmxlbmd0aDsgaSsrKSB7XHJcblx0XHRcdFx0aWYgKHNlbGYuY2hlY2sod29yZHNbaV0pKSB7XHJcblx0XHRcdFx0XHRydi5wdXNoKHdvcmRzW2ldKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHRcdHJldHVybiBydjtcclxuXHRcdH1cclxuXHRcdFxyXG5cdFx0ZnVuY3Rpb24gY29ycmVjdCh3b3JkKSB7XHJcblx0XHRcdC8vIEdldCB0aGUgZWRpdC1kaXN0YW5jZS0xIGFuZCBlZGl0LWRpc3RhbmNlLTIgZm9ybXMgb2YgdGhpcyB3b3JkLlxyXG5cdFx0XHR2YXIgZWQxID0gZWRpdHMxKFt3b3JkXSk7XHJcblx0XHRcdHZhciBlZDIgPSBlZGl0czEoZWQxKTtcclxuXHRcdFx0XHJcblx0XHRcdHZhciBjb3JyZWN0aW9ucyA9IGtub3duKGVkMSkuY29uY2F0KGtub3duKGVkMikpO1xyXG5cdFx0XHRcclxuXHRcdFx0Ly8gU29ydCB0aGUgZWRpdHMgYmFzZWQgb24gaG93IG1hbnkgZGlmZmVyZW50IHdheXMgdGhleSB3ZXJlIGNyZWF0ZWQuXHJcblx0XHRcdHZhciB3ZWlnaHRlZF9jb3JyZWN0aW9ucyA9IHt9O1xyXG5cdFx0XHRcclxuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIF9sZW4gPSBjb3JyZWN0aW9ucy5sZW5ndGg7IGkgPCBfbGVuOyBpKyspIHtcclxuXHRcdFx0XHRpZiAoIShjb3JyZWN0aW9uc1tpXSBpbiB3ZWlnaHRlZF9jb3JyZWN0aW9ucykpIHtcclxuXHRcdFx0XHRcdHdlaWdodGVkX2NvcnJlY3Rpb25zW2NvcnJlY3Rpb25zW2ldXSA9IDE7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdGVsc2Uge1xyXG5cdFx0XHRcdFx0d2VpZ2h0ZWRfY29ycmVjdGlvbnNbY29ycmVjdGlvbnNbaV1dICs9IDE7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdFxyXG5cdFx0XHR2YXIgc29ydGVkX2NvcnJlY3Rpb25zID0gW107XHJcblx0XHRcdFxyXG5cdFx0XHRmb3IgKHZhciBpIGluIHdlaWdodGVkX2NvcnJlY3Rpb25zKSB7XHJcblx0XHRcdFx0c29ydGVkX2NvcnJlY3Rpb25zLnB1c2goWyBpLCB3ZWlnaHRlZF9jb3JyZWN0aW9uc1tpXSBdKTtcclxuXHRcdFx0fVxyXG5cdFx0XHRcclxuXHRcdFx0ZnVuY3Rpb24gc29ydGVyKGEsIGIpIHtcclxuXHRcdFx0XHRpZiAoYVsxXSA8IGJbMV0pIHtcclxuXHRcdFx0XHRcdHJldHVybiAtMTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0XHJcblx0XHRcdFx0cmV0dXJuIDE7XHJcblx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHRcdHNvcnRlZF9jb3JyZWN0aW9ucy5zb3J0KHNvcnRlcikucmV2ZXJzZSgpO1xyXG5cdFx0XHRcclxuXHRcdFx0dmFyIHJ2ID0gW107XHJcblx0XHRcdFxyXG5cdFx0XHRmb3IgKHZhciBpID0gMCwgX2xlbiA9IE1hdGgubWluKGxpbWl0LCBzb3J0ZWRfY29ycmVjdGlvbnMubGVuZ3RoKTsgaSA8IF9sZW47IGkrKykge1xyXG5cdFx0XHRcdGlmICghc2VsZi5oYXNGbGFnKHNvcnRlZF9jb3JyZWN0aW9uc1tpXVswXSwgXCJOT1NVR0dFU1RcIikpIHtcclxuXHRcdFx0XHRcdHJ2LnB1c2goc29ydGVkX2NvcnJlY3Rpb25zW2ldWzBdKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHRcdHJldHVybiBydjtcclxuXHRcdH1cclxuXHRcdFxyXG5cdFx0cmV0dXJuIGNvcnJlY3Qod29yZCk7XHJcblx0fVxyXG59O1xuOyBicm93c2VyaWZ5X3NoaW1fX2RlZmluZV9fbW9kdWxlX19leHBvcnRfXyh0eXBlb2YgVHlwbyAhPSBcInVuZGVmaW5lZFwiID8gVHlwbyA6IHdpbmRvdy5UeXBvKTtcblxufSkuY2FsbChnbG9iYWwsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgZnVuY3Rpb24gZGVmaW5lRXhwb3J0KGV4KSB7IG1vZHVsZS5leHBvcnRzID0gZXg7IH0pO1xuIiwiLy8gQ29kZU1pcnJvciwgY29weXJpZ2h0IChjKSBieSBNYXJpam4gSGF2ZXJiZWtlIGFuZCBvdGhlcnNcclxuLy8gRGlzdHJpYnV0ZWQgdW5kZXIgYW4gTUlUIGxpY2Vuc2U6IGh0dHA6Ly9jb2RlbWlycm9yLm5ldC9MSUNFTlNFXHJcblxyXG4oZnVuY3Rpb24obW9kKSB7XHJcbiAgaWYgKHR5cGVvZiBleHBvcnRzID09IFwib2JqZWN0XCIgJiYgdHlwZW9mIG1vZHVsZSA9PSBcIm9iamVjdFwiKSAvLyBDb21tb25KU1xyXG4gICAgbW9kKHJlcXVpcmUoXCIuLi8uLi9saWIvY29kZW1pcnJvclwiKSk7XHJcbiAgZWxzZSBpZiAodHlwZW9mIGRlZmluZSA9PSBcImZ1bmN0aW9uXCIgJiYgZGVmaW5lLmFtZCkgLy8gQU1EXHJcbiAgICBkZWZpbmUoW1wiLi4vLi4vbGliL2NvZGVtaXJyb3JcIl0sIG1vZCk7XHJcbiAgZWxzZSAvLyBQbGFpbiBicm93c2VyIGVudlxyXG4gICAgbW9kKENvZGVNaXJyb3IpO1xyXG59KShmdW5jdGlvbihDb2RlTWlycm9yKSB7XHJcbiAgXCJ1c2Ugc3RyaWN0XCI7XHJcblxyXG4gIENvZGVNaXJyb3IuZGVmaW5lT3B0aW9uKFwiZnVsbFNjcmVlblwiLCBmYWxzZSwgZnVuY3Rpb24oY20sIHZhbCwgb2xkKSB7XHJcbiAgICBpZiAob2xkID09IENvZGVNaXJyb3IuSW5pdCkgb2xkID0gZmFsc2U7XHJcbiAgICBpZiAoIW9sZCA9PSAhdmFsKSByZXR1cm47XHJcbiAgICBpZiAodmFsKSBzZXRGdWxsc2NyZWVuKGNtKTtcclxuICAgIGVsc2Ugc2V0Tm9ybWFsKGNtKTtcclxuICB9KTtcclxuXHJcbiAgZnVuY3Rpb24gc2V0RnVsbHNjcmVlbihjbSkge1xyXG4gICAgdmFyIHdyYXAgPSBjbS5nZXRXcmFwcGVyRWxlbWVudCgpO1xyXG4gICAgY20uc3RhdGUuZnVsbFNjcmVlblJlc3RvcmUgPSB7c2Nyb2xsVG9wOiB3aW5kb3cucGFnZVlPZmZzZXQsIHNjcm9sbExlZnQ6IHdpbmRvdy5wYWdlWE9mZnNldCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoOiB3cmFwLnN0eWxlLndpZHRoLCBoZWlnaHQ6IHdyYXAuc3R5bGUuaGVpZ2h0fTtcclxuICAgIHdyYXAuc3R5bGUud2lkdGggPSBcIlwiO1xyXG4gICAgd3JhcC5zdHlsZS5oZWlnaHQgPSBcImF1dG9cIjtcclxuICAgIHdyYXAuY2xhc3NOYW1lICs9IFwiIENvZGVNaXJyb3ItZnVsbHNjcmVlblwiO1xyXG4gICAgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlLm92ZXJmbG93ID0gXCJoaWRkZW5cIjtcclxuICAgIGNtLnJlZnJlc2goKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIHNldE5vcm1hbChjbSkge1xyXG4gICAgdmFyIHdyYXAgPSBjbS5nZXRXcmFwcGVyRWxlbWVudCgpO1xyXG4gICAgd3JhcC5jbGFzc05hbWUgPSB3cmFwLmNsYXNzTmFtZS5yZXBsYWNlKC9cXHMqQ29kZU1pcnJvci1mdWxsc2NyZWVuXFxiLywgXCJcIik7XHJcbiAgICBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGUub3ZlcmZsb3cgPSBcIlwiO1xyXG4gICAgdmFyIGluZm8gPSBjbS5zdGF0ZS5mdWxsU2NyZWVuUmVzdG9yZTtcclxuICAgIHdyYXAuc3R5bGUud2lkdGggPSBpbmZvLndpZHRoOyB3cmFwLnN0eWxlLmhlaWdodCA9IGluZm8uaGVpZ2h0O1xyXG4gICAgd2luZG93LnNjcm9sbFRvKGluZm8uc2Nyb2xsTGVmdCwgaW5mby5zY3JvbGxUb3ApO1xyXG4gICAgY20ucmVmcmVzaCgpO1xyXG4gIH1cclxufSk7XHJcbiIsIi8vIENvZGVNaXJyb3IsIGNvcHlyaWdodCAoYykgYnkgTWFyaWpuIEhhdmVyYmVrZSBhbmQgb3RoZXJzXHJcbi8vIERpc3RyaWJ1dGVkIHVuZGVyIGFuIE1JVCBsaWNlbnNlOiBodHRwOi8vY29kZW1pcnJvci5uZXQvTElDRU5TRVxyXG5cclxuKGZ1bmN0aW9uKG1vZCkge1xyXG4gIGlmICh0eXBlb2YgZXhwb3J0cyA9PSBcIm9iamVjdFwiICYmIHR5cGVvZiBtb2R1bGUgPT0gXCJvYmplY3RcIikgLy8gQ29tbW9uSlNcclxuICAgIG1vZChyZXF1aXJlKFwiLi4vLi4vbGliL2NvZGVtaXJyb3JcIikpO1xyXG4gIGVsc2UgaWYgKHR5cGVvZiBkZWZpbmUgPT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQpIC8vIEFNRFxyXG4gICAgZGVmaW5lKFtcIi4uLy4uL2xpYi9jb2RlbWlycm9yXCJdLCBtb2QpO1xyXG4gIGVsc2UgLy8gUGxhaW4gYnJvd3NlciBlbnZcclxuICAgIG1vZChDb2RlTWlycm9yKTtcclxufSkoZnVuY3Rpb24oQ29kZU1pcnJvcikge1xyXG4gIFwidXNlIHN0cmljdFwiO1xyXG5cclxuICB2YXIgbGlzdFJFID0gL14oXFxzKikoPls+IF0qfFsqKy1dXFxzfChcXGQrKShbLildKSkoXFxzKikvLFxyXG4gICAgICBlbXB0eUxpc3RSRSA9IC9eKFxccyopKD5bPiBdKnxbKistXXwoXFxkKylbLildKShcXHMqKSQvLFxyXG4gICAgICB1bm9yZGVyZWRMaXN0UkUgPSAvWyorLV1cXHMvO1xyXG5cclxuICBDb2RlTWlycm9yLmNvbW1hbmRzLm5ld2xpbmVBbmRJbmRlbnRDb250aW51ZU1hcmtkb3duTGlzdCA9IGZ1bmN0aW9uKGNtKSB7XHJcbiAgICBpZiAoY20uZ2V0T3B0aW9uKFwiZGlzYWJsZUlucHV0XCIpKSByZXR1cm4gQ29kZU1pcnJvci5QYXNzO1xyXG4gICAgdmFyIHJhbmdlcyA9IGNtLmxpc3RTZWxlY3Rpb25zKCksIHJlcGxhY2VtZW50cyA9IFtdO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCByYW5nZXMubGVuZ3RoOyBpKyspIHtcclxuICAgICAgdmFyIHBvcyA9IHJhbmdlc1tpXS5oZWFkO1xyXG4gICAgICB2YXIgZW9sU3RhdGUgPSBjbS5nZXRTdGF0ZUFmdGVyKHBvcy5saW5lKTtcclxuICAgICAgdmFyIGluTGlzdCA9IGVvbFN0YXRlLmxpc3QgIT09IGZhbHNlO1xyXG4gICAgICB2YXIgaW5RdW90ZSA9IGVvbFN0YXRlLnF1b3RlICE9PSAwO1xyXG5cclxuICAgICAgdmFyIGxpbmUgPSBjbS5nZXRMaW5lKHBvcy5saW5lKSwgbWF0Y2ggPSBsaXN0UkUuZXhlYyhsaW5lKTtcclxuICAgICAgaWYgKCFyYW5nZXNbaV0uZW1wdHkoKSB8fCAoIWluTGlzdCAmJiAhaW5RdW90ZSkgfHwgIW1hdGNoKSB7XHJcbiAgICAgICAgY20uZXhlY0NvbW1hbmQoXCJuZXdsaW5lQW5kSW5kZW50XCIpO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG4gICAgICBpZiAoZW1wdHlMaXN0UkUudGVzdChsaW5lKSkge1xyXG4gICAgICAgIGNtLnJlcGxhY2VSYW5nZShcIlwiLCB7XHJcbiAgICAgICAgICBsaW5lOiBwb3MubGluZSwgY2g6IDBcclxuICAgICAgICB9LCB7XHJcbiAgICAgICAgICBsaW5lOiBwb3MubGluZSwgY2g6IHBvcy5jaCArIDFcclxuICAgICAgICB9KTtcclxuICAgICAgICByZXBsYWNlbWVudHNbaV0gPSBcIlxcblwiO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHZhciBpbmRlbnQgPSBtYXRjaFsxXSwgYWZ0ZXIgPSBtYXRjaFs1XTtcclxuICAgICAgICB2YXIgYnVsbGV0ID0gdW5vcmRlcmVkTGlzdFJFLnRlc3QobWF0Y2hbMl0pIHx8IG1hdGNoWzJdLmluZGV4T2YoXCI+XCIpID49IDBcclxuICAgICAgICAgID8gbWF0Y2hbMl1cclxuICAgICAgICAgIDogKHBhcnNlSW50KG1hdGNoWzNdLCAxMCkgKyAxKSArIG1hdGNoWzRdO1xyXG5cclxuICAgICAgICByZXBsYWNlbWVudHNbaV0gPSBcIlxcblwiICsgaW5kZW50ICsgYnVsbGV0ICsgYWZ0ZXI7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBjbS5yZXBsYWNlU2VsZWN0aW9ucyhyZXBsYWNlbWVudHMpO1xyXG4gIH07XHJcbn0pO1xyXG4iLCIvLyBDb2RlTWlycm9yLCBjb3B5cmlnaHQgKGMpIGJ5IE1hcmlqbiBIYXZlcmJla2UgYW5kIG90aGVyc1xyXG4vLyBEaXN0cmlidXRlZCB1bmRlciBhbiBNSVQgbGljZW5zZTogaHR0cDovL2NvZGVtaXJyb3IubmV0L0xJQ0VOU0VcclxuXHJcbi8vIFV0aWxpdHkgZnVuY3Rpb24gdGhhdCBhbGxvd3MgbW9kZXMgdG8gYmUgY29tYmluZWQuIFRoZSBtb2RlIGdpdmVuXHJcbi8vIGFzIHRoZSBiYXNlIGFyZ3VtZW50IHRha2VzIGNhcmUgb2YgbW9zdCBvZiB0aGUgbm9ybWFsIG1vZGVcclxuLy8gZnVuY3Rpb25hbGl0eSwgYnV0IGEgc2Vjb25kICh0eXBpY2FsbHkgc2ltcGxlKSBtb2RlIGlzIHVzZWQsIHdoaWNoXHJcbi8vIGNhbiBvdmVycmlkZSB0aGUgc3R5bGUgb2YgdGV4dC4gQm90aCBtb2RlcyBnZXQgdG8gcGFyc2UgYWxsIG9mIHRoZVxyXG4vLyB0ZXh0LCBidXQgd2hlbiBib3RoIGFzc2lnbiBhIG5vbi1udWxsIHN0eWxlIHRvIGEgcGllY2Ugb2YgY29kZSwgdGhlXHJcbi8vIG92ZXJsYXkgd2lucywgdW5sZXNzIHRoZSBjb21iaW5lIGFyZ3VtZW50IHdhcyB0cnVlIGFuZCBub3Qgb3ZlcnJpZGRlbixcclxuLy8gb3Igc3RhdGUub3ZlcmxheS5jb21iaW5lVG9rZW5zIHdhcyB0cnVlLCBpbiB3aGljaCBjYXNlIHRoZSBzdHlsZXMgYXJlXHJcbi8vIGNvbWJpbmVkLlxyXG5cclxuKGZ1bmN0aW9uKG1vZCkge1xyXG4gIGlmICh0eXBlb2YgZXhwb3J0cyA9PSBcIm9iamVjdFwiICYmIHR5cGVvZiBtb2R1bGUgPT0gXCJvYmplY3RcIikgLy8gQ29tbW9uSlNcclxuICAgIG1vZChyZXF1aXJlKFwiLi4vLi4vbGliL2NvZGVtaXJyb3JcIikpO1xyXG4gIGVsc2UgaWYgKHR5cGVvZiBkZWZpbmUgPT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQpIC8vIEFNRFxyXG4gICAgZGVmaW5lKFtcIi4uLy4uL2xpYi9jb2RlbWlycm9yXCJdLCBtb2QpO1xyXG4gIGVsc2UgLy8gUGxhaW4gYnJvd3NlciBlbnZcclxuICAgIG1vZChDb2RlTWlycm9yKTtcclxufSkoZnVuY3Rpb24oQ29kZU1pcnJvcikge1xyXG5cInVzZSBzdHJpY3RcIjtcclxuXHJcbkNvZGVNaXJyb3Iub3ZlcmxheU1vZGUgPSBmdW5jdGlvbihiYXNlLCBvdmVybGF5LCBjb21iaW5lKSB7XHJcbiAgcmV0dXJuIHtcclxuICAgIHN0YXJ0U3RhdGU6IGZ1bmN0aW9uKCkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIGJhc2U6IENvZGVNaXJyb3Iuc3RhcnRTdGF0ZShiYXNlKSxcclxuICAgICAgICBvdmVybGF5OiBDb2RlTWlycm9yLnN0YXJ0U3RhdGUob3ZlcmxheSksXHJcbiAgICAgICAgYmFzZVBvczogMCwgYmFzZUN1cjogbnVsbCxcclxuICAgICAgICBvdmVybGF5UG9zOiAwLCBvdmVybGF5Q3VyOiBudWxsLFxyXG4gICAgICAgIHN0cmVhbVNlZW46IG51bGxcclxuICAgICAgfTtcclxuICAgIH0sXHJcbiAgICBjb3B5U3RhdGU6IGZ1bmN0aW9uKHN0YXRlKSB7XHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgYmFzZTogQ29kZU1pcnJvci5jb3B5U3RhdGUoYmFzZSwgc3RhdGUuYmFzZSksXHJcbiAgICAgICAgb3ZlcmxheTogQ29kZU1pcnJvci5jb3B5U3RhdGUob3ZlcmxheSwgc3RhdGUub3ZlcmxheSksXHJcbiAgICAgICAgYmFzZVBvczogc3RhdGUuYmFzZVBvcywgYmFzZUN1cjogbnVsbCxcclxuICAgICAgICBvdmVybGF5UG9zOiBzdGF0ZS5vdmVybGF5UG9zLCBvdmVybGF5Q3VyOiBudWxsXHJcbiAgICAgIH07XHJcbiAgICB9LFxyXG5cclxuICAgIHRva2VuOiBmdW5jdGlvbihzdHJlYW0sIHN0YXRlKSB7XHJcbiAgICAgIGlmIChzdHJlYW0gIT0gc3RhdGUuc3RyZWFtU2VlbiB8fFxyXG4gICAgICAgICAgTWF0aC5taW4oc3RhdGUuYmFzZVBvcywgc3RhdGUub3ZlcmxheVBvcykgPCBzdHJlYW0uc3RhcnQpIHtcclxuICAgICAgICBzdGF0ZS5zdHJlYW1TZWVuID0gc3RyZWFtO1xyXG4gICAgICAgIHN0YXRlLmJhc2VQb3MgPSBzdGF0ZS5vdmVybGF5UG9zID0gc3RyZWFtLnN0YXJ0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoc3RyZWFtLnN0YXJ0ID09IHN0YXRlLmJhc2VQb3MpIHtcclxuICAgICAgICBzdGF0ZS5iYXNlQ3VyID0gYmFzZS50b2tlbihzdHJlYW0sIHN0YXRlLmJhc2UpO1xyXG4gICAgICAgIHN0YXRlLmJhc2VQb3MgPSBzdHJlYW0ucG9zO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChzdHJlYW0uc3RhcnQgPT0gc3RhdGUub3ZlcmxheVBvcykge1xyXG4gICAgICAgIHN0cmVhbS5wb3MgPSBzdHJlYW0uc3RhcnQ7XHJcbiAgICAgICAgc3RhdGUub3ZlcmxheUN1ciA9IG92ZXJsYXkudG9rZW4oc3RyZWFtLCBzdGF0ZS5vdmVybGF5KTtcclxuICAgICAgICBzdGF0ZS5vdmVybGF5UG9zID0gc3RyZWFtLnBvcztcclxuICAgICAgfVxyXG4gICAgICBzdHJlYW0ucG9zID0gTWF0aC5taW4oc3RhdGUuYmFzZVBvcywgc3RhdGUub3ZlcmxheVBvcyk7XHJcblxyXG4gICAgICAvLyBzdGF0ZS5vdmVybGF5LmNvbWJpbmVUb2tlbnMgYWx3YXlzIHRha2VzIHByZWNlZGVuY2Ugb3ZlciBjb21iaW5lLFxyXG4gICAgICAvLyB1bmxlc3Mgc2V0IHRvIG51bGxcclxuICAgICAgaWYgKHN0YXRlLm92ZXJsYXlDdXIgPT0gbnVsbCkgcmV0dXJuIHN0YXRlLmJhc2VDdXI7XHJcbiAgICAgIGVsc2UgaWYgKHN0YXRlLmJhc2VDdXIgIT0gbnVsbCAmJlxyXG4gICAgICAgICAgICAgICBzdGF0ZS5vdmVybGF5LmNvbWJpbmVUb2tlbnMgfHxcclxuICAgICAgICAgICAgICAgY29tYmluZSAmJiBzdGF0ZS5vdmVybGF5LmNvbWJpbmVUb2tlbnMgPT0gbnVsbClcclxuICAgICAgICByZXR1cm4gc3RhdGUuYmFzZUN1ciArIFwiIFwiICsgc3RhdGUub3ZlcmxheUN1cjtcclxuICAgICAgZWxzZSByZXR1cm4gc3RhdGUub3ZlcmxheUN1cjtcclxuICAgIH0sXHJcblxyXG4gICAgaW5kZW50OiBiYXNlLmluZGVudCAmJiBmdW5jdGlvbihzdGF0ZSwgdGV4dEFmdGVyKSB7XHJcbiAgICAgIHJldHVybiBiYXNlLmluZGVudChzdGF0ZS5iYXNlLCB0ZXh0QWZ0ZXIpO1xyXG4gICAgfSxcclxuICAgIGVsZWN0cmljQ2hhcnM6IGJhc2UuZWxlY3RyaWNDaGFycyxcclxuXHJcbiAgICBpbm5lck1vZGU6IGZ1bmN0aW9uKHN0YXRlKSB7IHJldHVybiB7c3RhdGU6IHN0YXRlLmJhc2UsIG1vZGU6IGJhc2V9OyB9LFxyXG5cclxuICAgIGJsYW5rTGluZTogZnVuY3Rpb24oc3RhdGUpIHtcclxuICAgICAgaWYgKGJhc2UuYmxhbmtMaW5lKSBiYXNlLmJsYW5rTGluZShzdGF0ZS5iYXNlKTtcclxuICAgICAgaWYgKG92ZXJsYXkuYmxhbmtMaW5lKSBvdmVybGF5LmJsYW5rTGluZShzdGF0ZS5vdmVybGF5KTtcclxuICAgIH1cclxuICB9O1xyXG59O1xyXG5cclxufSk7XHJcbiIsIi8vIENvZGVNaXJyb3IsIGNvcHlyaWdodCAoYykgYnkgTWFyaWpuIEhhdmVyYmVrZSBhbmQgb3RoZXJzXHJcbi8vIERpc3RyaWJ1dGVkIHVuZGVyIGFuIE1JVCBsaWNlbnNlOiBodHRwOi8vY29kZW1pcnJvci5uZXQvTElDRU5TRVxyXG5cclxuLy8gVGhpcyBpcyBDb2RlTWlycm9yIChodHRwOi8vY29kZW1pcnJvci5uZXQpLCBhIGNvZGUgZWRpdG9yXHJcbi8vIGltcGxlbWVudGVkIGluIEphdmFTY3JpcHQgb24gdG9wIG9mIHRoZSBicm93c2VyJ3MgRE9NLlxyXG4vL1xyXG4vLyBZb3UgY2FuIGZpbmQgc29tZSB0ZWNobmljYWwgYmFja2dyb3VuZCBmb3Igc29tZSBvZiB0aGUgY29kZSBiZWxvd1xyXG4vLyBhdCBodHRwOi8vbWFyaWpuaGF2ZXJiZWtlLm5sL2Jsb2cvI2NtLWludGVybmFscyAuXHJcblxyXG4oZnVuY3Rpb24obW9kKSB7XHJcbiAgaWYgKHR5cGVvZiBleHBvcnRzID09IFwib2JqZWN0XCIgJiYgdHlwZW9mIG1vZHVsZSA9PSBcIm9iamVjdFwiKSAvLyBDb21tb25KU1xyXG4gICAgbW9kdWxlLmV4cG9ydHMgPSBtb2QoKTtcclxuICBlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kKSAvLyBBTURcclxuICAgIHJldHVybiBkZWZpbmUoW10sIG1vZCk7XHJcbiAgZWxzZSAvLyBQbGFpbiBicm93c2VyIGVudlxyXG4gICAgdGhpcy5Db2RlTWlycm9yID0gbW9kKCk7XHJcbn0pKGZ1bmN0aW9uKCkge1xyXG4gIFwidXNlIHN0cmljdFwiO1xyXG5cclxuICAvLyBCUk9XU0VSIFNOSUZGSU5HXHJcblxyXG4gIC8vIEtsdWRnZXMgZm9yIGJ1Z3MgYW5kIGJlaGF2aW9yIGRpZmZlcmVuY2VzIHRoYXQgY2FuJ3QgYmUgZmVhdHVyZVxyXG4gIC8vIGRldGVjdGVkIGFyZSBlbmFibGVkIGJhc2VkIG9uIHVzZXJBZ2VudCBldGMgc25pZmZpbmcuXHJcbiAgdmFyIHVzZXJBZ2VudCA9IG5hdmlnYXRvci51c2VyQWdlbnQ7XHJcbiAgdmFyIHBsYXRmb3JtID0gbmF2aWdhdG9yLnBsYXRmb3JtO1xyXG5cclxuICB2YXIgZ2Vja28gPSAvZ2Vja29cXC9cXGQvaS50ZXN0KHVzZXJBZ2VudCk7XHJcbiAgdmFyIGllX3VwdG8xMCA9IC9NU0lFIFxcZC8udGVzdCh1c2VyQWdlbnQpO1xyXG4gIHZhciBpZV8xMXVwID0gL1RyaWRlbnRcXC8oPzpbNy05XXxcXGR7Mix9KVxcLi4qcnY6KFxcZCspLy5leGVjKHVzZXJBZ2VudCk7XHJcbiAgdmFyIGllID0gaWVfdXB0bzEwIHx8IGllXzExdXA7XHJcbiAgdmFyIGllX3ZlcnNpb24gPSBpZSAmJiAoaWVfdXB0bzEwID8gZG9jdW1lbnQuZG9jdW1lbnRNb2RlIHx8IDYgOiBpZV8xMXVwWzFdKTtcclxuICB2YXIgd2Via2l0ID0gL1dlYktpdFxcLy8udGVzdCh1c2VyQWdlbnQpO1xyXG4gIHZhciBxdHdlYmtpdCA9IHdlYmtpdCAmJiAvUXRcXC9cXGQrXFwuXFxkKy8udGVzdCh1c2VyQWdlbnQpO1xyXG4gIHZhciBjaHJvbWUgPSAvQ2hyb21lXFwvLy50ZXN0KHVzZXJBZ2VudCk7XHJcbiAgdmFyIHByZXN0byA9IC9PcGVyYVxcLy8udGVzdCh1c2VyQWdlbnQpO1xyXG4gIHZhciBzYWZhcmkgPSAvQXBwbGUgQ29tcHV0ZXIvLnRlc3QobmF2aWdhdG9yLnZlbmRvcik7XHJcbiAgdmFyIG1hY19nZU1vdW50YWluTGlvbiA9IC9NYWMgT1MgWCAxXFxkXFxEKFs4LTldfFxcZFxcZClcXEQvLnRlc3QodXNlckFnZW50KTtcclxuICB2YXIgcGhhbnRvbSA9IC9QaGFudG9tSlMvLnRlc3QodXNlckFnZW50KTtcclxuXHJcbiAgdmFyIGlvcyA9IC9BcHBsZVdlYktpdC8udGVzdCh1c2VyQWdlbnQpICYmIC9Nb2JpbGVcXC9cXHcrLy50ZXN0KHVzZXJBZ2VudCk7XHJcbiAgLy8gVGhpcyBpcyB3b2VmdWxseSBpbmNvbXBsZXRlLiBTdWdnZXN0aW9ucyBmb3IgYWx0ZXJuYXRpdmUgbWV0aG9kcyB3ZWxjb21lLlxyXG4gIHZhciBtb2JpbGUgPSBpb3MgfHwgL0FuZHJvaWR8d2ViT1N8QmxhY2tCZXJyeXxPcGVyYSBNaW5pfE9wZXJhIE1vYml8SUVNb2JpbGUvaS50ZXN0KHVzZXJBZ2VudCk7XHJcbiAgdmFyIG1hYyA9IGlvcyB8fCAvTWFjLy50ZXN0KHBsYXRmb3JtKTtcclxuICB2YXIgd2luZG93cyA9IC93aW4vaS50ZXN0KHBsYXRmb3JtKTtcclxuXHJcbiAgdmFyIHByZXN0b192ZXJzaW9uID0gcHJlc3RvICYmIHVzZXJBZ2VudC5tYXRjaCgvVmVyc2lvblxcLyhcXGQqXFwuXFxkKikvKTtcclxuICBpZiAocHJlc3RvX3ZlcnNpb24pIHByZXN0b192ZXJzaW9uID0gTnVtYmVyKHByZXN0b192ZXJzaW9uWzFdKTtcclxuICBpZiAocHJlc3RvX3ZlcnNpb24gJiYgcHJlc3RvX3ZlcnNpb24gPj0gMTUpIHsgcHJlc3RvID0gZmFsc2U7IHdlYmtpdCA9IHRydWU7IH1cclxuICAvLyBTb21lIGJyb3dzZXJzIHVzZSB0aGUgd3JvbmcgZXZlbnQgcHJvcGVydGllcyB0byBzaWduYWwgY21kL2N0cmwgb24gT1MgWFxyXG4gIHZhciBmbGlwQ3RybENtZCA9IG1hYyAmJiAocXR3ZWJraXQgfHwgcHJlc3RvICYmIChwcmVzdG9fdmVyc2lvbiA9PSBudWxsIHx8IHByZXN0b192ZXJzaW9uIDwgMTIuMTEpKTtcclxuICB2YXIgY2FwdHVyZVJpZ2h0Q2xpY2sgPSBnZWNrbyB8fCAoaWUgJiYgaWVfdmVyc2lvbiA+PSA5KTtcclxuXHJcbiAgLy8gT3B0aW1pemUgc29tZSBjb2RlIHdoZW4gdGhlc2UgZmVhdHVyZXMgYXJlIG5vdCB1c2VkLlxyXG4gIHZhciBzYXdSZWFkT25seVNwYW5zID0gZmFsc2UsIHNhd0NvbGxhcHNlZFNwYW5zID0gZmFsc2U7XHJcblxyXG4gIC8vIEVESVRPUiBDT05TVFJVQ1RPUlxyXG5cclxuICAvLyBBIENvZGVNaXJyb3IgaW5zdGFuY2UgcmVwcmVzZW50cyBhbiBlZGl0b3IuIFRoaXMgaXMgdGhlIG9iamVjdFxyXG4gIC8vIHRoYXQgdXNlciBjb2RlIGlzIHVzdWFsbHkgZGVhbGluZyB3aXRoLlxyXG5cclxuICBmdW5jdGlvbiBDb2RlTWlycm9yKHBsYWNlLCBvcHRpb25zKSB7XHJcbiAgICBpZiAoISh0aGlzIGluc3RhbmNlb2YgQ29kZU1pcnJvcikpIHJldHVybiBuZXcgQ29kZU1pcnJvcihwbGFjZSwgb3B0aW9ucyk7XHJcblxyXG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucyA9IG9wdGlvbnMgPyBjb3B5T2JqKG9wdGlvbnMpIDoge307XHJcbiAgICAvLyBEZXRlcm1pbmUgZWZmZWN0aXZlIG9wdGlvbnMgYmFzZWQgb24gZ2l2ZW4gdmFsdWVzIGFuZCBkZWZhdWx0cy5cclxuICAgIGNvcHlPYmooZGVmYXVsdHMsIG9wdGlvbnMsIGZhbHNlKTtcclxuICAgIHNldEd1dHRlcnNGb3JMaW5lTnVtYmVycyhvcHRpb25zKTtcclxuXHJcbiAgICB2YXIgZG9jID0gb3B0aW9ucy52YWx1ZTtcclxuICAgIGlmICh0eXBlb2YgZG9jID09IFwic3RyaW5nXCIpIGRvYyA9IG5ldyBEb2MoZG9jLCBvcHRpb25zLm1vZGUsIG51bGwsIG9wdGlvbnMubGluZVNlcGFyYXRvcik7XHJcbiAgICB0aGlzLmRvYyA9IGRvYztcclxuXHJcbiAgICB2YXIgaW5wdXQgPSBuZXcgQ29kZU1pcnJvci5pbnB1dFN0eWxlc1tvcHRpb25zLmlucHV0U3R5bGVdKHRoaXMpO1xyXG4gICAgdmFyIGRpc3BsYXkgPSB0aGlzLmRpc3BsYXkgPSBuZXcgRGlzcGxheShwbGFjZSwgZG9jLCBpbnB1dCk7XHJcbiAgICBkaXNwbGF5LndyYXBwZXIuQ29kZU1pcnJvciA9IHRoaXM7XHJcbiAgICB1cGRhdGVHdXR0ZXJzKHRoaXMpO1xyXG4gICAgdGhlbWVDaGFuZ2VkKHRoaXMpO1xyXG4gICAgaWYgKG9wdGlvbnMubGluZVdyYXBwaW5nKVxyXG4gICAgICB0aGlzLmRpc3BsYXkud3JhcHBlci5jbGFzc05hbWUgKz0gXCIgQ29kZU1pcnJvci13cmFwXCI7XHJcbiAgICBpZiAob3B0aW9ucy5hdXRvZm9jdXMgJiYgIW1vYmlsZSkgZGlzcGxheS5pbnB1dC5mb2N1cygpO1xyXG4gICAgaW5pdFNjcm9sbGJhcnModGhpcyk7XHJcblxyXG4gICAgdGhpcy5zdGF0ZSA9IHtcclxuICAgICAga2V5TWFwczogW10sICAvLyBzdG9yZXMgbWFwcyBhZGRlZCBieSBhZGRLZXlNYXBcclxuICAgICAgb3ZlcmxheXM6IFtdLCAvLyBoaWdobGlnaHRpbmcgb3ZlcmxheXMsIGFzIGFkZGVkIGJ5IGFkZE92ZXJsYXlcclxuICAgICAgbW9kZUdlbjogMCwgICAvLyBidW1wZWQgd2hlbiBtb2RlL292ZXJsYXkgY2hhbmdlcywgdXNlZCB0byBpbnZhbGlkYXRlIGhpZ2hsaWdodGluZyBpbmZvXHJcbiAgICAgIG92ZXJ3cml0ZTogZmFsc2UsXHJcbiAgICAgIGRlbGF5aW5nQmx1ckV2ZW50OiBmYWxzZSxcclxuICAgICAgZm9jdXNlZDogZmFsc2UsXHJcbiAgICAgIHN1cHByZXNzRWRpdHM6IGZhbHNlLCAvLyB1c2VkIHRvIGRpc2FibGUgZWRpdGluZyBkdXJpbmcga2V5IGhhbmRsZXJzIHdoZW4gaW4gcmVhZE9ubHkgbW9kZVxyXG4gICAgICBwYXN0ZUluY29taW5nOiBmYWxzZSwgY3V0SW5jb21pbmc6IGZhbHNlLCAvLyBoZWxwIHJlY29nbml6ZSBwYXN0ZS9jdXQgZWRpdHMgaW4gaW5wdXQucG9sbFxyXG4gICAgICBzZWxlY3RpbmdUZXh0OiBmYWxzZSxcclxuICAgICAgZHJhZ2dpbmdUZXh0OiBmYWxzZSxcclxuICAgICAgaGlnaGxpZ2h0OiBuZXcgRGVsYXllZCgpLCAvLyBzdG9yZXMgaGlnaGxpZ2h0IHdvcmtlciB0aW1lb3V0XHJcbiAgICAgIGtleVNlcTogbnVsbCwgIC8vIFVuZmluaXNoZWQga2V5IHNlcXVlbmNlXHJcbiAgICAgIHNwZWNpYWxDaGFyczogbnVsbFxyXG4gICAgfTtcclxuXHJcbiAgICB2YXIgY20gPSB0aGlzO1xyXG5cclxuICAgIC8vIE92ZXJyaWRlIG1hZ2ljIHRleHRhcmVhIGNvbnRlbnQgcmVzdG9yZSB0aGF0IElFIHNvbWV0aW1lcyBkb2VzXHJcbiAgICAvLyBvbiBvdXIgaGlkZGVuIHRleHRhcmVhIG9uIHJlbG9hZFxyXG4gICAgaWYgKGllICYmIGllX3ZlcnNpb24gPCAxMSkgc2V0VGltZW91dChmdW5jdGlvbigpIHsgY20uZGlzcGxheS5pbnB1dC5yZXNldCh0cnVlKTsgfSwgMjApO1xyXG5cclxuICAgIHJlZ2lzdGVyRXZlbnRIYW5kbGVycyh0aGlzKTtcclxuICAgIGVuc3VyZUdsb2JhbEhhbmRsZXJzKCk7XHJcblxyXG4gICAgc3RhcnRPcGVyYXRpb24odGhpcyk7XHJcbiAgICB0aGlzLmN1ck9wLmZvcmNlVXBkYXRlID0gdHJ1ZTtcclxuICAgIGF0dGFjaERvYyh0aGlzLCBkb2MpO1xyXG5cclxuICAgIGlmICgob3B0aW9ucy5hdXRvZm9jdXMgJiYgIW1vYmlsZSkgfHwgY20uaGFzRm9jdXMoKSlcclxuICAgICAgc2V0VGltZW91dChiaW5kKG9uRm9jdXMsIHRoaXMpLCAyMCk7XHJcbiAgICBlbHNlXHJcbiAgICAgIG9uQmx1cih0aGlzKTtcclxuXHJcbiAgICBmb3IgKHZhciBvcHQgaW4gb3B0aW9uSGFuZGxlcnMpIGlmIChvcHRpb25IYW5kbGVycy5oYXNPd25Qcm9wZXJ0eShvcHQpKVxyXG4gICAgICBvcHRpb25IYW5kbGVyc1tvcHRdKHRoaXMsIG9wdGlvbnNbb3B0XSwgSW5pdCk7XHJcbiAgICBtYXliZVVwZGF0ZUxpbmVOdW1iZXJXaWR0aCh0aGlzKTtcclxuICAgIGlmIChvcHRpb25zLmZpbmlzaEluaXQpIG9wdGlvbnMuZmluaXNoSW5pdCh0aGlzKTtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaW5pdEhvb2tzLmxlbmd0aDsgKytpKSBpbml0SG9va3NbaV0odGhpcyk7XHJcbiAgICBlbmRPcGVyYXRpb24odGhpcyk7XHJcbiAgICAvLyBTdXBwcmVzcyBvcHRpbWl6ZWxlZ2liaWxpdHkgaW4gV2Via2l0LCBzaW5jZSBpdCBicmVha3MgdGV4dFxyXG4gICAgLy8gbWVhc3VyaW5nIG9uIGxpbmUgd3JhcHBpbmcgYm91bmRhcmllcy5cclxuICAgIGlmICh3ZWJraXQgJiYgb3B0aW9ucy5saW5lV3JhcHBpbmcgJiZcclxuICAgICAgICBnZXRDb21wdXRlZFN0eWxlKGRpc3BsYXkubGluZURpdikudGV4dFJlbmRlcmluZyA9PSBcIm9wdGltaXplbGVnaWJpbGl0eVwiKVxyXG4gICAgICBkaXNwbGF5LmxpbmVEaXYuc3R5bGUudGV4dFJlbmRlcmluZyA9IFwiYXV0b1wiO1xyXG4gIH1cclxuXHJcbiAgLy8gRElTUExBWSBDT05TVFJVQ1RPUlxyXG5cclxuICAvLyBUaGUgZGlzcGxheSBoYW5kbGVzIHRoZSBET00gaW50ZWdyYXRpb24sIGJvdGggZm9yIGlucHV0IHJlYWRpbmdcclxuICAvLyBhbmQgY29udGVudCBkcmF3aW5nLiBJdCBob2xkcyByZWZlcmVuY2VzIHRvIERPTSBub2RlcyBhbmRcclxuICAvLyBkaXNwbGF5LXJlbGF0ZWQgc3RhdGUuXHJcblxyXG4gIGZ1bmN0aW9uIERpc3BsYXkocGxhY2UsIGRvYywgaW5wdXQpIHtcclxuICAgIHZhciBkID0gdGhpcztcclxuICAgIHRoaXMuaW5wdXQgPSBpbnB1dDtcclxuXHJcbiAgICAvLyBDb3ZlcnMgYm90dG9tLXJpZ2h0IHNxdWFyZSB3aGVuIGJvdGggc2Nyb2xsYmFycyBhcmUgcHJlc2VudC5cclxuICAgIGQuc2Nyb2xsYmFyRmlsbGVyID0gZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1zY3JvbGxiYXItZmlsbGVyXCIpO1xyXG4gICAgZC5zY3JvbGxiYXJGaWxsZXIuc2V0QXR0cmlidXRlKFwiY20tbm90LWNvbnRlbnRcIiwgXCJ0cnVlXCIpO1xyXG4gICAgLy8gQ292ZXJzIGJvdHRvbSBvZiBndXR0ZXIgd2hlbiBjb3Zlckd1dHRlck5leHRUb1Njcm9sbGJhciBpcyBvblxyXG4gICAgLy8gYW5kIGggc2Nyb2xsYmFyIGlzIHByZXNlbnQuXHJcbiAgICBkLmd1dHRlckZpbGxlciA9IGVsdChcImRpdlwiLCBudWxsLCBcIkNvZGVNaXJyb3ItZ3V0dGVyLWZpbGxlclwiKTtcclxuICAgIGQuZ3V0dGVyRmlsbGVyLnNldEF0dHJpYnV0ZShcImNtLW5vdC1jb250ZW50XCIsIFwidHJ1ZVwiKTtcclxuICAgIC8vIFdpbGwgY29udGFpbiB0aGUgYWN0dWFsIGNvZGUsIHBvc2l0aW9uZWQgdG8gY292ZXIgdGhlIHZpZXdwb3J0LlxyXG4gICAgZC5saW5lRGl2ID0gZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1jb2RlXCIpO1xyXG4gICAgLy8gRWxlbWVudHMgYXJlIGFkZGVkIHRvIHRoZXNlIHRvIHJlcHJlc2VudCBzZWxlY3Rpb24gYW5kIGN1cnNvcnMuXHJcbiAgICBkLnNlbGVjdGlvbkRpdiA9IGVsdChcImRpdlwiLCBudWxsLCBudWxsLCBcInBvc2l0aW9uOiByZWxhdGl2ZTsgei1pbmRleDogMVwiKTtcclxuICAgIGQuY3Vyc29yRGl2ID0gZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1jdXJzb3JzXCIpO1xyXG4gICAgLy8gQSB2aXNpYmlsaXR5OiBoaWRkZW4gZWxlbWVudCB1c2VkIHRvIGZpbmQgdGhlIHNpemUgb2YgdGhpbmdzLlxyXG4gICAgZC5tZWFzdXJlID0gZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1tZWFzdXJlXCIpO1xyXG4gICAgLy8gV2hlbiBsaW5lcyBvdXRzaWRlIG9mIHRoZSB2aWV3cG9ydCBhcmUgbWVhc3VyZWQsIHRoZXkgYXJlIGRyYXduIGluIHRoaXMuXHJcbiAgICBkLmxpbmVNZWFzdXJlID0gZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1tZWFzdXJlXCIpO1xyXG4gICAgLy8gV3JhcHMgZXZlcnl0aGluZyB0aGF0IG5lZWRzIHRvIGV4aXN0IGluc2lkZSB0aGUgdmVydGljYWxseS1wYWRkZWQgY29vcmRpbmF0ZSBzeXN0ZW1cclxuICAgIGQubGluZVNwYWNlID0gZWx0KFwiZGl2XCIsIFtkLm1lYXN1cmUsIGQubGluZU1lYXN1cmUsIGQuc2VsZWN0aW9uRGl2LCBkLmN1cnNvckRpdiwgZC5saW5lRGl2XSxcclxuICAgICAgICAgICAgICAgICAgICAgIG51bGwsIFwicG9zaXRpb246IHJlbGF0aXZlOyBvdXRsaW5lOiBub25lXCIpO1xyXG4gICAgLy8gTW92ZWQgYXJvdW5kIGl0cyBwYXJlbnQgdG8gY292ZXIgdmlzaWJsZSB2aWV3LlxyXG4gICAgZC5tb3ZlciA9IGVsdChcImRpdlwiLCBbZWx0KFwiZGl2XCIsIFtkLmxpbmVTcGFjZV0sIFwiQ29kZU1pcnJvci1saW5lc1wiKV0sIG51bGwsIFwicG9zaXRpb246IHJlbGF0aXZlXCIpO1xyXG4gICAgLy8gU2V0IHRvIHRoZSBoZWlnaHQgb2YgdGhlIGRvY3VtZW50LCBhbGxvd2luZyBzY3JvbGxpbmcuXHJcbiAgICBkLnNpemVyID0gZWx0KFwiZGl2XCIsIFtkLm1vdmVyXSwgXCJDb2RlTWlycm9yLXNpemVyXCIpO1xyXG4gICAgZC5zaXplcldpZHRoID0gbnVsbDtcclxuICAgIC8vIEJlaGF2aW9yIG9mIGVsdHMgd2l0aCBvdmVyZmxvdzogYXV0byBhbmQgcGFkZGluZyBpc1xyXG4gICAgLy8gaW5jb25zaXN0ZW50IGFjcm9zcyBicm93c2Vycy4gVGhpcyBpcyB1c2VkIHRvIGVuc3VyZSB0aGVcclxuICAgIC8vIHNjcm9sbGFibGUgYXJlYSBpcyBiaWcgZW5vdWdoLlxyXG4gICAgZC5oZWlnaHRGb3JjZXIgPSBlbHQoXCJkaXZcIiwgbnVsbCwgbnVsbCwgXCJwb3NpdGlvbjogYWJzb2x1dGU7IGhlaWdodDogXCIgKyBzY3JvbGxlckdhcCArIFwicHg7IHdpZHRoOiAxcHg7XCIpO1xyXG4gICAgLy8gV2lsbCBjb250YWluIHRoZSBndXR0ZXJzLCBpZiBhbnkuXHJcbiAgICBkLmd1dHRlcnMgPSBlbHQoXCJkaXZcIiwgbnVsbCwgXCJDb2RlTWlycm9yLWd1dHRlcnNcIik7XHJcbiAgICBkLmxpbmVHdXR0ZXIgPSBudWxsO1xyXG4gICAgLy8gQWN0dWFsIHNjcm9sbGFibGUgZWxlbWVudC5cclxuICAgIGQuc2Nyb2xsZXIgPSBlbHQoXCJkaXZcIiwgW2Quc2l6ZXIsIGQuaGVpZ2h0Rm9yY2VyLCBkLmd1dHRlcnNdLCBcIkNvZGVNaXJyb3Itc2Nyb2xsXCIpO1xyXG4gICAgZC5zY3JvbGxlci5zZXRBdHRyaWJ1dGUoXCJ0YWJJbmRleFwiLCBcIi0xXCIpO1xyXG4gICAgLy8gVGhlIGVsZW1lbnQgaW4gd2hpY2ggdGhlIGVkaXRvciBsaXZlcy5cclxuICAgIGQud3JhcHBlciA9IGVsdChcImRpdlwiLCBbZC5zY3JvbGxiYXJGaWxsZXIsIGQuZ3V0dGVyRmlsbGVyLCBkLnNjcm9sbGVyXSwgXCJDb2RlTWlycm9yXCIpO1xyXG5cclxuICAgIC8vIFdvcmsgYXJvdW5kIElFNyB6LWluZGV4IGJ1ZyAobm90IHBlcmZlY3QsIGhlbmNlIElFNyBub3QgcmVhbGx5IGJlaW5nIHN1cHBvcnRlZClcclxuICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uIDwgOCkgeyBkLmd1dHRlcnMuc3R5bGUuekluZGV4ID0gLTE7IGQuc2Nyb2xsZXIuc3R5bGUucGFkZGluZ1JpZ2h0ID0gMDsgfVxyXG4gICAgaWYgKCF3ZWJraXQgJiYgIShnZWNrbyAmJiBtb2JpbGUpKSBkLnNjcm9sbGVyLmRyYWdnYWJsZSA9IHRydWU7XHJcblxyXG4gICAgaWYgKHBsYWNlKSB7XHJcbiAgICAgIGlmIChwbGFjZS5hcHBlbmRDaGlsZCkgcGxhY2UuYXBwZW5kQ2hpbGQoZC53cmFwcGVyKTtcclxuICAgICAgZWxzZSBwbGFjZShkLndyYXBwZXIpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEN1cnJlbnQgcmVuZGVyZWQgcmFuZ2UgKG1heSBiZSBiaWdnZXIgdGhhbiB0aGUgdmlldyB3aW5kb3cpLlxyXG4gICAgZC52aWV3RnJvbSA9IGQudmlld1RvID0gZG9jLmZpcnN0O1xyXG4gICAgZC5yZXBvcnRlZFZpZXdGcm9tID0gZC5yZXBvcnRlZFZpZXdUbyA9IGRvYy5maXJzdDtcclxuICAgIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZW5kZXJlZCBsaW5lcy5cclxuICAgIGQudmlldyA9IFtdO1xyXG4gICAgZC5yZW5kZXJlZFZpZXcgPSBudWxsO1xyXG4gICAgLy8gSG9sZHMgaW5mbyBhYm91dCBhIHNpbmdsZSByZW5kZXJlZCBsaW5lIHdoZW4gaXQgd2FzIHJlbmRlcmVkXHJcbiAgICAvLyBmb3IgbWVhc3VyZW1lbnQsIHdoaWxlIG5vdCBpbiB2aWV3LlxyXG4gICAgZC5leHRlcm5hbE1lYXN1cmVkID0gbnVsbDtcclxuICAgIC8vIEVtcHR5IHNwYWNlIChpbiBwaXhlbHMpIGFib3ZlIHRoZSB2aWV3XHJcbiAgICBkLnZpZXdPZmZzZXQgPSAwO1xyXG4gICAgZC5sYXN0V3JhcEhlaWdodCA9IGQubGFzdFdyYXBXaWR0aCA9IDA7XHJcbiAgICBkLnVwZGF0ZUxpbmVOdW1iZXJzID0gbnVsbDtcclxuXHJcbiAgICBkLm5hdGl2ZUJhcldpZHRoID0gZC5iYXJIZWlnaHQgPSBkLmJhcldpZHRoID0gMDtcclxuICAgIGQuc2Nyb2xsYmFyc0NsaXBwZWQgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBVc2VkIHRvIG9ubHkgcmVzaXplIHRoZSBsaW5lIG51bWJlciBndXR0ZXIgd2hlbiBuZWNlc3NhcnkgKHdoZW5cclxuICAgIC8vIHRoZSBhbW91bnQgb2YgbGluZXMgY3Jvc3NlcyBhIGJvdW5kYXJ5IHRoYXQgbWFrZXMgaXRzIHdpZHRoIGNoYW5nZSlcclxuICAgIGQubGluZU51bVdpZHRoID0gZC5saW5lTnVtSW5uZXJXaWR0aCA9IGQubGluZU51bUNoYXJzID0gbnVsbDtcclxuICAgIC8vIFNldCB0byB0cnVlIHdoZW4gYSBub24taG9yaXpvbnRhbC1zY3JvbGxpbmcgbGluZSB3aWRnZXQgaXNcclxuICAgIC8vIGFkZGVkLiBBcyBhbiBvcHRpbWl6YXRpb24sIGxpbmUgd2lkZ2V0IGFsaWduaW5nIGlzIHNraXBwZWQgd2hlblxyXG4gICAgLy8gdGhpcyBpcyBmYWxzZS5cclxuICAgIGQuYWxpZ25XaWRnZXRzID0gZmFsc2U7XHJcblxyXG4gICAgZC5jYWNoZWRDaGFyV2lkdGggPSBkLmNhY2hlZFRleHRIZWlnaHQgPSBkLmNhY2hlZFBhZGRpbmdIID0gbnVsbDtcclxuXHJcbiAgICAvLyBUcmFja3MgdGhlIG1heGltdW0gbGluZSBsZW5ndGggc28gdGhhdCB0aGUgaG9yaXpvbnRhbCBzY3JvbGxiYXJcclxuICAgIC8vIGNhbiBiZSBrZXB0IHN0YXRpYyB3aGVuIHNjcm9sbGluZy5cclxuICAgIGQubWF4TGluZSA9IG51bGw7XHJcbiAgICBkLm1heExpbmVMZW5ndGggPSAwO1xyXG4gICAgZC5tYXhMaW5lQ2hhbmdlZCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIG1lYXN1cmluZyB3aGVlbCBzY3JvbGxpbmcgZ3JhbnVsYXJpdHlcclxuICAgIGQud2hlZWxEWCA9IGQud2hlZWxEWSA9IGQud2hlZWxTdGFydFggPSBkLndoZWVsU3RhcnRZID0gbnVsbDtcclxuXHJcbiAgICAvLyBUcnVlIHdoZW4gc2hpZnQgaXMgaGVsZCBkb3duLlxyXG4gICAgZC5zaGlmdCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIFVzZWQgdG8gdHJhY2sgd2hldGhlciBhbnl0aGluZyBoYXBwZW5lZCBzaW5jZSB0aGUgY29udGV4dCBtZW51XHJcbiAgICAvLyB3YXMgb3BlbmVkLlxyXG4gICAgZC5zZWxGb3JDb250ZXh0TWVudSA9IG51bGw7XHJcblxyXG4gICAgZC5hY3RpdmVUb3VjaCA9IG51bGw7XHJcblxyXG4gICAgaW5wdXQuaW5pdChkKTtcclxuICB9XHJcblxyXG4gIC8vIFNUQVRFIFVQREFURVNcclxuXHJcbiAgLy8gVXNlZCB0byBnZXQgdGhlIGVkaXRvciBpbnRvIGEgY29uc2lzdGVudCBzdGF0ZSBhZ2FpbiB3aGVuIG9wdGlvbnMgY2hhbmdlLlxyXG5cclxuICBmdW5jdGlvbiBsb2FkTW9kZShjbSkge1xyXG4gICAgY20uZG9jLm1vZGUgPSBDb2RlTWlycm9yLmdldE1vZGUoY20ub3B0aW9ucywgY20uZG9jLm1vZGVPcHRpb24pO1xyXG4gICAgcmVzZXRNb2RlU3RhdGUoY20pO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gcmVzZXRNb2RlU3RhdGUoY20pIHtcclxuICAgIGNtLmRvYy5pdGVyKGZ1bmN0aW9uKGxpbmUpIHtcclxuICAgICAgaWYgKGxpbmUuc3RhdGVBZnRlcikgbGluZS5zdGF0ZUFmdGVyID0gbnVsbDtcclxuICAgICAgaWYgKGxpbmUuc3R5bGVzKSBsaW5lLnN0eWxlcyA9IG51bGw7XHJcbiAgICB9KTtcclxuICAgIGNtLmRvYy5mcm9udGllciA9IGNtLmRvYy5maXJzdDtcclxuICAgIHN0YXJ0V29ya2VyKGNtLCAxMDApO1xyXG4gICAgY20uc3RhdGUubW9kZUdlbisrO1xyXG4gICAgaWYgKGNtLmN1ck9wKSByZWdDaGFuZ2UoY20pO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gd3JhcHBpbmdDaGFuZ2VkKGNtKSB7XHJcbiAgICBpZiAoY20ub3B0aW9ucy5saW5lV3JhcHBpbmcpIHtcclxuICAgICAgYWRkQ2xhc3MoY20uZGlzcGxheS53cmFwcGVyLCBcIkNvZGVNaXJyb3Itd3JhcFwiKTtcclxuICAgICAgY20uZGlzcGxheS5zaXplci5zdHlsZS5taW5XaWR0aCA9IFwiXCI7XHJcbiAgICAgIGNtLmRpc3BsYXkuc2l6ZXJXaWR0aCA9IG51bGw7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBybUNsYXNzKGNtLmRpc3BsYXkud3JhcHBlciwgXCJDb2RlTWlycm9yLXdyYXBcIik7XHJcbiAgICAgIGZpbmRNYXhMaW5lKGNtKTtcclxuICAgIH1cclxuICAgIGVzdGltYXRlTGluZUhlaWdodHMoY20pO1xyXG4gICAgcmVnQ2hhbmdlKGNtKTtcclxuICAgIGNsZWFyQ2FjaGVzKGNtKTtcclxuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKXt1cGRhdGVTY3JvbGxiYXJzKGNtKTt9LCAxMDApO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJucyBhIGZ1bmN0aW9uIHRoYXQgZXN0aW1hdGVzIHRoZSBoZWlnaHQgb2YgYSBsaW5lLCB0byB1c2UgYXNcclxuICAvLyBmaXJzdCBhcHByb3hpbWF0aW9uIHVudGlsIHRoZSBsaW5lIGJlY29tZXMgdmlzaWJsZSAoYW5kIGlzIHRodXNcclxuICAvLyBwcm9wZXJseSBtZWFzdXJhYmxlKS5cclxuICBmdW5jdGlvbiBlc3RpbWF0ZUhlaWdodChjbSkge1xyXG4gICAgdmFyIHRoID0gdGV4dEhlaWdodChjbS5kaXNwbGF5KSwgd3JhcHBpbmcgPSBjbS5vcHRpb25zLmxpbmVXcmFwcGluZztcclxuICAgIHZhciBwZXJMaW5lID0gd3JhcHBpbmcgJiYgTWF0aC5tYXgoNSwgY20uZGlzcGxheS5zY3JvbGxlci5jbGllbnRXaWR0aCAvIGNoYXJXaWR0aChjbS5kaXNwbGF5KSAtIDMpO1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uKGxpbmUpIHtcclxuICAgICAgaWYgKGxpbmVJc0hpZGRlbihjbS5kb2MsIGxpbmUpKSByZXR1cm4gMDtcclxuXHJcbiAgICAgIHZhciB3aWRnZXRzSGVpZ2h0ID0gMDtcclxuICAgICAgaWYgKGxpbmUud2lkZ2V0cykgZm9yICh2YXIgaSA9IDA7IGkgPCBsaW5lLndpZGdldHMubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICBpZiAobGluZS53aWRnZXRzW2ldLmhlaWdodCkgd2lkZ2V0c0hlaWdodCArPSBsaW5lLndpZGdldHNbaV0uaGVpZ2h0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAod3JhcHBpbmcpXHJcbiAgICAgICAgcmV0dXJuIHdpZGdldHNIZWlnaHQgKyAoTWF0aC5jZWlsKGxpbmUudGV4dC5sZW5ndGggLyBwZXJMaW5lKSB8fCAxKSAqIHRoO1xyXG4gICAgICBlbHNlXHJcbiAgICAgICAgcmV0dXJuIHdpZGdldHNIZWlnaHQgKyB0aDtcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBlc3RpbWF0ZUxpbmVIZWlnaHRzKGNtKSB7XHJcbiAgICB2YXIgZG9jID0gY20uZG9jLCBlc3QgPSBlc3RpbWF0ZUhlaWdodChjbSk7XHJcbiAgICBkb2MuaXRlcihmdW5jdGlvbihsaW5lKSB7XHJcbiAgICAgIHZhciBlc3RIZWlnaHQgPSBlc3QobGluZSk7XHJcbiAgICAgIGlmIChlc3RIZWlnaHQgIT0gbGluZS5oZWlnaHQpIHVwZGF0ZUxpbmVIZWlnaHQobGluZSwgZXN0SGVpZ2h0KTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gdGhlbWVDaGFuZ2VkKGNtKSB7XHJcbiAgICBjbS5kaXNwbGF5LndyYXBwZXIuY2xhc3NOYW1lID0gY20uZGlzcGxheS53cmFwcGVyLmNsYXNzTmFtZS5yZXBsYWNlKC9cXHMqY20tcy1cXFMrL2csIFwiXCIpICtcclxuICAgICAgY20ub3B0aW9ucy50aGVtZS5yZXBsYWNlKC8oXnxcXHMpXFxzKi9nLCBcIiBjbS1zLVwiKTtcclxuICAgIGNsZWFyQ2FjaGVzKGNtKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGd1dHRlcnNDaGFuZ2VkKGNtKSB7XHJcbiAgICB1cGRhdGVHdXR0ZXJzKGNtKTtcclxuICAgIHJlZ0NoYW5nZShjbSk7XHJcbiAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7YWxpZ25Ib3Jpem9udGFsbHkoY20pO30sIDIwKTtcclxuICB9XHJcblxyXG4gIC8vIFJlYnVpbGQgdGhlIGd1dHRlciBlbGVtZW50cywgZW5zdXJlIHRoZSBtYXJnaW4gdG8gdGhlIGxlZnQgb2YgdGhlXHJcbiAgLy8gY29kZSBtYXRjaGVzIHRoZWlyIHdpZHRoLlxyXG4gIGZ1bmN0aW9uIHVwZGF0ZUd1dHRlcnMoY20pIHtcclxuICAgIHZhciBndXR0ZXJzID0gY20uZGlzcGxheS5ndXR0ZXJzLCBzcGVjcyA9IGNtLm9wdGlvbnMuZ3V0dGVycztcclxuICAgIHJlbW92ZUNoaWxkcmVuKGd1dHRlcnMpO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzcGVjcy5sZW5ndGg7ICsraSkge1xyXG4gICAgICB2YXIgZ3V0dGVyQ2xhc3MgPSBzcGVjc1tpXTtcclxuICAgICAgdmFyIGdFbHQgPSBndXR0ZXJzLmFwcGVuZENoaWxkKGVsdChcImRpdlwiLCBudWxsLCBcIkNvZGVNaXJyb3ItZ3V0dGVyIFwiICsgZ3V0dGVyQ2xhc3MpKTtcclxuICAgICAgaWYgKGd1dHRlckNsYXNzID09IFwiQ29kZU1pcnJvci1saW5lbnVtYmVyc1wiKSB7XHJcbiAgICAgICAgY20uZGlzcGxheS5saW5lR3V0dGVyID0gZ0VsdDtcclxuICAgICAgICBnRWx0LnN0eWxlLndpZHRoID0gKGNtLmRpc3BsYXkubGluZU51bVdpZHRoIHx8IDEpICsgXCJweFwiO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBndXR0ZXJzLnN0eWxlLmRpc3BsYXkgPSBpID8gXCJcIiA6IFwibm9uZVwiO1xyXG4gICAgdXBkYXRlR3V0dGVyU3BhY2UoY20pO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gdXBkYXRlR3V0dGVyU3BhY2UoY20pIHtcclxuICAgIHZhciB3aWR0aCA9IGNtLmRpc3BsYXkuZ3V0dGVycy5vZmZzZXRXaWR0aDtcclxuICAgIGNtLmRpc3BsYXkuc2l6ZXIuc3R5bGUubWFyZ2luTGVmdCA9IHdpZHRoICsgXCJweFwiO1xyXG4gIH1cclxuXHJcbiAgLy8gQ29tcHV0ZSB0aGUgY2hhcmFjdGVyIGxlbmd0aCBvZiBhIGxpbmUsIHRha2luZyBpbnRvIGFjY291bnRcclxuICAvLyBjb2xsYXBzZWQgcmFuZ2VzIChzZWUgbWFya1RleHQpIHRoYXQgbWlnaHQgaGlkZSBwYXJ0cywgYW5kIGpvaW5cclxuICAvLyBvdGhlciBsaW5lcyBvbnRvIGl0LlxyXG4gIGZ1bmN0aW9uIGxpbmVMZW5ndGgobGluZSkge1xyXG4gICAgaWYgKGxpbmUuaGVpZ2h0ID09IDApIHJldHVybiAwO1xyXG4gICAgdmFyIGxlbiA9IGxpbmUudGV4dC5sZW5ndGgsIG1lcmdlZCwgY3VyID0gbGluZTtcclxuICAgIHdoaWxlIChtZXJnZWQgPSBjb2xsYXBzZWRTcGFuQXRTdGFydChjdXIpKSB7XHJcbiAgICAgIHZhciBmb3VuZCA9IG1lcmdlZC5maW5kKDAsIHRydWUpO1xyXG4gICAgICBjdXIgPSBmb3VuZC5mcm9tLmxpbmU7XHJcbiAgICAgIGxlbiArPSBmb3VuZC5mcm9tLmNoIC0gZm91bmQudG8uY2g7XHJcbiAgICB9XHJcbiAgICBjdXIgPSBsaW5lO1xyXG4gICAgd2hpbGUgKG1lcmdlZCA9IGNvbGxhcHNlZFNwYW5BdEVuZChjdXIpKSB7XHJcbiAgICAgIHZhciBmb3VuZCA9IG1lcmdlZC5maW5kKDAsIHRydWUpO1xyXG4gICAgICBsZW4gLT0gY3VyLnRleHQubGVuZ3RoIC0gZm91bmQuZnJvbS5jaDtcclxuICAgICAgY3VyID0gZm91bmQudG8ubGluZTtcclxuICAgICAgbGVuICs9IGN1ci50ZXh0Lmxlbmd0aCAtIGZvdW5kLnRvLmNoO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGxlbjtcclxuICB9XHJcblxyXG4gIC8vIEZpbmQgdGhlIGxvbmdlc3QgbGluZSBpbiB0aGUgZG9jdW1lbnQuXHJcbiAgZnVuY3Rpb24gZmluZE1heExpbmUoY20pIHtcclxuICAgIHZhciBkID0gY20uZGlzcGxheSwgZG9jID0gY20uZG9jO1xyXG4gICAgZC5tYXhMaW5lID0gZ2V0TGluZShkb2MsIGRvYy5maXJzdCk7XHJcbiAgICBkLm1heExpbmVMZW5ndGggPSBsaW5lTGVuZ3RoKGQubWF4TGluZSk7XHJcbiAgICBkLm1heExpbmVDaGFuZ2VkID0gdHJ1ZTtcclxuICAgIGRvYy5pdGVyKGZ1bmN0aW9uKGxpbmUpIHtcclxuICAgICAgdmFyIGxlbiA9IGxpbmVMZW5ndGgobGluZSk7XHJcbiAgICAgIGlmIChsZW4gPiBkLm1heExpbmVMZW5ndGgpIHtcclxuICAgICAgICBkLm1heExpbmVMZW5ndGggPSBsZW47XHJcbiAgICAgICAgZC5tYXhMaW5lID0gbGluZTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvLyBNYWtlIHN1cmUgdGhlIGd1dHRlcnMgb3B0aW9ucyBjb250YWlucyB0aGUgZWxlbWVudFxyXG4gIC8vIFwiQ29kZU1pcnJvci1saW5lbnVtYmVyc1wiIHdoZW4gdGhlIGxpbmVOdW1iZXJzIG9wdGlvbiBpcyB0cnVlLlxyXG4gIGZ1bmN0aW9uIHNldEd1dHRlcnNGb3JMaW5lTnVtYmVycyhvcHRpb25zKSB7XHJcbiAgICB2YXIgZm91bmQgPSBpbmRleE9mKG9wdGlvbnMuZ3V0dGVycywgXCJDb2RlTWlycm9yLWxpbmVudW1iZXJzXCIpO1xyXG4gICAgaWYgKGZvdW5kID09IC0xICYmIG9wdGlvbnMubGluZU51bWJlcnMpIHtcclxuICAgICAgb3B0aW9ucy5ndXR0ZXJzID0gb3B0aW9ucy5ndXR0ZXJzLmNvbmNhdChbXCJDb2RlTWlycm9yLWxpbmVudW1iZXJzXCJdKTtcclxuICAgIH0gZWxzZSBpZiAoZm91bmQgPiAtMSAmJiAhb3B0aW9ucy5saW5lTnVtYmVycykge1xyXG4gICAgICBvcHRpb25zLmd1dHRlcnMgPSBvcHRpb25zLmd1dHRlcnMuc2xpY2UoMCk7XHJcbiAgICAgIG9wdGlvbnMuZ3V0dGVycy5zcGxpY2UoZm91bmQsIDEpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU0NST0xMQkFSU1xyXG5cclxuICAvLyBQcmVwYXJlIERPTSByZWFkcyBuZWVkZWQgdG8gdXBkYXRlIHRoZSBzY3JvbGxiYXJzLiBEb25lIGluIG9uZVxyXG4gIC8vIHNob3QgdG8gbWluaW1pemUgdXBkYXRlL21lYXN1cmUgcm91bmR0cmlwcy5cclxuICBmdW5jdGlvbiBtZWFzdXJlRm9yU2Nyb2xsYmFycyhjbSkge1xyXG4gICAgdmFyIGQgPSBjbS5kaXNwbGF5LCBndXR0ZXJXID0gZC5ndXR0ZXJzLm9mZnNldFdpZHRoO1xyXG4gICAgdmFyIGRvY0ggPSBNYXRoLnJvdW5kKGNtLmRvYy5oZWlnaHQgKyBwYWRkaW5nVmVydChjbS5kaXNwbGF5KSk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBjbGllbnRIZWlnaHQ6IGQuc2Nyb2xsZXIuY2xpZW50SGVpZ2h0LFxyXG4gICAgICB2aWV3SGVpZ2h0OiBkLndyYXBwZXIuY2xpZW50SGVpZ2h0LFxyXG4gICAgICBzY3JvbGxXaWR0aDogZC5zY3JvbGxlci5zY3JvbGxXaWR0aCwgY2xpZW50V2lkdGg6IGQuc2Nyb2xsZXIuY2xpZW50V2lkdGgsXHJcbiAgICAgIHZpZXdXaWR0aDogZC53cmFwcGVyLmNsaWVudFdpZHRoLFxyXG4gICAgICBiYXJMZWZ0OiBjbS5vcHRpb25zLmZpeGVkR3V0dGVyID8gZ3V0dGVyVyA6IDAsXHJcbiAgICAgIGRvY0hlaWdodDogZG9jSCxcclxuICAgICAgc2Nyb2xsSGVpZ2h0OiBkb2NIICsgc2Nyb2xsR2FwKGNtKSArIGQuYmFySGVpZ2h0LFxyXG4gICAgICBuYXRpdmVCYXJXaWR0aDogZC5uYXRpdmVCYXJXaWR0aCxcclxuICAgICAgZ3V0dGVyV2lkdGg6IGd1dHRlcldcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBOYXRpdmVTY3JvbGxiYXJzKHBsYWNlLCBzY3JvbGwsIGNtKSB7XHJcbiAgICB0aGlzLmNtID0gY207XHJcbiAgICB2YXIgdmVydCA9IHRoaXMudmVydCA9IGVsdChcImRpdlwiLCBbZWx0KFwiZGl2XCIsIG51bGwsIG51bGwsIFwibWluLXdpZHRoOiAxcHhcIildLCBcIkNvZGVNaXJyb3ItdnNjcm9sbGJhclwiKTtcclxuICAgIHZhciBob3JpeiA9IHRoaXMuaG9yaXogPSBlbHQoXCJkaXZcIiwgW2VsdChcImRpdlwiLCBudWxsLCBudWxsLCBcImhlaWdodDogMTAwJTsgbWluLWhlaWdodDogMXB4XCIpXSwgXCJDb2RlTWlycm9yLWhzY3JvbGxiYXJcIik7XHJcbiAgICBwbGFjZSh2ZXJ0KTsgcGxhY2UoaG9yaXopO1xyXG5cclxuICAgIG9uKHZlcnQsIFwic2Nyb2xsXCIsIGZ1bmN0aW9uKCkge1xyXG4gICAgICBpZiAodmVydC5jbGllbnRIZWlnaHQpIHNjcm9sbCh2ZXJ0LnNjcm9sbFRvcCwgXCJ2ZXJ0aWNhbFwiKTtcclxuICAgIH0pO1xyXG4gICAgb24oaG9yaXosIFwic2Nyb2xsXCIsIGZ1bmN0aW9uKCkge1xyXG4gICAgICBpZiAoaG9yaXouY2xpZW50V2lkdGgpIHNjcm9sbChob3Jpei5zY3JvbGxMZWZ0LCBcImhvcml6b250YWxcIik7XHJcbiAgICB9KTtcclxuXHJcbiAgICB0aGlzLmNoZWNrZWRaZXJvV2lkdGggPSBmYWxzZTtcclxuICAgIC8vIE5lZWQgdG8gc2V0IGEgbWluaW11bSB3aWR0aCB0byBzZWUgdGhlIHNjcm9sbGJhciBvbiBJRTcgKGJ1dCBtdXN0IG5vdCBzZXQgaXQgb24gSUU4KS5cclxuICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uIDwgOCkgdGhpcy5ob3Jpei5zdHlsZS5taW5IZWlnaHQgPSB0aGlzLnZlcnQuc3R5bGUubWluV2lkdGggPSBcIjE4cHhcIjtcclxuICB9XHJcblxyXG4gIE5hdGl2ZVNjcm9sbGJhcnMucHJvdG90eXBlID0gY29weU9iaih7XHJcbiAgICB1cGRhdGU6IGZ1bmN0aW9uKG1lYXN1cmUpIHtcclxuICAgICAgdmFyIG5lZWRzSCA9IG1lYXN1cmUuc2Nyb2xsV2lkdGggPiBtZWFzdXJlLmNsaWVudFdpZHRoICsgMTtcclxuICAgICAgdmFyIG5lZWRzViA9IG1lYXN1cmUuc2Nyb2xsSGVpZ2h0ID4gbWVhc3VyZS5jbGllbnRIZWlnaHQgKyAxO1xyXG4gICAgICB2YXIgc1dpZHRoID0gbWVhc3VyZS5uYXRpdmVCYXJXaWR0aDtcclxuXHJcbiAgICAgIGlmIChuZWVkc1YpIHtcclxuICAgICAgICB0aGlzLnZlcnQuc3R5bGUuZGlzcGxheSA9IFwiYmxvY2tcIjtcclxuICAgICAgICB0aGlzLnZlcnQuc3R5bGUuYm90dG9tID0gbmVlZHNIID8gc1dpZHRoICsgXCJweFwiIDogXCIwXCI7XHJcbiAgICAgICAgdmFyIHRvdGFsSGVpZ2h0ID0gbWVhc3VyZS52aWV3SGVpZ2h0IC0gKG5lZWRzSCA/IHNXaWR0aCA6IDApO1xyXG4gICAgICAgIC8vIEEgYnVnIGluIElFOCBjYW4gY2F1c2UgdGhpcyB2YWx1ZSB0byBiZSBuZWdhdGl2ZSwgc28gZ3VhcmQgaXQuXHJcbiAgICAgICAgdGhpcy52ZXJ0LmZpcnN0Q2hpbGQuc3R5bGUuaGVpZ2h0ID1cclxuICAgICAgICAgIE1hdGgubWF4KDAsIG1lYXN1cmUuc2Nyb2xsSGVpZ2h0IC0gbWVhc3VyZS5jbGllbnRIZWlnaHQgKyB0b3RhbEhlaWdodCkgKyBcInB4XCI7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhpcy52ZXJ0LnN0eWxlLmRpc3BsYXkgPSBcIlwiO1xyXG4gICAgICAgIHRoaXMudmVydC5maXJzdENoaWxkLnN0eWxlLmhlaWdodCA9IFwiMFwiO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAobmVlZHNIKSB7XHJcbiAgICAgICAgdGhpcy5ob3Jpei5zdHlsZS5kaXNwbGF5ID0gXCJibG9ja1wiO1xyXG4gICAgICAgIHRoaXMuaG9yaXouc3R5bGUucmlnaHQgPSBuZWVkc1YgPyBzV2lkdGggKyBcInB4XCIgOiBcIjBcIjtcclxuICAgICAgICB0aGlzLmhvcml6LnN0eWxlLmxlZnQgPSBtZWFzdXJlLmJhckxlZnQgKyBcInB4XCI7XHJcbiAgICAgICAgdmFyIHRvdGFsV2lkdGggPSBtZWFzdXJlLnZpZXdXaWR0aCAtIG1lYXN1cmUuYmFyTGVmdCAtIChuZWVkc1YgPyBzV2lkdGggOiAwKTtcclxuICAgICAgICB0aGlzLmhvcml6LmZpcnN0Q2hpbGQuc3R5bGUud2lkdGggPVxyXG4gICAgICAgICAgKG1lYXN1cmUuc2Nyb2xsV2lkdGggLSBtZWFzdXJlLmNsaWVudFdpZHRoICsgdG90YWxXaWR0aCkgKyBcInB4XCI7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhpcy5ob3Jpei5zdHlsZS5kaXNwbGF5ID0gXCJcIjtcclxuICAgICAgICB0aGlzLmhvcml6LmZpcnN0Q2hpbGQuc3R5bGUud2lkdGggPSBcIjBcIjtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKCF0aGlzLmNoZWNrZWRaZXJvV2lkdGggJiYgbWVhc3VyZS5jbGllbnRIZWlnaHQgPiAwKSB7XHJcbiAgICAgICAgaWYgKHNXaWR0aCA9PSAwKSB0aGlzLnplcm9XaWR0aEhhY2soKTtcclxuICAgICAgICB0aGlzLmNoZWNrZWRaZXJvV2lkdGggPSB0cnVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4ge3JpZ2h0OiBuZWVkc1YgPyBzV2lkdGggOiAwLCBib3R0b206IG5lZWRzSCA/IHNXaWR0aCA6IDB9O1xyXG4gICAgfSxcclxuICAgIHNldFNjcm9sbExlZnQ6IGZ1bmN0aW9uKHBvcykge1xyXG4gICAgICBpZiAodGhpcy5ob3Jpei5zY3JvbGxMZWZ0ICE9IHBvcykgdGhpcy5ob3Jpei5zY3JvbGxMZWZ0ID0gcG9zO1xyXG4gICAgICBpZiAodGhpcy5kaXNhYmxlSG9yaXopIHRoaXMuZW5hYmxlWmVyb1dpZHRoQmFyKHRoaXMuaG9yaXosIHRoaXMuZGlzYWJsZUhvcml6KTtcclxuICAgIH0sXHJcbiAgICBzZXRTY3JvbGxUb3A6IGZ1bmN0aW9uKHBvcykge1xyXG4gICAgICBpZiAodGhpcy52ZXJ0LnNjcm9sbFRvcCAhPSBwb3MpIHRoaXMudmVydC5zY3JvbGxUb3AgPSBwb3M7XHJcbiAgICAgIGlmICh0aGlzLmRpc2FibGVWZXJ0KSB0aGlzLmVuYWJsZVplcm9XaWR0aEJhcih0aGlzLnZlcnQsIHRoaXMuZGlzYWJsZVZlcnQpO1xyXG4gICAgfSxcclxuICAgIHplcm9XaWR0aEhhY2s6IGZ1bmN0aW9uKCkge1xyXG4gICAgICB2YXIgdyA9IG1hYyAmJiAhbWFjX2dlTW91bnRhaW5MaW9uID8gXCIxMnB4XCIgOiBcIjE4cHhcIjtcclxuICAgICAgdGhpcy5ob3Jpei5zdHlsZS5oZWlnaHQgPSB0aGlzLnZlcnQuc3R5bGUud2lkdGggPSB3O1xyXG4gICAgICB0aGlzLmhvcml6LnN0eWxlLnBvaW50ZXJFdmVudHMgPSB0aGlzLnZlcnQuc3R5bGUucG9pbnRlckV2ZW50cyA9IFwibm9uZVwiO1xyXG4gICAgICB0aGlzLmRpc2FibGVIb3JpeiA9IG5ldyBEZWxheWVkO1xyXG4gICAgICB0aGlzLmRpc2FibGVWZXJ0ID0gbmV3IERlbGF5ZWQ7XHJcbiAgICB9LFxyXG4gICAgZW5hYmxlWmVyb1dpZHRoQmFyOiBmdW5jdGlvbihiYXIsIGRlbGF5KSB7XHJcbiAgICAgIGJhci5zdHlsZS5wb2ludGVyRXZlbnRzID0gXCJhdXRvXCI7XHJcbiAgICAgIGZ1bmN0aW9uIG1heWJlRGlzYWJsZSgpIHtcclxuICAgICAgICAvLyBUbyBmaW5kIG91dCB3aGV0aGVyIHRoZSBzY3JvbGxiYXIgaXMgc3RpbGwgdmlzaWJsZSwgd2VcclxuICAgICAgICAvLyBjaGVjayB3aGV0aGVyIHRoZSBlbGVtZW50IHVuZGVyIHRoZSBwaXhlbCBpbiB0aGUgYm90dG9tXHJcbiAgICAgICAgLy8gbGVmdCBjb3JuZXIgb2YgdGhlIHNjcm9sbGJhciBib3ggaXMgdGhlIHNjcm9sbGJhciBib3hcclxuICAgICAgICAvLyBpdHNlbGYgKHdoZW4gdGhlIGJhciBpcyBzdGlsbCB2aXNpYmxlKSBvciBpdHMgZmlsbGVyIGNoaWxkXHJcbiAgICAgICAgLy8gKHdoZW4gdGhlIGJhciBpcyBoaWRkZW4pLiBJZiBpdCBpcyBzdGlsbCB2aXNpYmxlLCB3ZSBrZWVwXHJcbiAgICAgICAgLy8gaXQgZW5hYmxlZCwgaWYgaXQncyBoaWRkZW4sIHdlIGRpc2FibGUgcG9pbnRlciBldmVudHMuXHJcbiAgICAgICAgdmFyIGJveCA9IGJhci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgICAgICB2YXIgZWx0ID0gZG9jdW1lbnQuZWxlbWVudEZyb21Qb2ludChib3gubGVmdCArIDEsIGJveC5ib3R0b20gLSAxKTtcclxuICAgICAgICBpZiAoZWx0ICE9IGJhcikgYmFyLnN0eWxlLnBvaW50ZXJFdmVudHMgPSBcIm5vbmVcIjtcclxuICAgICAgICBlbHNlIGRlbGF5LnNldCgxMDAwLCBtYXliZURpc2FibGUpO1xyXG4gICAgICB9XHJcbiAgICAgIGRlbGF5LnNldCgxMDAwLCBtYXliZURpc2FibGUpO1xyXG4gICAgfSxcclxuICAgIGNsZWFyOiBmdW5jdGlvbigpIHtcclxuICAgICAgdmFyIHBhcmVudCA9IHRoaXMuaG9yaXoucGFyZW50Tm9kZTtcclxuICAgICAgcGFyZW50LnJlbW92ZUNoaWxkKHRoaXMuaG9yaXopO1xyXG4gICAgICBwYXJlbnQucmVtb3ZlQ2hpbGQodGhpcy52ZXJ0KTtcclxuICAgIH1cclxuICB9LCBOYXRpdmVTY3JvbGxiYXJzLnByb3RvdHlwZSk7XHJcblxyXG4gIGZ1bmN0aW9uIE51bGxTY3JvbGxiYXJzKCkge31cclxuXHJcbiAgTnVsbFNjcm9sbGJhcnMucHJvdG90eXBlID0gY29weU9iaih7XHJcbiAgICB1cGRhdGU6IGZ1bmN0aW9uKCkgeyByZXR1cm4ge2JvdHRvbTogMCwgcmlnaHQ6IDB9OyB9LFxyXG4gICAgc2V0U2Nyb2xsTGVmdDogZnVuY3Rpb24oKSB7fSxcclxuICAgIHNldFNjcm9sbFRvcDogZnVuY3Rpb24oKSB7fSxcclxuICAgIGNsZWFyOiBmdW5jdGlvbigpIHt9XHJcbiAgfSwgTnVsbFNjcm9sbGJhcnMucHJvdG90eXBlKTtcclxuXHJcbiAgQ29kZU1pcnJvci5zY3JvbGxiYXJNb2RlbCA9IHtcIm5hdGl2ZVwiOiBOYXRpdmVTY3JvbGxiYXJzLCBcIm51bGxcIjogTnVsbFNjcm9sbGJhcnN9O1xyXG5cclxuICBmdW5jdGlvbiBpbml0U2Nyb2xsYmFycyhjbSkge1xyXG4gICAgaWYgKGNtLmRpc3BsYXkuc2Nyb2xsYmFycykge1xyXG4gICAgICBjbS5kaXNwbGF5LnNjcm9sbGJhcnMuY2xlYXIoKTtcclxuICAgICAgaWYgKGNtLmRpc3BsYXkuc2Nyb2xsYmFycy5hZGRDbGFzcylcclxuICAgICAgICBybUNsYXNzKGNtLmRpc3BsYXkud3JhcHBlciwgY20uZGlzcGxheS5zY3JvbGxiYXJzLmFkZENsYXNzKTtcclxuICAgIH1cclxuXHJcbiAgICBjbS5kaXNwbGF5LnNjcm9sbGJhcnMgPSBuZXcgQ29kZU1pcnJvci5zY3JvbGxiYXJNb2RlbFtjbS5vcHRpb25zLnNjcm9sbGJhclN0eWxlXShmdW5jdGlvbihub2RlKSB7XHJcbiAgICAgIGNtLmRpc3BsYXkud3JhcHBlci5pbnNlcnRCZWZvcmUobm9kZSwgY20uZGlzcGxheS5zY3JvbGxiYXJGaWxsZXIpO1xyXG4gICAgICAvLyBQcmV2ZW50IGNsaWNrcyBpbiB0aGUgc2Nyb2xsYmFycyBmcm9tIGtpbGxpbmcgZm9jdXNcclxuICAgICAgb24obm9kZSwgXCJtb3VzZWRvd25cIiwgZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgaWYgKGNtLnN0YXRlLmZvY3VzZWQpIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7IGNtLmRpc3BsYXkuaW5wdXQuZm9jdXMoKTsgfSwgMCk7XHJcbiAgICAgIH0pO1xyXG4gICAgICBub2RlLnNldEF0dHJpYnV0ZShcImNtLW5vdC1jb250ZW50XCIsIFwidHJ1ZVwiKTtcclxuICAgIH0sIGZ1bmN0aW9uKHBvcywgYXhpcykge1xyXG4gICAgICBpZiAoYXhpcyA9PSBcImhvcml6b250YWxcIikgc2V0U2Nyb2xsTGVmdChjbSwgcG9zKTtcclxuICAgICAgZWxzZSBzZXRTY3JvbGxUb3AoY20sIHBvcyk7XHJcbiAgICB9LCBjbSk7XHJcbiAgICBpZiAoY20uZGlzcGxheS5zY3JvbGxiYXJzLmFkZENsYXNzKVxyXG4gICAgICBhZGRDbGFzcyhjbS5kaXNwbGF5LndyYXBwZXIsIGNtLmRpc3BsYXkuc2Nyb2xsYmFycy5hZGRDbGFzcyk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiB1cGRhdGVTY3JvbGxiYXJzKGNtLCBtZWFzdXJlKSB7XHJcbiAgICBpZiAoIW1lYXN1cmUpIG1lYXN1cmUgPSBtZWFzdXJlRm9yU2Nyb2xsYmFycyhjbSk7XHJcbiAgICB2YXIgc3RhcnRXaWR0aCA9IGNtLmRpc3BsYXkuYmFyV2lkdGgsIHN0YXJ0SGVpZ2h0ID0gY20uZGlzcGxheS5iYXJIZWlnaHQ7XHJcbiAgICB1cGRhdGVTY3JvbGxiYXJzSW5uZXIoY20sIG1lYXN1cmUpO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCA0ICYmIHN0YXJ0V2lkdGggIT0gY20uZGlzcGxheS5iYXJXaWR0aCB8fCBzdGFydEhlaWdodCAhPSBjbS5kaXNwbGF5LmJhckhlaWdodDsgaSsrKSB7XHJcbiAgICAgIGlmIChzdGFydFdpZHRoICE9IGNtLmRpc3BsYXkuYmFyV2lkdGggJiYgY20ub3B0aW9ucy5saW5lV3JhcHBpbmcpXHJcbiAgICAgICAgdXBkYXRlSGVpZ2h0c0luVmlld3BvcnQoY20pO1xyXG4gICAgICB1cGRhdGVTY3JvbGxiYXJzSW5uZXIoY20sIG1lYXN1cmVGb3JTY3JvbGxiYXJzKGNtKSk7XHJcbiAgICAgIHN0YXJ0V2lkdGggPSBjbS5kaXNwbGF5LmJhcldpZHRoOyBzdGFydEhlaWdodCA9IGNtLmRpc3BsYXkuYmFySGVpZ2h0O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmUtc3luY2hyb25pemUgdGhlIGZha2Ugc2Nyb2xsYmFycyB3aXRoIHRoZSBhY3R1YWwgc2l6ZSBvZiB0aGVcclxuICAvLyBjb250ZW50LlxyXG4gIGZ1bmN0aW9uIHVwZGF0ZVNjcm9sbGJhcnNJbm5lcihjbSwgbWVhc3VyZSkge1xyXG4gICAgdmFyIGQgPSBjbS5kaXNwbGF5O1xyXG4gICAgdmFyIHNpemVzID0gZC5zY3JvbGxiYXJzLnVwZGF0ZShtZWFzdXJlKTtcclxuXHJcbiAgICBkLnNpemVyLnN0eWxlLnBhZGRpbmdSaWdodCA9IChkLmJhcldpZHRoID0gc2l6ZXMucmlnaHQpICsgXCJweFwiO1xyXG4gICAgZC5zaXplci5zdHlsZS5wYWRkaW5nQm90dG9tID0gKGQuYmFySGVpZ2h0ID0gc2l6ZXMuYm90dG9tKSArIFwicHhcIjtcclxuXHJcbiAgICBpZiAoc2l6ZXMucmlnaHQgJiYgc2l6ZXMuYm90dG9tKSB7XHJcbiAgICAgIGQuc2Nyb2xsYmFyRmlsbGVyLnN0eWxlLmRpc3BsYXkgPSBcImJsb2NrXCI7XHJcbiAgICAgIGQuc2Nyb2xsYmFyRmlsbGVyLnN0eWxlLmhlaWdodCA9IHNpemVzLmJvdHRvbSArIFwicHhcIjtcclxuICAgICAgZC5zY3JvbGxiYXJGaWxsZXIuc3R5bGUud2lkdGggPSBzaXplcy5yaWdodCArIFwicHhcIjtcclxuICAgIH0gZWxzZSBkLnNjcm9sbGJhckZpbGxlci5zdHlsZS5kaXNwbGF5ID0gXCJcIjtcclxuICAgIGlmIChzaXplcy5ib3R0b20gJiYgY20ub3B0aW9ucy5jb3Zlckd1dHRlck5leHRUb1Njcm9sbGJhciAmJiBjbS5vcHRpb25zLmZpeGVkR3V0dGVyKSB7XHJcbiAgICAgIGQuZ3V0dGVyRmlsbGVyLnN0eWxlLmRpc3BsYXkgPSBcImJsb2NrXCI7XHJcbiAgICAgIGQuZ3V0dGVyRmlsbGVyLnN0eWxlLmhlaWdodCA9IHNpemVzLmJvdHRvbSArIFwicHhcIjtcclxuICAgICAgZC5ndXR0ZXJGaWxsZXIuc3R5bGUud2lkdGggPSBtZWFzdXJlLmd1dHRlcldpZHRoICsgXCJweFwiO1xyXG4gICAgfSBlbHNlIGQuZ3V0dGVyRmlsbGVyLnN0eWxlLmRpc3BsYXkgPSBcIlwiO1xyXG4gIH1cclxuXHJcbiAgLy8gQ29tcHV0ZSB0aGUgbGluZXMgdGhhdCBhcmUgdmlzaWJsZSBpbiBhIGdpdmVuIHZpZXdwb3J0IChkZWZhdWx0c1xyXG4gIC8vIHRoZSB0aGUgY3VycmVudCBzY3JvbGwgcG9zaXRpb24pLiB2aWV3cG9ydCBtYXkgY29udGFpbiB0b3AsXHJcbiAgLy8gaGVpZ2h0LCBhbmQgZW5zdXJlIChzZWUgb3Auc2Nyb2xsVG9Qb3MpIHByb3BlcnRpZXMuXHJcbiAgZnVuY3Rpb24gdmlzaWJsZUxpbmVzKGRpc3BsYXksIGRvYywgdmlld3BvcnQpIHtcclxuICAgIHZhciB0b3AgPSB2aWV3cG9ydCAmJiB2aWV3cG9ydC50b3AgIT0gbnVsbCA/IE1hdGgubWF4KDAsIHZpZXdwb3J0LnRvcCkgOiBkaXNwbGF5LnNjcm9sbGVyLnNjcm9sbFRvcDtcclxuICAgIHRvcCA9IE1hdGguZmxvb3IodG9wIC0gcGFkZGluZ1RvcChkaXNwbGF5KSk7XHJcbiAgICB2YXIgYm90dG9tID0gdmlld3BvcnQgJiYgdmlld3BvcnQuYm90dG9tICE9IG51bGwgPyB2aWV3cG9ydC5ib3R0b20gOiB0b3AgKyBkaXNwbGF5LndyYXBwZXIuY2xpZW50SGVpZ2h0O1xyXG5cclxuICAgIHZhciBmcm9tID0gbGluZUF0SGVpZ2h0KGRvYywgdG9wKSwgdG8gPSBsaW5lQXRIZWlnaHQoZG9jLCBib3R0b20pO1xyXG4gICAgLy8gRW5zdXJlIGlzIGEge2Zyb206IHtsaW5lLCBjaH0sIHRvOiB7bGluZSwgY2h9fSBvYmplY3QsIGFuZFxyXG4gICAgLy8gZm9yY2VzIHRob3NlIGxpbmVzIGludG8gdGhlIHZpZXdwb3J0IChpZiBwb3NzaWJsZSkuXHJcbiAgICBpZiAodmlld3BvcnQgJiYgdmlld3BvcnQuZW5zdXJlKSB7XHJcbiAgICAgIHZhciBlbnN1cmVGcm9tID0gdmlld3BvcnQuZW5zdXJlLmZyb20ubGluZSwgZW5zdXJlVG8gPSB2aWV3cG9ydC5lbnN1cmUudG8ubGluZTtcclxuICAgICAgaWYgKGVuc3VyZUZyb20gPCBmcm9tKSB7XHJcbiAgICAgICAgZnJvbSA9IGVuc3VyZUZyb207XHJcbiAgICAgICAgdG8gPSBsaW5lQXRIZWlnaHQoZG9jLCBoZWlnaHRBdExpbmUoZ2V0TGluZShkb2MsIGVuc3VyZUZyb20pKSArIGRpc3BsYXkud3JhcHBlci5jbGllbnRIZWlnaHQpO1xyXG4gICAgICB9IGVsc2UgaWYgKE1hdGgubWluKGVuc3VyZVRvLCBkb2MubGFzdExpbmUoKSkgPj0gdG8pIHtcclxuICAgICAgICBmcm9tID0gbGluZUF0SGVpZ2h0KGRvYywgaGVpZ2h0QXRMaW5lKGdldExpbmUoZG9jLCBlbnN1cmVUbykpIC0gZGlzcGxheS53cmFwcGVyLmNsaWVudEhlaWdodCk7XHJcbiAgICAgICAgdG8gPSBlbnN1cmVUbztcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIHtmcm9tOiBmcm9tLCB0bzogTWF0aC5tYXgodG8sIGZyb20gKyAxKX07XHJcbiAgfVxyXG5cclxuICAvLyBMSU5FIE5VTUJFUlNcclxuXHJcbiAgLy8gUmUtYWxpZ24gbGluZSBudW1iZXJzIGFuZCBndXR0ZXIgbWFya3MgdG8gY29tcGVuc2F0ZSBmb3JcclxuICAvLyBob3Jpem9udGFsIHNjcm9sbGluZy5cclxuICBmdW5jdGlvbiBhbGlnbkhvcml6b250YWxseShjbSkge1xyXG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCB2aWV3ID0gZGlzcGxheS52aWV3O1xyXG4gICAgaWYgKCFkaXNwbGF5LmFsaWduV2lkZ2V0cyAmJiAoIWRpc3BsYXkuZ3V0dGVycy5maXJzdENoaWxkIHx8ICFjbS5vcHRpb25zLmZpeGVkR3V0dGVyKSkgcmV0dXJuO1xyXG4gICAgdmFyIGNvbXAgPSBjb21wZW5zYXRlRm9ySFNjcm9sbChkaXNwbGF5KSAtIGRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsTGVmdCArIGNtLmRvYy5zY3JvbGxMZWZ0O1xyXG4gICAgdmFyIGd1dHRlclcgPSBkaXNwbGF5Lmd1dHRlcnMub2Zmc2V0V2lkdGgsIGxlZnQgPSBjb21wICsgXCJweFwiO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB2aWV3Lmxlbmd0aDsgaSsrKSBpZiAoIXZpZXdbaV0uaGlkZGVuKSB7XHJcbiAgICAgIGlmIChjbS5vcHRpb25zLmZpeGVkR3V0dGVyICYmIHZpZXdbaV0uZ3V0dGVyKVxyXG4gICAgICAgIHZpZXdbaV0uZ3V0dGVyLnN0eWxlLmxlZnQgPSBsZWZ0O1xyXG4gICAgICB2YXIgYWxpZ24gPSB2aWV3W2ldLmFsaWduYWJsZTtcclxuICAgICAgaWYgKGFsaWduKSBmb3IgKHZhciBqID0gMDsgaiA8IGFsaWduLmxlbmd0aDsgaisrKVxyXG4gICAgICAgIGFsaWduW2pdLnN0eWxlLmxlZnQgPSBsZWZ0O1xyXG4gICAgfVxyXG4gICAgaWYgKGNtLm9wdGlvbnMuZml4ZWRHdXR0ZXIpXHJcbiAgICAgIGRpc3BsYXkuZ3V0dGVycy5zdHlsZS5sZWZ0ID0gKGNvbXAgKyBndXR0ZXJXKSArIFwicHhcIjtcclxuICB9XHJcblxyXG4gIC8vIFVzZWQgdG8gZW5zdXJlIHRoYXQgdGhlIGxpbmUgbnVtYmVyIGd1dHRlciBpcyBzdGlsbCB0aGUgcmlnaHRcclxuICAvLyBzaXplIGZvciB0aGUgY3VycmVudCBkb2N1bWVudCBzaXplLiBSZXR1cm5zIHRydWUgd2hlbiBhbiB1cGRhdGVcclxuICAvLyBpcyBuZWVkZWQuXHJcbiAgZnVuY3Rpb24gbWF5YmVVcGRhdGVMaW5lTnVtYmVyV2lkdGgoY20pIHtcclxuICAgIGlmICghY20ub3B0aW9ucy5saW5lTnVtYmVycykgcmV0dXJuIGZhbHNlO1xyXG4gICAgdmFyIGRvYyA9IGNtLmRvYywgbGFzdCA9IGxpbmVOdW1iZXJGb3IoY20ub3B0aW9ucywgZG9jLmZpcnN0ICsgZG9jLnNpemUgLSAxKSwgZGlzcGxheSA9IGNtLmRpc3BsYXk7XHJcbiAgICBpZiAobGFzdC5sZW5ndGggIT0gZGlzcGxheS5saW5lTnVtQ2hhcnMpIHtcclxuICAgICAgdmFyIHRlc3QgPSBkaXNwbGF5Lm1lYXN1cmUuYXBwZW5kQ2hpbGQoZWx0KFwiZGl2XCIsIFtlbHQoXCJkaXZcIiwgbGFzdCldLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJDb2RlTWlycm9yLWxpbmVudW1iZXIgQ29kZU1pcnJvci1ndXR0ZXItZWx0XCIpKTtcclxuICAgICAgdmFyIGlubmVyVyA9IHRlc3QuZmlyc3RDaGlsZC5vZmZzZXRXaWR0aCwgcGFkZGluZyA9IHRlc3Qub2Zmc2V0V2lkdGggLSBpbm5lclc7XHJcbiAgICAgIGRpc3BsYXkubGluZUd1dHRlci5zdHlsZS53aWR0aCA9IFwiXCI7XHJcbiAgICAgIGRpc3BsYXkubGluZU51bUlubmVyV2lkdGggPSBNYXRoLm1heChpbm5lclcsIGRpc3BsYXkubGluZUd1dHRlci5vZmZzZXRXaWR0aCAtIHBhZGRpbmcpICsgMTtcclxuICAgICAgZGlzcGxheS5saW5lTnVtV2lkdGggPSBkaXNwbGF5LmxpbmVOdW1Jbm5lcldpZHRoICsgcGFkZGluZztcclxuICAgICAgZGlzcGxheS5saW5lTnVtQ2hhcnMgPSBkaXNwbGF5LmxpbmVOdW1Jbm5lcldpZHRoID8gbGFzdC5sZW5ndGggOiAtMTtcclxuICAgICAgZGlzcGxheS5saW5lR3V0dGVyLnN0eWxlLndpZHRoID0gZGlzcGxheS5saW5lTnVtV2lkdGggKyBcInB4XCI7XHJcbiAgICAgIHVwZGF0ZUd1dHRlclNwYWNlKGNtKTtcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBsaW5lTnVtYmVyRm9yKG9wdGlvbnMsIGkpIHtcclxuICAgIHJldHVybiBTdHJpbmcob3B0aW9ucy5saW5lTnVtYmVyRm9ybWF0dGVyKGkgKyBvcHRpb25zLmZpcnN0TGluZU51bWJlcikpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ29tcHV0ZXMgZGlzcGxheS5zY3JvbGxlci5zY3JvbGxMZWZ0ICsgZGlzcGxheS5ndXR0ZXJzLm9mZnNldFdpZHRoLFxyXG4gIC8vIGJ1dCB1c2luZyBnZXRCb3VuZGluZ0NsaWVudFJlY3QgdG8gZ2V0IGEgc3ViLXBpeGVsLWFjY3VyYXRlXHJcbiAgLy8gcmVzdWx0LlxyXG4gIGZ1bmN0aW9uIGNvbXBlbnNhdGVGb3JIU2Nyb2xsKGRpc3BsYXkpIHtcclxuICAgIHJldHVybiBkaXNwbGF5LnNjcm9sbGVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQgLSBkaXNwbGF5LnNpemVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQ7XHJcbiAgfVxyXG5cclxuICAvLyBESVNQTEFZIERSQVdJTkdcclxuXHJcbiAgZnVuY3Rpb24gRGlzcGxheVVwZGF0ZShjbSwgdmlld3BvcnQsIGZvcmNlKSB7XHJcbiAgICB2YXIgZGlzcGxheSA9IGNtLmRpc3BsYXk7XHJcblxyXG4gICAgdGhpcy52aWV3cG9ydCA9IHZpZXdwb3J0O1xyXG4gICAgLy8gU3RvcmUgc29tZSB2YWx1ZXMgdGhhdCB3ZSdsbCBuZWVkIGxhdGVyIChidXQgZG9uJ3Qgd2FudCB0byBmb3JjZSBhIHJlbGF5b3V0IGZvcilcclxuICAgIHRoaXMudmlzaWJsZSA9IHZpc2libGVMaW5lcyhkaXNwbGF5LCBjbS5kb2MsIHZpZXdwb3J0KTtcclxuICAgIHRoaXMuZWRpdG9ySXNIaWRkZW4gPSAhZGlzcGxheS53cmFwcGVyLm9mZnNldFdpZHRoO1xyXG4gICAgdGhpcy53cmFwcGVySGVpZ2h0ID0gZGlzcGxheS53cmFwcGVyLmNsaWVudEhlaWdodDtcclxuICAgIHRoaXMud3JhcHBlcldpZHRoID0gZGlzcGxheS53cmFwcGVyLmNsaWVudFdpZHRoO1xyXG4gICAgdGhpcy5vbGREaXNwbGF5V2lkdGggPSBkaXNwbGF5V2lkdGgoY20pO1xyXG4gICAgdGhpcy5mb3JjZSA9IGZvcmNlO1xyXG4gICAgdGhpcy5kaW1zID0gZ2V0RGltZW5zaW9ucyhjbSk7XHJcbiAgICB0aGlzLmV2ZW50cyA9IFtdO1xyXG4gIH1cclxuXHJcbiAgRGlzcGxheVVwZGF0ZS5wcm90b3R5cGUuc2lnbmFsID0gZnVuY3Rpb24oZW1pdHRlciwgdHlwZSkge1xyXG4gICAgaWYgKGhhc0hhbmRsZXIoZW1pdHRlciwgdHlwZSkpXHJcbiAgICAgIHRoaXMuZXZlbnRzLnB1c2goYXJndW1lbnRzKTtcclxuICB9O1xyXG4gIERpc3BsYXlVcGRhdGUucHJvdG90eXBlLmZpbmlzaCA9IGZ1bmN0aW9uKCkge1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmV2ZW50cy5sZW5ndGg7IGkrKylcclxuICAgICAgc2lnbmFsLmFwcGx5KG51bGwsIHRoaXMuZXZlbnRzW2ldKTtcclxuICB9O1xyXG5cclxuICBmdW5jdGlvbiBtYXliZUNsaXBTY3JvbGxiYXJzKGNtKSB7XHJcbiAgICB2YXIgZGlzcGxheSA9IGNtLmRpc3BsYXk7XHJcbiAgICBpZiAoIWRpc3BsYXkuc2Nyb2xsYmFyc0NsaXBwZWQgJiYgZGlzcGxheS5zY3JvbGxlci5vZmZzZXRXaWR0aCkge1xyXG4gICAgICBkaXNwbGF5Lm5hdGl2ZUJhcldpZHRoID0gZGlzcGxheS5zY3JvbGxlci5vZmZzZXRXaWR0aCAtIGRpc3BsYXkuc2Nyb2xsZXIuY2xpZW50V2lkdGg7XHJcbiAgICAgIGRpc3BsYXkuaGVpZ2h0Rm9yY2VyLnN0eWxlLmhlaWdodCA9IHNjcm9sbEdhcChjbSkgKyBcInB4XCI7XHJcbiAgICAgIGRpc3BsYXkuc2l6ZXIuc3R5bGUubWFyZ2luQm90dG9tID0gLWRpc3BsYXkubmF0aXZlQmFyV2lkdGggKyBcInB4XCI7XHJcbiAgICAgIGRpc3BsYXkuc2l6ZXIuc3R5bGUuYm9yZGVyUmlnaHRXaWR0aCA9IHNjcm9sbEdhcChjbSkgKyBcInB4XCI7XHJcbiAgICAgIGRpc3BsYXkuc2Nyb2xsYmFyc0NsaXBwZWQgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRG9lcyB0aGUgYWN0dWFsIHVwZGF0aW5nIG9mIHRoZSBsaW5lIGRpc3BsYXkuIEJhaWxzIG91dFxyXG4gIC8vIChyZXR1cm5pbmcgZmFsc2UpIHdoZW4gdGhlcmUgaXMgbm90aGluZyB0byBiZSBkb25lIGFuZCBmb3JjZWQgaXNcclxuICAvLyBmYWxzZS5cclxuICBmdW5jdGlvbiB1cGRhdGVEaXNwbGF5SWZOZWVkZWQoY20sIHVwZGF0ZSkge1xyXG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCBkb2MgPSBjbS5kb2M7XHJcblxyXG4gICAgaWYgKHVwZGF0ZS5lZGl0b3JJc0hpZGRlbikge1xyXG4gICAgICByZXNldFZpZXcoY20pO1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQmFpbCBvdXQgaWYgdGhlIHZpc2libGUgYXJlYSBpcyBhbHJlYWR5IHJlbmRlcmVkIGFuZCBub3RoaW5nIGNoYW5nZWQuXHJcbiAgICBpZiAoIXVwZGF0ZS5mb3JjZSAmJlxyXG4gICAgICAgIHVwZGF0ZS52aXNpYmxlLmZyb20gPj0gZGlzcGxheS52aWV3RnJvbSAmJiB1cGRhdGUudmlzaWJsZS50byA8PSBkaXNwbGF5LnZpZXdUbyAmJlxyXG4gICAgICAgIChkaXNwbGF5LnVwZGF0ZUxpbmVOdW1iZXJzID09IG51bGwgfHwgZGlzcGxheS51cGRhdGVMaW5lTnVtYmVycyA+PSBkaXNwbGF5LnZpZXdUbykgJiZcclxuICAgICAgICBkaXNwbGF5LnJlbmRlcmVkVmlldyA9PSBkaXNwbGF5LnZpZXcgJiYgY291bnREaXJ0eVZpZXcoY20pID09IDApXHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuXHJcbiAgICBpZiAobWF5YmVVcGRhdGVMaW5lTnVtYmVyV2lkdGgoY20pKSB7XHJcbiAgICAgIHJlc2V0VmlldyhjbSk7XHJcbiAgICAgIHVwZGF0ZS5kaW1zID0gZ2V0RGltZW5zaW9ucyhjbSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ29tcHV0ZSBhIHN1aXRhYmxlIG5ldyB2aWV3cG9ydCAoZnJvbSAmIHRvKVxyXG4gICAgdmFyIGVuZCA9IGRvYy5maXJzdCArIGRvYy5zaXplO1xyXG4gICAgdmFyIGZyb20gPSBNYXRoLm1heCh1cGRhdGUudmlzaWJsZS5mcm9tIC0gY20ub3B0aW9ucy52aWV3cG9ydE1hcmdpbiwgZG9jLmZpcnN0KTtcclxuICAgIHZhciB0byA9IE1hdGgubWluKGVuZCwgdXBkYXRlLnZpc2libGUudG8gKyBjbS5vcHRpb25zLnZpZXdwb3J0TWFyZ2luKTtcclxuICAgIGlmIChkaXNwbGF5LnZpZXdGcm9tIDwgZnJvbSAmJiBmcm9tIC0gZGlzcGxheS52aWV3RnJvbSA8IDIwKSBmcm9tID0gTWF0aC5tYXgoZG9jLmZpcnN0LCBkaXNwbGF5LnZpZXdGcm9tKTtcclxuICAgIGlmIChkaXNwbGF5LnZpZXdUbyA+IHRvICYmIGRpc3BsYXkudmlld1RvIC0gdG8gPCAyMCkgdG8gPSBNYXRoLm1pbihlbmQsIGRpc3BsYXkudmlld1RvKTtcclxuICAgIGlmIChzYXdDb2xsYXBzZWRTcGFucykge1xyXG4gICAgICBmcm9tID0gdmlzdWFsTGluZU5vKGNtLmRvYywgZnJvbSk7XHJcbiAgICAgIHRvID0gdmlzdWFsTGluZUVuZE5vKGNtLmRvYywgdG8pO1xyXG4gICAgfVxyXG5cclxuICAgIHZhciBkaWZmZXJlbnQgPSBmcm9tICE9IGRpc3BsYXkudmlld0Zyb20gfHwgdG8gIT0gZGlzcGxheS52aWV3VG8gfHxcclxuICAgICAgZGlzcGxheS5sYXN0V3JhcEhlaWdodCAhPSB1cGRhdGUud3JhcHBlckhlaWdodCB8fCBkaXNwbGF5Lmxhc3RXcmFwV2lkdGggIT0gdXBkYXRlLndyYXBwZXJXaWR0aDtcclxuICAgIGFkanVzdFZpZXcoY20sIGZyb20sIHRvKTtcclxuXHJcbiAgICBkaXNwbGF5LnZpZXdPZmZzZXQgPSBoZWlnaHRBdExpbmUoZ2V0TGluZShjbS5kb2MsIGRpc3BsYXkudmlld0Zyb20pKTtcclxuICAgIC8vIFBvc2l0aW9uIHRoZSBtb3ZlciBkaXYgdG8gYWxpZ24gd2l0aCB0aGUgY3VycmVudCBzY3JvbGwgcG9zaXRpb25cclxuICAgIGNtLmRpc3BsYXkubW92ZXIuc3R5bGUudG9wID0gZGlzcGxheS52aWV3T2Zmc2V0ICsgXCJweFwiO1xyXG5cclxuICAgIHZhciB0b1VwZGF0ZSA9IGNvdW50RGlydHlWaWV3KGNtKTtcclxuICAgIGlmICghZGlmZmVyZW50ICYmIHRvVXBkYXRlID09IDAgJiYgIXVwZGF0ZS5mb3JjZSAmJiBkaXNwbGF5LnJlbmRlcmVkVmlldyA9PSBkaXNwbGF5LnZpZXcgJiZcclxuICAgICAgICAoZGlzcGxheS51cGRhdGVMaW5lTnVtYmVycyA9PSBudWxsIHx8IGRpc3BsYXkudXBkYXRlTGluZU51bWJlcnMgPj0gZGlzcGxheS52aWV3VG8pKVxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcblxyXG4gICAgLy8gRm9yIGJpZyBjaGFuZ2VzLCB3ZSBoaWRlIHRoZSBlbmNsb3NpbmcgZWxlbWVudCBkdXJpbmcgdGhlXHJcbiAgICAvLyB1cGRhdGUsIHNpbmNlIHRoYXQgc3BlZWRzIHVwIHRoZSBvcGVyYXRpb25zIG9uIG1vc3QgYnJvd3NlcnMuXHJcbiAgICB2YXIgZm9jdXNlZCA9IGFjdGl2ZUVsdCgpO1xyXG4gICAgaWYgKHRvVXBkYXRlID4gNCkgZGlzcGxheS5saW5lRGl2LnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcclxuICAgIHBhdGNoRGlzcGxheShjbSwgZGlzcGxheS51cGRhdGVMaW5lTnVtYmVycywgdXBkYXRlLmRpbXMpO1xyXG4gICAgaWYgKHRvVXBkYXRlID4gNCkgZGlzcGxheS5saW5lRGl2LnN0eWxlLmRpc3BsYXkgPSBcIlwiO1xyXG4gICAgZGlzcGxheS5yZW5kZXJlZFZpZXcgPSBkaXNwbGF5LnZpZXc7XHJcbiAgICAvLyBUaGVyZSBtaWdodCBoYXZlIGJlZW4gYSB3aWRnZXQgd2l0aCBhIGZvY3VzZWQgZWxlbWVudCB0aGF0IGdvdFxyXG4gICAgLy8gaGlkZGVuIG9yIHVwZGF0ZWQsIGlmIHNvIHJlLWZvY3VzIGl0LlxyXG4gICAgaWYgKGZvY3VzZWQgJiYgYWN0aXZlRWx0KCkgIT0gZm9jdXNlZCAmJiBmb2N1c2VkLm9mZnNldEhlaWdodCkgZm9jdXNlZC5mb2N1cygpO1xyXG5cclxuICAgIC8vIFByZXZlbnQgc2VsZWN0aW9uIGFuZCBjdXJzb3JzIGZyb20gaW50ZXJmZXJpbmcgd2l0aCB0aGUgc2Nyb2xsXHJcbiAgICAvLyB3aWR0aCBhbmQgaGVpZ2h0LlxyXG4gICAgcmVtb3ZlQ2hpbGRyZW4oZGlzcGxheS5jdXJzb3JEaXYpO1xyXG4gICAgcmVtb3ZlQ2hpbGRyZW4oZGlzcGxheS5zZWxlY3Rpb25EaXYpO1xyXG4gICAgZGlzcGxheS5ndXR0ZXJzLnN0eWxlLmhlaWdodCA9IGRpc3BsYXkuc2l6ZXIuc3R5bGUubWluSGVpZ2h0ID0gMDtcclxuXHJcbiAgICBpZiAoZGlmZmVyZW50KSB7XHJcbiAgICAgIGRpc3BsYXkubGFzdFdyYXBIZWlnaHQgPSB1cGRhdGUud3JhcHBlckhlaWdodDtcclxuICAgICAgZGlzcGxheS5sYXN0V3JhcFdpZHRoID0gdXBkYXRlLndyYXBwZXJXaWR0aDtcclxuICAgICAgc3RhcnRXb3JrZXIoY20sIDQwMCk7XHJcbiAgICB9XHJcblxyXG4gICAgZGlzcGxheS51cGRhdGVMaW5lTnVtYmVycyA9IG51bGw7XHJcblxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBwb3N0VXBkYXRlRGlzcGxheShjbSwgdXBkYXRlKSB7XHJcbiAgICB2YXIgdmlld3BvcnQgPSB1cGRhdGUudmlld3BvcnQ7XHJcbiAgICBmb3IgKHZhciBmaXJzdCA9IHRydWU7OyBmaXJzdCA9IGZhbHNlKSB7XHJcbiAgICAgIGlmICghZmlyc3QgfHwgIWNtLm9wdGlvbnMubGluZVdyYXBwaW5nIHx8IHVwZGF0ZS5vbGREaXNwbGF5V2lkdGggPT0gZGlzcGxheVdpZHRoKGNtKSkge1xyXG4gICAgICAgIC8vIENsaXAgZm9yY2VkIHZpZXdwb3J0IHRvIGFjdHVhbCBzY3JvbGxhYmxlIGFyZWEuXHJcbiAgICAgICAgaWYgKHZpZXdwb3J0ICYmIHZpZXdwb3J0LnRvcCAhPSBudWxsKVxyXG4gICAgICAgICAgdmlld3BvcnQgPSB7dG9wOiBNYXRoLm1pbihjbS5kb2MuaGVpZ2h0ICsgcGFkZGluZ1ZlcnQoY20uZGlzcGxheSkgLSBkaXNwbGF5SGVpZ2h0KGNtKSwgdmlld3BvcnQudG9wKX07XHJcbiAgICAgICAgLy8gVXBkYXRlZCBsaW5lIGhlaWdodHMgbWlnaHQgcmVzdWx0IGluIHRoZSBkcmF3biBhcmVhIG5vdFxyXG4gICAgICAgIC8vIGFjdHVhbGx5IGNvdmVyaW5nIHRoZSB2aWV3cG9ydC4gS2VlcCBsb29waW5nIHVudGlsIGl0IGRvZXMuXHJcbiAgICAgICAgdXBkYXRlLnZpc2libGUgPSB2aXNpYmxlTGluZXMoY20uZGlzcGxheSwgY20uZG9jLCB2aWV3cG9ydCk7XHJcbiAgICAgICAgaWYgKHVwZGF0ZS52aXNpYmxlLmZyb20gPj0gY20uZGlzcGxheS52aWV3RnJvbSAmJiB1cGRhdGUudmlzaWJsZS50byA8PSBjbS5kaXNwbGF5LnZpZXdUbylcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcbiAgICAgIGlmICghdXBkYXRlRGlzcGxheUlmTmVlZGVkKGNtLCB1cGRhdGUpKSBicmVhaztcclxuICAgICAgdXBkYXRlSGVpZ2h0c0luVmlld3BvcnQoY20pO1xyXG4gICAgICB2YXIgYmFyTWVhc3VyZSA9IG1lYXN1cmVGb3JTY3JvbGxiYXJzKGNtKTtcclxuICAgICAgdXBkYXRlU2VsZWN0aW9uKGNtKTtcclxuICAgICAgc2V0RG9jdW1lbnRIZWlnaHQoY20sIGJhck1lYXN1cmUpO1xyXG4gICAgICB1cGRhdGVTY3JvbGxiYXJzKGNtLCBiYXJNZWFzdXJlKTtcclxuICAgIH1cclxuXHJcbiAgICB1cGRhdGUuc2lnbmFsKGNtLCBcInVwZGF0ZVwiLCBjbSk7XHJcbiAgICBpZiAoY20uZGlzcGxheS52aWV3RnJvbSAhPSBjbS5kaXNwbGF5LnJlcG9ydGVkVmlld0Zyb20gfHwgY20uZGlzcGxheS52aWV3VG8gIT0gY20uZGlzcGxheS5yZXBvcnRlZFZpZXdUbykge1xyXG4gICAgICB1cGRhdGUuc2lnbmFsKGNtLCBcInZpZXdwb3J0Q2hhbmdlXCIsIGNtLCBjbS5kaXNwbGF5LnZpZXdGcm9tLCBjbS5kaXNwbGF5LnZpZXdUbyk7XHJcbiAgICAgIGNtLmRpc3BsYXkucmVwb3J0ZWRWaWV3RnJvbSA9IGNtLmRpc3BsYXkudmlld0Zyb207IGNtLmRpc3BsYXkucmVwb3J0ZWRWaWV3VG8gPSBjbS5kaXNwbGF5LnZpZXdUbztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIHVwZGF0ZURpc3BsYXlTaW1wbGUoY20sIHZpZXdwb3J0KSB7XHJcbiAgICB2YXIgdXBkYXRlID0gbmV3IERpc3BsYXlVcGRhdGUoY20sIHZpZXdwb3J0KTtcclxuICAgIGlmICh1cGRhdGVEaXNwbGF5SWZOZWVkZWQoY20sIHVwZGF0ZSkpIHtcclxuICAgICAgdXBkYXRlSGVpZ2h0c0luVmlld3BvcnQoY20pO1xyXG4gICAgICBwb3N0VXBkYXRlRGlzcGxheShjbSwgdXBkYXRlKTtcclxuICAgICAgdmFyIGJhck1lYXN1cmUgPSBtZWFzdXJlRm9yU2Nyb2xsYmFycyhjbSk7XHJcbiAgICAgIHVwZGF0ZVNlbGVjdGlvbihjbSk7XHJcbiAgICAgIHNldERvY3VtZW50SGVpZ2h0KGNtLCBiYXJNZWFzdXJlKTtcclxuICAgICAgdXBkYXRlU2Nyb2xsYmFycyhjbSwgYmFyTWVhc3VyZSk7XHJcbiAgICAgIHVwZGF0ZS5maW5pc2goKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIHNldERvY3VtZW50SGVpZ2h0KGNtLCBtZWFzdXJlKSB7XHJcbiAgICBjbS5kaXNwbGF5LnNpemVyLnN0eWxlLm1pbkhlaWdodCA9IG1lYXN1cmUuZG9jSGVpZ2h0ICsgXCJweFwiO1xyXG4gICAgdmFyIHRvdGFsID0gbWVhc3VyZS5kb2NIZWlnaHQgKyBjbS5kaXNwbGF5LmJhckhlaWdodDtcclxuICAgIGNtLmRpc3BsYXkuaGVpZ2h0Rm9yY2VyLnN0eWxlLnRvcCA9IHRvdGFsICsgXCJweFwiO1xyXG4gICAgY20uZGlzcGxheS5ndXR0ZXJzLnN0eWxlLmhlaWdodCA9IE1hdGgubWF4KHRvdGFsICsgc2Nyb2xsR2FwKGNtKSwgbWVhc3VyZS5jbGllbnRIZWlnaHQpICsgXCJweFwiO1xyXG4gIH1cclxuXHJcbiAgLy8gUmVhZCB0aGUgYWN0dWFsIGhlaWdodHMgb2YgdGhlIHJlbmRlcmVkIGxpbmVzLCBhbmQgdXBkYXRlIHRoZWlyXHJcbiAgLy8gc3RvcmVkIGhlaWdodHMgdG8gbWF0Y2guXHJcbiAgZnVuY3Rpb24gdXBkYXRlSGVpZ2h0c0luVmlld3BvcnQoY20pIHtcclxuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheTtcclxuICAgIHZhciBwcmV2Qm90dG9tID0gZGlzcGxheS5saW5lRGl2Lm9mZnNldFRvcDtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZGlzcGxheS52aWV3Lmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIHZhciBjdXIgPSBkaXNwbGF5LnZpZXdbaV0sIGhlaWdodDtcclxuICAgICAgaWYgKGN1ci5oaWRkZW4pIGNvbnRpbnVlO1xyXG4gICAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA8IDgpIHtcclxuICAgICAgICB2YXIgYm90ID0gY3VyLm5vZGUub2Zmc2V0VG9wICsgY3VyLm5vZGUub2Zmc2V0SGVpZ2h0O1xyXG4gICAgICAgIGhlaWdodCA9IGJvdCAtIHByZXZCb3R0b207XHJcbiAgICAgICAgcHJldkJvdHRvbSA9IGJvdDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB2YXIgYm94ID0gY3VyLm5vZGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICAgICAgaGVpZ2h0ID0gYm94LmJvdHRvbSAtIGJveC50b3A7XHJcbiAgICAgIH1cclxuICAgICAgdmFyIGRpZmYgPSBjdXIubGluZS5oZWlnaHQgLSBoZWlnaHQ7XHJcbiAgICAgIGlmIChoZWlnaHQgPCAyKSBoZWlnaHQgPSB0ZXh0SGVpZ2h0KGRpc3BsYXkpO1xyXG4gICAgICBpZiAoZGlmZiA+IC4wMDEgfHwgZGlmZiA8IC0uMDAxKSB7XHJcbiAgICAgICAgdXBkYXRlTGluZUhlaWdodChjdXIubGluZSwgaGVpZ2h0KTtcclxuICAgICAgICB1cGRhdGVXaWRnZXRIZWlnaHQoY3VyLmxpbmUpO1xyXG4gICAgICAgIGlmIChjdXIucmVzdCkgZm9yICh2YXIgaiA9IDA7IGogPCBjdXIucmVzdC5sZW5ndGg7IGorKylcclxuICAgICAgICAgIHVwZGF0ZVdpZGdldEhlaWdodChjdXIucmVzdFtqXSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJlYWQgYW5kIHN0b3JlIHRoZSBoZWlnaHQgb2YgbGluZSB3aWRnZXRzIGFzc29jaWF0ZWQgd2l0aCB0aGVcclxuICAvLyBnaXZlbiBsaW5lLlxyXG4gIGZ1bmN0aW9uIHVwZGF0ZVdpZGdldEhlaWdodChsaW5lKSB7XHJcbiAgICBpZiAobGluZS53aWRnZXRzKSBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmUud2lkZ2V0cy5sZW5ndGg7ICsraSlcclxuICAgICAgbGluZS53aWRnZXRzW2ldLmhlaWdodCA9IGxpbmUud2lkZ2V0c1tpXS5ub2RlLnBhcmVudE5vZGUub2Zmc2V0SGVpZ2h0O1xyXG4gIH1cclxuXHJcbiAgLy8gRG8gYSBidWxrLXJlYWQgb2YgdGhlIERPTSBwb3NpdGlvbnMgYW5kIHNpemVzIG5lZWRlZCB0byBkcmF3IHRoZVxyXG4gIC8vIHZpZXcsIHNvIHRoYXQgd2UgZG9uJ3QgaW50ZXJsZWF2ZSByZWFkaW5nIGFuZCB3cml0aW5nIHRvIHRoZSBET00uXHJcbiAgZnVuY3Rpb24gZ2V0RGltZW5zaW9ucyhjbSkge1xyXG4gICAgdmFyIGQgPSBjbS5kaXNwbGF5LCBsZWZ0ID0ge30sIHdpZHRoID0ge307XHJcbiAgICB2YXIgZ3V0dGVyTGVmdCA9IGQuZ3V0dGVycy5jbGllbnRMZWZ0O1xyXG4gICAgZm9yICh2YXIgbiA9IGQuZ3V0dGVycy5maXJzdENoaWxkLCBpID0gMDsgbjsgbiA9IG4ubmV4dFNpYmxpbmcsICsraSkge1xyXG4gICAgICBsZWZ0W2NtLm9wdGlvbnMuZ3V0dGVyc1tpXV0gPSBuLm9mZnNldExlZnQgKyBuLmNsaWVudExlZnQgKyBndXR0ZXJMZWZ0O1xyXG4gICAgICB3aWR0aFtjbS5vcHRpb25zLmd1dHRlcnNbaV1dID0gbi5jbGllbnRXaWR0aDtcclxuICAgIH1cclxuICAgIHJldHVybiB7Zml4ZWRQb3M6IGNvbXBlbnNhdGVGb3JIU2Nyb2xsKGQpLFxyXG4gICAgICAgICAgICBndXR0ZXJUb3RhbFdpZHRoOiBkLmd1dHRlcnMub2Zmc2V0V2lkdGgsXHJcbiAgICAgICAgICAgIGd1dHRlckxlZnQ6IGxlZnQsXHJcbiAgICAgICAgICAgIGd1dHRlcldpZHRoOiB3aWR0aCxcclxuICAgICAgICAgICAgd3JhcHBlcldpZHRoOiBkLndyYXBwZXIuY2xpZW50V2lkdGh9O1xyXG4gIH1cclxuXHJcbiAgLy8gU3luYyB0aGUgYWN0dWFsIGRpc3BsYXkgRE9NIHN0cnVjdHVyZSB3aXRoIGRpc3BsYXkudmlldywgcmVtb3ZpbmdcclxuICAvLyBub2RlcyBmb3IgbGluZXMgdGhhdCBhcmUgbm8gbG9uZ2VyIGluIHZpZXcsIGFuZCBjcmVhdGluZyB0aGUgb25lc1xyXG4gIC8vIHRoYXQgYXJlIG5vdCB0aGVyZSB5ZXQsIGFuZCB1cGRhdGluZyB0aGUgb25lcyB0aGF0IGFyZSBvdXQgb2ZcclxuICAvLyBkYXRlLlxyXG4gIGZ1bmN0aW9uIHBhdGNoRGlzcGxheShjbSwgdXBkYXRlTnVtYmVyc0Zyb20sIGRpbXMpIHtcclxuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheSwgbGluZU51bWJlcnMgPSBjbS5vcHRpb25zLmxpbmVOdW1iZXJzO1xyXG4gICAgdmFyIGNvbnRhaW5lciA9IGRpc3BsYXkubGluZURpdiwgY3VyID0gY29udGFpbmVyLmZpcnN0Q2hpbGQ7XHJcblxyXG4gICAgZnVuY3Rpb24gcm0obm9kZSkge1xyXG4gICAgICB2YXIgbmV4dCA9IG5vZGUubmV4dFNpYmxpbmc7XHJcbiAgICAgIC8vIFdvcmtzIGFyb3VuZCBhIHRocm93LXNjcm9sbCBidWcgaW4gT1MgWCBXZWJraXRcclxuICAgICAgaWYgKHdlYmtpdCAmJiBtYWMgJiYgY20uZGlzcGxheS5jdXJyZW50V2hlZWxUYXJnZXQgPT0gbm9kZSlcclxuICAgICAgICBub2RlLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcclxuICAgICAgZWxzZVxyXG4gICAgICAgIG5vZGUucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChub2RlKTtcclxuICAgICAgcmV0dXJuIG5leHQ7XHJcbiAgICB9XHJcblxyXG4gICAgdmFyIHZpZXcgPSBkaXNwbGF5LnZpZXcsIGxpbmVOID0gZGlzcGxheS52aWV3RnJvbTtcclxuICAgIC8vIExvb3Agb3ZlciB0aGUgZWxlbWVudHMgaW4gdGhlIHZpZXcsIHN5bmNpbmcgY3VyICh0aGUgRE9NIG5vZGVzXHJcbiAgICAvLyBpbiBkaXNwbGF5LmxpbmVEaXYpIHdpdGggdGhlIHZpZXcgYXMgd2UgZ28uXHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZpZXcubGVuZ3RoOyBpKyspIHtcclxuICAgICAgdmFyIGxpbmVWaWV3ID0gdmlld1tpXTtcclxuICAgICAgaWYgKGxpbmVWaWV3LmhpZGRlbikge1xyXG4gICAgICB9IGVsc2UgaWYgKCFsaW5lVmlldy5ub2RlIHx8IGxpbmVWaWV3Lm5vZGUucGFyZW50Tm9kZSAhPSBjb250YWluZXIpIHsgLy8gTm90IGRyYXduIHlldFxyXG4gICAgICAgIHZhciBub2RlID0gYnVpbGRMaW5lRWxlbWVudChjbSwgbGluZVZpZXcsIGxpbmVOLCBkaW1zKTtcclxuICAgICAgICBjb250YWluZXIuaW5zZXJ0QmVmb3JlKG5vZGUsIGN1cik7XHJcbiAgICAgIH0gZWxzZSB7IC8vIEFscmVhZHkgZHJhd25cclxuICAgICAgICB3aGlsZSAoY3VyICE9IGxpbmVWaWV3Lm5vZGUpIGN1ciA9IHJtKGN1cik7XHJcbiAgICAgICAgdmFyIHVwZGF0ZU51bWJlciA9IGxpbmVOdW1iZXJzICYmIHVwZGF0ZU51bWJlcnNGcm9tICE9IG51bGwgJiZcclxuICAgICAgICAgIHVwZGF0ZU51bWJlcnNGcm9tIDw9IGxpbmVOICYmIGxpbmVWaWV3LmxpbmVOdW1iZXI7XHJcbiAgICAgICAgaWYgKGxpbmVWaWV3LmNoYW5nZXMpIHtcclxuICAgICAgICAgIGlmIChpbmRleE9mKGxpbmVWaWV3LmNoYW5nZXMsIFwiZ3V0dGVyXCIpID4gLTEpIHVwZGF0ZU51bWJlciA9IGZhbHNlO1xyXG4gICAgICAgICAgdXBkYXRlTGluZUZvckNoYW5nZXMoY20sIGxpbmVWaWV3LCBsaW5lTiwgZGltcyk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICh1cGRhdGVOdW1iZXIpIHtcclxuICAgICAgICAgIHJlbW92ZUNoaWxkcmVuKGxpbmVWaWV3LmxpbmVOdW1iZXIpO1xyXG4gICAgICAgICAgbGluZVZpZXcubGluZU51bWJlci5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShsaW5lTnVtYmVyRm9yKGNtLm9wdGlvbnMsIGxpbmVOKSkpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjdXIgPSBsaW5lVmlldy5ub2RlLm5leHRTaWJsaW5nO1xyXG4gICAgICB9XHJcbiAgICAgIGxpbmVOICs9IGxpbmVWaWV3LnNpemU7XHJcbiAgICB9XHJcbiAgICB3aGlsZSAoY3VyKSBjdXIgPSBybShjdXIpO1xyXG4gIH1cclxuXHJcbiAgLy8gV2hlbiBhbiBhc3BlY3Qgb2YgYSBsaW5lIGNoYW5nZXMsIGEgc3RyaW5nIGlzIGFkZGVkIHRvXHJcbiAgLy8gbGluZVZpZXcuY2hhbmdlcy4gVGhpcyB1cGRhdGVzIHRoZSByZWxldmFudCBwYXJ0IG9mIHRoZSBsaW5lJ3NcclxuICAvLyBET00gc3RydWN0dXJlLlxyXG4gIGZ1bmN0aW9uIHVwZGF0ZUxpbmVGb3JDaGFuZ2VzKGNtLCBsaW5lVmlldywgbGluZU4sIGRpbXMpIHtcclxuICAgIGZvciAodmFyIGogPSAwOyBqIDwgbGluZVZpZXcuY2hhbmdlcy5sZW5ndGg7IGorKykge1xyXG4gICAgICB2YXIgdHlwZSA9IGxpbmVWaWV3LmNoYW5nZXNbal07XHJcbiAgICAgIGlmICh0eXBlID09IFwidGV4dFwiKSB1cGRhdGVMaW5lVGV4dChjbSwgbGluZVZpZXcpO1xyXG4gICAgICBlbHNlIGlmICh0eXBlID09IFwiZ3V0dGVyXCIpIHVwZGF0ZUxpbmVHdXR0ZXIoY20sIGxpbmVWaWV3LCBsaW5lTiwgZGltcyk7XHJcbiAgICAgIGVsc2UgaWYgKHR5cGUgPT0gXCJjbGFzc1wiKSB1cGRhdGVMaW5lQ2xhc3NlcyhsaW5lVmlldyk7XHJcbiAgICAgIGVsc2UgaWYgKHR5cGUgPT0gXCJ3aWRnZXRcIikgdXBkYXRlTGluZVdpZGdldHMoY20sIGxpbmVWaWV3LCBkaW1zKTtcclxuICAgIH1cclxuICAgIGxpbmVWaWV3LmNoYW5nZXMgPSBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gTGluZXMgd2l0aCBndXR0ZXIgZWxlbWVudHMsIHdpZGdldHMgb3IgYSBiYWNrZ3JvdW5kIGNsYXNzIG5lZWQgdG9cclxuICAvLyBiZSB3cmFwcGVkLCBhbmQgaGF2ZSB0aGUgZXh0cmEgZWxlbWVudHMgYWRkZWQgdG8gdGhlIHdyYXBwZXIgZGl2XHJcbiAgZnVuY3Rpb24gZW5zdXJlTGluZVdyYXBwZWQobGluZVZpZXcpIHtcclxuICAgIGlmIChsaW5lVmlldy5ub2RlID09IGxpbmVWaWV3LnRleHQpIHtcclxuICAgICAgbGluZVZpZXcubm9kZSA9IGVsdChcImRpdlwiLCBudWxsLCBudWxsLCBcInBvc2l0aW9uOiByZWxhdGl2ZVwiKTtcclxuICAgICAgaWYgKGxpbmVWaWV3LnRleHQucGFyZW50Tm9kZSlcclxuICAgICAgICBsaW5lVmlldy50ZXh0LnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKGxpbmVWaWV3Lm5vZGUsIGxpbmVWaWV3LnRleHQpO1xyXG4gICAgICBsaW5lVmlldy5ub2RlLmFwcGVuZENoaWxkKGxpbmVWaWV3LnRleHQpO1xyXG4gICAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA8IDgpIGxpbmVWaWV3Lm5vZGUuc3R5bGUuekluZGV4ID0gMjtcclxuICAgIH1cclxuICAgIHJldHVybiBsaW5lVmlldy5ub2RlO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gdXBkYXRlTGluZUJhY2tncm91bmQobGluZVZpZXcpIHtcclxuICAgIHZhciBjbHMgPSBsaW5lVmlldy5iZ0NsYXNzID8gbGluZVZpZXcuYmdDbGFzcyArIFwiIFwiICsgKGxpbmVWaWV3LmxpbmUuYmdDbGFzcyB8fCBcIlwiKSA6IGxpbmVWaWV3LmxpbmUuYmdDbGFzcztcclxuICAgIGlmIChjbHMpIGNscyArPSBcIiBDb2RlTWlycm9yLWxpbmViYWNrZ3JvdW5kXCI7XHJcbiAgICBpZiAobGluZVZpZXcuYmFja2dyb3VuZCkge1xyXG4gICAgICBpZiAoY2xzKSBsaW5lVmlldy5iYWNrZ3JvdW5kLmNsYXNzTmFtZSA9IGNscztcclxuICAgICAgZWxzZSB7IGxpbmVWaWV3LmJhY2tncm91bmQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChsaW5lVmlldy5iYWNrZ3JvdW5kKTsgbGluZVZpZXcuYmFja2dyb3VuZCA9IG51bGw7IH1cclxuICAgIH0gZWxzZSBpZiAoY2xzKSB7XHJcbiAgICAgIHZhciB3cmFwID0gZW5zdXJlTGluZVdyYXBwZWQobGluZVZpZXcpO1xyXG4gICAgICBsaW5lVmlldy5iYWNrZ3JvdW5kID0gd3JhcC5pbnNlcnRCZWZvcmUoZWx0KFwiZGl2XCIsIG51bGwsIGNscyksIHdyYXAuZmlyc3RDaGlsZCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBXcmFwcGVyIGFyb3VuZCBidWlsZExpbmVDb250ZW50IHdoaWNoIHdpbGwgcmV1c2UgdGhlIHN0cnVjdHVyZVxyXG4gIC8vIGluIGRpc3BsYXkuZXh0ZXJuYWxNZWFzdXJlZCB3aGVuIHBvc3NpYmxlLlxyXG4gIGZ1bmN0aW9uIGdldExpbmVDb250ZW50KGNtLCBsaW5lVmlldykge1xyXG4gICAgdmFyIGV4dCA9IGNtLmRpc3BsYXkuZXh0ZXJuYWxNZWFzdXJlZDtcclxuICAgIGlmIChleHQgJiYgZXh0LmxpbmUgPT0gbGluZVZpZXcubGluZSkge1xyXG4gICAgICBjbS5kaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQgPSBudWxsO1xyXG4gICAgICBsaW5lVmlldy5tZWFzdXJlID0gZXh0Lm1lYXN1cmU7XHJcbiAgICAgIHJldHVybiBleHQuYnVpbHQ7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gYnVpbGRMaW5lQ29udGVudChjbSwgbGluZVZpZXcpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmVkcmF3IHRoZSBsaW5lJ3MgdGV4dC4gSW50ZXJhY3RzIHdpdGggdGhlIGJhY2tncm91bmQgYW5kIHRleHRcclxuICAvLyBjbGFzc2VzIGJlY2F1c2UgdGhlIG1vZGUgbWF5IG91dHB1dCB0b2tlbnMgdGhhdCBpbmZsdWVuY2UgdGhlc2VcclxuICAvLyBjbGFzc2VzLlxyXG4gIGZ1bmN0aW9uIHVwZGF0ZUxpbmVUZXh0KGNtLCBsaW5lVmlldykge1xyXG4gICAgdmFyIGNscyA9IGxpbmVWaWV3LnRleHQuY2xhc3NOYW1lO1xyXG4gICAgdmFyIGJ1aWx0ID0gZ2V0TGluZUNvbnRlbnQoY20sIGxpbmVWaWV3KTtcclxuICAgIGlmIChsaW5lVmlldy50ZXh0ID09IGxpbmVWaWV3Lm5vZGUpIGxpbmVWaWV3Lm5vZGUgPSBidWlsdC5wcmU7XHJcbiAgICBsaW5lVmlldy50ZXh0LnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKGJ1aWx0LnByZSwgbGluZVZpZXcudGV4dCk7XHJcbiAgICBsaW5lVmlldy50ZXh0ID0gYnVpbHQucHJlO1xyXG4gICAgaWYgKGJ1aWx0LmJnQ2xhc3MgIT0gbGluZVZpZXcuYmdDbGFzcyB8fCBidWlsdC50ZXh0Q2xhc3MgIT0gbGluZVZpZXcudGV4dENsYXNzKSB7XHJcbiAgICAgIGxpbmVWaWV3LmJnQ2xhc3MgPSBidWlsdC5iZ0NsYXNzO1xyXG4gICAgICBsaW5lVmlldy50ZXh0Q2xhc3MgPSBidWlsdC50ZXh0Q2xhc3M7XHJcbiAgICAgIHVwZGF0ZUxpbmVDbGFzc2VzKGxpbmVWaWV3KTtcclxuICAgIH0gZWxzZSBpZiAoY2xzKSB7XHJcbiAgICAgIGxpbmVWaWV3LnRleHQuY2xhc3NOYW1lID0gY2xzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gdXBkYXRlTGluZUNsYXNzZXMobGluZVZpZXcpIHtcclxuICAgIHVwZGF0ZUxpbmVCYWNrZ3JvdW5kKGxpbmVWaWV3KTtcclxuICAgIGlmIChsaW5lVmlldy5saW5lLndyYXBDbGFzcylcclxuICAgICAgZW5zdXJlTGluZVdyYXBwZWQobGluZVZpZXcpLmNsYXNzTmFtZSA9IGxpbmVWaWV3LmxpbmUud3JhcENsYXNzO1xyXG4gICAgZWxzZSBpZiAobGluZVZpZXcubm9kZSAhPSBsaW5lVmlldy50ZXh0KVxyXG4gICAgICBsaW5lVmlldy5ub2RlLmNsYXNzTmFtZSA9IFwiXCI7XHJcbiAgICB2YXIgdGV4dENsYXNzID0gbGluZVZpZXcudGV4dENsYXNzID8gbGluZVZpZXcudGV4dENsYXNzICsgXCIgXCIgKyAobGluZVZpZXcubGluZS50ZXh0Q2xhc3MgfHwgXCJcIikgOiBsaW5lVmlldy5saW5lLnRleHRDbGFzcztcclxuICAgIGxpbmVWaWV3LnRleHQuY2xhc3NOYW1lID0gdGV4dENsYXNzIHx8IFwiXCI7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiB1cGRhdGVMaW5lR3V0dGVyKGNtLCBsaW5lVmlldywgbGluZU4sIGRpbXMpIHtcclxuICAgIGlmIChsaW5lVmlldy5ndXR0ZXIpIHtcclxuICAgICAgbGluZVZpZXcubm9kZS5yZW1vdmVDaGlsZChsaW5lVmlldy5ndXR0ZXIpO1xyXG4gICAgICBsaW5lVmlldy5ndXR0ZXIgPSBudWxsO1xyXG4gICAgfVxyXG4gICAgaWYgKGxpbmVWaWV3Lmd1dHRlckJhY2tncm91bmQpIHtcclxuICAgICAgbGluZVZpZXcubm9kZS5yZW1vdmVDaGlsZChsaW5lVmlldy5ndXR0ZXJCYWNrZ3JvdW5kKTtcclxuICAgICAgbGluZVZpZXcuZ3V0dGVyQmFja2dyb3VuZCA9IG51bGw7XHJcbiAgICB9XHJcbiAgICBpZiAobGluZVZpZXcubGluZS5ndXR0ZXJDbGFzcykge1xyXG4gICAgICB2YXIgd3JhcCA9IGVuc3VyZUxpbmVXcmFwcGVkKGxpbmVWaWV3KTtcclxuICAgICAgbGluZVZpZXcuZ3V0dGVyQmFja2dyb3VuZCA9IGVsdChcImRpdlwiLCBudWxsLCBcIkNvZGVNaXJyb3ItZ3V0dGVyLWJhY2tncm91bmQgXCIgKyBsaW5lVmlldy5saW5lLmd1dHRlckNsYXNzLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwibGVmdDogXCIgKyAoY20ub3B0aW9ucy5maXhlZEd1dHRlciA/IGRpbXMuZml4ZWRQb3MgOiAtZGltcy5ndXR0ZXJUb3RhbFdpZHRoKSArXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJweDsgd2lkdGg6IFwiICsgZGltcy5ndXR0ZXJUb3RhbFdpZHRoICsgXCJweFwiKTtcclxuICAgICAgd3JhcC5pbnNlcnRCZWZvcmUobGluZVZpZXcuZ3V0dGVyQmFja2dyb3VuZCwgbGluZVZpZXcudGV4dCk7XHJcbiAgICB9XHJcbiAgICB2YXIgbWFya2VycyA9IGxpbmVWaWV3LmxpbmUuZ3V0dGVyTWFya2VycztcclxuICAgIGlmIChjbS5vcHRpb25zLmxpbmVOdW1iZXJzIHx8IG1hcmtlcnMpIHtcclxuICAgICAgdmFyIHdyYXAgPSBlbnN1cmVMaW5lV3JhcHBlZChsaW5lVmlldyk7XHJcbiAgICAgIHZhciBndXR0ZXJXcmFwID0gbGluZVZpZXcuZ3V0dGVyID0gZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1ndXR0ZXItd3JhcHBlclwiLCBcImxlZnQ6IFwiICtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGNtLm9wdGlvbnMuZml4ZWRHdXR0ZXIgPyBkaW1zLmZpeGVkUG9zIDogLWRpbXMuZ3V0dGVyVG90YWxXaWR0aCkgKyBcInB4XCIpO1xyXG4gICAgICBjbS5kaXNwbGF5LmlucHV0LnNldFVuZWRpdGFibGUoZ3V0dGVyV3JhcCk7XHJcbiAgICAgIHdyYXAuaW5zZXJ0QmVmb3JlKGd1dHRlcldyYXAsIGxpbmVWaWV3LnRleHQpO1xyXG4gICAgICBpZiAobGluZVZpZXcubGluZS5ndXR0ZXJDbGFzcylcclxuICAgICAgICBndXR0ZXJXcmFwLmNsYXNzTmFtZSArPSBcIiBcIiArIGxpbmVWaWV3LmxpbmUuZ3V0dGVyQ2xhc3M7XHJcbiAgICAgIGlmIChjbS5vcHRpb25zLmxpbmVOdW1iZXJzICYmICghbWFya2VycyB8fCAhbWFya2Vyc1tcIkNvZGVNaXJyb3ItbGluZW51bWJlcnNcIl0pKVxyXG4gICAgICAgIGxpbmVWaWV3LmxpbmVOdW1iZXIgPSBndXR0ZXJXcmFwLmFwcGVuZENoaWxkKFxyXG4gICAgICAgICAgZWx0KFwiZGl2XCIsIGxpbmVOdW1iZXJGb3IoY20ub3B0aW9ucywgbGluZU4pLFxyXG4gICAgICAgICAgICAgIFwiQ29kZU1pcnJvci1saW5lbnVtYmVyIENvZGVNaXJyb3ItZ3V0dGVyLWVsdFwiLFxyXG4gICAgICAgICAgICAgIFwibGVmdDogXCIgKyBkaW1zLmd1dHRlckxlZnRbXCJDb2RlTWlycm9yLWxpbmVudW1iZXJzXCJdICsgXCJweDsgd2lkdGg6IFwiXHJcbiAgICAgICAgICAgICAgKyBjbS5kaXNwbGF5LmxpbmVOdW1Jbm5lcldpZHRoICsgXCJweFwiKSk7XHJcbiAgICAgIGlmIChtYXJrZXJzKSBmb3IgKHZhciBrID0gMDsgayA8IGNtLm9wdGlvbnMuZ3V0dGVycy5sZW5ndGg7ICsraykge1xyXG4gICAgICAgIHZhciBpZCA9IGNtLm9wdGlvbnMuZ3V0dGVyc1trXSwgZm91bmQgPSBtYXJrZXJzLmhhc093blByb3BlcnR5KGlkKSAmJiBtYXJrZXJzW2lkXTtcclxuICAgICAgICBpZiAoZm91bmQpXHJcbiAgICAgICAgICBndXR0ZXJXcmFwLmFwcGVuZENoaWxkKGVsdChcImRpdlwiLCBbZm91bmRdLCBcIkNvZGVNaXJyb3ItZ3V0dGVyLWVsdFwiLCBcImxlZnQ6IFwiICtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpbXMuZ3V0dGVyTGVmdFtpZF0gKyBcInB4OyB3aWR0aDogXCIgKyBkaW1zLmd1dHRlcldpZHRoW2lkXSArIFwicHhcIikpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiB1cGRhdGVMaW5lV2lkZ2V0cyhjbSwgbGluZVZpZXcsIGRpbXMpIHtcclxuICAgIGlmIChsaW5lVmlldy5hbGlnbmFibGUpIGxpbmVWaWV3LmFsaWduYWJsZSA9IG51bGw7XHJcbiAgICBmb3IgKHZhciBub2RlID0gbGluZVZpZXcubm9kZS5maXJzdENoaWxkLCBuZXh0OyBub2RlOyBub2RlID0gbmV4dCkge1xyXG4gICAgICB2YXIgbmV4dCA9IG5vZGUubmV4dFNpYmxpbmc7XHJcbiAgICAgIGlmIChub2RlLmNsYXNzTmFtZSA9PSBcIkNvZGVNaXJyb3ItbGluZXdpZGdldFwiKVxyXG4gICAgICAgIGxpbmVWaWV3Lm5vZGUucmVtb3ZlQ2hpbGQobm9kZSk7XHJcbiAgICB9XHJcbiAgICBpbnNlcnRMaW5lV2lkZ2V0cyhjbSwgbGluZVZpZXcsIGRpbXMpO1xyXG4gIH1cclxuXHJcbiAgLy8gQnVpbGQgYSBsaW5lJ3MgRE9NIHJlcHJlc2VudGF0aW9uIGZyb20gc2NyYXRjaFxyXG4gIGZ1bmN0aW9uIGJ1aWxkTGluZUVsZW1lbnQoY20sIGxpbmVWaWV3LCBsaW5lTiwgZGltcykge1xyXG4gICAgdmFyIGJ1aWx0ID0gZ2V0TGluZUNvbnRlbnQoY20sIGxpbmVWaWV3KTtcclxuICAgIGxpbmVWaWV3LnRleHQgPSBsaW5lVmlldy5ub2RlID0gYnVpbHQucHJlO1xyXG4gICAgaWYgKGJ1aWx0LmJnQ2xhc3MpIGxpbmVWaWV3LmJnQ2xhc3MgPSBidWlsdC5iZ0NsYXNzO1xyXG4gICAgaWYgKGJ1aWx0LnRleHRDbGFzcykgbGluZVZpZXcudGV4dENsYXNzID0gYnVpbHQudGV4dENsYXNzO1xyXG5cclxuICAgIHVwZGF0ZUxpbmVDbGFzc2VzKGxpbmVWaWV3KTtcclxuICAgIHVwZGF0ZUxpbmVHdXR0ZXIoY20sIGxpbmVWaWV3LCBsaW5lTiwgZGltcyk7XHJcbiAgICBpbnNlcnRMaW5lV2lkZ2V0cyhjbSwgbGluZVZpZXcsIGRpbXMpO1xyXG4gICAgcmV0dXJuIGxpbmVWaWV3Lm5vZGU7XHJcbiAgfVxyXG5cclxuICAvLyBBIGxpbmVWaWV3IG1heSBjb250YWluIG11bHRpcGxlIGxvZ2ljYWwgbGluZXMgKHdoZW4gbWVyZ2VkIGJ5XHJcbiAgLy8gY29sbGFwc2VkIHNwYW5zKS4gVGhlIHdpZGdldHMgZm9yIGFsbCBvZiB0aGVtIG5lZWQgdG8gYmUgZHJhd24uXHJcbiAgZnVuY3Rpb24gaW5zZXJ0TGluZVdpZGdldHMoY20sIGxpbmVWaWV3LCBkaW1zKSB7XHJcbiAgICBpbnNlcnRMaW5lV2lkZ2V0c0ZvcihjbSwgbGluZVZpZXcubGluZSwgbGluZVZpZXcsIGRpbXMsIHRydWUpO1xyXG4gICAgaWYgKGxpbmVWaWV3LnJlc3QpIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZVZpZXcucmVzdC5sZW5ndGg7IGkrKylcclxuICAgICAgaW5zZXJ0TGluZVdpZGdldHNGb3IoY20sIGxpbmVWaWV3LnJlc3RbaV0sIGxpbmVWaWV3LCBkaW1zLCBmYWxzZSk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBpbnNlcnRMaW5lV2lkZ2V0c0ZvcihjbSwgbGluZSwgbGluZVZpZXcsIGRpbXMsIGFsbG93QWJvdmUpIHtcclxuICAgIGlmICghbGluZS53aWRnZXRzKSByZXR1cm47XHJcbiAgICB2YXIgd3JhcCA9IGVuc3VyZUxpbmVXcmFwcGVkKGxpbmVWaWV3KTtcclxuICAgIGZvciAodmFyIGkgPSAwLCB3cyA9IGxpbmUud2lkZ2V0czsgaSA8IHdzLmxlbmd0aDsgKytpKSB7XHJcbiAgICAgIHZhciB3aWRnZXQgPSB3c1tpXSwgbm9kZSA9IGVsdChcImRpdlwiLCBbd2lkZ2V0Lm5vZGVdLCBcIkNvZGVNaXJyb3ItbGluZXdpZGdldFwiKTtcclxuICAgICAgaWYgKCF3aWRnZXQuaGFuZGxlTW91c2VFdmVudHMpIG5vZGUuc2V0QXR0cmlidXRlKFwiY20taWdub3JlLWV2ZW50c1wiLCBcInRydWVcIik7XHJcbiAgICAgIHBvc2l0aW9uTGluZVdpZGdldCh3aWRnZXQsIG5vZGUsIGxpbmVWaWV3LCBkaW1zKTtcclxuICAgICAgY20uZGlzcGxheS5pbnB1dC5zZXRVbmVkaXRhYmxlKG5vZGUpO1xyXG4gICAgICBpZiAoYWxsb3dBYm92ZSAmJiB3aWRnZXQuYWJvdmUpXHJcbiAgICAgICAgd3JhcC5pbnNlcnRCZWZvcmUobm9kZSwgbGluZVZpZXcuZ3V0dGVyIHx8IGxpbmVWaWV3LnRleHQpO1xyXG4gICAgICBlbHNlXHJcbiAgICAgICAgd3JhcC5hcHBlbmRDaGlsZChub2RlKTtcclxuICAgICAgc2lnbmFsTGF0ZXIod2lkZ2V0LCBcInJlZHJhd1wiKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIHBvc2l0aW9uTGluZVdpZGdldCh3aWRnZXQsIG5vZGUsIGxpbmVWaWV3LCBkaW1zKSB7XHJcbiAgICBpZiAod2lkZ2V0Lm5vSFNjcm9sbCkge1xyXG4gICAgICAobGluZVZpZXcuYWxpZ25hYmxlIHx8IChsaW5lVmlldy5hbGlnbmFibGUgPSBbXSkpLnB1c2gobm9kZSk7XHJcbiAgICAgIHZhciB3aWR0aCA9IGRpbXMud3JhcHBlcldpZHRoO1xyXG4gICAgICBub2RlLnN0eWxlLmxlZnQgPSBkaW1zLmZpeGVkUG9zICsgXCJweFwiO1xyXG4gICAgICBpZiAoIXdpZGdldC5jb3Zlckd1dHRlcikge1xyXG4gICAgICAgIHdpZHRoIC09IGRpbXMuZ3V0dGVyVG90YWxXaWR0aDtcclxuICAgICAgICBub2RlLnN0eWxlLnBhZGRpbmdMZWZ0ID0gZGltcy5ndXR0ZXJUb3RhbFdpZHRoICsgXCJweFwiO1xyXG4gICAgICB9XHJcbiAgICAgIG5vZGUuc3R5bGUud2lkdGggPSB3aWR0aCArIFwicHhcIjtcclxuICAgIH1cclxuICAgIGlmICh3aWRnZXQuY292ZXJHdXR0ZXIpIHtcclxuICAgICAgbm9kZS5zdHlsZS56SW5kZXggPSA1O1xyXG4gICAgICBub2RlLnN0eWxlLnBvc2l0aW9uID0gXCJyZWxhdGl2ZVwiO1xyXG4gICAgICBpZiAoIXdpZGdldC5ub0hTY3JvbGwpIG5vZGUuc3R5bGUubWFyZ2luTGVmdCA9IC1kaW1zLmd1dHRlclRvdGFsV2lkdGggKyBcInB4XCI7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBQT1NJVElPTiBPQkpFQ1RcclxuXHJcbiAgLy8gQSBQb3MgaW5zdGFuY2UgcmVwcmVzZW50cyBhIHBvc2l0aW9uIHdpdGhpbiB0aGUgdGV4dC5cclxuICB2YXIgUG9zID0gQ29kZU1pcnJvci5Qb3MgPSBmdW5jdGlvbihsaW5lLCBjaCkge1xyXG4gICAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIFBvcykpIHJldHVybiBuZXcgUG9zKGxpbmUsIGNoKTtcclxuICAgIHRoaXMubGluZSA9IGxpbmU7IHRoaXMuY2ggPSBjaDtcclxuICB9O1xyXG5cclxuICAvLyBDb21wYXJlIHR3byBwb3NpdGlvbnMsIHJldHVybiAwIGlmIHRoZXkgYXJlIHRoZSBzYW1lLCBhIG5lZ2F0aXZlXHJcbiAgLy8gbnVtYmVyIHdoZW4gYSBpcyBsZXNzLCBhbmQgYSBwb3NpdGl2ZSBudW1iZXIgb3RoZXJ3aXNlLlxyXG4gIHZhciBjbXAgPSBDb2RlTWlycm9yLmNtcFBvcyA9IGZ1bmN0aW9uKGEsIGIpIHsgcmV0dXJuIGEubGluZSAtIGIubGluZSB8fCBhLmNoIC0gYi5jaDsgfTtcclxuXHJcbiAgZnVuY3Rpb24gY29weVBvcyh4KSB7cmV0dXJuIFBvcyh4LmxpbmUsIHguY2gpO31cclxuICBmdW5jdGlvbiBtYXhQb3MoYSwgYikgeyByZXR1cm4gY21wKGEsIGIpIDwgMCA/IGIgOiBhOyB9XHJcbiAgZnVuY3Rpb24gbWluUG9zKGEsIGIpIHsgcmV0dXJuIGNtcChhLCBiKSA8IDAgPyBhIDogYjsgfVxyXG5cclxuICAvLyBJTlBVVCBIQU5ETElOR1xyXG5cclxuICBmdW5jdGlvbiBlbnN1cmVGb2N1cyhjbSkge1xyXG4gICAgaWYgKCFjbS5zdGF0ZS5mb2N1c2VkKSB7IGNtLmRpc3BsYXkuaW5wdXQuZm9jdXMoKTsgb25Gb2N1cyhjbSk7IH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGlzUmVhZE9ubHkoY20pIHtcclxuICAgIHJldHVybiBjbS5vcHRpb25zLnJlYWRPbmx5IHx8IGNtLmRvYy5jYW50RWRpdDtcclxuICB9XHJcblxyXG4gIC8vIFRoaXMgd2lsbCBiZSBzZXQgdG8gYW4gYXJyYXkgb2Ygc3RyaW5ncyB3aGVuIGNvcHlpbmcsIHNvIHRoYXQsXHJcbiAgLy8gd2hlbiBwYXN0aW5nLCB3ZSBrbm93IHdoYXQga2luZCBvZiBzZWxlY3Rpb25zIHRoZSBjb3BpZWQgdGV4dFxyXG4gIC8vIHdhcyBtYWRlIG91dCBvZi5cclxuICB2YXIgbGFzdENvcGllZCA9IG51bGw7XHJcblxyXG4gIGZ1bmN0aW9uIGFwcGx5VGV4dElucHV0KGNtLCBpbnNlcnRlZCwgZGVsZXRlZCwgc2VsLCBvcmlnaW4pIHtcclxuICAgIHZhciBkb2MgPSBjbS5kb2M7XHJcbiAgICBjbS5kaXNwbGF5LnNoaWZ0ID0gZmFsc2U7XHJcbiAgICBpZiAoIXNlbCkgc2VsID0gZG9jLnNlbDtcclxuXHJcbiAgICB2YXIgcGFzdGUgPSBjbS5zdGF0ZS5wYXN0ZUluY29taW5nIHx8IG9yaWdpbiA9PSBcInBhc3RlXCI7XHJcbiAgICB2YXIgdGV4dExpbmVzID0gZG9jLnNwbGl0TGluZXMoaW5zZXJ0ZWQpLCBtdWx0aVBhc3RlID0gbnVsbDtcclxuICAgIC8vIFdoZW4gcGFzaW5nIE4gbGluZXMgaW50byBOIHNlbGVjdGlvbnMsIGluc2VydCBvbmUgbGluZSBwZXIgc2VsZWN0aW9uXHJcbiAgICBpZiAocGFzdGUgJiYgc2VsLnJhbmdlcy5sZW5ndGggPiAxKSB7XHJcbiAgICAgIGlmIChsYXN0Q29waWVkICYmIGxhc3RDb3BpZWQuam9pbihcIlxcblwiKSA9PSBpbnNlcnRlZCkge1xyXG4gICAgICAgIGlmIChzZWwucmFuZ2VzLmxlbmd0aCAlIGxhc3RDb3BpZWQubGVuZ3RoID09IDApIHtcclxuICAgICAgICAgIG11bHRpUGFzdGUgPSBbXTtcclxuICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGFzdENvcGllZC5sZW5ndGg7IGkrKylcclxuICAgICAgICAgICAgbXVsdGlQYXN0ZS5wdXNoKGRvYy5zcGxpdExpbmVzKGxhc3RDb3BpZWRbaV0pKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0gZWxzZSBpZiAodGV4dExpbmVzLmxlbmd0aCA9PSBzZWwucmFuZ2VzLmxlbmd0aCkge1xyXG4gICAgICAgIG11bHRpUGFzdGUgPSBtYXAodGV4dExpbmVzLCBmdW5jdGlvbihsKSB7IHJldHVybiBbbF07IH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTm9ybWFsIGJlaGF2aW9yIGlzIHRvIGluc2VydCB0aGUgbmV3IHRleHQgaW50byBldmVyeSBzZWxlY3Rpb25cclxuICAgIGZvciAodmFyIGkgPSBzZWwucmFuZ2VzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XHJcbiAgICAgIHZhciByYW5nZSA9IHNlbC5yYW5nZXNbaV07XHJcbiAgICAgIHZhciBmcm9tID0gcmFuZ2UuZnJvbSgpLCB0byA9IHJhbmdlLnRvKCk7XHJcbiAgICAgIGlmIChyYW5nZS5lbXB0eSgpKSB7XHJcbiAgICAgICAgaWYgKGRlbGV0ZWQgJiYgZGVsZXRlZCA+IDApIC8vIEhhbmRsZSBkZWxldGlvblxyXG4gICAgICAgICAgZnJvbSA9IFBvcyhmcm9tLmxpbmUsIGZyb20uY2ggLSBkZWxldGVkKTtcclxuICAgICAgICBlbHNlIGlmIChjbS5zdGF0ZS5vdmVyd3JpdGUgJiYgIXBhc3RlKSAvLyBIYW5kbGUgb3ZlcndyaXRlXHJcbiAgICAgICAgICB0byA9IFBvcyh0by5saW5lLCBNYXRoLm1pbihnZXRMaW5lKGRvYywgdG8ubGluZSkudGV4dC5sZW5ndGgsIHRvLmNoICsgbHN0KHRleHRMaW5lcykubGVuZ3RoKSk7XHJcbiAgICAgIH1cclxuICAgICAgdmFyIHVwZGF0ZUlucHV0ID0gY20uY3VyT3AudXBkYXRlSW5wdXQ7XHJcbiAgICAgIHZhciBjaGFuZ2VFdmVudCA9IHtmcm9tOiBmcm9tLCB0bzogdG8sIHRleHQ6IG11bHRpUGFzdGUgPyBtdWx0aVBhc3RlW2kgJSBtdWx0aVBhc3RlLmxlbmd0aF0gOiB0ZXh0TGluZXMsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICBvcmlnaW46IG9yaWdpbiB8fCAocGFzdGUgPyBcInBhc3RlXCIgOiBjbS5zdGF0ZS5jdXRJbmNvbWluZyA/IFwiY3V0XCIgOiBcIitpbnB1dFwiKX07XHJcbiAgICAgIG1ha2VDaGFuZ2UoY20uZG9jLCBjaGFuZ2VFdmVudCk7XHJcbiAgICAgIHNpZ25hbExhdGVyKGNtLCBcImlucHV0UmVhZFwiLCBjbSwgY2hhbmdlRXZlbnQpO1xyXG4gICAgfVxyXG4gICAgaWYgKGluc2VydGVkICYmICFwYXN0ZSlcclxuICAgICAgdHJpZ2dlckVsZWN0cmljKGNtLCBpbnNlcnRlZCk7XHJcblxyXG4gICAgZW5zdXJlQ3Vyc29yVmlzaWJsZShjbSk7XHJcbiAgICBjbS5jdXJPcC51cGRhdGVJbnB1dCA9IHVwZGF0ZUlucHV0O1xyXG4gICAgY20uY3VyT3AudHlwaW5nID0gdHJ1ZTtcclxuICAgIGNtLnN0YXRlLnBhc3RlSW5jb21pbmcgPSBjbS5zdGF0ZS5jdXRJbmNvbWluZyA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gaGFuZGxlUGFzdGUoZSwgY20pIHtcclxuICAgIHZhciBwYXN0ZWQgPSBlLmNsaXBib2FyZERhdGEgJiYgZS5jbGlwYm9hcmREYXRhLmdldERhdGEoXCJ0ZXh0L3BsYWluXCIpO1xyXG4gICAgaWYgKHBhc3RlZCkge1xyXG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgIGlmICghaXNSZWFkT25seShjbSkgJiYgIWNtLm9wdGlvbnMuZGlzYWJsZUlucHV0KVxyXG4gICAgICAgIHJ1bkluT3AoY20sIGZ1bmN0aW9uKCkgeyBhcHBseVRleHRJbnB1dChjbSwgcGFzdGVkLCAwLCBudWxsLCBcInBhc3RlXCIpOyB9KTtcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiB0cmlnZ2VyRWxlY3RyaWMoY20sIGluc2VydGVkKSB7XHJcbiAgICAvLyBXaGVuIGFuICdlbGVjdHJpYycgY2hhcmFjdGVyIGlzIGluc2VydGVkLCBpbW1lZGlhdGVseSB0cmlnZ2VyIGEgcmVpbmRlbnRcclxuICAgIGlmICghY20ub3B0aW9ucy5lbGVjdHJpY0NoYXJzIHx8ICFjbS5vcHRpb25zLnNtYXJ0SW5kZW50KSByZXR1cm47XHJcbiAgICB2YXIgc2VsID0gY20uZG9jLnNlbDtcclxuXHJcbiAgICBmb3IgKHZhciBpID0gc2VsLnJhbmdlcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xyXG4gICAgICB2YXIgcmFuZ2UgPSBzZWwucmFuZ2VzW2ldO1xyXG4gICAgICBpZiAocmFuZ2UuaGVhZC5jaCA+IDEwMCB8fCAoaSAmJiBzZWwucmFuZ2VzW2kgLSAxXS5oZWFkLmxpbmUgPT0gcmFuZ2UuaGVhZC5saW5lKSkgY29udGludWU7XHJcbiAgICAgIHZhciBtb2RlID0gY20uZ2V0TW9kZUF0KHJhbmdlLmhlYWQpO1xyXG4gICAgICB2YXIgaW5kZW50ZWQgPSBmYWxzZTtcclxuICAgICAgaWYgKG1vZGUuZWxlY3RyaWNDaGFycykge1xyXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbW9kZS5lbGVjdHJpY0NoYXJzLmxlbmd0aDsgaisrKVxyXG4gICAgICAgICAgaWYgKGluc2VydGVkLmluZGV4T2YobW9kZS5lbGVjdHJpY0NoYXJzLmNoYXJBdChqKSkgPiAtMSkge1xyXG4gICAgICAgICAgICBpbmRlbnRlZCA9IGluZGVudExpbmUoY20sIHJhbmdlLmhlYWQubGluZSwgXCJzbWFydFwiKTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICB9XHJcbiAgICAgIH0gZWxzZSBpZiAobW9kZS5lbGVjdHJpY0lucHV0KSB7XHJcbiAgICAgICAgaWYgKG1vZGUuZWxlY3RyaWNJbnB1dC50ZXN0KGdldExpbmUoY20uZG9jLCByYW5nZS5oZWFkLmxpbmUpLnRleHQuc2xpY2UoMCwgcmFuZ2UuaGVhZC5jaCkpKVxyXG4gICAgICAgICAgaW5kZW50ZWQgPSBpbmRlbnRMaW5lKGNtLCByYW5nZS5oZWFkLmxpbmUsIFwic21hcnRcIik7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKGluZGVudGVkKSBzaWduYWxMYXRlcihjbSwgXCJlbGVjdHJpY0lucHV0XCIsIGNtLCByYW5nZS5oZWFkLmxpbmUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gY29weWFibGVSYW5nZXMoY20pIHtcclxuICAgIHZhciB0ZXh0ID0gW10sIHJhbmdlcyA9IFtdO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjbS5kb2Muc2VsLnJhbmdlcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICB2YXIgbGluZSA9IGNtLmRvYy5zZWwucmFuZ2VzW2ldLmhlYWQubGluZTtcclxuICAgICAgdmFyIGxpbmVSYW5nZSA9IHthbmNob3I6IFBvcyhsaW5lLCAwKSwgaGVhZDogUG9zKGxpbmUgKyAxLCAwKX07XHJcbiAgICAgIHJhbmdlcy5wdXNoKGxpbmVSYW5nZSk7XHJcbiAgICAgIHRleHQucHVzaChjbS5nZXRSYW5nZShsaW5lUmFuZ2UuYW5jaG9yLCBsaW5lUmFuZ2UuaGVhZCkpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHt0ZXh0OiB0ZXh0LCByYW5nZXM6IHJhbmdlc307XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBkaXNhYmxlQnJvd3Nlck1hZ2ljKGZpZWxkKSB7XHJcbiAgICBmaWVsZC5zZXRBdHRyaWJ1dGUoXCJhdXRvY29ycmVjdFwiLCBcIm9mZlwiKTtcclxuICAgIGZpZWxkLnNldEF0dHJpYnV0ZShcImF1dG9jYXBpdGFsaXplXCIsIFwib2ZmXCIpO1xyXG4gICAgZmllbGQuc2V0QXR0cmlidXRlKFwic3BlbGxjaGVja1wiLCBcImZhbHNlXCIpO1xyXG4gIH1cclxuXHJcbiAgLy8gVEVYVEFSRUEgSU5QVVQgU1RZTEVcclxuXHJcbiAgZnVuY3Rpb24gVGV4dGFyZWFJbnB1dChjbSkge1xyXG4gICAgdGhpcy5jbSA9IGNtO1xyXG4gICAgLy8gU2VlIGlucHV0LnBvbGwgYW5kIGlucHV0LnJlc2V0XHJcbiAgICB0aGlzLnByZXZJbnB1dCA9IFwiXCI7XHJcblxyXG4gICAgLy8gRmxhZyB0aGF0IGluZGljYXRlcyB3aGV0aGVyIHdlIGV4cGVjdCBpbnB1dCB0byBhcHBlYXIgcmVhbCBzb29uXHJcbiAgICAvLyBub3cgKGFmdGVyIHNvbWUgZXZlbnQgbGlrZSAna2V5cHJlc3MnIG9yICdpbnB1dCcpIGFuZCBhcmVcclxuICAgIC8vIHBvbGxpbmcgaW50ZW5zaXZlbHkuXHJcbiAgICB0aGlzLnBvbGxpbmdGYXN0ID0gZmFsc2U7XHJcbiAgICAvLyBTZWxmLXJlc2V0dGluZyB0aW1lb3V0IGZvciB0aGUgcG9sbGVyXHJcbiAgICB0aGlzLnBvbGxpbmcgPSBuZXcgRGVsYXllZCgpO1xyXG4gICAgLy8gVHJhY2tzIHdoZW4gaW5wdXQucmVzZXQgaGFzIHB1bnRlZCB0byBqdXN0IHB1dHRpbmcgYSBzaG9ydFxyXG4gICAgLy8gc3RyaW5nIGludG8gdGhlIHRleHRhcmVhIGluc3RlYWQgb2YgdGhlIGZ1bGwgc2VsZWN0aW9uLlxyXG4gICAgdGhpcy5pbmFjY3VyYXRlU2VsZWN0aW9uID0gZmFsc2U7XHJcbiAgICAvLyBVc2VkIHRvIHdvcmsgYXJvdW5kIElFIGlzc3VlIHdpdGggc2VsZWN0aW9uIGJlaW5nIGZvcmdvdHRlbiB3aGVuIGZvY3VzIG1vdmVzIGF3YXkgZnJvbSB0ZXh0YXJlYVxyXG4gICAgdGhpcy5oYXNTZWxlY3Rpb24gPSBmYWxzZTtcclxuICAgIHRoaXMuY29tcG9zaW5nID0gbnVsbDtcclxuICB9O1xyXG5cclxuICBmdW5jdGlvbiBoaWRkZW5UZXh0YXJlYSgpIHtcclxuICAgIHZhciB0ZSA9IGVsdChcInRleHRhcmVhXCIsIG51bGwsIG51bGwsIFwicG9zaXRpb246IGFic29sdXRlOyBwYWRkaW5nOiAwOyB3aWR0aDogMXB4OyBoZWlnaHQ6IDFlbTsgb3V0bGluZTogbm9uZVwiKTtcclxuICAgIHZhciBkaXYgPSBlbHQoXCJkaXZcIiwgW3RlXSwgbnVsbCwgXCJvdmVyZmxvdzogaGlkZGVuOyBwb3NpdGlvbjogcmVsYXRpdmU7IHdpZHRoOiAzcHg7IGhlaWdodDogMHB4O1wiKTtcclxuICAgIC8vIFRoZSB0ZXh0YXJlYSBpcyBrZXB0IHBvc2l0aW9uZWQgbmVhciB0aGUgY3Vyc29yIHRvIHByZXZlbnQgdGhlXHJcbiAgICAvLyBmYWN0IHRoYXQgaXQnbGwgYmUgc2Nyb2xsZWQgaW50byB2aWV3IG9uIGlucHV0IGZyb20gc2Nyb2xsaW5nXHJcbiAgICAvLyBvdXIgZmFrZSBjdXJzb3Igb3V0IG9mIHZpZXcuIE9uIHdlYmtpdCwgd2hlbiB3cmFwPW9mZiwgcGFzdGUgaXNcclxuICAgIC8vIHZlcnkgc2xvdy4gU28gbWFrZSB0aGUgYXJlYSB3aWRlIGluc3RlYWQuXHJcbiAgICBpZiAod2Via2l0KSB0ZS5zdHlsZS53aWR0aCA9IFwiMTAwMHB4XCI7XHJcbiAgICBlbHNlIHRlLnNldEF0dHJpYnV0ZShcIndyYXBcIiwgXCJvZmZcIik7XHJcbiAgICAvLyBJZiBib3JkZXI6IDA7IC0tIGlPUyBmYWlscyB0byBvcGVuIGtleWJvYXJkIChpc3N1ZSAjMTI4NylcclxuICAgIGlmIChpb3MpIHRlLnN0eWxlLmJvcmRlciA9IFwiMXB4IHNvbGlkIGJsYWNrXCI7XHJcbiAgICBkaXNhYmxlQnJvd3Nlck1hZ2ljKHRlKTtcclxuICAgIHJldHVybiBkaXY7XHJcbiAgfVxyXG5cclxuICBUZXh0YXJlYUlucHV0LnByb3RvdHlwZSA9IGNvcHlPYmooe1xyXG4gICAgaW5pdDogZnVuY3Rpb24oZGlzcGxheSkge1xyXG4gICAgICB2YXIgaW5wdXQgPSB0aGlzLCBjbSA9IHRoaXMuY207XHJcblxyXG4gICAgICAvLyBXcmFwcyBhbmQgaGlkZXMgaW5wdXQgdGV4dGFyZWFcclxuICAgICAgdmFyIGRpdiA9IHRoaXMud3JhcHBlciA9IGhpZGRlblRleHRhcmVhKCk7XHJcbiAgICAgIC8vIFRoZSBzZW1paGlkZGVuIHRleHRhcmVhIHRoYXQgaXMgZm9jdXNlZCB3aGVuIHRoZSBlZGl0b3IgaXNcclxuICAgICAgLy8gZm9jdXNlZCwgYW5kIHJlY2VpdmVzIGlucHV0LlxyXG4gICAgICB2YXIgdGUgPSB0aGlzLnRleHRhcmVhID0gZGl2LmZpcnN0Q2hpbGQ7XHJcbiAgICAgIGRpc3BsYXkud3JhcHBlci5pbnNlcnRCZWZvcmUoZGl2LCBkaXNwbGF5LndyYXBwZXIuZmlyc3RDaGlsZCk7XHJcblxyXG4gICAgICAvLyBOZWVkZWQgdG8gaGlkZSBiaWcgYmx1ZSBibGlua2luZyBjdXJzb3Igb24gTW9iaWxlIFNhZmFyaSAoZG9lc24ndCBzZWVtIHRvIHdvcmsgaW4gaU9TIDggYW55bW9yZSlcclxuICAgICAgaWYgKGlvcykgdGUuc3R5bGUud2lkdGggPSBcIjBweFwiO1xyXG5cclxuICAgICAgb24odGUsIFwiaW5wdXRcIiwgZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPj0gOSAmJiBpbnB1dC5oYXNTZWxlY3Rpb24pIGlucHV0Lmhhc1NlbGVjdGlvbiA9IG51bGw7XHJcbiAgICAgICAgaW5wdXQucG9sbCgpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIG9uKHRlLCBcInBhc3RlXCIsIGZ1bmN0aW9uKGUpIHtcclxuICAgICAgICBpZiAoaGFuZGxlUGFzdGUoZSwgY20pKSByZXR1cm4gdHJ1ZTtcclxuXHJcbiAgICAgICAgY20uc3RhdGUucGFzdGVJbmNvbWluZyA9IHRydWU7XHJcbiAgICAgICAgaW5wdXQuZmFzdFBvbGwoKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBmdW5jdGlvbiBwcmVwYXJlQ29weUN1dChlKSB7XHJcbiAgICAgICAgaWYgKGNtLnNvbWV0aGluZ1NlbGVjdGVkKCkpIHtcclxuICAgICAgICAgIGxhc3RDb3BpZWQgPSBjbS5nZXRTZWxlY3Rpb25zKCk7XHJcbiAgICAgICAgICBpZiAoaW5wdXQuaW5hY2N1cmF0ZVNlbGVjdGlvbikge1xyXG4gICAgICAgICAgICBpbnB1dC5wcmV2SW5wdXQgPSBcIlwiO1xyXG4gICAgICAgICAgICBpbnB1dC5pbmFjY3VyYXRlU2VsZWN0aW9uID0gZmFsc2U7XHJcbiAgICAgICAgICAgIHRlLnZhbHVlID0gbGFzdENvcGllZC5qb2luKFwiXFxuXCIpO1xyXG4gICAgICAgICAgICBzZWxlY3RJbnB1dCh0ZSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIGlmICghY20ub3B0aW9ucy5saW5lV2lzZUNvcHlDdXQpIHtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdmFyIHJhbmdlcyA9IGNvcHlhYmxlUmFuZ2VzKGNtKTtcclxuICAgICAgICAgIGxhc3RDb3BpZWQgPSByYW5nZXMudGV4dDtcclxuICAgICAgICAgIGlmIChlLnR5cGUgPT0gXCJjdXRcIikge1xyXG4gICAgICAgICAgICBjbS5zZXRTZWxlY3Rpb25zKHJhbmdlcy5yYW5nZXMsIG51bGwsIHNlbF9kb250U2Nyb2xsKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGlucHV0LnByZXZJbnB1dCA9IFwiXCI7XHJcbiAgICAgICAgICAgIHRlLnZhbHVlID0gcmFuZ2VzLnRleHQuam9pbihcIlxcblwiKTtcclxuICAgICAgICAgICAgc2VsZWN0SW5wdXQodGUpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoZS50eXBlID09IFwiY3V0XCIpIGNtLnN0YXRlLmN1dEluY29taW5nID0gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgICBvbih0ZSwgXCJjdXRcIiwgcHJlcGFyZUNvcHlDdXQpO1xyXG4gICAgICBvbih0ZSwgXCJjb3B5XCIsIHByZXBhcmVDb3B5Q3V0KTtcclxuXHJcbiAgICAgIG9uKGRpc3BsYXkuc2Nyb2xsZXIsIFwicGFzdGVcIiwgZnVuY3Rpb24oZSkge1xyXG4gICAgICAgIGlmIChldmVudEluV2lkZ2V0KGRpc3BsYXksIGUpKSByZXR1cm47XHJcbiAgICAgICAgY20uc3RhdGUucGFzdGVJbmNvbWluZyA9IHRydWU7XHJcbiAgICAgICAgaW5wdXQuZm9jdXMoKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBQcmV2ZW50IG5vcm1hbCBzZWxlY3Rpb24gaW4gdGhlIGVkaXRvciAod2UgaGFuZGxlIG91ciBvd24pXHJcbiAgICAgIG9uKGRpc3BsYXkubGluZVNwYWNlLCBcInNlbGVjdHN0YXJ0XCIsIGZ1bmN0aW9uKGUpIHtcclxuICAgICAgICBpZiAoIWV2ZW50SW5XaWRnZXQoZGlzcGxheSwgZSkpIGVfcHJldmVudERlZmF1bHQoZSk7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgb24odGUsIFwiY29tcG9zaXRpb25zdGFydFwiLCBmdW5jdGlvbigpIHtcclxuICAgICAgICB2YXIgc3RhcnQgPSBjbS5nZXRDdXJzb3IoXCJmcm9tXCIpO1xyXG4gICAgICAgIGlmIChpbnB1dC5jb21wb3NpbmcpIGlucHV0LmNvbXBvc2luZy5yYW5nZS5jbGVhcigpXHJcbiAgICAgICAgaW5wdXQuY29tcG9zaW5nID0ge1xyXG4gICAgICAgICAgc3RhcnQ6IHN0YXJ0LFxyXG4gICAgICAgICAgcmFuZ2U6IGNtLm1hcmtUZXh0KHN0YXJ0LCBjbS5nZXRDdXJzb3IoXCJ0b1wiKSwge2NsYXNzTmFtZTogXCJDb2RlTWlycm9yLWNvbXBvc2luZ1wifSlcclxuICAgICAgICB9O1xyXG4gICAgICB9KTtcclxuICAgICAgb24odGUsIFwiY29tcG9zaXRpb25lbmRcIiwgZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgaWYgKGlucHV0LmNvbXBvc2luZykge1xyXG4gICAgICAgICAgaW5wdXQucG9sbCgpO1xyXG4gICAgICAgICAgaW5wdXQuY29tcG9zaW5nLnJhbmdlLmNsZWFyKCk7XHJcbiAgICAgICAgICBpbnB1dC5jb21wb3NpbmcgPSBudWxsO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9LFxyXG5cclxuICAgIHByZXBhcmVTZWxlY3Rpb246IGZ1bmN0aW9uKCkge1xyXG4gICAgICAvLyBSZWRyYXcgdGhlIHNlbGVjdGlvbiBhbmQvb3IgY3Vyc29yXHJcbiAgICAgIHZhciBjbSA9IHRoaXMuY20sIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCBkb2MgPSBjbS5kb2M7XHJcbiAgICAgIHZhciByZXN1bHQgPSBwcmVwYXJlU2VsZWN0aW9uKGNtKTtcclxuXHJcbiAgICAgIC8vIE1vdmUgdGhlIGhpZGRlbiB0ZXh0YXJlYSBuZWFyIHRoZSBjdXJzb3IgdG8gcHJldmVudCBzY3JvbGxpbmcgYXJ0aWZhY3RzXHJcbiAgICAgIGlmIChjbS5vcHRpb25zLm1vdmVJbnB1dFdpdGhDdXJzb3IpIHtcclxuICAgICAgICB2YXIgaGVhZFBvcyA9IGN1cnNvckNvb3JkcyhjbSwgZG9jLnNlbC5wcmltYXJ5KCkuaGVhZCwgXCJkaXZcIik7XHJcbiAgICAgICAgdmFyIHdyYXBPZmYgPSBkaXNwbGF5LndyYXBwZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksIGxpbmVPZmYgPSBkaXNwbGF5LmxpbmVEaXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICAgICAgcmVzdWx0LnRlVG9wID0gTWF0aC5tYXgoMCwgTWF0aC5taW4oZGlzcGxheS53cmFwcGVyLmNsaWVudEhlaWdodCAtIDEwLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlYWRQb3MudG9wICsgbGluZU9mZi50b3AgLSB3cmFwT2ZmLnRvcCkpO1xyXG4gICAgICAgIHJlc3VsdC50ZUxlZnQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbihkaXNwbGF5LndyYXBwZXIuY2xpZW50V2lkdGggLSAxMCxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaGVhZFBvcy5sZWZ0ICsgbGluZU9mZi5sZWZ0IC0gd3JhcE9mZi5sZWZ0KSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9LFxyXG5cclxuICAgIHNob3dTZWxlY3Rpb246IGZ1bmN0aW9uKGRyYXduKSB7XHJcbiAgICAgIHZhciBjbSA9IHRoaXMuY20sIGRpc3BsYXkgPSBjbS5kaXNwbGF5O1xyXG4gICAgICByZW1vdmVDaGlsZHJlbkFuZEFkZChkaXNwbGF5LmN1cnNvckRpdiwgZHJhd24uY3Vyc29ycyk7XHJcbiAgICAgIHJlbW92ZUNoaWxkcmVuQW5kQWRkKGRpc3BsYXkuc2VsZWN0aW9uRGl2LCBkcmF3bi5zZWxlY3Rpb24pO1xyXG4gICAgICBpZiAoZHJhd24udGVUb3AgIT0gbnVsbCkge1xyXG4gICAgICAgIHRoaXMud3JhcHBlci5zdHlsZS50b3AgPSBkcmF3bi50ZVRvcCArIFwicHhcIjtcclxuICAgICAgICB0aGlzLndyYXBwZXIuc3R5bGUubGVmdCA9IGRyYXduLnRlTGVmdCArIFwicHhcIjtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvLyBSZXNldCB0aGUgaW5wdXQgdG8gY29ycmVzcG9uZCB0byB0aGUgc2VsZWN0aW9uIChvciB0byBiZSBlbXB0eSxcclxuICAgIC8vIHdoZW4gbm90IHR5cGluZyBhbmQgbm90aGluZyBpcyBzZWxlY3RlZClcclxuICAgIHJlc2V0OiBmdW5jdGlvbih0eXBpbmcpIHtcclxuICAgICAgaWYgKHRoaXMuY29udGV4dE1lbnVQZW5kaW5nKSByZXR1cm47XHJcbiAgICAgIHZhciBtaW5pbWFsLCBzZWxlY3RlZCwgY20gPSB0aGlzLmNtLCBkb2MgPSBjbS5kb2M7XHJcbiAgICAgIGlmIChjbS5zb21ldGhpbmdTZWxlY3RlZCgpKSB7XHJcbiAgICAgICAgdGhpcy5wcmV2SW5wdXQgPSBcIlwiO1xyXG4gICAgICAgIHZhciByYW5nZSA9IGRvYy5zZWwucHJpbWFyeSgpO1xyXG4gICAgICAgIG1pbmltYWwgPSBoYXNDb3B5RXZlbnQgJiZcclxuICAgICAgICAgIChyYW5nZS50bygpLmxpbmUgLSByYW5nZS5mcm9tKCkubGluZSA+IDEwMCB8fCAoc2VsZWN0ZWQgPSBjbS5nZXRTZWxlY3Rpb24oKSkubGVuZ3RoID4gMTAwMCk7XHJcbiAgICAgICAgdmFyIGNvbnRlbnQgPSBtaW5pbWFsID8gXCItXCIgOiBzZWxlY3RlZCB8fCBjbS5nZXRTZWxlY3Rpb24oKTtcclxuICAgICAgICB0aGlzLnRleHRhcmVhLnZhbHVlID0gY29udGVudDtcclxuICAgICAgICBpZiAoY20uc3RhdGUuZm9jdXNlZCkgc2VsZWN0SW5wdXQodGhpcy50ZXh0YXJlYSk7XHJcbiAgICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPj0gOSkgdGhpcy5oYXNTZWxlY3Rpb24gPSBjb250ZW50O1xyXG4gICAgICB9IGVsc2UgaWYgKCF0eXBpbmcpIHtcclxuICAgICAgICB0aGlzLnByZXZJbnB1dCA9IHRoaXMudGV4dGFyZWEudmFsdWUgPSBcIlwiO1xyXG4gICAgICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uID49IDkpIHRoaXMuaGFzU2VsZWN0aW9uID0gbnVsbDtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLmluYWNjdXJhdGVTZWxlY3Rpb24gPSBtaW5pbWFsO1xyXG4gICAgfSxcclxuXHJcbiAgICBnZXRGaWVsZDogZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzLnRleHRhcmVhOyB9LFxyXG5cclxuICAgIHN1cHBvcnRzVG91Y2g6IGZ1bmN0aW9uKCkgeyByZXR1cm4gZmFsc2U7IH0sXHJcblxyXG4gICAgZm9jdXM6IGZ1bmN0aW9uKCkge1xyXG4gICAgICBpZiAodGhpcy5jbS5vcHRpb25zLnJlYWRPbmx5ICE9IFwibm9jdXJzb3JcIiAmJiAoIW1vYmlsZSB8fCBhY3RpdmVFbHQoKSAhPSB0aGlzLnRleHRhcmVhKSkge1xyXG4gICAgICAgIHRyeSB7IHRoaXMudGV4dGFyZWEuZm9jdXMoKTsgfVxyXG4gICAgICAgIGNhdGNoIChlKSB7fSAvLyBJRTggd2lsbCB0aHJvdyBpZiB0aGUgdGV4dGFyZWEgaXMgZGlzcGxheTogbm9uZSBvciBub3QgaW4gRE9NXHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgYmx1cjogZnVuY3Rpb24oKSB7IHRoaXMudGV4dGFyZWEuYmx1cigpOyB9LFxyXG5cclxuICAgIHJlc2V0UG9zaXRpb246IGZ1bmN0aW9uKCkge1xyXG4gICAgICB0aGlzLndyYXBwZXIuc3R5bGUudG9wID0gdGhpcy53cmFwcGVyLnN0eWxlLmxlZnQgPSAwO1xyXG4gICAgfSxcclxuXHJcbiAgICByZWNlaXZlZEZvY3VzOiBmdW5jdGlvbigpIHsgdGhpcy5zbG93UG9sbCgpOyB9LFxyXG5cclxuICAgIC8vIFBvbGwgZm9yIGlucHV0IGNoYW5nZXMsIHVzaW5nIHRoZSBub3JtYWwgcmF0ZSBvZiBwb2xsaW5nLiBUaGlzXHJcbiAgICAvLyBydW5zIGFzIGxvbmcgYXMgdGhlIGVkaXRvciBpcyBmb2N1c2VkLlxyXG4gICAgc2xvd1BvbGw6IGZ1bmN0aW9uKCkge1xyXG4gICAgICB2YXIgaW5wdXQgPSB0aGlzO1xyXG4gICAgICBpZiAoaW5wdXQucG9sbGluZ0Zhc3QpIHJldHVybjtcclxuICAgICAgaW5wdXQucG9sbGluZy5zZXQodGhpcy5jbS5vcHRpb25zLnBvbGxJbnRlcnZhbCwgZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgaW5wdXQucG9sbCgpO1xyXG4gICAgICAgIGlmIChpbnB1dC5jbS5zdGF0ZS5mb2N1c2VkKSBpbnB1dC5zbG93UG9sbCgpO1xyXG4gICAgICB9KTtcclxuICAgIH0sXHJcblxyXG4gICAgLy8gV2hlbiBhbiBldmVudCBoYXMganVzdCBjb21lIGluIHRoYXQgaXMgbGlrZWx5IHRvIGFkZCBvciBjaGFuZ2VcclxuICAgIC8vIHNvbWV0aGluZyBpbiB0aGUgaW5wdXQgdGV4dGFyZWEsIHdlIHBvbGwgZmFzdGVyLCB0byBlbnN1cmUgdGhhdFxyXG4gICAgLy8gdGhlIGNoYW5nZSBhcHBlYXJzIG9uIHRoZSBzY3JlZW4gcXVpY2tseS5cclxuICAgIGZhc3RQb2xsOiBmdW5jdGlvbigpIHtcclxuICAgICAgdmFyIG1pc3NlZCA9IGZhbHNlLCBpbnB1dCA9IHRoaXM7XHJcbiAgICAgIGlucHV0LnBvbGxpbmdGYXN0ID0gdHJ1ZTtcclxuICAgICAgZnVuY3Rpb24gcCgpIHtcclxuICAgICAgICB2YXIgY2hhbmdlZCA9IGlucHV0LnBvbGwoKTtcclxuICAgICAgICBpZiAoIWNoYW5nZWQgJiYgIW1pc3NlZCkge21pc3NlZCA9IHRydWU7IGlucHV0LnBvbGxpbmcuc2V0KDYwLCBwKTt9XHJcbiAgICAgICAgZWxzZSB7aW5wdXQucG9sbGluZ0Zhc3QgPSBmYWxzZTsgaW5wdXQuc2xvd1BvbGwoKTt9XHJcbiAgICAgIH1cclxuICAgICAgaW5wdXQucG9sbGluZy5zZXQoMjAsIHApO1xyXG4gICAgfSxcclxuXHJcbiAgICAvLyBSZWFkIGlucHV0IGZyb20gdGhlIHRleHRhcmVhLCBhbmQgdXBkYXRlIHRoZSBkb2N1bWVudCB0byBtYXRjaC5cclxuICAgIC8vIFdoZW4gc29tZXRoaW5nIGlzIHNlbGVjdGVkLCBpdCBpcyBwcmVzZW50IGluIHRoZSB0ZXh0YXJlYSwgYW5kXHJcbiAgICAvLyBzZWxlY3RlZCAodW5sZXNzIGl0IGlzIGh1Z2UsIGluIHdoaWNoIGNhc2UgYSBwbGFjZWhvbGRlciBpc1xyXG4gICAgLy8gdXNlZCkuIFdoZW4gbm90aGluZyBpcyBzZWxlY3RlZCwgdGhlIGN1cnNvciBzaXRzIGFmdGVyIHByZXZpb3VzbHlcclxuICAgIC8vIHNlZW4gdGV4dCAoY2FuIGJlIGVtcHR5KSwgd2hpY2ggaXMgc3RvcmVkIGluIHByZXZJbnB1dCAod2UgbXVzdFxyXG4gICAgLy8gbm90IHJlc2V0IHRoZSB0ZXh0YXJlYSB3aGVuIHR5cGluZywgYmVjYXVzZSB0aGF0IGJyZWFrcyBJTUUpLlxyXG4gICAgcG9sbDogZnVuY3Rpb24oKSB7XHJcbiAgICAgIHZhciBjbSA9IHRoaXMuY20sIGlucHV0ID0gdGhpcy50ZXh0YXJlYSwgcHJldklucHV0ID0gdGhpcy5wcmV2SW5wdXQ7XHJcbiAgICAgIC8vIFNpbmNlIHRoaXMgaXMgY2FsbGVkIGEgKmxvdCosIHRyeSB0byBiYWlsIG91dCBhcyBjaGVhcGx5IGFzXHJcbiAgICAgIC8vIHBvc3NpYmxlIHdoZW4gaXQgaXMgY2xlYXIgdGhhdCBub3RoaW5nIGhhcHBlbmVkLiBoYXNTZWxlY3Rpb25cclxuICAgICAgLy8gd2lsbCBiZSB0aGUgY2FzZSB3aGVuIHRoZXJlIGlzIGEgbG90IG9mIHRleHQgaW4gdGhlIHRleHRhcmVhLFxyXG4gICAgICAvLyBpbiB3aGljaCBjYXNlIHJlYWRpbmcgaXRzIHZhbHVlIHdvdWxkIGJlIGV4cGVuc2l2ZS5cclxuICAgICAgaWYgKHRoaXMuY29udGV4dE1lbnVQZW5kaW5nIHx8ICFjbS5zdGF0ZS5mb2N1c2VkIHx8XHJcbiAgICAgICAgICAoaGFzU2VsZWN0aW9uKGlucHV0KSAmJiAhcHJldklucHV0ICYmICF0aGlzLmNvbXBvc2luZykgfHxcclxuICAgICAgICAgIGlzUmVhZE9ubHkoY20pIHx8IGNtLm9wdGlvbnMuZGlzYWJsZUlucHV0IHx8IGNtLnN0YXRlLmtleVNlcSlcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcblxyXG4gICAgICB2YXIgdGV4dCA9IGlucHV0LnZhbHVlO1xyXG4gICAgICAvLyBJZiBub3RoaW5nIGNoYW5nZWQsIGJhaWwuXHJcbiAgICAgIGlmICh0ZXh0ID09IHByZXZJbnB1dCAmJiAhY20uc29tZXRoaW5nU2VsZWN0ZWQoKSkgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAvLyBXb3JrIGFyb3VuZCBub25zZW5zaWNhbCBzZWxlY3Rpb24gcmVzZXR0aW5nIGluIElFOS8xMCwgYW5kXHJcbiAgICAgIC8vIGluZXhwbGljYWJsZSBhcHBlYXJhbmNlIG9mIHByaXZhdGUgYXJlYSB1bmljb2RlIGNoYXJhY3RlcnMgb25cclxuICAgICAgLy8gc29tZSBrZXkgY29tYm9zIGluIE1hYyAoIzI2ODkpLlxyXG4gICAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA+PSA5ICYmIHRoaXMuaGFzU2VsZWN0aW9uID09PSB0ZXh0IHx8XHJcbiAgICAgICAgICBtYWMgJiYgL1tcXHVmNzAwLVxcdWY3ZmZdLy50ZXN0KHRleHQpKSB7XHJcbiAgICAgICAgY20uZGlzcGxheS5pbnB1dC5yZXNldCgpO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGNtLmRvYy5zZWwgPT0gY20uZGlzcGxheS5zZWxGb3JDb250ZXh0TWVudSkge1xyXG4gICAgICAgIHZhciBmaXJzdCA9IHRleHQuY2hhckNvZGVBdCgwKTtcclxuICAgICAgICBpZiAoZmlyc3QgPT0gMHgyMDBiICYmICFwcmV2SW5wdXQpIHByZXZJbnB1dCA9IFwiXFx1MjAwYlwiO1xyXG4gICAgICAgIGlmIChmaXJzdCA9PSAweDIxZGEpIHsgdGhpcy5yZXNldCgpOyByZXR1cm4gdGhpcy5jbS5leGVjQ29tbWFuZChcInVuZG9cIik7IH1cclxuICAgICAgfVxyXG4gICAgICAvLyBGaW5kIHRoZSBwYXJ0IG9mIHRoZSBpbnB1dCB0aGF0IGlzIGFjdHVhbGx5IG5ld1xyXG4gICAgICB2YXIgc2FtZSA9IDAsIGwgPSBNYXRoLm1pbihwcmV2SW5wdXQubGVuZ3RoLCB0ZXh0Lmxlbmd0aCk7XHJcbiAgICAgIHdoaWxlIChzYW1lIDwgbCAmJiBwcmV2SW5wdXQuY2hhckNvZGVBdChzYW1lKSA9PSB0ZXh0LmNoYXJDb2RlQXQoc2FtZSkpICsrc2FtZTtcclxuXHJcbiAgICAgIHZhciBzZWxmID0gdGhpcztcclxuICAgICAgcnVuSW5PcChjbSwgZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgYXBwbHlUZXh0SW5wdXQoY20sIHRleHQuc2xpY2Uoc2FtZSksIHByZXZJbnB1dC5sZW5ndGggLSBzYW1lLFxyXG4gICAgICAgICAgICAgICAgICAgICAgIG51bGwsIHNlbGYuY29tcG9zaW5nID8gXCIqY29tcG9zZVwiIDogbnVsbCk7XHJcblxyXG4gICAgICAgIC8vIERvbid0IGxlYXZlIGxvbmcgdGV4dCBpbiB0aGUgdGV4dGFyZWEsIHNpbmNlIGl0IG1ha2VzIGZ1cnRoZXIgcG9sbGluZyBzbG93XHJcbiAgICAgICAgaWYgKHRleHQubGVuZ3RoID4gMTAwMCB8fCB0ZXh0LmluZGV4T2YoXCJcXG5cIikgPiAtMSkgaW5wdXQudmFsdWUgPSBzZWxmLnByZXZJbnB1dCA9IFwiXCI7XHJcbiAgICAgICAgZWxzZSBzZWxmLnByZXZJbnB1dCA9IHRleHQ7XHJcblxyXG4gICAgICAgIGlmIChzZWxmLmNvbXBvc2luZykge1xyXG4gICAgICAgICAgc2VsZi5jb21wb3NpbmcucmFuZ2UuY2xlYXIoKTtcclxuICAgICAgICAgIHNlbGYuY29tcG9zaW5nLnJhbmdlID0gY20ubWFya1RleHQoc2VsZi5jb21wb3Npbmcuc3RhcnQsIGNtLmdldEN1cnNvcihcInRvXCIpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7Y2xhc3NOYW1lOiBcIkNvZGVNaXJyb3ItY29tcG9zaW5nXCJ9KTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0sXHJcblxyXG4gICAgZW5zdXJlUG9sbGVkOiBmdW5jdGlvbigpIHtcclxuICAgICAgaWYgKHRoaXMucG9sbGluZ0Zhc3QgJiYgdGhpcy5wb2xsKCkpIHRoaXMucG9sbGluZ0Zhc3QgPSBmYWxzZTtcclxuICAgIH0sXHJcblxyXG4gICAgb25LZXlQcmVzczogZnVuY3Rpb24oKSB7XHJcbiAgICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uID49IDkpIHRoaXMuaGFzU2VsZWN0aW9uID0gbnVsbDtcclxuICAgICAgdGhpcy5mYXN0UG9sbCgpO1xyXG4gICAgfSxcclxuXHJcbiAgICBvbkNvbnRleHRNZW51OiBmdW5jdGlvbihlKSB7XHJcbiAgICAgIHZhciBpbnB1dCA9IHRoaXMsIGNtID0gaW5wdXQuY20sIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCB0ZSA9IGlucHV0LnRleHRhcmVhO1xyXG4gICAgICB2YXIgcG9zID0gcG9zRnJvbU1vdXNlKGNtLCBlKSwgc2Nyb2xsUG9zID0gZGlzcGxheS5zY3JvbGxlci5zY3JvbGxUb3A7XHJcbiAgICAgIGlmICghcG9zIHx8IHByZXN0bykgcmV0dXJuOyAvLyBPcGVyYSBpcyBkaWZmaWN1bHQuXHJcblxyXG4gICAgICAvLyBSZXNldCB0aGUgY3VycmVudCB0ZXh0IHNlbGVjdGlvbiBvbmx5IGlmIHRoZSBjbGljayBpcyBkb25lIG91dHNpZGUgb2YgdGhlIHNlbGVjdGlvblxyXG4gICAgICAvLyBhbmQgJ3Jlc2V0U2VsZWN0aW9uT25Db250ZXh0TWVudScgb3B0aW9uIGlzIHRydWUuXHJcbiAgICAgIHZhciByZXNldCA9IGNtLm9wdGlvbnMucmVzZXRTZWxlY3Rpb25PbkNvbnRleHRNZW51O1xyXG4gICAgICBpZiAocmVzZXQgJiYgY20uZG9jLnNlbC5jb250YWlucyhwb3MpID09IC0xKVxyXG4gICAgICAgIG9wZXJhdGlvbihjbSwgc2V0U2VsZWN0aW9uKShjbS5kb2MsIHNpbXBsZVNlbGVjdGlvbihwb3MpLCBzZWxfZG9udFNjcm9sbCk7XHJcblxyXG4gICAgICB2YXIgb2xkQ1NTID0gdGUuc3R5bGUuY3NzVGV4dDtcclxuICAgICAgaW5wdXQud3JhcHBlci5zdHlsZS5wb3NpdGlvbiA9IFwiYWJzb2x1dGVcIjtcclxuICAgICAgdGUuc3R5bGUuY3NzVGV4dCA9IFwicG9zaXRpb246IGZpeGVkOyB3aWR0aDogMzBweDsgaGVpZ2h0OiAzMHB4OyB0b3A6IFwiICsgKGUuY2xpZW50WSAtIDUpICtcclxuICAgICAgICBcInB4OyBsZWZ0OiBcIiArIChlLmNsaWVudFggLSA1KSArIFwicHg7IHotaW5kZXg6IDEwMDA7IGJhY2tncm91bmQ6IFwiICtcclxuICAgICAgICAoaWUgPyBcInJnYmEoMjU1LCAyNTUsIDI1NSwgLjA1KVwiIDogXCJ0cmFuc3BhcmVudFwiKSArXHJcbiAgICAgICAgXCI7IG91dGxpbmU6IG5vbmU7IGJvcmRlci13aWR0aDogMDsgb3V0bGluZTogbm9uZTsgb3ZlcmZsb3c6IGhpZGRlbjsgb3BhY2l0eTogLjA1OyBmaWx0ZXI6IGFscGhhKG9wYWNpdHk9NSk7XCI7XHJcbiAgICAgIGlmICh3ZWJraXQpIHZhciBvbGRTY3JvbGxZID0gd2luZG93LnNjcm9sbFk7IC8vIFdvcmsgYXJvdW5kIENocm9tZSBpc3N1ZSAoIzI3MTIpXHJcbiAgICAgIGRpc3BsYXkuaW5wdXQuZm9jdXMoKTtcclxuICAgICAgaWYgKHdlYmtpdCkgd2luZG93LnNjcm9sbFRvKG51bGwsIG9sZFNjcm9sbFkpO1xyXG4gICAgICBkaXNwbGF5LmlucHV0LnJlc2V0KCk7XHJcbiAgICAgIC8vIEFkZHMgXCJTZWxlY3QgYWxsXCIgdG8gY29udGV4dCBtZW51IGluIEZGXHJcbiAgICAgIGlmICghY20uc29tZXRoaW5nU2VsZWN0ZWQoKSkgdGUudmFsdWUgPSBpbnB1dC5wcmV2SW5wdXQgPSBcIiBcIjtcclxuICAgICAgaW5wdXQuY29udGV4dE1lbnVQZW5kaW5nID0gdHJ1ZTtcclxuICAgICAgZGlzcGxheS5zZWxGb3JDb250ZXh0TWVudSA9IGNtLmRvYy5zZWw7XHJcbiAgICAgIGNsZWFyVGltZW91dChkaXNwbGF5LmRldGVjdGluZ1NlbGVjdEFsbCk7XHJcblxyXG4gICAgICAvLyBTZWxlY3QtYWxsIHdpbGwgYmUgZ3JleWVkIG91dCBpZiB0aGVyZSdzIG5vdGhpbmcgdG8gc2VsZWN0LCBzb1xyXG4gICAgICAvLyB0aGlzIGFkZHMgYSB6ZXJvLXdpZHRoIHNwYWNlIHNvIHRoYXQgd2UgY2FuIGxhdGVyIGNoZWNrIHdoZXRoZXJcclxuICAgICAgLy8gaXQgZ290IHNlbGVjdGVkLlxyXG4gICAgICBmdW5jdGlvbiBwcmVwYXJlU2VsZWN0QWxsSGFjaygpIHtcclxuICAgICAgICBpZiAodGUuc2VsZWN0aW9uU3RhcnQgIT0gbnVsbCkge1xyXG4gICAgICAgICAgdmFyIHNlbGVjdGVkID0gY20uc29tZXRoaW5nU2VsZWN0ZWQoKTtcclxuICAgICAgICAgIHZhciBleHR2YWwgPSBcIlxcdTIwMGJcIiArIChzZWxlY3RlZCA/IHRlLnZhbHVlIDogXCJcIik7XHJcbiAgICAgICAgICB0ZS52YWx1ZSA9IFwiXFx1MjFkYVwiOyAvLyBVc2VkIHRvIGNhdGNoIGNvbnRleHQtbWVudSB1bmRvXHJcbiAgICAgICAgICB0ZS52YWx1ZSA9IGV4dHZhbDtcclxuICAgICAgICAgIGlucHV0LnByZXZJbnB1dCA9IHNlbGVjdGVkID8gXCJcIiA6IFwiXFx1MjAwYlwiO1xyXG4gICAgICAgICAgdGUuc2VsZWN0aW9uU3RhcnQgPSAxOyB0ZS5zZWxlY3Rpb25FbmQgPSBleHR2YWwubGVuZ3RoO1xyXG4gICAgICAgICAgLy8gUmUtc2V0IHRoaXMsIGluIGNhc2Ugc29tZSBvdGhlciBoYW5kbGVyIHRvdWNoZWQgdGhlXHJcbiAgICAgICAgICAvLyBzZWxlY3Rpb24gaW4gdGhlIG1lYW50aW1lLlxyXG4gICAgICAgICAgZGlzcGxheS5zZWxGb3JDb250ZXh0TWVudSA9IGNtLmRvYy5zZWw7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGZ1bmN0aW9uIHJlaGlkZSgpIHtcclxuICAgICAgICBpbnB1dC5jb250ZXh0TWVudVBlbmRpbmcgPSBmYWxzZTtcclxuICAgICAgICBpbnB1dC53cmFwcGVyLnN0eWxlLnBvc2l0aW9uID0gXCJyZWxhdGl2ZVwiO1xyXG4gICAgICAgIHRlLnN0eWxlLmNzc1RleHQgPSBvbGRDU1M7XHJcbiAgICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPCA5KSBkaXNwbGF5LnNjcm9sbGJhcnMuc2V0U2Nyb2xsVG9wKGRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsVG9wID0gc2Nyb2xsUG9zKTtcclxuXHJcbiAgICAgICAgLy8gVHJ5IHRvIGRldGVjdCB0aGUgdXNlciBjaG9vc2luZyBzZWxlY3QtYWxsXHJcbiAgICAgICAgaWYgKHRlLnNlbGVjdGlvblN0YXJ0ICE9IG51bGwpIHtcclxuICAgICAgICAgIGlmICghaWUgfHwgKGllICYmIGllX3ZlcnNpb24gPCA5KSkgcHJlcGFyZVNlbGVjdEFsbEhhY2soKTtcclxuICAgICAgICAgIHZhciBpID0gMCwgcG9sbCA9IGZ1bmN0aW9uKCkge1xyXG4gICAgICAgICAgICBpZiAoZGlzcGxheS5zZWxGb3JDb250ZXh0TWVudSA9PSBjbS5kb2Muc2VsICYmIHRlLnNlbGVjdGlvblN0YXJ0ID09IDAgJiZcclxuICAgICAgICAgICAgICAgIHRlLnNlbGVjdGlvbkVuZCA+IDAgJiYgaW5wdXQucHJldklucHV0ID09IFwiXFx1MjAwYlwiKVxyXG4gICAgICAgICAgICAgIG9wZXJhdGlvbihjbSwgY29tbWFuZHMuc2VsZWN0QWxsKShjbSk7XHJcbiAgICAgICAgICAgIGVsc2UgaWYgKGkrKyA8IDEwKSBkaXNwbGF5LmRldGVjdGluZ1NlbGVjdEFsbCA9IHNldFRpbWVvdXQocG9sbCwgNTAwKTtcclxuICAgICAgICAgICAgZWxzZSBkaXNwbGF5LmlucHV0LnJlc2V0KCk7XHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgICAgZGlzcGxheS5kZXRlY3RpbmdTZWxlY3RBbGwgPSBzZXRUaW1lb3V0KHBvbGwsIDIwMCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA+PSA5KSBwcmVwYXJlU2VsZWN0QWxsSGFjaygpO1xyXG4gICAgICBpZiAoY2FwdHVyZVJpZ2h0Q2xpY2spIHtcclxuICAgICAgICBlX3N0b3AoZSk7XHJcbiAgICAgICAgdmFyIG1vdXNldXAgPSBmdW5jdGlvbigpIHtcclxuICAgICAgICAgIG9mZih3aW5kb3csIFwibW91c2V1cFwiLCBtb3VzZXVwKTtcclxuICAgICAgICAgIHNldFRpbWVvdXQocmVoaWRlLCAyMCk7XHJcbiAgICAgICAgfTtcclxuICAgICAgICBvbih3aW5kb3csIFwibW91c2V1cFwiLCBtb3VzZXVwKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzZXRUaW1lb3V0KHJlaGlkZSwgNTApO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIHJlYWRPbmx5Q2hhbmdlZDogZnVuY3Rpb24odmFsKSB7XHJcbiAgICAgIGlmICghdmFsKSB0aGlzLnJlc2V0KCk7XHJcbiAgICB9LFxyXG5cclxuICAgIHNldFVuZWRpdGFibGU6IG5vdGhpbmcsXHJcblxyXG4gICAgbmVlZHNDb250ZW50QXR0cmlidXRlOiBmYWxzZVxyXG4gIH0sIFRleHRhcmVhSW5wdXQucHJvdG90eXBlKTtcclxuXHJcbiAgLy8gQ09OVEVOVEVESVRBQkxFIElOUFVUIFNUWUxFXHJcblxyXG4gIGZ1bmN0aW9uIENvbnRlbnRFZGl0YWJsZUlucHV0KGNtKSB7XHJcbiAgICB0aGlzLmNtID0gY207XHJcbiAgICB0aGlzLmxhc3RBbmNob3JOb2RlID0gdGhpcy5sYXN0QW5jaG9yT2Zmc2V0ID0gdGhpcy5sYXN0Rm9jdXNOb2RlID0gdGhpcy5sYXN0Rm9jdXNPZmZzZXQgPSBudWxsO1xyXG4gICAgdGhpcy5wb2xsaW5nID0gbmV3IERlbGF5ZWQoKTtcclxuICAgIHRoaXMuZ3JhY2VQZXJpb2QgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIENvbnRlbnRFZGl0YWJsZUlucHV0LnByb3RvdHlwZSA9IGNvcHlPYmooe1xyXG4gICAgaW5pdDogZnVuY3Rpb24oZGlzcGxheSkge1xyXG4gICAgICB2YXIgaW5wdXQgPSB0aGlzLCBjbSA9IGlucHV0LmNtO1xyXG4gICAgICB2YXIgZGl2ID0gaW5wdXQuZGl2ID0gZGlzcGxheS5saW5lRGl2O1xyXG4gICAgICBkaXNhYmxlQnJvd3Nlck1hZ2ljKGRpdik7XHJcblxyXG4gICAgICBvbihkaXYsIFwicGFzdGVcIiwgZnVuY3Rpb24oZSkgeyBoYW5kbGVQYXN0ZShlLCBjbSk7IH0pXHJcblxyXG4gICAgICBvbihkaXYsIFwiY29tcG9zaXRpb25zdGFydFwiLCBmdW5jdGlvbihlKSB7XHJcbiAgICAgICAgdmFyIGRhdGEgPSBlLmRhdGE7XHJcbiAgICAgICAgaW5wdXQuY29tcG9zaW5nID0ge3NlbDogY20uZG9jLnNlbCwgZGF0YTogZGF0YSwgc3RhcnREYXRhOiBkYXRhfTtcclxuICAgICAgICBpZiAoIWRhdGEpIHJldHVybjtcclxuICAgICAgICB2YXIgcHJpbSA9IGNtLmRvYy5zZWwucHJpbWFyeSgpO1xyXG4gICAgICAgIHZhciBsaW5lID0gY20uZ2V0TGluZShwcmltLmhlYWQubGluZSk7XHJcbiAgICAgICAgdmFyIGZvdW5kID0gbGluZS5pbmRleE9mKGRhdGEsIE1hdGgubWF4KDAsIHByaW0uaGVhZC5jaCAtIGRhdGEubGVuZ3RoKSk7XHJcbiAgICAgICAgaWYgKGZvdW5kID4gLTEgJiYgZm91bmQgPD0gcHJpbS5oZWFkLmNoKVxyXG4gICAgICAgICAgaW5wdXQuY29tcG9zaW5nLnNlbCA9IHNpbXBsZVNlbGVjdGlvbihQb3MocHJpbS5oZWFkLmxpbmUsIGZvdW5kKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUG9zKHByaW0uaGVhZC5saW5lLCBmb3VuZCArIGRhdGEubGVuZ3RoKSk7XHJcbiAgICAgIH0pO1xyXG4gICAgICBvbihkaXYsIFwiY29tcG9zaXRpb251cGRhdGVcIiwgZnVuY3Rpb24oZSkge1xyXG4gICAgICAgIGlucHV0LmNvbXBvc2luZy5kYXRhID0gZS5kYXRhO1xyXG4gICAgICB9KTtcclxuICAgICAgb24oZGl2LCBcImNvbXBvc2l0aW9uZW5kXCIsIGZ1bmN0aW9uKGUpIHtcclxuICAgICAgICB2YXIgb3VycyA9IGlucHV0LmNvbXBvc2luZztcclxuICAgICAgICBpZiAoIW91cnMpIHJldHVybjtcclxuICAgICAgICBpZiAoZS5kYXRhICE9IG91cnMuc3RhcnREYXRhICYmICEvXFx1MjAwYi8udGVzdChlLmRhdGEpKVxyXG4gICAgICAgICAgb3Vycy5kYXRhID0gZS5kYXRhO1xyXG4gICAgICAgIC8vIE5lZWQgYSBzbWFsbCBkZWxheSB0byBwcmV2ZW50IG90aGVyIGNvZGUgKGlucHV0IGV2ZW50LFxyXG4gICAgICAgIC8vIHNlbGVjdGlvbiBwb2xsaW5nKSBmcm9tIGRvaW5nIGRhbWFnZSB3aGVuIGZpcmVkIHJpZ2h0IGFmdGVyXHJcbiAgICAgICAgLy8gY29tcG9zaXRpb25lbmQuXHJcbiAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcclxuICAgICAgICAgIGlmICghb3Vycy5oYW5kbGVkKVxyXG4gICAgICAgICAgICBpbnB1dC5hcHBseUNvbXBvc2l0aW9uKG91cnMpO1xyXG4gICAgICAgICAgaWYgKGlucHV0LmNvbXBvc2luZyA9PSBvdXJzKVxyXG4gICAgICAgICAgICBpbnB1dC5jb21wb3NpbmcgPSBudWxsO1xyXG4gICAgICAgIH0sIDUwKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBvbihkaXYsIFwidG91Y2hzdGFydFwiLCBmdW5jdGlvbigpIHtcclxuICAgICAgICBpbnB1dC5mb3JjZUNvbXBvc2l0aW9uRW5kKCk7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgb24oZGl2LCBcImlucHV0XCIsIGZ1bmN0aW9uKCkge1xyXG4gICAgICAgIGlmIChpbnB1dC5jb21wb3NpbmcpIHJldHVybjtcclxuICAgICAgICBpZiAoaXNSZWFkT25seShjbSkgfHwgIWlucHV0LnBvbGxDb250ZW50KCkpXHJcbiAgICAgICAgICBydW5Jbk9wKGlucHV0LmNtLCBmdW5jdGlvbigpIHtyZWdDaGFuZ2UoY20pO30pO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGZ1bmN0aW9uIG9uQ29weUN1dChlKSB7XHJcbiAgICAgICAgaWYgKGNtLnNvbWV0aGluZ1NlbGVjdGVkKCkpIHtcclxuICAgICAgICAgIGxhc3RDb3BpZWQgPSBjbS5nZXRTZWxlY3Rpb25zKCk7XHJcbiAgICAgICAgICBpZiAoZS50eXBlID09IFwiY3V0XCIpIGNtLnJlcGxhY2VTZWxlY3Rpb24oXCJcIiwgbnVsbCwgXCJjdXRcIik7XHJcbiAgICAgICAgfSBlbHNlIGlmICghY20ub3B0aW9ucy5saW5lV2lzZUNvcHlDdXQpIHtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdmFyIHJhbmdlcyA9IGNvcHlhYmxlUmFuZ2VzKGNtKTtcclxuICAgICAgICAgIGxhc3RDb3BpZWQgPSByYW5nZXMudGV4dDtcclxuICAgICAgICAgIGlmIChlLnR5cGUgPT0gXCJjdXRcIikge1xyXG4gICAgICAgICAgICBjbS5vcGVyYXRpb24oZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgICAgICAgY20uc2V0U2VsZWN0aW9ucyhyYW5nZXMucmFuZ2VzLCAwLCBzZWxfZG9udFNjcm9sbCk7XHJcbiAgICAgICAgICAgICAgY20ucmVwbGFjZVNlbGVjdGlvbihcIlwiLCBudWxsLCBcImN1dFwiKTtcclxuICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIC8vIGlPUyBleHBvc2VzIHRoZSBjbGlwYm9hcmQgQVBJLCBidXQgc2VlbXMgdG8gZGlzY2FyZCBjb250ZW50IGluc2VydGVkIGludG8gaXRcclxuICAgICAgICBpZiAoZS5jbGlwYm9hcmREYXRhICYmICFpb3MpIHtcclxuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICAgIGUuY2xpcGJvYXJkRGF0YS5jbGVhckRhdGEoKTtcclxuICAgICAgICAgIGUuY2xpcGJvYXJkRGF0YS5zZXREYXRhKFwidGV4dC9wbGFpblwiLCBsYXN0Q29waWVkLmpvaW4oXCJcXG5cIikpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBPbGQtZmFzaGlvbmVkIGJyaWVmbHktZm9jdXMtYS10ZXh0YXJlYSBoYWNrXHJcbiAgICAgICAgICB2YXIga2x1ZGdlID0gaGlkZGVuVGV4dGFyZWEoKSwgdGUgPSBrbHVkZ2UuZmlyc3RDaGlsZDtcclxuICAgICAgICAgIGNtLmRpc3BsYXkubGluZVNwYWNlLmluc2VydEJlZm9yZShrbHVkZ2UsIGNtLmRpc3BsYXkubGluZVNwYWNlLmZpcnN0Q2hpbGQpO1xyXG4gICAgICAgICAgdGUudmFsdWUgPSBsYXN0Q29waWVkLmpvaW4oXCJcXG5cIik7XHJcbiAgICAgICAgICB2YXIgaGFkRm9jdXMgPSBkb2N1bWVudC5hY3RpdmVFbGVtZW50O1xyXG4gICAgICAgICAgc2VsZWN0SW5wdXQodGUpO1xyXG4gICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcclxuICAgICAgICAgICAgY20uZGlzcGxheS5saW5lU3BhY2UucmVtb3ZlQ2hpbGQoa2x1ZGdlKTtcclxuICAgICAgICAgICAgaGFkRm9jdXMuZm9jdXMoKTtcclxuICAgICAgICAgIH0sIDUwKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgb24oZGl2LCBcImNvcHlcIiwgb25Db3B5Q3V0KTtcclxuICAgICAgb24oZGl2LCBcImN1dFwiLCBvbkNvcHlDdXQpO1xyXG4gICAgfSxcclxuXHJcbiAgICBwcmVwYXJlU2VsZWN0aW9uOiBmdW5jdGlvbigpIHtcclxuICAgICAgdmFyIHJlc3VsdCA9IHByZXBhcmVTZWxlY3Rpb24odGhpcy5jbSwgZmFsc2UpO1xyXG4gICAgICByZXN1bHQuZm9jdXMgPSB0aGlzLmNtLnN0YXRlLmZvY3VzZWQ7XHJcbiAgICAgIHJldHVybiByZXN1bHQ7XHJcbiAgICB9LFxyXG5cclxuICAgIHNob3dTZWxlY3Rpb246IGZ1bmN0aW9uKGluZm8pIHtcclxuICAgICAgaWYgKCFpbmZvIHx8ICF0aGlzLmNtLmRpc3BsYXkudmlldy5sZW5ndGgpIHJldHVybjtcclxuICAgICAgaWYgKGluZm8uZm9jdXMpIHRoaXMuc2hvd1ByaW1hcnlTZWxlY3Rpb24oKTtcclxuICAgICAgdGhpcy5zaG93TXVsdGlwbGVTZWxlY3Rpb25zKGluZm8pO1xyXG4gICAgfSxcclxuXHJcbiAgICBzaG93UHJpbWFyeVNlbGVjdGlvbjogZnVuY3Rpb24oKSB7XHJcbiAgICAgIHZhciBzZWwgPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCksIHByaW0gPSB0aGlzLmNtLmRvYy5zZWwucHJpbWFyeSgpO1xyXG4gICAgICB2YXIgY3VyQW5jaG9yID0gZG9tVG9Qb3ModGhpcy5jbSwgc2VsLmFuY2hvck5vZGUsIHNlbC5hbmNob3JPZmZzZXQpO1xyXG4gICAgICB2YXIgY3VyRm9jdXMgPSBkb21Ub1Bvcyh0aGlzLmNtLCBzZWwuZm9jdXNOb2RlLCBzZWwuZm9jdXNPZmZzZXQpO1xyXG4gICAgICBpZiAoY3VyQW5jaG9yICYmICFjdXJBbmNob3IuYmFkICYmIGN1ckZvY3VzICYmICFjdXJGb2N1cy5iYWQgJiZcclxuICAgICAgICAgIGNtcChtaW5Qb3MoY3VyQW5jaG9yLCBjdXJGb2N1cyksIHByaW0uZnJvbSgpKSA9PSAwICYmXHJcbiAgICAgICAgICBjbXAobWF4UG9zKGN1ckFuY2hvciwgY3VyRm9jdXMpLCBwcmltLnRvKCkpID09IDApXHJcbiAgICAgICAgcmV0dXJuO1xyXG5cclxuICAgICAgdmFyIHN0YXJ0ID0gcG9zVG9ET00odGhpcy5jbSwgcHJpbS5mcm9tKCkpO1xyXG4gICAgICB2YXIgZW5kID0gcG9zVG9ET00odGhpcy5jbSwgcHJpbS50bygpKTtcclxuICAgICAgaWYgKCFzdGFydCAmJiAhZW5kKSByZXR1cm47XHJcblxyXG4gICAgICB2YXIgdmlldyA9IHRoaXMuY20uZGlzcGxheS52aWV3O1xyXG4gICAgICB2YXIgb2xkID0gc2VsLnJhbmdlQ291bnQgJiYgc2VsLmdldFJhbmdlQXQoMCk7XHJcbiAgICAgIGlmICghc3RhcnQpIHtcclxuICAgICAgICBzdGFydCA9IHtub2RlOiB2aWV3WzBdLm1lYXN1cmUubWFwWzJdLCBvZmZzZXQ6IDB9O1xyXG4gICAgICB9IGVsc2UgaWYgKCFlbmQpIHsgLy8gRklYTUUgZGFuZ2Vyb3VzbHkgaGFja3lcclxuICAgICAgICB2YXIgbWVhc3VyZSA9IHZpZXdbdmlldy5sZW5ndGggLSAxXS5tZWFzdXJlO1xyXG4gICAgICAgIHZhciBtYXAgPSBtZWFzdXJlLm1hcHMgPyBtZWFzdXJlLm1hcHNbbWVhc3VyZS5tYXBzLmxlbmd0aCAtIDFdIDogbWVhc3VyZS5tYXA7XHJcbiAgICAgICAgZW5kID0ge25vZGU6IG1hcFttYXAubGVuZ3RoIC0gMV0sIG9mZnNldDogbWFwW21hcC5sZW5ndGggLSAyXSAtIG1hcFttYXAubGVuZ3RoIC0gM119O1xyXG4gICAgICB9XHJcblxyXG4gICAgICB0cnkgeyB2YXIgcm5nID0gcmFuZ2Uoc3RhcnQubm9kZSwgc3RhcnQub2Zmc2V0LCBlbmQub2Zmc2V0LCBlbmQubm9kZSk7IH1cclxuICAgICAgY2F0Y2goZSkge30gLy8gT3VyIG1vZGVsIG9mIHRoZSBET00gbWlnaHQgYmUgb3V0ZGF0ZWQsIGluIHdoaWNoIGNhc2UgdGhlIHJhbmdlIHdlIHRyeSB0byBzZXQgY2FuIGJlIGltcG9zc2libGVcclxuICAgICAgaWYgKHJuZykge1xyXG4gICAgICAgIHNlbC5yZW1vdmVBbGxSYW5nZXMoKTtcclxuICAgICAgICBzZWwuYWRkUmFuZ2Uocm5nKTtcclxuICAgICAgICBpZiAob2xkICYmIHNlbC5hbmNob3JOb2RlID09IG51bGwpIHNlbC5hZGRSYW5nZShvbGQpO1xyXG4gICAgICAgIGVsc2UgaWYgKGdlY2tvKSB0aGlzLnN0YXJ0R3JhY2VQZXJpb2QoKTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLnJlbWVtYmVyU2VsZWN0aW9uKCk7XHJcbiAgICB9LFxyXG5cclxuICAgIHN0YXJ0R3JhY2VQZXJpb2Q6IGZ1bmN0aW9uKCkge1xyXG4gICAgICB2YXIgaW5wdXQgPSB0aGlzO1xyXG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5ncmFjZVBlcmlvZCk7XHJcbiAgICAgIHRoaXMuZ3JhY2VQZXJpb2QgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xyXG4gICAgICAgIGlucHV0LmdyYWNlUGVyaW9kID0gZmFsc2U7XHJcbiAgICAgICAgaWYgKGlucHV0LnNlbGVjdGlvbkNoYW5nZWQoKSlcclxuICAgICAgICAgIGlucHV0LmNtLm9wZXJhdGlvbihmdW5jdGlvbigpIHsgaW5wdXQuY20uY3VyT3Auc2VsZWN0aW9uQ2hhbmdlZCA9IHRydWU7IH0pO1xyXG4gICAgICB9LCAyMCk7XHJcbiAgICB9LFxyXG5cclxuICAgIHNob3dNdWx0aXBsZVNlbGVjdGlvbnM6IGZ1bmN0aW9uKGluZm8pIHtcclxuICAgICAgcmVtb3ZlQ2hpbGRyZW5BbmRBZGQodGhpcy5jbS5kaXNwbGF5LmN1cnNvckRpdiwgaW5mby5jdXJzb3JzKTtcclxuICAgICAgcmVtb3ZlQ2hpbGRyZW5BbmRBZGQodGhpcy5jbS5kaXNwbGF5LnNlbGVjdGlvbkRpdiwgaW5mby5zZWxlY3Rpb24pO1xyXG4gICAgfSxcclxuXHJcbiAgICByZW1lbWJlclNlbGVjdGlvbjogZnVuY3Rpb24oKSB7XHJcbiAgICAgIHZhciBzZWwgPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7XHJcbiAgICAgIHRoaXMubGFzdEFuY2hvck5vZGUgPSBzZWwuYW5jaG9yTm9kZTsgdGhpcy5sYXN0QW5jaG9yT2Zmc2V0ID0gc2VsLmFuY2hvck9mZnNldDtcclxuICAgICAgdGhpcy5sYXN0Rm9jdXNOb2RlID0gc2VsLmZvY3VzTm9kZTsgdGhpcy5sYXN0Rm9jdXNPZmZzZXQgPSBzZWwuZm9jdXNPZmZzZXQ7XHJcbiAgICB9LFxyXG5cclxuICAgIHNlbGVjdGlvbkluRWRpdG9yOiBmdW5jdGlvbigpIHtcclxuICAgICAgdmFyIHNlbCA9IHdpbmRvdy5nZXRTZWxlY3Rpb24oKTtcclxuICAgICAgaWYgKCFzZWwucmFuZ2VDb3VudCkgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB2YXIgbm9kZSA9IHNlbC5nZXRSYW5nZUF0KDApLmNvbW1vbkFuY2VzdG9yQ29udGFpbmVyO1xyXG4gICAgICByZXR1cm4gY29udGFpbnModGhpcy5kaXYsIG5vZGUpO1xyXG4gICAgfSxcclxuXHJcbiAgICBmb2N1czogZnVuY3Rpb24oKSB7XHJcbiAgICAgIGlmICh0aGlzLmNtLm9wdGlvbnMucmVhZE9ubHkgIT0gXCJub2N1cnNvclwiKSB0aGlzLmRpdi5mb2N1cygpO1xyXG4gICAgfSxcclxuICAgIGJsdXI6IGZ1bmN0aW9uKCkgeyB0aGlzLmRpdi5ibHVyKCk7IH0sXHJcbiAgICBnZXRGaWVsZDogZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzLmRpdjsgfSxcclxuXHJcbiAgICBzdXBwb3J0c1RvdWNoOiBmdW5jdGlvbigpIHsgcmV0dXJuIHRydWU7IH0sXHJcblxyXG4gICAgcmVjZWl2ZWRGb2N1czogZnVuY3Rpb24oKSB7XHJcbiAgICAgIHZhciBpbnB1dCA9IHRoaXM7XHJcbiAgICAgIGlmICh0aGlzLnNlbGVjdGlvbkluRWRpdG9yKCkpXHJcbiAgICAgICAgdGhpcy5wb2xsU2VsZWN0aW9uKCk7XHJcbiAgICAgIGVsc2VcclxuICAgICAgICBydW5Jbk9wKHRoaXMuY20sIGZ1bmN0aW9uKCkgeyBpbnB1dC5jbS5jdXJPcC5zZWxlY3Rpb25DaGFuZ2VkID0gdHJ1ZTsgfSk7XHJcblxyXG4gICAgICBmdW5jdGlvbiBwb2xsKCkge1xyXG4gICAgICAgIGlmIChpbnB1dC5jbS5zdGF0ZS5mb2N1c2VkKSB7XHJcbiAgICAgICAgICBpbnB1dC5wb2xsU2VsZWN0aW9uKCk7XHJcbiAgICAgICAgICBpbnB1dC5wb2xsaW5nLnNldChpbnB1dC5jbS5vcHRpb25zLnBvbGxJbnRlcnZhbCwgcG9sbCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHRoaXMucG9sbGluZy5zZXQodGhpcy5jbS5vcHRpb25zLnBvbGxJbnRlcnZhbCwgcG9sbCk7XHJcbiAgICB9LFxyXG5cclxuICAgIHNlbGVjdGlvbkNoYW5nZWQ6IGZ1bmN0aW9uKCkge1xyXG4gICAgICB2YXIgc2VsID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xyXG4gICAgICByZXR1cm4gc2VsLmFuY2hvck5vZGUgIT0gdGhpcy5sYXN0QW5jaG9yTm9kZSB8fCBzZWwuYW5jaG9yT2Zmc2V0ICE9IHRoaXMubGFzdEFuY2hvck9mZnNldCB8fFxyXG4gICAgICAgIHNlbC5mb2N1c05vZGUgIT0gdGhpcy5sYXN0Rm9jdXNOb2RlIHx8IHNlbC5mb2N1c09mZnNldCAhPSB0aGlzLmxhc3RGb2N1c09mZnNldDtcclxuICAgIH0sXHJcblxyXG4gICAgcG9sbFNlbGVjdGlvbjogZnVuY3Rpb24oKSB7XHJcbiAgICAgIGlmICghdGhpcy5jb21wb3NpbmcgJiYgIXRoaXMuZ3JhY2VQZXJpb2QgJiYgdGhpcy5zZWxlY3Rpb25DaGFuZ2VkKCkpIHtcclxuICAgICAgICB2YXIgc2VsID0gd2luZG93LmdldFNlbGVjdGlvbigpLCBjbSA9IHRoaXMuY207XHJcbiAgICAgICAgdGhpcy5yZW1lbWJlclNlbGVjdGlvbigpO1xyXG4gICAgICAgIHZhciBhbmNob3IgPSBkb21Ub1BvcyhjbSwgc2VsLmFuY2hvck5vZGUsIHNlbC5hbmNob3JPZmZzZXQpO1xyXG4gICAgICAgIHZhciBoZWFkID0gZG9tVG9Qb3MoY20sIHNlbC5mb2N1c05vZGUsIHNlbC5mb2N1c09mZnNldCk7XHJcbiAgICAgICAgaWYgKGFuY2hvciAmJiBoZWFkKSBydW5Jbk9wKGNtLCBmdW5jdGlvbigpIHtcclxuICAgICAgICAgIHNldFNlbGVjdGlvbihjbS5kb2MsIHNpbXBsZVNlbGVjdGlvbihhbmNob3IsIGhlYWQpLCBzZWxfZG9udFNjcm9sbCk7XHJcbiAgICAgICAgICBpZiAoYW5jaG9yLmJhZCB8fCBoZWFkLmJhZCkgY20uY3VyT3Auc2VsZWN0aW9uQ2hhbmdlZCA9IHRydWU7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgcG9sbENvbnRlbnQ6IGZ1bmN0aW9uKCkge1xyXG4gICAgICB2YXIgY20gPSB0aGlzLmNtLCBkaXNwbGF5ID0gY20uZGlzcGxheSwgc2VsID0gY20uZG9jLnNlbC5wcmltYXJ5KCk7XHJcbiAgICAgIHZhciBmcm9tID0gc2VsLmZyb20oKSwgdG8gPSBzZWwudG8oKTtcclxuICAgICAgaWYgKGZyb20ubGluZSA8IGRpc3BsYXkudmlld0Zyb20gfHwgdG8ubGluZSA+IGRpc3BsYXkudmlld1RvIC0gMSkgcmV0dXJuIGZhbHNlO1xyXG5cclxuICAgICAgdmFyIGZyb21JbmRleDtcclxuICAgICAgaWYgKGZyb20ubGluZSA9PSBkaXNwbGF5LnZpZXdGcm9tIHx8IChmcm9tSW5kZXggPSBmaW5kVmlld0luZGV4KGNtLCBmcm9tLmxpbmUpKSA9PSAwKSB7XHJcbiAgICAgICAgdmFyIGZyb21MaW5lID0gbGluZU5vKGRpc3BsYXkudmlld1swXS5saW5lKTtcclxuICAgICAgICB2YXIgZnJvbU5vZGUgPSBkaXNwbGF5LnZpZXdbMF0ubm9kZTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB2YXIgZnJvbUxpbmUgPSBsaW5lTm8oZGlzcGxheS52aWV3W2Zyb21JbmRleF0ubGluZSk7XHJcbiAgICAgICAgdmFyIGZyb21Ob2RlID0gZGlzcGxheS52aWV3W2Zyb21JbmRleCAtIDFdLm5vZGUubmV4dFNpYmxpbmc7XHJcbiAgICAgIH1cclxuICAgICAgdmFyIHRvSW5kZXggPSBmaW5kVmlld0luZGV4KGNtLCB0by5saW5lKTtcclxuICAgICAgaWYgKHRvSW5kZXggPT0gZGlzcGxheS52aWV3Lmxlbmd0aCAtIDEpIHtcclxuICAgICAgICB2YXIgdG9MaW5lID0gZGlzcGxheS52aWV3VG8gLSAxO1xyXG4gICAgICAgIHZhciB0b05vZGUgPSBkaXNwbGF5LmxpbmVEaXYubGFzdENoaWxkO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHZhciB0b0xpbmUgPSBsaW5lTm8oZGlzcGxheS52aWV3W3RvSW5kZXggKyAxXS5saW5lKSAtIDE7XHJcbiAgICAgICAgdmFyIHRvTm9kZSA9IGRpc3BsYXkudmlld1t0b0luZGV4ICsgMV0ubm9kZS5wcmV2aW91c1NpYmxpbmc7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHZhciBuZXdUZXh0ID0gY20uZG9jLnNwbGl0TGluZXMoZG9tVGV4dEJldHdlZW4oY20sIGZyb21Ob2RlLCB0b05vZGUsIGZyb21MaW5lLCB0b0xpbmUpKTtcclxuICAgICAgdmFyIG9sZFRleHQgPSBnZXRCZXR3ZWVuKGNtLmRvYywgUG9zKGZyb21MaW5lLCAwKSwgUG9zKHRvTGluZSwgZ2V0TGluZShjbS5kb2MsIHRvTGluZSkudGV4dC5sZW5ndGgpKTtcclxuICAgICAgd2hpbGUgKG5ld1RleHQubGVuZ3RoID4gMSAmJiBvbGRUZXh0Lmxlbmd0aCA+IDEpIHtcclxuICAgICAgICBpZiAobHN0KG5ld1RleHQpID09IGxzdChvbGRUZXh0KSkgeyBuZXdUZXh0LnBvcCgpOyBvbGRUZXh0LnBvcCgpOyB0b0xpbmUtLTsgfVxyXG4gICAgICAgIGVsc2UgaWYgKG5ld1RleHRbMF0gPT0gb2xkVGV4dFswXSkgeyBuZXdUZXh0LnNoaWZ0KCk7IG9sZFRleHQuc2hpZnQoKTsgZnJvbUxpbmUrKzsgfVxyXG4gICAgICAgIGVsc2UgYnJlYWs7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHZhciBjdXRGcm9udCA9IDAsIGN1dEVuZCA9IDA7XHJcbiAgICAgIHZhciBuZXdUb3AgPSBuZXdUZXh0WzBdLCBvbGRUb3AgPSBvbGRUZXh0WzBdLCBtYXhDdXRGcm9udCA9IE1hdGgubWluKG5ld1RvcC5sZW5ndGgsIG9sZFRvcC5sZW5ndGgpO1xyXG4gICAgICB3aGlsZSAoY3V0RnJvbnQgPCBtYXhDdXRGcm9udCAmJiBuZXdUb3AuY2hhckNvZGVBdChjdXRGcm9udCkgPT0gb2xkVG9wLmNoYXJDb2RlQXQoY3V0RnJvbnQpKVxyXG4gICAgICAgICsrY3V0RnJvbnQ7XHJcbiAgICAgIHZhciBuZXdCb3QgPSBsc3QobmV3VGV4dCksIG9sZEJvdCA9IGxzdChvbGRUZXh0KTtcclxuICAgICAgdmFyIG1heEN1dEVuZCA9IE1hdGgubWluKG5ld0JvdC5sZW5ndGggLSAobmV3VGV4dC5sZW5ndGggPT0gMSA/IGN1dEZyb250IDogMCksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRCb3QubGVuZ3RoIC0gKG9sZFRleHQubGVuZ3RoID09IDEgPyBjdXRGcm9udCA6IDApKTtcclxuICAgICAgd2hpbGUgKGN1dEVuZCA8IG1heEN1dEVuZCAmJlxyXG4gICAgICAgICAgICAgbmV3Qm90LmNoYXJDb2RlQXQobmV3Qm90Lmxlbmd0aCAtIGN1dEVuZCAtIDEpID09IG9sZEJvdC5jaGFyQ29kZUF0KG9sZEJvdC5sZW5ndGggLSBjdXRFbmQgLSAxKSlcclxuICAgICAgICArK2N1dEVuZDtcclxuXHJcbiAgICAgIG5ld1RleHRbbmV3VGV4dC5sZW5ndGggLSAxXSA9IG5ld0JvdC5zbGljZSgwLCBuZXdCb3QubGVuZ3RoIC0gY3V0RW5kKTtcclxuICAgICAgbmV3VGV4dFswXSA9IG5ld1RleHRbMF0uc2xpY2UoY3V0RnJvbnQpO1xyXG5cclxuICAgICAgdmFyIGNoRnJvbSA9IFBvcyhmcm9tTGluZSwgY3V0RnJvbnQpO1xyXG4gICAgICB2YXIgY2hUbyA9IFBvcyh0b0xpbmUsIG9sZFRleHQubGVuZ3RoID8gbHN0KG9sZFRleHQpLmxlbmd0aCAtIGN1dEVuZCA6IDApO1xyXG4gICAgICBpZiAobmV3VGV4dC5sZW5ndGggPiAxIHx8IG5ld1RleHRbMF0gfHwgY21wKGNoRnJvbSwgY2hUbykpIHtcclxuICAgICAgICByZXBsYWNlUmFuZ2UoY20uZG9jLCBuZXdUZXh0LCBjaEZyb20sIGNoVG8sIFwiK2lucHV0XCIpO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIGVuc3VyZVBvbGxlZDogZnVuY3Rpb24oKSB7XHJcbiAgICAgIHRoaXMuZm9yY2VDb21wb3NpdGlvbkVuZCgpO1xyXG4gICAgfSxcclxuICAgIHJlc2V0OiBmdW5jdGlvbigpIHtcclxuICAgICAgdGhpcy5mb3JjZUNvbXBvc2l0aW9uRW5kKCk7XHJcbiAgICB9LFxyXG4gICAgZm9yY2VDb21wb3NpdGlvbkVuZDogZnVuY3Rpb24oKSB7XHJcbiAgICAgIGlmICghdGhpcy5jb21wb3NpbmcgfHwgdGhpcy5jb21wb3NpbmcuaGFuZGxlZCkgcmV0dXJuO1xyXG4gICAgICB0aGlzLmFwcGx5Q29tcG9zaXRpb24odGhpcy5jb21wb3NpbmcpO1xyXG4gICAgICB0aGlzLmNvbXBvc2luZy5oYW5kbGVkID0gdHJ1ZTtcclxuICAgICAgdGhpcy5kaXYuYmx1cigpO1xyXG4gICAgICB0aGlzLmRpdi5mb2N1cygpO1xyXG4gICAgfSxcclxuICAgIGFwcGx5Q29tcG9zaXRpb246IGZ1bmN0aW9uKGNvbXBvc2luZykge1xyXG4gICAgICBpZiAoaXNSZWFkT25seSh0aGlzLmNtKSlcclxuICAgICAgICBvcGVyYXRpb24odGhpcy5jbSwgcmVnQ2hhbmdlKSh0aGlzLmNtKVxyXG4gICAgICBlbHNlIGlmIChjb21wb3NpbmcuZGF0YSAmJiBjb21wb3NpbmcuZGF0YSAhPSBjb21wb3Npbmcuc3RhcnREYXRhKVxyXG4gICAgICAgIG9wZXJhdGlvbih0aGlzLmNtLCBhcHBseVRleHRJbnB1dCkodGhpcy5jbSwgY29tcG9zaW5nLmRhdGEsIDAsIGNvbXBvc2luZy5zZWwpO1xyXG4gICAgfSxcclxuXHJcbiAgICBzZXRVbmVkaXRhYmxlOiBmdW5jdGlvbihub2RlKSB7XHJcbiAgICAgIG5vZGUuY29udGVudEVkaXRhYmxlID0gXCJmYWxzZVwiXHJcbiAgICB9LFxyXG5cclxuICAgIG9uS2V5UHJlc3M6IGZ1bmN0aW9uKGUpIHtcclxuICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICBpZiAoIWlzUmVhZE9ubHkodGhpcy5jbSkpXHJcbiAgICAgICAgb3BlcmF0aW9uKHRoaXMuY20sIGFwcGx5VGV4dElucHV0KSh0aGlzLmNtLCBTdHJpbmcuZnJvbUNoYXJDb2RlKGUuY2hhckNvZGUgPT0gbnVsbCA/IGUua2V5Q29kZSA6IGUuY2hhckNvZGUpLCAwKTtcclxuICAgIH0sXHJcblxyXG4gICAgcmVhZE9ubHlDaGFuZ2VkOiBmdW5jdGlvbih2YWwpIHtcclxuICAgICAgdGhpcy5kaXYuY29udGVudEVkaXRhYmxlID0gU3RyaW5nKHZhbCAhPSBcIm5vY3Vyc29yXCIpXHJcbiAgICB9LFxyXG5cclxuICAgIG9uQ29udGV4dE1lbnU6IG5vdGhpbmcsXHJcbiAgICByZXNldFBvc2l0aW9uOiBub3RoaW5nLFxyXG5cclxuICAgIG5lZWRzQ29udGVudEF0dHJpYnV0ZTogdHJ1ZVxyXG4gIH0sIENvbnRlbnRFZGl0YWJsZUlucHV0LnByb3RvdHlwZSk7XHJcblxyXG4gIGZ1bmN0aW9uIHBvc1RvRE9NKGNtLCBwb3MpIHtcclxuICAgIHZhciB2aWV3ID0gZmluZFZpZXdGb3JMaW5lKGNtLCBwb3MubGluZSk7XHJcbiAgICBpZiAoIXZpZXcgfHwgdmlldy5oaWRkZW4pIHJldHVybiBudWxsO1xyXG4gICAgdmFyIGxpbmUgPSBnZXRMaW5lKGNtLmRvYywgcG9zLmxpbmUpO1xyXG4gICAgdmFyIGluZm8gPSBtYXBGcm9tTGluZVZpZXcodmlldywgbGluZSwgcG9zLmxpbmUpO1xyXG5cclxuICAgIHZhciBvcmRlciA9IGdldE9yZGVyKGxpbmUpLCBzaWRlID0gXCJsZWZ0XCI7XHJcbiAgICBpZiAob3JkZXIpIHtcclxuICAgICAgdmFyIHBhcnRQb3MgPSBnZXRCaWRpUGFydEF0KG9yZGVyLCBwb3MuY2gpO1xyXG4gICAgICBzaWRlID0gcGFydFBvcyAlIDIgPyBcInJpZ2h0XCIgOiBcImxlZnRcIjtcclxuICAgIH1cclxuICAgIHZhciByZXN1bHQgPSBub2RlQW5kT2Zmc2V0SW5MaW5lTWFwKGluZm8ubWFwLCBwb3MuY2gsIHNpZGUpO1xyXG4gICAgcmVzdWx0Lm9mZnNldCA9IHJlc3VsdC5jb2xsYXBzZSA9PSBcInJpZ2h0XCIgPyByZXN1bHQuZW5kIDogcmVzdWx0LnN0YXJ0O1xyXG4gICAgcmV0dXJuIHJlc3VsdDtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGJhZFBvcyhwb3MsIGJhZCkgeyBpZiAoYmFkKSBwb3MuYmFkID0gdHJ1ZTsgcmV0dXJuIHBvczsgfVxyXG5cclxuICBmdW5jdGlvbiBkb21Ub1BvcyhjbSwgbm9kZSwgb2Zmc2V0KSB7XHJcbiAgICB2YXIgbGluZU5vZGU7XHJcbiAgICBpZiAobm9kZSA9PSBjbS5kaXNwbGF5LmxpbmVEaXYpIHtcclxuICAgICAgbGluZU5vZGUgPSBjbS5kaXNwbGF5LmxpbmVEaXYuY2hpbGROb2Rlc1tvZmZzZXRdO1xyXG4gICAgICBpZiAoIWxpbmVOb2RlKSByZXR1cm4gYmFkUG9zKGNtLmNsaXBQb3MoUG9zKGNtLmRpc3BsYXkudmlld1RvIC0gMSkpLCB0cnVlKTtcclxuICAgICAgbm9kZSA9IG51bGw7IG9mZnNldCA9IDA7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBmb3IgKGxpbmVOb2RlID0gbm9kZTs7IGxpbmVOb2RlID0gbGluZU5vZGUucGFyZW50Tm9kZSkge1xyXG4gICAgICAgIGlmICghbGluZU5vZGUgfHwgbGluZU5vZGUgPT0gY20uZGlzcGxheS5saW5lRGl2KSByZXR1cm4gbnVsbDtcclxuICAgICAgICBpZiAobGluZU5vZGUucGFyZW50Tm9kZSAmJiBsaW5lTm9kZS5wYXJlbnROb2RlID09IGNtLmRpc3BsYXkubGluZURpdikgYnJlYWs7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY20uZGlzcGxheS52aWV3Lmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIHZhciBsaW5lVmlldyA9IGNtLmRpc3BsYXkudmlld1tpXTtcclxuICAgICAgaWYgKGxpbmVWaWV3Lm5vZGUgPT0gbGluZU5vZGUpXHJcbiAgICAgICAgcmV0dXJuIGxvY2F0ZU5vZGVJbkxpbmVWaWV3KGxpbmVWaWV3LCBub2RlLCBvZmZzZXQpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gbG9jYXRlTm9kZUluTGluZVZpZXcobGluZVZpZXcsIG5vZGUsIG9mZnNldCkge1xyXG4gICAgdmFyIHdyYXBwZXIgPSBsaW5lVmlldy50ZXh0LmZpcnN0Q2hpbGQsIGJhZCA9IGZhbHNlO1xyXG4gICAgaWYgKCFub2RlIHx8ICFjb250YWlucyh3cmFwcGVyLCBub2RlKSkgcmV0dXJuIGJhZFBvcyhQb3MobGluZU5vKGxpbmVWaWV3LmxpbmUpLCAwKSwgdHJ1ZSk7XHJcbiAgICBpZiAobm9kZSA9PSB3cmFwcGVyKSB7XHJcbiAgICAgIGJhZCA9IHRydWU7XHJcbiAgICAgIG5vZGUgPSB3cmFwcGVyLmNoaWxkTm9kZXNbb2Zmc2V0XTtcclxuICAgICAgb2Zmc2V0ID0gMDtcclxuICAgICAgaWYgKCFub2RlKSB7XHJcbiAgICAgICAgdmFyIGxpbmUgPSBsaW5lVmlldy5yZXN0ID8gbHN0KGxpbmVWaWV3LnJlc3QpIDogbGluZVZpZXcubGluZTtcclxuICAgICAgICByZXR1cm4gYmFkUG9zKFBvcyhsaW5lTm8obGluZSksIGxpbmUudGV4dC5sZW5ndGgpLCBiYWQpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgdmFyIHRleHROb2RlID0gbm9kZS5ub2RlVHlwZSA9PSAzID8gbm9kZSA6IG51bGwsIHRvcE5vZGUgPSBub2RlO1xyXG4gICAgaWYgKCF0ZXh0Tm9kZSAmJiBub2RlLmNoaWxkTm9kZXMubGVuZ3RoID09IDEgJiYgbm9kZS5maXJzdENoaWxkLm5vZGVUeXBlID09IDMpIHtcclxuICAgICAgdGV4dE5vZGUgPSBub2RlLmZpcnN0Q2hpbGQ7XHJcbiAgICAgIGlmIChvZmZzZXQpIG9mZnNldCA9IHRleHROb2RlLm5vZGVWYWx1ZS5sZW5ndGg7XHJcbiAgICB9XHJcbiAgICB3aGlsZSAodG9wTm9kZS5wYXJlbnROb2RlICE9IHdyYXBwZXIpIHRvcE5vZGUgPSB0b3BOb2RlLnBhcmVudE5vZGU7XHJcbiAgICB2YXIgbWVhc3VyZSA9IGxpbmVWaWV3Lm1lYXN1cmUsIG1hcHMgPSBtZWFzdXJlLm1hcHM7XHJcblxyXG4gICAgZnVuY3Rpb24gZmluZCh0ZXh0Tm9kZSwgdG9wTm9kZSwgb2Zmc2V0KSB7XHJcbiAgICAgIGZvciAodmFyIGkgPSAtMTsgaSA8IChtYXBzID8gbWFwcy5sZW5ndGggOiAwKTsgaSsrKSB7XHJcbiAgICAgICAgdmFyIG1hcCA9IGkgPCAwID8gbWVhc3VyZS5tYXAgOiBtYXBzW2ldO1xyXG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbWFwLmxlbmd0aDsgaiArPSAzKSB7XHJcbiAgICAgICAgICB2YXIgY3VyTm9kZSA9IG1hcFtqICsgMl07XHJcbiAgICAgICAgICBpZiAoY3VyTm9kZSA9PSB0ZXh0Tm9kZSB8fCBjdXJOb2RlID09IHRvcE5vZGUpIHtcclxuICAgICAgICAgICAgdmFyIGxpbmUgPSBsaW5lTm8oaSA8IDAgPyBsaW5lVmlldy5saW5lIDogbGluZVZpZXcucmVzdFtpXSk7XHJcbiAgICAgICAgICAgIHZhciBjaCA9IG1hcFtqXSArIG9mZnNldDtcclxuICAgICAgICAgICAgaWYgKG9mZnNldCA8IDAgfHwgY3VyTm9kZSAhPSB0ZXh0Tm9kZSkgY2ggPSBtYXBbaiArIChvZmZzZXQgPyAxIDogMCldO1xyXG4gICAgICAgICAgICByZXR1cm4gUG9zKGxpbmUsIGNoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHZhciBmb3VuZCA9IGZpbmQodGV4dE5vZGUsIHRvcE5vZGUsIG9mZnNldCk7XHJcbiAgICBpZiAoZm91bmQpIHJldHVybiBiYWRQb3MoZm91bmQsIGJhZCk7XHJcblxyXG4gICAgLy8gRklYTUUgdGhpcyBpcyBhbGwgcmVhbGx5IHNoYWt5LiBtaWdodCBoYW5kbGUgdGhlIGZldyBjYXNlcyBpdCBuZWVkcyB0byBoYW5kbGUsIGJ1dCBsaWtlbHkgdG8gY2F1c2UgcHJvYmxlbXNcclxuICAgIGZvciAodmFyIGFmdGVyID0gdG9wTm9kZS5uZXh0U2libGluZywgZGlzdCA9IHRleHROb2RlID8gdGV4dE5vZGUubm9kZVZhbHVlLmxlbmd0aCAtIG9mZnNldCA6IDA7IGFmdGVyOyBhZnRlciA9IGFmdGVyLm5leHRTaWJsaW5nKSB7XHJcbiAgICAgIGZvdW5kID0gZmluZChhZnRlciwgYWZ0ZXIuZmlyc3RDaGlsZCwgMCk7XHJcbiAgICAgIGlmIChmb3VuZClcclxuICAgICAgICByZXR1cm4gYmFkUG9zKFBvcyhmb3VuZC5saW5lLCBmb3VuZC5jaCAtIGRpc3QpLCBiYWQpO1xyXG4gICAgICBlbHNlXHJcbiAgICAgICAgZGlzdCArPSBhZnRlci50ZXh0Q29udGVudC5sZW5ndGg7XHJcbiAgICB9XHJcbiAgICBmb3IgKHZhciBiZWZvcmUgPSB0b3BOb2RlLnByZXZpb3VzU2libGluZywgZGlzdCA9IG9mZnNldDsgYmVmb3JlOyBiZWZvcmUgPSBiZWZvcmUucHJldmlvdXNTaWJsaW5nKSB7XHJcbiAgICAgIGZvdW5kID0gZmluZChiZWZvcmUsIGJlZm9yZS5maXJzdENoaWxkLCAtMSk7XHJcbiAgICAgIGlmIChmb3VuZClcclxuICAgICAgICByZXR1cm4gYmFkUG9zKFBvcyhmb3VuZC5saW5lLCBmb3VuZC5jaCArIGRpc3QpLCBiYWQpO1xyXG4gICAgICBlbHNlXHJcbiAgICAgICAgZGlzdCArPSBhZnRlci50ZXh0Q29udGVudC5sZW5ndGg7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBkb21UZXh0QmV0d2VlbihjbSwgZnJvbSwgdG8sIGZyb21MaW5lLCB0b0xpbmUpIHtcclxuICAgIHZhciB0ZXh0ID0gXCJcIiwgY2xvc2luZyA9IGZhbHNlLCBsaW5lU2VwID0gY20uZG9jLmxpbmVTZXBhcmF0b3IoKTtcclxuICAgIGZ1bmN0aW9uIHJlY29nbml6ZU1hcmtlcihpZCkgeyByZXR1cm4gZnVuY3Rpb24obWFya2VyKSB7IHJldHVybiBtYXJrZXIuaWQgPT0gaWQ7IH07IH1cclxuICAgIGZ1bmN0aW9uIHdhbGsobm9kZSkge1xyXG4gICAgICBpZiAobm9kZS5ub2RlVHlwZSA9PSAxKSB7XHJcbiAgICAgICAgdmFyIGNtVGV4dCA9IG5vZGUuZ2V0QXR0cmlidXRlKFwiY20tdGV4dFwiKTtcclxuICAgICAgICBpZiAoY21UZXh0ICE9IG51bGwpIHtcclxuICAgICAgICAgIGlmIChjbVRleHQgPT0gXCJcIikgY21UZXh0ID0gbm9kZS50ZXh0Q29udGVudC5yZXBsYWNlKC9cXHUyMDBiL2csIFwiXCIpO1xyXG4gICAgICAgICAgdGV4dCArPSBjbVRleHQ7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHZhciBtYXJrZXJJRCA9IG5vZGUuZ2V0QXR0cmlidXRlKFwiY20tbWFya2VyXCIpLCByYW5nZTtcclxuICAgICAgICBpZiAobWFya2VySUQpIHtcclxuICAgICAgICAgIHZhciBmb3VuZCA9IGNtLmZpbmRNYXJrcyhQb3MoZnJvbUxpbmUsIDApLCBQb3ModG9MaW5lICsgMSwgMCksIHJlY29nbml6ZU1hcmtlcigrbWFya2VySUQpKTtcclxuICAgICAgICAgIGlmIChmb3VuZC5sZW5ndGggJiYgKHJhbmdlID0gZm91bmRbMF0uZmluZCgpKSlcclxuICAgICAgICAgICAgdGV4dCArPSBnZXRCZXR3ZWVuKGNtLmRvYywgcmFuZ2UuZnJvbSwgcmFuZ2UudG8pLmpvaW4obGluZVNlcCk7XHJcbiAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChub2RlLmdldEF0dHJpYnV0ZShcImNvbnRlbnRlZGl0YWJsZVwiKSA9PSBcImZhbHNlXCIpIHJldHVybjtcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGUuY2hpbGROb2Rlcy5sZW5ndGg7IGkrKylcclxuICAgICAgICAgIHdhbGsobm9kZS5jaGlsZE5vZGVzW2ldKTtcclxuICAgICAgICBpZiAoL14ocHJlfGRpdnxwKSQvaS50ZXN0KG5vZGUubm9kZU5hbWUpKVxyXG4gICAgICAgICAgY2xvc2luZyA9IHRydWU7XHJcbiAgICAgIH0gZWxzZSBpZiAobm9kZS5ub2RlVHlwZSA9PSAzKSB7XHJcbiAgICAgICAgdmFyIHZhbCA9IG5vZGUubm9kZVZhbHVlO1xyXG4gICAgICAgIGlmICghdmFsKSByZXR1cm47XHJcbiAgICAgICAgaWYgKGNsb3NpbmcpIHtcclxuICAgICAgICAgIHRleHQgKz0gbGluZVNlcDtcclxuICAgICAgICAgIGNsb3NpbmcgPSBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGV4dCArPSB2YWw7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGZvciAoOzspIHtcclxuICAgICAgd2Fsayhmcm9tKTtcclxuICAgICAgaWYgKGZyb20gPT0gdG8pIGJyZWFrO1xyXG4gICAgICBmcm9tID0gZnJvbS5uZXh0U2libGluZztcclxuICAgIH1cclxuICAgIHJldHVybiB0ZXh0O1xyXG4gIH1cclxuXHJcbiAgQ29kZU1pcnJvci5pbnB1dFN0eWxlcyA9IHtcInRleHRhcmVhXCI6IFRleHRhcmVhSW5wdXQsIFwiY29udGVudGVkaXRhYmxlXCI6IENvbnRlbnRFZGl0YWJsZUlucHV0fTtcclxuXHJcbiAgLy8gU0VMRUNUSU9OIC8gQ1VSU09SXHJcblxyXG4gIC8vIFNlbGVjdGlvbiBvYmplY3RzIGFyZSBpbW11dGFibGUuIEEgbmV3IG9uZSBpcyBjcmVhdGVkIGV2ZXJ5IHRpbWVcclxuICAvLyB0aGUgc2VsZWN0aW9uIGNoYW5nZXMuIEEgc2VsZWN0aW9uIGlzIG9uZSBvciBtb3JlIG5vbi1vdmVybGFwcGluZ1xyXG4gIC8vIChhbmQgbm9uLXRvdWNoaW5nKSByYW5nZXMsIHNvcnRlZCwgYW5kIGFuIGludGVnZXIgdGhhdCBpbmRpY2F0ZXNcclxuICAvLyB3aGljaCBvbmUgaXMgdGhlIHByaW1hcnkgc2VsZWN0aW9uICh0aGUgb25lIHRoYXQncyBzY3JvbGxlZCBpbnRvXHJcbiAgLy8gdmlldywgdGhhdCBnZXRDdXJzb3IgcmV0dXJucywgZXRjKS5cclxuICBmdW5jdGlvbiBTZWxlY3Rpb24ocmFuZ2VzLCBwcmltSW5kZXgpIHtcclxuICAgIHRoaXMucmFuZ2VzID0gcmFuZ2VzO1xyXG4gICAgdGhpcy5wcmltSW5kZXggPSBwcmltSW5kZXg7XHJcbiAgfVxyXG5cclxuICBTZWxlY3Rpb24ucHJvdG90eXBlID0ge1xyXG4gICAgcHJpbWFyeTogZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzLnJhbmdlc1t0aGlzLnByaW1JbmRleF07IH0sXHJcbiAgICBlcXVhbHM6IGZ1bmN0aW9uKG90aGVyKSB7XHJcbiAgICAgIGlmIChvdGhlciA9PSB0aGlzKSByZXR1cm4gdHJ1ZTtcclxuICAgICAgaWYgKG90aGVyLnByaW1JbmRleCAhPSB0aGlzLnByaW1JbmRleCB8fCBvdGhlci5yYW5nZXMubGVuZ3RoICE9IHRoaXMucmFuZ2VzLmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMucmFuZ2VzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgdmFyIGhlcmUgPSB0aGlzLnJhbmdlc1tpXSwgdGhlcmUgPSBvdGhlci5yYW5nZXNbaV07XHJcbiAgICAgICAgaWYgKGNtcChoZXJlLmFuY2hvciwgdGhlcmUuYW5jaG9yKSAhPSAwIHx8IGNtcChoZXJlLmhlYWQsIHRoZXJlLmhlYWQpICE9IDApIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0sXHJcbiAgICBkZWVwQ29weTogZnVuY3Rpb24oKSB7XHJcbiAgICAgIGZvciAodmFyIG91dCA9IFtdLCBpID0gMDsgaSA8IHRoaXMucmFuZ2VzLmxlbmd0aDsgaSsrKVxyXG4gICAgICAgIG91dFtpXSA9IG5ldyBSYW5nZShjb3B5UG9zKHRoaXMucmFuZ2VzW2ldLmFuY2hvciksIGNvcHlQb3ModGhpcy5yYW5nZXNbaV0uaGVhZCkpO1xyXG4gICAgICByZXR1cm4gbmV3IFNlbGVjdGlvbihvdXQsIHRoaXMucHJpbUluZGV4KTtcclxuICAgIH0sXHJcbiAgICBzb21ldGhpbmdTZWxlY3RlZDogZnVuY3Rpb24oKSB7XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5yYW5nZXMubGVuZ3RoOyBpKyspXHJcbiAgICAgICAgaWYgKCF0aGlzLnJhbmdlc1tpXS5lbXB0eSgpKSByZXR1cm4gdHJ1ZTtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfSxcclxuICAgIGNvbnRhaW5zOiBmdW5jdGlvbihwb3MsIGVuZCkge1xyXG4gICAgICBpZiAoIWVuZCkgZW5kID0gcG9zO1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMucmFuZ2VzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgdmFyIHJhbmdlID0gdGhpcy5yYW5nZXNbaV07XHJcbiAgICAgICAgaWYgKGNtcChlbmQsIHJhbmdlLmZyb20oKSkgPj0gMCAmJiBjbXAocG9zLCByYW5nZS50bygpKSA8PSAwKVxyXG4gICAgICAgICAgcmV0dXJuIGk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIC0xO1xyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIGZ1bmN0aW9uIFJhbmdlKGFuY2hvciwgaGVhZCkge1xyXG4gICAgdGhpcy5hbmNob3IgPSBhbmNob3I7IHRoaXMuaGVhZCA9IGhlYWQ7XHJcbiAgfVxyXG5cclxuICBSYW5nZS5wcm90b3R5cGUgPSB7XHJcbiAgICBmcm9tOiBmdW5jdGlvbigpIHsgcmV0dXJuIG1pblBvcyh0aGlzLmFuY2hvciwgdGhpcy5oZWFkKTsgfSxcclxuICAgIHRvOiBmdW5jdGlvbigpIHsgcmV0dXJuIG1heFBvcyh0aGlzLmFuY2hvciwgdGhpcy5oZWFkKTsgfSxcclxuICAgIGVtcHR5OiBmdW5jdGlvbigpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuaGVhZC5saW5lID09IHRoaXMuYW5jaG9yLmxpbmUgJiYgdGhpcy5oZWFkLmNoID09IHRoaXMuYW5jaG9yLmNoO1xyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIFRha2UgYW4gdW5zb3J0ZWQsIHBvdGVudGlhbGx5IG92ZXJsYXBwaW5nIHNldCBvZiByYW5nZXMsIGFuZFxyXG4gIC8vIGJ1aWxkIGEgc2VsZWN0aW9uIG91dCBvZiBpdC4gJ0NvbnN1bWVzJyByYW5nZXMgYXJyYXkgKG1vZGlmeWluZ1xyXG4gIC8vIGl0KS5cclxuICBmdW5jdGlvbiBub3JtYWxpemVTZWxlY3Rpb24ocmFuZ2VzLCBwcmltSW5kZXgpIHtcclxuICAgIHZhciBwcmltID0gcmFuZ2VzW3ByaW1JbmRleF07XHJcbiAgICByYW5nZXMuc29ydChmdW5jdGlvbihhLCBiKSB7IHJldHVybiBjbXAoYS5mcm9tKCksIGIuZnJvbSgpKTsgfSk7XHJcbiAgICBwcmltSW5kZXggPSBpbmRleE9mKHJhbmdlcywgcHJpbSk7XHJcbiAgICBmb3IgKHZhciBpID0gMTsgaSA8IHJhbmdlcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICB2YXIgY3VyID0gcmFuZ2VzW2ldLCBwcmV2ID0gcmFuZ2VzW2kgLSAxXTtcclxuICAgICAgaWYgKGNtcChwcmV2LnRvKCksIGN1ci5mcm9tKCkpID49IDApIHtcclxuICAgICAgICB2YXIgZnJvbSA9IG1pblBvcyhwcmV2LmZyb20oKSwgY3VyLmZyb20oKSksIHRvID0gbWF4UG9zKHByZXYudG8oKSwgY3VyLnRvKCkpO1xyXG4gICAgICAgIHZhciBpbnYgPSBwcmV2LmVtcHR5KCkgPyBjdXIuZnJvbSgpID09IGN1ci5oZWFkIDogcHJldi5mcm9tKCkgPT0gcHJldi5oZWFkO1xyXG4gICAgICAgIGlmIChpIDw9IHByaW1JbmRleCkgLS1wcmltSW5kZXg7XHJcbiAgICAgICAgcmFuZ2VzLnNwbGljZSgtLWksIDIsIG5ldyBSYW5nZShpbnYgPyB0byA6IGZyb20sIGludiA/IGZyb20gOiB0bykpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gbmV3IFNlbGVjdGlvbihyYW5nZXMsIHByaW1JbmRleCk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBzaW1wbGVTZWxlY3Rpb24oYW5jaG9yLCBoZWFkKSB7XHJcbiAgICByZXR1cm4gbmV3IFNlbGVjdGlvbihbbmV3IFJhbmdlKGFuY2hvciwgaGVhZCB8fCBhbmNob3IpXSwgMCk7XHJcbiAgfVxyXG5cclxuICAvLyBNb3N0IG9mIHRoZSBleHRlcm5hbCBBUEkgY2xpcHMgZ2l2ZW4gcG9zaXRpb25zIHRvIG1ha2Ugc3VyZSB0aGV5XHJcbiAgLy8gYWN0dWFsbHkgZXhpc3Qgd2l0aGluIHRoZSBkb2N1bWVudC5cclxuICBmdW5jdGlvbiBjbGlwTGluZShkb2MsIG4pIHtyZXR1cm4gTWF0aC5tYXgoZG9jLmZpcnN0LCBNYXRoLm1pbihuLCBkb2MuZmlyc3QgKyBkb2Muc2l6ZSAtIDEpKTt9XHJcbiAgZnVuY3Rpb24gY2xpcFBvcyhkb2MsIHBvcykge1xyXG4gICAgaWYgKHBvcy5saW5lIDwgZG9jLmZpcnN0KSByZXR1cm4gUG9zKGRvYy5maXJzdCwgMCk7XHJcbiAgICB2YXIgbGFzdCA9IGRvYy5maXJzdCArIGRvYy5zaXplIC0gMTtcclxuICAgIGlmIChwb3MubGluZSA+IGxhc3QpIHJldHVybiBQb3MobGFzdCwgZ2V0TGluZShkb2MsIGxhc3QpLnRleHQubGVuZ3RoKTtcclxuICAgIHJldHVybiBjbGlwVG9MZW4ocG9zLCBnZXRMaW5lKGRvYywgcG9zLmxpbmUpLnRleHQubGVuZ3RoKTtcclxuICB9XHJcbiAgZnVuY3Rpb24gY2xpcFRvTGVuKHBvcywgbGluZWxlbikge1xyXG4gICAgdmFyIGNoID0gcG9zLmNoO1xyXG4gICAgaWYgKGNoID09IG51bGwgfHwgY2ggPiBsaW5lbGVuKSByZXR1cm4gUG9zKHBvcy5saW5lLCBsaW5lbGVuKTtcclxuICAgIGVsc2UgaWYgKGNoIDwgMCkgcmV0dXJuIFBvcyhwb3MubGluZSwgMCk7XHJcbiAgICBlbHNlIHJldHVybiBwb3M7XHJcbiAgfVxyXG4gIGZ1bmN0aW9uIGlzTGluZShkb2MsIGwpIHtyZXR1cm4gbCA+PSBkb2MuZmlyc3QgJiYgbCA8IGRvYy5maXJzdCArIGRvYy5zaXplO31cclxuICBmdW5jdGlvbiBjbGlwUG9zQXJyYXkoZG9jLCBhcnJheSkge1xyXG4gICAgZm9yICh2YXIgb3V0ID0gW10sIGkgPSAwOyBpIDwgYXJyYXkubGVuZ3RoOyBpKyspIG91dFtpXSA9IGNsaXBQb3MoZG9jLCBhcnJheVtpXSk7XHJcbiAgICByZXR1cm4gb3V0O1xyXG4gIH1cclxuXHJcbiAgLy8gU0VMRUNUSU9OIFVQREFURVNcclxuXHJcbiAgLy8gVGhlICdzY3JvbGwnIHBhcmFtZXRlciBnaXZlbiB0byBtYW55IG9mIHRoZXNlIGluZGljYXRlZCB3aGV0aGVyXHJcbiAgLy8gdGhlIG5ldyBjdXJzb3IgcG9zaXRpb24gc2hvdWxkIGJlIHNjcm9sbGVkIGludG8gdmlldyBhZnRlclxyXG4gIC8vIG1vZGlmeWluZyB0aGUgc2VsZWN0aW9uLlxyXG5cclxuICAvLyBJZiBzaGlmdCBpcyBoZWxkIG9yIHRoZSBleHRlbmQgZmxhZyBpcyBzZXQsIGV4dGVuZHMgYSByYW5nZSB0b1xyXG4gIC8vIGluY2x1ZGUgYSBnaXZlbiBwb3NpdGlvbiAoYW5kIG9wdGlvbmFsbHkgYSBzZWNvbmQgcG9zaXRpb24pLlxyXG4gIC8vIE90aGVyd2lzZSwgc2ltcGx5IHJldHVybnMgdGhlIHJhbmdlIGJldHdlZW4gdGhlIGdpdmVuIHBvc2l0aW9ucy5cclxuICAvLyBVc2VkIGZvciBjdXJzb3IgbW90aW9uIGFuZCBzdWNoLlxyXG4gIGZ1bmN0aW9uIGV4dGVuZFJhbmdlKGRvYywgcmFuZ2UsIGhlYWQsIG90aGVyKSB7XHJcbiAgICBpZiAoZG9jLmNtICYmIGRvYy5jbS5kaXNwbGF5LnNoaWZ0IHx8IGRvYy5leHRlbmQpIHtcclxuICAgICAgdmFyIGFuY2hvciA9IHJhbmdlLmFuY2hvcjtcclxuICAgICAgaWYgKG90aGVyKSB7XHJcbiAgICAgICAgdmFyIHBvc0JlZm9yZSA9IGNtcChoZWFkLCBhbmNob3IpIDwgMDtcclxuICAgICAgICBpZiAocG9zQmVmb3JlICE9IChjbXAob3RoZXIsIGFuY2hvcikgPCAwKSkge1xyXG4gICAgICAgICAgYW5jaG9yID0gaGVhZDtcclxuICAgICAgICAgIGhlYWQgPSBvdGhlcjtcclxuICAgICAgICB9IGVsc2UgaWYgKHBvc0JlZm9yZSAhPSAoY21wKGhlYWQsIG90aGVyKSA8IDApKSB7XHJcbiAgICAgICAgICBoZWFkID0gb3RoZXI7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBuZXcgUmFuZ2UoYW5jaG9yLCBoZWFkKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHJldHVybiBuZXcgUmFuZ2Uob3RoZXIgfHwgaGVhZCwgaGVhZCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHRlbmQgdGhlIHByaW1hcnkgc2VsZWN0aW9uIHJhbmdlLCBkaXNjYXJkIHRoZSByZXN0LlxyXG4gIGZ1bmN0aW9uIGV4dGVuZFNlbGVjdGlvbihkb2MsIGhlYWQsIG90aGVyLCBvcHRpb25zKSB7XHJcbiAgICBzZXRTZWxlY3Rpb24oZG9jLCBuZXcgU2VsZWN0aW9uKFtleHRlbmRSYW5nZShkb2MsIGRvYy5zZWwucHJpbWFyeSgpLCBoZWFkLCBvdGhlcildLCAwKSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBFeHRlbmQgYWxsIHNlbGVjdGlvbnMgKHBvcyBpcyBhbiBhcnJheSBvZiBzZWxlY3Rpb25zIHdpdGggbGVuZ3RoXHJcbiAgLy8gZXF1YWwgdGhlIG51bWJlciBvZiBzZWxlY3Rpb25zKVxyXG4gIGZ1bmN0aW9uIGV4dGVuZFNlbGVjdGlvbnMoZG9jLCBoZWFkcywgb3B0aW9ucykge1xyXG4gICAgZm9yICh2YXIgb3V0ID0gW10sIGkgPSAwOyBpIDwgZG9jLnNlbC5yYW5nZXMubGVuZ3RoOyBpKyspXHJcbiAgICAgIG91dFtpXSA9IGV4dGVuZFJhbmdlKGRvYywgZG9jLnNlbC5yYW5nZXNbaV0sIGhlYWRzW2ldLCBudWxsKTtcclxuICAgIHZhciBuZXdTZWwgPSBub3JtYWxpemVTZWxlY3Rpb24ob3V0LCBkb2Muc2VsLnByaW1JbmRleCk7XHJcbiAgICBzZXRTZWxlY3Rpb24oZG9jLCBuZXdTZWwsIG9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlcyBhIHNpbmdsZSByYW5nZSBpbiB0aGUgc2VsZWN0aW9uLlxyXG4gIGZ1bmN0aW9uIHJlcGxhY2VPbmVTZWxlY3Rpb24oZG9jLCBpLCByYW5nZSwgb3B0aW9ucykge1xyXG4gICAgdmFyIHJhbmdlcyA9IGRvYy5zZWwucmFuZ2VzLnNsaWNlKDApO1xyXG4gICAgcmFuZ2VzW2ldID0gcmFuZ2U7XHJcbiAgICBzZXRTZWxlY3Rpb24oZG9jLCBub3JtYWxpemVTZWxlY3Rpb24ocmFuZ2VzLCBkb2Muc2VsLnByaW1JbmRleCksIG9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmVzZXQgdGhlIHNlbGVjdGlvbiB0byBhIHNpbmdsZSByYW5nZS5cclxuICBmdW5jdGlvbiBzZXRTaW1wbGVTZWxlY3Rpb24oZG9jLCBhbmNob3IsIGhlYWQsIG9wdGlvbnMpIHtcclxuICAgIHNldFNlbGVjdGlvbihkb2MsIHNpbXBsZVNlbGVjdGlvbihhbmNob3IsIGhlYWQpLCBvcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIEdpdmUgYmVmb3JlU2VsZWN0aW9uQ2hhbmdlIGhhbmRsZXJzIGEgY2hhbmdlIHRvIGluZmx1ZW5jZSBhXHJcbiAgLy8gc2VsZWN0aW9uIHVwZGF0ZS5cclxuICBmdW5jdGlvbiBmaWx0ZXJTZWxlY3Rpb25DaGFuZ2UoZG9jLCBzZWwpIHtcclxuICAgIHZhciBvYmogPSB7XHJcbiAgICAgIHJhbmdlczogc2VsLnJhbmdlcyxcclxuICAgICAgdXBkYXRlOiBmdW5jdGlvbihyYW5nZXMpIHtcclxuICAgICAgICB0aGlzLnJhbmdlcyA9IFtdO1xyXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmFuZ2VzLmxlbmd0aDsgaSsrKVxyXG4gICAgICAgICAgdGhpcy5yYW5nZXNbaV0gPSBuZXcgUmFuZ2UoY2xpcFBvcyhkb2MsIHJhbmdlc1tpXS5hbmNob3IpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpcFBvcyhkb2MsIHJhbmdlc1tpXS5oZWFkKSk7XHJcbiAgICAgIH1cclxuICAgIH07XHJcbiAgICBzaWduYWwoZG9jLCBcImJlZm9yZVNlbGVjdGlvbkNoYW5nZVwiLCBkb2MsIG9iaik7XHJcbiAgICBpZiAoZG9jLmNtKSBzaWduYWwoZG9jLmNtLCBcImJlZm9yZVNlbGVjdGlvbkNoYW5nZVwiLCBkb2MuY20sIG9iaik7XHJcbiAgICBpZiAob2JqLnJhbmdlcyAhPSBzZWwucmFuZ2VzKSByZXR1cm4gbm9ybWFsaXplU2VsZWN0aW9uKG9iai5yYW5nZXMsIG9iai5yYW5nZXMubGVuZ3RoIC0gMSk7XHJcbiAgICBlbHNlIHJldHVybiBzZWw7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBzZXRTZWxlY3Rpb25SZXBsYWNlSGlzdG9yeShkb2MsIHNlbCwgb3B0aW9ucykge1xyXG4gICAgdmFyIGRvbmUgPSBkb2MuaGlzdG9yeS5kb25lLCBsYXN0ID0gbHN0KGRvbmUpO1xyXG4gICAgaWYgKGxhc3QgJiYgbGFzdC5yYW5nZXMpIHtcclxuICAgICAgZG9uZVtkb25lLmxlbmd0aCAtIDFdID0gc2VsO1xyXG4gICAgICBzZXRTZWxlY3Rpb25Ob1VuZG8oZG9jLCBzZWwsIG9wdGlvbnMpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgc2V0U2VsZWN0aW9uKGRvYywgc2VsLCBvcHRpb25zKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNldCBhIG5ldyBzZWxlY3Rpb24uXHJcbiAgZnVuY3Rpb24gc2V0U2VsZWN0aW9uKGRvYywgc2VsLCBvcHRpb25zKSB7XHJcbiAgICBzZXRTZWxlY3Rpb25Ob1VuZG8oZG9jLCBzZWwsIG9wdGlvbnMpO1xyXG4gICAgYWRkU2VsZWN0aW9uVG9IaXN0b3J5KGRvYywgZG9jLnNlbCwgZG9jLmNtID8gZG9jLmNtLmN1ck9wLmlkIDogTmFOLCBvcHRpb25zKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIHNldFNlbGVjdGlvbk5vVW5kbyhkb2MsIHNlbCwgb3B0aW9ucykge1xyXG4gICAgaWYgKGhhc0hhbmRsZXIoZG9jLCBcImJlZm9yZVNlbGVjdGlvbkNoYW5nZVwiKSB8fCBkb2MuY20gJiYgaGFzSGFuZGxlcihkb2MuY20sIFwiYmVmb3JlU2VsZWN0aW9uQ2hhbmdlXCIpKVxyXG4gICAgICBzZWwgPSBmaWx0ZXJTZWxlY3Rpb25DaGFuZ2UoZG9jLCBzZWwpO1xyXG5cclxuICAgIHZhciBiaWFzID0gb3B0aW9ucyAmJiBvcHRpb25zLmJpYXMgfHxcclxuICAgICAgKGNtcChzZWwucHJpbWFyeSgpLmhlYWQsIGRvYy5zZWwucHJpbWFyeSgpLmhlYWQpIDwgMCA/IC0xIDogMSk7XHJcbiAgICBzZXRTZWxlY3Rpb25Jbm5lcihkb2MsIHNraXBBdG9taWNJblNlbGVjdGlvbihkb2MsIHNlbCwgYmlhcywgdHJ1ZSkpO1xyXG5cclxuICAgIGlmICghKG9wdGlvbnMgJiYgb3B0aW9ucy5zY3JvbGwgPT09IGZhbHNlKSAmJiBkb2MuY20pXHJcbiAgICAgIGVuc3VyZUN1cnNvclZpc2libGUoZG9jLmNtKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIHNldFNlbGVjdGlvbklubmVyKGRvYywgc2VsKSB7XHJcbiAgICBpZiAoc2VsLmVxdWFscyhkb2Muc2VsKSkgcmV0dXJuO1xyXG5cclxuICAgIGRvYy5zZWwgPSBzZWw7XHJcblxyXG4gICAgaWYgKGRvYy5jbSkge1xyXG4gICAgICBkb2MuY20uY3VyT3AudXBkYXRlSW5wdXQgPSBkb2MuY20uY3VyT3Auc2VsZWN0aW9uQ2hhbmdlZCA9IHRydWU7XHJcbiAgICAgIHNpZ25hbEN1cnNvckFjdGl2aXR5KGRvYy5jbSk7XHJcbiAgICB9XHJcbiAgICBzaWduYWxMYXRlcihkb2MsIFwiY3Vyc29yQWN0aXZpdHlcIiwgZG9jKTtcclxuICB9XHJcblxyXG4gIC8vIFZlcmlmeSB0aGF0IHRoZSBzZWxlY3Rpb24gZG9lcyBub3QgcGFydGlhbGx5IHNlbGVjdCBhbnkgYXRvbWljXHJcbiAgLy8gbWFya2VkIHJhbmdlcy5cclxuICBmdW5jdGlvbiByZUNoZWNrU2VsZWN0aW9uKGRvYykge1xyXG4gICAgc2V0U2VsZWN0aW9uSW5uZXIoZG9jLCBza2lwQXRvbWljSW5TZWxlY3Rpb24oZG9jLCBkb2Muc2VsLCBudWxsLCBmYWxzZSksIHNlbF9kb250U2Nyb2xsKTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIHNlbGVjdGlvbiB0aGF0IGRvZXMgbm90IHBhcnRpYWxseSBzZWxlY3QgYW55IGF0b21pY1xyXG4gIC8vIHJhbmdlcy5cclxuICBmdW5jdGlvbiBza2lwQXRvbWljSW5TZWxlY3Rpb24oZG9jLCBzZWwsIGJpYXMsIG1heUNsZWFyKSB7XHJcbiAgICB2YXIgb3V0O1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzZWwucmFuZ2VzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIHZhciByYW5nZSA9IHNlbC5yYW5nZXNbaV07XHJcbiAgICAgIHZhciBvbGQgPSBzZWwucmFuZ2VzLmxlbmd0aCA9PSBkb2Muc2VsLnJhbmdlcy5sZW5ndGggJiYgZG9jLnNlbC5yYW5nZXNbaV07XHJcbiAgICAgIHZhciBuZXdBbmNob3IgPSBza2lwQXRvbWljKGRvYywgcmFuZ2UuYW5jaG9yLCBvbGQgJiYgb2xkLmFuY2hvciwgYmlhcywgbWF5Q2xlYXIpO1xyXG4gICAgICB2YXIgbmV3SGVhZCA9IHNraXBBdG9taWMoZG9jLCByYW5nZS5oZWFkLCBvbGQgJiYgb2xkLmhlYWQsIGJpYXMsIG1heUNsZWFyKTtcclxuICAgICAgaWYgKG91dCB8fCBuZXdBbmNob3IgIT0gcmFuZ2UuYW5jaG9yIHx8IG5ld0hlYWQgIT0gcmFuZ2UuaGVhZCkge1xyXG4gICAgICAgIGlmICghb3V0KSBvdXQgPSBzZWwucmFuZ2VzLnNsaWNlKDAsIGkpO1xyXG4gICAgICAgIG91dFtpXSA9IG5ldyBSYW5nZShuZXdBbmNob3IsIG5ld0hlYWQpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gb3V0ID8gbm9ybWFsaXplU2VsZWN0aW9uKG91dCwgc2VsLnByaW1JbmRleCkgOiBzZWw7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBza2lwQXRvbWljSW5uZXIoZG9jLCBwb3MsIG9sZFBvcywgZGlyLCBtYXlDbGVhcikge1xyXG4gICAgdmFyIGxpbmUgPSBnZXRMaW5lKGRvYywgcG9zLmxpbmUpO1xyXG4gICAgaWYgKGxpbmUubWFya2VkU3BhbnMpIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZS5tYXJrZWRTcGFucy5sZW5ndGg7ICsraSkge1xyXG4gICAgICB2YXIgc3AgPSBsaW5lLm1hcmtlZFNwYW5zW2ldLCBtID0gc3AubWFya2VyO1xyXG4gICAgICBpZiAoKHNwLmZyb20gPT0gbnVsbCB8fCAobS5pbmNsdXNpdmVMZWZ0ID8gc3AuZnJvbSA8PSBwb3MuY2ggOiBzcC5mcm9tIDwgcG9zLmNoKSkgJiZcclxuICAgICAgICAgIChzcC50byA9PSBudWxsIHx8IChtLmluY2x1c2l2ZVJpZ2h0ID8gc3AudG8gPj0gcG9zLmNoIDogc3AudG8gPiBwb3MuY2gpKSkge1xyXG4gICAgICAgIGlmIChtYXlDbGVhcikge1xyXG4gICAgICAgICAgc2lnbmFsKG0sIFwiYmVmb3JlQ3Vyc29yRW50ZXJcIik7XHJcbiAgICAgICAgICBpZiAobS5leHBsaWNpdGx5Q2xlYXJlZCkge1xyXG4gICAgICAgICAgICBpZiAoIWxpbmUubWFya2VkU3BhbnMpIGJyZWFrO1xyXG4gICAgICAgICAgICBlbHNlIHstLWk7IGNvbnRpbnVlO31cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKCFtLmF0b21pYykgY29udGludWU7XHJcblxyXG4gICAgICAgIGlmIChvbGRQb3MpIHtcclxuICAgICAgICAgIHZhciBuZWFyID0gbS5maW5kKGRpciA8IDAgPyAxIDogLTEpLCBkaWZmO1xyXG4gICAgICAgICAgaWYgKGRpciA8IDAgPyBtLmluY2x1c2l2ZVJpZ2h0IDogbS5pbmNsdXNpdmVMZWZ0KSBuZWFyID0gbW92ZVBvcyhkb2MsIG5lYXIsIC1kaXIsIGxpbmUpO1xyXG4gICAgICAgICAgaWYgKG5lYXIgJiYgbmVhci5saW5lID09IHBvcy5saW5lICYmIChkaWZmID0gY21wKG5lYXIsIG9sZFBvcykpICYmIChkaXIgPCAwID8gZGlmZiA8IDAgOiBkaWZmID4gMCkpXHJcbiAgICAgICAgICAgIHJldHVybiBza2lwQXRvbWljSW5uZXIoZG9jLCBuZWFyLCBwb3MsIGRpciwgbWF5Q2xlYXIpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgdmFyIGZhciA9IG0uZmluZChkaXIgPCAwID8gLTEgOiAxKTtcclxuICAgICAgICBpZiAoZGlyIDwgMCA/IG0uaW5jbHVzaXZlTGVmdCA6IG0uaW5jbHVzaXZlUmlnaHQpIGZhciA9IG1vdmVQb3MoZG9jLCBmYXIsIGRpciwgbGluZSk7XHJcbiAgICAgICAgcmV0dXJuIGZhciA/IHNraXBBdG9taWNJbm5lcihkb2MsIGZhciwgcG9zLCBkaXIsIG1heUNsZWFyKSA6IG51bGw7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBwb3M7XHJcbiAgfVxyXG5cclxuICAvLyBFbnN1cmUgYSBnaXZlbiBwb3NpdGlvbiBpcyBub3QgaW5zaWRlIGFuIGF0b21pYyByYW5nZS5cclxuICBmdW5jdGlvbiBza2lwQXRvbWljKGRvYywgcG9zLCBvbGRQb3MsIGJpYXMsIG1heUNsZWFyKSB7XHJcbiAgICB2YXIgZGlyID0gYmlhcyB8fCAxO1xyXG4gICAgdmFyIGZvdW5kID0gc2tpcEF0b21pY0lubmVyKGRvYywgcG9zLCBvbGRQb3MsIGRpciwgbWF5Q2xlYXIpIHx8XHJcbiAgICAgICAgKCFtYXlDbGVhciAmJiBza2lwQXRvbWljSW5uZXIoZG9jLCBwb3MsIG9sZFBvcywgZGlyLCB0cnVlKSkgfHxcclxuICAgICAgICBza2lwQXRvbWljSW5uZXIoZG9jLCBwb3MsIG9sZFBvcywgLWRpciwgbWF5Q2xlYXIpIHx8XHJcbiAgICAgICAgKCFtYXlDbGVhciAmJiBza2lwQXRvbWljSW5uZXIoZG9jLCBwb3MsIG9sZFBvcywgLWRpciwgdHJ1ZSkpO1xyXG4gICAgaWYgKCFmb3VuZCkge1xyXG4gICAgICBkb2MuY2FudEVkaXQgPSB0cnVlO1xyXG4gICAgICByZXR1cm4gUG9zKGRvYy5maXJzdCwgMCk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gZm91bmQ7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBtb3ZlUG9zKGRvYywgcG9zLCBkaXIsIGxpbmUpIHtcclxuICAgIGlmIChkaXIgPCAwICYmIHBvcy5jaCA9PSAwKSB7XHJcbiAgICAgIGlmIChwb3MubGluZSA+IGRvYy5maXJzdCkgcmV0dXJuIGNsaXBQb3MoZG9jLCBQb3MocG9zLmxpbmUgLSAxKSk7XHJcbiAgICAgIGVsc2UgcmV0dXJuIG51bGw7XHJcbiAgICB9IGVsc2UgaWYgKGRpciA+IDAgJiYgcG9zLmNoID09IChsaW5lIHx8IGdldExpbmUoZG9jLCBwb3MubGluZSkpLnRleHQubGVuZ3RoKSB7XHJcbiAgICAgIGlmIChwb3MubGluZSA8IGRvYy5maXJzdCArIGRvYy5zaXplIC0gMSkgcmV0dXJuIFBvcyhwb3MubGluZSArIDEsIDApO1xyXG4gICAgICBlbHNlIHJldHVybiBudWxsO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmV0dXJuIG5ldyBQb3MocG9zLmxpbmUsIHBvcy5jaCArIGRpcik7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTRUxFQ1RJT04gRFJBV0lOR1xyXG5cclxuICBmdW5jdGlvbiB1cGRhdGVTZWxlY3Rpb24oY20pIHtcclxuICAgIGNtLmRpc3BsYXkuaW5wdXQuc2hvd1NlbGVjdGlvbihjbS5kaXNwbGF5LmlucHV0LnByZXBhcmVTZWxlY3Rpb24oKSk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBwcmVwYXJlU2VsZWN0aW9uKGNtLCBwcmltYXJ5KSB7XHJcbiAgICB2YXIgZG9jID0gY20uZG9jLCByZXN1bHQgPSB7fTtcclxuICAgIHZhciBjdXJGcmFnbWVudCA9IHJlc3VsdC5jdXJzb3JzID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpO1xyXG4gICAgdmFyIHNlbEZyYWdtZW50ID0gcmVzdWx0LnNlbGVjdGlvbiA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtcclxuXHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGRvYy5zZWwucmFuZ2VzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIGlmIChwcmltYXJ5ID09PSBmYWxzZSAmJiBpID09IGRvYy5zZWwucHJpbUluZGV4KSBjb250aW51ZTtcclxuICAgICAgdmFyIHJhbmdlID0gZG9jLnNlbC5yYW5nZXNbaV07XHJcbiAgICAgIHZhciBjb2xsYXBzZWQgPSByYW5nZS5lbXB0eSgpO1xyXG4gICAgICBpZiAoY29sbGFwc2VkIHx8IGNtLm9wdGlvbnMuc2hvd0N1cnNvcldoZW5TZWxlY3RpbmcpXHJcbiAgICAgICAgZHJhd1NlbGVjdGlvbkN1cnNvcihjbSwgcmFuZ2UuaGVhZCwgY3VyRnJhZ21lbnQpO1xyXG4gICAgICBpZiAoIWNvbGxhcHNlZClcclxuICAgICAgICBkcmF3U2VsZWN0aW9uUmFuZ2UoY20sIHJhbmdlLCBzZWxGcmFnbWVudCk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH1cclxuXHJcbiAgLy8gRHJhd3MgYSBjdXJzb3IgZm9yIHRoZSBnaXZlbiByYW5nZVxyXG4gIGZ1bmN0aW9uIGRyYXdTZWxlY3Rpb25DdXJzb3IoY20sIGhlYWQsIG91dHB1dCkge1xyXG4gICAgdmFyIHBvcyA9IGN1cnNvckNvb3JkcyhjbSwgaGVhZCwgXCJkaXZcIiwgbnVsbCwgbnVsbCwgIWNtLm9wdGlvbnMuc2luZ2xlQ3Vyc29ySGVpZ2h0UGVyTGluZSk7XHJcblxyXG4gICAgdmFyIGN1cnNvciA9IG91dHB1dC5hcHBlbmRDaGlsZChlbHQoXCJkaXZcIiwgXCJcXHUwMGEwXCIsIFwiQ29kZU1pcnJvci1jdXJzb3JcIikpO1xyXG4gICAgY3Vyc29yLnN0eWxlLmxlZnQgPSBwb3MubGVmdCArIFwicHhcIjtcclxuICAgIGN1cnNvci5zdHlsZS50b3AgPSBwb3MudG9wICsgXCJweFwiO1xyXG4gICAgY3Vyc29yLnN0eWxlLmhlaWdodCA9IE1hdGgubWF4KDAsIHBvcy5ib3R0b20gLSBwb3MudG9wKSAqIGNtLm9wdGlvbnMuY3Vyc29ySGVpZ2h0ICsgXCJweFwiO1xyXG5cclxuICAgIGlmIChwb3Mub3RoZXIpIHtcclxuICAgICAgLy8gU2Vjb25kYXJ5IGN1cnNvciwgc2hvd24gd2hlbiBvbiBhICdqdW1wJyBpbiBiaS1kaXJlY3Rpb25hbCB0ZXh0XHJcbiAgICAgIHZhciBvdGhlckN1cnNvciA9IG91dHB1dC5hcHBlbmRDaGlsZChlbHQoXCJkaXZcIiwgXCJcXHUwMGEwXCIsIFwiQ29kZU1pcnJvci1jdXJzb3IgQ29kZU1pcnJvci1zZWNvbmRhcnljdXJzb3JcIikpO1xyXG4gICAgICBvdGhlckN1cnNvci5zdHlsZS5kaXNwbGF5ID0gXCJcIjtcclxuICAgICAgb3RoZXJDdXJzb3Iuc3R5bGUubGVmdCA9IHBvcy5vdGhlci5sZWZ0ICsgXCJweFwiO1xyXG4gICAgICBvdGhlckN1cnNvci5zdHlsZS50b3AgPSBwb3Mub3RoZXIudG9wICsgXCJweFwiO1xyXG4gICAgICBvdGhlckN1cnNvci5zdHlsZS5oZWlnaHQgPSAocG9zLm90aGVyLmJvdHRvbSAtIHBvcy5vdGhlci50b3ApICogLjg1ICsgXCJweFwiO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRHJhd3MgdGhlIGdpdmVuIHJhbmdlIGFzIGEgaGlnaGxpZ2h0ZWQgc2VsZWN0aW9uXHJcbiAgZnVuY3Rpb24gZHJhd1NlbGVjdGlvblJhbmdlKGNtLCByYW5nZSwgb3V0cHV0KSB7XHJcbiAgICB2YXIgZGlzcGxheSA9IGNtLmRpc3BsYXksIGRvYyA9IGNtLmRvYztcclxuICAgIHZhciBmcmFnbWVudCA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtcclxuICAgIHZhciBwYWRkaW5nID0gcGFkZGluZ0goY20uZGlzcGxheSksIGxlZnRTaWRlID0gcGFkZGluZy5sZWZ0O1xyXG4gICAgdmFyIHJpZ2h0U2lkZSA9IE1hdGgubWF4KGRpc3BsYXkuc2l6ZXJXaWR0aCwgZGlzcGxheVdpZHRoKGNtKSAtIGRpc3BsYXkuc2l6ZXIub2Zmc2V0TGVmdCkgLSBwYWRkaW5nLnJpZ2h0O1xyXG5cclxuICAgIGZ1bmN0aW9uIGFkZChsZWZ0LCB0b3AsIHdpZHRoLCBib3R0b20pIHtcclxuICAgICAgaWYgKHRvcCA8IDApIHRvcCA9IDA7XHJcbiAgICAgIHRvcCA9IE1hdGgucm91bmQodG9wKTtcclxuICAgICAgYm90dG9tID0gTWF0aC5yb3VuZChib3R0b20pO1xyXG4gICAgICBmcmFnbWVudC5hcHBlbmRDaGlsZChlbHQoXCJkaXZcIiwgbnVsbCwgXCJDb2RlTWlycm9yLXNlbGVjdGVkXCIsIFwicG9zaXRpb246IGFic29sdXRlOyBsZWZ0OiBcIiArIGxlZnQgK1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJweDsgdG9wOiBcIiArIHRvcCArIFwicHg7IHdpZHRoOiBcIiArICh3aWR0aCA9PSBudWxsID8gcmlnaHRTaWRlIC0gbGVmdCA6IHdpZHRoKSArXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcInB4OyBoZWlnaHQ6IFwiICsgKGJvdHRvbSAtIHRvcCkgKyBcInB4XCIpKTtcclxuICAgIH1cclxuXHJcbiAgICBmdW5jdGlvbiBkcmF3Rm9yTGluZShsaW5lLCBmcm9tQXJnLCB0b0FyZykge1xyXG4gICAgICB2YXIgbGluZU9iaiA9IGdldExpbmUoZG9jLCBsaW5lKTtcclxuICAgICAgdmFyIGxpbmVMZW4gPSBsaW5lT2JqLnRleHQubGVuZ3RoO1xyXG4gICAgICB2YXIgc3RhcnQsIGVuZDtcclxuICAgICAgZnVuY3Rpb24gY29vcmRzKGNoLCBiaWFzKSB7XHJcbiAgICAgICAgcmV0dXJuIGNoYXJDb29yZHMoY20sIFBvcyhsaW5lLCBjaCksIFwiZGl2XCIsIGxpbmVPYmosIGJpYXMpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpdGVyYXRlQmlkaVNlY3Rpb25zKGdldE9yZGVyKGxpbmVPYmopLCBmcm9tQXJnIHx8IDAsIHRvQXJnID09IG51bGwgPyBsaW5lTGVuIDogdG9BcmcsIGZ1bmN0aW9uKGZyb20sIHRvLCBkaXIpIHtcclxuICAgICAgICB2YXIgbGVmdFBvcyA9IGNvb3Jkcyhmcm9tLCBcImxlZnRcIiksIHJpZ2h0UG9zLCBsZWZ0LCByaWdodDtcclxuICAgICAgICBpZiAoZnJvbSA9PSB0bykge1xyXG4gICAgICAgICAgcmlnaHRQb3MgPSBsZWZ0UG9zO1xyXG4gICAgICAgICAgbGVmdCA9IHJpZ2h0ID0gbGVmdFBvcy5sZWZ0O1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICByaWdodFBvcyA9IGNvb3Jkcyh0byAtIDEsIFwicmlnaHRcIik7XHJcbiAgICAgICAgICBpZiAoZGlyID09IFwicnRsXCIpIHsgdmFyIHRtcCA9IGxlZnRQb3M7IGxlZnRQb3MgPSByaWdodFBvczsgcmlnaHRQb3MgPSB0bXA7IH1cclxuICAgICAgICAgIGxlZnQgPSBsZWZ0UG9zLmxlZnQ7XHJcbiAgICAgICAgICByaWdodCA9IHJpZ2h0UG9zLnJpZ2h0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoZnJvbUFyZyA9PSBudWxsICYmIGZyb20gPT0gMCkgbGVmdCA9IGxlZnRTaWRlO1xyXG4gICAgICAgIGlmIChyaWdodFBvcy50b3AgLSBsZWZ0UG9zLnRvcCA+IDMpIHsgLy8gRGlmZmVyZW50IGxpbmVzLCBkcmF3IHRvcCBwYXJ0XHJcbiAgICAgICAgICBhZGQobGVmdCwgbGVmdFBvcy50b3AsIG51bGwsIGxlZnRQb3MuYm90dG9tKTtcclxuICAgICAgICAgIGxlZnQgPSBsZWZ0U2lkZTtcclxuICAgICAgICAgIGlmIChsZWZ0UG9zLmJvdHRvbSA8IHJpZ2h0UG9zLnRvcCkgYWRkKGxlZnQsIGxlZnRQb3MuYm90dG9tLCBudWxsLCByaWdodFBvcy50b3ApO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodG9BcmcgPT0gbnVsbCAmJiB0byA9PSBsaW5lTGVuKSByaWdodCA9IHJpZ2h0U2lkZTtcclxuICAgICAgICBpZiAoIXN0YXJ0IHx8IGxlZnRQb3MudG9wIDwgc3RhcnQudG9wIHx8IGxlZnRQb3MudG9wID09IHN0YXJ0LnRvcCAmJiBsZWZ0UG9zLmxlZnQgPCBzdGFydC5sZWZ0KVxyXG4gICAgICAgICAgc3RhcnQgPSBsZWZ0UG9zO1xyXG4gICAgICAgIGlmICghZW5kIHx8IHJpZ2h0UG9zLmJvdHRvbSA+IGVuZC5ib3R0b20gfHwgcmlnaHRQb3MuYm90dG9tID09IGVuZC5ib3R0b20gJiYgcmlnaHRQb3MucmlnaHQgPiBlbmQucmlnaHQpXHJcbiAgICAgICAgICBlbmQgPSByaWdodFBvcztcclxuICAgICAgICBpZiAobGVmdCA8IGxlZnRTaWRlICsgMSkgbGVmdCA9IGxlZnRTaWRlO1xyXG4gICAgICAgIGFkZChsZWZ0LCByaWdodFBvcy50b3AsIHJpZ2h0IC0gbGVmdCwgcmlnaHRQb3MuYm90dG9tKTtcclxuICAgICAgfSk7XHJcbiAgICAgIHJldHVybiB7c3RhcnQ6IHN0YXJ0LCBlbmQ6IGVuZH07XHJcbiAgICB9XHJcblxyXG4gICAgdmFyIHNGcm9tID0gcmFuZ2UuZnJvbSgpLCBzVG8gPSByYW5nZS50bygpO1xyXG4gICAgaWYgKHNGcm9tLmxpbmUgPT0gc1RvLmxpbmUpIHtcclxuICAgICAgZHJhd0ZvckxpbmUoc0Zyb20ubGluZSwgc0Zyb20uY2gsIHNUby5jaCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB2YXIgZnJvbUxpbmUgPSBnZXRMaW5lKGRvYywgc0Zyb20ubGluZSksIHRvTGluZSA9IGdldExpbmUoZG9jLCBzVG8ubGluZSk7XHJcbiAgICAgIHZhciBzaW5nbGVWTGluZSA9IHZpc3VhbExpbmUoZnJvbUxpbmUpID09IHZpc3VhbExpbmUodG9MaW5lKTtcclxuICAgICAgdmFyIGxlZnRFbmQgPSBkcmF3Rm9yTGluZShzRnJvbS5saW5lLCBzRnJvbS5jaCwgc2luZ2xlVkxpbmUgPyBmcm9tTGluZS50ZXh0Lmxlbmd0aCArIDEgOiBudWxsKS5lbmQ7XHJcbiAgICAgIHZhciByaWdodFN0YXJ0ID0gZHJhd0ZvckxpbmUoc1RvLmxpbmUsIHNpbmdsZVZMaW5lID8gMCA6IG51bGwsIHNUby5jaCkuc3RhcnQ7XHJcbiAgICAgIGlmIChzaW5nbGVWTGluZSkge1xyXG4gICAgICAgIGlmIChsZWZ0RW5kLnRvcCA8IHJpZ2h0U3RhcnQudG9wIC0gMikge1xyXG4gICAgICAgICAgYWRkKGxlZnRFbmQucmlnaHQsIGxlZnRFbmQudG9wLCBudWxsLCBsZWZ0RW5kLmJvdHRvbSk7XHJcbiAgICAgICAgICBhZGQobGVmdFNpZGUsIHJpZ2h0U3RhcnQudG9wLCByaWdodFN0YXJ0LmxlZnQsIHJpZ2h0U3RhcnQuYm90dG9tKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgYWRkKGxlZnRFbmQucmlnaHQsIGxlZnRFbmQudG9wLCByaWdodFN0YXJ0LmxlZnQgLSBsZWZ0RW5kLnJpZ2h0LCBsZWZ0RW5kLmJvdHRvbSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGlmIChsZWZ0RW5kLmJvdHRvbSA8IHJpZ2h0U3RhcnQudG9wKVxyXG4gICAgICAgIGFkZChsZWZ0U2lkZSwgbGVmdEVuZC5ib3R0b20sIG51bGwsIHJpZ2h0U3RhcnQudG9wKTtcclxuICAgIH1cclxuXHJcbiAgICBvdXRwdXQuYXBwZW5kQ2hpbGQoZnJhZ21lbnQpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3Vyc29yLWJsaW5raW5nXHJcbiAgZnVuY3Rpb24gcmVzdGFydEJsaW5rKGNtKSB7XHJcbiAgICBpZiAoIWNtLnN0YXRlLmZvY3VzZWQpIHJldHVybjtcclxuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheTtcclxuICAgIGNsZWFySW50ZXJ2YWwoZGlzcGxheS5ibGlua2VyKTtcclxuICAgIHZhciBvbiA9IHRydWU7XHJcbiAgICBkaXNwbGF5LmN1cnNvckRpdi5zdHlsZS52aXNpYmlsaXR5ID0gXCJcIjtcclxuICAgIGlmIChjbS5vcHRpb25zLmN1cnNvckJsaW5rUmF0ZSA+IDApXHJcbiAgICAgIGRpc3BsYXkuYmxpbmtlciA9IHNldEludGVydmFsKGZ1bmN0aW9uKCkge1xyXG4gICAgICAgIGRpc3BsYXkuY3Vyc29yRGl2LnN0eWxlLnZpc2liaWxpdHkgPSAob24gPSAhb24pID8gXCJcIiA6IFwiaGlkZGVuXCI7XHJcbiAgICAgIH0sIGNtLm9wdGlvbnMuY3Vyc29yQmxpbmtSYXRlKTtcclxuICAgIGVsc2UgaWYgKGNtLm9wdGlvbnMuY3Vyc29yQmxpbmtSYXRlIDwgMClcclxuICAgICAgZGlzcGxheS5jdXJzb3JEaXYuc3R5bGUudmlzaWJpbGl0eSA9IFwiaGlkZGVuXCI7XHJcbiAgfVxyXG5cclxuICAvLyBISUdITElHSFQgV09SS0VSXHJcblxyXG4gIGZ1bmN0aW9uIHN0YXJ0V29ya2VyKGNtLCB0aW1lKSB7XHJcbiAgICBpZiAoY20uZG9jLm1vZGUuc3RhcnRTdGF0ZSAmJiBjbS5kb2MuZnJvbnRpZXIgPCBjbS5kaXNwbGF5LnZpZXdUbylcclxuICAgICAgY20uc3RhdGUuaGlnaGxpZ2h0LnNldCh0aW1lLCBiaW5kKGhpZ2hsaWdodFdvcmtlciwgY20pKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGhpZ2hsaWdodFdvcmtlcihjbSkge1xyXG4gICAgdmFyIGRvYyA9IGNtLmRvYztcclxuICAgIGlmIChkb2MuZnJvbnRpZXIgPCBkb2MuZmlyc3QpIGRvYy5mcm9udGllciA9IGRvYy5maXJzdDtcclxuICAgIGlmIChkb2MuZnJvbnRpZXIgPj0gY20uZGlzcGxheS52aWV3VG8pIHJldHVybjtcclxuICAgIHZhciBlbmQgPSArbmV3IERhdGUgKyBjbS5vcHRpb25zLndvcmtUaW1lO1xyXG4gICAgdmFyIHN0YXRlID0gY29weVN0YXRlKGRvYy5tb2RlLCBnZXRTdGF0ZUJlZm9yZShjbSwgZG9jLmZyb250aWVyKSk7XHJcbiAgICB2YXIgY2hhbmdlZExpbmVzID0gW107XHJcblxyXG4gICAgZG9jLml0ZXIoZG9jLmZyb250aWVyLCBNYXRoLm1pbihkb2MuZmlyc3QgKyBkb2Muc2l6ZSwgY20uZGlzcGxheS52aWV3VG8gKyA1MDApLCBmdW5jdGlvbihsaW5lKSB7XHJcbiAgICAgIGlmIChkb2MuZnJvbnRpZXIgPj0gY20uZGlzcGxheS52aWV3RnJvbSkgeyAvLyBWaXNpYmxlXHJcbiAgICAgICAgdmFyIG9sZFN0eWxlcyA9IGxpbmUuc3R5bGVzLCB0b29Mb25nID0gbGluZS50ZXh0Lmxlbmd0aCA+IGNtLm9wdGlvbnMubWF4SGlnaGxpZ2h0TGVuZ3RoO1xyXG4gICAgICAgIHZhciBoaWdobGlnaHRlZCA9IGhpZ2hsaWdodExpbmUoY20sIGxpbmUsIHRvb0xvbmcgPyBjb3B5U3RhdGUoZG9jLm1vZGUsIHN0YXRlKSA6IHN0YXRlLCB0cnVlKTtcclxuICAgICAgICBsaW5lLnN0eWxlcyA9IGhpZ2hsaWdodGVkLnN0eWxlcztcclxuICAgICAgICB2YXIgb2xkQ2xzID0gbGluZS5zdHlsZUNsYXNzZXMsIG5ld0NscyA9IGhpZ2hsaWdodGVkLmNsYXNzZXM7XHJcbiAgICAgICAgaWYgKG5ld0NscykgbGluZS5zdHlsZUNsYXNzZXMgPSBuZXdDbHM7XHJcbiAgICAgICAgZWxzZSBpZiAob2xkQ2xzKSBsaW5lLnN0eWxlQ2xhc3NlcyA9IG51bGw7XHJcbiAgICAgICAgdmFyIGlzY2hhbmdlID0gIW9sZFN0eWxlcyB8fCBvbGRTdHlsZXMubGVuZ3RoICE9IGxpbmUuc3R5bGVzLmxlbmd0aCB8fFxyXG4gICAgICAgICAgb2xkQ2xzICE9IG5ld0NscyAmJiAoIW9sZENscyB8fCAhbmV3Q2xzIHx8IG9sZENscy5iZ0NsYXNzICE9IG5ld0Nscy5iZ0NsYXNzIHx8IG9sZENscy50ZXh0Q2xhc3MgIT0gbmV3Q2xzLnRleHRDbGFzcyk7XHJcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7ICFpc2NoYW5nZSAmJiBpIDwgb2xkU3R5bGVzLmxlbmd0aDsgKytpKSBpc2NoYW5nZSA9IG9sZFN0eWxlc1tpXSAhPSBsaW5lLnN0eWxlc1tpXTtcclxuICAgICAgICBpZiAoaXNjaGFuZ2UpIGNoYW5nZWRMaW5lcy5wdXNoKGRvYy5mcm9udGllcik7XHJcbiAgICAgICAgbGluZS5zdGF0ZUFmdGVyID0gdG9vTG9uZyA/IHN0YXRlIDogY29weVN0YXRlKGRvYy5tb2RlLCBzdGF0ZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgaWYgKGxpbmUudGV4dC5sZW5ndGggPD0gY20ub3B0aW9ucy5tYXhIaWdobGlnaHRMZW5ndGgpXHJcbiAgICAgICAgICBwcm9jZXNzTGluZShjbSwgbGluZS50ZXh0LCBzdGF0ZSk7XHJcbiAgICAgICAgbGluZS5zdGF0ZUFmdGVyID0gZG9jLmZyb250aWVyICUgNSA9PSAwID8gY29weVN0YXRlKGRvYy5tb2RlLCBzdGF0ZSkgOiBudWxsO1xyXG4gICAgICB9XHJcbiAgICAgICsrZG9jLmZyb250aWVyO1xyXG4gICAgICBpZiAoK25ldyBEYXRlID4gZW5kKSB7XHJcbiAgICAgICAgc3RhcnRXb3JrZXIoY20sIGNtLm9wdGlvbnMud29ya0RlbGF5KTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgICBpZiAoY2hhbmdlZExpbmVzLmxlbmd0aCkgcnVuSW5PcChjbSwgZnVuY3Rpb24oKSB7XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2hhbmdlZExpbmVzLmxlbmd0aDsgaSsrKVxyXG4gICAgICAgIHJlZ0xpbmVDaGFuZ2UoY20sIGNoYW5nZWRMaW5lc1tpXSwgXCJ0ZXh0XCIpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvLyBGaW5kcyB0aGUgbGluZSB0byBzdGFydCB3aXRoIHdoZW4gc3RhcnRpbmcgYSBwYXJzZS4gVHJpZXMgdG9cclxuICAvLyBmaW5kIGEgbGluZSB3aXRoIGEgc3RhdGVBZnRlciwgc28gdGhhdCBpdCBjYW4gc3RhcnQgd2l0aCBhXHJcbiAgLy8gdmFsaWQgc3RhdGUuIElmIHRoYXQgZmFpbHMsIGl0IHJldHVybnMgdGhlIGxpbmUgd2l0aCB0aGVcclxuICAvLyBzbWFsbGVzdCBpbmRlbnRhdGlvbiwgd2hpY2ggdGVuZHMgdG8gbmVlZCB0aGUgbGVhc3QgY29udGV4dCB0b1xyXG4gIC8vIHBhcnNlIGNvcnJlY3RseS5cclxuICBmdW5jdGlvbiBmaW5kU3RhcnRMaW5lKGNtLCBuLCBwcmVjaXNlKSB7XHJcbiAgICB2YXIgbWluaW5kZW50LCBtaW5saW5lLCBkb2MgPSBjbS5kb2M7XHJcbiAgICB2YXIgbGltID0gcHJlY2lzZSA/IC0xIDogbiAtIChjbS5kb2MubW9kZS5pbm5lck1vZGUgPyAxMDAwIDogMTAwKTtcclxuICAgIGZvciAodmFyIHNlYXJjaCA9IG47IHNlYXJjaCA+IGxpbTsgLS1zZWFyY2gpIHtcclxuICAgICAgaWYgKHNlYXJjaCA8PSBkb2MuZmlyc3QpIHJldHVybiBkb2MuZmlyc3Q7XHJcbiAgICAgIHZhciBsaW5lID0gZ2V0TGluZShkb2MsIHNlYXJjaCAtIDEpO1xyXG4gICAgICBpZiAobGluZS5zdGF0ZUFmdGVyICYmICghcHJlY2lzZSB8fCBzZWFyY2ggPD0gZG9jLmZyb250aWVyKSkgcmV0dXJuIHNlYXJjaDtcclxuICAgICAgdmFyIGluZGVudGVkID0gY291bnRDb2x1bW4obGluZS50ZXh0LCBudWxsLCBjbS5vcHRpb25zLnRhYlNpemUpO1xyXG4gICAgICBpZiAobWlubGluZSA9PSBudWxsIHx8IG1pbmluZGVudCA+IGluZGVudGVkKSB7XHJcbiAgICAgICAgbWlubGluZSA9IHNlYXJjaCAtIDE7XHJcbiAgICAgICAgbWluaW5kZW50ID0gaW5kZW50ZWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBtaW5saW5lO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gZ2V0U3RhdGVCZWZvcmUoY20sIG4sIHByZWNpc2UpIHtcclxuICAgIHZhciBkb2MgPSBjbS5kb2MsIGRpc3BsYXkgPSBjbS5kaXNwbGF5O1xyXG4gICAgaWYgKCFkb2MubW9kZS5zdGFydFN0YXRlKSByZXR1cm4gdHJ1ZTtcclxuICAgIHZhciBwb3MgPSBmaW5kU3RhcnRMaW5lKGNtLCBuLCBwcmVjaXNlKSwgc3RhdGUgPSBwb3MgPiBkb2MuZmlyc3QgJiYgZ2V0TGluZShkb2MsIHBvcy0xKS5zdGF0ZUFmdGVyO1xyXG4gICAgaWYgKCFzdGF0ZSkgc3RhdGUgPSBzdGFydFN0YXRlKGRvYy5tb2RlKTtcclxuICAgIGVsc2Ugc3RhdGUgPSBjb3B5U3RhdGUoZG9jLm1vZGUsIHN0YXRlKTtcclxuICAgIGRvYy5pdGVyKHBvcywgbiwgZnVuY3Rpb24obGluZSkge1xyXG4gICAgICBwcm9jZXNzTGluZShjbSwgbGluZS50ZXh0LCBzdGF0ZSk7XHJcbiAgICAgIHZhciBzYXZlID0gcG9zID09IG4gLSAxIHx8IHBvcyAlIDUgPT0gMCB8fCBwb3MgPj0gZGlzcGxheS52aWV3RnJvbSAmJiBwb3MgPCBkaXNwbGF5LnZpZXdUbztcclxuICAgICAgbGluZS5zdGF0ZUFmdGVyID0gc2F2ZSA/IGNvcHlTdGF0ZShkb2MubW9kZSwgc3RhdGUpIDogbnVsbDtcclxuICAgICAgKytwb3M7XHJcbiAgICB9KTtcclxuICAgIGlmIChwcmVjaXNlKSBkb2MuZnJvbnRpZXIgPSBwb3M7XHJcbiAgICByZXR1cm4gc3RhdGU7XHJcbiAgfVxyXG5cclxuICAvLyBQT1NJVElPTiBNRUFTVVJFTUVOVFxyXG5cclxuICBmdW5jdGlvbiBwYWRkaW5nVG9wKGRpc3BsYXkpIHtyZXR1cm4gZGlzcGxheS5saW5lU3BhY2Uub2Zmc2V0VG9wO31cclxuICBmdW5jdGlvbiBwYWRkaW5nVmVydChkaXNwbGF5KSB7cmV0dXJuIGRpc3BsYXkubW92ZXIub2Zmc2V0SGVpZ2h0IC0gZGlzcGxheS5saW5lU3BhY2Uub2Zmc2V0SGVpZ2h0O31cclxuICBmdW5jdGlvbiBwYWRkaW5nSChkaXNwbGF5KSB7XHJcbiAgICBpZiAoZGlzcGxheS5jYWNoZWRQYWRkaW5nSCkgcmV0dXJuIGRpc3BsYXkuY2FjaGVkUGFkZGluZ0g7XHJcbiAgICB2YXIgZSA9IHJlbW92ZUNoaWxkcmVuQW5kQWRkKGRpc3BsYXkubWVhc3VyZSwgZWx0KFwicHJlXCIsIFwieFwiKSk7XHJcbiAgICB2YXIgc3R5bGUgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZSA/IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGUpIDogZS5jdXJyZW50U3R5bGU7XHJcbiAgICB2YXIgZGF0YSA9IHtsZWZ0OiBwYXJzZUludChzdHlsZS5wYWRkaW5nTGVmdCksIHJpZ2h0OiBwYXJzZUludChzdHlsZS5wYWRkaW5nUmlnaHQpfTtcclxuICAgIGlmICghaXNOYU4oZGF0YS5sZWZ0KSAmJiAhaXNOYU4oZGF0YS5yaWdodCkpIGRpc3BsYXkuY2FjaGVkUGFkZGluZ0ggPSBkYXRhO1xyXG4gICAgcmV0dXJuIGRhdGE7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBzY3JvbGxHYXAoY20pIHsgcmV0dXJuIHNjcm9sbGVyR2FwIC0gY20uZGlzcGxheS5uYXRpdmVCYXJXaWR0aDsgfVxyXG4gIGZ1bmN0aW9uIGRpc3BsYXlXaWR0aChjbSkge1xyXG4gICAgcmV0dXJuIGNtLmRpc3BsYXkuc2Nyb2xsZXIuY2xpZW50V2lkdGggLSBzY3JvbGxHYXAoY20pIC0gY20uZGlzcGxheS5iYXJXaWR0aDtcclxuICB9XHJcbiAgZnVuY3Rpb24gZGlzcGxheUhlaWdodChjbSkge1xyXG4gICAgcmV0dXJuIGNtLmRpc3BsYXkuc2Nyb2xsZXIuY2xpZW50SGVpZ2h0IC0gc2Nyb2xsR2FwKGNtKSAtIGNtLmRpc3BsYXkuYmFySGVpZ2h0O1xyXG4gIH1cclxuXHJcbiAgLy8gRW5zdXJlIHRoZSBsaW5lVmlldy53cmFwcGluZy5oZWlnaHRzIGFycmF5IGlzIHBvcHVsYXRlZC4gVGhpcyBpc1xyXG4gIC8vIGFuIGFycmF5IG9mIGJvdHRvbSBvZmZzZXRzIGZvciB0aGUgbGluZXMgdGhhdCBtYWtlIHVwIGEgZHJhd25cclxuICAvLyBsaW5lLiBXaGVuIGxpbmVXcmFwcGluZyBpcyBvbiwgdGhlcmUgbWlnaHQgYmUgbW9yZSB0aGFuIG9uZVxyXG4gIC8vIGhlaWdodC5cclxuICBmdW5jdGlvbiBlbnN1cmVMaW5lSGVpZ2h0cyhjbSwgbGluZVZpZXcsIHJlY3QpIHtcclxuICAgIHZhciB3cmFwcGluZyA9IGNtLm9wdGlvbnMubGluZVdyYXBwaW5nO1xyXG4gICAgdmFyIGN1cldpZHRoID0gd3JhcHBpbmcgJiYgZGlzcGxheVdpZHRoKGNtKTtcclxuICAgIGlmICghbGluZVZpZXcubWVhc3VyZS5oZWlnaHRzIHx8IHdyYXBwaW5nICYmIGxpbmVWaWV3Lm1lYXN1cmUud2lkdGggIT0gY3VyV2lkdGgpIHtcclxuICAgICAgdmFyIGhlaWdodHMgPSBsaW5lVmlldy5tZWFzdXJlLmhlaWdodHMgPSBbXTtcclxuICAgICAgaWYgKHdyYXBwaW5nKSB7XHJcbiAgICAgICAgbGluZVZpZXcubWVhc3VyZS53aWR0aCA9IGN1cldpZHRoO1xyXG4gICAgICAgIHZhciByZWN0cyA9IGxpbmVWaWV3LnRleHQuZmlyc3RDaGlsZC5nZXRDbGllbnRSZWN0cygpO1xyXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmVjdHMubGVuZ3RoIC0gMTsgaSsrKSB7XHJcbiAgICAgICAgICB2YXIgY3VyID0gcmVjdHNbaV0sIG5leHQgPSByZWN0c1tpICsgMV07XHJcbiAgICAgICAgICBpZiAoTWF0aC5hYnMoY3VyLmJvdHRvbSAtIG5leHQuYm90dG9tKSA+IDIpXHJcbiAgICAgICAgICAgIGhlaWdodHMucHVzaCgoY3VyLmJvdHRvbSArIG5leHQudG9wKSAvIDIgLSByZWN0LnRvcCk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGhlaWdodHMucHVzaChyZWN0LmJvdHRvbSAtIHJlY3QudG9wKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbmQgYSBsaW5lIG1hcCAobWFwcGluZyBjaGFyYWN0ZXIgb2Zmc2V0cyB0byB0ZXh0IG5vZGVzKSBhbmQgYVxyXG4gIC8vIG1lYXN1cmVtZW50IGNhY2hlIGZvciB0aGUgZ2l2ZW4gbGluZSBudW1iZXIuIChBIGxpbmUgdmlldyBtaWdodFxyXG4gIC8vIGNvbnRhaW4gbXVsdGlwbGUgbGluZXMgd2hlbiBjb2xsYXBzZWQgcmFuZ2VzIGFyZSBwcmVzZW50LilcclxuICBmdW5jdGlvbiBtYXBGcm9tTGluZVZpZXcobGluZVZpZXcsIGxpbmUsIGxpbmVOKSB7XHJcbiAgICBpZiAobGluZVZpZXcubGluZSA9PSBsaW5lKVxyXG4gICAgICByZXR1cm4ge21hcDogbGluZVZpZXcubWVhc3VyZS5tYXAsIGNhY2hlOiBsaW5lVmlldy5tZWFzdXJlLmNhY2hlfTtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZVZpZXcucmVzdC5sZW5ndGg7IGkrKylcclxuICAgICAgaWYgKGxpbmVWaWV3LnJlc3RbaV0gPT0gbGluZSlcclxuICAgICAgICByZXR1cm4ge21hcDogbGluZVZpZXcubWVhc3VyZS5tYXBzW2ldLCBjYWNoZTogbGluZVZpZXcubWVhc3VyZS5jYWNoZXNbaV19O1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaW5lVmlldy5yZXN0Lmxlbmd0aDsgaSsrKVxyXG4gICAgICBpZiAobGluZU5vKGxpbmVWaWV3LnJlc3RbaV0pID4gbGluZU4pXHJcbiAgICAgICAgcmV0dXJuIHttYXA6IGxpbmVWaWV3Lm1lYXN1cmUubWFwc1tpXSwgY2FjaGU6IGxpbmVWaWV3Lm1lYXN1cmUuY2FjaGVzW2ldLCBiZWZvcmU6IHRydWV9O1xyXG4gIH1cclxuXHJcbiAgLy8gUmVuZGVyIGEgbGluZSBpbnRvIHRoZSBoaWRkZW4gbm9kZSBkaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQuIFVzZWRcclxuICAvLyB3aGVuIG1lYXN1cmVtZW50IGlzIG5lZWRlZCBmb3IgYSBsaW5lIHRoYXQncyBub3QgaW4gdGhlIHZpZXdwb3J0LlxyXG4gIGZ1bmN0aW9uIHVwZGF0ZUV4dGVybmFsTWVhc3VyZW1lbnQoY20sIGxpbmUpIHtcclxuICAgIGxpbmUgPSB2aXN1YWxMaW5lKGxpbmUpO1xyXG4gICAgdmFyIGxpbmVOID0gbGluZU5vKGxpbmUpO1xyXG4gICAgdmFyIHZpZXcgPSBjbS5kaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQgPSBuZXcgTGluZVZpZXcoY20uZG9jLCBsaW5lLCBsaW5lTik7XHJcbiAgICB2aWV3LmxpbmVOID0gbGluZU47XHJcbiAgICB2YXIgYnVpbHQgPSB2aWV3LmJ1aWx0ID0gYnVpbGRMaW5lQ29udGVudChjbSwgdmlldyk7XHJcbiAgICB2aWV3LnRleHQgPSBidWlsdC5wcmU7XHJcbiAgICByZW1vdmVDaGlsZHJlbkFuZEFkZChjbS5kaXNwbGF5LmxpbmVNZWFzdXJlLCBidWlsdC5wcmUpO1xyXG4gICAgcmV0dXJuIHZpZXc7XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgYSB7dG9wLCBib3R0b20sIGxlZnQsIHJpZ2h0fSBib3ggKGluIGxpbmUtbG9jYWwgY29vcmRpbmF0ZXMpXHJcbiAgLy8gZm9yIGEgZ2l2ZW4gY2hhcmFjdGVyLlxyXG4gIGZ1bmN0aW9uIG1lYXN1cmVDaGFyKGNtLCBsaW5lLCBjaCwgYmlhcykge1xyXG4gICAgcmV0dXJuIG1lYXN1cmVDaGFyUHJlcGFyZWQoY20sIHByZXBhcmVNZWFzdXJlRm9yTGluZShjbSwgbGluZSksIGNoLCBiaWFzKTtcclxuICB9XHJcblxyXG4gIC8vIEZpbmQgYSBsaW5lIHZpZXcgdGhhdCBjb3JyZXNwb25kcyB0byB0aGUgZ2l2ZW4gbGluZSBudW1iZXIuXHJcbiAgZnVuY3Rpb24gZmluZFZpZXdGb3JMaW5lKGNtLCBsaW5lTikge1xyXG4gICAgaWYgKGxpbmVOID49IGNtLmRpc3BsYXkudmlld0Zyb20gJiYgbGluZU4gPCBjbS5kaXNwbGF5LnZpZXdUbylcclxuICAgICAgcmV0dXJuIGNtLmRpc3BsYXkudmlld1tmaW5kVmlld0luZGV4KGNtLCBsaW5lTildO1xyXG4gICAgdmFyIGV4dCA9IGNtLmRpc3BsYXkuZXh0ZXJuYWxNZWFzdXJlZDtcclxuICAgIGlmIChleHQgJiYgbGluZU4gPj0gZXh0LmxpbmVOICYmIGxpbmVOIDwgZXh0LmxpbmVOICsgZXh0LnNpemUpXHJcbiAgICAgIHJldHVybiBleHQ7XHJcbiAgfVxyXG5cclxuICAvLyBNZWFzdXJlbWVudCBjYW4gYmUgc3BsaXQgaW4gdHdvIHN0ZXBzLCB0aGUgc2V0LXVwIHdvcmsgdGhhdFxyXG4gIC8vIGFwcGxpZXMgdG8gdGhlIHdob2xlIGxpbmUsIGFuZCB0aGUgbWVhc3VyZW1lbnQgb2YgdGhlIGFjdHVhbFxyXG4gIC8vIGNoYXJhY3Rlci4gRnVuY3Rpb25zIGxpa2UgY29vcmRzQ2hhciwgdGhhdCBuZWVkIHRvIGRvIGEgbG90IG9mXHJcbiAgLy8gbWVhc3VyZW1lbnRzIGluIGEgcm93LCBjYW4gdGh1cyBlbnN1cmUgdGhhdCB0aGUgc2V0LXVwIHdvcmsgaXNcclxuICAvLyBvbmx5IGRvbmUgb25jZS5cclxuICBmdW5jdGlvbiBwcmVwYXJlTWVhc3VyZUZvckxpbmUoY20sIGxpbmUpIHtcclxuICAgIHZhciBsaW5lTiA9IGxpbmVObyhsaW5lKTtcclxuICAgIHZhciB2aWV3ID0gZmluZFZpZXdGb3JMaW5lKGNtLCBsaW5lTik7XHJcbiAgICBpZiAodmlldyAmJiAhdmlldy50ZXh0KSB7XHJcbiAgICAgIHZpZXcgPSBudWxsO1xyXG4gICAgfSBlbHNlIGlmICh2aWV3ICYmIHZpZXcuY2hhbmdlcykge1xyXG4gICAgICB1cGRhdGVMaW5lRm9yQ2hhbmdlcyhjbSwgdmlldywgbGluZU4sIGdldERpbWVuc2lvbnMoY20pKTtcclxuICAgICAgY20uY3VyT3AuZm9yY2VVcGRhdGUgPSB0cnVlO1xyXG4gICAgfVxyXG4gICAgaWYgKCF2aWV3KVxyXG4gICAgICB2aWV3ID0gdXBkYXRlRXh0ZXJuYWxNZWFzdXJlbWVudChjbSwgbGluZSk7XHJcblxyXG4gICAgdmFyIGluZm8gPSBtYXBGcm9tTGluZVZpZXcodmlldywgbGluZSwgbGluZU4pO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgbGluZTogbGluZSwgdmlldzogdmlldywgcmVjdDogbnVsbCxcclxuICAgICAgbWFwOiBpbmZvLm1hcCwgY2FjaGU6IGluZm8uY2FjaGUsIGJlZm9yZTogaW5mby5iZWZvcmUsXHJcbiAgICAgIGhhc0hlaWdodHM6IGZhbHNlXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgLy8gR2l2ZW4gYSBwcmVwYXJlZCBtZWFzdXJlbWVudCBvYmplY3QsIG1lYXN1cmVzIHRoZSBwb3NpdGlvbiBvZiBhblxyXG4gIC8vIGFjdHVhbCBjaGFyYWN0ZXIgKG9yIGZldGNoZXMgaXQgZnJvbSB0aGUgY2FjaGUpLlxyXG4gIGZ1bmN0aW9uIG1lYXN1cmVDaGFyUHJlcGFyZWQoY20sIHByZXBhcmVkLCBjaCwgYmlhcywgdmFySGVpZ2h0KSB7XHJcbiAgICBpZiAocHJlcGFyZWQuYmVmb3JlKSBjaCA9IC0xO1xyXG4gICAgdmFyIGtleSA9IGNoICsgKGJpYXMgfHwgXCJcIiksIGZvdW5kO1xyXG4gICAgaWYgKHByZXBhcmVkLmNhY2hlLmhhc093blByb3BlcnR5KGtleSkpIHtcclxuICAgICAgZm91bmQgPSBwcmVwYXJlZC5jYWNoZVtrZXldO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgaWYgKCFwcmVwYXJlZC5yZWN0KVxyXG4gICAgICAgIHByZXBhcmVkLnJlY3QgPSBwcmVwYXJlZC52aWV3LnRleHQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICAgIGlmICghcHJlcGFyZWQuaGFzSGVpZ2h0cykge1xyXG4gICAgICAgIGVuc3VyZUxpbmVIZWlnaHRzKGNtLCBwcmVwYXJlZC52aWV3LCBwcmVwYXJlZC5yZWN0KTtcclxuICAgICAgICBwcmVwYXJlZC5oYXNIZWlnaHRzID0gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgICBmb3VuZCA9IG1lYXN1cmVDaGFySW5uZXIoY20sIHByZXBhcmVkLCBjaCwgYmlhcyk7XHJcbiAgICAgIGlmICghZm91bmQuYm9ndXMpIHByZXBhcmVkLmNhY2hlW2tleV0gPSBmb3VuZDtcclxuICAgIH1cclxuICAgIHJldHVybiB7bGVmdDogZm91bmQubGVmdCwgcmlnaHQ6IGZvdW5kLnJpZ2h0LFxyXG4gICAgICAgICAgICB0b3A6IHZhckhlaWdodCA/IGZvdW5kLnJ0b3AgOiBmb3VuZC50b3AsXHJcbiAgICAgICAgICAgIGJvdHRvbTogdmFySGVpZ2h0ID8gZm91bmQucmJvdHRvbSA6IGZvdW5kLmJvdHRvbX07XHJcbiAgfVxyXG5cclxuICB2YXIgbnVsbFJlY3QgPSB7bGVmdDogMCwgcmlnaHQ6IDAsIHRvcDogMCwgYm90dG9tOiAwfTtcclxuXHJcbiAgZnVuY3Rpb24gbm9kZUFuZE9mZnNldEluTGluZU1hcChtYXAsIGNoLCBiaWFzKSB7XHJcbiAgICB2YXIgbm9kZSwgc3RhcnQsIGVuZCwgY29sbGFwc2U7XHJcbiAgICAvLyBGaXJzdCwgc2VhcmNoIHRoZSBsaW5lIG1hcCBmb3IgdGhlIHRleHQgbm9kZSBjb3JyZXNwb25kaW5nIHRvLFxyXG4gICAgLy8gb3IgY2xvc2VzdCB0bywgdGhlIHRhcmdldCBjaGFyYWN0ZXIuXHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG1hcC5sZW5ndGg7IGkgKz0gMykge1xyXG4gICAgICB2YXIgbVN0YXJ0ID0gbWFwW2ldLCBtRW5kID0gbWFwW2kgKyAxXTtcclxuICAgICAgaWYgKGNoIDwgbVN0YXJ0KSB7XHJcbiAgICAgICAgc3RhcnQgPSAwOyBlbmQgPSAxO1xyXG4gICAgICAgIGNvbGxhcHNlID0gXCJsZWZ0XCI7XHJcbiAgICAgIH0gZWxzZSBpZiAoY2ggPCBtRW5kKSB7XHJcbiAgICAgICAgc3RhcnQgPSBjaCAtIG1TdGFydDtcclxuICAgICAgICBlbmQgPSBzdGFydCArIDE7XHJcbiAgICAgIH0gZWxzZSBpZiAoaSA9PSBtYXAubGVuZ3RoIC0gMyB8fCBjaCA9PSBtRW5kICYmIG1hcFtpICsgM10gPiBjaCkge1xyXG4gICAgICAgIGVuZCA9IG1FbmQgLSBtU3RhcnQ7XHJcbiAgICAgICAgc3RhcnQgPSBlbmQgLSAxO1xyXG4gICAgICAgIGlmIChjaCA+PSBtRW5kKSBjb2xsYXBzZSA9IFwicmlnaHRcIjtcclxuICAgICAgfVxyXG4gICAgICBpZiAoc3RhcnQgIT0gbnVsbCkge1xyXG4gICAgICAgIG5vZGUgPSBtYXBbaSArIDJdO1xyXG4gICAgICAgIGlmIChtU3RhcnQgPT0gbUVuZCAmJiBiaWFzID09IChub2RlLmluc2VydExlZnQgPyBcImxlZnRcIiA6IFwicmlnaHRcIikpXHJcbiAgICAgICAgICBjb2xsYXBzZSA9IGJpYXM7XHJcbiAgICAgICAgaWYgKGJpYXMgPT0gXCJsZWZ0XCIgJiYgc3RhcnQgPT0gMClcclxuICAgICAgICAgIHdoaWxlIChpICYmIG1hcFtpIC0gMl0gPT0gbWFwW2kgLSAzXSAmJiBtYXBbaSAtIDFdLmluc2VydExlZnQpIHtcclxuICAgICAgICAgICAgbm9kZSA9IG1hcFsoaSAtPSAzKSArIDJdO1xyXG4gICAgICAgICAgICBjb2xsYXBzZSA9IFwibGVmdFwiO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIGlmIChiaWFzID09IFwicmlnaHRcIiAmJiBzdGFydCA9PSBtRW5kIC0gbVN0YXJ0KVxyXG4gICAgICAgICAgd2hpbGUgKGkgPCBtYXAubGVuZ3RoIC0gMyAmJiBtYXBbaSArIDNdID09IG1hcFtpICsgNF0gJiYgIW1hcFtpICsgNV0uaW5zZXJ0TGVmdCkge1xyXG4gICAgICAgICAgICBub2RlID0gbWFwWyhpICs9IDMpICsgMl07XHJcbiAgICAgICAgICAgIGNvbGxhcHNlID0gXCJyaWdodFwiO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4ge25vZGU6IG5vZGUsIHN0YXJ0OiBzdGFydCwgZW5kOiBlbmQsIGNvbGxhcHNlOiBjb2xsYXBzZSwgY292ZXJTdGFydDogbVN0YXJ0LCBjb3ZlckVuZDogbUVuZH07XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBtZWFzdXJlQ2hhcklubmVyKGNtLCBwcmVwYXJlZCwgY2gsIGJpYXMpIHtcclxuICAgIHZhciBwbGFjZSA9IG5vZGVBbmRPZmZzZXRJbkxpbmVNYXAocHJlcGFyZWQubWFwLCBjaCwgYmlhcyk7XHJcbiAgICB2YXIgbm9kZSA9IHBsYWNlLm5vZGUsIHN0YXJ0ID0gcGxhY2Uuc3RhcnQsIGVuZCA9IHBsYWNlLmVuZCwgY29sbGFwc2UgPSBwbGFjZS5jb2xsYXBzZTtcclxuXHJcbiAgICB2YXIgcmVjdDtcclxuICAgIGlmIChub2RlLm5vZGVUeXBlID09IDMpIHsgLy8gSWYgaXQgaXMgYSB0ZXh0IG5vZGUsIHVzZSBhIHJhbmdlIHRvIHJldHJpZXZlIHRoZSBjb29yZGluYXRlcy5cclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCA0OyBpKyspIHsgLy8gUmV0cnkgYSBtYXhpbXVtIG9mIDQgdGltZXMgd2hlbiBub25zZW5zZSByZWN0YW5nbGVzIGFyZSByZXR1cm5lZFxyXG4gICAgICAgIHdoaWxlIChzdGFydCAmJiBpc0V4dGVuZGluZ0NoYXIocHJlcGFyZWQubGluZS50ZXh0LmNoYXJBdChwbGFjZS5jb3ZlclN0YXJ0ICsgc3RhcnQpKSkgLS1zdGFydDtcclxuICAgICAgICB3aGlsZSAocGxhY2UuY292ZXJTdGFydCArIGVuZCA8IHBsYWNlLmNvdmVyRW5kICYmIGlzRXh0ZW5kaW5nQ2hhcihwcmVwYXJlZC5saW5lLnRleHQuY2hhckF0KHBsYWNlLmNvdmVyU3RhcnQgKyBlbmQpKSkgKytlbmQ7XHJcbiAgICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPCA5ICYmIHN0YXJ0ID09IDAgJiYgZW5kID09IHBsYWNlLmNvdmVyRW5kIC0gcGxhY2UuY292ZXJTdGFydCkge1xyXG4gICAgICAgICAgcmVjdCA9IG5vZGUucGFyZW50Tm9kZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgICAgICB9IGVsc2UgaWYgKGllICYmIGNtLm9wdGlvbnMubGluZVdyYXBwaW5nKSB7XHJcbiAgICAgICAgICB2YXIgcmVjdHMgPSByYW5nZShub2RlLCBzdGFydCwgZW5kKS5nZXRDbGllbnRSZWN0cygpO1xyXG4gICAgICAgICAgaWYgKHJlY3RzLmxlbmd0aClcclxuICAgICAgICAgICAgcmVjdCA9IHJlY3RzW2JpYXMgPT0gXCJyaWdodFwiID8gcmVjdHMubGVuZ3RoIC0gMSA6IDBdO1xyXG4gICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICByZWN0ID0gbnVsbFJlY3Q7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHJlY3QgPSByYW5nZShub2RlLCBzdGFydCwgZW5kKS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSB8fCBudWxsUmVjdDtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKHJlY3QubGVmdCB8fCByZWN0LnJpZ2h0IHx8IHN0YXJ0ID09IDApIGJyZWFrO1xyXG4gICAgICAgIGVuZCA9IHN0YXJ0O1xyXG4gICAgICAgIHN0YXJ0ID0gc3RhcnQgLSAxO1xyXG4gICAgICAgIGNvbGxhcHNlID0gXCJyaWdodFwiO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uIDwgMTEpIHJlY3QgPSBtYXliZVVwZGF0ZVJlY3RGb3Jab29taW5nKGNtLmRpc3BsYXkubWVhc3VyZSwgcmVjdCk7XHJcbiAgICB9IGVsc2UgeyAvLyBJZiBpdCBpcyBhIHdpZGdldCwgc2ltcGx5IGdldCB0aGUgYm94IGZvciB0aGUgd2hvbGUgd2lkZ2V0LlxyXG4gICAgICBpZiAoc3RhcnQgPiAwKSBjb2xsYXBzZSA9IGJpYXMgPSBcInJpZ2h0XCI7XHJcbiAgICAgIHZhciByZWN0cztcclxuICAgICAgaWYgKGNtLm9wdGlvbnMubGluZVdyYXBwaW5nICYmIChyZWN0cyA9IG5vZGUuZ2V0Q2xpZW50UmVjdHMoKSkubGVuZ3RoID4gMSlcclxuICAgICAgICByZWN0ID0gcmVjdHNbYmlhcyA9PSBcInJpZ2h0XCIgPyByZWN0cy5sZW5ndGggLSAxIDogMF07XHJcbiAgICAgIGVsc2VcclxuICAgICAgICByZWN0ID0gbm9kZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIH1cclxuICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uIDwgOSAmJiAhc3RhcnQgJiYgKCFyZWN0IHx8ICFyZWN0LmxlZnQgJiYgIXJlY3QucmlnaHQpKSB7XHJcbiAgICAgIHZhciByU3BhbiA9IG5vZGUucGFyZW50Tm9kZS5nZXRDbGllbnRSZWN0cygpWzBdO1xyXG4gICAgICBpZiAoclNwYW4pXHJcbiAgICAgICAgcmVjdCA9IHtsZWZ0OiByU3Bhbi5sZWZ0LCByaWdodDogclNwYW4ubGVmdCArIGNoYXJXaWR0aChjbS5kaXNwbGF5KSwgdG9wOiByU3Bhbi50b3AsIGJvdHRvbTogclNwYW4uYm90dG9tfTtcclxuICAgICAgZWxzZVxyXG4gICAgICAgIHJlY3QgPSBudWxsUmVjdDtcclxuICAgIH1cclxuXHJcbiAgICB2YXIgcnRvcCA9IHJlY3QudG9wIC0gcHJlcGFyZWQucmVjdC50b3AsIHJib3QgPSByZWN0LmJvdHRvbSAtIHByZXBhcmVkLnJlY3QudG9wO1xyXG4gICAgdmFyIG1pZCA9IChydG9wICsgcmJvdCkgLyAyO1xyXG4gICAgdmFyIGhlaWdodHMgPSBwcmVwYXJlZC52aWV3Lm1lYXN1cmUuaGVpZ2h0cztcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaGVpZ2h0cy5sZW5ndGggLSAxOyBpKyspXHJcbiAgICAgIGlmIChtaWQgPCBoZWlnaHRzW2ldKSBicmVhaztcclxuICAgIHZhciB0b3AgPSBpID8gaGVpZ2h0c1tpIC0gMV0gOiAwLCBib3QgPSBoZWlnaHRzW2ldO1xyXG4gICAgdmFyIHJlc3VsdCA9IHtsZWZ0OiAoY29sbGFwc2UgPT0gXCJyaWdodFwiID8gcmVjdC5yaWdodCA6IHJlY3QubGVmdCkgLSBwcmVwYXJlZC5yZWN0LmxlZnQsXHJcbiAgICAgICAgICAgICAgICAgIHJpZ2h0OiAoY29sbGFwc2UgPT0gXCJsZWZ0XCIgPyByZWN0LmxlZnQgOiByZWN0LnJpZ2h0KSAtIHByZXBhcmVkLnJlY3QubGVmdCxcclxuICAgICAgICAgICAgICAgICAgdG9wOiB0b3AsIGJvdHRvbTogYm90fTtcclxuICAgIGlmICghcmVjdC5sZWZ0ICYmICFyZWN0LnJpZ2h0KSByZXN1bHQuYm9ndXMgPSB0cnVlO1xyXG4gICAgaWYgKCFjbS5vcHRpb25zLnNpbmdsZUN1cnNvckhlaWdodFBlckxpbmUpIHsgcmVzdWx0LnJ0b3AgPSBydG9wOyByZXN1bHQucmJvdHRvbSA9IHJib3Q7IH1cclxuXHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH1cclxuXHJcbiAgLy8gV29yayBhcm91bmQgcHJvYmxlbSB3aXRoIGJvdW5kaW5nIGNsaWVudCByZWN0cyBvbiByYW5nZXMgYmVpbmdcclxuICAvLyByZXR1cm5lZCBpbmNvcnJlY3RseSB3aGVuIHpvb21lZCBvbiBJRTEwIGFuZCBiZWxvdy5cclxuICBmdW5jdGlvbiBtYXliZVVwZGF0ZVJlY3RGb3Jab29taW5nKG1lYXN1cmUsIHJlY3QpIHtcclxuICAgIGlmICghd2luZG93LnNjcmVlbiB8fCBzY3JlZW4ubG9naWNhbFhEUEkgPT0gbnVsbCB8fFxyXG4gICAgICAgIHNjcmVlbi5sb2dpY2FsWERQSSA9PSBzY3JlZW4uZGV2aWNlWERQSSB8fCAhaGFzQmFkWm9vbWVkUmVjdHMobWVhc3VyZSkpXHJcbiAgICAgIHJldHVybiByZWN0O1xyXG4gICAgdmFyIHNjYWxlWCA9IHNjcmVlbi5sb2dpY2FsWERQSSAvIHNjcmVlbi5kZXZpY2VYRFBJO1xyXG4gICAgdmFyIHNjYWxlWSA9IHNjcmVlbi5sb2dpY2FsWURQSSAvIHNjcmVlbi5kZXZpY2VZRFBJO1xyXG4gICAgcmV0dXJuIHtsZWZ0OiByZWN0LmxlZnQgKiBzY2FsZVgsIHJpZ2h0OiByZWN0LnJpZ2h0ICogc2NhbGVYLFxyXG4gICAgICAgICAgICB0b3A6IHJlY3QudG9wICogc2NhbGVZLCBib3R0b206IHJlY3QuYm90dG9tICogc2NhbGVZfTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGNsZWFyTGluZU1lYXN1cmVtZW50Q2FjaGVGb3IobGluZVZpZXcpIHtcclxuICAgIGlmIChsaW5lVmlldy5tZWFzdXJlKSB7XHJcbiAgICAgIGxpbmVWaWV3Lm1lYXN1cmUuY2FjaGUgPSB7fTtcclxuICAgICAgbGluZVZpZXcubWVhc3VyZS5oZWlnaHRzID0gbnVsbDtcclxuICAgICAgaWYgKGxpbmVWaWV3LnJlc3QpIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZVZpZXcucmVzdC5sZW5ndGg7IGkrKylcclxuICAgICAgICBsaW5lVmlldy5tZWFzdXJlLmNhY2hlc1tpXSA9IHt9O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gY2xlYXJMaW5lTWVhc3VyZW1lbnRDYWNoZShjbSkge1xyXG4gICAgY20uZGlzcGxheS5leHRlcm5hbE1lYXN1cmUgPSBudWxsO1xyXG4gICAgcmVtb3ZlQ2hpbGRyZW4oY20uZGlzcGxheS5saW5lTWVhc3VyZSk7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNtLmRpc3BsYXkudmlldy5sZW5ndGg7IGkrKylcclxuICAgICAgY2xlYXJMaW5lTWVhc3VyZW1lbnRDYWNoZUZvcihjbS5kaXNwbGF5LnZpZXdbaV0pO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gY2xlYXJDYWNoZXMoY20pIHtcclxuICAgIGNsZWFyTGluZU1lYXN1cmVtZW50Q2FjaGUoY20pO1xyXG4gICAgY20uZGlzcGxheS5jYWNoZWRDaGFyV2lkdGggPSBjbS5kaXNwbGF5LmNhY2hlZFRleHRIZWlnaHQgPSBjbS5kaXNwbGF5LmNhY2hlZFBhZGRpbmdIID0gbnVsbDtcclxuICAgIGlmICghY20ub3B0aW9ucy5saW5lV3JhcHBpbmcpIGNtLmRpc3BsYXkubWF4TGluZUNoYW5nZWQgPSB0cnVlO1xyXG4gICAgY20uZGlzcGxheS5saW5lTnVtQ2hhcnMgPSBudWxsO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gcGFnZVNjcm9sbFgoKSB7IHJldHVybiB3aW5kb3cucGFnZVhPZmZzZXQgfHwgKGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCB8fCBkb2N1bWVudC5ib2R5KS5zY3JvbGxMZWZ0OyB9XHJcbiAgZnVuY3Rpb24gcGFnZVNjcm9sbFkoKSB7IHJldHVybiB3aW5kb3cucGFnZVlPZmZzZXQgfHwgKGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCB8fCBkb2N1bWVudC5ib2R5KS5zY3JvbGxUb3A7IH1cclxuXHJcbiAgLy8gQ29udmVydHMgYSB7dG9wLCBib3R0b20sIGxlZnQsIHJpZ2h0fSBib3ggZnJvbSBsaW5lLWxvY2FsXHJcbiAgLy8gY29vcmRpbmF0ZXMgaW50byBhbm90aGVyIGNvb3JkaW5hdGUgc3lzdGVtLiBDb250ZXh0IG1heSBiZSBvbmUgb2ZcclxuICAvLyBcImxpbmVcIiwgXCJkaXZcIiAoZGlzcGxheS5saW5lRGl2KSwgXCJsb2NhbFwiL251bGwgKGVkaXRvciksIFwid2luZG93XCIsXHJcbiAgLy8gb3IgXCJwYWdlXCIuXHJcbiAgZnVuY3Rpb24gaW50b0Nvb3JkU3lzdGVtKGNtLCBsaW5lT2JqLCByZWN0LCBjb250ZXh0KSB7XHJcbiAgICBpZiAobGluZU9iai53aWRnZXRzKSBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmVPYmoud2lkZ2V0cy5sZW5ndGg7ICsraSkgaWYgKGxpbmVPYmoud2lkZ2V0c1tpXS5hYm92ZSkge1xyXG4gICAgICB2YXIgc2l6ZSA9IHdpZGdldEhlaWdodChsaW5lT2JqLndpZGdldHNbaV0pO1xyXG4gICAgICByZWN0LnRvcCArPSBzaXplOyByZWN0LmJvdHRvbSArPSBzaXplO1xyXG4gICAgfVxyXG4gICAgaWYgKGNvbnRleHQgPT0gXCJsaW5lXCIpIHJldHVybiByZWN0O1xyXG4gICAgaWYgKCFjb250ZXh0KSBjb250ZXh0ID0gXCJsb2NhbFwiO1xyXG4gICAgdmFyIHlPZmYgPSBoZWlnaHRBdExpbmUobGluZU9iaik7XHJcbiAgICBpZiAoY29udGV4dCA9PSBcImxvY2FsXCIpIHlPZmYgKz0gcGFkZGluZ1RvcChjbS5kaXNwbGF5KTtcclxuICAgIGVsc2UgeU9mZiAtPSBjbS5kaXNwbGF5LnZpZXdPZmZzZXQ7XHJcbiAgICBpZiAoY29udGV4dCA9PSBcInBhZ2VcIiB8fCBjb250ZXh0ID09IFwid2luZG93XCIpIHtcclxuICAgICAgdmFyIGxPZmYgPSBjbS5kaXNwbGF5LmxpbmVTcGFjZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgICAgeU9mZiArPSBsT2ZmLnRvcCArIChjb250ZXh0ID09IFwid2luZG93XCIgPyAwIDogcGFnZVNjcm9sbFkoKSk7XHJcbiAgICAgIHZhciB4T2ZmID0gbE9mZi5sZWZ0ICsgKGNvbnRleHQgPT0gXCJ3aW5kb3dcIiA/IDAgOiBwYWdlU2Nyb2xsWCgpKTtcclxuICAgICAgcmVjdC5sZWZ0ICs9IHhPZmY7IHJlY3QucmlnaHQgKz0geE9mZjtcclxuICAgIH1cclxuICAgIHJlY3QudG9wICs9IHlPZmY7IHJlY3QuYm90dG9tICs9IHlPZmY7XHJcbiAgICByZXR1cm4gcmVjdDtcclxuICB9XHJcblxyXG4gIC8vIENvdmVydHMgYSBib3ggZnJvbSBcImRpdlwiIGNvb3JkcyB0byBhbm90aGVyIGNvb3JkaW5hdGUgc3lzdGVtLlxyXG4gIC8vIENvbnRleHQgbWF5IGJlIFwid2luZG93XCIsIFwicGFnZVwiLCBcImRpdlwiLCBvciBcImxvY2FsXCIvbnVsbC5cclxuICBmdW5jdGlvbiBmcm9tQ29vcmRTeXN0ZW0oY20sIGNvb3JkcywgY29udGV4dCkge1xyXG4gICAgaWYgKGNvbnRleHQgPT0gXCJkaXZcIikgcmV0dXJuIGNvb3JkcztcclxuICAgIHZhciBsZWZ0ID0gY29vcmRzLmxlZnQsIHRvcCA9IGNvb3Jkcy50b3A7XHJcbiAgICAvLyBGaXJzdCBtb3ZlIGludG8gXCJwYWdlXCIgY29vcmRpbmF0ZSBzeXN0ZW1cclxuICAgIGlmIChjb250ZXh0ID09IFwicGFnZVwiKSB7XHJcbiAgICAgIGxlZnQgLT0gcGFnZVNjcm9sbFgoKTtcclxuICAgICAgdG9wIC09IHBhZ2VTY3JvbGxZKCk7XHJcbiAgICB9IGVsc2UgaWYgKGNvbnRleHQgPT0gXCJsb2NhbFwiIHx8ICFjb250ZXh0KSB7XHJcbiAgICAgIHZhciBsb2NhbEJveCA9IGNtLmRpc3BsYXkuc2l6ZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICAgIGxlZnQgKz0gbG9jYWxCb3gubGVmdDtcclxuICAgICAgdG9wICs9IGxvY2FsQm94LnRvcDtcclxuICAgIH1cclxuXHJcbiAgICB2YXIgbGluZVNwYWNlQm94ID0gY20uZGlzcGxheS5saW5lU3BhY2UuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICByZXR1cm4ge2xlZnQ6IGxlZnQgLSBsaW5lU3BhY2VCb3gubGVmdCwgdG9wOiB0b3AgLSBsaW5lU3BhY2VCb3gudG9wfTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGNoYXJDb29yZHMoY20sIHBvcywgY29udGV4dCwgbGluZU9iaiwgYmlhcykge1xyXG4gICAgaWYgKCFsaW5lT2JqKSBsaW5lT2JqID0gZ2V0TGluZShjbS5kb2MsIHBvcy5saW5lKTtcclxuICAgIHJldHVybiBpbnRvQ29vcmRTeXN0ZW0oY20sIGxpbmVPYmosIG1lYXN1cmVDaGFyKGNtLCBsaW5lT2JqLCBwb3MuY2gsIGJpYXMpLCBjb250ZXh0KTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybnMgYSBib3ggZm9yIGEgZ2l2ZW4gY3Vyc29yIHBvc2l0aW9uLCB3aGljaCBtYXkgaGF2ZSBhblxyXG4gIC8vICdvdGhlcicgcHJvcGVydHkgY29udGFpbmluZyB0aGUgcG9zaXRpb24gb2YgdGhlIHNlY29uZGFyeSBjdXJzb3JcclxuICAvLyBvbiBhIGJpZGkgYm91bmRhcnkuXHJcbiAgZnVuY3Rpb24gY3Vyc29yQ29vcmRzKGNtLCBwb3MsIGNvbnRleHQsIGxpbmVPYmosIHByZXBhcmVkTWVhc3VyZSwgdmFySGVpZ2h0KSB7XHJcbiAgICBsaW5lT2JqID0gbGluZU9iaiB8fCBnZXRMaW5lKGNtLmRvYywgcG9zLmxpbmUpO1xyXG4gICAgaWYgKCFwcmVwYXJlZE1lYXN1cmUpIHByZXBhcmVkTWVhc3VyZSA9IHByZXBhcmVNZWFzdXJlRm9yTGluZShjbSwgbGluZU9iaik7XHJcbiAgICBmdW5jdGlvbiBnZXQoY2gsIHJpZ2h0KSB7XHJcbiAgICAgIHZhciBtID0gbWVhc3VyZUNoYXJQcmVwYXJlZChjbSwgcHJlcGFyZWRNZWFzdXJlLCBjaCwgcmlnaHQgPyBcInJpZ2h0XCIgOiBcImxlZnRcIiwgdmFySGVpZ2h0KTtcclxuICAgICAgaWYgKHJpZ2h0KSBtLmxlZnQgPSBtLnJpZ2h0OyBlbHNlIG0ucmlnaHQgPSBtLmxlZnQ7XHJcbiAgICAgIHJldHVybiBpbnRvQ29vcmRTeXN0ZW0oY20sIGxpbmVPYmosIG0sIGNvbnRleHQpO1xyXG4gICAgfVxyXG4gICAgZnVuY3Rpb24gZ2V0QmlkaShjaCwgcGFydFBvcykge1xyXG4gICAgICB2YXIgcGFydCA9IG9yZGVyW3BhcnRQb3NdLCByaWdodCA9IHBhcnQubGV2ZWwgJSAyO1xyXG4gICAgICBpZiAoY2ggPT0gYmlkaUxlZnQocGFydCkgJiYgcGFydFBvcyAmJiBwYXJ0LmxldmVsIDwgb3JkZXJbcGFydFBvcyAtIDFdLmxldmVsKSB7XHJcbiAgICAgICAgcGFydCA9IG9yZGVyWy0tcGFydFBvc107XHJcbiAgICAgICAgY2ggPSBiaWRpUmlnaHQocGFydCkgLSAocGFydC5sZXZlbCAlIDIgPyAwIDogMSk7XHJcbiAgICAgICAgcmlnaHQgPSB0cnVlO1xyXG4gICAgICB9IGVsc2UgaWYgKGNoID09IGJpZGlSaWdodChwYXJ0KSAmJiBwYXJ0UG9zIDwgb3JkZXIubGVuZ3RoIC0gMSAmJiBwYXJ0LmxldmVsIDwgb3JkZXJbcGFydFBvcyArIDFdLmxldmVsKSB7XHJcbiAgICAgICAgcGFydCA9IG9yZGVyWysrcGFydFBvc107XHJcbiAgICAgICAgY2ggPSBiaWRpTGVmdChwYXJ0KSAtIHBhcnQubGV2ZWwgJSAyO1xyXG4gICAgICAgIHJpZ2h0ID0gZmFsc2U7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKHJpZ2h0ICYmIGNoID09IHBhcnQudG8gJiYgY2ggPiBwYXJ0LmZyb20pIHJldHVybiBnZXQoY2ggLSAxKTtcclxuICAgICAgcmV0dXJuIGdldChjaCwgcmlnaHQpO1xyXG4gICAgfVxyXG4gICAgdmFyIG9yZGVyID0gZ2V0T3JkZXIobGluZU9iaiksIGNoID0gcG9zLmNoO1xyXG4gICAgaWYgKCFvcmRlcikgcmV0dXJuIGdldChjaCk7XHJcbiAgICB2YXIgcGFydFBvcyA9IGdldEJpZGlQYXJ0QXQob3JkZXIsIGNoKTtcclxuICAgIHZhciB2YWwgPSBnZXRCaWRpKGNoLCBwYXJ0UG9zKTtcclxuICAgIGlmIChiaWRpT3RoZXIgIT0gbnVsbCkgdmFsLm90aGVyID0gZ2V0QmlkaShjaCwgYmlkaU90aGVyKTtcclxuICAgIHJldHVybiB2YWw7XHJcbiAgfVxyXG5cclxuICAvLyBVc2VkIHRvIGNoZWFwbHkgZXN0aW1hdGUgdGhlIGNvb3JkaW5hdGVzIGZvciBhIHBvc2l0aW9uLiBVc2VkIGZvclxyXG4gIC8vIGludGVybWVkaWF0ZSBzY3JvbGwgdXBkYXRlcy5cclxuICBmdW5jdGlvbiBlc3RpbWF0ZUNvb3JkcyhjbSwgcG9zKSB7XHJcbiAgICB2YXIgbGVmdCA9IDAsIHBvcyA9IGNsaXBQb3MoY20uZG9jLCBwb3MpO1xyXG4gICAgaWYgKCFjbS5vcHRpb25zLmxpbmVXcmFwcGluZykgbGVmdCA9IGNoYXJXaWR0aChjbS5kaXNwbGF5KSAqIHBvcy5jaDtcclxuICAgIHZhciBsaW5lT2JqID0gZ2V0TGluZShjbS5kb2MsIHBvcy5saW5lKTtcclxuICAgIHZhciB0b3AgPSBoZWlnaHRBdExpbmUobGluZU9iaikgKyBwYWRkaW5nVG9wKGNtLmRpc3BsYXkpO1xyXG4gICAgcmV0dXJuIHtsZWZ0OiBsZWZ0LCByaWdodDogbGVmdCwgdG9wOiB0b3AsIGJvdHRvbTogdG9wICsgbGluZU9iai5oZWlnaHR9O1xyXG4gIH1cclxuXHJcbiAgLy8gUG9zaXRpb25zIHJldHVybmVkIGJ5IGNvb3Jkc0NoYXIgY29udGFpbiBzb21lIGV4dHJhIGluZm9ybWF0aW9uLlxyXG4gIC8vIHhSZWwgaXMgdGhlIHJlbGF0aXZlIHggcG9zaXRpb24gb2YgdGhlIGlucHV0IGNvb3JkaW5hdGVzIGNvbXBhcmVkXHJcbiAgLy8gdG8gdGhlIGZvdW5kIHBvc2l0aW9uIChzbyB4UmVsID4gMCBtZWFucyB0aGUgY29vcmRpbmF0ZXMgYXJlIHRvXHJcbiAgLy8gdGhlIHJpZ2h0IG9mIHRoZSBjaGFyYWN0ZXIgcG9zaXRpb24sIGZvciBleGFtcGxlKS4gV2hlbiBvdXRzaWRlXHJcbiAgLy8gaXMgdHJ1ZSwgdGhhdCBtZWFucyB0aGUgY29vcmRpbmF0ZXMgbGllIG91dHNpZGUgdGhlIGxpbmUnc1xyXG4gIC8vIHZlcnRpY2FsIHJhbmdlLlxyXG4gIGZ1bmN0aW9uIFBvc1dpdGhJbmZvKGxpbmUsIGNoLCBvdXRzaWRlLCB4UmVsKSB7XHJcbiAgICB2YXIgcG9zID0gUG9zKGxpbmUsIGNoKTtcclxuICAgIHBvcy54UmVsID0geFJlbDtcclxuICAgIGlmIChvdXRzaWRlKSBwb3Mub3V0c2lkZSA9IHRydWU7XHJcbiAgICByZXR1cm4gcG9zO1xyXG4gIH1cclxuXHJcbiAgLy8gQ29tcHV0ZSB0aGUgY2hhcmFjdGVyIHBvc2l0aW9uIGNsb3Nlc3QgdG8gdGhlIGdpdmVuIGNvb3JkaW5hdGVzLlxyXG4gIC8vIElucHV0IG11c3QgYmUgbGluZVNwYWNlLWxvY2FsIChcImRpdlwiIGNvb3JkaW5hdGUgc3lzdGVtKS5cclxuICBmdW5jdGlvbiBjb29yZHNDaGFyKGNtLCB4LCB5KSB7XHJcbiAgICB2YXIgZG9jID0gY20uZG9jO1xyXG4gICAgeSArPSBjbS5kaXNwbGF5LnZpZXdPZmZzZXQ7XHJcbiAgICBpZiAoeSA8IDApIHJldHVybiBQb3NXaXRoSW5mbyhkb2MuZmlyc3QsIDAsIHRydWUsIC0xKTtcclxuICAgIHZhciBsaW5lTiA9IGxpbmVBdEhlaWdodChkb2MsIHkpLCBsYXN0ID0gZG9jLmZpcnN0ICsgZG9jLnNpemUgLSAxO1xyXG4gICAgaWYgKGxpbmVOID4gbGFzdClcclxuICAgICAgcmV0dXJuIFBvc1dpdGhJbmZvKGRvYy5maXJzdCArIGRvYy5zaXplIC0gMSwgZ2V0TGluZShkb2MsIGxhc3QpLnRleHQubGVuZ3RoLCB0cnVlLCAxKTtcclxuICAgIGlmICh4IDwgMCkgeCA9IDA7XHJcblxyXG4gICAgdmFyIGxpbmVPYmogPSBnZXRMaW5lKGRvYywgbGluZU4pO1xyXG4gICAgZm9yICg7Oykge1xyXG4gICAgICB2YXIgZm91bmQgPSBjb29yZHNDaGFySW5uZXIoY20sIGxpbmVPYmosIGxpbmVOLCB4LCB5KTtcclxuICAgICAgdmFyIG1lcmdlZCA9IGNvbGxhcHNlZFNwYW5BdEVuZChsaW5lT2JqKTtcclxuICAgICAgdmFyIG1lcmdlZFBvcyA9IG1lcmdlZCAmJiBtZXJnZWQuZmluZCgwLCB0cnVlKTtcclxuICAgICAgaWYgKG1lcmdlZCAmJiAoZm91bmQuY2ggPiBtZXJnZWRQb3MuZnJvbS5jaCB8fCBmb3VuZC5jaCA9PSBtZXJnZWRQb3MuZnJvbS5jaCAmJiBmb3VuZC54UmVsID4gMCkpXHJcbiAgICAgICAgbGluZU4gPSBsaW5lTm8obGluZU9iaiA9IG1lcmdlZFBvcy50by5saW5lKTtcclxuICAgICAgZWxzZVxyXG4gICAgICAgIHJldHVybiBmb3VuZDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGNvb3Jkc0NoYXJJbm5lcihjbSwgbGluZU9iaiwgbGluZU5vLCB4LCB5KSB7XHJcbiAgICB2YXIgaW5uZXJPZmYgPSB5IC0gaGVpZ2h0QXRMaW5lKGxpbmVPYmopO1xyXG4gICAgdmFyIHdyb25nTGluZSA9IGZhbHNlLCBhZGp1c3QgPSAyICogY20uZGlzcGxheS53cmFwcGVyLmNsaWVudFdpZHRoO1xyXG4gICAgdmFyIHByZXBhcmVkTWVhc3VyZSA9IHByZXBhcmVNZWFzdXJlRm9yTGluZShjbSwgbGluZU9iaik7XHJcblxyXG4gICAgZnVuY3Rpb24gZ2V0WChjaCkge1xyXG4gICAgICB2YXIgc3AgPSBjdXJzb3JDb29yZHMoY20sIFBvcyhsaW5lTm8sIGNoKSwgXCJsaW5lXCIsIGxpbmVPYmosIHByZXBhcmVkTWVhc3VyZSk7XHJcbiAgICAgIHdyb25nTGluZSA9IHRydWU7XHJcbiAgICAgIGlmIChpbm5lck9mZiA+IHNwLmJvdHRvbSkgcmV0dXJuIHNwLmxlZnQgLSBhZGp1c3Q7XHJcbiAgICAgIGVsc2UgaWYgKGlubmVyT2ZmIDwgc3AudG9wKSByZXR1cm4gc3AubGVmdCArIGFkanVzdDtcclxuICAgICAgZWxzZSB3cm9uZ0xpbmUgPSBmYWxzZTtcclxuICAgICAgcmV0dXJuIHNwLmxlZnQ7XHJcbiAgICB9XHJcblxyXG4gICAgdmFyIGJpZGkgPSBnZXRPcmRlcihsaW5lT2JqKSwgZGlzdCA9IGxpbmVPYmoudGV4dC5sZW5ndGg7XHJcbiAgICB2YXIgZnJvbSA9IGxpbmVMZWZ0KGxpbmVPYmopLCB0byA9IGxpbmVSaWdodChsaW5lT2JqKTtcclxuICAgIHZhciBmcm9tWCA9IGdldFgoZnJvbSksIGZyb21PdXRzaWRlID0gd3JvbmdMaW5lLCB0b1ggPSBnZXRYKHRvKSwgdG9PdXRzaWRlID0gd3JvbmdMaW5lO1xyXG5cclxuICAgIGlmICh4ID4gdG9YKSByZXR1cm4gUG9zV2l0aEluZm8obGluZU5vLCB0bywgdG9PdXRzaWRlLCAxKTtcclxuICAgIC8vIERvIGEgYmluYXJ5IHNlYXJjaCBiZXR3ZWVuIHRoZXNlIGJvdW5kcy5cclxuICAgIGZvciAoOzspIHtcclxuICAgICAgaWYgKGJpZGkgPyB0byA9PSBmcm9tIHx8IHRvID09IG1vdmVWaXN1YWxseShsaW5lT2JqLCBmcm9tLCAxKSA6IHRvIC0gZnJvbSA8PSAxKSB7XHJcbiAgICAgICAgdmFyIGNoID0geCA8IGZyb21YIHx8IHggLSBmcm9tWCA8PSB0b1ggLSB4ID8gZnJvbSA6IHRvO1xyXG4gICAgICAgIHZhciB4RGlmZiA9IHggLSAoY2ggPT0gZnJvbSA/IGZyb21YIDogdG9YKTtcclxuICAgICAgICB3aGlsZSAoaXNFeHRlbmRpbmdDaGFyKGxpbmVPYmoudGV4dC5jaGFyQXQoY2gpKSkgKytjaDtcclxuICAgICAgICB2YXIgcG9zID0gUG9zV2l0aEluZm8obGluZU5vLCBjaCwgY2ggPT0gZnJvbSA/IGZyb21PdXRzaWRlIDogdG9PdXRzaWRlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICB4RGlmZiA8IC0xID8gLTEgOiB4RGlmZiA+IDEgPyAxIDogMCk7XHJcbiAgICAgICAgcmV0dXJuIHBvcztcclxuICAgICAgfVxyXG4gICAgICB2YXIgc3RlcCA9IE1hdGguY2VpbChkaXN0IC8gMiksIG1pZGRsZSA9IGZyb20gKyBzdGVwO1xyXG4gICAgICBpZiAoYmlkaSkge1xyXG4gICAgICAgIG1pZGRsZSA9IGZyb207XHJcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdGVwOyArK2kpIG1pZGRsZSA9IG1vdmVWaXN1YWxseShsaW5lT2JqLCBtaWRkbGUsIDEpO1xyXG4gICAgICB9XHJcbiAgICAgIHZhciBtaWRkbGVYID0gZ2V0WChtaWRkbGUpO1xyXG4gICAgICBpZiAobWlkZGxlWCA+IHgpIHt0byA9IG1pZGRsZTsgdG9YID0gbWlkZGxlWDsgaWYgKHRvT3V0c2lkZSA9IHdyb25nTGluZSkgdG9YICs9IDEwMDA7IGRpc3QgPSBzdGVwO31cclxuICAgICAgZWxzZSB7ZnJvbSA9IG1pZGRsZTsgZnJvbVggPSBtaWRkbGVYOyBmcm9tT3V0c2lkZSA9IHdyb25nTGluZTsgZGlzdCAtPSBzdGVwO31cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHZhciBtZWFzdXJlVGV4dDtcclxuICAvLyBDb21wdXRlIHRoZSBkZWZhdWx0IHRleHQgaGVpZ2h0LlxyXG4gIGZ1bmN0aW9uIHRleHRIZWlnaHQoZGlzcGxheSkge1xyXG4gICAgaWYgKGRpc3BsYXkuY2FjaGVkVGV4dEhlaWdodCAhPSBudWxsKSByZXR1cm4gZGlzcGxheS5jYWNoZWRUZXh0SGVpZ2h0O1xyXG4gICAgaWYgKG1lYXN1cmVUZXh0ID09IG51bGwpIHtcclxuICAgICAgbWVhc3VyZVRleHQgPSBlbHQoXCJwcmVcIik7XHJcbiAgICAgIC8vIE1lYXN1cmUgYSBidW5jaCBvZiBsaW5lcywgZm9yIGJyb3dzZXJzIHRoYXQgY29tcHV0ZVxyXG4gICAgICAvLyBmcmFjdGlvbmFsIGhlaWdodHMuXHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgNDk7ICsraSkge1xyXG4gICAgICAgIG1lYXN1cmVUZXh0LmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKFwieFwiKSk7XHJcbiAgICAgICAgbWVhc3VyZVRleHQuYXBwZW5kQ2hpbGQoZWx0KFwiYnJcIikpO1xyXG4gICAgICB9XHJcbiAgICAgIG1lYXN1cmVUZXh0LmFwcGVuZENoaWxkKGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKFwieFwiKSk7XHJcbiAgICB9XHJcbiAgICByZW1vdmVDaGlsZHJlbkFuZEFkZChkaXNwbGF5Lm1lYXN1cmUsIG1lYXN1cmVUZXh0KTtcclxuICAgIHZhciBoZWlnaHQgPSBtZWFzdXJlVGV4dC5vZmZzZXRIZWlnaHQgLyA1MDtcclxuICAgIGlmIChoZWlnaHQgPiAzKSBkaXNwbGF5LmNhY2hlZFRleHRIZWlnaHQgPSBoZWlnaHQ7XHJcbiAgICByZW1vdmVDaGlsZHJlbihkaXNwbGF5Lm1lYXN1cmUpO1xyXG4gICAgcmV0dXJuIGhlaWdodCB8fCAxO1xyXG4gIH1cclxuXHJcbiAgLy8gQ29tcHV0ZSB0aGUgZGVmYXVsdCBjaGFyYWN0ZXIgd2lkdGguXHJcbiAgZnVuY3Rpb24gY2hhcldpZHRoKGRpc3BsYXkpIHtcclxuICAgIGlmIChkaXNwbGF5LmNhY2hlZENoYXJXaWR0aCAhPSBudWxsKSByZXR1cm4gZGlzcGxheS5jYWNoZWRDaGFyV2lkdGg7XHJcbiAgICB2YXIgYW5jaG9yID0gZWx0KFwic3BhblwiLCBcInh4eHh4eHh4eHhcIik7XHJcbiAgICB2YXIgcHJlID0gZWx0KFwicHJlXCIsIFthbmNob3JdKTtcclxuICAgIHJlbW92ZUNoaWxkcmVuQW5kQWRkKGRpc3BsYXkubWVhc3VyZSwgcHJlKTtcclxuICAgIHZhciByZWN0ID0gYW5jaG9yLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLCB3aWR0aCA9IChyZWN0LnJpZ2h0IC0gcmVjdC5sZWZ0KSAvIDEwO1xyXG4gICAgaWYgKHdpZHRoID4gMikgZGlzcGxheS5jYWNoZWRDaGFyV2lkdGggPSB3aWR0aDtcclxuICAgIHJldHVybiB3aWR0aCB8fCAxMDtcclxuICB9XHJcblxyXG4gIC8vIE9QRVJBVElPTlNcclxuXHJcbiAgLy8gT3BlcmF0aW9ucyBhcmUgdXNlZCB0byB3cmFwIGEgc2VyaWVzIG9mIGNoYW5nZXMgdG8gdGhlIGVkaXRvclxyXG4gIC8vIHN0YXRlIGluIHN1Y2ggYSB3YXkgdGhhdCBlYWNoIGNoYW5nZSB3b24ndCBoYXZlIHRvIHVwZGF0ZSB0aGVcclxuICAvLyBjdXJzb3IgYW5kIGRpc3BsYXkgKHdoaWNoIHdvdWxkIGJlIGF3a3dhcmQsIHNsb3csIGFuZFxyXG4gIC8vIGVycm9yLXByb25lKS4gSW5zdGVhZCwgZGlzcGxheSB1cGRhdGVzIGFyZSBiYXRjaGVkIGFuZCB0aGVuIGFsbFxyXG4gIC8vIGNvbWJpbmVkIGFuZCBleGVjdXRlZCBhdCBvbmNlLlxyXG5cclxuICB2YXIgb3BlcmF0aW9uR3JvdXAgPSBudWxsO1xyXG5cclxuICB2YXIgbmV4dE9wSWQgPSAwO1xyXG4gIC8vIFN0YXJ0IGEgbmV3IG9wZXJhdGlvbi5cclxuICBmdW5jdGlvbiBzdGFydE9wZXJhdGlvbihjbSkge1xyXG4gICAgY20uY3VyT3AgPSB7XHJcbiAgICAgIGNtOiBjbSxcclxuICAgICAgdmlld0NoYW5nZWQ6IGZhbHNlLCAgICAgIC8vIEZsYWcgdGhhdCBpbmRpY2F0ZXMgdGhhdCBsaW5lcyBtaWdodCBuZWVkIHRvIGJlIHJlZHJhd25cclxuICAgICAgc3RhcnRIZWlnaHQ6IGNtLmRvYy5oZWlnaHQsIC8vIFVzZWQgdG8gZGV0ZWN0IG5lZWQgdG8gdXBkYXRlIHNjcm9sbGJhclxyXG4gICAgICBmb3JjZVVwZGF0ZTogZmFsc2UsICAgICAgLy8gVXNlZCB0byBmb3JjZSBhIHJlZHJhd1xyXG4gICAgICB1cGRhdGVJbnB1dDogbnVsbCwgICAgICAgLy8gV2hldGhlciB0byByZXNldCB0aGUgaW5wdXQgdGV4dGFyZWFcclxuICAgICAgdHlwaW5nOiBmYWxzZSwgICAgICAgICAgIC8vIFdoZXRoZXIgdGhpcyByZXNldCBzaG91bGQgYmUgY2FyZWZ1bCB0byBsZWF2ZSBleGlzdGluZyB0ZXh0IChmb3IgY29tcG9zaXRpbmcpXHJcbiAgICAgIGNoYW5nZU9ianM6IG51bGwsICAgICAgICAvLyBBY2N1bXVsYXRlZCBjaGFuZ2VzLCBmb3IgZmlyaW5nIGNoYW5nZSBldmVudHNcclxuICAgICAgY3Vyc29yQWN0aXZpdHlIYW5kbGVyczogbnVsbCwgLy8gU2V0IG9mIGhhbmRsZXJzIHRvIGZpcmUgY3Vyc29yQWN0aXZpdHkgb25cclxuICAgICAgY3Vyc29yQWN0aXZpdHlDYWxsZWQ6IDAsIC8vIFRyYWNrcyB3aGljaCBjdXJzb3JBY3Rpdml0eSBoYW5kbGVycyBoYXZlIGJlZW4gY2FsbGVkIGFscmVhZHlcclxuICAgICAgc2VsZWN0aW9uQ2hhbmdlZDogZmFsc2UsIC8vIFdoZXRoZXIgdGhlIHNlbGVjdGlvbiBuZWVkcyB0byBiZSByZWRyYXduXHJcbiAgICAgIHVwZGF0ZU1heExpbmU6IGZhbHNlLCAgICAvLyBTZXQgd2hlbiB0aGUgd2lkZXN0IGxpbmUgbmVlZHMgdG8gYmUgZGV0ZXJtaW5lZCBhbmV3XHJcbiAgICAgIHNjcm9sbExlZnQ6IG51bGwsIHNjcm9sbFRvcDogbnVsbCwgLy8gSW50ZXJtZWRpYXRlIHNjcm9sbCBwb3NpdGlvbiwgbm90IHB1c2hlZCB0byBET00geWV0XHJcbiAgICAgIHNjcm9sbFRvUG9zOiBudWxsLCAgICAgICAvLyBVc2VkIHRvIHNjcm9sbCB0byBhIHNwZWNpZmljIHBvc2l0aW9uXHJcbiAgICAgIGZvY3VzOiBmYWxzZSxcclxuICAgICAgaWQ6ICsrbmV4dE9wSWQgICAgICAgICAgIC8vIFVuaXF1ZSBJRFxyXG4gICAgfTtcclxuICAgIGlmIChvcGVyYXRpb25Hcm91cCkge1xyXG4gICAgICBvcGVyYXRpb25Hcm91cC5vcHMucHVzaChjbS5jdXJPcCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjbS5jdXJPcC5vd25zR3JvdXAgPSBvcGVyYXRpb25Hcm91cCA9IHtcclxuICAgICAgICBvcHM6IFtjbS5jdXJPcF0sXHJcbiAgICAgICAgZGVsYXllZENhbGxiYWNrczogW11cclxuICAgICAgfTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGZpcmVDYWxsYmFja3NGb3JPcHMoZ3JvdXApIHtcclxuICAgIC8vIENhbGxzIGRlbGF5ZWQgY2FsbGJhY2tzIGFuZCBjdXJzb3JBY3Rpdml0eSBoYW5kbGVycyB1bnRpbCBub1xyXG4gICAgLy8gbmV3IG9uZXMgYXBwZWFyXHJcbiAgICB2YXIgY2FsbGJhY2tzID0gZ3JvdXAuZGVsYXllZENhbGxiYWNrcywgaSA9IDA7XHJcbiAgICBkbyB7XHJcbiAgICAgIGZvciAoOyBpIDwgY2FsbGJhY2tzLmxlbmd0aDsgaSsrKVxyXG4gICAgICAgIGNhbGxiYWNrc1tpXS5jYWxsKG51bGwpO1xyXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGdyb3VwLm9wcy5sZW5ndGg7IGorKykge1xyXG4gICAgICAgIHZhciBvcCA9IGdyb3VwLm9wc1tqXTtcclxuICAgICAgICBpZiAob3AuY3Vyc29yQWN0aXZpdHlIYW5kbGVycylcclxuICAgICAgICAgIHdoaWxlIChvcC5jdXJzb3JBY3Rpdml0eUNhbGxlZCA8IG9wLmN1cnNvckFjdGl2aXR5SGFuZGxlcnMubGVuZ3RoKVxyXG4gICAgICAgICAgICBvcC5jdXJzb3JBY3Rpdml0eUhhbmRsZXJzW29wLmN1cnNvckFjdGl2aXR5Q2FsbGVkKytdLmNhbGwobnVsbCwgb3AuY20pO1xyXG4gICAgICB9XHJcbiAgICB9IHdoaWxlIChpIDwgY2FsbGJhY2tzLmxlbmd0aCk7XHJcbiAgfVxyXG5cclxuICAvLyBGaW5pc2ggYW4gb3BlcmF0aW9uLCB1cGRhdGluZyB0aGUgZGlzcGxheSBhbmQgc2lnbmFsbGluZyBkZWxheWVkIGV2ZW50c1xyXG4gIGZ1bmN0aW9uIGVuZE9wZXJhdGlvbihjbSkge1xyXG4gICAgdmFyIG9wID0gY20uY3VyT3AsIGdyb3VwID0gb3Aub3duc0dyb3VwO1xyXG4gICAgaWYgKCFncm91cCkgcmV0dXJuO1xyXG5cclxuICAgIHRyeSB7IGZpcmVDYWxsYmFja3NGb3JPcHMoZ3JvdXApOyB9XHJcbiAgICBmaW5hbGx5IHtcclxuICAgICAgb3BlcmF0aW9uR3JvdXAgPSBudWxsO1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGdyb3VwLm9wcy5sZW5ndGg7IGkrKylcclxuICAgICAgICBncm91cC5vcHNbaV0uY20uY3VyT3AgPSBudWxsO1xyXG4gICAgICBlbmRPcGVyYXRpb25zKGdyb3VwKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFRoZSBET00gdXBkYXRlcyBkb25lIHdoZW4gYW4gb3BlcmF0aW9uIGZpbmlzaGVzIGFyZSBiYXRjaGVkIHNvXHJcbiAgLy8gdGhhdCB0aGUgbWluaW11bSBudW1iZXIgb2YgcmVsYXlvdXRzIGFyZSByZXF1aXJlZC5cclxuICBmdW5jdGlvbiBlbmRPcGVyYXRpb25zKGdyb3VwKSB7XHJcbiAgICB2YXIgb3BzID0gZ3JvdXAub3BzO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvcHMubGVuZ3RoOyBpKyspIC8vIFJlYWQgRE9NXHJcbiAgICAgIGVuZE9wZXJhdGlvbl9SMShvcHNbaV0pO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvcHMubGVuZ3RoOyBpKyspIC8vIFdyaXRlIERPTSAobWF5YmUpXHJcbiAgICAgIGVuZE9wZXJhdGlvbl9XMShvcHNbaV0pO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvcHMubGVuZ3RoOyBpKyspIC8vIFJlYWQgRE9NXHJcbiAgICAgIGVuZE9wZXJhdGlvbl9SMihvcHNbaV0pO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvcHMubGVuZ3RoOyBpKyspIC8vIFdyaXRlIERPTSAobWF5YmUpXHJcbiAgICAgIGVuZE9wZXJhdGlvbl9XMihvcHNbaV0pO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvcHMubGVuZ3RoOyBpKyspIC8vIFJlYWQgRE9NXHJcbiAgICAgIGVuZE9wZXJhdGlvbl9maW5pc2gob3BzW2ldKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGVuZE9wZXJhdGlvbl9SMShvcCkge1xyXG4gICAgdmFyIGNtID0gb3AuY20sIGRpc3BsYXkgPSBjbS5kaXNwbGF5O1xyXG4gICAgbWF5YmVDbGlwU2Nyb2xsYmFycyhjbSk7XHJcbiAgICBpZiAob3AudXBkYXRlTWF4TGluZSkgZmluZE1heExpbmUoY20pO1xyXG5cclxuICAgIG9wLm11c3RVcGRhdGUgPSBvcC52aWV3Q2hhbmdlZCB8fCBvcC5mb3JjZVVwZGF0ZSB8fCBvcC5zY3JvbGxUb3AgIT0gbnVsbCB8fFxyXG4gICAgICBvcC5zY3JvbGxUb1BvcyAmJiAob3Auc2Nyb2xsVG9Qb3MuZnJvbS5saW5lIDwgZGlzcGxheS52aWV3RnJvbSB8fFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgb3Auc2Nyb2xsVG9Qb3MudG8ubGluZSA+PSBkaXNwbGF5LnZpZXdUbykgfHxcclxuICAgICAgZGlzcGxheS5tYXhMaW5lQ2hhbmdlZCAmJiBjbS5vcHRpb25zLmxpbmVXcmFwcGluZztcclxuICAgIG9wLnVwZGF0ZSA9IG9wLm11c3RVcGRhdGUgJiZcclxuICAgICAgbmV3IERpc3BsYXlVcGRhdGUoY20sIG9wLm11c3RVcGRhdGUgJiYge3RvcDogb3Auc2Nyb2xsVG9wLCBlbnN1cmU6IG9wLnNjcm9sbFRvUG9zfSwgb3AuZm9yY2VVcGRhdGUpO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gZW5kT3BlcmF0aW9uX1cxKG9wKSB7XHJcbiAgICBvcC51cGRhdGVkRGlzcGxheSA9IG9wLm11c3RVcGRhdGUgJiYgdXBkYXRlRGlzcGxheUlmTmVlZGVkKG9wLmNtLCBvcC51cGRhdGUpO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gZW5kT3BlcmF0aW9uX1IyKG9wKSB7XHJcbiAgICB2YXIgY20gPSBvcC5jbSwgZGlzcGxheSA9IGNtLmRpc3BsYXk7XHJcbiAgICBpZiAob3AudXBkYXRlZERpc3BsYXkpIHVwZGF0ZUhlaWdodHNJblZpZXdwb3J0KGNtKTtcclxuXHJcbiAgICBvcC5iYXJNZWFzdXJlID0gbWVhc3VyZUZvclNjcm9sbGJhcnMoY20pO1xyXG5cclxuICAgIC8vIElmIHRoZSBtYXggbGluZSBjaGFuZ2VkIHNpbmNlIGl0IHdhcyBsYXN0IG1lYXN1cmVkLCBtZWFzdXJlIGl0LFxyXG4gICAgLy8gYW5kIGVuc3VyZSB0aGUgZG9jdW1lbnQncyB3aWR0aCBtYXRjaGVzIGl0LlxyXG4gICAgLy8gdXBkYXRlRGlzcGxheV9XMiB3aWxsIHVzZSB0aGVzZSBwcm9wZXJ0aWVzIHRvIGRvIHRoZSBhY3R1YWwgcmVzaXppbmdcclxuICAgIGlmIChkaXNwbGF5Lm1heExpbmVDaGFuZ2VkICYmICFjbS5vcHRpb25zLmxpbmVXcmFwcGluZykge1xyXG4gICAgICBvcC5hZGp1c3RXaWR0aFRvID0gbWVhc3VyZUNoYXIoY20sIGRpc3BsYXkubWF4TGluZSwgZGlzcGxheS5tYXhMaW5lLnRleHQubGVuZ3RoKS5sZWZ0ICsgMztcclxuICAgICAgY20uZGlzcGxheS5zaXplcldpZHRoID0gb3AuYWRqdXN0V2lkdGhUbztcclxuICAgICAgb3AuYmFyTWVhc3VyZS5zY3JvbGxXaWR0aCA9XHJcbiAgICAgICAgTWF0aC5tYXgoZGlzcGxheS5zY3JvbGxlci5jbGllbnRXaWR0aCwgZGlzcGxheS5zaXplci5vZmZzZXRMZWZ0ICsgb3AuYWRqdXN0V2lkdGhUbyArIHNjcm9sbEdhcChjbSkgKyBjbS5kaXNwbGF5LmJhcldpZHRoKTtcclxuICAgICAgb3AubWF4U2Nyb2xsTGVmdCA9IE1hdGgubWF4KDAsIGRpc3BsYXkuc2l6ZXIub2Zmc2V0TGVmdCArIG9wLmFkanVzdFdpZHRoVG8gLSBkaXNwbGF5V2lkdGgoY20pKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAob3AudXBkYXRlZERpc3BsYXkgfHwgb3Auc2VsZWN0aW9uQ2hhbmdlZClcclxuICAgICAgb3AucHJlcGFyZWRTZWxlY3Rpb24gPSBkaXNwbGF5LmlucHV0LnByZXBhcmVTZWxlY3Rpb24oKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGVuZE9wZXJhdGlvbl9XMihvcCkge1xyXG4gICAgdmFyIGNtID0gb3AuY207XHJcblxyXG4gICAgaWYgKG9wLmFkanVzdFdpZHRoVG8gIT0gbnVsbCkge1xyXG4gICAgICBjbS5kaXNwbGF5LnNpemVyLnN0eWxlLm1pbldpZHRoID0gb3AuYWRqdXN0V2lkdGhUbyArIFwicHhcIjtcclxuICAgICAgaWYgKG9wLm1heFNjcm9sbExlZnQgPCBjbS5kb2Muc2Nyb2xsTGVmdClcclxuICAgICAgICBzZXRTY3JvbGxMZWZ0KGNtLCBNYXRoLm1pbihjbS5kaXNwbGF5LnNjcm9sbGVyLnNjcm9sbExlZnQsIG9wLm1heFNjcm9sbExlZnQpLCB0cnVlKTtcclxuICAgICAgY20uZGlzcGxheS5tYXhMaW5lQ2hhbmdlZCA9IGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChvcC5wcmVwYXJlZFNlbGVjdGlvbilcclxuICAgICAgY20uZGlzcGxheS5pbnB1dC5zaG93U2VsZWN0aW9uKG9wLnByZXBhcmVkU2VsZWN0aW9uKTtcclxuICAgIGlmIChvcC51cGRhdGVkRGlzcGxheSlcclxuICAgICAgc2V0RG9jdW1lbnRIZWlnaHQoY20sIG9wLmJhck1lYXN1cmUpO1xyXG4gICAgaWYgKG9wLnVwZGF0ZWREaXNwbGF5IHx8IG9wLnN0YXJ0SGVpZ2h0ICE9IGNtLmRvYy5oZWlnaHQpXHJcbiAgICAgIHVwZGF0ZVNjcm9sbGJhcnMoY20sIG9wLmJhck1lYXN1cmUpO1xyXG5cclxuICAgIGlmIChvcC5zZWxlY3Rpb25DaGFuZ2VkKSByZXN0YXJ0QmxpbmsoY20pO1xyXG5cclxuICAgIGlmIChjbS5zdGF0ZS5mb2N1c2VkICYmIG9wLnVwZGF0ZUlucHV0KVxyXG4gICAgICBjbS5kaXNwbGF5LmlucHV0LnJlc2V0KG9wLnR5cGluZyk7XHJcbiAgICBpZiAob3AuZm9jdXMgJiYgb3AuZm9jdXMgPT0gYWN0aXZlRWx0KCkgJiYgKCFkb2N1bWVudC5oYXNGb2N1cyB8fCBkb2N1bWVudC5oYXNGb2N1cygpKSlcclxuICAgICAgZW5zdXJlRm9jdXMob3AuY20pO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gZW5kT3BlcmF0aW9uX2ZpbmlzaChvcCkge1xyXG4gICAgdmFyIGNtID0gb3AuY20sIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCBkb2MgPSBjbS5kb2M7XHJcblxyXG4gICAgaWYgKG9wLnVwZGF0ZWREaXNwbGF5KSBwb3N0VXBkYXRlRGlzcGxheShjbSwgb3AudXBkYXRlKTtcclxuXHJcbiAgICAvLyBBYm9ydCBtb3VzZSB3aGVlbCBkZWx0YSBtZWFzdXJlbWVudCwgd2hlbiBzY3JvbGxpbmcgZXhwbGljaXRseVxyXG4gICAgaWYgKGRpc3BsYXkud2hlZWxTdGFydFggIT0gbnVsbCAmJiAob3Auc2Nyb2xsVG9wICE9IG51bGwgfHwgb3Auc2Nyb2xsTGVmdCAhPSBudWxsIHx8IG9wLnNjcm9sbFRvUG9zKSlcclxuICAgICAgZGlzcGxheS53aGVlbFN0YXJ0WCA9IGRpc3BsYXkud2hlZWxTdGFydFkgPSBudWxsO1xyXG5cclxuICAgIC8vIFByb3BhZ2F0ZSB0aGUgc2Nyb2xsIHBvc2l0aW9uIHRvIHRoZSBhY3R1YWwgRE9NIHNjcm9sbGVyXHJcbiAgICBpZiAob3Auc2Nyb2xsVG9wICE9IG51bGwgJiYgKGRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsVG9wICE9IG9wLnNjcm9sbFRvcCB8fCBvcC5mb3JjZVNjcm9sbCkpIHtcclxuICAgICAgZG9jLnNjcm9sbFRvcCA9IE1hdGgubWF4KDAsIE1hdGgubWluKGRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsSGVpZ2h0IC0gZGlzcGxheS5zY3JvbGxlci5jbGllbnRIZWlnaHQsIG9wLnNjcm9sbFRvcCkpO1xyXG4gICAgICBkaXNwbGF5LnNjcm9sbGJhcnMuc2V0U2Nyb2xsVG9wKGRvYy5zY3JvbGxUb3ApO1xyXG4gICAgICBkaXNwbGF5LnNjcm9sbGVyLnNjcm9sbFRvcCA9IGRvYy5zY3JvbGxUb3A7XHJcbiAgICB9XHJcbiAgICBpZiAob3Auc2Nyb2xsTGVmdCAhPSBudWxsICYmIChkaXNwbGF5LnNjcm9sbGVyLnNjcm9sbExlZnQgIT0gb3Auc2Nyb2xsTGVmdCB8fCBvcC5mb3JjZVNjcm9sbCkpIHtcclxuICAgICAgZG9jLnNjcm9sbExlZnQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbihkaXNwbGF5LnNjcm9sbGVyLnNjcm9sbFdpZHRoIC0gZGlzcGxheVdpZHRoKGNtKSwgb3Auc2Nyb2xsTGVmdCkpO1xyXG4gICAgICBkaXNwbGF5LnNjcm9sbGJhcnMuc2V0U2Nyb2xsTGVmdChkb2Muc2Nyb2xsTGVmdCk7XHJcbiAgICAgIGRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsTGVmdCA9IGRvYy5zY3JvbGxMZWZ0O1xyXG4gICAgICBhbGlnbkhvcml6b250YWxseShjbSk7XHJcbiAgICB9XHJcbiAgICAvLyBJZiB3ZSBuZWVkIHRvIHNjcm9sbCBhIHNwZWNpZmljIHBvc2l0aW9uIGludG8gdmlldywgZG8gc28uXHJcbiAgICBpZiAob3Auc2Nyb2xsVG9Qb3MpIHtcclxuICAgICAgdmFyIGNvb3JkcyA9IHNjcm9sbFBvc0ludG9WaWV3KGNtLCBjbGlwUG9zKGRvYywgb3Auc2Nyb2xsVG9Qb3MuZnJvbSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGlwUG9zKGRvYywgb3Auc2Nyb2xsVG9Qb3MudG8pLCBvcC5zY3JvbGxUb1Bvcy5tYXJnaW4pO1xyXG4gICAgICBpZiAob3Auc2Nyb2xsVG9Qb3MuaXNDdXJzb3IgJiYgY20uc3RhdGUuZm9jdXNlZCkgbWF5YmVTY3JvbGxXaW5kb3coY20sIGNvb3Jkcyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRmlyZSBldmVudHMgZm9yIG1hcmtlcnMgdGhhdCBhcmUgaGlkZGVuL3VuaWRkZW4gYnkgZWRpdGluZyBvclxyXG4gICAgLy8gdW5kb2luZ1xyXG4gICAgdmFyIGhpZGRlbiA9IG9wLm1heWJlSGlkZGVuTWFya2VycywgdW5oaWRkZW4gPSBvcC5tYXliZVVuaGlkZGVuTWFya2VycztcclxuICAgIGlmIChoaWRkZW4pIGZvciAodmFyIGkgPSAwOyBpIDwgaGlkZGVuLmxlbmd0aDsgKytpKVxyXG4gICAgICBpZiAoIWhpZGRlbltpXS5saW5lcy5sZW5ndGgpIHNpZ25hbChoaWRkZW5baV0sIFwiaGlkZVwiKTtcclxuICAgIGlmICh1bmhpZGRlbikgZm9yICh2YXIgaSA9IDA7IGkgPCB1bmhpZGRlbi5sZW5ndGg7ICsraSlcclxuICAgICAgaWYgKHVuaGlkZGVuW2ldLmxpbmVzLmxlbmd0aCkgc2lnbmFsKHVuaGlkZGVuW2ldLCBcInVuaGlkZVwiKTtcclxuXHJcbiAgICBpZiAoZGlzcGxheS53cmFwcGVyLm9mZnNldEhlaWdodClcclxuICAgICAgZG9jLnNjcm9sbFRvcCA9IGNtLmRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsVG9wO1xyXG5cclxuICAgIC8vIEZpcmUgY2hhbmdlIGV2ZW50cywgYW5kIGRlbGF5ZWQgZXZlbnQgaGFuZGxlcnNcclxuICAgIGlmIChvcC5jaGFuZ2VPYmpzKVxyXG4gICAgICBzaWduYWwoY20sIFwiY2hhbmdlc1wiLCBjbSwgb3AuY2hhbmdlT2Jqcyk7XHJcbiAgICBpZiAob3AudXBkYXRlKVxyXG4gICAgICBvcC51cGRhdGUuZmluaXNoKCk7XHJcbiAgfVxyXG5cclxuICAvLyBSdW4gdGhlIGdpdmVuIGZ1bmN0aW9uIGluIGFuIG9wZXJhdGlvblxyXG4gIGZ1bmN0aW9uIHJ1bkluT3AoY20sIGYpIHtcclxuICAgIGlmIChjbS5jdXJPcCkgcmV0dXJuIGYoKTtcclxuICAgIHN0YXJ0T3BlcmF0aW9uKGNtKTtcclxuICAgIHRyeSB7IHJldHVybiBmKCk7IH1cclxuICAgIGZpbmFsbHkgeyBlbmRPcGVyYXRpb24oY20pOyB9XHJcbiAgfVxyXG4gIC8vIFdyYXBzIGEgZnVuY3Rpb24gaW4gYW4gb3BlcmF0aW9uLiBSZXR1cm5zIHRoZSB3cmFwcGVkIGZ1bmN0aW9uLlxyXG4gIGZ1bmN0aW9uIG9wZXJhdGlvbihjbSwgZikge1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xyXG4gICAgICBpZiAoY20uY3VyT3ApIHJldHVybiBmLmFwcGx5KGNtLCBhcmd1bWVudHMpO1xyXG4gICAgICBzdGFydE9wZXJhdGlvbihjbSk7XHJcbiAgICAgIHRyeSB7IHJldHVybiBmLmFwcGx5KGNtLCBhcmd1bWVudHMpOyB9XHJcbiAgICAgIGZpbmFsbHkgeyBlbmRPcGVyYXRpb24oY20pOyB9XHJcbiAgICB9O1xyXG4gIH1cclxuICAvLyBVc2VkIHRvIGFkZCBtZXRob2RzIHRvIGVkaXRvciBhbmQgZG9jIGluc3RhbmNlcywgd3JhcHBpbmcgdGhlbSBpblxyXG4gIC8vIG9wZXJhdGlvbnMuXHJcbiAgZnVuY3Rpb24gbWV0aG9kT3AoZikge1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xyXG4gICAgICBpZiAodGhpcy5jdXJPcCkgcmV0dXJuIGYuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcclxuICAgICAgc3RhcnRPcGVyYXRpb24odGhpcyk7XHJcbiAgICAgIHRyeSB7IHJldHVybiBmLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH1cclxuICAgICAgZmluYWxseSB7IGVuZE9wZXJhdGlvbih0aGlzKTsgfVxyXG4gICAgfTtcclxuICB9XHJcbiAgZnVuY3Rpb24gZG9jTWV0aG9kT3AoZikge1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xyXG4gICAgICB2YXIgY20gPSB0aGlzLmNtO1xyXG4gICAgICBpZiAoIWNtIHx8IGNtLmN1ck9wKSByZXR1cm4gZi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xyXG4gICAgICBzdGFydE9wZXJhdGlvbihjbSk7XHJcbiAgICAgIHRyeSB7IHJldHVybiBmLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7IH1cclxuICAgICAgZmluYWxseSB7IGVuZE9wZXJhdGlvbihjbSk7IH1cclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBWSUVXIFRSQUNLSU5HXHJcblxyXG4gIC8vIFRoZXNlIG9iamVjdHMgYXJlIHVzZWQgdG8gcmVwcmVzZW50IHRoZSB2aXNpYmxlIChjdXJyZW50bHkgZHJhd24pXHJcbiAgLy8gcGFydCBvZiB0aGUgZG9jdW1lbnQuIEEgTGluZVZpZXcgbWF5IGNvcnJlc3BvbmQgdG8gbXVsdGlwbGVcclxuICAvLyBsb2dpY2FsIGxpbmVzLCBpZiB0aG9zZSBhcmUgY29ubmVjdGVkIGJ5IGNvbGxhcHNlZCByYW5nZXMuXHJcbiAgZnVuY3Rpb24gTGluZVZpZXcoZG9jLCBsaW5lLCBsaW5lTikge1xyXG4gICAgLy8gVGhlIHN0YXJ0aW5nIGxpbmVcclxuICAgIHRoaXMubGluZSA9IGxpbmU7XHJcbiAgICAvLyBDb250aW51aW5nIGxpbmVzLCBpZiBhbnlcclxuICAgIHRoaXMucmVzdCA9IHZpc3VhbExpbmVDb250aW51ZWQobGluZSk7XHJcbiAgICAvLyBOdW1iZXIgb2YgbG9naWNhbCBsaW5lcyBpbiB0aGlzIHZpc3VhbCBsaW5lXHJcbiAgICB0aGlzLnNpemUgPSB0aGlzLnJlc3QgPyBsaW5lTm8obHN0KHRoaXMucmVzdCkpIC0gbGluZU4gKyAxIDogMTtcclxuICAgIHRoaXMubm9kZSA9IHRoaXMudGV4dCA9IG51bGw7XHJcbiAgICB0aGlzLmhpZGRlbiA9IGxpbmVJc0hpZGRlbihkb2MsIGxpbmUpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcmFuZ2Ugb2YgTGluZVZpZXcgb2JqZWN0cyBmb3IgdGhlIGdpdmVuIGxpbmVzLlxyXG4gIGZ1bmN0aW9uIGJ1aWxkVmlld0FycmF5KGNtLCBmcm9tLCB0bykge1xyXG4gICAgdmFyIGFycmF5ID0gW10sIG5leHRQb3M7XHJcbiAgICBmb3IgKHZhciBwb3MgPSBmcm9tOyBwb3MgPCB0bzsgcG9zID0gbmV4dFBvcykge1xyXG4gICAgICB2YXIgdmlldyA9IG5ldyBMaW5lVmlldyhjbS5kb2MsIGdldExpbmUoY20uZG9jLCBwb3MpLCBwb3MpO1xyXG4gICAgICBuZXh0UG9zID0gcG9zICsgdmlldy5zaXplO1xyXG4gICAgICBhcnJheS5wdXNoKHZpZXcpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGFycmF5O1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlcyB0aGUgZGlzcGxheS52aWV3IGRhdGEgc3RydWN0dXJlIGZvciBhIGdpdmVuIGNoYW5nZSB0byB0aGVcclxuICAvLyBkb2N1bWVudC4gRnJvbSBhbmQgdG8gYXJlIGluIHByZS1jaGFuZ2UgY29vcmRpbmF0ZXMuIExlbmRpZmYgaXNcclxuICAvLyB0aGUgYW1vdW50IG9mIGxpbmVzIGFkZGVkIG9yIHN1YnRyYWN0ZWQgYnkgdGhlIGNoYW5nZS4gVGhpcyBpc1xyXG4gIC8vIHVzZWQgZm9yIGNoYW5nZXMgdGhhdCBzcGFuIG11bHRpcGxlIGxpbmVzLCBvciBjaGFuZ2UgdGhlIHdheVxyXG4gIC8vIGxpbmVzIGFyZSBkaXZpZGVkIGludG8gdmlzdWFsIGxpbmVzLiByZWdMaW5lQ2hhbmdlIChiZWxvdylcclxuICAvLyByZWdpc3RlcnMgc2luZ2xlLWxpbmUgY2hhbmdlcy5cclxuICBmdW5jdGlvbiByZWdDaGFuZ2UoY20sIGZyb20sIHRvLCBsZW5kaWZmKSB7XHJcbiAgICBpZiAoZnJvbSA9PSBudWxsKSBmcm9tID0gY20uZG9jLmZpcnN0O1xyXG4gICAgaWYgKHRvID09IG51bGwpIHRvID0gY20uZG9jLmZpcnN0ICsgY20uZG9jLnNpemU7XHJcbiAgICBpZiAoIWxlbmRpZmYpIGxlbmRpZmYgPSAwO1xyXG5cclxuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheTtcclxuICAgIGlmIChsZW5kaWZmICYmIHRvIDwgZGlzcGxheS52aWV3VG8gJiZcclxuICAgICAgICAoZGlzcGxheS51cGRhdGVMaW5lTnVtYmVycyA9PSBudWxsIHx8IGRpc3BsYXkudXBkYXRlTGluZU51bWJlcnMgPiBmcm9tKSlcclxuICAgICAgZGlzcGxheS51cGRhdGVMaW5lTnVtYmVycyA9IGZyb207XHJcblxyXG4gICAgY20uY3VyT3Audmlld0NoYW5nZWQgPSB0cnVlO1xyXG5cclxuICAgIGlmIChmcm9tID49IGRpc3BsYXkudmlld1RvKSB7IC8vIENoYW5nZSBhZnRlclxyXG4gICAgICBpZiAoc2F3Q29sbGFwc2VkU3BhbnMgJiYgdmlzdWFsTGluZU5vKGNtLmRvYywgZnJvbSkgPCBkaXNwbGF5LnZpZXdUbylcclxuICAgICAgICByZXNldFZpZXcoY20pO1xyXG4gICAgfSBlbHNlIGlmICh0byA8PSBkaXNwbGF5LnZpZXdGcm9tKSB7IC8vIENoYW5nZSBiZWZvcmVcclxuICAgICAgaWYgKHNhd0NvbGxhcHNlZFNwYW5zICYmIHZpc3VhbExpbmVFbmRObyhjbS5kb2MsIHRvICsgbGVuZGlmZikgPiBkaXNwbGF5LnZpZXdGcm9tKSB7XHJcbiAgICAgICAgcmVzZXRWaWV3KGNtKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBkaXNwbGF5LnZpZXdGcm9tICs9IGxlbmRpZmY7XHJcbiAgICAgICAgZGlzcGxheS52aWV3VG8gKz0gbGVuZGlmZjtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIGlmIChmcm9tIDw9IGRpc3BsYXkudmlld0Zyb20gJiYgdG8gPj0gZGlzcGxheS52aWV3VG8pIHsgLy8gRnVsbCBvdmVybGFwXHJcbiAgICAgIHJlc2V0VmlldyhjbSk7XHJcbiAgICB9IGVsc2UgaWYgKGZyb20gPD0gZGlzcGxheS52aWV3RnJvbSkgeyAvLyBUb3Agb3ZlcmxhcFxyXG4gICAgICB2YXIgY3V0ID0gdmlld0N1dHRpbmdQb2ludChjbSwgdG8sIHRvICsgbGVuZGlmZiwgMSk7XHJcbiAgICAgIGlmIChjdXQpIHtcclxuICAgICAgICBkaXNwbGF5LnZpZXcgPSBkaXNwbGF5LnZpZXcuc2xpY2UoY3V0LmluZGV4KTtcclxuICAgICAgICBkaXNwbGF5LnZpZXdGcm9tID0gY3V0LmxpbmVOO1xyXG4gICAgICAgIGRpc3BsYXkudmlld1RvICs9IGxlbmRpZmY7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgcmVzZXRWaWV3KGNtKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIGlmICh0byA+PSBkaXNwbGF5LnZpZXdUbykgeyAvLyBCb3R0b20gb3ZlcmxhcFxyXG4gICAgICB2YXIgY3V0ID0gdmlld0N1dHRpbmdQb2ludChjbSwgZnJvbSwgZnJvbSwgLTEpO1xyXG4gICAgICBpZiAoY3V0KSB7XHJcbiAgICAgICAgZGlzcGxheS52aWV3ID0gZGlzcGxheS52aWV3LnNsaWNlKDAsIGN1dC5pbmRleCk7XHJcbiAgICAgICAgZGlzcGxheS52aWV3VG8gPSBjdXQubGluZU47XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgcmVzZXRWaWV3KGNtKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHsgLy8gR2FwIGluIHRoZSBtaWRkbGVcclxuICAgICAgdmFyIGN1dFRvcCA9IHZpZXdDdXR0aW5nUG9pbnQoY20sIGZyb20sIGZyb20sIC0xKTtcclxuICAgICAgdmFyIGN1dEJvdCA9IHZpZXdDdXR0aW5nUG9pbnQoY20sIHRvLCB0byArIGxlbmRpZmYsIDEpO1xyXG4gICAgICBpZiAoY3V0VG9wICYmIGN1dEJvdCkge1xyXG4gICAgICAgIGRpc3BsYXkudmlldyA9IGRpc3BsYXkudmlldy5zbGljZSgwLCBjdXRUb3AuaW5kZXgpXHJcbiAgICAgICAgICAuY29uY2F0KGJ1aWxkVmlld0FycmF5KGNtLCBjdXRUb3AubGluZU4sIGN1dEJvdC5saW5lTikpXHJcbiAgICAgICAgICAuY29uY2F0KGRpc3BsYXkudmlldy5zbGljZShjdXRCb3QuaW5kZXgpKTtcclxuICAgICAgICBkaXNwbGF5LnZpZXdUbyArPSBsZW5kaWZmO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHJlc2V0VmlldyhjbSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICB2YXIgZXh0ID0gZGlzcGxheS5leHRlcm5hbE1lYXN1cmVkO1xyXG4gICAgaWYgKGV4dCkge1xyXG4gICAgICBpZiAodG8gPCBleHQubGluZU4pXHJcbiAgICAgICAgZXh0LmxpbmVOICs9IGxlbmRpZmY7XHJcbiAgICAgIGVsc2UgaWYgKGZyb20gPCBleHQubGluZU4gKyBleHQuc2l6ZSlcclxuICAgICAgICBkaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQgPSBudWxsO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmVnaXN0ZXIgYSBjaGFuZ2UgdG8gYSBzaW5nbGUgbGluZS4gVHlwZSBtdXN0IGJlIG9uZSBvZiBcInRleHRcIixcclxuICAvLyBcImd1dHRlclwiLCBcImNsYXNzXCIsIFwid2lkZ2V0XCJcclxuICBmdW5jdGlvbiByZWdMaW5lQ2hhbmdlKGNtLCBsaW5lLCB0eXBlKSB7XHJcbiAgICBjbS5jdXJPcC52aWV3Q2hhbmdlZCA9IHRydWU7XHJcbiAgICB2YXIgZGlzcGxheSA9IGNtLmRpc3BsYXksIGV4dCA9IGNtLmRpc3BsYXkuZXh0ZXJuYWxNZWFzdXJlZDtcclxuICAgIGlmIChleHQgJiYgbGluZSA+PSBleHQubGluZU4gJiYgbGluZSA8IGV4dC5saW5lTiArIGV4dC5zaXplKVxyXG4gICAgICBkaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQgPSBudWxsO1xyXG5cclxuICAgIGlmIChsaW5lIDwgZGlzcGxheS52aWV3RnJvbSB8fCBsaW5lID49IGRpc3BsYXkudmlld1RvKSByZXR1cm47XHJcbiAgICB2YXIgbGluZVZpZXcgPSBkaXNwbGF5LnZpZXdbZmluZFZpZXdJbmRleChjbSwgbGluZSldO1xyXG4gICAgaWYgKGxpbmVWaWV3Lm5vZGUgPT0gbnVsbCkgcmV0dXJuO1xyXG4gICAgdmFyIGFyciA9IGxpbmVWaWV3LmNoYW5nZXMgfHwgKGxpbmVWaWV3LmNoYW5nZXMgPSBbXSk7XHJcbiAgICBpZiAoaW5kZXhPZihhcnIsIHR5cGUpID09IC0xKSBhcnIucHVzaCh0eXBlKTtcclxuICB9XHJcblxyXG4gIC8vIENsZWFyIHRoZSB2aWV3LlxyXG4gIGZ1bmN0aW9uIHJlc2V0VmlldyhjbSkge1xyXG4gICAgY20uZGlzcGxheS52aWV3RnJvbSA9IGNtLmRpc3BsYXkudmlld1RvID0gY20uZG9jLmZpcnN0O1xyXG4gICAgY20uZGlzcGxheS52aWV3ID0gW107XHJcbiAgICBjbS5kaXNwbGF5LnZpZXdPZmZzZXQgPSAwO1xyXG4gIH1cclxuXHJcbiAgLy8gRmluZCB0aGUgdmlldyBlbGVtZW50IGNvcnJlc3BvbmRpbmcgdG8gYSBnaXZlbiBsaW5lLiBSZXR1cm4gbnVsbFxyXG4gIC8vIHdoZW4gdGhlIGxpbmUgaXNuJ3QgdmlzaWJsZS5cclxuICBmdW5jdGlvbiBmaW5kVmlld0luZGV4KGNtLCBuKSB7XHJcbiAgICBpZiAobiA+PSBjbS5kaXNwbGF5LnZpZXdUbykgcmV0dXJuIG51bGw7XHJcbiAgICBuIC09IGNtLmRpc3BsYXkudmlld0Zyb207XHJcbiAgICBpZiAobiA8IDApIHJldHVybiBudWxsO1xyXG4gICAgdmFyIHZpZXcgPSBjbS5kaXNwbGF5LnZpZXc7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZpZXcubGVuZ3RoOyBpKyspIHtcclxuICAgICAgbiAtPSB2aWV3W2ldLnNpemU7XHJcbiAgICAgIGlmIChuIDwgMCkgcmV0dXJuIGk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiB2aWV3Q3V0dGluZ1BvaW50KGNtLCBvbGROLCBuZXdOLCBkaXIpIHtcclxuICAgIHZhciBpbmRleCA9IGZpbmRWaWV3SW5kZXgoY20sIG9sZE4pLCBkaWZmLCB2aWV3ID0gY20uZGlzcGxheS52aWV3O1xyXG4gICAgaWYgKCFzYXdDb2xsYXBzZWRTcGFucyB8fCBuZXdOID09IGNtLmRvYy5maXJzdCArIGNtLmRvYy5zaXplKVxyXG4gICAgICByZXR1cm4ge2luZGV4OiBpbmRleCwgbGluZU46IG5ld059O1xyXG4gICAgZm9yICh2YXIgaSA9IDAsIG4gPSBjbS5kaXNwbGF5LnZpZXdGcm9tOyBpIDwgaW5kZXg7IGkrKylcclxuICAgICAgbiArPSB2aWV3W2ldLnNpemU7XHJcbiAgICBpZiAobiAhPSBvbGROKSB7XHJcbiAgICAgIGlmIChkaXIgPiAwKSB7XHJcbiAgICAgICAgaWYgKGluZGV4ID09IHZpZXcubGVuZ3RoIC0gMSkgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgZGlmZiA9IChuICsgdmlld1tpbmRleF0uc2l6ZSkgLSBvbGROO1xyXG4gICAgICAgIGluZGV4Kys7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgZGlmZiA9IG4gLSBvbGROO1xyXG4gICAgICB9XHJcbiAgICAgIG9sZE4gKz0gZGlmZjsgbmV3TiArPSBkaWZmO1xyXG4gICAgfVxyXG4gICAgd2hpbGUgKHZpc3VhbExpbmVObyhjbS5kb2MsIG5ld04pICE9IG5ld04pIHtcclxuICAgICAgaWYgKGluZGV4ID09IChkaXIgPCAwID8gMCA6IHZpZXcubGVuZ3RoIC0gMSkpIHJldHVybiBudWxsO1xyXG4gICAgICBuZXdOICs9IGRpciAqIHZpZXdbaW5kZXggLSAoZGlyIDwgMCA/IDEgOiAwKV0uc2l6ZTtcclxuICAgICAgaW5kZXggKz0gZGlyO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHtpbmRleDogaW5kZXgsIGxpbmVOOiBuZXdOfTtcclxuICB9XHJcblxyXG4gIC8vIEZvcmNlIHRoZSB2aWV3IHRvIGNvdmVyIGEgZ2l2ZW4gcmFuZ2UsIGFkZGluZyBlbXB0eSB2aWV3IGVsZW1lbnRcclxuICAvLyBvciBjbGlwcGluZyBvZmYgZXhpc3Rpbmcgb25lcyBhcyBuZWVkZWQuXHJcbiAgZnVuY3Rpb24gYWRqdXN0VmlldyhjbSwgZnJvbSwgdG8pIHtcclxuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheSwgdmlldyA9IGRpc3BsYXkudmlldztcclxuICAgIGlmICh2aWV3Lmxlbmd0aCA9PSAwIHx8IGZyb20gPj0gZGlzcGxheS52aWV3VG8gfHwgdG8gPD0gZGlzcGxheS52aWV3RnJvbSkge1xyXG4gICAgICBkaXNwbGF5LnZpZXcgPSBidWlsZFZpZXdBcnJheShjbSwgZnJvbSwgdG8pO1xyXG4gICAgICBkaXNwbGF5LnZpZXdGcm9tID0gZnJvbTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGlmIChkaXNwbGF5LnZpZXdGcm9tID4gZnJvbSlcclxuICAgICAgICBkaXNwbGF5LnZpZXcgPSBidWlsZFZpZXdBcnJheShjbSwgZnJvbSwgZGlzcGxheS52aWV3RnJvbSkuY29uY2F0KGRpc3BsYXkudmlldyk7XHJcbiAgICAgIGVsc2UgaWYgKGRpc3BsYXkudmlld0Zyb20gPCBmcm9tKVxyXG4gICAgICAgIGRpc3BsYXkudmlldyA9IGRpc3BsYXkudmlldy5zbGljZShmaW5kVmlld0luZGV4KGNtLCBmcm9tKSk7XHJcbiAgICAgIGRpc3BsYXkudmlld0Zyb20gPSBmcm9tO1xyXG4gICAgICBpZiAoZGlzcGxheS52aWV3VG8gPCB0bylcclxuICAgICAgICBkaXNwbGF5LnZpZXcgPSBkaXNwbGF5LnZpZXcuY29uY2F0KGJ1aWxkVmlld0FycmF5KGNtLCBkaXNwbGF5LnZpZXdUbywgdG8pKTtcclxuICAgICAgZWxzZSBpZiAoZGlzcGxheS52aWV3VG8gPiB0bylcclxuICAgICAgICBkaXNwbGF5LnZpZXcgPSBkaXNwbGF5LnZpZXcuc2xpY2UoMCwgZmluZFZpZXdJbmRleChjbSwgdG8pKTtcclxuICAgIH1cclxuICAgIGRpc3BsYXkudmlld1RvID0gdG87XHJcbiAgfVxyXG5cclxuICAvLyBDb3VudCB0aGUgbnVtYmVyIG9mIGxpbmVzIGluIHRoZSB2aWV3IHdob3NlIERPTSByZXByZXNlbnRhdGlvbiBpc1xyXG4gIC8vIG91dCBvZiBkYXRlIChvciBub25leGlzdGVudCkuXHJcbiAgZnVuY3Rpb24gY291bnREaXJ0eVZpZXcoY20pIHtcclxuICAgIHZhciB2aWV3ID0gY20uZGlzcGxheS52aWV3LCBkaXJ0eSA9IDA7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZpZXcubGVuZ3RoOyBpKyspIHtcclxuICAgICAgdmFyIGxpbmVWaWV3ID0gdmlld1tpXTtcclxuICAgICAgaWYgKCFsaW5lVmlldy5oaWRkZW4gJiYgKCFsaW5lVmlldy5ub2RlIHx8IGxpbmVWaWV3LmNoYW5nZXMpKSArK2RpcnR5O1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGRpcnR5O1xyXG4gIH1cclxuXHJcbiAgLy8gRVZFTlQgSEFORExFUlNcclxuXHJcbiAgLy8gQXR0YWNoIHRoZSBuZWNlc3NhcnkgZXZlbnQgaGFuZGxlcnMgd2hlbiBpbml0aWFsaXppbmcgdGhlIGVkaXRvclxyXG4gIGZ1bmN0aW9uIHJlZ2lzdGVyRXZlbnRIYW5kbGVycyhjbSkge1xyXG4gICAgdmFyIGQgPSBjbS5kaXNwbGF5O1xyXG4gICAgb24oZC5zY3JvbGxlciwgXCJtb3VzZWRvd25cIiwgb3BlcmF0aW9uKGNtLCBvbk1vdXNlRG93bikpO1xyXG4gICAgLy8gT2xkZXIgSUUncyB3aWxsIG5vdCBmaXJlIGEgc2Vjb25kIG1vdXNlZG93biBmb3IgYSBkb3VibGUgY2xpY2tcclxuICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uIDwgMTEpXHJcbiAgICAgIG9uKGQuc2Nyb2xsZXIsIFwiZGJsY2xpY2tcIiwgb3BlcmF0aW9uKGNtLCBmdW5jdGlvbihlKSB7XHJcbiAgICAgICAgaWYgKHNpZ25hbERPTUV2ZW50KGNtLCBlKSkgcmV0dXJuO1xyXG4gICAgICAgIHZhciBwb3MgPSBwb3NGcm9tTW91c2UoY20sIGUpO1xyXG4gICAgICAgIGlmICghcG9zIHx8IGNsaWNrSW5HdXR0ZXIoY20sIGUpIHx8IGV2ZW50SW5XaWRnZXQoY20uZGlzcGxheSwgZSkpIHJldHVybjtcclxuICAgICAgICBlX3ByZXZlbnREZWZhdWx0KGUpO1xyXG4gICAgICAgIHZhciB3b3JkID0gY20uZmluZFdvcmRBdChwb3MpO1xyXG4gICAgICAgIGV4dGVuZFNlbGVjdGlvbihjbS5kb2MsIHdvcmQuYW5jaG9yLCB3b3JkLmhlYWQpO1xyXG4gICAgICB9KSk7XHJcbiAgICBlbHNlXHJcbiAgICAgIG9uKGQuc2Nyb2xsZXIsIFwiZGJsY2xpY2tcIiwgZnVuY3Rpb24oZSkgeyBzaWduYWxET01FdmVudChjbSwgZSkgfHwgZV9wcmV2ZW50RGVmYXVsdChlKTsgfSk7XHJcbiAgICAvLyBTb21lIGJyb3dzZXJzIGZpcmUgY29udGV4dG1lbnUgKmFmdGVyKiBvcGVuaW5nIHRoZSBtZW51LCBhdFxyXG4gICAgLy8gd2hpY2ggcG9pbnQgd2UgY2FuJ3QgbWVzcyB3aXRoIGl0IGFueW1vcmUuIENvbnRleHQgbWVudSBpc1xyXG4gICAgLy8gaGFuZGxlZCBpbiBvbk1vdXNlRG93biBmb3IgdGhlc2UgYnJvd3NlcnMuXHJcbiAgICBpZiAoIWNhcHR1cmVSaWdodENsaWNrKSBvbihkLnNjcm9sbGVyLCBcImNvbnRleHRtZW51XCIsIGZ1bmN0aW9uKGUpIHtvbkNvbnRleHRNZW51KGNtLCBlKTt9KTtcclxuXHJcbiAgICAvLyBVc2VkIHRvIHN1cHByZXNzIG1vdXNlIGV2ZW50IGhhbmRsaW5nIHdoZW4gYSB0b3VjaCBoYXBwZW5zXHJcbiAgICB2YXIgdG91Y2hGaW5pc2hlZCwgcHJldlRvdWNoID0ge2VuZDogMH07XHJcbiAgICBmdW5jdGlvbiBmaW5pc2hUb3VjaCgpIHtcclxuICAgICAgaWYgKGQuYWN0aXZlVG91Y2gpIHtcclxuICAgICAgICB0b3VjaEZpbmlzaGVkID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtkLmFjdGl2ZVRvdWNoID0gbnVsbDt9LCAxMDAwKTtcclxuICAgICAgICBwcmV2VG91Y2ggPSBkLmFjdGl2ZVRvdWNoO1xyXG4gICAgICAgIHByZXZUb3VjaC5lbmQgPSArbmV3IERhdGU7XHJcbiAgICAgIH1cclxuICAgIH07XHJcbiAgICBmdW5jdGlvbiBpc01vdXNlTGlrZVRvdWNoRXZlbnQoZSkge1xyXG4gICAgICBpZiAoZS50b3VjaGVzLmxlbmd0aCAhPSAxKSByZXR1cm4gZmFsc2U7XHJcbiAgICAgIHZhciB0b3VjaCA9IGUudG91Y2hlc1swXTtcclxuICAgICAgcmV0dXJuIHRvdWNoLnJhZGl1c1ggPD0gMSAmJiB0b3VjaC5yYWRpdXNZIDw9IDE7XHJcbiAgICB9XHJcbiAgICBmdW5jdGlvbiBmYXJBd2F5KHRvdWNoLCBvdGhlcikge1xyXG4gICAgICBpZiAob3RoZXIubGVmdCA9PSBudWxsKSByZXR1cm4gdHJ1ZTtcclxuICAgICAgdmFyIGR4ID0gb3RoZXIubGVmdCAtIHRvdWNoLmxlZnQsIGR5ID0gb3RoZXIudG9wIC0gdG91Y2gudG9wO1xyXG4gICAgICByZXR1cm4gZHggKiBkeCArIGR5ICogZHkgPiAyMCAqIDIwO1xyXG4gICAgfVxyXG4gICAgb24oZC5zY3JvbGxlciwgXCJ0b3VjaHN0YXJ0XCIsIGZ1bmN0aW9uKGUpIHtcclxuICAgICAgaWYgKCFpc01vdXNlTGlrZVRvdWNoRXZlbnQoZSkpIHtcclxuICAgICAgICBjbGVhclRpbWVvdXQodG91Y2hGaW5pc2hlZCk7XHJcbiAgICAgICAgdmFyIG5vdyA9ICtuZXcgRGF0ZTtcclxuICAgICAgICBkLmFjdGl2ZVRvdWNoID0ge3N0YXJ0OiBub3csIG1vdmVkOiBmYWxzZSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgIHByZXY6IG5vdyAtIHByZXZUb3VjaC5lbmQgPD0gMzAwID8gcHJldlRvdWNoIDogbnVsbH07XHJcbiAgICAgICAgaWYgKGUudG91Y2hlcy5sZW5ndGggPT0gMSkge1xyXG4gICAgICAgICAgZC5hY3RpdmVUb3VjaC5sZWZ0ID0gZS50b3VjaGVzWzBdLnBhZ2VYO1xyXG4gICAgICAgICAgZC5hY3RpdmVUb3VjaC50b3AgPSBlLnRvdWNoZXNbMF0ucGFnZVk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICAgIG9uKGQuc2Nyb2xsZXIsIFwidG91Y2htb3ZlXCIsIGZ1bmN0aW9uKCkge1xyXG4gICAgICBpZiAoZC5hY3RpdmVUb3VjaCkgZC5hY3RpdmVUb3VjaC5tb3ZlZCA9IHRydWU7XHJcbiAgICB9KTtcclxuICAgIG9uKGQuc2Nyb2xsZXIsIFwidG91Y2hlbmRcIiwgZnVuY3Rpb24oZSkge1xyXG4gICAgICB2YXIgdG91Y2ggPSBkLmFjdGl2ZVRvdWNoO1xyXG4gICAgICBpZiAodG91Y2ggJiYgIWV2ZW50SW5XaWRnZXQoZCwgZSkgJiYgdG91Y2gubGVmdCAhPSBudWxsICYmXHJcbiAgICAgICAgICAhdG91Y2gubW92ZWQgJiYgbmV3IERhdGUgLSB0b3VjaC5zdGFydCA8IDMwMCkge1xyXG4gICAgICAgIHZhciBwb3MgPSBjbS5jb29yZHNDaGFyKGQuYWN0aXZlVG91Y2gsIFwicGFnZVwiKSwgcmFuZ2U7XHJcbiAgICAgICAgaWYgKCF0b3VjaC5wcmV2IHx8IGZhckF3YXkodG91Y2gsIHRvdWNoLnByZXYpKSAvLyBTaW5nbGUgdGFwXHJcbiAgICAgICAgICByYW5nZSA9IG5ldyBSYW5nZShwb3MsIHBvcyk7XHJcbiAgICAgICAgZWxzZSBpZiAoIXRvdWNoLnByZXYucHJldiB8fCBmYXJBd2F5KHRvdWNoLCB0b3VjaC5wcmV2LnByZXYpKSAvLyBEb3VibGUgdGFwXHJcbiAgICAgICAgICByYW5nZSA9IGNtLmZpbmRXb3JkQXQocG9zKTtcclxuICAgICAgICBlbHNlIC8vIFRyaXBsZSB0YXBcclxuICAgICAgICAgIHJhbmdlID0gbmV3IFJhbmdlKFBvcyhwb3MubGluZSwgMCksIGNsaXBQb3MoY20uZG9jLCBQb3MocG9zLmxpbmUgKyAxLCAwKSkpO1xyXG4gICAgICAgIGNtLnNldFNlbGVjdGlvbihyYW5nZS5hbmNob3IsIHJhbmdlLmhlYWQpO1xyXG4gICAgICAgIGNtLmZvY3VzKCk7XHJcbiAgICAgICAgZV9wcmV2ZW50RGVmYXVsdChlKTtcclxuICAgICAgfVxyXG4gICAgICBmaW5pc2hUb3VjaCgpO1xyXG4gICAgfSk7XHJcbiAgICBvbihkLnNjcm9sbGVyLCBcInRvdWNoY2FuY2VsXCIsIGZpbmlzaFRvdWNoKTtcclxuXHJcbiAgICAvLyBTeW5jIHNjcm9sbGluZyBiZXR3ZWVuIGZha2Ugc2Nyb2xsYmFycyBhbmQgcmVhbCBzY3JvbGxhYmxlXHJcbiAgICAvLyBhcmVhLCBlbnN1cmUgdmlld3BvcnQgaXMgdXBkYXRlZCB3aGVuIHNjcm9sbGluZy5cclxuICAgIG9uKGQuc2Nyb2xsZXIsIFwic2Nyb2xsXCIsIGZ1bmN0aW9uKCkge1xyXG4gICAgICBpZiAoZC5zY3JvbGxlci5jbGllbnRIZWlnaHQpIHtcclxuICAgICAgICBzZXRTY3JvbGxUb3AoY20sIGQuc2Nyb2xsZXIuc2Nyb2xsVG9wKTtcclxuICAgICAgICBzZXRTY3JvbGxMZWZ0KGNtLCBkLnNjcm9sbGVyLnNjcm9sbExlZnQsIHRydWUpO1xyXG4gICAgICAgIHNpZ25hbChjbSwgXCJzY3JvbGxcIiwgY20pO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBMaXN0ZW4gdG8gd2hlZWwgZXZlbnRzIGluIG9yZGVyIHRvIHRyeSBhbmQgdXBkYXRlIHRoZSB2aWV3cG9ydCBvbiB0aW1lLlxyXG4gICAgb24oZC5zY3JvbGxlciwgXCJtb3VzZXdoZWVsXCIsIGZ1bmN0aW9uKGUpe29uU2Nyb2xsV2hlZWwoY20sIGUpO30pO1xyXG4gICAgb24oZC5zY3JvbGxlciwgXCJET01Nb3VzZVNjcm9sbFwiLCBmdW5jdGlvbihlKXtvblNjcm9sbFdoZWVsKGNtLCBlKTt9KTtcclxuXHJcbiAgICAvLyBQcmV2ZW50IHdyYXBwZXIgZnJvbSBldmVyIHNjcm9sbGluZ1xyXG4gICAgb24oZC53cmFwcGVyLCBcInNjcm9sbFwiLCBmdW5jdGlvbigpIHsgZC53cmFwcGVyLnNjcm9sbFRvcCA9IGQud3JhcHBlci5zY3JvbGxMZWZ0ID0gMDsgfSk7XHJcblxyXG4gICAgZC5kcmFnRnVuY3Rpb25zID0ge1xyXG4gICAgICBlbnRlcjogZnVuY3Rpb24oZSkge2lmICghc2lnbmFsRE9NRXZlbnQoY20sIGUpKSBlX3N0b3AoZSk7fSxcclxuICAgICAgb3ZlcjogZnVuY3Rpb24oZSkge2lmICghc2lnbmFsRE9NRXZlbnQoY20sIGUpKSB7IG9uRHJhZ092ZXIoY20sIGUpOyBlX3N0b3AoZSk7IH19LFxyXG4gICAgICBzdGFydDogZnVuY3Rpb24oZSl7b25EcmFnU3RhcnQoY20sIGUpO30sXHJcbiAgICAgIGRyb3A6IG9wZXJhdGlvbihjbSwgb25Ecm9wKSxcclxuICAgICAgbGVhdmU6IGZ1bmN0aW9uKCkge2NsZWFyRHJhZ0N1cnNvcihjbSk7fVxyXG4gICAgfTtcclxuXHJcbiAgICB2YXIgaW5wID0gZC5pbnB1dC5nZXRGaWVsZCgpO1xyXG4gICAgb24oaW5wLCBcImtleXVwXCIsIGZ1bmN0aW9uKGUpIHsgb25LZXlVcC5jYWxsKGNtLCBlKTsgfSk7XHJcbiAgICBvbihpbnAsIFwia2V5ZG93blwiLCBvcGVyYXRpb24oY20sIG9uS2V5RG93bikpO1xyXG4gICAgb24oaW5wLCBcImtleXByZXNzXCIsIG9wZXJhdGlvbihjbSwgb25LZXlQcmVzcykpO1xyXG4gICAgb24oaW5wLCBcImZvY3VzXCIsIGJpbmQob25Gb2N1cywgY20pKTtcclxuICAgIG9uKGlucCwgXCJibHVyXCIsIGJpbmQob25CbHVyLCBjbSkpO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gZHJhZ0Ryb3BDaGFuZ2VkKGNtLCB2YWx1ZSwgb2xkKSB7XHJcbiAgICB2YXIgd2FzT24gPSBvbGQgJiYgb2xkICE9IENvZGVNaXJyb3IuSW5pdDtcclxuICAgIGlmICghdmFsdWUgIT0gIXdhc09uKSB7XHJcbiAgICAgIHZhciBmdW5jcyA9IGNtLmRpc3BsYXkuZHJhZ0Z1bmN0aW9ucztcclxuICAgICAgdmFyIHRvZ2dsZSA9IHZhbHVlID8gb24gOiBvZmY7XHJcbiAgICAgIHRvZ2dsZShjbS5kaXNwbGF5LnNjcm9sbGVyLCBcImRyYWdzdGFydFwiLCBmdW5jcy5zdGFydCk7XHJcbiAgICAgIHRvZ2dsZShjbS5kaXNwbGF5LnNjcm9sbGVyLCBcImRyYWdlbnRlclwiLCBmdW5jcy5lbnRlcik7XHJcbiAgICAgIHRvZ2dsZShjbS5kaXNwbGF5LnNjcm9sbGVyLCBcImRyYWdvdmVyXCIsIGZ1bmNzLm92ZXIpO1xyXG4gICAgICB0b2dnbGUoY20uZGlzcGxheS5zY3JvbGxlciwgXCJkcmFnbGVhdmVcIiwgZnVuY3MubGVhdmUpO1xyXG4gICAgICB0b2dnbGUoY20uZGlzcGxheS5zY3JvbGxlciwgXCJkcm9wXCIsIGZ1bmNzLmRyb3ApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbGVkIHdoZW4gdGhlIHdpbmRvdyByZXNpemVzXHJcbiAgZnVuY3Rpb24gb25SZXNpemUoY20pIHtcclxuICAgIHZhciBkID0gY20uZGlzcGxheTtcclxuICAgIGlmIChkLmxhc3RXcmFwSGVpZ2h0ID09IGQud3JhcHBlci5jbGllbnRIZWlnaHQgJiYgZC5sYXN0V3JhcFdpZHRoID09IGQud3JhcHBlci5jbGllbnRXaWR0aClcclxuICAgICAgcmV0dXJuO1xyXG4gICAgLy8gTWlnaHQgYmUgYSB0ZXh0IHNjYWxpbmcgb3BlcmF0aW9uLCBjbGVhciBzaXplIGNhY2hlcy5cclxuICAgIGQuY2FjaGVkQ2hhcldpZHRoID0gZC5jYWNoZWRUZXh0SGVpZ2h0ID0gZC5jYWNoZWRQYWRkaW5nSCA9IG51bGw7XHJcbiAgICBkLnNjcm9sbGJhcnNDbGlwcGVkID0gZmFsc2U7XHJcbiAgICBjbS5zZXRTaXplKCk7XHJcbiAgfVxyXG5cclxuICAvLyBNT1VTRSBFVkVOVFNcclxuXHJcbiAgLy8gUmV0dXJuIHRydWUgd2hlbiB0aGUgZ2l2ZW4gbW91c2UgZXZlbnQgaGFwcGVuZWQgaW4gYSB3aWRnZXRcclxuICBmdW5jdGlvbiBldmVudEluV2lkZ2V0KGRpc3BsYXksIGUpIHtcclxuICAgIGZvciAodmFyIG4gPSBlX3RhcmdldChlKTsgbiAhPSBkaXNwbGF5LndyYXBwZXI7IG4gPSBuLnBhcmVudE5vZGUpIHtcclxuICAgICAgaWYgKCFuIHx8IChuLm5vZGVUeXBlID09IDEgJiYgbi5nZXRBdHRyaWJ1dGUoXCJjbS1pZ25vcmUtZXZlbnRzXCIpID09IFwidHJ1ZVwiKSB8fFxyXG4gICAgICAgICAgKG4ucGFyZW50Tm9kZSA9PSBkaXNwbGF5LnNpemVyICYmIG4gIT0gZGlzcGxheS5tb3ZlcikpXHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBHaXZlbiBhIG1vdXNlIGV2ZW50LCBmaW5kIHRoZSBjb3JyZXNwb25kaW5nIHBvc2l0aW9uLiBJZiBsaWJlcmFsXHJcbiAgLy8gaXMgZmFsc2UsIGl0IGNoZWNrcyB3aGV0aGVyIGEgZ3V0dGVyIG9yIHNjcm9sbGJhciB3YXMgY2xpY2tlZCxcclxuICAvLyBhbmQgcmV0dXJucyBudWxsIGlmIGl0IHdhcy4gZm9yUmVjdCBpcyB1c2VkIGJ5IHJlY3Rhbmd1bGFyXHJcbiAgLy8gc2VsZWN0aW9ucywgYW5kIHRyaWVzIHRvIGVzdGltYXRlIGEgY2hhcmFjdGVyIHBvc2l0aW9uIGV2ZW4gZm9yXHJcbiAgLy8gY29vcmRpbmF0ZXMgYmV5b25kIHRoZSByaWdodCBvZiB0aGUgdGV4dC5cclxuICBmdW5jdGlvbiBwb3NGcm9tTW91c2UoY20sIGUsIGxpYmVyYWwsIGZvclJlY3QpIHtcclxuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheTtcclxuICAgIGlmICghbGliZXJhbCAmJiBlX3RhcmdldChlKS5nZXRBdHRyaWJ1dGUoXCJjbS1ub3QtY29udGVudFwiKSA9PSBcInRydWVcIikgcmV0dXJuIG51bGw7XHJcblxyXG4gICAgdmFyIHgsIHksIHNwYWNlID0gZGlzcGxheS5saW5lU3BhY2UuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICAvLyBGYWlscyB1bnByZWRpY3RhYmx5IG9uIElFWzY3XSB3aGVuIG1vdXNlIGlzIGRyYWdnZWQgYXJvdW5kIHF1aWNrbHkuXHJcbiAgICB0cnkgeyB4ID0gZS5jbGllbnRYIC0gc3BhY2UubGVmdDsgeSA9IGUuY2xpZW50WSAtIHNwYWNlLnRvcDsgfVxyXG4gICAgY2F0Y2ggKGUpIHsgcmV0dXJuIG51bGw7IH1cclxuICAgIHZhciBjb29yZHMgPSBjb29yZHNDaGFyKGNtLCB4LCB5KSwgbGluZTtcclxuICAgIGlmIChmb3JSZWN0ICYmIGNvb3Jkcy54UmVsID09IDEgJiYgKGxpbmUgPSBnZXRMaW5lKGNtLmRvYywgY29vcmRzLmxpbmUpLnRleHQpLmxlbmd0aCA9PSBjb29yZHMuY2gpIHtcclxuICAgICAgdmFyIGNvbERpZmYgPSBjb3VudENvbHVtbihsaW5lLCBsaW5lLmxlbmd0aCwgY20ub3B0aW9ucy50YWJTaXplKSAtIGxpbmUubGVuZ3RoO1xyXG4gICAgICBjb29yZHMgPSBQb3MoY29vcmRzLmxpbmUsIE1hdGgubWF4KDAsIE1hdGgucm91bmQoKHggLSBwYWRkaW5nSChjbS5kaXNwbGF5KS5sZWZ0KSAvIGNoYXJXaWR0aChjbS5kaXNwbGF5KSkgLSBjb2xEaWZmKSk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gY29vcmRzO1xyXG4gIH1cclxuXHJcbiAgLy8gQSBtb3VzZSBkb3duIGNhbiBiZSBhIHNpbmdsZSBjbGljaywgZG91YmxlIGNsaWNrLCB0cmlwbGUgY2xpY2ssXHJcbiAgLy8gc3RhcnQgb2Ygc2VsZWN0aW9uIGRyYWcsIHN0YXJ0IG9mIHRleHQgZHJhZywgbmV3IGN1cnNvclxyXG4gIC8vIChjdHJsLWNsaWNrKSwgcmVjdGFuZ2xlIGRyYWcgKGFsdC1kcmFnKSwgb3IgeHdpblxyXG4gIC8vIG1pZGRsZS1jbGljay1wYXN0ZS4gT3IgaXQgbWlnaHQgYmUgYSBjbGljayBvbiBzb21ldGhpbmcgd2Ugc2hvdWxkXHJcbiAgLy8gbm90IGludGVyZmVyZSB3aXRoLCBzdWNoIGFzIGEgc2Nyb2xsYmFyIG9yIHdpZGdldC5cclxuICBmdW5jdGlvbiBvbk1vdXNlRG93bihlKSB7XHJcbiAgICB2YXIgY20gPSB0aGlzLCBkaXNwbGF5ID0gY20uZGlzcGxheTtcclxuICAgIGlmIChkaXNwbGF5LmFjdGl2ZVRvdWNoICYmIGRpc3BsYXkuaW5wdXQuc3VwcG9ydHNUb3VjaCgpIHx8IHNpZ25hbERPTUV2ZW50KGNtLCBlKSkgcmV0dXJuO1xyXG4gICAgZGlzcGxheS5zaGlmdCA9IGUuc2hpZnRLZXk7XHJcblxyXG4gICAgaWYgKGV2ZW50SW5XaWRnZXQoZGlzcGxheSwgZSkpIHtcclxuICAgICAgaWYgKCF3ZWJraXQpIHtcclxuICAgICAgICAvLyBCcmllZmx5IHR1cm4gb2ZmIGRyYWdnYWJpbGl0eSwgdG8gYWxsb3cgd2lkZ2V0cyB0byBkb1xyXG4gICAgICAgIC8vIG5vcm1hbCBkcmFnZ2luZyB0aGluZ3MuXHJcbiAgICAgICAgZGlzcGxheS5zY3JvbGxlci5kcmFnZ2FibGUgPSBmYWxzZTtcclxuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCl7ZGlzcGxheS5zY3JvbGxlci5kcmFnZ2FibGUgPSB0cnVlO30sIDEwMCk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgaWYgKGNsaWNrSW5HdXR0ZXIoY20sIGUpKSByZXR1cm47XHJcbiAgICB2YXIgc3RhcnQgPSBwb3NGcm9tTW91c2UoY20sIGUpO1xyXG4gICAgd2luZG93LmZvY3VzKCk7XHJcblxyXG4gICAgc3dpdGNoIChlX2J1dHRvbihlKSkge1xyXG4gICAgY2FzZSAxOlxyXG4gICAgICAvLyAjMzI2MTogbWFrZSBzdXJlLCB0aGF0IHdlJ3JlIG5vdCBzdGFydGluZyBhIHNlY29uZCBzZWxlY3Rpb25cclxuICAgICAgaWYgKGNtLnN0YXRlLnNlbGVjdGluZ1RleHQpXHJcbiAgICAgICAgY20uc3RhdGUuc2VsZWN0aW5nVGV4dChlKTtcclxuICAgICAgZWxzZSBpZiAoc3RhcnQpXHJcbiAgICAgICAgbGVmdEJ1dHRvbkRvd24oY20sIGUsIHN0YXJ0KTtcclxuICAgICAgZWxzZSBpZiAoZV90YXJnZXQoZSkgPT0gZGlzcGxheS5zY3JvbGxlcilcclxuICAgICAgICBlX3ByZXZlbnREZWZhdWx0KGUpO1xyXG4gICAgICBicmVhaztcclxuICAgIGNhc2UgMjpcclxuICAgICAgaWYgKHdlYmtpdCkgY20uc3RhdGUubGFzdE1pZGRsZURvd24gPSArbmV3IERhdGU7XHJcbiAgICAgIGlmIChzdGFydCkgZXh0ZW5kU2VsZWN0aW9uKGNtLmRvYywgc3RhcnQpO1xyXG4gICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge2Rpc3BsYXkuaW5wdXQuZm9jdXMoKTt9LCAyMCk7XHJcbiAgICAgIGVfcHJldmVudERlZmF1bHQoZSk7XHJcbiAgICAgIGJyZWFrO1xyXG4gICAgY2FzZSAzOlxyXG4gICAgICBpZiAoY2FwdHVyZVJpZ2h0Q2xpY2spIG9uQ29udGV4dE1lbnUoY20sIGUpO1xyXG4gICAgICBlbHNlIGRlbGF5Qmx1ckV2ZW50KGNtKTtcclxuICAgICAgYnJlYWs7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICB2YXIgbGFzdENsaWNrLCBsYXN0RG91YmxlQ2xpY2s7XHJcbiAgZnVuY3Rpb24gbGVmdEJ1dHRvbkRvd24oY20sIGUsIHN0YXJ0KSB7XHJcbiAgICBpZiAoaWUpIHNldFRpbWVvdXQoYmluZChlbnN1cmVGb2N1cywgY20pLCAwKTtcclxuICAgIGVsc2UgY20uY3VyT3AuZm9jdXMgPSBhY3RpdmVFbHQoKTtcclxuXHJcbiAgICB2YXIgbm93ID0gK25ldyBEYXRlLCB0eXBlO1xyXG4gICAgaWYgKGxhc3REb3VibGVDbGljayAmJiBsYXN0RG91YmxlQ2xpY2sudGltZSA+IG5vdyAtIDQwMCAmJiBjbXAobGFzdERvdWJsZUNsaWNrLnBvcywgc3RhcnQpID09IDApIHtcclxuICAgICAgdHlwZSA9IFwidHJpcGxlXCI7XHJcbiAgICB9IGVsc2UgaWYgKGxhc3RDbGljayAmJiBsYXN0Q2xpY2sudGltZSA+IG5vdyAtIDQwMCAmJiBjbXAobGFzdENsaWNrLnBvcywgc3RhcnQpID09IDApIHtcclxuICAgICAgdHlwZSA9IFwiZG91YmxlXCI7XHJcbiAgICAgIGxhc3REb3VibGVDbGljayA9IHt0aW1lOiBub3csIHBvczogc3RhcnR9O1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdHlwZSA9IFwic2luZ2xlXCI7XHJcbiAgICAgIGxhc3RDbGljayA9IHt0aW1lOiBub3csIHBvczogc3RhcnR9O1xyXG4gICAgfVxyXG5cclxuICAgIHZhciBzZWwgPSBjbS5kb2Muc2VsLCBtb2RpZmllciA9IG1hYyA/IGUubWV0YUtleSA6IGUuY3RybEtleSwgY29udGFpbmVkO1xyXG4gICAgaWYgKGNtLm9wdGlvbnMuZHJhZ0Ryb3AgJiYgZHJhZ0FuZERyb3AgJiYgIWlzUmVhZE9ubHkoY20pICYmXHJcbiAgICAgICAgdHlwZSA9PSBcInNpbmdsZVwiICYmIChjb250YWluZWQgPSBzZWwuY29udGFpbnMoc3RhcnQpKSA+IC0xICYmXHJcbiAgICAgICAgKGNtcCgoY29udGFpbmVkID0gc2VsLnJhbmdlc1tjb250YWluZWRdKS5mcm9tKCksIHN0YXJ0KSA8IDAgfHwgc3RhcnQueFJlbCA+IDApICYmXHJcbiAgICAgICAgKGNtcChjb250YWluZWQudG8oKSwgc3RhcnQpID4gMCB8fCBzdGFydC54UmVsIDwgMCkpXHJcbiAgICAgIGxlZnRCdXR0b25TdGFydERyYWcoY20sIGUsIHN0YXJ0LCBtb2RpZmllcik7XHJcbiAgICBlbHNlXHJcbiAgICAgIGxlZnRCdXR0b25TZWxlY3QoY20sIGUsIHN0YXJ0LCB0eXBlLCBtb2RpZmllcik7XHJcbiAgfVxyXG5cclxuICAvLyBTdGFydCBhIHRleHQgZHJhZy4gV2hlbiBpdCBlbmRzLCBzZWUgaWYgYW55IGRyYWdnaW5nIGFjdHVhbGx5XHJcbiAgLy8gaGFwcGVuLCBhbmQgdHJlYXQgYXMgYSBjbGljayBpZiBpdCBkaWRuJ3QuXHJcbiAgZnVuY3Rpb24gbGVmdEJ1dHRvblN0YXJ0RHJhZyhjbSwgZSwgc3RhcnQsIG1vZGlmaWVyKSB7XHJcbiAgICB2YXIgZGlzcGxheSA9IGNtLmRpc3BsYXksIHN0YXJ0VGltZSA9ICtuZXcgRGF0ZTtcclxuICAgIHZhciBkcmFnRW5kID0gb3BlcmF0aW9uKGNtLCBmdW5jdGlvbihlMikge1xyXG4gICAgICBpZiAod2Via2l0KSBkaXNwbGF5LnNjcm9sbGVyLmRyYWdnYWJsZSA9IGZhbHNlO1xyXG4gICAgICBjbS5zdGF0ZS5kcmFnZ2luZ1RleHQgPSBmYWxzZTtcclxuICAgICAgb2ZmKGRvY3VtZW50LCBcIm1vdXNldXBcIiwgZHJhZ0VuZCk7XHJcbiAgICAgIG9mZihkaXNwbGF5LnNjcm9sbGVyLCBcImRyb3BcIiwgZHJhZ0VuZCk7XHJcbiAgICAgIGlmIChNYXRoLmFicyhlLmNsaWVudFggLSBlMi5jbGllbnRYKSArIE1hdGguYWJzKGUuY2xpZW50WSAtIGUyLmNsaWVudFkpIDwgMTApIHtcclxuICAgICAgICBlX3ByZXZlbnREZWZhdWx0KGUyKTtcclxuICAgICAgICBpZiAoIW1vZGlmaWVyICYmICtuZXcgRGF0ZSAtIDIwMCA8IHN0YXJ0VGltZSlcclxuICAgICAgICAgIGV4dGVuZFNlbGVjdGlvbihjbS5kb2MsIHN0YXJ0KTtcclxuICAgICAgICAvLyBXb3JrIGFyb3VuZCB1bmV4cGxhaW5hYmxlIGZvY3VzIHByb2JsZW0gaW4gSUU5ICgjMjEyNykgYW5kIENocm9tZSAoIzMwODEpXHJcbiAgICAgICAgaWYgKHdlYmtpdCB8fCBpZSAmJiBpZV92ZXJzaW9uID09IDkpXHJcbiAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge2RvY3VtZW50LmJvZHkuZm9jdXMoKTsgZGlzcGxheS5pbnB1dC5mb2N1cygpO30sIDIwKTtcclxuICAgICAgICBlbHNlXHJcbiAgICAgICAgICBkaXNwbGF5LmlucHV0LmZvY3VzKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gICAgLy8gTGV0IHRoZSBkcmFnIGhhbmRsZXIgaGFuZGxlIHRoaXMuXHJcbiAgICBpZiAod2Via2l0KSBkaXNwbGF5LnNjcm9sbGVyLmRyYWdnYWJsZSA9IHRydWU7XHJcbiAgICBjbS5zdGF0ZS5kcmFnZ2luZ1RleHQgPSBkcmFnRW5kO1xyXG4gICAgLy8gSUUncyBhcHByb2FjaCB0byBkcmFnZ2FibGVcclxuICAgIGlmIChkaXNwbGF5LnNjcm9sbGVyLmRyYWdEcm9wKSBkaXNwbGF5LnNjcm9sbGVyLmRyYWdEcm9wKCk7XHJcbiAgICBvbihkb2N1bWVudCwgXCJtb3VzZXVwXCIsIGRyYWdFbmQpO1xyXG4gICAgb24oZGlzcGxheS5zY3JvbGxlciwgXCJkcm9wXCIsIGRyYWdFbmQpO1xyXG4gIH1cclxuXHJcbiAgLy8gTm9ybWFsIHNlbGVjdGlvbiwgYXMgb3Bwb3NlZCB0byB0ZXh0IGRyYWdnaW5nLlxyXG4gIGZ1bmN0aW9uIGxlZnRCdXR0b25TZWxlY3QoY20sIGUsIHN0YXJ0LCB0eXBlLCBhZGROZXcpIHtcclxuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheSwgZG9jID0gY20uZG9jO1xyXG4gICAgZV9wcmV2ZW50RGVmYXVsdChlKTtcclxuXHJcbiAgICB2YXIgb3VyUmFuZ2UsIG91ckluZGV4LCBzdGFydFNlbCA9IGRvYy5zZWwsIHJhbmdlcyA9IHN0YXJ0U2VsLnJhbmdlcztcclxuICAgIGlmIChhZGROZXcgJiYgIWUuc2hpZnRLZXkpIHtcclxuICAgICAgb3VySW5kZXggPSBkb2Muc2VsLmNvbnRhaW5zKHN0YXJ0KTtcclxuICAgICAgaWYgKG91ckluZGV4ID4gLTEpXHJcbiAgICAgICAgb3VyUmFuZ2UgPSByYW5nZXNbb3VySW5kZXhdO1xyXG4gICAgICBlbHNlXHJcbiAgICAgICAgb3VyUmFuZ2UgPSBuZXcgUmFuZ2Uoc3RhcnQsIHN0YXJ0KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIG91clJhbmdlID0gZG9jLnNlbC5wcmltYXJ5KCk7XHJcbiAgICAgIG91ckluZGV4ID0gZG9jLnNlbC5wcmltSW5kZXg7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGUuYWx0S2V5KSB7XHJcbiAgICAgIHR5cGUgPSBcInJlY3RcIjtcclxuICAgICAgaWYgKCFhZGROZXcpIG91clJhbmdlID0gbmV3IFJhbmdlKHN0YXJ0LCBzdGFydCk7XHJcbiAgICAgIHN0YXJ0ID0gcG9zRnJvbU1vdXNlKGNtLCBlLCB0cnVlLCB0cnVlKTtcclxuICAgICAgb3VySW5kZXggPSAtMTtcclxuICAgIH0gZWxzZSBpZiAodHlwZSA9PSBcImRvdWJsZVwiKSB7XHJcbiAgICAgIHZhciB3b3JkID0gY20uZmluZFdvcmRBdChzdGFydCk7XHJcbiAgICAgIGlmIChjbS5kaXNwbGF5LnNoaWZ0IHx8IGRvYy5leHRlbmQpXHJcbiAgICAgICAgb3VyUmFuZ2UgPSBleHRlbmRSYW5nZShkb2MsIG91clJhbmdlLCB3b3JkLmFuY2hvciwgd29yZC5oZWFkKTtcclxuICAgICAgZWxzZVxyXG4gICAgICAgIG91clJhbmdlID0gd29yZDtcclxuICAgIH0gZWxzZSBpZiAodHlwZSA9PSBcInRyaXBsZVwiKSB7XHJcbiAgICAgIHZhciBsaW5lID0gbmV3IFJhbmdlKFBvcyhzdGFydC5saW5lLCAwKSwgY2xpcFBvcyhkb2MsIFBvcyhzdGFydC5saW5lICsgMSwgMCkpKTtcclxuICAgICAgaWYgKGNtLmRpc3BsYXkuc2hpZnQgfHwgZG9jLmV4dGVuZClcclxuICAgICAgICBvdXJSYW5nZSA9IGV4dGVuZFJhbmdlKGRvYywgb3VyUmFuZ2UsIGxpbmUuYW5jaG9yLCBsaW5lLmhlYWQpO1xyXG4gICAgICBlbHNlXHJcbiAgICAgICAgb3VyUmFuZ2UgPSBsaW5lO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgb3VyUmFuZ2UgPSBleHRlbmRSYW5nZShkb2MsIG91clJhbmdlLCBzdGFydCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFhZGROZXcpIHtcclxuICAgICAgb3VySW5kZXggPSAwO1xyXG4gICAgICBzZXRTZWxlY3Rpb24oZG9jLCBuZXcgU2VsZWN0aW9uKFtvdXJSYW5nZV0sIDApLCBzZWxfbW91c2UpO1xyXG4gICAgICBzdGFydFNlbCA9IGRvYy5zZWw7XHJcbiAgICB9IGVsc2UgaWYgKG91ckluZGV4ID09IC0xKSB7XHJcbiAgICAgIG91ckluZGV4ID0gcmFuZ2VzLmxlbmd0aDtcclxuICAgICAgc2V0U2VsZWN0aW9uKGRvYywgbm9ybWFsaXplU2VsZWN0aW9uKHJhbmdlcy5jb25jYXQoW291clJhbmdlXSksIG91ckluZGV4KSxcclxuICAgICAgICAgICAgICAgICAgIHtzY3JvbGw6IGZhbHNlLCBvcmlnaW46IFwiKm1vdXNlXCJ9KTtcclxuICAgIH0gZWxzZSBpZiAocmFuZ2VzLmxlbmd0aCA+IDEgJiYgcmFuZ2VzW291ckluZGV4XS5lbXB0eSgpICYmIHR5cGUgPT0gXCJzaW5nbGVcIiAmJiAhZS5zaGlmdEtleSkge1xyXG4gICAgICBzZXRTZWxlY3Rpb24oZG9jLCBub3JtYWxpemVTZWxlY3Rpb24ocmFuZ2VzLnNsaWNlKDAsIG91ckluZGV4KS5jb25jYXQocmFuZ2VzLnNsaWNlKG91ckluZGV4ICsgMSkpLCAwKSxcclxuICAgICAgICAgICAgICAgICAgIHtzY3JvbGw6IGZhbHNlLCBvcmlnaW46IFwiKm1vdXNlXCJ9KTtcclxuICAgICAgc3RhcnRTZWwgPSBkb2Muc2VsO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmVwbGFjZU9uZVNlbGVjdGlvbihkb2MsIG91ckluZGV4LCBvdXJSYW5nZSwgc2VsX21vdXNlKTtcclxuICAgIH1cclxuXHJcbiAgICB2YXIgbGFzdFBvcyA9IHN0YXJ0O1xyXG4gICAgZnVuY3Rpb24gZXh0ZW5kVG8ocG9zKSB7XHJcbiAgICAgIGlmIChjbXAobGFzdFBvcywgcG9zKSA9PSAwKSByZXR1cm47XHJcbiAgICAgIGxhc3RQb3MgPSBwb3M7XHJcblxyXG4gICAgICBpZiAodHlwZSA9PSBcInJlY3RcIikge1xyXG4gICAgICAgIHZhciByYW5nZXMgPSBbXSwgdGFiU2l6ZSA9IGNtLm9wdGlvbnMudGFiU2l6ZTtcclxuICAgICAgICB2YXIgc3RhcnRDb2wgPSBjb3VudENvbHVtbihnZXRMaW5lKGRvYywgc3RhcnQubGluZSkudGV4dCwgc3RhcnQuY2gsIHRhYlNpemUpO1xyXG4gICAgICAgIHZhciBwb3NDb2wgPSBjb3VudENvbHVtbihnZXRMaW5lKGRvYywgcG9zLmxpbmUpLnRleHQsIHBvcy5jaCwgdGFiU2l6ZSk7XHJcbiAgICAgICAgdmFyIGxlZnQgPSBNYXRoLm1pbihzdGFydENvbCwgcG9zQ29sKSwgcmlnaHQgPSBNYXRoLm1heChzdGFydENvbCwgcG9zQ29sKTtcclxuICAgICAgICBmb3IgKHZhciBsaW5lID0gTWF0aC5taW4oc3RhcnQubGluZSwgcG9zLmxpbmUpLCBlbmQgPSBNYXRoLm1pbihjbS5sYXN0TGluZSgpLCBNYXRoLm1heChzdGFydC5saW5lLCBwb3MubGluZSkpO1xyXG4gICAgICAgICAgICAgbGluZSA8PSBlbmQ7IGxpbmUrKykge1xyXG4gICAgICAgICAgdmFyIHRleHQgPSBnZXRMaW5lKGRvYywgbGluZSkudGV4dCwgbGVmdFBvcyA9IGZpbmRDb2x1bW4odGV4dCwgbGVmdCwgdGFiU2l6ZSk7XHJcbiAgICAgICAgICBpZiAobGVmdCA9PSByaWdodClcclxuICAgICAgICAgICAgcmFuZ2VzLnB1c2gobmV3IFJhbmdlKFBvcyhsaW5lLCBsZWZ0UG9zKSwgUG9zKGxpbmUsIGxlZnRQb3MpKSk7XHJcbiAgICAgICAgICBlbHNlIGlmICh0ZXh0Lmxlbmd0aCA+IGxlZnRQb3MpXHJcbiAgICAgICAgICAgIHJhbmdlcy5wdXNoKG5ldyBSYW5nZShQb3MobGluZSwgbGVmdFBvcyksIFBvcyhsaW5lLCBmaW5kQ29sdW1uKHRleHQsIHJpZ2h0LCB0YWJTaXplKSkpKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgaWYgKCFyYW5nZXMubGVuZ3RoKSByYW5nZXMucHVzaChuZXcgUmFuZ2Uoc3RhcnQsIHN0YXJ0KSk7XHJcbiAgICAgICAgc2V0U2VsZWN0aW9uKGRvYywgbm9ybWFsaXplU2VsZWN0aW9uKHN0YXJ0U2VsLnJhbmdlcy5zbGljZSgwLCBvdXJJbmRleCkuY29uY2F0KHJhbmdlcyksIG91ckluZGV4KSxcclxuICAgICAgICAgICAgICAgICAgICAge29yaWdpbjogXCIqbW91c2VcIiwgc2Nyb2xsOiBmYWxzZX0pO1xyXG4gICAgICAgIGNtLnNjcm9sbEludG9WaWV3KHBvcyk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdmFyIG9sZFJhbmdlID0gb3VyUmFuZ2U7XHJcbiAgICAgICAgdmFyIGFuY2hvciA9IG9sZFJhbmdlLmFuY2hvciwgaGVhZCA9IHBvcztcclxuICAgICAgICBpZiAodHlwZSAhPSBcInNpbmdsZVwiKSB7XHJcbiAgICAgICAgICBpZiAodHlwZSA9PSBcImRvdWJsZVwiKVxyXG4gICAgICAgICAgICB2YXIgcmFuZ2UgPSBjbS5maW5kV29yZEF0KHBvcyk7XHJcbiAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgIHZhciByYW5nZSA9IG5ldyBSYW5nZShQb3MocG9zLmxpbmUsIDApLCBjbGlwUG9zKGRvYywgUG9zKHBvcy5saW5lICsgMSwgMCkpKTtcclxuICAgICAgICAgIGlmIChjbXAocmFuZ2UuYW5jaG9yLCBhbmNob3IpID4gMCkge1xyXG4gICAgICAgICAgICBoZWFkID0gcmFuZ2UuaGVhZDtcclxuICAgICAgICAgICAgYW5jaG9yID0gbWluUG9zKG9sZFJhbmdlLmZyb20oKSwgcmFuZ2UuYW5jaG9yKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGhlYWQgPSByYW5nZS5hbmNob3I7XHJcbiAgICAgICAgICAgIGFuY2hvciA9IG1heFBvcyhvbGRSYW5nZS50bygpLCByYW5nZS5oZWFkKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICAgdmFyIHJhbmdlcyA9IHN0YXJ0U2VsLnJhbmdlcy5zbGljZSgwKTtcclxuICAgICAgICByYW5nZXNbb3VySW5kZXhdID0gbmV3IFJhbmdlKGNsaXBQb3MoZG9jLCBhbmNob3IpLCBoZWFkKTtcclxuICAgICAgICBzZXRTZWxlY3Rpb24oZG9jLCBub3JtYWxpemVTZWxlY3Rpb24ocmFuZ2VzLCBvdXJJbmRleCksIHNlbF9tb3VzZSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICB2YXIgZWRpdG9yU2l6ZSA9IGRpc3BsYXkud3JhcHBlci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIC8vIFVzZWQgdG8gZW5zdXJlIHRpbWVvdXQgcmUtdHJpZXMgZG9uJ3QgZmlyZSB3aGVuIGFub3RoZXIgZXh0ZW5kXHJcbiAgICAvLyBoYXBwZW5lZCBpbiB0aGUgbWVhbnRpbWUgKGNsZWFyVGltZW91dCBpc24ndCByZWxpYWJsZSAtLSBhdFxyXG4gICAgLy8gbGVhc3Qgb24gQ2hyb21lLCB0aGUgdGltZW91dHMgc3RpbGwgaGFwcGVuIGV2ZW4gd2hlbiBjbGVhcmVkLFxyXG4gICAgLy8gaWYgdGhlIGNsZWFyIGhhcHBlbnMgYWZ0ZXIgdGhlaXIgc2NoZWR1bGVkIGZpcmluZyB0aW1lKS5cclxuICAgIHZhciBjb3VudGVyID0gMDtcclxuXHJcbiAgICBmdW5jdGlvbiBleHRlbmQoZSkge1xyXG4gICAgICB2YXIgY3VyQ291bnQgPSArK2NvdW50ZXI7XHJcbiAgICAgIHZhciBjdXIgPSBwb3NGcm9tTW91c2UoY20sIGUsIHRydWUsIHR5cGUgPT0gXCJyZWN0XCIpO1xyXG4gICAgICBpZiAoIWN1cikgcmV0dXJuO1xyXG4gICAgICBpZiAoY21wKGN1ciwgbGFzdFBvcykgIT0gMCkge1xyXG4gICAgICAgIGNtLmN1ck9wLmZvY3VzID0gYWN0aXZlRWx0KCk7XHJcbiAgICAgICAgZXh0ZW5kVG8oY3VyKTtcclxuICAgICAgICB2YXIgdmlzaWJsZSA9IHZpc2libGVMaW5lcyhkaXNwbGF5LCBkb2MpO1xyXG4gICAgICAgIGlmIChjdXIubGluZSA+PSB2aXNpYmxlLnRvIHx8IGN1ci5saW5lIDwgdmlzaWJsZS5mcm9tKVxyXG4gICAgICAgICAgc2V0VGltZW91dChvcGVyYXRpb24oY20sIGZ1bmN0aW9uKCl7aWYgKGNvdW50ZXIgPT0gY3VyQ291bnQpIGV4dGVuZChlKTt9KSwgMTUwKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB2YXIgb3V0c2lkZSA9IGUuY2xpZW50WSA8IGVkaXRvclNpemUudG9wID8gLTIwIDogZS5jbGllbnRZID4gZWRpdG9yU2l6ZS5ib3R0b20gPyAyMCA6IDA7XHJcbiAgICAgICAgaWYgKG91dHNpZGUpIHNldFRpbWVvdXQob3BlcmF0aW9uKGNtLCBmdW5jdGlvbigpIHtcclxuICAgICAgICAgIGlmIChjb3VudGVyICE9IGN1ckNvdW50KSByZXR1cm47XHJcbiAgICAgICAgICBkaXNwbGF5LnNjcm9sbGVyLnNjcm9sbFRvcCArPSBvdXRzaWRlO1xyXG4gICAgICAgICAgZXh0ZW5kKGUpO1xyXG4gICAgICAgIH0pLCA1MCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBmdW5jdGlvbiBkb25lKGUpIHtcclxuICAgICAgY20uc3RhdGUuc2VsZWN0aW5nVGV4dCA9IGZhbHNlO1xyXG4gICAgICBjb3VudGVyID0gSW5maW5pdHk7XHJcbiAgICAgIGVfcHJldmVudERlZmF1bHQoZSk7XHJcbiAgICAgIGRpc3BsYXkuaW5wdXQuZm9jdXMoKTtcclxuICAgICAgb2ZmKGRvY3VtZW50LCBcIm1vdXNlbW92ZVwiLCBtb3ZlKTtcclxuICAgICAgb2ZmKGRvY3VtZW50LCBcIm1vdXNldXBcIiwgdXApO1xyXG4gICAgICBkb2MuaGlzdG9yeS5sYXN0U2VsT3JpZ2luID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICB2YXIgbW92ZSA9IG9wZXJhdGlvbihjbSwgZnVuY3Rpb24oZSkge1xyXG4gICAgICBpZiAoIWVfYnV0dG9uKGUpKSBkb25lKGUpO1xyXG4gICAgICBlbHNlIGV4dGVuZChlKTtcclxuICAgIH0pO1xyXG4gICAgdmFyIHVwID0gb3BlcmF0aW9uKGNtLCBkb25lKTtcclxuICAgIGNtLnN0YXRlLnNlbGVjdGluZ1RleHQgPSB1cDtcclxuICAgIG9uKGRvY3VtZW50LCBcIm1vdXNlbW92ZVwiLCBtb3ZlKTtcclxuICAgIG9uKGRvY3VtZW50LCBcIm1vdXNldXBcIiwgdXApO1xyXG4gIH1cclxuXHJcbiAgLy8gRGV0ZXJtaW5lcyB3aGV0aGVyIGFuIGV2ZW50IGhhcHBlbmVkIGluIHRoZSBndXR0ZXIsIGFuZCBmaXJlcyB0aGVcclxuICAvLyBoYW5kbGVycyBmb3IgdGhlIGNvcnJlc3BvbmRpbmcgZXZlbnQuXHJcbiAgZnVuY3Rpb24gZ3V0dGVyRXZlbnQoY20sIGUsIHR5cGUsIHByZXZlbnQpIHtcclxuICAgIHRyeSB7IHZhciBtWCA9IGUuY2xpZW50WCwgbVkgPSBlLmNsaWVudFk7IH1cclxuICAgIGNhdGNoKGUpIHsgcmV0dXJuIGZhbHNlOyB9XHJcbiAgICBpZiAobVggPj0gTWF0aC5mbG9vcihjbS5kaXNwbGF5Lmd1dHRlcnMuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkucmlnaHQpKSByZXR1cm4gZmFsc2U7XHJcbiAgICBpZiAocHJldmVudCkgZV9wcmV2ZW50RGVmYXVsdChlKTtcclxuXHJcbiAgICB2YXIgZGlzcGxheSA9IGNtLmRpc3BsYXk7XHJcbiAgICB2YXIgbGluZUJveCA9IGRpc3BsYXkubGluZURpdi5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuXHJcbiAgICBpZiAobVkgPiBsaW5lQm94LmJvdHRvbSB8fCAhaGFzSGFuZGxlcihjbSwgdHlwZSkpIHJldHVybiBlX2RlZmF1bHRQcmV2ZW50ZWQoZSk7XHJcbiAgICBtWSAtPSBsaW5lQm94LnRvcCAtIGRpc3BsYXkudmlld09mZnNldDtcclxuXHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNtLm9wdGlvbnMuZ3V0dGVycy5sZW5ndGg7ICsraSkge1xyXG4gICAgICB2YXIgZyA9IGRpc3BsYXkuZ3V0dGVycy5jaGlsZE5vZGVzW2ldO1xyXG4gICAgICBpZiAoZyAmJiBnLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnJpZ2h0ID49IG1YKSB7XHJcbiAgICAgICAgdmFyIGxpbmUgPSBsaW5lQXRIZWlnaHQoY20uZG9jLCBtWSk7XHJcbiAgICAgICAgdmFyIGd1dHRlciA9IGNtLm9wdGlvbnMuZ3V0dGVyc1tpXTtcclxuICAgICAgICBzaWduYWwoY20sIHR5cGUsIGNtLCBsaW5lLCBndXR0ZXIsIGUpO1xyXG4gICAgICAgIHJldHVybiBlX2RlZmF1bHRQcmV2ZW50ZWQoZSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGNsaWNrSW5HdXR0ZXIoY20sIGUpIHtcclxuICAgIHJldHVybiBndXR0ZXJFdmVudChjbSwgZSwgXCJndXR0ZXJDbGlja1wiLCB0cnVlKTtcclxuICB9XHJcblxyXG4gIC8vIEtsdWRnZSB0byB3b3JrIGFyb3VuZCBzdHJhbmdlIElFIGJlaGF2aW9yIHdoZXJlIGl0J2xsIHNvbWV0aW1lc1xyXG4gIC8vIHJlLWZpcmUgYSBzZXJpZXMgb2YgZHJhZy1yZWxhdGVkIGV2ZW50cyByaWdodCBhZnRlciB0aGUgZHJvcCAoIzE1NTEpXHJcbiAgdmFyIGxhc3REcm9wID0gMDtcclxuXHJcbiAgZnVuY3Rpb24gb25Ecm9wKGUpIHtcclxuICAgIHZhciBjbSA9IHRoaXM7XHJcbiAgICBjbGVhckRyYWdDdXJzb3IoY20pO1xyXG4gICAgaWYgKHNpZ25hbERPTUV2ZW50KGNtLCBlKSB8fCBldmVudEluV2lkZ2V0KGNtLmRpc3BsYXksIGUpKVxyXG4gICAgICByZXR1cm47XHJcbiAgICBlX3ByZXZlbnREZWZhdWx0KGUpO1xyXG4gICAgaWYgKGllKSBsYXN0RHJvcCA9ICtuZXcgRGF0ZTtcclxuICAgIHZhciBwb3MgPSBwb3NGcm9tTW91c2UoY20sIGUsIHRydWUpLCBmaWxlcyA9IGUuZGF0YVRyYW5zZmVyLmZpbGVzO1xyXG4gICAgaWYgKCFwb3MgfHwgaXNSZWFkT25seShjbSkpIHJldHVybjtcclxuICAgIC8vIE1pZ2h0IGJlIGEgZmlsZSBkcm9wLCBpbiB3aGljaCBjYXNlIHdlIHNpbXBseSBleHRyYWN0IHRoZSB0ZXh0XHJcbiAgICAvLyBhbmQgaW5zZXJ0IGl0LlxyXG4gICAgaWYgKGZpbGVzICYmIGZpbGVzLmxlbmd0aCAmJiB3aW5kb3cuRmlsZVJlYWRlciAmJiB3aW5kb3cuRmlsZSkge1xyXG4gICAgICB2YXIgbiA9IGZpbGVzLmxlbmd0aCwgdGV4dCA9IEFycmF5KG4pLCByZWFkID0gMDtcclxuICAgICAgdmFyIGxvYWRGaWxlID0gZnVuY3Rpb24oZmlsZSwgaSkge1xyXG4gICAgICAgIGlmIChjbS5vcHRpb25zLmFsbG93RHJvcEZpbGVUeXBlcyAmJlxyXG4gICAgICAgICAgICBpbmRleE9mKGNtLm9wdGlvbnMuYWxsb3dEcm9wRmlsZVR5cGVzLCBmaWxlLnR5cGUpID09IC0xKVxyXG4gICAgICAgICAgcmV0dXJuO1xyXG5cclxuICAgICAgICB2YXIgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXI7XHJcbiAgICAgICAgcmVhZGVyLm9ubG9hZCA9IG9wZXJhdGlvbihjbSwgZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgICB2YXIgY29udGVudCA9IHJlYWRlci5yZXN1bHQ7XHJcbiAgICAgICAgICBpZiAoL1tcXHgwMC1cXHgwOFxceDBlLVxceDFmXXsyfS8udGVzdChjb250ZW50KSkgY29udGVudCA9IFwiXCI7XHJcbiAgICAgICAgICB0ZXh0W2ldID0gY29udGVudDtcclxuICAgICAgICAgIGlmICgrK3JlYWQgPT0gbikge1xyXG4gICAgICAgICAgICBwb3MgPSBjbGlwUG9zKGNtLmRvYywgcG9zKTtcclxuICAgICAgICAgICAgdmFyIGNoYW5nZSA9IHtmcm9tOiBwb3MsIHRvOiBwb3MsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dDogY20uZG9jLnNwbGl0TGluZXModGV4dC5qb2luKGNtLmRvYy5saW5lU2VwYXJhdG9yKCkpKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICBvcmlnaW46IFwicGFzdGVcIn07XHJcbiAgICAgICAgICAgIG1ha2VDaGFuZ2UoY20uZG9jLCBjaGFuZ2UpO1xyXG4gICAgICAgICAgICBzZXRTZWxlY3Rpb25SZXBsYWNlSGlzdG9yeShjbS5kb2MsIHNpbXBsZVNlbGVjdGlvbihwb3MsIGNoYW5nZUVuZChjaGFuZ2UpKSk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgcmVhZGVyLnJlYWRBc1RleHQoZmlsZSk7XHJcbiAgICAgIH07XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbjsgKytpKSBsb2FkRmlsZShmaWxlc1tpXSwgaSk7XHJcbiAgICB9IGVsc2UgeyAvLyBOb3JtYWwgZHJvcFxyXG4gICAgICAvLyBEb24ndCBkbyBhIHJlcGxhY2UgaWYgdGhlIGRyb3AgaGFwcGVuZWQgaW5zaWRlIG9mIHRoZSBzZWxlY3RlZCB0ZXh0LlxyXG4gICAgICBpZiAoY20uc3RhdGUuZHJhZ2dpbmdUZXh0ICYmIGNtLmRvYy5zZWwuY29udGFpbnMocG9zKSA+IC0xKSB7XHJcbiAgICAgICAgY20uc3RhdGUuZHJhZ2dpbmdUZXh0KGUpO1xyXG4gICAgICAgIC8vIEVuc3VyZSB0aGUgZWRpdG9yIGlzIHJlLWZvY3VzZWRcclxuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge2NtLmRpc3BsYXkuaW5wdXQuZm9jdXMoKTt9LCAyMCk7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgdmFyIHRleHQgPSBlLmRhdGFUcmFuc2Zlci5nZXREYXRhKFwiVGV4dFwiKTtcclxuICAgICAgICBpZiAodGV4dCkge1xyXG4gICAgICAgICAgaWYgKGNtLnN0YXRlLmRyYWdnaW5nVGV4dCAmJiAhKG1hYyA/IGUuYWx0S2V5IDogZS5jdHJsS2V5KSlcclxuICAgICAgICAgICAgdmFyIHNlbGVjdGVkID0gY20ubGlzdFNlbGVjdGlvbnMoKTtcclxuICAgICAgICAgIHNldFNlbGVjdGlvbk5vVW5kbyhjbS5kb2MsIHNpbXBsZVNlbGVjdGlvbihwb3MsIHBvcykpO1xyXG4gICAgICAgICAgaWYgKHNlbGVjdGVkKSBmb3IgKHZhciBpID0gMDsgaSA8IHNlbGVjdGVkLmxlbmd0aDsgKytpKVxyXG4gICAgICAgICAgICByZXBsYWNlUmFuZ2UoY20uZG9jLCBcIlwiLCBzZWxlY3RlZFtpXS5hbmNob3IsIHNlbGVjdGVkW2ldLmhlYWQsIFwiZHJhZ1wiKTtcclxuICAgICAgICAgIGNtLnJlcGxhY2VTZWxlY3Rpb24odGV4dCwgXCJhcm91bmRcIiwgXCJwYXN0ZVwiKTtcclxuICAgICAgICAgIGNtLmRpc3BsYXkuaW5wdXQuZm9jdXMoKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgY2F0Y2goZSl7fVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gb25EcmFnU3RhcnQoY20sIGUpIHtcclxuICAgIGlmIChpZSAmJiAoIWNtLnN0YXRlLmRyYWdnaW5nVGV4dCB8fCArbmV3IERhdGUgLSBsYXN0RHJvcCA8IDEwMCkpIHsgZV9zdG9wKGUpOyByZXR1cm47IH1cclxuICAgIGlmIChzaWduYWxET01FdmVudChjbSwgZSkgfHwgZXZlbnRJbldpZGdldChjbS5kaXNwbGF5LCBlKSkgcmV0dXJuO1xyXG5cclxuICAgIGUuZGF0YVRyYW5zZmVyLnNldERhdGEoXCJUZXh0XCIsIGNtLmdldFNlbGVjdGlvbigpKTtcclxuXHJcbiAgICAvLyBVc2UgZHVtbXkgaW1hZ2UgaW5zdGVhZCBvZiBkZWZhdWx0IGJyb3dzZXJzIGltYWdlLlxyXG4gICAgLy8gUmVjZW50IFNhZmFyaSAofjYuMC4yKSBoYXZlIGEgdGVuZGVuY3kgdG8gc2VnZmF1bHQgd2hlbiB0aGlzIGhhcHBlbnMsIHNvIHdlIGRvbid0IGRvIGl0IHRoZXJlLlxyXG4gICAgaWYgKGUuZGF0YVRyYW5zZmVyLnNldERyYWdJbWFnZSAmJiAhc2FmYXJpKSB7XHJcbiAgICAgIHZhciBpbWcgPSBlbHQoXCJpbWdcIiwgbnVsbCwgbnVsbCwgXCJwb3NpdGlvbjogZml4ZWQ7IGxlZnQ6IDA7IHRvcDogMDtcIik7XHJcbiAgICAgIGltZy5zcmMgPSBcImRhdGE6aW1hZ2UvZ2lmO2Jhc2U2NCxSMGxHT0RsaEFRQUJBQUFBQUNINUJBRUtBQUVBTEFBQUFBQUJBQUVBQUFJQ1RBRUFPdz09XCI7XHJcbiAgICAgIGlmIChwcmVzdG8pIHtcclxuICAgICAgICBpbWcud2lkdGggPSBpbWcuaGVpZ2h0ID0gMTtcclxuICAgICAgICBjbS5kaXNwbGF5LndyYXBwZXIuYXBwZW5kQ2hpbGQoaW1nKTtcclxuICAgICAgICAvLyBGb3JjZSBhIHJlbGF5b3V0LCBvciBPcGVyYSB3b24ndCB1c2Ugb3VyIGltYWdlIGZvciBzb21lIG9ic2N1cmUgcmVhc29uXHJcbiAgICAgICAgaW1nLl90b3AgPSBpbWcub2Zmc2V0VG9wO1xyXG4gICAgICB9XHJcbiAgICAgIGUuZGF0YVRyYW5zZmVyLnNldERyYWdJbWFnZShpbWcsIDAsIDApO1xyXG4gICAgICBpZiAocHJlc3RvKSBpbWcucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChpbWcpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gb25EcmFnT3ZlcihjbSwgZSkge1xyXG4gICAgdmFyIHBvcyA9IHBvc0Zyb21Nb3VzZShjbSwgZSk7XHJcbiAgICBpZiAoIXBvcykgcmV0dXJuO1xyXG4gICAgdmFyIGZyYWcgPSBkb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7XHJcbiAgICBkcmF3U2VsZWN0aW9uQ3Vyc29yKGNtLCBwb3MsIGZyYWcpO1xyXG4gICAgaWYgKCFjbS5kaXNwbGF5LmRyYWdDdXJzb3IpIHtcclxuICAgICAgY20uZGlzcGxheS5kcmFnQ3Vyc29yID0gZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1jdXJzb3JzIENvZGVNaXJyb3ItZHJhZ2N1cnNvcnNcIik7XHJcbiAgICAgIGNtLmRpc3BsYXkubGluZVNwYWNlLmluc2VydEJlZm9yZShjbS5kaXNwbGF5LmRyYWdDdXJzb3IsIGNtLmRpc3BsYXkuY3Vyc29yRGl2KTtcclxuICAgIH1cclxuICAgIHJlbW92ZUNoaWxkcmVuQW5kQWRkKGNtLmRpc3BsYXkuZHJhZ0N1cnNvciwgZnJhZyk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBjbGVhckRyYWdDdXJzb3IoY20pIHtcclxuICAgIGlmIChjbS5kaXNwbGF5LmRyYWdDdXJzb3IpIHtcclxuICAgICAgY20uZGlzcGxheS5saW5lU3BhY2UucmVtb3ZlQ2hpbGQoY20uZGlzcGxheS5kcmFnQ3Vyc29yKTtcclxuICAgICAgY20uZGlzcGxheS5kcmFnQ3Vyc29yID0gbnVsbDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNDUk9MTCBFVkVOVFNcclxuXHJcbiAgLy8gU3luYyB0aGUgc2Nyb2xsYWJsZSBhcmVhIGFuZCBzY3JvbGxiYXJzLCBlbnN1cmUgdGhlIHZpZXdwb3J0XHJcbiAgLy8gY292ZXJzIHRoZSB2aXNpYmxlIGFyZWEuXHJcbiAgZnVuY3Rpb24gc2V0U2Nyb2xsVG9wKGNtLCB2YWwpIHtcclxuICAgIGlmIChNYXRoLmFicyhjbS5kb2Muc2Nyb2xsVG9wIC0gdmFsKSA8IDIpIHJldHVybjtcclxuICAgIGNtLmRvYy5zY3JvbGxUb3AgPSB2YWw7XHJcbiAgICBpZiAoIWdlY2tvKSB1cGRhdGVEaXNwbGF5U2ltcGxlKGNtLCB7dG9wOiB2YWx9KTtcclxuICAgIGlmIChjbS5kaXNwbGF5LnNjcm9sbGVyLnNjcm9sbFRvcCAhPSB2YWwpIGNtLmRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsVG9wID0gdmFsO1xyXG4gICAgY20uZGlzcGxheS5zY3JvbGxiYXJzLnNldFNjcm9sbFRvcCh2YWwpO1xyXG4gICAgaWYgKGdlY2tvKSB1cGRhdGVEaXNwbGF5U2ltcGxlKGNtKTtcclxuICAgIHN0YXJ0V29ya2VyKGNtLCAxMDApO1xyXG4gIH1cclxuICAvLyBTeW5jIHNjcm9sbGVyIGFuZCBzY3JvbGxiYXIsIGVuc3VyZSB0aGUgZ3V0dGVyIGVsZW1lbnRzIGFyZVxyXG4gIC8vIGFsaWduZWQuXHJcbiAgZnVuY3Rpb24gc2V0U2Nyb2xsTGVmdChjbSwgdmFsLCBpc1Njcm9sbGVyKSB7XHJcbiAgICBpZiAoaXNTY3JvbGxlciA/IHZhbCA9PSBjbS5kb2Muc2Nyb2xsTGVmdCA6IE1hdGguYWJzKGNtLmRvYy5zY3JvbGxMZWZ0IC0gdmFsKSA8IDIpIHJldHVybjtcclxuICAgIHZhbCA9IE1hdGgubWluKHZhbCwgY20uZGlzcGxheS5zY3JvbGxlci5zY3JvbGxXaWR0aCAtIGNtLmRpc3BsYXkuc2Nyb2xsZXIuY2xpZW50V2lkdGgpO1xyXG4gICAgY20uZG9jLnNjcm9sbExlZnQgPSB2YWw7XHJcbiAgICBhbGlnbkhvcml6b250YWxseShjbSk7XHJcbiAgICBpZiAoY20uZGlzcGxheS5zY3JvbGxlci5zY3JvbGxMZWZ0ICE9IHZhbCkgY20uZGlzcGxheS5zY3JvbGxlci5zY3JvbGxMZWZ0ID0gdmFsO1xyXG4gICAgY20uZGlzcGxheS5zY3JvbGxiYXJzLnNldFNjcm9sbExlZnQodmFsKTtcclxuICB9XHJcblxyXG4gIC8vIFNpbmNlIHRoZSBkZWx0YSB2YWx1ZXMgcmVwb3J0ZWQgb24gbW91c2Ugd2hlZWwgZXZlbnRzIGFyZVxyXG4gIC8vIHVuc3RhbmRhcmRpemVkIGJldHdlZW4gYnJvd3NlcnMgYW5kIGV2ZW4gYnJvd3NlciB2ZXJzaW9ucywgYW5kXHJcbiAgLy8gZ2VuZXJhbGx5IGhvcnJpYmx5IHVucHJlZGljdGFibGUsIHRoaXMgY29kZSBzdGFydHMgYnkgbWVhc3VyaW5nXHJcbiAgLy8gdGhlIHNjcm9sbCBlZmZlY3QgdGhhdCB0aGUgZmlyc3QgZmV3IG1vdXNlIHdoZWVsIGV2ZW50cyBoYXZlLFxyXG4gIC8vIGFuZCwgZnJvbSB0aGF0LCBkZXRlY3RzIHRoZSB3YXkgaXQgY2FuIGNvbnZlcnQgZGVsdGFzIHRvIHBpeGVsXHJcbiAgLy8gb2Zmc2V0cyBhZnRlcndhcmRzLlxyXG4gIC8vXHJcbiAgLy8gVGhlIHJlYXNvbiB3ZSB3YW50IHRvIGtub3cgdGhlIGFtb3VudCBhIHdoZWVsIGV2ZW50IHdpbGwgc2Nyb2xsXHJcbiAgLy8gaXMgdGhhdCBpdCBnaXZlcyB1cyBhIGNoYW5jZSB0byB1cGRhdGUgdGhlIGRpc3BsYXkgYmVmb3JlIHRoZVxyXG4gIC8vIGFjdHVhbCBzY3JvbGxpbmcgaGFwcGVucywgcmVkdWNpbmcgZmxpY2tlcmluZy5cclxuXHJcbiAgdmFyIHdoZWVsU2FtcGxlcyA9IDAsIHdoZWVsUGl4ZWxzUGVyVW5pdCA9IG51bGw7XHJcbiAgLy8gRmlsbCBpbiBhIGJyb3dzZXItZGV0ZWN0ZWQgc3RhcnRpbmcgdmFsdWUgb24gYnJvd3NlcnMgd2hlcmUgd2VcclxuICAvLyBrbm93IG9uZS4gVGhlc2UgZG9uJ3QgaGF2ZSB0byBiZSBhY2N1cmF0ZSAtLSB0aGUgcmVzdWx0IG9mIHRoZW1cclxuICAvLyBiZWluZyB3cm9uZyB3b3VsZCBqdXN0IGJlIGEgc2xpZ2h0IGZsaWNrZXIgb24gdGhlIGZpcnN0IHdoZWVsXHJcbiAgLy8gc2Nyb2xsIChpZiBpdCBpcyBsYXJnZSBlbm91Z2gpLlxyXG4gIGlmIChpZSkgd2hlZWxQaXhlbHNQZXJVbml0ID0gLS41MztcclxuICBlbHNlIGlmIChnZWNrbykgd2hlZWxQaXhlbHNQZXJVbml0ID0gMTU7XHJcbiAgZWxzZSBpZiAoY2hyb21lKSB3aGVlbFBpeGVsc1BlclVuaXQgPSAtLjc7XHJcbiAgZWxzZSBpZiAoc2FmYXJpKSB3aGVlbFBpeGVsc1BlclVuaXQgPSAtMS8zO1xyXG5cclxuICB2YXIgd2hlZWxFdmVudERlbHRhID0gZnVuY3Rpb24oZSkge1xyXG4gICAgdmFyIGR4ID0gZS53aGVlbERlbHRhWCwgZHkgPSBlLndoZWVsRGVsdGFZO1xyXG4gICAgaWYgKGR4ID09IG51bGwgJiYgZS5kZXRhaWwgJiYgZS5heGlzID09IGUuSE9SSVpPTlRBTF9BWElTKSBkeCA9IGUuZGV0YWlsO1xyXG4gICAgaWYgKGR5ID09IG51bGwgJiYgZS5kZXRhaWwgJiYgZS5heGlzID09IGUuVkVSVElDQUxfQVhJUykgZHkgPSBlLmRldGFpbDtcclxuICAgIGVsc2UgaWYgKGR5ID09IG51bGwpIGR5ID0gZS53aGVlbERlbHRhO1xyXG4gICAgcmV0dXJuIHt4OiBkeCwgeTogZHl9O1xyXG4gIH07XHJcbiAgQ29kZU1pcnJvci53aGVlbEV2ZW50UGl4ZWxzID0gZnVuY3Rpb24oZSkge1xyXG4gICAgdmFyIGRlbHRhID0gd2hlZWxFdmVudERlbHRhKGUpO1xyXG4gICAgZGVsdGEueCAqPSB3aGVlbFBpeGVsc1BlclVuaXQ7XHJcbiAgICBkZWx0YS55ICo9IHdoZWVsUGl4ZWxzUGVyVW5pdDtcclxuICAgIHJldHVybiBkZWx0YTtcclxuICB9O1xyXG5cclxuICBmdW5jdGlvbiBvblNjcm9sbFdoZWVsKGNtLCBlKSB7XHJcbiAgICB2YXIgZGVsdGEgPSB3aGVlbEV2ZW50RGVsdGEoZSksIGR4ID0gZGVsdGEueCwgZHkgPSBkZWx0YS55O1xyXG5cclxuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheSwgc2Nyb2xsID0gZGlzcGxheS5zY3JvbGxlcjtcclxuICAgIC8vIFF1aXQgaWYgdGhlcmUncyBub3RoaW5nIHRvIHNjcm9sbCBoZXJlXHJcbiAgICB2YXIgY2FuU2Nyb2xsWCA9IHNjcm9sbC5zY3JvbGxXaWR0aCA+IHNjcm9sbC5jbGllbnRXaWR0aDtcclxuICAgIHZhciBjYW5TY3JvbGxZID0gc2Nyb2xsLnNjcm9sbEhlaWdodCA+IHNjcm9sbC5jbGllbnRIZWlnaHQ7XHJcbiAgICBpZiAoIShkeCAmJiBjYW5TY3JvbGxYIHx8IGR5ICYmIGNhblNjcm9sbFkpKSByZXR1cm47XHJcblxyXG4gICAgLy8gV2Via2l0IGJyb3dzZXJzIG9uIE9TIFggYWJvcnQgbW9tZW50dW0gc2Nyb2xscyB3aGVuIHRoZSB0YXJnZXRcclxuICAgIC8vIG9mIHRoZSBzY3JvbGwgZXZlbnQgaXMgcmVtb3ZlZCBmcm9tIHRoZSBzY3JvbGxhYmxlIGVsZW1lbnQuXHJcbiAgICAvLyBUaGlzIGhhY2sgKHNlZSByZWxhdGVkIGNvZGUgaW4gcGF0Y2hEaXNwbGF5KSBtYWtlcyBzdXJlIHRoZVxyXG4gICAgLy8gZWxlbWVudCBpcyBrZXB0IGFyb3VuZC5cclxuICAgIGlmIChkeSAmJiBtYWMgJiYgd2Via2l0KSB7XHJcbiAgICAgIG91dGVyOiBmb3IgKHZhciBjdXIgPSBlLnRhcmdldCwgdmlldyA9IGRpc3BsYXkudmlldzsgY3VyICE9IHNjcm9sbDsgY3VyID0gY3VyLnBhcmVudE5vZGUpIHtcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZpZXcubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgIGlmICh2aWV3W2ldLm5vZGUgPT0gY3VyKSB7XHJcbiAgICAgICAgICAgIGNtLmRpc3BsYXkuY3VycmVudFdoZWVsVGFyZ2V0ID0gY3VyO1xyXG4gICAgICAgICAgICBicmVhayBvdXRlcjtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBPbiBzb21lIGJyb3dzZXJzLCBob3Jpem9udGFsIHNjcm9sbGluZyB3aWxsIGNhdXNlIHJlZHJhd3MgdG9cclxuICAgIC8vIGhhcHBlbiBiZWZvcmUgdGhlIGd1dHRlciBoYXMgYmVlbiByZWFsaWduZWQsIGNhdXNpbmcgaXQgdG9cclxuICAgIC8vIHdyaWdnbGUgYXJvdW5kIGluIGEgbW9zdCB1bnNlZW1seSB3YXkuIFdoZW4gd2UgaGF2ZSBhblxyXG4gICAgLy8gZXN0aW1hdGVkIHBpeGVscy9kZWx0YSB2YWx1ZSwgd2UganVzdCBoYW5kbGUgaG9yaXpvbnRhbFxyXG4gICAgLy8gc2Nyb2xsaW5nIGVudGlyZWx5IGhlcmUuIEl0J2xsIGJlIHNsaWdodGx5IG9mZiBmcm9tIG5hdGl2ZSwgYnV0XHJcbiAgICAvLyBiZXR0ZXIgdGhhbiBnbGl0Y2hpbmcgb3V0LlxyXG4gICAgaWYgKGR4ICYmICFnZWNrbyAmJiAhcHJlc3RvICYmIHdoZWVsUGl4ZWxzUGVyVW5pdCAhPSBudWxsKSB7XHJcbiAgICAgIGlmIChkeSAmJiBjYW5TY3JvbGxZKVxyXG4gICAgICAgIHNldFNjcm9sbFRvcChjbSwgTWF0aC5tYXgoMCwgTWF0aC5taW4oc2Nyb2xsLnNjcm9sbFRvcCArIGR5ICogd2hlZWxQaXhlbHNQZXJVbml0LCBzY3JvbGwuc2Nyb2xsSGVpZ2h0IC0gc2Nyb2xsLmNsaWVudEhlaWdodCkpKTtcclxuICAgICAgc2V0U2Nyb2xsTGVmdChjbSwgTWF0aC5tYXgoMCwgTWF0aC5taW4oc2Nyb2xsLnNjcm9sbExlZnQgKyBkeCAqIHdoZWVsUGl4ZWxzUGVyVW5pdCwgc2Nyb2xsLnNjcm9sbFdpZHRoIC0gc2Nyb2xsLmNsaWVudFdpZHRoKSkpO1xyXG4gICAgICAvLyBPbmx5IHByZXZlbnQgZGVmYXVsdCBzY3JvbGxpbmcgaWYgdmVydGljYWwgc2Nyb2xsaW5nIGlzXHJcbiAgICAgIC8vIGFjdHVhbGx5IHBvc3NpYmxlLiBPdGhlcndpc2UsIGl0IGNhdXNlcyB2ZXJ0aWNhbCBzY3JvbGxcclxuICAgICAgLy8gaml0dGVyIG9uIE9TWCB0cmFja3BhZHMgd2hlbiBkZWx0YVggaXMgc21hbGwgYW5kIGRlbHRhWVxyXG4gICAgICAvLyBpcyBsYXJnZSAoaXNzdWUgIzM1NzkpXHJcbiAgICAgIGlmICghZHkgfHwgKGR5ICYmIGNhblNjcm9sbFkpKVxyXG4gICAgICAgIGVfcHJldmVudERlZmF1bHQoZSk7XHJcbiAgICAgIGRpc3BsYXkud2hlZWxTdGFydFggPSBudWxsOyAvLyBBYm9ydCBtZWFzdXJlbWVudCwgaWYgaW4gcHJvZ3Jlc3NcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vICdQcm9qZWN0JyB0aGUgdmlzaWJsZSB2aWV3cG9ydCB0byBjb3ZlciB0aGUgYXJlYSB0aGF0IGlzIGJlaW5nXHJcbiAgICAvLyBzY3JvbGxlZCBpbnRvIHZpZXcgKGlmIHdlIGtub3cgZW5vdWdoIHRvIGVzdGltYXRlIGl0KS5cclxuICAgIGlmIChkeSAmJiB3aGVlbFBpeGVsc1BlclVuaXQgIT0gbnVsbCkge1xyXG4gICAgICB2YXIgcGl4ZWxzID0gZHkgKiB3aGVlbFBpeGVsc1BlclVuaXQ7XHJcbiAgICAgIHZhciB0b3AgPSBjbS5kb2Muc2Nyb2xsVG9wLCBib3QgPSB0b3AgKyBkaXNwbGF5LndyYXBwZXIuY2xpZW50SGVpZ2h0O1xyXG4gICAgICBpZiAocGl4ZWxzIDwgMCkgdG9wID0gTWF0aC5tYXgoMCwgdG9wICsgcGl4ZWxzIC0gNTApO1xyXG4gICAgICBlbHNlIGJvdCA9IE1hdGgubWluKGNtLmRvYy5oZWlnaHQsIGJvdCArIHBpeGVscyArIDUwKTtcclxuICAgICAgdXBkYXRlRGlzcGxheVNpbXBsZShjbSwge3RvcDogdG9wLCBib3R0b206IGJvdH0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh3aGVlbFNhbXBsZXMgPCAyMCkge1xyXG4gICAgICBpZiAoZGlzcGxheS53aGVlbFN0YXJ0WCA9PSBudWxsKSB7XHJcbiAgICAgICAgZGlzcGxheS53aGVlbFN0YXJ0WCA9IHNjcm9sbC5zY3JvbGxMZWZ0OyBkaXNwbGF5LndoZWVsU3RhcnRZID0gc2Nyb2xsLnNjcm9sbFRvcDtcclxuICAgICAgICBkaXNwbGF5LndoZWVsRFggPSBkeDsgZGlzcGxheS53aGVlbERZID0gZHk7XHJcbiAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcclxuICAgICAgICAgIGlmIChkaXNwbGF5LndoZWVsU3RhcnRYID09IG51bGwpIHJldHVybjtcclxuICAgICAgICAgIHZhciBtb3ZlZFggPSBzY3JvbGwuc2Nyb2xsTGVmdCAtIGRpc3BsYXkud2hlZWxTdGFydFg7XHJcbiAgICAgICAgICB2YXIgbW92ZWRZID0gc2Nyb2xsLnNjcm9sbFRvcCAtIGRpc3BsYXkud2hlZWxTdGFydFk7XHJcbiAgICAgICAgICB2YXIgc2FtcGxlID0gKG1vdmVkWSAmJiBkaXNwbGF5LndoZWVsRFkgJiYgbW92ZWRZIC8gZGlzcGxheS53aGVlbERZKSB8fFxyXG4gICAgICAgICAgICAobW92ZWRYICYmIGRpc3BsYXkud2hlZWxEWCAmJiBtb3ZlZFggLyBkaXNwbGF5LndoZWVsRFgpO1xyXG4gICAgICAgICAgZGlzcGxheS53aGVlbFN0YXJ0WCA9IGRpc3BsYXkud2hlZWxTdGFydFkgPSBudWxsO1xyXG4gICAgICAgICAgaWYgKCFzYW1wbGUpIHJldHVybjtcclxuICAgICAgICAgIHdoZWVsUGl4ZWxzUGVyVW5pdCA9ICh3aGVlbFBpeGVsc1BlclVuaXQgKiB3aGVlbFNhbXBsZXMgKyBzYW1wbGUpIC8gKHdoZWVsU2FtcGxlcyArIDEpO1xyXG4gICAgICAgICAgKyt3aGVlbFNhbXBsZXM7XHJcbiAgICAgICAgfSwgMjAwKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBkaXNwbGF5LndoZWVsRFggKz0gZHg7IGRpc3BsYXkud2hlZWxEWSArPSBkeTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gS0VZIEVWRU5UU1xyXG5cclxuICAvLyBSdW4gYSBoYW5kbGVyIHRoYXQgd2FzIGJvdW5kIHRvIGEga2V5LlxyXG4gIGZ1bmN0aW9uIGRvSGFuZGxlQmluZGluZyhjbSwgYm91bmQsIGRyb3BTaGlmdCkge1xyXG4gICAgaWYgKHR5cGVvZiBib3VuZCA9PSBcInN0cmluZ1wiKSB7XHJcbiAgICAgIGJvdW5kID0gY29tbWFuZHNbYm91bmRdO1xyXG4gICAgICBpZiAoIWJvdW5kKSByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgICAvLyBFbnN1cmUgcHJldmlvdXMgaW5wdXQgaGFzIGJlZW4gcmVhZCwgc28gdGhhdCB0aGUgaGFuZGxlciBzZWVzIGFcclxuICAgIC8vIGNvbnNpc3RlbnQgdmlldyBvZiB0aGUgZG9jdW1lbnRcclxuICAgIGNtLmRpc3BsYXkuaW5wdXQuZW5zdXJlUG9sbGVkKCk7XHJcbiAgICB2YXIgcHJldlNoaWZ0ID0gY20uZGlzcGxheS5zaGlmdCwgZG9uZSA9IGZhbHNlO1xyXG4gICAgdHJ5IHtcclxuICAgICAgaWYgKGlzUmVhZE9ubHkoY20pKSBjbS5zdGF0ZS5zdXBwcmVzc0VkaXRzID0gdHJ1ZTtcclxuICAgICAgaWYgKGRyb3BTaGlmdCkgY20uZGlzcGxheS5zaGlmdCA9IGZhbHNlO1xyXG4gICAgICBkb25lID0gYm91bmQoY20pICE9IFBhc3M7XHJcbiAgICB9IGZpbmFsbHkge1xyXG4gICAgICBjbS5kaXNwbGF5LnNoaWZ0ID0gcHJldlNoaWZ0O1xyXG4gICAgICBjbS5zdGF0ZS5zdXBwcmVzc0VkaXRzID0gZmFsc2U7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gZG9uZTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGxvb2t1cEtleUZvckVkaXRvcihjbSwgbmFtZSwgaGFuZGxlKSB7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNtLnN0YXRlLmtleU1hcHMubGVuZ3RoOyBpKyspIHtcclxuICAgICAgdmFyIHJlc3VsdCA9IGxvb2t1cEtleShuYW1lLCBjbS5zdGF0ZS5rZXlNYXBzW2ldLCBoYW5kbGUsIGNtKTtcclxuICAgICAgaWYgKHJlc3VsdCkgcmV0dXJuIHJlc3VsdDtcclxuICAgIH1cclxuICAgIHJldHVybiAoY20ub3B0aW9ucy5leHRyYUtleXMgJiYgbG9va3VwS2V5KG5hbWUsIGNtLm9wdGlvbnMuZXh0cmFLZXlzLCBoYW5kbGUsIGNtKSlcclxuICAgICAgfHwgbG9va3VwS2V5KG5hbWUsIGNtLm9wdGlvbnMua2V5TWFwLCBoYW5kbGUsIGNtKTtcclxuICB9XHJcblxyXG4gIHZhciBzdG9wU2VxID0gbmV3IERlbGF5ZWQ7XHJcbiAgZnVuY3Rpb24gZGlzcGF0Y2hLZXkoY20sIG5hbWUsIGUsIGhhbmRsZSkge1xyXG4gICAgdmFyIHNlcSA9IGNtLnN0YXRlLmtleVNlcTtcclxuICAgIGlmIChzZXEpIHtcclxuICAgICAgaWYgKGlzTW9kaWZpZXJLZXkobmFtZSkpIHJldHVybiBcImhhbmRsZWRcIjtcclxuICAgICAgc3RvcFNlcS5zZXQoNTAsIGZ1bmN0aW9uKCkge1xyXG4gICAgICAgIGlmIChjbS5zdGF0ZS5rZXlTZXEgPT0gc2VxKSB7XHJcbiAgICAgICAgICBjbS5zdGF0ZS5rZXlTZXEgPSBudWxsO1xyXG4gICAgICAgICAgY20uZGlzcGxheS5pbnB1dC5yZXNldCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICAgIG5hbWUgPSBzZXEgKyBcIiBcIiArIG5hbWU7XHJcbiAgICB9XHJcbiAgICB2YXIgcmVzdWx0ID0gbG9va3VwS2V5Rm9yRWRpdG9yKGNtLCBuYW1lLCBoYW5kbGUpO1xyXG5cclxuICAgIGlmIChyZXN1bHQgPT0gXCJtdWx0aVwiKVxyXG4gICAgICBjbS5zdGF0ZS5rZXlTZXEgPSBuYW1lO1xyXG4gICAgaWYgKHJlc3VsdCA9PSBcImhhbmRsZWRcIilcclxuICAgICAgc2lnbmFsTGF0ZXIoY20sIFwia2V5SGFuZGxlZFwiLCBjbSwgbmFtZSwgZSk7XHJcblxyXG4gICAgaWYgKHJlc3VsdCA9PSBcImhhbmRsZWRcIiB8fCByZXN1bHQgPT0gXCJtdWx0aVwiKSB7XHJcbiAgICAgIGVfcHJldmVudERlZmF1bHQoZSk7XHJcbiAgICAgIHJlc3RhcnRCbGluayhjbSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHNlcSAmJiAhcmVzdWx0ICYmIC9cXCckLy50ZXN0KG5hbWUpKSB7XHJcbiAgICAgIGVfcHJldmVudERlZmF1bHQoZSk7XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuICEhcmVzdWx0O1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGEga2V5IGZyb20gdGhlIGtleWRvd24gZXZlbnQuXHJcbiAgZnVuY3Rpb24gaGFuZGxlS2V5QmluZGluZyhjbSwgZSkge1xyXG4gICAgdmFyIG5hbWUgPSBrZXlOYW1lKGUsIHRydWUpO1xyXG4gICAgaWYgKCFuYW1lKSByZXR1cm4gZmFsc2U7XHJcblxyXG4gICAgaWYgKGUuc2hpZnRLZXkgJiYgIWNtLnN0YXRlLmtleVNlcSkge1xyXG4gICAgICAvLyBGaXJzdCB0cnkgdG8gcmVzb2x2ZSBmdWxsIG5hbWUgKGluY2x1ZGluZyAnU2hpZnQtJykuIEZhaWxpbmdcclxuICAgICAgLy8gdGhhdCwgc2VlIGlmIHRoZXJlIGlzIGEgY3Vyc29yLW1vdGlvbiBjb21tYW5kIChzdGFydGluZyB3aXRoXHJcbiAgICAgIC8vICdnbycpIGJvdW5kIHRvIHRoZSBrZXluYW1lIHdpdGhvdXQgJ1NoaWZ0LScuXHJcbiAgICAgIHJldHVybiBkaXNwYXRjaEtleShjbSwgXCJTaGlmdC1cIiArIG5hbWUsIGUsIGZ1bmN0aW9uKGIpIHtyZXR1cm4gZG9IYW5kbGVCaW5kaW5nKGNtLCBiLCB0cnVlKTt9KVxyXG4gICAgICAgICAgfHwgZGlzcGF0Y2hLZXkoY20sIG5hbWUsIGUsIGZ1bmN0aW9uKGIpIHtcclxuICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBiID09IFwic3RyaW5nXCIgPyAvXmdvW0EtWl0vLnRlc3QoYikgOiBiLm1vdGlvbilcclxuICAgICAgICAgICAgICAgICByZXR1cm4gZG9IYW5kbGVCaW5kaW5nKGNtLCBiKTtcclxuICAgICAgICAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgcmV0dXJuIGRpc3BhdGNoS2V5KGNtLCBuYW1lLCBlLCBmdW5jdGlvbihiKSB7IHJldHVybiBkb0hhbmRsZUJpbmRpbmcoY20sIGIpOyB9KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEhhbmRsZSBhIGtleSBmcm9tIHRoZSBrZXlwcmVzcyBldmVudFxyXG4gIGZ1bmN0aW9uIGhhbmRsZUNoYXJCaW5kaW5nKGNtLCBlLCBjaCkge1xyXG4gICAgcmV0dXJuIGRpc3BhdGNoS2V5KGNtLCBcIidcIiArIGNoICsgXCInXCIsIGUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oYikgeyByZXR1cm4gZG9IYW5kbGVCaW5kaW5nKGNtLCBiLCB0cnVlKTsgfSk7XHJcbiAgfVxyXG5cclxuICB2YXIgbGFzdFN0b3BwZWRLZXkgPSBudWxsO1xyXG4gIGZ1bmN0aW9uIG9uS2V5RG93bihlKSB7XHJcbiAgICB2YXIgY20gPSB0aGlzO1xyXG4gICAgY20uY3VyT3AuZm9jdXMgPSBhY3RpdmVFbHQoKTtcclxuICAgIGlmIChzaWduYWxET01FdmVudChjbSwgZSkpIHJldHVybjtcclxuICAgIC8vIElFIGRvZXMgc3RyYW5nZSB0aGluZ3Mgd2l0aCBlc2NhcGUuXHJcbiAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA8IDExICYmIGUua2V5Q29kZSA9PSAyNykgZS5yZXR1cm5WYWx1ZSA9IGZhbHNlO1xyXG4gICAgdmFyIGNvZGUgPSBlLmtleUNvZGU7XHJcbiAgICBjbS5kaXNwbGF5LnNoaWZ0ID0gY29kZSA9PSAxNiB8fCBlLnNoaWZ0S2V5O1xyXG4gICAgdmFyIGhhbmRsZWQgPSBoYW5kbGVLZXlCaW5kaW5nKGNtLCBlKTtcclxuICAgIGlmIChwcmVzdG8pIHtcclxuICAgICAgbGFzdFN0b3BwZWRLZXkgPSBoYW5kbGVkID8gY29kZSA6IG51bGw7XHJcbiAgICAgIC8vIE9wZXJhIGhhcyBubyBjdXQgZXZlbnQuLi4gd2UgdHJ5IHRvIGF0IGxlYXN0IGNhdGNoIHRoZSBrZXkgY29tYm9cclxuICAgICAgaWYgKCFoYW5kbGVkICYmIGNvZGUgPT0gODggJiYgIWhhc0NvcHlFdmVudCAmJiAobWFjID8gZS5tZXRhS2V5IDogZS5jdHJsS2V5KSlcclxuICAgICAgICBjbS5yZXBsYWNlU2VsZWN0aW9uKFwiXCIsIG51bGwsIFwiY3V0XCIpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFR1cm4gbW91c2UgaW50byBjcm9zc2hhaXIgd2hlbiBBbHQgaXMgaGVsZCBvbiBNYWMuXHJcbiAgICBpZiAoY29kZSA9PSAxOCAmJiAhL1xcYkNvZGVNaXJyb3ItY3Jvc3NoYWlyXFxiLy50ZXN0KGNtLmRpc3BsYXkubGluZURpdi5jbGFzc05hbWUpKVxyXG4gICAgICBzaG93Q3Jvc3NIYWlyKGNtKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIHNob3dDcm9zc0hhaXIoY20pIHtcclxuICAgIHZhciBsaW5lRGl2ID0gY20uZGlzcGxheS5saW5lRGl2O1xyXG4gICAgYWRkQ2xhc3MobGluZURpdiwgXCJDb2RlTWlycm9yLWNyb3NzaGFpclwiKTtcclxuXHJcbiAgICBmdW5jdGlvbiB1cChlKSB7XHJcbiAgICAgIGlmIChlLmtleUNvZGUgPT0gMTggfHwgIWUuYWx0S2V5KSB7XHJcbiAgICAgICAgcm1DbGFzcyhsaW5lRGl2LCBcIkNvZGVNaXJyb3ItY3Jvc3NoYWlyXCIpO1xyXG4gICAgICAgIG9mZihkb2N1bWVudCwgXCJrZXl1cFwiLCB1cCk7XHJcbiAgICAgICAgb2ZmKGRvY3VtZW50LCBcIm1vdXNlb3ZlclwiLCB1cCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIG9uKGRvY3VtZW50LCBcImtleXVwXCIsIHVwKTtcclxuICAgIG9uKGRvY3VtZW50LCBcIm1vdXNlb3ZlclwiLCB1cCk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBvbktleVVwKGUpIHtcclxuICAgIGlmIChlLmtleUNvZGUgPT0gMTYpIHRoaXMuZG9jLnNlbC5zaGlmdCA9IGZhbHNlO1xyXG4gICAgc2lnbmFsRE9NRXZlbnQodGhpcywgZSk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBvbktleVByZXNzKGUpIHtcclxuICAgIHZhciBjbSA9IHRoaXM7XHJcbiAgICBpZiAoZXZlbnRJbldpZGdldChjbS5kaXNwbGF5LCBlKSB8fCBzaWduYWxET01FdmVudChjbSwgZSkgfHwgZS5jdHJsS2V5ICYmICFlLmFsdEtleSB8fCBtYWMgJiYgZS5tZXRhS2V5KSByZXR1cm47XHJcbiAgICB2YXIga2V5Q29kZSA9IGUua2V5Q29kZSwgY2hhckNvZGUgPSBlLmNoYXJDb2RlO1xyXG4gICAgaWYgKHByZXN0byAmJiBrZXlDb2RlID09IGxhc3RTdG9wcGVkS2V5KSB7bGFzdFN0b3BwZWRLZXkgPSBudWxsOyBlX3ByZXZlbnREZWZhdWx0KGUpOyByZXR1cm47fVxyXG4gICAgaWYgKChwcmVzdG8gJiYgKCFlLndoaWNoIHx8IGUud2hpY2ggPCAxMCkpICYmIGhhbmRsZUtleUJpbmRpbmcoY20sIGUpKSByZXR1cm47XHJcbiAgICB2YXIgY2ggPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGNoYXJDb2RlID09IG51bGwgPyBrZXlDb2RlIDogY2hhckNvZGUpO1xyXG4gICAgaWYgKGhhbmRsZUNoYXJCaW5kaW5nKGNtLCBlLCBjaCkpIHJldHVybjtcclxuICAgIGNtLmRpc3BsYXkuaW5wdXQub25LZXlQcmVzcyhlKTtcclxuICB9XHJcblxyXG4gIC8vIEZPQ1VTL0JMVVIgRVZFTlRTXHJcblxyXG4gIGZ1bmN0aW9uIGRlbGF5Qmx1ckV2ZW50KGNtKSB7XHJcbiAgICBjbS5zdGF0ZS5kZWxheWluZ0JsdXJFdmVudCA9IHRydWU7XHJcbiAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xyXG4gICAgICBpZiAoY20uc3RhdGUuZGVsYXlpbmdCbHVyRXZlbnQpIHtcclxuICAgICAgICBjbS5zdGF0ZS5kZWxheWluZ0JsdXJFdmVudCA9IGZhbHNlO1xyXG4gICAgICAgIG9uQmx1cihjbSk7XHJcbiAgICAgIH1cclxuICAgIH0sIDEwMCk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBvbkZvY3VzKGNtKSB7XHJcbiAgICBpZiAoY20uc3RhdGUuZGVsYXlpbmdCbHVyRXZlbnQpIGNtLnN0YXRlLmRlbGF5aW5nQmx1ckV2ZW50ID0gZmFsc2U7XHJcblxyXG4gICAgaWYgKGNtLm9wdGlvbnMucmVhZE9ubHkgPT0gXCJub2N1cnNvclwiKSByZXR1cm47XHJcbiAgICBpZiAoIWNtLnN0YXRlLmZvY3VzZWQpIHtcclxuICAgICAgc2lnbmFsKGNtLCBcImZvY3VzXCIsIGNtKTtcclxuICAgICAgY20uc3RhdGUuZm9jdXNlZCA9IHRydWU7XHJcbiAgICAgIGFkZENsYXNzKGNtLmRpc3BsYXkud3JhcHBlciwgXCJDb2RlTWlycm9yLWZvY3VzZWRcIik7XHJcbiAgICAgIC8vIFRoaXMgdGVzdCBwcmV2ZW50cyB0aGlzIGZyb20gZmlyaW5nIHdoZW4gYSBjb250ZXh0XHJcbiAgICAgIC8vIG1lbnUgaXMgY2xvc2VkIChzaW5jZSB0aGUgaW5wdXQgcmVzZXQgd291bGQga2lsbCB0aGVcclxuICAgICAgLy8gc2VsZWN0LWFsbCBkZXRlY3Rpb24gaGFjaylcclxuICAgICAgaWYgKCFjbS5jdXJPcCAmJiBjbS5kaXNwbGF5LnNlbEZvckNvbnRleHRNZW51ICE9IGNtLmRvYy5zZWwpIHtcclxuICAgICAgICBjbS5kaXNwbGF5LmlucHV0LnJlc2V0KCk7XHJcbiAgICAgICAgaWYgKHdlYmtpdCkgc2V0VGltZW91dChmdW5jdGlvbigpIHsgY20uZGlzcGxheS5pbnB1dC5yZXNldCh0cnVlKTsgfSwgMjApOyAvLyBJc3N1ZSAjMTczMFxyXG4gICAgICB9XHJcbiAgICAgIGNtLmRpc3BsYXkuaW5wdXQucmVjZWl2ZWRGb2N1cygpO1xyXG4gICAgfVxyXG4gICAgcmVzdGFydEJsaW5rKGNtKTtcclxuICB9XHJcbiAgZnVuY3Rpb24gb25CbHVyKGNtKSB7XHJcbiAgICBpZiAoY20uc3RhdGUuZGVsYXlpbmdCbHVyRXZlbnQpIHJldHVybjtcclxuXHJcbiAgICBpZiAoY20uc3RhdGUuZm9jdXNlZCkge1xyXG4gICAgICBzaWduYWwoY20sIFwiYmx1clwiLCBjbSk7XHJcbiAgICAgIGNtLnN0YXRlLmZvY3VzZWQgPSBmYWxzZTtcclxuICAgICAgcm1DbGFzcyhjbS5kaXNwbGF5LndyYXBwZXIsIFwiQ29kZU1pcnJvci1mb2N1c2VkXCIpO1xyXG4gICAgfVxyXG4gICAgY2xlYXJJbnRlcnZhbChjbS5kaXNwbGF5LmJsaW5rZXIpO1xyXG4gICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtpZiAoIWNtLnN0YXRlLmZvY3VzZWQpIGNtLmRpc3BsYXkuc2hpZnQgPSBmYWxzZTt9LCAxNTApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ09OVEVYVCBNRU5VIEhBTkRMSU5HXHJcblxyXG4gIC8vIFRvIG1ha2UgdGhlIGNvbnRleHQgbWVudSB3b3JrLCB3ZSBuZWVkIHRvIGJyaWVmbHkgdW5oaWRlIHRoZVxyXG4gIC8vIHRleHRhcmVhIChtYWtpbmcgaXQgYXMgdW5vYnRydXNpdmUgYXMgcG9zc2libGUpIHRvIGxldCB0aGVcclxuICAvLyByaWdodC1jbGljayB0YWtlIGVmZmVjdCBvbiBpdC5cclxuICBmdW5jdGlvbiBvbkNvbnRleHRNZW51KGNtLCBlKSB7XHJcbiAgICBpZiAoZXZlbnRJbldpZGdldChjbS5kaXNwbGF5LCBlKSB8fCBjb250ZXh0TWVudUluR3V0dGVyKGNtLCBlKSkgcmV0dXJuO1xyXG4gICAgaWYgKHNpZ25hbERPTUV2ZW50KGNtLCBlLCBcImNvbnRleHRtZW51XCIpKSByZXR1cm47XHJcbiAgICBjbS5kaXNwbGF5LmlucHV0Lm9uQ29udGV4dE1lbnUoZSk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBjb250ZXh0TWVudUluR3V0dGVyKGNtLCBlKSB7XHJcbiAgICBpZiAoIWhhc0hhbmRsZXIoY20sIFwiZ3V0dGVyQ29udGV4dE1lbnVcIikpIHJldHVybiBmYWxzZTtcclxuICAgIHJldHVybiBndXR0ZXJFdmVudChjbSwgZSwgXCJndXR0ZXJDb250ZXh0TWVudVwiLCBmYWxzZSk7XHJcbiAgfVxyXG5cclxuICAvLyBVUERBVElOR1xyXG5cclxuICAvLyBDb21wdXRlIHRoZSBwb3NpdGlvbiBvZiB0aGUgZW5kIG9mIGEgY2hhbmdlIChpdHMgJ3RvJyBwcm9wZXJ0eVxyXG4gIC8vIHJlZmVycyB0byB0aGUgcHJlLWNoYW5nZSBlbmQpLlxyXG4gIHZhciBjaGFuZ2VFbmQgPSBDb2RlTWlycm9yLmNoYW5nZUVuZCA9IGZ1bmN0aW9uKGNoYW5nZSkge1xyXG4gICAgaWYgKCFjaGFuZ2UudGV4dCkgcmV0dXJuIGNoYW5nZS50bztcclxuICAgIHJldHVybiBQb3MoY2hhbmdlLmZyb20ubGluZSArIGNoYW5nZS50ZXh0Lmxlbmd0aCAtIDEsXHJcbiAgICAgICAgICAgICAgIGxzdChjaGFuZ2UudGV4dCkubGVuZ3RoICsgKGNoYW5nZS50ZXh0Lmxlbmd0aCA9PSAxID8gY2hhbmdlLmZyb20uY2ggOiAwKSk7XHJcbiAgfTtcclxuXHJcbiAgLy8gQWRqdXN0IGEgcG9zaXRpb24gdG8gcmVmZXIgdG8gdGhlIHBvc3QtY2hhbmdlIHBvc2l0aW9uIG9mIHRoZVxyXG4gIC8vIHNhbWUgdGV4dCwgb3IgdGhlIGVuZCBvZiB0aGUgY2hhbmdlIGlmIHRoZSBjaGFuZ2UgY292ZXJzIGl0LlxyXG4gIGZ1bmN0aW9uIGFkanVzdEZvckNoYW5nZShwb3MsIGNoYW5nZSkge1xyXG4gICAgaWYgKGNtcChwb3MsIGNoYW5nZS5mcm9tKSA8IDApIHJldHVybiBwb3M7XHJcbiAgICBpZiAoY21wKHBvcywgY2hhbmdlLnRvKSA8PSAwKSByZXR1cm4gY2hhbmdlRW5kKGNoYW5nZSk7XHJcblxyXG4gICAgdmFyIGxpbmUgPSBwb3MubGluZSArIGNoYW5nZS50ZXh0Lmxlbmd0aCAtIChjaGFuZ2UudG8ubGluZSAtIGNoYW5nZS5mcm9tLmxpbmUpIC0gMSwgY2ggPSBwb3MuY2g7XHJcbiAgICBpZiAocG9zLmxpbmUgPT0gY2hhbmdlLnRvLmxpbmUpIGNoICs9IGNoYW5nZUVuZChjaGFuZ2UpLmNoIC0gY2hhbmdlLnRvLmNoO1xyXG4gICAgcmV0dXJuIFBvcyhsaW5lLCBjaCk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBjb21wdXRlU2VsQWZ0ZXJDaGFuZ2UoZG9jLCBjaGFuZ2UpIHtcclxuICAgIHZhciBvdXQgPSBbXTtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZG9jLnNlbC5yYW5nZXMubGVuZ3RoOyBpKyspIHtcclxuICAgICAgdmFyIHJhbmdlID0gZG9jLnNlbC5yYW5nZXNbaV07XHJcbiAgICAgIG91dC5wdXNoKG5ldyBSYW5nZShhZGp1c3RGb3JDaGFuZ2UocmFuZ2UuYW5jaG9yLCBjaGFuZ2UpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgYWRqdXN0Rm9yQ2hhbmdlKHJhbmdlLmhlYWQsIGNoYW5nZSkpKTtcclxuICAgIH1cclxuICAgIHJldHVybiBub3JtYWxpemVTZWxlY3Rpb24ob3V0LCBkb2Muc2VsLnByaW1JbmRleCk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBvZmZzZXRQb3MocG9zLCBvbGQsIG53KSB7XHJcbiAgICBpZiAocG9zLmxpbmUgPT0gb2xkLmxpbmUpXHJcbiAgICAgIHJldHVybiBQb3MobncubGluZSwgcG9zLmNoIC0gb2xkLmNoICsgbncuY2gpO1xyXG4gICAgZWxzZVxyXG4gICAgICByZXR1cm4gUG9zKG53LmxpbmUgKyAocG9zLmxpbmUgLSBvbGQubGluZSksIHBvcy5jaCk7XHJcbiAgfVxyXG5cclxuICAvLyBVc2VkIGJ5IHJlcGxhY2VTZWxlY3Rpb25zIHRvIGFsbG93IG1vdmluZyB0aGUgc2VsZWN0aW9uIHRvIHRoZVxyXG4gIC8vIHN0YXJ0IG9yIGFyb3VuZCB0aGUgcmVwbGFjZWQgdGVzdC4gSGludCBtYXkgYmUgXCJzdGFydFwiIG9yIFwiYXJvdW5kXCIuXHJcbiAgZnVuY3Rpb24gY29tcHV0ZVJlcGxhY2VkU2VsKGRvYywgY2hhbmdlcywgaGludCkge1xyXG4gICAgdmFyIG91dCA9IFtdO1xyXG4gICAgdmFyIG9sZFByZXYgPSBQb3MoZG9jLmZpcnN0LCAwKSwgbmV3UHJldiA9IG9sZFByZXY7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNoYW5nZXMubGVuZ3RoOyBpKyspIHtcclxuICAgICAgdmFyIGNoYW5nZSA9IGNoYW5nZXNbaV07XHJcbiAgICAgIHZhciBmcm9tID0gb2Zmc2V0UG9zKGNoYW5nZS5mcm9tLCBvbGRQcmV2LCBuZXdQcmV2KTtcclxuICAgICAgdmFyIHRvID0gb2Zmc2V0UG9zKGNoYW5nZUVuZChjaGFuZ2UpLCBvbGRQcmV2LCBuZXdQcmV2KTtcclxuICAgICAgb2xkUHJldiA9IGNoYW5nZS50bztcclxuICAgICAgbmV3UHJldiA9IHRvO1xyXG4gICAgICBpZiAoaGludCA9PSBcImFyb3VuZFwiKSB7XHJcbiAgICAgICAgdmFyIHJhbmdlID0gZG9jLnNlbC5yYW5nZXNbaV0sIGludiA9IGNtcChyYW5nZS5oZWFkLCByYW5nZS5hbmNob3IpIDwgMDtcclxuICAgICAgICBvdXRbaV0gPSBuZXcgUmFuZ2UoaW52ID8gdG8gOiBmcm9tLCBpbnYgPyBmcm9tIDogdG8pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIG91dFtpXSA9IG5ldyBSYW5nZShmcm9tLCBmcm9tKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIG5ldyBTZWxlY3Rpb24ob3V0LCBkb2Muc2VsLnByaW1JbmRleCk7XHJcbiAgfVxyXG5cclxuICAvLyBBbGxvdyBcImJlZm9yZUNoYW5nZVwiIGV2ZW50IGhhbmRsZXJzIHRvIGluZmx1ZW5jZSBhIGNoYW5nZVxyXG4gIGZ1bmN0aW9uIGZpbHRlckNoYW5nZShkb2MsIGNoYW5nZSwgdXBkYXRlKSB7XHJcbiAgICB2YXIgb2JqID0ge1xyXG4gICAgICBjYW5jZWxlZDogZmFsc2UsXHJcbiAgICAgIGZyb206IGNoYW5nZS5mcm9tLFxyXG4gICAgICB0bzogY2hhbmdlLnRvLFxyXG4gICAgICB0ZXh0OiBjaGFuZ2UudGV4dCxcclxuICAgICAgb3JpZ2luOiBjaGFuZ2Uub3JpZ2luLFxyXG4gICAgICBjYW5jZWw6IGZ1bmN0aW9uKCkgeyB0aGlzLmNhbmNlbGVkID0gdHJ1ZTsgfVxyXG4gICAgfTtcclxuICAgIGlmICh1cGRhdGUpIG9iai51cGRhdGUgPSBmdW5jdGlvbihmcm9tLCB0bywgdGV4dCwgb3JpZ2luKSB7XHJcbiAgICAgIGlmIChmcm9tKSB0aGlzLmZyb20gPSBjbGlwUG9zKGRvYywgZnJvbSk7XHJcbiAgICAgIGlmICh0bykgdGhpcy50byA9IGNsaXBQb3MoZG9jLCB0byk7XHJcbiAgICAgIGlmICh0ZXh0KSB0aGlzLnRleHQgPSB0ZXh0O1xyXG4gICAgICBpZiAob3JpZ2luICE9PSB1bmRlZmluZWQpIHRoaXMub3JpZ2luID0gb3JpZ2luO1xyXG4gICAgfTtcclxuICAgIHNpZ25hbChkb2MsIFwiYmVmb3JlQ2hhbmdlXCIsIGRvYywgb2JqKTtcclxuICAgIGlmIChkb2MuY20pIHNpZ25hbChkb2MuY20sIFwiYmVmb3JlQ2hhbmdlXCIsIGRvYy5jbSwgb2JqKTtcclxuXHJcbiAgICBpZiAob2JqLmNhbmNlbGVkKSByZXR1cm4gbnVsbDtcclxuICAgIHJldHVybiB7ZnJvbTogb2JqLmZyb20sIHRvOiBvYmoudG8sIHRleHQ6IG9iai50ZXh0LCBvcmlnaW46IG9iai5vcmlnaW59O1xyXG4gIH1cclxuXHJcbiAgLy8gQXBwbHkgYSBjaGFuZ2UgdG8gYSBkb2N1bWVudCwgYW5kIGFkZCBpdCB0byB0aGUgZG9jdW1lbnQnc1xyXG4gIC8vIGhpc3RvcnksIGFuZCBwcm9wYWdhdGluZyBpdCB0byBhbGwgbGlua2VkIGRvY3VtZW50cy5cclxuICBmdW5jdGlvbiBtYWtlQ2hhbmdlKGRvYywgY2hhbmdlLCBpZ25vcmVSZWFkT25seSkge1xyXG4gICAgaWYgKGRvYy5jbSkge1xyXG4gICAgICBpZiAoIWRvYy5jbS5jdXJPcCkgcmV0dXJuIG9wZXJhdGlvbihkb2MuY20sIG1ha2VDaGFuZ2UpKGRvYywgY2hhbmdlLCBpZ25vcmVSZWFkT25seSk7XHJcbiAgICAgIGlmIChkb2MuY20uc3RhdGUuc3VwcHJlc3NFZGl0cykgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChoYXNIYW5kbGVyKGRvYywgXCJiZWZvcmVDaGFuZ2VcIikgfHwgZG9jLmNtICYmIGhhc0hhbmRsZXIoZG9jLmNtLCBcImJlZm9yZUNoYW5nZVwiKSkge1xyXG4gICAgICBjaGFuZ2UgPSBmaWx0ZXJDaGFuZ2UoZG9jLCBjaGFuZ2UsIHRydWUpO1xyXG4gICAgICBpZiAoIWNoYW5nZSkgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFBvc3NpYmx5IHNwbGl0IG9yIHN1cHByZXNzIHRoZSB1cGRhdGUgYmFzZWQgb24gdGhlIHByZXNlbmNlXHJcbiAgICAvLyBvZiByZWFkLW9ubHkgc3BhbnMgaW4gaXRzIHJhbmdlLlxyXG4gICAgdmFyIHNwbGl0ID0gc2F3UmVhZE9ubHlTcGFucyAmJiAhaWdub3JlUmVhZE9ubHkgJiYgcmVtb3ZlUmVhZE9ubHlSYW5nZXMoZG9jLCBjaGFuZ2UuZnJvbSwgY2hhbmdlLnRvKTtcclxuICAgIGlmIChzcGxpdCkge1xyXG4gICAgICBmb3IgKHZhciBpID0gc3BsaXQubGVuZ3RoIC0gMTsgaSA+PSAwOyAtLWkpXHJcbiAgICAgICAgbWFrZUNoYW5nZUlubmVyKGRvYywge2Zyb206IHNwbGl0W2ldLmZyb20sIHRvOiBzcGxpdFtpXS50bywgdGV4dDogaSA/IFtcIlwiXSA6IGNoYW5nZS50ZXh0fSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBtYWtlQ2hhbmdlSW5uZXIoZG9jLCBjaGFuZ2UpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gbWFrZUNoYW5nZUlubmVyKGRvYywgY2hhbmdlKSB7XHJcbiAgICBpZiAoY2hhbmdlLnRleHQubGVuZ3RoID09IDEgJiYgY2hhbmdlLnRleHRbMF0gPT0gXCJcIiAmJiBjbXAoY2hhbmdlLmZyb20sIGNoYW5nZS50bykgPT0gMCkgcmV0dXJuO1xyXG4gICAgdmFyIHNlbEFmdGVyID0gY29tcHV0ZVNlbEFmdGVyQ2hhbmdlKGRvYywgY2hhbmdlKTtcclxuICAgIGFkZENoYW5nZVRvSGlzdG9yeShkb2MsIGNoYW5nZSwgc2VsQWZ0ZXIsIGRvYy5jbSA/IGRvYy5jbS5jdXJPcC5pZCA6IE5hTik7XHJcblxyXG4gICAgbWFrZUNoYW5nZVNpbmdsZURvYyhkb2MsIGNoYW5nZSwgc2VsQWZ0ZXIsIHN0cmV0Y2hTcGFuc092ZXJDaGFuZ2UoZG9jLCBjaGFuZ2UpKTtcclxuICAgIHZhciByZWJhc2VkID0gW107XHJcblxyXG4gICAgbGlua2VkRG9jcyhkb2MsIGZ1bmN0aW9uKGRvYywgc2hhcmVkSGlzdCkge1xyXG4gICAgICBpZiAoIXNoYXJlZEhpc3QgJiYgaW5kZXhPZihyZWJhc2VkLCBkb2MuaGlzdG9yeSkgPT0gLTEpIHtcclxuICAgICAgICByZWJhc2VIaXN0KGRvYy5oaXN0b3J5LCBjaGFuZ2UpO1xyXG4gICAgICAgIHJlYmFzZWQucHVzaChkb2MuaGlzdG9yeSk7XHJcbiAgICAgIH1cclxuICAgICAgbWFrZUNoYW5nZVNpbmdsZURvYyhkb2MsIGNoYW5nZSwgbnVsbCwgc3RyZXRjaFNwYW5zT3ZlckNoYW5nZShkb2MsIGNoYW5nZSkpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXZlcnQgYSBjaGFuZ2Ugc3RvcmVkIGluIGEgZG9jdW1lbnQncyBoaXN0b3J5LlxyXG4gIGZ1bmN0aW9uIG1ha2VDaGFuZ2VGcm9tSGlzdG9yeShkb2MsIHR5cGUsIGFsbG93U2VsZWN0aW9uT25seSkge1xyXG4gICAgaWYgKGRvYy5jbSAmJiBkb2MuY20uc3RhdGUuc3VwcHJlc3NFZGl0cykgcmV0dXJuO1xyXG5cclxuICAgIHZhciBoaXN0ID0gZG9jLmhpc3RvcnksIGV2ZW50LCBzZWxBZnRlciA9IGRvYy5zZWw7XHJcbiAgICB2YXIgc291cmNlID0gdHlwZSA9PSBcInVuZG9cIiA/IGhpc3QuZG9uZSA6IGhpc3QudW5kb25lLCBkZXN0ID0gdHlwZSA9PSBcInVuZG9cIiA/IGhpc3QudW5kb25lIDogaGlzdC5kb25lO1xyXG5cclxuICAgIC8vIFZlcmlmeSB0aGF0IHRoZXJlIGlzIGEgdXNlYWJsZSBldmVudCAoc28gdGhhdCBjdHJsLXogd29uJ3RcclxuICAgIC8vIG5lZWRsZXNzbHkgY2xlYXIgc2VsZWN0aW9uIGV2ZW50cylcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc291cmNlLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIGV2ZW50ID0gc291cmNlW2ldO1xyXG4gICAgICBpZiAoYWxsb3dTZWxlY3Rpb25Pbmx5ID8gZXZlbnQucmFuZ2VzICYmICFldmVudC5lcXVhbHMoZG9jLnNlbCkgOiAhZXZlbnQucmFuZ2VzKVxyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgfVxyXG4gICAgaWYgKGkgPT0gc291cmNlLmxlbmd0aCkgcmV0dXJuO1xyXG4gICAgaGlzdC5sYXN0T3JpZ2luID0gaGlzdC5sYXN0U2VsT3JpZ2luID0gbnVsbDtcclxuXHJcbiAgICBmb3IgKDs7KSB7XHJcbiAgICAgIGV2ZW50ID0gc291cmNlLnBvcCgpO1xyXG4gICAgICBpZiAoZXZlbnQucmFuZ2VzKSB7XHJcbiAgICAgICAgcHVzaFNlbGVjdGlvblRvSGlzdG9yeShldmVudCwgZGVzdCk7XHJcbiAgICAgICAgaWYgKGFsbG93U2VsZWN0aW9uT25seSAmJiAhZXZlbnQuZXF1YWxzKGRvYy5zZWwpKSB7XHJcbiAgICAgICAgICBzZXRTZWxlY3Rpb24oZG9jLCBldmVudCwge2NsZWFyUmVkbzogZmFsc2V9KTtcclxuICAgICAgICAgIHJldHVybjtcclxuICAgICAgICB9XHJcbiAgICAgICAgc2VsQWZ0ZXIgPSBldmVudDtcclxuICAgICAgfVxyXG4gICAgICBlbHNlIGJyZWFrO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEJ1aWxkIHVwIGEgcmV2ZXJzZSBjaGFuZ2Ugb2JqZWN0IHRvIGFkZCB0byB0aGUgb3Bwb3NpdGUgaGlzdG9yeVxyXG4gICAgLy8gc3RhY2sgKHJlZG8gd2hlbiB1bmRvaW5nLCBhbmQgdmljZSB2ZXJzYSkuXHJcbiAgICB2YXIgYW50aUNoYW5nZXMgPSBbXTtcclxuICAgIHB1c2hTZWxlY3Rpb25Ub0hpc3Rvcnkoc2VsQWZ0ZXIsIGRlc3QpO1xyXG4gICAgZGVzdC5wdXNoKHtjaGFuZ2VzOiBhbnRpQ2hhbmdlcywgZ2VuZXJhdGlvbjogaGlzdC5nZW5lcmF0aW9ufSk7XHJcbiAgICBoaXN0LmdlbmVyYXRpb24gPSBldmVudC5nZW5lcmF0aW9uIHx8ICsraGlzdC5tYXhHZW5lcmF0aW9uO1xyXG5cclxuICAgIHZhciBmaWx0ZXIgPSBoYXNIYW5kbGVyKGRvYywgXCJiZWZvcmVDaGFuZ2VcIikgfHwgZG9jLmNtICYmIGhhc0hhbmRsZXIoZG9jLmNtLCBcImJlZm9yZUNoYW5nZVwiKTtcclxuXHJcbiAgICBmb3IgKHZhciBpID0gZXZlbnQuY2hhbmdlcy5sZW5ndGggLSAxOyBpID49IDA7IC0taSkge1xyXG4gICAgICB2YXIgY2hhbmdlID0gZXZlbnQuY2hhbmdlc1tpXTtcclxuICAgICAgY2hhbmdlLm9yaWdpbiA9IHR5cGU7XHJcbiAgICAgIGlmIChmaWx0ZXIgJiYgIWZpbHRlckNoYW5nZShkb2MsIGNoYW5nZSwgZmFsc2UpKSB7XHJcbiAgICAgICAgc291cmNlLmxlbmd0aCA9IDA7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBhbnRpQ2hhbmdlcy5wdXNoKGhpc3RvcnlDaGFuZ2VGcm9tQ2hhbmdlKGRvYywgY2hhbmdlKSk7XHJcblxyXG4gICAgICB2YXIgYWZ0ZXIgPSBpID8gY29tcHV0ZVNlbEFmdGVyQ2hhbmdlKGRvYywgY2hhbmdlKSA6IGxzdChzb3VyY2UpO1xyXG4gICAgICBtYWtlQ2hhbmdlU2luZ2xlRG9jKGRvYywgY2hhbmdlLCBhZnRlciwgbWVyZ2VPbGRTcGFucyhkb2MsIGNoYW5nZSkpO1xyXG4gICAgICBpZiAoIWkgJiYgZG9jLmNtKSBkb2MuY20uc2Nyb2xsSW50b1ZpZXcoe2Zyb206IGNoYW5nZS5mcm9tLCB0bzogY2hhbmdlRW5kKGNoYW5nZSl9KTtcclxuICAgICAgdmFyIHJlYmFzZWQgPSBbXTtcclxuXHJcbiAgICAgIC8vIFByb3BhZ2F0ZSB0byB0aGUgbGlua2VkIGRvY3VtZW50c1xyXG4gICAgICBsaW5rZWREb2NzKGRvYywgZnVuY3Rpb24oZG9jLCBzaGFyZWRIaXN0KSB7XHJcbiAgICAgICAgaWYgKCFzaGFyZWRIaXN0ICYmIGluZGV4T2YocmViYXNlZCwgZG9jLmhpc3RvcnkpID09IC0xKSB7XHJcbiAgICAgICAgICByZWJhc2VIaXN0KGRvYy5oaXN0b3J5LCBjaGFuZ2UpO1xyXG4gICAgICAgICAgcmViYXNlZC5wdXNoKGRvYy5oaXN0b3J5KTtcclxuICAgICAgICB9XHJcbiAgICAgICAgbWFrZUNoYW5nZVNpbmdsZURvYyhkb2MsIGNoYW5nZSwgbnVsbCwgbWVyZ2VPbGRTcGFucyhkb2MsIGNoYW5nZSkpO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFN1Yi12aWV3cyBuZWVkIHRoZWlyIGxpbmUgbnVtYmVycyBzaGlmdGVkIHdoZW4gdGV4dCBpcyBhZGRlZFxyXG4gIC8vIGFib3ZlIG9yIGJlbG93IHRoZW0gaW4gdGhlIHBhcmVudCBkb2N1bWVudC5cclxuICBmdW5jdGlvbiBzaGlmdERvYyhkb2MsIGRpc3RhbmNlKSB7XHJcbiAgICBpZiAoZGlzdGFuY2UgPT0gMCkgcmV0dXJuO1xyXG4gICAgZG9jLmZpcnN0ICs9IGRpc3RhbmNlO1xyXG4gICAgZG9jLnNlbCA9IG5ldyBTZWxlY3Rpb24obWFwKGRvYy5zZWwucmFuZ2VzLCBmdW5jdGlvbihyYW5nZSkge1xyXG4gICAgICByZXR1cm4gbmV3IFJhbmdlKFBvcyhyYW5nZS5hbmNob3IubGluZSArIGRpc3RhbmNlLCByYW5nZS5hbmNob3IuY2gpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgIFBvcyhyYW5nZS5oZWFkLmxpbmUgKyBkaXN0YW5jZSwgcmFuZ2UuaGVhZC5jaCkpO1xyXG4gICAgfSksIGRvYy5zZWwucHJpbUluZGV4KTtcclxuICAgIGlmIChkb2MuY20pIHtcclxuICAgICAgcmVnQ2hhbmdlKGRvYy5jbSwgZG9jLmZpcnN0LCBkb2MuZmlyc3QgLSBkaXN0YW5jZSwgZGlzdGFuY2UpO1xyXG4gICAgICBmb3IgKHZhciBkID0gZG9jLmNtLmRpc3BsYXksIGwgPSBkLnZpZXdGcm9tOyBsIDwgZC52aWV3VG87IGwrKylcclxuICAgICAgICByZWdMaW5lQ2hhbmdlKGRvYy5jbSwgbCwgXCJndXR0ZXJcIik7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBNb3JlIGxvd2VyLWxldmVsIGNoYW5nZSBmdW5jdGlvbiwgaGFuZGxpbmcgb25seSBhIHNpbmdsZSBkb2N1bWVudFxyXG4gIC8vIChub3QgbGlua2VkIG9uZXMpLlxyXG4gIGZ1bmN0aW9uIG1ha2VDaGFuZ2VTaW5nbGVEb2MoZG9jLCBjaGFuZ2UsIHNlbEFmdGVyLCBzcGFucykge1xyXG4gICAgaWYgKGRvYy5jbSAmJiAhZG9jLmNtLmN1ck9wKVxyXG4gICAgICByZXR1cm4gb3BlcmF0aW9uKGRvYy5jbSwgbWFrZUNoYW5nZVNpbmdsZURvYykoZG9jLCBjaGFuZ2UsIHNlbEFmdGVyLCBzcGFucyk7XHJcblxyXG4gICAgaWYgKGNoYW5nZS50by5saW5lIDwgZG9jLmZpcnN0KSB7XHJcbiAgICAgIHNoaWZ0RG9jKGRvYywgY2hhbmdlLnRleHQubGVuZ3RoIC0gMSAtIChjaGFuZ2UudG8ubGluZSAtIGNoYW5nZS5mcm9tLmxpbmUpKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gICAgaWYgKGNoYW5nZS5mcm9tLmxpbmUgPiBkb2MubGFzdExpbmUoKSkgcmV0dXJuO1xyXG5cclxuICAgIC8vIENsaXAgdGhlIGNoYW5nZSB0byB0aGUgc2l6ZSBvZiB0aGlzIGRvY1xyXG4gICAgaWYgKGNoYW5nZS5mcm9tLmxpbmUgPCBkb2MuZmlyc3QpIHtcclxuICAgICAgdmFyIHNoaWZ0ID0gY2hhbmdlLnRleHQubGVuZ3RoIC0gMSAtIChkb2MuZmlyc3QgLSBjaGFuZ2UuZnJvbS5saW5lKTtcclxuICAgICAgc2hpZnREb2MoZG9jLCBzaGlmdCk7XHJcbiAgICAgIGNoYW5nZSA9IHtmcm9tOiBQb3MoZG9jLmZpcnN0LCAwKSwgdG86IFBvcyhjaGFuZ2UudG8ubGluZSArIHNoaWZ0LCBjaGFuZ2UudG8uY2gpLFxyXG4gICAgICAgICAgICAgICAgdGV4dDogW2xzdChjaGFuZ2UudGV4dCldLCBvcmlnaW46IGNoYW5nZS5vcmlnaW59O1xyXG4gICAgfVxyXG4gICAgdmFyIGxhc3QgPSBkb2MubGFzdExpbmUoKTtcclxuICAgIGlmIChjaGFuZ2UudG8ubGluZSA+IGxhc3QpIHtcclxuICAgICAgY2hhbmdlID0ge2Zyb206IGNoYW5nZS5mcm9tLCB0bzogUG9zKGxhc3QsIGdldExpbmUoZG9jLCBsYXN0KS50ZXh0Lmxlbmd0aCksXHJcbiAgICAgICAgICAgICAgICB0ZXh0OiBbY2hhbmdlLnRleHRbMF1dLCBvcmlnaW46IGNoYW5nZS5vcmlnaW59O1xyXG4gICAgfVxyXG5cclxuICAgIGNoYW5nZS5yZW1vdmVkID0gZ2V0QmV0d2Vlbihkb2MsIGNoYW5nZS5mcm9tLCBjaGFuZ2UudG8pO1xyXG5cclxuICAgIGlmICghc2VsQWZ0ZXIpIHNlbEFmdGVyID0gY29tcHV0ZVNlbEFmdGVyQ2hhbmdlKGRvYywgY2hhbmdlKTtcclxuICAgIGlmIChkb2MuY20pIG1ha2VDaGFuZ2VTaW5nbGVEb2NJbkVkaXRvcihkb2MuY20sIGNoYW5nZSwgc3BhbnMpO1xyXG4gICAgZWxzZSB1cGRhdGVEb2MoZG9jLCBjaGFuZ2UsIHNwYW5zKTtcclxuICAgIHNldFNlbGVjdGlvbk5vVW5kbyhkb2MsIHNlbEFmdGVyLCBzZWxfZG9udFNjcm9sbCk7XHJcbiAgfVxyXG5cclxuICAvLyBIYW5kbGUgdGhlIGludGVyYWN0aW9uIG9mIGEgY2hhbmdlIHRvIGEgZG9jdW1lbnQgd2l0aCB0aGUgZWRpdG9yXHJcbiAgLy8gdGhhdCB0aGlzIGRvY3VtZW50IGlzIHBhcnQgb2YuXHJcbiAgZnVuY3Rpb24gbWFrZUNoYW5nZVNpbmdsZURvY0luRWRpdG9yKGNtLCBjaGFuZ2UsIHNwYW5zKSB7XHJcbiAgICB2YXIgZG9jID0gY20uZG9jLCBkaXNwbGF5ID0gY20uZGlzcGxheSwgZnJvbSA9IGNoYW5nZS5mcm9tLCB0byA9IGNoYW5nZS50bztcclxuXHJcbiAgICB2YXIgcmVjb21wdXRlTWF4TGVuZ3RoID0gZmFsc2UsIGNoZWNrV2lkdGhTdGFydCA9IGZyb20ubGluZTtcclxuICAgIGlmICghY20ub3B0aW9ucy5saW5lV3JhcHBpbmcpIHtcclxuICAgICAgY2hlY2tXaWR0aFN0YXJ0ID0gbGluZU5vKHZpc3VhbExpbmUoZ2V0TGluZShkb2MsIGZyb20ubGluZSkpKTtcclxuICAgICAgZG9jLml0ZXIoY2hlY2tXaWR0aFN0YXJ0LCB0by5saW5lICsgMSwgZnVuY3Rpb24obGluZSkge1xyXG4gICAgICAgIGlmIChsaW5lID09IGRpc3BsYXkubWF4TGluZSkge1xyXG4gICAgICAgICAgcmVjb21wdXRlTWF4TGVuZ3RoID0gdHJ1ZTtcclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGRvYy5zZWwuY29udGFpbnMoY2hhbmdlLmZyb20sIGNoYW5nZS50bykgPiAtMSlcclxuICAgICAgc2lnbmFsQ3Vyc29yQWN0aXZpdHkoY20pO1xyXG5cclxuICAgIHVwZGF0ZURvYyhkb2MsIGNoYW5nZSwgc3BhbnMsIGVzdGltYXRlSGVpZ2h0KGNtKSk7XHJcblxyXG4gICAgaWYgKCFjbS5vcHRpb25zLmxpbmVXcmFwcGluZykge1xyXG4gICAgICBkb2MuaXRlcihjaGVja1dpZHRoU3RhcnQsIGZyb20ubGluZSArIGNoYW5nZS50ZXh0Lmxlbmd0aCwgZnVuY3Rpb24obGluZSkge1xyXG4gICAgICAgIHZhciBsZW4gPSBsaW5lTGVuZ3RoKGxpbmUpO1xyXG4gICAgICAgIGlmIChsZW4gPiBkaXNwbGF5Lm1heExpbmVMZW5ndGgpIHtcclxuICAgICAgICAgIGRpc3BsYXkubWF4TGluZSA9IGxpbmU7XHJcbiAgICAgICAgICBkaXNwbGF5Lm1heExpbmVMZW5ndGggPSBsZW47XHJcbiAgICAgICAgICBkaXNwbGF5Lm1heExpbmVDaGFuZ2VkID0gdHJ1ZTtcclxuICAgICAgICAgIHJlY29tcHV0ZU1heExlbmd0aCA9IGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICAgIGlmIChyZWNvbXB1dGVNYXhMZW5ndGgpIGNtLmN1ck9wLnVwZGF0ZU1heExpbmUgPSB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFkanVzdCBmcm9udGllciwgc2NoZWR1bGUgd29ya2VyXHJcbiAgICBkb2MuZnJvbnRpZXIgPSBNYXRoLm1pbihkb2MuZnJvbnRpZXIsIGZyb20ubGluZSk7XHJcbiAgICBzdGFydFdvcmtlcihjbSwgNDAwKTtcclxuXHJcbiAgICB2YXIgbGVuZGlmZiA9IGNoYW5nZS50ZXh0Lmxlbmd0aCAtICh0by5saW5lIC0gZnJvbS5saW5lKSAtIDE7XHJcbiAgICAvLyBSZW1lbWJlciB0aGF0IHRoZXNlIGxpbmVzIGNoYW5nZWQsIGZvciB1cGRhdGluZyB0aGUgZGlzcGxheVxyXG4gICAgaWYgKGNoYW5nZS5mdWxsKVxyXG4gICAgICByZWdDaGFuZ2UoY20pO1xyXG4gICAgZWxzZSBpZiAoZnJvbS5saW5lID09IHRvLmxpbmUgJiYgY2hhbmdlLnRleHQubGVuZ3RoID09IDEgJiYgIWlzV2hvbGVMaW5lVXBkYXRlKGNtLmRvYywgY2hhbmdlKSlcclxuICAgICAgcmVnTGluZUNoYW5nZShjbSwgZnJvbS5saW5lLCBcInRleHRcIik7XHJcbiAgICBlbHNlXHJcbiAgICAgIHJlZ0NoYW5nZShjbSwgZnJvbS5saW5lLCB0by5saW5lICsgMSwgbGVuZGlmZik7XHJcblxyXG4gICAgdmFyIGNoYW5nZXNIYW5kbGVyID0gaGFzSGFuZGxlcihjbSwgXCJjaGFuZ2VzXCIpLCBjaGFuZ2VIYW5kbGVyID0gaGFzSGFuZGxlcihjbSwgXCJjaGFuZ2VcIik7XHJcbiAgICBpZiAoY2hhbmdlSGFuZGxlciB8fCBjaGFuZ2VzSGFuZGxlcikge1xyXG4gICAgICB2YXIgb2JqID0ge1xyXG4gICAgICAgIGZyb206IGZyb20sIHRvOiB0byxcclxuICAgICAgICB0ZXh0OiBjaGFuZ2UudGV4dCxcclxuICAgICAgICByZW1vdmVkOiBjaGFuZ2UucmVtb3ZlZCxcclxuICAgICAgICBvcmlnaW46IGNoYW5nZS5vcmlnaW5cclxuICAgICAgfTtcclxuICAgICAgaWYgKGNoYW5nZUhhbmRsZXIpIHNpZ25hbExhdGVyKGNtLCBcImNoYW5nZVwiLCBjbSwgb2JqKTtcclxuICAgICAgaWYgKGNoYW5nZXNIYW5kbGVyKSAoY20uY3VyT3AuY2hhbmdlT2JqcyB8fCAoY20uY3VyT3AuY2hhbmdlT2JqcyA9IFtdKSkucHVzaChvYmopO1xyXG4gICAgfVxyXG4gICAgY20uZGlzcGxheS5zZWxGb3JDb250ZXh0TWVudSA9IG51bGw7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiByZXBsYWNlUmFuZ2UoZG9jLCBjb2RlLCBmcm9tLCB0bywgb3JpZ2luKSB7XHJcbiAgICBpZiAoIXRvKSB0byA9IGZyb207XHJcbiAgICBpZiAoY21wKHRvLCBmcm9tKSA8IDApIHsgdmFyIHRtcCA9IHRvOyB0byA9IGZyb207IGZyb20gPSB0bXA7IH1cclxuICAgIGlmICh0eXBlb2YgY29kZSA9PSBcInN0cmluZ1wiKSBjb2RlID0gZG9jLnNwbGl0TGluZXMoY29kZSk7XHJcbiAgICBtYWtlQ2hhbmdlKGRvYywge2Zyb206IGZyb20sIHRvOiB0bywgdGV4dDogY29kZSwgb3JpZ2luOiBvcmlnaW59KTtcclxuICB9XHJcblxyXG4gIC8vIFNDUk9MTElORyBUSElOR1MgSU5UTyBWSUVXXHJcblxyXG4gIC8vIElmIGFuIGVkaXRvciBzaXRzIG9uIHRoZSB0b3Agb3IgYm90dG9tIG9mIHRoZSB3aW5kb3csIHBhcnRpYWxseVxyXG4gIC8vIHNjcm9sbGVkIG91dCBvZiB2aWV3LCB0aGlzIGVuc3VyZXMgdGhhdCB0aGUgY3Vyc29yIGlzIHZpc2libGUuXHJcbiAgZnVuY3Rpb24gbWF5YmVTY3JvbGxXaW5kb3coY20sIGNvb3Jkcykge1xyXG4gICAgaWYgKHNpZ25hbERPTUV2ZW50KGNtLCBcInNjcm9sbEN1cnNvckludG9WaWV3XCIpKSByZXR1cm47XHJcblxyXG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCBib3ggPSBkaXNwbGF5LnNpemVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLCBkb1Njcm9sbCA9IG51bGw7XHJcbiAgICBpZiAoY29vcmRzLnRvcCArIGJveC50b3AgPCAwKSBkb1Njcm9sbCA9IHRydWU7XHJcbiAgICBlbHNlIGlmIChjb29yZHMuYm90dG9tICsgYm94LnRvcCA+ICh3aW5kb3cuaW5uZXJIZWlnaHQgfHwgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodCkpIGRvU2Nyb2xsID0gZmFsc2U7XHJcbiAgICBpZiAoZG9TY3JvbGwgIT0gbnVsbCAmJiAhcGhhbnRvbSkge1xyXG4gICAgICB2YXIgc2Nyb2xsTm9kZSA9IGVsdChcImRpdlwiLCBcIlxcdTIwMGJcIiwgbnVsbCwgXCJwb3NpdGlvbjogYWJzb2x1dGU7IHRvcDogXCIgK1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAoY29vcmRzLnRvcCAtIGRpc3BsYXkudmlld09mZnNldCAtIHBhZGRpbmdUb3AoY20uZGlzcGxheSkpICsgXCJweDsgaGVpZ2h0OiBcIiArXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIChjb29yZHMuYm90dG9tIC0gY29vcmRzLnRvcCArIHNjcm9sbEdhcChjbSkgKyBkaXNwbGF5LmJhckhlaWdodCkgKyBcInB4OyBsZWZ0OiBcIiArXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvb3Jkcy5sZWZ0ICsgXCJweDsgd2lkdGg6IDJweDtcIik7XHJcbiAgICAgIGNtLmRpc3BsYXkubGluZVNwYWNlLmFwcGVuZENoaWxkKHNjcm9sbE5vZGUpO1xyXG4gICAgICBzY3JvbGxOb2RlLnNjcm9sbEludG9WaWV3KGRvU2Nyb2xsKTtcclxuICAgICAgY20uZGlzcGxheS5saW5lU3BhY2UucmVtb3ZlQ2hpbGQoc2Nyb2xsTm9kZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTY3JvbGwgYSBnaXZlbiBwb3NpdGlvbiBpbnRvIHZpZXcgKGltbWVkaWF0ZWx5KSwgdmVyaWZ5aW5nIHRoYXRcclxuICAvLyBpdCBhY3R1YWxseSBiZWNhbWUgdmlzaWJsZSAoYXMgbGluZSBoZWlnaHRzIGFyZSBhY2N1cmF0ZWx5XHJcbiAgLy8gbWVhc3VyZWQsIHRoZSBwb3NpdGlvbiBvZiBzb21ldGhpbmcgbWF5ICdkcmlmdCcgZHVyaW5nIGRyYXdpbmcpLlxyXG4gIGZ1bmN0aW9uIHNjcm9sbFBvc0ludG9WaWV3KGNtLCBwb3MsIGVuZCwgbWFyZ2luKSB7XHJcbiAgICBpZiAobWFyZ2luID09IG51bGwpIG1hcmdpbiA9IDA7XHJcbiAgICBmb3IgKHZhciBsaW1pdCA9IDA7IGxpbWl0IDwgNTsgbGltaXQrKykge1xyXG4gICAgICB2YXIgY2hhbmdlZCA9IGZhbHNlLCBjb29yZHMgPSBjdXJzb3JDb29yZHMoY20sIHBvcyk7XHJcbiAgICAgIHZhciBlbmRDb29yZHMgPSAhZW5kIHx8IGVuZCA9PSBwb3MgPyBjb29yZHMgOiBjdXJzb3JDb29yZHMoY20sIGVuZCk7XHJcbiAgICAgIHZhciBzY3JvbGxQb3MgPSBjYWxjdWxhdGVTY3JvbGxQb3MoY20sIE1hdGgubWluKGNvb3Jkcy5sZWZ0LCBlbmRDb29yZHMubGVmdCksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWF0aC5taW4oY29vcmRzLnRvcCwgZW5kQ29vcmRzLnRvcCkgLSBtYXJnaW4sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWF0aC5tYXgoY29vcmRzLmxlZnQsIGVuZENvb3Jkcy5sZWZ0KSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNYXRoLm1heChjb29yZHMuYm90dG9tLCBlbmRDb29yZHMuYm90dG9tKSArIG1hcmdpbik7XHJcbiAgICAgIHZhciBzdGFydFRvcCA9IGNtLmRvYy5zY3JvbGxUb3AsIHN0YXJ0TGVmdCA9IGNtLmRvYy5zY3JvbGxMZWZ0O1xyXG4gICAgICBpZiAoc2Nyb2xsUG9zLnNjcm9sbFRvcCAhPSBudWxsKSB7XHJcbiAgICAgICAgc2V0U2Nyb2xsVG9wKGNtLCBzY3JvbGxQb3Muc2Nyb2xsVG9wKTtcclxuICAgICAgICBpZiAoTWF0aC5hYnMoY20uZG9jLnNjcm9sbFRvcCAtIHN0YXJ0VG9wKSA+IDEpIGNoYW5nZWQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChzY3JvbGxQb3Muc2Nyb2xsTGVmdCAhPSBudWxsKSB7XHJcbiAgICAgICAgc2V0U2Nyb2xsTGVmdChjbSwgc2Nyb2xsUG9zLnNjcm9sbExlZnQpO1xyXG4gICAgICAgIGlmIChNYXRoLmFicyhjbS5kb2Muc2Nyb2xsTGVmdCAtIHN0YXJ0TGVmdCkgPiAxKSBjaGFuZ2VkID0gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgICBpZiAoIWNoYW5nZWQpIGJyZWFrO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGNvb3JkcztcclxuICB9XHJcblxyXG4gIC8vIFNjcm9sbCBhIGdpdmVuIHNldCBvZiBjb29yZGluYXRlcyBpbnRvIHZpZXcgKGltbWVkaWF0ZWx5KS5cclxuICBmdW5jdGlvbiBzY3JvbGxJbnRvVmlldyhjbSwgeDEsIHkxLCB4MiwgeTIpIHtcclxuICAgIHZhciBzY3JvbGxQb3MgPSBjYWxjdWxhdGVTY3JvbGxQb3MoY20sIHgxLCB5MSwgeDIsIHkyKTtcclxuICAgIGlmIChzY3JvbGxQb3Muc2Nyb2xsVG9wICE9IG51bGwpIHNldFNjcm9sbFRvcChjbSwgc2Nyb2xsUG9zLnNjcm9sbFRvcCk7XHJcbiAgICBpZiAoc2Nyb2xsUG9zLnNjcm9sbExlZnQgIT0gbnVsbCkgc2V0U2Nyb2xsTGVmdChjbSwgc2Nyb2xsUG9zLnNjcm9sbExlZnQpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsY3VsYXRlIGEgbmV3IHNjcm9sbCBwb3NpdGlvbiBuZWVkZWQgdG8gc2Nyb2xsIHRoZSBnaXZlblxyXG4gIC8vIHJlY3RhbmdsZSBpbnRvIHZpZXcuIFJldHVybnMgYW4gb2JqZWN0IHdpdGggc2Nyb2xsVG9wIGFuZFxyXG4gIC8vIHNjcm9sbExlZnQgcHJvcGVydGllcy4gV2hlbiB0aGVzZSBhcmUgdW5kZWZpbmVkLCB0aGVcclxuICAvLyB2ZXJ0aWNhbC9ob3Jpem9udGFsIHBvc2l0aW9uIGRvZXMgbm90IG5lZWQgdG8gYmUgYWRqdXN0ZWQuXHJcbiAgZnVuY3Rpb24gY2FsY3VsYXRlU2Nyb2xsUG9zKGNtLCB4MSwgeTEsIHgyLCB5Mikge1xyXG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCBzbmFwTWFyZ2luID0gdGV4dEhlaWdodChjbS5kaXNwbGF5KTtcclxuICAgIGlmICh5MSA8IDApIHkxID0gMDtcclxuICAgIHZhciBzY3JlZW50b3AgPSBjbS5jdXJPcCAmJiBjbS5jdXJPcC5zY3JvbGxUb3AgIT0gbnVsbCA/IGNtLmN1ck9wLnNjcm9sbFRvcCA6IGRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsVG9wO1xyXG4gICAgdmFyIHNjcmVlbiA9IGRpc3BsYXlIZWlnaHQoY20pLCByZXN1bHQgPSB7fTtcclxuICAgIGlmICh5MiAtIHkxID4gc2NyZWVuKSB5MiA9IHkxICsgc2NyZWVuO1xyXG4gICAgdmFyIGRvY0JvdHRvbSA9IGNtLmRvYy5oZWlnaHQgKyBwYWRkaW5nVmVydChkaXNwbGF5KTtcclxuICAgIHZhciBhdFRvcCA9IHkxIDwgc25hcE1hcmdpbiwgYXRCb3R0b20gPSB5MiA+IGRvY0JvdHRvbSAtIHNuYXBNYXJnaW47XHJcbiAgICBpZiAoeTEgPCBzY3JlZW50b3ApIHtcclxuICAgICAgcmVzdWx0LnNjcm9sbFRvcCA9IGF0VG9wID8gMCA6IHkxO1xyXG4gICAgfSBlbHNlIGlmICh5MiA+IHNjcmVlbnRvcCArIHNjcmVlbikge1xyXG4gICAgICB2YXIgbmV3VG9wID0gTWF0aC5taW4oeTEsIChhdEJvdHRvbSA/IGRvY0JvdHRvbSA6IHkyKSAtIHNjcmVlbik7XHJcbiAgICAgIGlmIChuZXdUb3AgIT0gc2NyZWVudG9wKSByZXN1bHQuc2Nyb2xsVG9wID0gbmV3VG9wO1xyXG4gICAgfVxyXG5cclxuICAgIHZhciBzY3JlZW5sZWZ0ID0gY20uY3VyT3AgJiYgY20uY3VyT3Auc2Nyb2xsTGVmdCAhPSBudWxsID8gY20uY3VyT3Auc2Nyb2xsTGVmdCA6IGRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsTGVmdDtcclxuICAgIHZhciBzY3JlZW53ID0gZGlzcGxheVdpZHRoKGNtKSAtIChjbS5vcHRpb25zLmZpeGVkR3V0dGVyID8gZGlzcGxheS5ndXR0ZXJzLm9mZnNldFdpZHRoIDogMCk7XHJcbiAgICB2YXIgdG9vV2lkZSA9IHgyIC0geDEgPiBzY3JlZW53O1xyXG4gICAgaWYgKHRvb1dpZGUpIHgyID0geDEgKyBzY3JlZW53O1xyXG4gICAgaWYgKHgxIDwgMTApXHJcbiAgICAgIHJlc3VsdC5zY3JvbGxMZWZ0ID0gMDtcclxuICAgIGVsc2UgaWYgKHgxIDwgc2NyZWVubGVmdClcclxuICAgICAgcmVzdWx0LnNjcm9sbExlZnQgPSBNYXRoLm1heCgwLCB4MSAtICh0b29XaWRlID8gMCA6IDEwKSk7XHJcbiAgICBlbHNlIGlmICh4MiA+IHNjcmVlbncgKyBzY3JlZW5sZWZ0IC0gMylcclxuICAgICAgcmVzdWx0LnNjcm9sbExlZnQgPSB4MiArICh0b29XaWRlID8gMCA6IDEwKSAtIHNjcmVlbnc7XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH1cclxuXHJcbiAgLy8gU3RvcmUgYSByZWxhdGl2ZSBhZGp1c3RtZW50IHRvIHRoZSBzY3JvbGwgcG9zaXRpb24gaW4gdGhlIGN1cnJlbnRcclxuICAvLyBvcGVyYXRpb24gKHRvIGJlIGFwcGxpZWQgd2hlbiB0aGUgb3BlcmF0aW9uIGZpbmlzaGVzKS5cclxuICBmdW5jdGlvbiBhZGRUb1Njcm9sbFBvcyhjbSwgbGVmdCwgdG9wKSB7XHJcbiAgICBpZiAobGVmdCAhPSBudWxsIHx8IHRvcCAhPSBudWxsKSByZXNvbHZlU2Nyb2xsVG9Qb3MoY20pO1xyXG4gICAgaWYgKGxlZnQgIT0gbnVsbClcclxuICAgICAgY20uY3VyT3Auc2Nyb2xsTGVmdCA9IChjbS5jdXJPcC5zY3JvbGxMZWZ0ID09IG51bGwgPyBjbS5kb2Muc2Nyb2xsTGVmdCA6IGNtLmN1ck9wLnNjcm9sbExlZnQpICsgbGVmdDtcclxuICAgIGlmICh0b3AgIT0gbnVsbClcclxuICAgICAgY20uY3VyT3Auc2Nyb2xsVG9wID0gKGNtLmN1ck9wLnNjcm9sbFRvcCA9PSBudWxsID8gY20uZG9jLnNjcm9sbFRvcCA6IGNtLmN1ck9wLnNjcm9sbFRvcCkgKyB0b3A7XHJcbiAgfVxyXG5cclxuICAvLyBNYWtlIHN1cmUgdGhhdCBhdCB0aGUgZW5kIG9mIHRoZSBvcGVyYXRpb24gdGhlIGN1cnJlbnQgY3Vyc29yIGlzXHJcbiAgLy8gc2hvd24uXHJcbiAgZnVuY3Rpb24gZW5zdXJlQ3Vyc29yVmlzaWJsZShjbSkge1xyXG4gICAgcmVzb2x2ZVNjcm9sbFRvUG9zKGNtKTtcclxuICAgIHZhciBjdXIgPSBjbS5nZXRDdXJzb3IoKSwgZnJvbSA9IGN1ciwgdG8gPSBjdXI7XHJcbiAgICBpZiAoIWNtLm9wdGlvbnMubGluZVdyYXBwaW5nKSB7XHJcbiAgICAgIGZyb20gPSBjdXIuY2ggPyBQb3MoY3VyLmxpbmUsIGN1ci5jaCAtIDEpIDogY3VyO1xyXG4gICAgICB0byA9IFBvcyhjdXIubGluZSwgY3VyLmNoICsgMSk7XHJcbiAgICB9XHJcbiAgICBjbS5jdXJPcC5zY3JvbGxUb1BvcyA9IHtmcm9tOiBmcm9tLCB0bzogdG8sIG1hcmdpbjogY20ub3B0aW9ucy5jdXJzb3JTY3JvbGxNYXJnaW4sIGlzQ3Vyc29yOiB0cnVlfTtcclxuICB9XHJcblxyXG4gIC8vIFdoZW4gYW4gb3BlcmF0aW9uIGhhcyBpdHMgc2Nyb2xsVG9Qb3MgcHJvcGVydHkgc2V0LCBhbmQgYW5vdGhlclxyXG4gIC8vIHNjcm9sbCBhY3Rpb24gaXMgYXBwbGllZCBiZWZvcmUgdGhlIGVuZCBvZiB0aGUgb3BlcmF0aW9uLCB0aGlzXHJcbiAgLy8gJ3NpbXVsYXRlcycgc2Nyb2xsaW5nIHRoYXQgcG9zaXRpb24gaW50byB2aWV3IGluIGEgY2hlYXAgd2F5LCBzb1xyXG4gIC8vIHRoYXQgdGhlIGVmZmVjdCBvZiBpbnRlcm1lZGlhdGUgc2Nyb2xsIGNvbW1hbmRzIGlzIG5vdCBpZ25vcmVkLlxyXG4gIGZ1bmN0aW9uIHJlc29sdmVTY3JvbGxUb1BvcyhjbSkge1xyXG4gICAgdmFyIHJhbmdlID0gY20uY3VyT3Auc2Nyb2xsVG9Qb3M7XHJcbiAgICBpZiAocmFuZ2UpIHtcclxuICAgICAgY20uY3VyT3Auc2Nyb2xsVG9Qb3MgPSBudWxsO1xyXG4gICAgICB2YXIgZnJvbSA9IGVzdGltYXRlQ29vcmRzKGNtLCByYW5nZS5mcm9tKSwgdG8gPSBlc3RpbWF0ZUNvb3JkcyhjbSwgcmFuZ2UudG8pO1xyXG4gICAgICB2YXIgc1BvcyA9IGNhbGN1bGF0ZVNjcm9sbFBvcyhjbSwgTWF0aC5taW4oZnJvbS5sZWZ0LCB0by5sZWZ0KSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWF0aC5taW4oZnJvbS50b3AsIHRvLnRvcCkgLSByYW5nZS5tYXJnaW4sXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hdGgubWF4KGZyb20ucmlnaHQsIHRvLnJpZ2h0KSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgTWF0aC5tYXgoZnJvbS5ib3R0b20sIHRvLmJvdHRvbSkgKyByYW5nZS5tYXJnaW4pO1xyXG4gICAgICBjbS5zY3JvbGxUbyhzUG9zLnNjcm9sbExlZnQsIHNQb3Muc2Nyb2xsVG9wKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEFQSSBVVElMSVRJRVNcclxuXHJcbiAgLy8gSW5kZW50IHRoZSBnaXZlbiBsaW5lLiBUaGUgaG93IHBhcmFtZXRlciBjYW4gYmUgXCJzbWFydFwiLFxyXG4gIC8vIFwiYWRkXCIvbnVsbCwgXCJzdWJ0cmFjdFwiLCBvciBcInByZXZcIi4gV2hlbiBhZ2dyZXNzaXZlIGlzIGZhbHNlXHJcbiAgLy8gKHR5cGljYWxseSBzZXQgdG8gdHJ1ZSBmb3IgZm9yY2VkIHNpbmdsZS1saW5lIGluZGVudHMpLCBlbXB0eVxyXG4gIC8vIGxpbmVzIGFyZSBub3QgaW5kZW50ZWQsIGFuZCBwbGFjZXMgd2hlcmUgdGhlIG1vZGUgcmV0dXJucyBQYXNzXHJcbiAgLy8gYXJlIGxlZnQgYWxvbmUuXHJcbiAgZnVuY3Rpb24gaW5kZW50TGluZShjbSwgbiwgaG93LCBhZ2dyZXNzaXZlKSB7XHJcbiAgICB2YXIgZG9jID0gY20uZG9jLCBzdGF0ZTtcclxuICAgIGlmIChob3cgPT0gbnVsbCkgaG93ID0gXCJhZGRcIjtcclxuICAgIGlmIChob3cgPT0gXCJzbWFydFwiKSB7XHJcbiAgICAgIC8vIEZhbGwgYmFjayB0byBcInByZXZcIiB3aGVuIHRoZSBtb2RlIGRvZXNuJ3QgaGF2ZSBhbiBpbmRlbnRhdGlvblxyXG4gICAgICAvLyBtZXRob2QuXHJcbiAgICAgIGlmICghZG9jLm1vZGUuaW5kZW50KSBob3cgPSBcInByZXZcIjtcclxuICAgICAgZWxzZSBzdGF0ZSA9IGdldFN0YXRlQmVmb3JlKGNtLCBuKTtcclxuICAgIH1cclxuXHJcbiAgICB2YXIgdGFiU2l6ZSA9IGNtLm9wdGlvbnMudGFiU2l6ZTtcclxuICAgIHZhciBsaW5lID0gZ2V0TGluZShkb2MsIG4pLCBjdXJTcGFjZSA9IGNvdW50Q29sdW1uKGxpbmUudGV4dCwgbnVsbCwgdGFiU2l6ZSk7XHJcbiAgICBpZiAobGluZS5zdGF0ZUFmdGVyKSBsaW5lLnN0YXRlQWZ0ZXIgPSBudWxsO1xyXG4gICAgdmFyIGN1clNwYWNlU3RyaW5nID0gbGluZS50ZXh0Lm1hdGNoKC9eXFxzKi8pWzBdLCBpbmRlbnRhdGlvbjtcclxuICAgIGlmICghYWdncmVzc2l2ZSAmJiAhL1xcUy8udGVzdChsaW5lLnRleHQpKSB7XHJcbiAgICAgIGluZGVudGF0aW9uID0gMDtcclxuICAgICAgaG93ID0gXCJub3RcIjtcclxuICAgIH0gZWxzZSBpZiAoaG93ID09IFwic21hcnRcIikge1xyXG4gICAgICBpbmRlbnRhdGlvbiA9IGRvYy5tb2RlLmluZGVudChzdGF0ZSwgbGluZS50ZXh0LnNsaWNlKGN1clNwYWNlU3RyaW5nLmxlbmd0aCksIGxpbmUudGV4dCk7XHJcbiAgICAgIGlmIChpbmRlbnRhdGlvbiA9PSBQYXNzIHx8IGluZGVudGF0aW9uID4gMTUwKSB7XHJcbiAgICAgICAgaWYgKCFhZ2dyZXNzaXZlKSByZXR1cm47XHJcbiAgICAgICAgaG93ID0gXCJwcmV2XCI7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGlmIChob3cgPT0gXCJwcmV2XCIpIHtcclxuICAgICAgaWYgKG4gPiBkb2MuZmlyc3QpIGluZGVudGF0aW9uID0gY291bnRDb2x1bW4oZ2V0TGluZShkb2MsIG4tMSkudGV4dCwgbnVsbCwgdGFiU2l6ZSk7XHJcbiAgICAgIGVsc2UgaW5kZW50YXRpb24gPSAwO1xyXG4gICAgfSBlbHNlIGlmIChob3cgPT0gXCJhZGRcIikge1xyXG4gICAgICBpbmRlbnRhdGlvbiA9IGN1clNwYWNlICsgY20ub3B0aW9ucy5pbmRlbnRVbml0O1xyXG4gICAgfSBlbHNlIGlmIChob3cgPT0gXCJzdWJ0cmFjdFwiKSB7XHJcbiAgICAgIGluZGVudGF0aW9uID0gY3VyU3BhY2UgLSBjbS5vcHRpb25zLmluZGVudFVuaXQ7XHJcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBob3cgPT0gXCJudW1iZXJcIikge1xyXG4gICAgICBpbmRlbnRhdGlvbiA9IGN1clNwYWNlICsgaG93O1xyXG4gICAgfVxyXG4gICAgaW5kZW50YXRpb24gPSBNYXRoLm1heCgwLCBpbmRlbnRhdGlvbik7XHJcblxyXG4gICAgdmFyIGluZGVudFN0cmluZyA9IFwiXCIsIHBvcyA9IDA7XHJcbiAgICBpZiAoY20ub3B0aW9ucy5pbmRlbnRXaXRoVGFicylcclxuICAgICAgZm9yICh2YXIgaSA9IE1hdGguZmxvb3IoaW5kZW50YXRpb24gLyB0YWJTaXplKTsgaTsgLS1pKSB7cG9zICs9IHRhYlNpemU7IGluZGVudFN0cmluZyArPSBcIlxcdFwiO31cclxuICAgIGlmIChwb3MgPCBpbmRlbnRhdGlvbikgaW5kZW50U3RyaW5nICs9IHNwYWNlU3RyKGluZGVudGF0aW9uIC0gcG9zKTtcclxuXHJcbiAgICBpZiAoaW5kZW50U3RyaW5nICE9IGN1clNwYWNlU3RyaW5nKSB7XHJcbiAgICAgIHJlcGxhY2VSYW5nZShkb2MsIGluZGVudFN0cmluZywgUG9zKG4sIDApLCBQb3MobiwgY3VyU3BhY2VTdHJpbmcubGVuZ3RoKSwgXCIraW5wdXRcIik7XHJcbiAgICAgIGxpbmUuc3RhdGVBZnRlciA9IG51bGw7XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gRW5zdXJlIHRoYXQsIGlmIHRoZSBjdXJzb3Igd2FzIGluIHRoZSB3aGl0ZXNwYWNlIGF0IHRoZSBzdGFydFxyXG4gICAgICAvLyBvZiB0aGUgbGluZSwgaXQgaXMgbW92ZWQgdG8gdGhlIGVuZCBvZiB0aGF0IHNwYWNlLlxyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGRvYy5zZWwucmFuZ2VzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgdmFyIHJhbmdlID0gZG9jLnNlbC5yYW5nZXNbaV07XHJcbiAgICAgICAgaWYgKHJhbmdlLmhlYWQubGluZSA9PSBuICYmIHJhbmdlLmhlYWQuY2ggPCBjdXJTcGFjZVN0cmluZy5sZW5ndGgpIHtcclxuICAgICAgICAgIHZhciBwb3MgPSBQb3MobiwgY3VyU3BhY2VTdHJpbmcubGVuZ3RoKTtcclxuICAgICAgICAgIHJlcGxhY2VPbmVTZWxlY3Rpb24oZG9jLCBpLCBuZXcgUmFuZ2UocG9zLCBwb3MpKTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gVXRpbGl0eSBmb3IgYXBwbHlpbmcgYSBjaGFuZ2UgdG8gYSBsaW5lIGJ5IGhhbmRsZSBvciBudW1iZXIsXHJcbiAgLy8gcmV0dXJuaW5nIHRoZSBudW1iZXIgYW5kIG9wdGlvbmFsbHkgcmVnaXN0ZXJpbmcgdGhlIGxpbmUgYXNcclxuICAvLyBjaGFuZ2VkLlxyXG4gIGZ1bmN0aW9uIGNoYW5nZUxpbmUoZG9jLCBoYW5kbGUsIGNoYW5nZVR5cGUsIG9wKSB7XHJcbiAgICB2YXIgbm8gPSBoYW5kbGUsIGxpbmUgPSBoYW5kbGU7XHJcbiAgICBpZiAodHlwZW9mIGhhbmRsZSA9PSBcIm51bWJlclwiKSBsaW5lID0gZ2V0TGluZShkb2MsIGNsaXBMaW5lKGRvYywgaGFuZGxlKSk7XHJcbiAgICBlbHNlIG5vID0gbGluZU5vKGhhbmRsZSk7XHJcbiAgICBpZiAobm8gPT0gbnVsbCkgcmV0dXJuIG51bGw7XHJcbiAgICBpZiAob3AobGluZSwgbm8pICYmIGRvYy5jbSkgcmVnTGluZUNoYW5nZShkb2MuY20sIG5vLCBjaGFuZ2VUeXBlKTtcclxuICAgIHJldHVybiBsaW5lO1xyXG4gIH1cclxuXHJcbiAgLy8gSGVscGVyIGZvciBkZWxldGluZyB0ZXh0IG5lYXIgdGhlIHNlbGVjdGlvbihzKSwgdXNlZCB0byBpbXBsZW1lbnRcclxuICAvLyBiYWNrc3BhY2UsIGRlbGV0ZSwgYW5kIHNpbWlsYXIgZnVuY3Rpb25hbGl0eS5cclxuICBmdW5jdGlvbiBkZWxldGVOZWFyU2VsZWN0aW9uKGNtLCBjb21wdXRlKSB7XHJcbiAgICB2YXIgcmFuZ2VzID0gY20uZG9jLnNlbC5yYW5nZXMsIGtpbGwgPSBbXTtcclxuICAgIC8vIEJ1aWxkIHVwIGEgc2V0IG9mIHJhbmdlcyB0byBraWxsIGZpcnN0LCBtZXJnaW5nIG92ZXJsYXBwaW5nXHJcbiAgICAvLyByYW5nZXMuXHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJhbmdlcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICB2YXIgdG9LaWxsID0gY29tcHV0ZShyYW5nZXNbaV0pO1xyXG4gICAgICB3aGlsZSAoa2lsbC5sZW5ndGggJiYgY21wKHRvS2lsbC5mcm9tLCBsc3Qoa2lsbCkudG8pIDw9IDApIHtcclxuICAgICAgICB2YXIgcmVwbGFjZWQgPSBraWxsLnBvcCgpO1xyXG4gICAgICAgIGlmIChjbXAocmVwbGFjZWQuZnJvbSwgdG9LaWxsLmZyb20pIDwgMCkge1xyXG4gICAgICAgICAgdG9LaWxsLmZyb20gPSByZXBsYWNlZC5mcm9tO1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGtpbGwucHVzaCh0b0tpbGwpO1xyXG4gICAgfVxyXG4gICAgLy8gTmV4dCwgcmVtb3ZlIHRob3NlIGFjdHVhbCByYW5nZXMuXHJcbiAgICBydW5Jbk9wKGNtLCBmdW5jdGlvbigpIHtcclxuICAgICAgZm9yICh2YXIgaSA9IGtpbGwubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pXHJcbiAgICAgICAgcmVwbGFjZVJhbmdlKGNtLmRvYywgXCJcIiwga2lsbFtpXS5mcm9tLCBraWxsW2ldLnRvLCBcIitkZWxldGVcIik7XHJcbiAgICAgIGVuc3VyZUN1cnNvclZpc2libGUoY20pO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvLyBVc2VkIGZvciBob3Jpem9udGFsIHJlbGF0aXZlIG1vdGlvbi4gRGlyIGlzIC0xIG9yIDEgKGxlZnQgb3JcclxuICAvLyByaWdodCksIHVuaXQgY2FuIGJlIFwiY2hhclwiLCBcImNvbHVtblwiIChsaWtlIGNoYXIsIGJ1dCBkb2Vzbid0XHJcbiAgLy8gY3Jvc3MgbGluZSBib3VuZGFyaWVzKSwgXCJ3b3JkXCIgKGFjcm9zcyBuZXh0IHdvcmQpLCBvciBcImdyb3VwXCIgKHRvXHJcbiAgLy8gdGhlIHN0YXJ0IG9mIG5leHQgZ3JvdXAgb2Ygd29yZCBvciBub24td29yZC1ub24td2hpdGVzcGFjZVxyXG4gIC8vIGNoYXJzKS4gVGhlIHZpc3VhbGx5IHBhcmFtIGNvbnRyb2xzIHdoZXRoZXIsIGluIHJpZ2h0LXRvLWxlZnRcclxuICAvLyB0ZXh0LCBkaXJlY3Rpb24gMSBtZWFucyB0byBtb3ZlIHRvd2FyZHMgdGhlIG5leHQgaW5kZXggaW4gdGhlXHJcbiAgLy8gc3RyaW5nLCBvciB0b3dhcmRzIHRoZSBjaGFyYWN0ZXIgdG8gdGhlIHJpZ2h0IG9mIHRoZSBjdXJyZW50XHJcbiAgLy8gcG9zaXRpb24uIFRoZSByZXN1bHRpbmcgcG9zaXRpb24gd2lsbCBoYXZlIGEgaGl0U2lkZT10cnVlXHJcbiAgLy8gcHJvcGVydHkgaWYgaXQgcmVhY2hlZCB0aGUgZW5kIG9mIHRoZSBkb2N1bWVudC5cclxuICBmdW5jdGlvbiBmaW5kUG9zSChkb2MsIHBvcywgZGlyLCB1bml0LCB2aXN1YWxseSkge1xyXG4gICAgdmFyIGxpbmUgPSBwb3MubGluZSwgY2ggPSBwb3MuY2gsIG9yaWdEaXIgPSBkaXI7XHJcbiAgICB2YXIgbGluZU9iaiA9IGdldExpbmUoZG9jLCBsaW5lKTtcclxuICAgIHZhciBwb3NzaWJsZSA9IHRydWU7XHJcbiAgICBmdW5jdGlvbiBmaW5kTmV4dExpbmUoKSB7XHJcbiAgICAgIHZhciBsID0gbGluZSArIGRpcjtcclxuICAgICAgaWYgKGwgPCBkb2MuZmlyc3QgfHwgbCA+PSBkb2MuZmlyc3QgKyBkb2Muc2l6ZSkgcmV0dXJuIChwb3NzaWJsZSA9IGZhbHNlKTtcclxuICAgICAgbGluZSA9IGw7XHJcbiAgICAgIHJldHVybiBsaW5lT2JqID0gZ2V0TGluZShkb2MsIGwpO1xyXG4gICAgfVxyXG4gICAgZnVuY3Rpb24gbW92ZU9uY2UoYm91bmRUb0xpbmUpIHtcclxuICAgICAgdmFyIG5leHQgPSAodmlzdWFsbHkgPyBtb3ZlVmlzdWFsbHkgOiBtb3ZlTG9naWNhbGx5KShsaW5lT2JqLCBjaCwgZGlyLCB0cnVlKTtcclxuICAgICAgaWYgKG5leHQgPT0gbnVsbCkge1xyXG4gICAgICAgIGlmICghYm91bmRUb0xpbmUgJiYgZmluZE5leHRMaW5lKCkpIHtcclxuICAgICAgICAgIGlmICh2aXN1YWxseSkgY2ggPSAoZGlyIDwgMCA/IGxpbmVSaWdodCA6IGxpbmVMZWZ0KShsaW5lT2JqKTtcclxuICAgICAgICAgIGVsc2UgY2ggPSBkaXIgPCAwID8gbGluZU9iai50ZXh0Lmxlbmd0aCA6IDA7XHJcbiAgICAgICAgfSBlbHNlIHJldHVybiAocG9zc2libGUgPSBmYWxzZSk7XHJcbiAgICAgIH0gZWxzZSBjaCA9IG5leHQ7XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh1bml0ID09IFwiY2hhclwiKSBtb3ZlT25jZSgpO1xyXG4gICAgZWxzZSBpZiAodW5pdCA9PSBcImNvbHVtblwiKSBtb3ZlT25jZSh0cnVlKTtcclxuICAgIGVsc2UgaWYgKHVuaXQgPT0gXCJ3b3JkXCIgfHwgdW5pdCA9PSBcImdyb3VwXCIpIHtcclxuICAgICAgdmFyIHNhd1R5cGUgPSBudWxsLCBncm91cCA9IHVuaXQgPT0gXCJncm91cFwiO1xyXG4gICAgICB2YXIgaGVscGVyID0gZG9jLmNtICYmIGRvYy5jbS5nZXRIZWxwZXIocG9zLCBcIndvcmRDaGFyc1wiKTtcclxuICAgICAgZm9yICh2YXIgZmlyc3QgPSB0cnVlOzsgZmlyc3QgPSBmYWxzZSkge1xyXG4gICAgICAgIGlmIChkaXIgPCAwICYmICFtb3ZlT25jZSghZmlyc3QpKSBicmVhaztcclxuICAgICAgICB2YXIgY3VyID0gbGluZU9iai50ZXh0LmNoYXJBdChjaCkgfHwgXCJcXG5cIjtcclxuICAgICAgICB2YXIgdHlwZSA9IGlzV29yZENoYXIoY3VyLCBoZWxwZXIpID8gXCJ3XCJcclxuICAgICAgICAgIDogZ3JvdXAgJiYgY3VyID09IFwiXFxuXCIgPyBcIm5cIlxyXG4gICAgICAgICAgOiAhZ3JvdXAgfHwgL1xccy8udGVzdChjdXIpID8gbnVsbFxyXG4gICAgICAgICAgOiBcInBcIjtcclxuICAgICAgICBpZiAoZ3JvdXAgJiYgIWZpcnN0ICYmICF0eXBlKSB0eXBlID0gXCJzXCI7XHJcbiAgICAgICAgaWYgKHNhd1R5cGUgJiYgc2F3VHlwZSAhPSB0eXBlKSB7XHJcbiAgICAgICAgICBpZiAoZGlyIDwgMCkge2RpciA9IDE7IG1vdmVPbmNlKCk7fVxyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodHlwZSkgc2F3VHlwZSA9IHR5cGU7XHJcbiAgICAgICAgaWYgKGRpciA+IDAgJiYgIW1vdmVPbmNlKCFmaXJzdCkpIGJyZWFrO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICB2YXIgcmVzdWx0ID0gc2tpcEF0b21pYyhkb2MsIFBvcyhsaW5lLCBjaCksIHBvcywgb3JpZ0RpciwgdHJ1ZSk7XHJcbiAgICBpZiAoIXBvc3NpYmxlKSByZXN1bHQuaGl0U2lkZSA9IHRydWU7XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH1cclxuXHJcbiAgLy8gRm9yIHJlbGF0aXZlIHZlcnRpY2FsIG1vdmVtZW50LiBEaXIgbWF5IGJlIC0xIG9yIDEuIFVuaXQgY2FuIGJlXHJcbiAgLy8gXCJwYWdlXCIgb3IgXCJsaW5lXCIuIFRoZSByZXN1bHRpbmcgcG9zaXRpb24gd2lsbCBoYXZlIGEgaGl0U2lkZT10cnVlXHJcbiAgLy8gcHJvcGVydHkgaWYgaXQgcmVhY2hlZCB0aGUgZW5kIG9mIHRoZSBkb2N1bWVudC5cclxuICBmdW5jdGlvbiBmaW5kUG9zVihjbSwgcG9zLCBkaXIsIHVuaXQpIHtcclxuICAgIHZhciBkb2MgPSBjbS5kb2MsIHggPSBwb3MubGVmdCwgeTtcclxuICAgIGlmICh1bml0ID09IFwicGFnZVwiKSB7XHJcbiAgICAgIHZhciBwYWdlU2l6ZSA9IE1hdGgubWluKGNtLmRpc3BsYXkud3JhcHBlci5jbGllbnRIZWlnaHQsIHdpbmRvdy5pbm5lckhlaWdodCB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50SGVpZ2h0KTtcclxuICAgICAgeSA9IHBvcy50b3AgKyBkaXIgKiAocGFnZVNpemUgLSAoZGlyIDwgMCA/IDEuNSA6IC41KSAqIHRleHRIZWlnaHQoY20uZGlzcGxheSkpO1xyXG4gICAgfSBlbHNlIGlmICh1bml0ID09IFwibGluZVwiKSB7XHJcbiAgICAgIHkgPSBkaXIgPiAwID8gcG9zLmJvdHRvbSArIDMgOiBwb3MudG9wIC0gMztcclxuICAgIH1cclxuICAgIGZvciAoOzspIHtcclxuICAgICAgdmFyIHRhcmdldCA9IGNvb3Jkc0NoYXIoY20sIHgsIHkpO1xyXG4gICAgICBpZiAoIXRhcmdldC5vdXRzaWRlKSBicmVhaztcclxuICAgICAgaWYgKGRpciA8IDAgPyB5IDw9IDAgOiB5ID49IGRvYy5oZWlnaHQpIHsgdGFyZ2V0LmhpdFNpZGUgPSB0cnVlOyBicmVhazsgfVxyXG4gICAgICB5ICs9IGRpciAqIDU7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGFyZ2V0O1xyXG4gIH1cclxuXHJcbiAgLy8gRURJVE9SIE1FVEhPRFNcclxuXHJcbiAgLy8gVGhlIHB1YmxpY2x5IHZpc2libGUgQVBJLiBOb3RlIHRoYXQgbWV0aG9kT3AoZikgbWVhbnNcclxuICAvLyAnd3JhcCBmIGluIGFuIG9wZXJhdGlvbiwgcGVyZm9ybWVkIG9uIGl0cyBgdGhpc2AgcGFyYW1ldGVyJy5cclxuXHJcbiAgLy8gVGhpcyBpcyBub3QgdGhlIGNvbXBsZXRlIHNldCBvZiBlZGl0b3IgbWV0aG9kcy4gTW9zdCBvZiB0aGVcclxuICAvLyBtZXRob2RzIGRlZmluZWQgb24gdGhlIERvYyB0eXBlIGFyZSBhbHNvIGluamVjdGVkIGludG9cclxuICAvLyBDb2RlTWlycm9yLnByb3RvdHlwZSwgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IGFuZFxyXG4gIC8vIGNvbnZlbmllbmNlLlxyXG5cclxuICBDb2RlTWlycm9yLnByb3RvdHlwZSA9IHtcclxuICAgIGNvbnN0cnVjdG9yOiBDb2RlTWlycm9yLFxyXG4gICAgZm9jdXM6IGZ1bmN0aW9uKCl7d2luZG93LmZvY3VzKCk7IHRoaXMuZGlzcGxheS5pbnB1dC5mb2N1cygpO30sXHJcblxyXG4gICAgc2V0T3B0aW9uOiBmdW5jdGlvbihvcHRpb24sIHZhbHVlKSB7XHJcbiAgICAgIHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zLCBvbGQgPSBvcHRpb25zW29wdGlvbl07XHJcbiAgICAgIGlmIChvcHRpb25zW29wdGlvbl0gPT0gdmFsdWUgJiYgb3B0aW9uICE9IFwibW9kZVwiKSByZXR1cm47XHJcbiAgICAgIG9wdGlvbnNbb3B0aW9uXSA9IHZhbHVlO1xyXG4gICAgICBpZiAob3B0aW9uSGFuZGxlcnMuaGFzT3duUHJvcGVydHkob3B0aW9uKSlcclxuICAgICAgICBvcGVyYXRpb24odGhpcywgb3B0aW9uSGFuZGxlcnNbb3B0aW9uXSkodGhpcywgdmFsdWUsIG9sZCk7XHJcbiAgICB9LFxyXG5cclxuICAgIGdldE9wdGlvbjogZnVuY3Rpb24ob3B0aW9uKSB7cmV0dXJuIHRoaXMub3B0aW9uc1tvcHRpb25dO30sXHJcbiAgICBnZXREb2M6IGZ1bmN0aW9uKCkge3JldHVybiB0aGlzLmRvYzt9LFxyXG5cclxuICAgIGFkZEtleU1hcDogZnVuY3Rpb24obWFwLCBib3R0b20pIHtcclxuICAgICAgdGhpcy5zdGF0ZS5rZXlNYXBzW2JvdHRvbSA/IFwicHVzaFwiIDogXCJ1bnNoaWZ0XCJdKGdldEtleU1hcChtYXApKTtcclxuICAgIH0sXHJcbiAgICByZW1vdmVLZXlNYXA6IGZ1bmN0aW9uKG1hcCkge1xyXG4gICAgICB2YXIgbWFwcyA9IHRoaXMuc3RhdGUua2V5TWFwcztcclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtYXBzLmxlbmd0aDsgKytpKVxyXG4gICAgICAgIGlmIChtYXBzW2ldID09IG1hcCB8fCBtYXBzW2ldLm5hbWUgPT0gbWFwKSB7XHJcbiAgICAgICAgICBtYXBzLnNwbGljZShpLCAxKTtcclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgIH0sXHJcblxyXG4gICAgYWRkT3ZlcmxheTogbWV0aG9kT3AoZnVuY3Rpb24oc3BlYywgb3B0aW9ucykge1xyXG4gICAgICB2YXIgbW9kZSA9IHNwZWMudG9rZW4gPyBzcGVjIDogQ29kZU1pcnJvci5nZXRNb2RlKHRoaXMub3B0aW9ucywgc3BlYyk7XHJcbiAgICAgIGlmIChtb2RlLnN0YXJ0U3RhdGUpIHRocm93IG5ldyBFcnJvcihcIk92ZXJsYXlzIG1heSBub3QgYmUgc3RhdGVmdWwuXCIpO1xyXG4gICAgICB0aGlzLnN0YXRlLm92ZXJsYXlzLnB1c2goe21vZGU6IG1vZGUsIG1vZGVTcGVjOiBzcGVjLCBvcGFxdWU6IG9wdGlvbnMgJiYgb3B0aW9ucy5vcGFxdWV9KTtcclxuICAgICAgdGhpcy5zdGF0ZS5tb2RlR2VuKys7XHJcbiAgICAgIHJlZ0NoYW5nZSh0aGlzKTtcclxuICAgIH0pLFxyXG4gICAgcmVtb3ZlT3ZlcmxheTogbWV0aG9kT3AoZnVuY3Rpb24oc3BlYykge1xyXG4gICAgICB2YXIgb3ZlcmxheXMgPSB0aGlzLnN0YXRlLm92ZXJsYXlzO1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG92ZXJsYXlzLmxlbmd0aDsgKytpKSB7XHJcbiAgICAgICAgdmFyIGN1ciA9IG92ZXJsYXlzW2ldLm1vZGVTcGVjO1xyXG4gICAgICAgIGlmIChjdXIgPT0gc3BlYyB8fCB0eXBlb2Ygc3BlYyA9PSBcInN0cmluZ1wiICYmIGN1ci5uYW1lID09IHNwZWMpIHtcclxuICAgICAgICAgIG92ZXJsYXlzLnNwbGljZShpLCAxKTtcclxuICAgICAgICAgIHRoaXMuc3RhdGUubW9kZUdlbisrO1xyXG4gICAgICAgICAgcmVnQ2hhbmdlKHRoaXMpO1xyXG4gICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSksXHJcblxyXG4gICAgaW5kZW50TGluZTogbWV0aG9kT3AoZnVuY3Rpb24obiwgZGlyLCBhZ2dyZXNzaXZlKSB7XHJcbiAgICAgIGlmICh0eXBlb2YgZGlyICE9IFwic3RyaW5nXCIgJiYgdHlwZW9mIGRpciAhPSBcIm51bWJlclwiKSB7XHJcbiAgICAgICAgaWYgKGRpciA9PSBudWxsKSBkaXIgPSB0aGlzLm9wdGlvbnMuc21hcnRJbmRlbnQgPyBcInNtYXJ0XCIgOiBcInByZXZcIjtcclxuICAgICAgICBlbHNlIGRpciA9IGRpciA/IFwiYWRkXCIgOiBcInN1YnRyYWN0XCI7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKGlzTGluZSh0aGlzLmRvYywgbikpIGluZGVudExpbmUodGhpcywgbiwgZGlyLCBhZ2dyZXNzaXZlKTtcclxuICAgIH0pLFxyXG4gICAgaW5kZW50U2VsZWN0aW9uOiBtZXRob2RPcChmdW5jdGlvbihob3cpIHtcclxuICAgICAgdmFyIHJhbmdlcyA9IHRoaXMuZG9jLnNlbC5yYW5nZXMsIGVuZCA9IC0xO1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJhbmdlcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIHZhciByYW5nZSA9IHJhbmdlc1tpXTtcclxuICAgICAgICBpZiAoIXJhbmdlLmVtcHR5KCkpIHtcclxuICAgICAgICAgIHZhciBmcm9tID0gcmFuZ2UuZnJvbSgpLCB0byA9IHJhbmdlLnRvKCk7XHJcbiAgICAgICAgICB2YXIgc3RhcnQgPSBNYXRoLm1heChlbmQsIGZyb20ubGluZSk7XHJcbiAgICAgICAgICBlbmQgPSBNYXRoLm1pbih0aGlzLmxhc3RMaW5lKCksIHRvLmxpbmUgLSAodG8uY2ggPyAwIDogMSkpICsgMTtcclxuICAgICAgICAgIGZvciAodmFyIGogPSBzdGFydDsgaiA8IGVuZDsgKytqKVxyXG4gICAgICAgICAgICBpbmRlbnRMaW5lKHRoaXMsIGosIGhvdyk7XHJcbiAgICAgICAgICB2YXIgbmV3UmFuZ2VzID0gdGhpcy5kb2Muc2VsLnJhbmdlcztcclxuICAgICAgICAgIGlmIChmcm9tLmNoID09IDAgJiYgcmFuZ2VzLmxlbmd0aCA9PSBuZXdSYW5nZXMubGVuZ3RoICYmIG5ld1Jhbmdlc1tpXS5mcm9tKCkuY2ggPiAwKVxyXG4gICAgICAgICAgICByZXBsYWNlT25lU2VsZWN0aW9uKHRoaXMuZG9jLCBpLCBuZXcgUmFuZ2UoZnJvbSwgbmV3UmFuZ2VzW2ldLnRvKCkpLCBzZWxfZG9udFNjcm9sbCk7XHJcbiAgICAgICAgfSBlbHNlIGlmIChyYW5nZS5oZWFkLmxpbmUgPiBlbmQpIHtcclxuICAgICAgICAgIGluZGVudExpbmUodGhpcywgcmFuZ2UuaGVhZC5saW5lLCBob3csIHRydWUpO1xyXG4gICAgICAgICAgZW5kID0gcmFuZ2UuaGVhZC5saW5lO1xyXG4gICAgICAgICAgaWYgKGkgPT0gdGhpcy5kb2Muc2VsLnByaW1JbmRleCkgZW5zdXJlQ3Vyc29yVmlzaWJsZSh0aGlzKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pLFxyXG5cclxuICAgIC8vIEZldGNoIHRoZSBwYXJzZXIgdG9rZW4gZm9yIGEgZ2l2ZW4gY2hhcmFjdGVyLiBVc2VmdWwgZm9yIGhhY2tzXHJcbiAgICAvLyB0aGF0IHdhbnQgdG8gaW5zcGVjdCB0aGUgbW9kZSBzdGF0ZSAoc2F5LCBmb3IgY29tcGxldGlvbikuXHJcbiAgICBnZXRUb2tlbkF0OiBmdW5jdGlvbihwb3MsIHByZWNpc2UpIHtcclxuICAgICAgcmV0dXJuIHRha2VUb2tlbih0aGlzLCBwb3MsIHByZWNpc2UpO1xyXG4gICAgfSxcclxuXHJcbiAgICBnZXRMaW5lVG9rZW5zOiBmdW5jdGlvbihsaW5lLCBwcmVjaXNlKSB7XHJcbiAgICAgIHJldHVybiB0YWtlVG9rZW4odGhpcywgUG9zKGxpbmUpLCBwcmVjaXNlLCB0cnVlKTtcclxuICAgIH0sXHJcblxyXG4gICAgZ2V0VG9rZW5UeXBlQXQ6IGZ1bmN0aW9uKHBvcykge1xyXG4gICAgICBwb3MgPSBjbGlwUG9zKHRoaXMuZG9jLCBwb3MpO1xyXG4gICAgICB2YXIgc3R5bGVzID0gZ2V0TGluZVN0eWxlcyh0aGlzLCBnZXRMaW5lKHRoaXMuZG9jLCBwb3MubGluZSkpO1xyXG4gICAgICB2YXIgYmVmb3JlID0gMCwgYWZ0ZXIgPSAoc3R5bGVzLmxlbmd0aCAtIDEpIC8gMiwgY2ggPSBwb3MuY2g7XHJcbiAgICAgIHZhciB0eXBlO1xyXG4gICAgICBpZiAoY2ggPT0gMCkgdHlwZSA9IHN0eWxlc1syXTtcclxuICAgICAgZWxzZSBmb3IgKDs7KSB7XHJcbiAgICAgICAgdmFyIG1pZCA9IChiZWZvcmUgKyBhZnRlcikgPj4gMTtcclxuICAgICAgICBpZiAoKG1pZCA/IHN0eWxlc1ttaWQgKiAyIC0gMV0gOiAwKSA+PSBjaCkgYWZ0ZXIgPSBtaWQ7XHJcbiAgICAgICAgZWxzZSBpZiAoc3R5bGVzW21pZCAqIDIgKyAxXSA8IGNoKSBiZWZvcmUgPSBtaWQgKyAxO1xyXG4gICAgICAgIGVsc2UgeyB0eXBlID0gc3R5bGVzW21pZCAqIDIgKyAyXTsgYnJlYWs7IH1cclxuICAgICAgfVxyXG4gICAgICB2YXIgY3V0ID0gdHlwZSA/IHR5cGUuaW5kZXhPZihcImNtLW92ZXJsYXkgXCIpIDogLTE7XHJcbiAgICAgIHJldHVybiBjdXQgPCAwID8gdHlwZSA6IGN1dCA9PSAwID8gbnVsbCA6IHR5cGUuc2xpY2UoMCwgY3V0IC0gMSk7XHJcbiAgICB9LFxyXG5cclxuICAgIGdldE1vZGVBdDogZnVuY3Rpb24ocG9zKSB7XHJcbiAgICAgIHZhciBtb2RlID0gdGhpcy5kb2MubW9kZTtcclxuICAgICAgaWYgKCFtb2RlLmlubmVyTW9kZSkgcmV0dXJuIG1vZGU7XHJcbiAgICAgIHJldHVybiBDb2RlTWlycm9yLmlubmVyTW9kZShtb2RlLCB0aGlzLmdldFRva2VuQXQocG9zKS5zdGF0ZSkubW9kZTtcclxuICAgIH0sXHJcblxyXG4gICAgZ2V0SGVscGVyOiBmdW5jdGlvbihwb3MsIHR5cGUpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuZ2V0SGVscGVycyhwb3MsIHR5cGUpWzBdO1xyXG4gICAgfSxcclxuXHJcbiAgICBnZXRIZWxwZXJzOiBmdW5jdGlvbihwb3MsIHR5cGUpIHtcclxuICAgICAgdmFyIGZvdW5kID0gW107XHJcbiAgICAgIGlmICghaGVscGVycy5oYXNPd25Qcm9wZXJ0eSh0eXBlKSkgcmV0dXJuIGZvdW5kO1xyXG4gICAgICB2YXIgaGVscCA9IGhlbHBlcnNbdHlwZV0sIG1vZGUgPSB0aGlzLmdldE1vZGVBdChwb3MpO1xyXG4gICAgICBpZiAodHlwZW9mIG1vZGVbdHlwZV0gPT0gXCJzdHJpbmdcIikge1xyXG4gICAgICAgIGlmIChoZWxwW21vZGVbdHlwZV1dKSBmb3VuZC5wdXNoKGhlbHBbbW9kZVt0eXBlXV0pO1xyXG4gICAgICB9IGVsc2UgaWYgKG1vZGVbdHlwZV0pIHtcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG1vZGVbdHlwZV0ubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgIHZhciB2YWwgPSBoZWxwW21vZGVbdHlwZV1baV1dO1xyXG4gICAgICAgICAgaWYgKHZhbCkgZm91bmQucHVzaCh2YWwpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIGlmIChtb2RlLmhlbHBlclR5cGUgJiYgaGVscFttb2RlLmhlbHBlclR5cGVdKSB7XHJcbiAgICAgICAgZm91bmQucHVzaChoZWxwW21vZGUuaGVscGVyVHlwZV0pO1xyXG4gICAgICB9IGVsc2UgaWYgKGhlbHBbbW9kZS5uYW1lXSkge1xyXG4gICAgICAgIGZvdW5kLnB1c2goaGVscFttb2RlLm5hbWVdKTtcclxuICAgICAgfVxyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGhlbHAuX2dsb2JhbC5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIHZhciBjdXIgPSBoZWxwLl9nbG9iYWxbaV07XHJcbiAgICAgICAgaWYgKGN1ci5wcmVkKG1vZGUsIHRoaXMpICYmIGluZGV4T2YoZm91bmQsIGN1ci52YWwpID09IC0xKVxyXG4gICAgICAgICAgZm91bmQucHVzaChjdXIudmFsKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gZm91bmQ7XHJcbiAgICB9LFxyXG5cclxuICAgIGdldFN0YXRlQWZ0ZXI6IGZ1bmN0aW9uKGxpbmUsIHByZWNpc2UpIHtcclxuICAgICAgdmFyIGRvYyA9IHRoaXMuZG9jO1xyXG4gICAgICBsaW5lID0gY2xpcExpbmUoZG9jLCBsaW5lID09IG51bGwgPyBkb2MuZmlyc3QgKyBkb2Muc2l6ZSAtIDE6IGxpbmUpO1xyXG4gICAgICByZXR1cm4gZ2V0U3RhdGVCZWZvcmUodGhpcywgbGluZSArIDEsIHByZWNpc2UpO1xyXG4gICAgfSxcclxuXHJcbiAgICBjdXJzb3JDb29yZHM6IGZ1bmN0aW9uKHN0YXJ0LCBtb2RlKSB7XHJcbiAgICAgIHZhciBwb3MsIHJhbmdlID0gdGhpcy5kb2Muc2VsLnByaW1hcnkoKTtcclxuICAgICAgaWYgKHN0YXJ0ID09IG51bGwpIHBvcyA9IHJhbmdlLmhlYWQ7XHJcbiAgICAgIGVsc2UgaWYgKHR5cGVvZiBzdGFydCA9PSBcIm9iamVjdFwiKSBwb3MgPSBjbGlwUG9zKHRoaXMuZG9jLCBzdGFydCk7XHJcbiAgICAgIGVsc2UgcG9zID0gc3RhcnQgPyByYW5nZS5mcm9tKCkgOiByYW5nZS50bygpO1xyXG4gICAgICByZXR1cm4gY3Vyc29yQ29vcmRzKHRoaXMsIHBvcywgbW9kZSB8fCBcInBhZ2VcIik7XHJcbiAgICB9LFxyXG5cclxuICAgIGNoYXJDb29yZHM6IGZ1bmN0aW9uKHBvcywgbW9kZSkge1xyXG4gICAgICByZXR1cm4gY2hhckNvb3Jkcyh0aGlzLCBjbGlwUG9zKHRoaXMuZG9jLCBwb3MpLCBtb2RlIHx8IFwicGFnZVwiKTtcclxuICAgIH0sXHJcblxyXG4gICAgY29vcmRzQ2hhcjogZnVuY3Rpb24oY29vcmRzLCBtb2RlKSB7XHJcbiAgICAgIGNvb3JkcyA9IGZyb21Db29yZFN5c3RlbSh0aGlzLCBjb29yZHMsIG1vZGUgfHwgXCJwYWdlXCIpO1xyXG4gICAgICByZXR1cm4gY29vcmRzQ2hhcih0aGlzLCBjb29yZHMubGVmdCwgY29vcmRzLnRvcCk7XHJcbiAgICB9LFxyXG5cclxuICAgIGxpbmVBdEhlaWdodDogZnVuY3Rpb24oaGVpZ2h0LCBtb2RlKSB7XHJcbiAgICAgIGhlaWdodCA9IGZyb21Db29yZFN5c3RlbSh0aGlzLCB7dG9wOiBoZWlnaHQsIGxlZnQ6IDB9LCBtb2RlIHx8IFwicGFnZVwiKS50b3A7XHJcbiAgICAgIHJldHVybiBsaW5lQXRIZWlnaHQodGhpcy5kb2MsIGhlaWdodCArIHRoaXMuZGlzcGxheS52aWV3T2Zmc2V0KTtcclxuICAgIH0sXHJcbiAgICBoZWlnaHRBdExpbmU6IGZ1bmN0aW9uKGxpbmUsIG1vZGUpIHtcclxuICAgICAgdmFyIGVuZCA9IGZhbHNlLCBsaW5lT2JqO1xyXG4gICAgICBpZiAodHlwZW9mIGxpbmUgPT0gXCJudW1iZXJcIikge1xyXG4gICAgICAgIHZhciBsYXN0ID0gdGhpcy5kb2MuZmlyc3QgKyB0aGlzLmRvYy5zaXplIC0gMTtcclxuICAgICAgICBpZiAobGluZSA8IHRoaXMuZG9jLmZpcnN0KSBsaW5lID0gdGhpcy5kb2MuZmlyc3Q7XHJcbiAgICAgICAgZWxzZSBpZiAobGluZSA+IGxhc3QpIHsgbGluZSA9IGxhc3Q7IGVuZCA9IHRydWU7IH1cclxuICAgICAgICBsaW5lT2JqID0gZ2V0TGluZSh0aGlzLmRvYywgbGluZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGluZU9iaiA9IGxpbmU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGludG9Db29yZFN5c3RlbSh0aGlzLCBsaW5lT2JqLCB7dG9wOiAwLCBsZWZ0OiAwfSwgbW9kZSB8fCBcInBhZ2VcIikudG9wICtcclxuICAgICAgICAoZW5kID8gdGhpcy5kb2MuaGVpZ2h0IC0gaGVpZ2h0QXRMaW5lKGxpbmVPYmopIDogMCk7XHJcbiAgICB9LFxyXG5cclxuICAgIGRlZmF1bHRUZXh0SGVpZ2h0OiBmdW5jdGlvbigpIHsgcmV0dXJuIHRleHRIZWlnaHQodGhpcy5kaXNwbGF5KTsgfSxcclxuICAgIGRlZmF1bHRDaGFyV2lkdGg6IGZ1bmN0aW9uKCkgeyByZXR1cm4gY2hhcldpZHRoKHRoaXMuZGlzcGxheSk7IH0sXHJcblxyXG4gICAgc2V0R3V0dGVyTWFya2VyOiBtZXRob2RPcChmdW5jdGlvbihsaW5lLCBndXR0ZXJJRCwgdmFsdWUpIHtcclxuICAgICAgcmV0dXJuIGNoYW5nZUxpbmUodGhpcy5kb2MsIGxpbmUsIFwiZ3V0dGVyXCIsIGZ1bmN0aW9uKGxpbmUpIHtcclxuICAgICAgICB2YXIgbWFya2VycyA9IGxpbmUuZ3V0dGVyTWFya2VycyB8fCAobGluZS5ndXR0ZXJNYXJrZXJzID0ge30pO1xyXG4gICAgICAgIG1hcmtlcnNbZ3V0dGVySURdID0gdmFsdWU7XHJcbiAgICAgICAgaWYgKCF2YWx1ZSAmJiBpc0VtcHR5KG1hcmtlcnMpKSBsaW5lLmd1dHRlck1hcmtlcnMgPSBudWxsO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH0pLFxyXG5cclxuICAgIGNsZWFyR3V0dGVyOiBtZXRob2RPcChmdW5jdGlvbihndXR0ZXJJRCkge1xyXG4gICAgICB2YXIgY20gPSB0aGlzLCBkb2MgPSBjbS5kb2MsIGkgPSBkb2MuZmlyc3Q7XHJcbiAgICAgIGRvYy5pdGVyKGZ1bmN0aW9uKGxpbmUpIHtcclxuICAgICAgICBpZiAobGluZS5ndXR0ZXJNYXJrZXJzICYmIGxpbmUuZ3V0dGVyTWFya2Vyc1tndXR0ZXJJRF0pIHtcclxuICAgICAgICAgIGxpbmUuZ3V0dGVyTWFya2Vyc1tndXR0ZXJJRF0gPSBudWxsO1xyXG4gICAgICAgICAgcmVnTGluZUNoYW5nZShjbSwgaSwgXCJndXR0ZXJcIik7XHJcbiAgICAgICAgICBpZiAoaXNFbXB0eShsaW5lLmd1dHRlck1hcmtlcnMpKSBsaW5lLmd1dHRlck1hcmtlcnMgPSBudWxsO1xyXG4gICAgICAgIH1cclxuICAgICAgICArK2k7XHJcbiAgICAgIH0pO1xyXG4gICAgfSksXHJcblxyXG4gICAgbGluZUluZm86IGZ1bmN0aW9uKGxpbmUpIHtcclxuICAgICAgaWYgKHR5cGVvZiBsaW5lID09IFwibnVtYmVyXCIpIHtcclxuICAgICAgICBpZiAoIWlzTGluZSh0aGlzLmRvYywgbGluZSkpIHJldHVybiBudWxsO1xyXG4gICAgICAgIHZhciBuID0gbGluZTtcclxuICAgICAgICBsaW5lID0gZ2V0TGluZSh0aGlzLmRvYywgbGluZSk7XHJcbiAgICAgICAgaWYgKCFsaW5lKSByZXR1cm4gbnVsbDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB2YXIgbiA9IGxpbmVObyhsaW5lKTtcclxuICAgICAgICBpZiAobiA9PSBudWxsKSByZXR1cm4gbnVsbDtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4ge2xpbmU6IG4sIGhhbmRsZTogbGluZSwgdGV4dDogbGluZS50ZXh0LCBndXR0ZXJNYXJrZXJzOiBsaW5lLmd1dHRlck1hcmtlcnMsXHJcbiAgICAgICAgICAgICAgdGV4dENsYXNzOiBsaW5lLnRleHRDbGFzcywgYmdDbGFzczogbGluZS5iZ0NsYXNzLCB3cmFwQ2xhc3M6IGxpbmUud3JhcENsYXNzLFxyXG4gICAgICAgICAgICAgIHdpZGdldHM6IGxpbmUud2lkZ2V0c307XHJcbiAgICB9LFxyXG5cclxuICAgIGdldFZpZXdwb3J0OiBmdW5jdGlvbigpIHsgcmV0dXJuIHtmcm9tOiB0aGlzLmRpc3BsYXkudmlld0Zyb20sIHRvOiB0aGlzLmRpc3BsYXkudmlld1RvfTt9LFxyXG5cclxuICAgIGFkZFdpZGdldDogZnVuY3Rpb24ocG9zLCBub2RlLCBzY3JvbGwsIHZlcnQsIGhvcml6KSB7XHJcbiAgICAgIHZhciBkaXNwbGF5ID0gdGhpcy5kaXNwbGF5O1xyXG4gICAgICBwb3MgPSBjdXJzb3JDb29yZHModGhpcywgY2xpcFBvcyh0aGlzLmRvYywgcG9zKSk7XHJcbiAgICAgIHZhciB0b3AgPSBwb3MuYm90dG9tLCBsZWZ0ID0gcG9zLmxlZnQ7XHJcbiAgICAgIG5vZGUuc3R5bGUucG9zaXRpb24gPSBcImFic29sdXRlXCI7XHJcbiAgICAgIG5vZGUuc2V0QXR0cmlidXRlKFwiY20taWdub3JlLWV2ZW50c1wiLCBcInRydWVcIik7XHJcbiAgICAgIHRoaXMuZGlzcGxheS5pbnB1dC5zZXRVbmVkaXRhYmxlKG5vZGUpO1xyXG4gICAgICBkaXNwbGF5LnNpemVyLmFwcGVuZENoaWxkKG5vZGUpO1xyXG4gICAgICBpZiAodmVydCA9PSBcIm92ZXJcIikge1xyXG4gICAgICAgIHRvcCA9IHBvcy50b3A7XHJcbiAgICAgIH0gZWxzZSBpZiAodmVydCA9PSBcImFib3ZlXCIgfHwgdmVydCA9PSBcIm5lYXJcIikge1xyXG4gICAgICAgIHZhciB2c3BhY2UgPSBNYXRoLm1heChkaXNwbGF5LndyYXBwZXIuY2xpZW50SGVpZ2h0LCB0aGlzLmRvYy5oZWlnaHQpLFxyXG4gICAgICAgIGhzcGFjZSA9IE1hdGgubWF4KGRpc3BsYXkuc2l6ZXIuY2xpZW50V2lkdGgsIGRpc3BsYXkubGluZVNwYWNlLmNsaWVudFdpZHRoKTtcclxuICAgICAgICAvLyBEZWZhdWx0IHRvIHBvc2l0aW9uaW5nIGFib3ZlIChpZiBzcGVjaWZpZWQgYW5kIHBvc3NpYmxlKTsgb3RoZXJ3aXNlIGRlZmF1bHQgdG8gcG9zaXRpb25pbmcgYmVsb3dcclxuICAgICAgICBpZiAoKHZlcnQgPT0gJ2Fib3ZlJyB8fCBwb3MuYm90dG9tICsgbm9kZS5vZmZzZXRIZWlnaHQgPiB2c3BhY2UpICYmIHBvcy50b3AgPiBub2RlLm9mZnNldEhlaWdodClcclxuICAgICAgICAgIHRvcCA9IHBvcy50b3AgLSBub2RlLm9mZnNldEhlaWdodDtcclxuICAgICAgICBlbHNlIGlmIChwb3MuYm90dG9tICsgbm9kZS5vZmZzZXRIZWlnaHQgPD0gdnNwYWNlKVxyXG4gICAgICAgICAgdG9wID0gcG9zLmJvdHRvbTtcclxuICAgICAgICBpZiAobGVmdCArIG5vZGUub2Zmc2V0V2lkdGggPiBoc3BhY2UpXHJcbiAgICAgICAgICBsZWZ0ID0gaHNwYWNlIC0gbm9kZS5vZmZzZXRXaWR0aDtcclxuICAgICAgfVxyXG4gICAgICBub2RlLnN0eWxlLnRvcCA9IHRvcCArIFwicHhcIjtcclxuICAgICAgbm9kZS5zdHlsZS5sZWZ0ID0gbm9kZS5zdHlsZS5yaWdodCA9IFwiXCI7XHJcbiAgICAgIGlmIChob3JpeiA9PSBcInJpZ2h0XCIpIHtcclxuICAgICAgICBsZWZ0ID0gZGlzcGxheS5zaXplci5jbGllbnRXaWR0aCAtIG5vZGUub2Zmc2V0V2lkdGg7XHJcbiAgICAgICAgbm9kZS5zdHlsZS5yaWdodCA9IFwiMHB4XCI7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgaWYgKGhvcml6ID09IFwibGVmdFwiKSBsZWZ0ID0gMDtcclxuICAgICAgICBlbHNlIGlmIChob3JpeiA9PSBcIm1pZGRsZVwiKSBsZWZ0ID0gKGRpc3BsYXkuc2l6ZXIuY2xpZW50V2lkdGggLSBub2RlLm9mZnNldFdpZHRoKSAvIDI7XHJcbiAgICAgICAgbm9kZS5zdHlsZS5sZWZ0ID0gbGVmdCArIFwicHhcIjtcclxuICAgICAgfVxyXG4gICAgICBpZiAoc2Nyb2xsKVxyXG4gICAgICAgIHNjcm9sbEludG9WaWV3KHRoaXMsIGxlZnQsIHRvcCwgbGVmdCArIG5vZGUub2Zmc2V0V2lkdGgsIHRvcCArIG5vZGUub2Zmc2V0SGVpZ2h0KTtcclxuICAgIH0sXHJcblxyXG4gICAgdHJpZ2dlck9uS2V5RG93bjogbWV0aG9kT3Aob25LZXlEb3duKSxcclxuICAgIHRyaWdnZXJPbktleVByZXNzOiBtZXRob2RPcChvbktleVByZXNzKSxcclxuICAgIHRyaWdnZXJPbktleVVwOiBvbktleVVwLFxyXG5cclxuICAgIGV4ZWNDb21tYW5kOiBmdW5jdGlvbihjbWQpIHtcclxuICAgICAgaWYgKGNvbW1hbmRzLmhhc093blByb3BlcnR5KGNtZCkpXHJcbiAgICAgICAgcmV0dXJuIGNvbW1hbmRzW2NtZF0uY2FsbChudWxsLCB0aGlzKTtcclxuICAgIH0sXHJcblxyXG4gICAgdHJpZ2dlckVsZWN0cmljOiBtZXRob2RPcChmdW5jdGlvbih0ZXh0KSB7IHRyaWdnZXJFbGVjdHJpYyh0aGlzLCB0ZXh0KTsgfSksXHJcblxyXG4gICAgZmluZFBvc0g6IGZ1bmN0aW9uKGZyb20sIGFtb3VudCwgdW5pdCwgdmlzdWFsbHkpIHtcclxuICAgICAgdmFyIGRpciA9IDE7XHJcbiAgICAgIGlmIChhbW91bnQgPCAwKSB7IGRpciA9IC0xOyBhbW91bnQgPSAtYW1vdW50OyB9XHJcbiAgICAgIGZvciAodmFyIGkgPSAwLCBjdXIgPSBjbGlwUG9zKHRoaXMuZG9jLCBmcm9tKTsgaSA8IGFtb3VudDsgKytpKSB7XHJcbiAgICAgICAgY3VyID0gZmluZFBvc0godGhpcy5kb2MsIGN1ciwgZGlyLCB1bml0LCB2aXN1YWxseSk7XHJcbiAgICAgICAgaWYgKGN1ci5oaXRTaWRlKSBicmVhaztcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gY3VyO1xyXG4gICAgfSxcclxuXHJcbiAgICBtb3ZlSDogbWV0aG9kT3AoZnVuY3Rpb24oZGlyLCB1bml0KSB7XHJcbiAgICAgIHZhciBjbSA9IHRoaXM7XHJcbiAgICAgIGNtLmV4dGVuZFNlbGVjdGlvbnNCeShmdW5jdGlvbihyYW5nZSkge1xyXG4gICAgICAgIGlmIChjbS5kaXNwbGF5LnNoaWZ0IHx8IGNtLmRvYy5leHRlbmQgfHwgcmFuZ2UuZW1wdHkoKSlcclxuICAgICAgICAgIHJldHVybiBmaW5kUG9zSChjbS5kb2MsIHJhbmdlLmhlYWQsIGRpciwgdW5pdCwgY20ub3B0aW9ucy5ydGxNb3ZlVmlzdWFsbHkpO1xyXG4gICAgICAgIGVsc2VcclxuICAgICAgICAgIHJldHVybiBkaXIgPCAwID8gcmFuZ2UuZnJvbSgpIDogcmFuZ2UudG8oKTtcclxuICAgICAgfSwgc2VsX21vdmUpO1xyXG4gICAgfSksXHJcblxyXG4gICAgZGVsZXRlSDogbWV0aG9kT3AoZnVuY3Rpb24oZGlyLCB1bml0KSB7XHJcbiAgICAgIHZhciBzZWwgPSB0aGlzLmRvYy5zZWwsIGRvYyA9IHRoaXMuZG9jO1xyXG4gICAgICBpZiAoc2VsLnNvbWV0aGluZ1NlbGVjdGVkKCkpXHJcbiAgICAgICAgZG9jLnJlcGxhY2VTZWxlY3Rpb24oXCJcIiwgbnVsbCwgXCIrZGVsZXRlXCIpO1xyXG4gICAgICBlbHNlXHJcbiAgICAgICAgZGVsZXRlTmVhclNlbGVjdGlvbih0aGlzLCBmdW5jdGlvbihyYW5nZSkge1xyXG4gICAgICAgICAgdmFyIG90aGVyID0gZmluZFBvc0goZG9jLCByYW5nZS5oZWFkLCBkaXIsIHVuaXQsIGZhbHNlKTtcclxuICAgICAgICAgIHJldHVybiBkaXIgPCAwID8ge2Zyb206IG90aGVyLCB0bzogcmFuZ2UuaGVhZH0gOiB7ZnJvbTogcmFuZ2UuaGVhZCwgdG86IG90aGVyfTtcclxuICAgICAgICB9KTtcclxuICAgIH0pLFxyXG5cclxuICAgIGZpbmRQb3NWOiBmdW5jdGlvbihmcm9tLCBhbW91bnQsIHVuaXQsIGdvYWxDb2x1bW4pIHtcclxuICAgICAgdmFyIGRpciA9IDEsIHggPSBnb2FsQ29sdW1uO1xyXG4gICAgICBpZiAoYW1vdW50IDwgMCkgeyBkaXIgPSAtMTsgYW1vdW50ID0gLWFtb3VudDsgfVxyXG4gICAgICBmb3IgKHZhciBpID0gMCwgY3VyID0gY2xpcFBvcyh0aGlzLmRvYywgZnJvbSk7IGkgPCBhbW91bnQ7ICsraSkge1xyXG4gICAgICAgIHZhciBjb29yZHMgPSBjdXJzb3JDb29yZHModGhpcywgY3VyLCBcImRpdlwiKTtcclxuICAgICAgICBpZiAoeCA9PSBudWxsKSB4ID0gY29vcmRzLmxlZnQ7XHJcbiAgICAgICAgZWxzZSBjb29yZHMubGVmdCA9IHg7XHJcbiAgICAgICAgY3VyID0gZmluZFBvc1YodGhpcywgY29vcmRzLCBkaXIsIHVuaXQpO1xyXG4gICAgICAgIGlmIChjdXIuaGl0U2lkZSkgYnJlYWs7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGN1cjtcclxuICAgIH0sXHJcblxyXG4gICAgbW92ZVY6IG1ldGhvZE9wKGZ1bmN0aW9uKGRpciwgdW5pdCkge1xyXG4gICAgICB2YXIgY20gPSB0aGlzLCBkb2MgPSB0aGlzLmRvYywgZ29hbHMgPSBbXTtcclxuICAgICAgdmFyIGNvbGxhcHNlID0gIWNtLmRpc3BsYXkuc2hpZnQgJiYgIWRvYy5leHRlbmQgJiYgZG9jLnNlbC5zb21ldGhpbmdTZWxlY3RlZCgpO1xyXG4gICAgICBkb2MuZXh0ZW5kU2VsZWN0aW9uc0J5KGZ1bmN0aW9uKHJhbmdlKSB7XHJcbiAgICAgICAgaWYgKGNvbGxhcHNlKVxyXG4gICAgICAgICAgcmV0dXJuIGRpciA8IDAgPyByYW5nZS5mcm9tKCkgOiByYW5nZS50bygpO1xyXG4gICAgICAgIHZhciBoZWFkUG9zID0gY3Vyc29yQ29vcmRzKGNtLCByYW5nZS5oZWFkLCBcImRpdlwiKTtcclxuICAgICAgICBpZiAocmFuZ2UuZ29hbENvbHVtbiAhPSBudWxsKSBoZWFkUG9zLmxlZnQgPSByYW5nZS5nb2FsQ29sdW1uO1xyXG4gICAgICAgIGdvYWxzLnB1c2goaGVhZFBvcy5sZWZ0KTtcclxuICAgICAgICB2YXIgcG9zID0gZmluZFBvc1YoY20sIGhlYWRQb3MsIGRpciwgdW5pdCk7XHJcbiAgICAgICAgaWYgKHVuaXQgPT0gXCJwYWdlXCIgJiYgcmFuZ2UgPT0gZG9jLnNlbC5wcmltYXJ5KCkpXHJcbiAgICAgICAgICBhZGRUb1Njcm9sbFBvcyhjbSwgbnVsbCwgY2hhckNvb3JkcyhjbSwgcG9zLCBcImRpdlwiKS50b3AgLSBoZWFkUG9zLnRvcCk7XHJcbiAgICAgICAgcmV0dXJuIHBvcztcclxuICAgICAgfSwgc2VsX21vdmUpO1xyXG4gICAgICBpZiAoZ29hbHMubGVuZ3RoKSBmb3IgKHZhciBpID0gMDsgaSA8IGRvYy5zZWwucmFuZ2VzLmxlbmd0aDsgaSsrKVxyXG4gICAgICAgIGRvYy5zZWwucmFuZ2VzW2ldLmdvYWxDb2x1bW4gPSBnb2Fsc1tpXTtcclxuICAgIH0pLFxyXG5cclxuICAgIC8vIEZpbmQgdGhlIHdvcmQgYXQgdGhlIGdpdmVuIHBvc2l0aW9uIChhcyByZXR1cm5lZCBieSBjb29yZHNDaGFyKS5cclxuICAgIGZpbmRXb3JkQXQ6IGZ1bmN0aW9uKHBvcykge1xyXG4gICAgICB2YXIgZG9jID0gdGhpcy5kb2MsIGxpbmUgPSBnZXRMaW5lKGRvYywgcG9zLmxpbmUpLnRleHQ7XHJcbiAgICAgIHZhciBzdGFydCA9IHBvcy5jaCwgZW5kID0gcG9zLmNoO1xyXG4gICAgICBpZiAobGluZSkge1xyXG4gICAgICAgIHZhciBoZWxwZXIgPSB0aGlzLmdldEhlbHBlcihwb3MsIFwid29yZENoYXJzXCIpO1xyXG4gICAgICAgIGlmICgocG9zLnhSZWwgPCAwIHx8IGVuZCA9PSBsaW5lLmxlbmd0aCkgJiYgc3RhcnQpIC0tc3RhcnQ7IGVsc2UgKytlbmQ7XHJcbiAgICAgICAgdmFyIHN0YXJ0Q2hhciA9IGxpbmUuY2hhckF0KHN0YXJ0KTtcclxuICAgICAgICB2YXIgY2hlY2sgPSBpc1dvcmRDaGFyKHN0YXJ0Q2hhciwgaGVscGVyKVxyXG4gICAgICAgICAgPyBmdW5jdGlvbihjaCkgeyByZXR1cm4gaXNXb3JkQ2hhcihjaCwgaGVscGVyKTsgfVxyXG4gICAgICAgICAgOiAvXFxzLy50ZXN0KHN0YXJ0Q2hhcikgPyBmdW5jdGlvbihjaCkge3JldHVybiAvXFxzLy50ZXN0KGNoKTt9XHJcbiAgICAgICAgICA6IGZ1bmN0aW9uKGNoKSB7cmV0dXJuICEvXFxzLy50ZXN0KGNoKSAmJiAhaXNXb3JkQ2hhcihjaCk7fTtcclxuICAgICAgICB3aGlsZSAoc3RhcnQgPiAwICYmIGNoZWNrKGxpbmUuY2hhckF0KHN0YXJ0IC0gMSkpKSAtLXN0YXJ0O1xyXG4gICAgICAgIHdoaWxlIChlbmQgPCBsaW5lLmxlbmd0aCAmJiBjaGVjayhsaW5lLmNoYXJBdChlbmQpKSkgKytlbmQ7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG5ldyBSYW5nZShQb3MocG9zLmxpbmUsIHN0YXJ0KSwgUG9zKHBvcy5saW5lLCBlbmQpKTtcclxuICAgIH0sXHJcblxyXG4gICAgdG9nZ2xlT3ZlcndyaXRlOiBmdW5jdGlvbih2YWx1ZSkge1xyXG4gICAgICBpZiAodmFsdWUgIT0gbnVsbCAmJiB2YWx1ZSA9PSB0aGlzLnN0YXRlLm92ZXJ3cml0ZSkgcmV0dXJuO1xyXG4gICAgICBpZiAodGhpcy5zdGF0ZS5vdmVyd3JpdGUgPSAhdGhpcy5zdGF0ZS5vdmVyd3JpdGUpXHJcbiAgICAgICAgYWRkQ2xhc3ModGhpcy5kaXNwbGF5LmN1cnNvckRpdiwgXCJDb2RlTWlycm9yLW92ZXJ3cml0ZVwiKTtcclxuICAgICAgZWxzZVxyXG4gICAgICAgIHJtQ2xhc3ModGhpcy5kaXNwbGF5LmN1cnNvckRpdiwgXCJDb2RlTWlycm9yLW92ZXJ3cml0ZVwiKTtcclxuXHJcbiAgICAgIHNpZ25hbCh0aGlzLCBcIm92ZXJ3cml0ZVRvZ2dsZVwiLCB0aGlzLCB0aGlzLnN0YXRlLm92ZXJ3cml0ZSk7XHJcbiAgICB9LFxyXG4gICAgaGFzRm9jdXM6IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpcy5kaXNwbGF5LmlucHV0LmdldEZpZWxkKCkgPT0gYWN0aXZlRWx0KCk7IH0sXHJcblxyXG4gICAgc2Nyb2xsVG86IG1ldGhvZE9wKGZ1bmN0aW9uKHgsIHkpIHtcclxuICAgICAgaWYgKHggIT0gbnVsbCB8fCB5ICE9IG51bGwpIHJlc29sdmVTY3JvbGxUb1Bvcyh0aGlzKTtcclxuICAgICAgaWYgKHggIT0gbnVsbCkgdGhpcy5jdXJPcC5zY3JvbGxMZWZ0ID0geDtcclxuICAgICAgaWYgKHkgIT0gbnVsbCkgdGhpcy5jdXJPcC5zY3JvbGxUb3AgPSB5O1xyXG4gICAgfSksXHJcbiAgICBnZXRTY3JvbGxJbmZvOiBmdW5jdGlvbigpIHtcclxuICAgICAgdmFyIHNjcm9sbGVyID0gdGhpcy5kaXNwbGF5LnNjcm9sbGVyO1xyXG4gICAgICByZXR1cm4ge2xlZnQ6IHNjcm9sbGVyLnNjcm9sbExlZnQsIHRvcDogc2Nyb2xsZXIuc2Nyb2xsVG9wLFxyXG4gICAgICAgICAgICAgIGhlaWdodDogc2Nyb2xsZXIuc2Nyb2xsSGVpZ2h0IC0gc2Nyb2xsR2FwKHRoaXMpIC0gdGhpcy5kaXNwbGF5LmJhckhlaWdodCxcclxuICAgICAgICAgICAgICB3aWR0aDogc2Nyb2xsZXIuc2Nyb2xsV2lkdGggLSBzY3JvbGxHYXAodGhpcykgLSB0aGlzLmRpc3BsYXkuYmFyV2lkdGgsXHJcbiAgICAgICAgICAgICAgY2xpZW50SGVpZ2h0OiBkaXNwbGF5SGVpZ2h0KHRoaXMpLCBjbGllbnRXaWR0aDogZGlzcGxheVdpZHRoKHRoaXMpfTtcclxuICAgIH0sXHJcblxyXG4gICAgc2Nyb2xsSW50b1ZpZXc6IG1ldGhvZE9wKGZ1bmN0aW9uKHJhbmdlLCBtYXJnaW4pIHtcclxuICAgICAgaWYgKHJhbmdlID09IG51bGwpIHtcclxuICAgICAgICByYW5nZSA9IHtmcm9tOiB0aGlzLmRvYy5zZWwucHJpbWFyeSgpLmhlYWQsIHRvOiBudWxsfTtcclxuICAgICAgICBpZiAobWFyZ2luID09IG51bGwpIG1hcmdpbiA9IHRoaXMub3B0aW9ucy5jdXJzb3JTY3JvbGxNYXJnaW47XHJcbiAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHJhbmdlID09IFwibnVtYmVyXCIpIHtcclxuICAgICAgICByYW5nZSA9IHtmcm9tOiBQb3MocmFuZ2UsIDApLCB0bzogbnVsbH07XHJcbiAgICAgIH0gZWxzZSBpZiAocmFuZ2UuZnJvbSA9PSBudWxsKSB7XHJcbiAgICAgICAgcmFuZ2UgPSB7ZnJvbTogcmFuZ2UsIHRvOiBudWxsfTtcclxuICAgICAgfVxyXG4gICAgICBpZiAoIXJhbmdlLnRvKSByYW5nZS50byA9IHJhbmdlLmZyb207XHJcbiAgICAgIHJhbmdlLm1hcmdpbiA9IG1hcmdpbiB8fCAwO1xyXG5cclxuICAgICAgaWYgKHJhbmdlLmZyb20ubGluZSAhPSBudWxsKSB7XHJcbiAgICAgICAgcmVzb2x2ZVNjcm9sbFRvUG9zKHRoaXMpO1xyXG4gICAgICAgIHRoaXMuY3VyT3Auc2Nyb2xsVG9Qb3MgPSByYW5nZTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB2YXIgc1BvcyA9IGNhbGN1bGF0ZVNjcm9sbFBvcyh0aGlzLCBNYXRoLm1pbihyYW5nZS5mcm9tLmxlZnQsIHJhbmdlLnRvLmxlZnQpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hdGgubWluKHJhbmdlLmZyb20udG9wLCByYW5nZS50by50b3ApIC0gcmFuZ2UubWFyZ2luLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1hdGgubWF4KHJhbmdlLmZyb20ucmlnaHQsIHJhbmdlLnRvLnJpZ2h0KSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNYXRoLm1heChyYW5nZS5mcm9tLmJvdHRvbSwgcmFuZ2UudG8uYm90dG9tKSArIHJhbmdlLm1hcmdpbik7XHJcbiAgICAgICAgdGhpcy5zY3JvbGxUbyhzUG9zLnNjcm9sbExlZnQsIHNQb3Muc2Nyb2xsVG9wKTtcclxuICAgICAgfVxyXG4gICAgfSksXHJcblxyXG4gICAgc2V0U2l6ZTogbWV0aG9kT3AoZnVuY3Rpb24od2lkdGgsIGhlaWdodCkge1xyXG4gICAgICB2YXIgY20gPSB0aGlzO1xyXG4gICAgICBmdW5jdGlvbiBpbnRlcnByZXQodmFsKSB7XHJcbiAgICAgICAgcmV0dXJuIHR5cGVvZiB2YWwgPT0gXCJudW1iZXJcIiB8fCAvXlxcZCskLy50ZXN0KFN0cmluZyh2YWwpKSA/IHZhbCArIFwicHhcIiA6IHZhbDtcclxuICAgICAgfVxyXG4gICAgICBpZiAod2lkdGggIT0gbnVsbCkgY20uZGlzcGxheS53cmFwcGVyLnN0eWxlLndpZHRoID0gaW50ZXJwcmV0KHdpZHRoKTtcclxuICAgICAgaWYgKGhlaWdodCAhPSBudWxsKSBjbS5kaXNwbGF5LndyYXBwZXIuc3R5bGUuaGVpZ2h0ID0gaW50ZXJwcmV0KGhlaWdodCk7XHJcbiAgICAgIGlmIChjbS5vcHRpb25zLmxpbmVXcmFwcGluZykgY2xlYXJMaW5lTWVhc3VyZW1lbnRDYWNoZSh0aGlzKTtcclxuICAgICAgdmFyIGxpbmVObyA9IGNtLmRpc3BsYXkudmlld0Zyb207XHJcbiAgICAgIGNtLmRvYy5pdGVyKGxpbmVObywgY20uZGlzcGxheS52aWV3VG8sIGZ1bmN0aW9uKGxpbmUpIHtcclxuICAgICAgICBpZiAobGluZS53aWRnZXRzKSBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmUud2lkZ2V0cy5sZW5ndGg7IGkrKylcclxuICAgICAgICAgIGlmIChsaW5lLndpZGdldHNbaV0ubm9IU2Nyb2xsKSB7IHJlZ0xpbmVDaGFuZ2UoY20sIGxpbmVObywgXCJ3aWRnZXRcIik7IGJyZWFrOyB9XHJcbiAgICAgICAgKytsaW5lTm87XHJcbiAgICAgIH0pO1xyXG4gICAgICBjbS5jdXJPcC5mb3JjZVVwZGF0ZSA9IHRydWU7XHJcbiAgICAgIHNpZ25hbChjbSwgXCJyZWZyZXNoXCIsIHRoaXMpO1xyXG4gICAgfSksXHJcblxyXG4gICAgb3BlcmF0aW9uOiBmdW5jdGlvbihmKXtyZXR1cm4gcnVuSW5PcCh0aGlzLCBmKTt9LFxyXG5cclxuICAgIHJlZnJlc2g6IG1ldGhvZE9wKGZ1bmN0aW9uKCkge1xyXG4gICAgICB2YXIgb2xkSGVpZ2h0ID0gdGhpcy5kaXNwbGF5LmNhY2hlZFRleHRIZWlnaHQ7XHJcbiAgICAgIHJlZ0NoYW5nZSh0aGlzKTtcclxuICAgICAgdGhpcy5jdXJPcC5mb3JjZVVwZGF0ZSA9IHRydWU7XHJcbiAgICAgIGNsZWFyQ2FjaGVzKHRoaXMpO1xyXG4gICAgICB0aGlzLnNjcm9sbFRvKHRoaXMuZG9jLnNjcm9sbExlZnQsIHRoaXMuZG9jLnNjcm9sbFRvcCk7XHJcbiAgICAgIHVwZGF0ZUd1dHRlclNwYWNlKHRoaXMpO1xyXG4gICAgICBpZiAob2xkSGVpZ2h0ID09IG51bGwgfHwgTWF0aC5hYnMob2xkSGVpZ2h0IC0gdGV4dEhlaWdodCh0aGlzLmRpc3BsYXkpKSA+IC41KVxyXG4gICAgICAgIGVzdGltYXRlTGluZUhlaWdodHModGhpcyk7XHJcbiAgICAgIHNpZ25hbCh0aGlzLCBcInJlZnJlc2hcIiwgdGhpcyk7XHJcbiAgICB9KSxcclxuXHJcbiAgICBzd2FwRG9jOiBtZXRob2RPcChmdW5jdGlvbihkb2MpIHtcclxuICAgICAgdmFyIG9sZCA9IHRoaXMuZG9jO1xyXG4gICAgICBvbGQuY20gPSBudWxsO1xyXG4gICAgICBhdHRhY2hEb2ModGhpcywgZG9jKTtcclxuICAgICAgY2xlYXJDYWNoZXModGhpcyk7XHJcbiAgICAgIHRoaXMuZGlzcGxheS5pbnB1dC5yZXNldCgpO1xyXG4gICAgICB0aGlzLnNjcm9sbFRvKGRvYy5zY3JvbGxMZWZ0LCBkb2Muc2Nyb2xsVG9wKTtcclxuICAgICAgdGhpcy5jdXJPcC5mb3JjZVNjcm9sbCA9IHRydWU7XHJcbiAgICAgIHNpZ25hbExhdGVyKHRoaXMsIFwic3dhcERvY1wiLCB0aGlzLCBvbGQpO1xyXG4gICAgICByZXR1cm4gb2xkO1xyXG4gICAgfSksXHJcblxyXG4gICAgZ2V0SW5wdXRGaWVsZDogZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kaXNwbGF5LmlucHV0LmdldEZpZWxkKCk7fSxcclxuICAgIGdldFdyYXBwZXJFbGVtZW50OiBmdW5jdGlvbigpe3JldHVybiB0aGlzLmRpc3BsYXkud3JhcHBlcjt9LFxyXG4gICAgZ2V0U2Nyb2xsZXJFbGVtZW50OiBmdW5jdGlvbigpe3JldHVybiB0aGlzLmRpc3BsYXkuc2Nyb2xsZXI7fSxcclxuICAgIGdldEd1dHRlckVsZW1lbnQ6IGZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZGlzcGxheS5ndXR0ZXJzO31cclxuICB9O1xyXG4gIGV2ZW50TWl4aW4oQ29kZU1pcnJvcik7XHJcblxyXG4gIC8vIE9QVElPTiBERUZBVUxUU1xyXG5cclxuICAvLyBUaGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAgdmFyIGRlZmF1bHRzID0gQ29kZU1pcnJvci5kZWZhdWx0cyA9IHt9O1xyXG4gIC8vIEZ1bmN0aW9ucyB0byBydW4gd2hlbiBvcHRpb25zIGFyZSBjaGFuZ2VkLlxyXG4gIHZhciBvcHRpb25IYW5kbGVycyA9IENvZGVNaXJyb3Iub3B0aW9uSGFuZGxlcnMgPSB7fTtcclxuXHJcbiAgZnVuY3Rpb24gb3B0aW9uKG5hbWUsIGRlZmx0LCBoYW5kbGUsIG5vdE9uSW5pdCkge1xyXG4gICAgQ29kZU1pcnJvci5kZWZhdWx0c1tuYW1lXSA9IGRlZmx0O1xyXG4gICAgaWYgKGhhbmRsZSkgb3B0aW9uSGFuZGxlcnNbbmFtZV0gPVxyXG4gICAgICBub3RPbkluaXQgPyBmdW5jdGlvbihjbSwgdmFsLCBvbGQpIHtpZiAob2xkICE9IEluaXQpIGhhbmRsZShjbSwgdmFsLCBvbGQpO30gOiBoYW5kbGU7XHJcbiAgfVxyXG5cclxuICAvLyBQYXNzZWQgdG8gb3B0aW9uIGhhbmRsZXJzIHdoZW4gdGhlcmUgaXMgbm8gb2xkIHZhbHVlLlxyXG4gIHZhciBJbml0ID0gQ29kZU1pcnJvci5Jbml0ID0ge3RvU3RyaW5nOiBmdW5jdGlvbigpe3JldHVybiBcIkNvZGVNaXJyb3IuSW5pdFwiO319O1xyXG5cclxuICAvLyBUaGVzZSB0d28gYXJlLCBvbiBpbml0LCBjYWxsZWQgZnJvbSB0aGUgY29uc3RydWN0b3IgYmVjYXVzZSB0aGV5XHJcbiAgLy8gaGF2ZSB0byBiZSBpbml0aWFsaXplZCBiZWZvcmUgdGhlIGVkaXRvciBjYW4gc3RhcnQgYXQgYWxsLlxyXG4gIG9wdGlvbihcInZhbHVlXCIsIFwiXCIsIGZ1bmN0aW9uKGNtLCB2YWwpIHtcclxuICAgIGNtLnNldFZhbHVlKHZhbCk7XHJcbiAgfSwgdHJ1ZSk7XHJcbiAgb3B0aW9uKFwibW9kZVwiLCBudWxsLCBmdW5jdGlvbihjbSwgdmFsKSB7XHJcbiAgICBjbS5kb2MubW9kZU9wdGlvbiA9IHZhbDtcclxuICAgIGxvYWRNb2RlKGNtKTtcclxuICB9LCB0cnVlKTtcclxuXHJcbiAgb3B0aW9uKFwiaW5kZW50VW5pdFwiLCAyLCBsb2FkTW9kZSwgdHJ1ZSk7XHJcbiAgb3B0aW9uKFwiaW5kZW50V2l0aFRhYnNcIiwgZmFsc2UpO1xyXG4gIG9wdGlvbihcInNtYXJ0SW5kZW50XCIsIHRydWUpO1xyXG4gIG9wdGlvbihcInRhYlNpemVcIiwgNCwgZnVuY3Rpb24oY20pIHtcclxuICAgIHJlc2V0TW9kZVN0YXRlKGNtKTtcclxuICAgIGNsZWFyQ2FjaGVzKGNtKTtcclxuICAgIHJlZ0NoYW5nZShjbSk7XHJcbiAgfSwgdHJ1ZSk7XHJcbiAgb3B0aW9uKFwibGluZVNlcGFyYXRvclwiLCBudWxsLCBmdW5jdGlvbihjbSwgdmFsKSB7XHJcbiAgICBjbS5kb2MubGluZVNlcCA9IHZhbDtcclxuICAgIGlmICghdmFsKSByZXR1cm47XHJcbiAgICB2YXIgbmV3QnJlYWtzID0gW10sIGxpbmVObyA9IGNtLmRvYy5maXJzdDtcclxuICAgIGNtLmRvYy5pdGVyKGZ1bmN0aW9uKGxpbmUpIHtcclxuICAgICAgZm9yICh2YXIgcG9zID0gMDs7KSB7XHJcbiAgICAgICAgdmFyIGZvdW5kID0gbGluZS50ZXh0LmluZGV4T2YodmFsLCBwb3MpO1xyXG4gICAgICAgIGlmIChmb3VuZCA9PSAtMSkgYnJlYWs7XHJcbiAgICAgICAgcG9zID0gZm91bmQgKyB2YWwubGVuZ3RoO1xyXG4gICAgICAgIG5ld0JyZWFrcy5wdXNoKFBvcyhsaW5lTm8sIGZvdW5kKSk7XHJcbiAgICAgIH1cclxuICAgICAgbGluZU5vKys7XHJcbiAgICB9KTtcclxuICAgIGZvciAodmFyIGkgPSBuZXdCcmVha3MubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pXHJcbiAgICAgIHJlcGxhY2VSYW5nZShjbS5kb2MsIHZhbCwgbmV3QnJlYWtzW2ldLCBQb3MobmV3QnJlYWtzW2ldLmxpbmUsIG5ld0JyZWFrc1tpXS5jaCArIHZhbC5sZW5ndGgpKVxyXG4gIH0pO1xyXG4gIG9wdGlvbihcInNwZWNpYWxDaGFyc1wiLCAvW1xcdFxcdTAwMDAtXFx1MDAxOVxcdTAwYWRcXHUyMDBiLVxcdTIwMGZcXHUyMDI4XFx1MjAyOVxcdWZlZmZdL2csIGZ1bmN0aW9uKGNtLCB2YWwsIG9sZCkge1xyXG4gICAgY20uc3RhdGUuc3BlY2lhbENoYXJzID0gbmV3IFJlZ0V4cCh2YWwuc291cmNlICsgKHZhbC50ZXN0KFwiXFx0XCIpID8gXCJcIiA6IFwifFxcdFwiKSwgXCJnXCIpO1xyXG4gICAgaWYgKG9sZCAhPSBDb2RlTWlycm9yLkluaXQpIGNtLnJlZnJlc2goKTtcclxuICB9KTtcclxuICBvcHRpb24oXCJzcGVjaWFsQ2hhclBsYWNlaG9sZGVyXCIsIGRlZmF1bHRTcGVjaWFsQ2hhclBsYWNlaG9sZGVyLCBmdW5jdGlvbihjbSkge2NtLnJlZnJlc2goKTt9LCB0cnVlKTtcclxuICBvcHRpb24oXCJlbGVjdHJpY0NoYXJzXCIsIHRydWUpO1xyXG4gIG9wdGlvbihcImlucHV0U3R5bGVcIiwgbW9iaWxlID8gXCJjb250ZW50ZWRpdGFibGVcIiA6IFwidGV4dGFyZWFcIiwgZnVuY3Rpb24oKSB7XHJcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnB1dFN0eWxlIGNhbiBub3QgKHlldCkgYmUgY2hhbmdlZCBpbiBhIHJ1bm5pbmcgZWRpdG9yXCIpOyAvLyBGSVhNRVxyXG4gIH0sIHRydWUpO1xyXG4gIG9wdGlvbihcInJ0bE1vdmVWaXN1YWxseVwiLCAhd2luZG93cyk7XHJcbiAgb3B0aW9uKFwid2hvbGVMaW5lVXBkYXRlQmVmb3JlXCIsIHRydWUpO1xyXG5cclxuICBvcHRpb24oXCJ0aGVtZVwiLCBcImRlZmF1bHRcIiwgZnVuY3Rpb24oY20pIHtcclxuICAgIHRoZW1lQ2hhbmdlZChjbSk7XHJcbiAgICBndXR0ZXJzQ2hhbmdlZChjbSk7XHJcbiAgfSwgdHJ1ZSk7XHJcbiAgb3B0aW9uKFwia2V5TWFwXCIsIFwiZGVmYXVsdFwiLCBmdW5jdGlvbihjbSwgdmFsLCBvbGQpIHtcclxuICAgIHZhciBuZXh0ID0gZ2V0S2V5TWFwKHZhbCk7XHJcbiAgICB2YXIgcHJldiA9IG9sZCAhPSBDb2RlTWlycm9yLkluaXQgJiYgZ2V0S2V5TWFwKG9sZCk7XHJcbiAgICBpZiAocHJldiAmJiBwcmV2LmRldGFjaCkgcHJldi5kZXRhY2goY20sIG5leHQpO1xyXG4gICAgaWYgKG5leHQuYXR0YWNoKSBuZXh0LmF0dGFjaChjbSwgcHJldiB8fCBudWxsKTtcclxuICB9KTtcclxuICBvcHRpb24oXCJleHRyYUtleXNcIiwgbnVsbCk7XHJcblxyXG4gIG9wdGlvbihcImxpbmVXcmFwcGluZ1wiLCBmYWxzZSwgd3JhcHBpbmdDaGFuZ2VkLCB0cnVlKTtcclxuICBvcHRpb24oXCJndXR0ZXJzXCIsIFtdLCBmdW5jdGlvbihjbSkge1xyXG4gICAgc2V0R3V0dGVyc0ZvckxpbmVOdW1iZXJzKGNtLm9wdGlvbnMpO1xyXG4gICAgZ3V0dGVyc0NoYW5nZWQoY20pO1xyXG4gIH0sIHRydWUpO1xyXG4gIG9wdGlvbihcImZpeGVkR3V0dGVyXCIsIHRydWUsIGZ1bmN0aW9uKGNtLCB2YWwpIHtcclxuICAgIGNtLmRpc3BsYXkuZ3V0dGVycy5zdHlsZS5sZWZ0ID0gdmFsID8gY29tcGVuc2F0ZUZvckhTY3JvbGwoY20uZGlzcGxheSkgKyBcInB4XCIgOiBcIjBcIjtcclxuICAgIGNtLnJlZnJlc2goKTtcclxuICB9LCB0cnVlKTtcclxuICBvcHRpb24oXCJjb3Zlckd1dHRlck5leHRUb1Njcm9sbGJhclwiLCBmYWxzZSwgZnVuY3Rpb24oY20pIHt1cGRhdGVTY3JvbGxiYXJzKGNtKTt9LCB0cnVlKTtcclxuICBvcHRpb24oXCJzY3JvbGxiYXJTdHlsZVwiLCBcIm5hdGl2ZVwiLCBmdW5jdGlvbihjbSkge1xyXG4gICAgaW5pdFNjcm9sbGJhcnMoY20pO1xyXG4gICAgdXBkYXRlU2Nyb2xsYmFycyhjbSk7XHJcbiAgICBjbS5kaXNwbGF5LnNjcm9sbGJhcnMuc2V0U2Nyb2xsVG9wKGNtLmRvYy5zY3JvbGxUb3ApO1xyXG4gICAgY20uZGlzcGxheS5zY3JvbGxiYXJzLnNldFNjcm9sbExlZnQoY20uZG9jLnNjcm9sbExlZnQpO1xyXG4gIH0sIHRydWUpO1xyXG4gIG9wdGlvbihcImxpbmVOdW1iZXJzXCIsIGZhbHNlLCBmdW5jdGlvbihjbSkge1xyXG4gICAgc2V0R3V0dGVyc0ZvckxpbmVOdW1iZXJzKGNtLm9wdGlvbnMpO1xyXG4gICAgZ3V0dGVyc0NoYW5nZWQoY20pO1xyXG4gIH0sIHRydWUpO1xyXG4gIG9wdGlvbihcImZpcnN0TGluZU51bWJlclwiLCAxLCBndXR0ZXJzQ2hhbmdlZCwgdHJ1ZSk7XHJcbiAgb3B0aW9uKFwibGluZU51bWJlckZvcm1hdHRlclwiLCBmdW5jdGlvbihpbnRlZ2VyKSB7cmV0dXJuIGludGVnZXI7fSwgZ3V0dGVyc0NoYW5nZWQsIHRydWUpO1xyXG4gIG9wdGlvbihcInNob3dDdXJzb3JXaGVuU2VsZWN0aW5nXCIsIGZhbHNlLCB1cGRhdGVTZWxlY3Rpb24sIHRydWUpO1xyXG5cclxuICBvcHRpb24oXCJyZXNldFNlbGVjdGlvbk9uQ29udGV4dE1lbnVcIiwgdHJ1ZSk7XHJcbiAgb3B0aW9uKFwibGluZVdpc2VDb3B5Q3V0XCIsIHRydWUpO1xyXG5cclxuICBvcHRpb24oXCJyZWFkT25seVwiLCBmYWxzZSwgZnVuY3Rpb24oY20sIHZhbCkge1xyXG4gICAgaWYgKHZhbCA9PSBcIm5vY3Vyc29yXCIpIHtcclxuICAgICAgb25CbHVyKGNtKTtcclxuICAgICAgY20uZGlzcGxheS5pbnB1dC5ibHVyKCk7XHJcbiAgICAgIGNtLmRpc3BsYXkuZGlzYWJsZWQgPSB0cnVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgY20uZGlzcGxheS5kaXNhYmxlZCA9IGZhbHNlO1xyXG4gICAgfVxyXG4gICAgY20uZGlzcGxheS5pbnB1dC5yZWFkT25seUNoYW5nZWQodmFsKVxyXG4gIH0pO1xyXG4gIG9wdGlvbihcImRpc2FibGVJbnB1dFwiLCBmYWxzZSwgZnVuY3Rpb24oY20sIHZhbCkge2lmICghdmFsKSBjbS5kaXNwbGF5LmlucHV0LnJlc2V0KCk7fSwgdHJ1ZSk7XHJcbiAgb3B0aW9uKFwiZHJhZ0Ryb3BcIiwgdHJ1ZSwgZHJhZ0Ryb3BDaGFuZ2VkKTtcclxuICBvcHRpb24oXCJhbGxvd0Ryb3BGaWxlVHlwZXNcIiwgbnVsbCk7XHJcblxyXG4gIG9wdGlvbihcImN1cnNvckJsaW5rUmF0ZVwiLCA1MzApO1xyXG4gIG9wdGlvbihcImN1cnNvclNjcm9sbE1hcmdpblwiLCAwKTtcclxuICBvcHRpb24oXCJjdXJzb3JIZWlnaHRcIiwgMSwgdXBkYXRlU2VsZWN0aW9uLCB0cnVlKTtcclxuICBvcHRpb24oXCJzaW5nbGVDdXJzb3JIZWlnaHRQZXJMaW5lXCIsIHRydWUsIHVwZGF0ZVNlbGVjdGlvbiwgdHJ1ZSk7XHJcbiAgb3B0aW9uKFwid29ya1RpbWVcIiwgMTAwKTtcclxuICBvcHRpb24oXCJ3b3JrRGVsYXlcIiwgMTAwKTtcclxuICBvcHRpb24oXCJmbGF0dGVuU3BhbnNcIiwgdHJ1ZSwgcmVzZXRNb2RlU3RhdGUsIHRydWUpO1xyXG4gIG9wdGlvbihcImFkZE1vZGVDbGFzc1wiLCBmYWxzZSwgcmVzZXRNb2RlU3RhdGUsIHRydWUpO1xyXG4gIG9wdGlvbihcInBvbGxJbnRlcnZhbFwiLCAxMDApO1xyXG4gIG9wdGlvbihcInVuZG9EZXB0aFwiLCAyMDAsIGZ1bmN0aW9uKGNtLCB2YWwpe2NtLmRvYy5oaXN0b3J5LnVuZG9EZXB0aCA9IHZhbDt9KTtcclxuICBvcHRpb24oXCJoaXN0b3J5RXZlbnREZWxheVwiLCAxMjUwKTtcclxuICBvcHRpb24oXCJ2aWV3cG9ydE1hcmdpblwiLCAxMCwgZnVuY3Rpb24oY20pe2NtLnJlZnJlc2goKTt9LCB0cnVlKTtcclxuICBvcHRpb24oXCJtYXhIaWdobGlnaHRMZW5ndGhcIiwgMTAwMDAsIHJlc2V0TW9kZVN0YXRlLCB0cnVlKTtcclxuICBvcHRpb24oXCJtb3ZlSW5wdXRXaXRoQ3Vyc29yXCIsIHRydWUsIGZ1bmN0aW9uKGNtLCB2YWwpIHtcclxuICAgIGlmICghdmFsKSBjbS5kaXNwbGF5LmlucHV0LnJlc2V0UG9zaXRpb24oKTtcclxuICB9KTtcclxuXHJcbiAgb3B0aW9uKFwidGFiaW5kZXhcIiwgbnVsbCwgZnVuY3Rpb24oY20sIHZhbCkge1xyXG4gICAgY20uZGlzcGxheS5pbnB1dC5nZXRGaWVsZCgpLnRhYkluZGV4ID0gdmFsIHx8IFwiXCI7XHJcbiAgfSk7XHJcbiAgb3B0aW9uKFwiYXV0b2ZvY3VzXCIsIG51bGwpO1xyXG5cclxuICAvLyBNT0RFIERFRklOSVRJT04gQU5EIFFVRVJZSU5HXHJcblxyXG4gIC8vIEtub3duIG1vZGVzLCBieSBuYW1lIGFuZCBieSBNSU1FXHJcbiAgdmFyIG1vZGVzID0gQ29kZU1pcnJvci5tb2RlcyA9IHt9LCBtaW1lTW9kZXMgPSBDb2RlTWlycm9yLm1pbWVNb2RlcyA9IHt9O1xyXG5cclxuICAvLyBFeHRyYSBhcmd1bWVudHMgYXJlIHN0b3JlZCBhcyB0aGUgbW9kZSdzIGRlcGVuZGVuY2llcywgd2hpY2ggaXNcclxuICAvLyB1c2VkIGJ5IChsZWdhY3kpIG1lY2hhbmlzbXMgbGlrZSBsb2FkbW9kZS5qcyB0byBhdXRvbWF0aWNhbGx5XHJcbiAgLy8gbG9hZCBhIG1vZGUuIChQcmVmZXJyZWQgbWVjaGFuaXNtIGlzIHRoZSByZXF1aXJlL2RlZmluZSBjYWxscy4pXHJcbiAgQ29kZU1pcnJvci5kZWZpbmVNb2RlID0gZnVuY3Rpb24obmFtZSwgbW9kZSkge1xyXG4gICAgaWYgKCFDb2RlTWlycm9yLmRlZmF1bHRzLm1vZGUgJiYgbmFtZSAhPSBcIm51bGxcIikgQ29kZU1pcnJvci5kZWZhdWx0cy5tb2RlID0gbmFtZTtcclxuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMilcclxuICAgICAgbW9kZS5kZXBlbmRlbmNpZXMgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xyXG4gICAgbW9kZXNbbmFtZV0gPSBtb2RlO1xyXG4gIH07XHJcblxyXG4gIENvZGVNaXJyb3IuZGVmaW5lTUlNRSA9IGZ1bmN0aW9uKG1pbWUsIHNwZWMpIHtcclxuICAgIG1pbWVNb2Rlc1ttaW1lXSA9IHNwZWM7XHJcbiAgfTtcclxuXHJcbiAgLy8gR2l2ZW4gYSBNSU1FIHR5cGUsIGEge25hbWUsIC4uLm9wdGlvbnN9IGNvbmZpZyBvYmplY3QsIG9yIGEgbmFtZVxyXG4gIC8vIHN0cmluZywgcmV0dXJuIGEgbW9kZSBjb25maWcgb2JqZWN0LlxyXG4gIENvZGVNaXJyb3IucmVzb2x2ZU1vZGUgPSBmdW5jdGlvbihzcGVjKSB7XHJcbiAgICBpZiAodHlwZW9mIHNwZWMgPT0gXCJzdHJpbmdcIiAmJiBtaW1lTW9kZXMuaGFzT3duUHJvcGVydHkoc3BlYykpIHtcclxuICAgICAgc3BlYyA9IG1pbWVNb2Rlc1tzcGVjXTtcclxuICAgIH0gZWxzZSBpZiAoc3BlYyAmJiB0eXBlb2Ygc3BlYy5uYW1lID09IFwic3RyaW5nXCIgJiYgbWltZU1vZGVzLmhhc093blByb3BlcnR5KHNwZWMubmFtZSkpIHtcclxuICAgICAgdmFyIGZvdW5kID0gbWltZU1vZGVzW3NwZWMubmFtZV07XHJcbiAgICAgIGlmICh0eXBlb2YgZm91bmQgPT0gXCJzdHJpbmdcIikgZm91bmQgPSB7bmFtZTogZm91bmR9O1xyXG4gICAgICBzcGVjID0gY3JlYXRlT2JqKGZvdW5kLCBzcGVjKTtcclxuICAgICAgc3BlYy5uYW1lID0gZm91bmQubmFtZTtcclxuICAgIH0gZWxzZSBpZiAodHlwZW9mIHNwZWMgPT0gXCJzdHJpbmdcIiAmJiAvXltcXHdcXC1dK1xcL1tcXHdcXC1dK1xcK3htbCQvLnRlc3Qoc3BlYykpIHtcclxuICAgICAgcmV0dXJuIENvZGVNaXJyb3IucmVzb2x2ZU1vZGUoXCJhcHBsaWNhdGlvbi94bWxcIik7XHJcbiAgICB9XHJcbiAgICBpZiAodHlwZW9mIHNwZWMgPT0gXCJzdHJpbmdcIikgcmV0dXJuIHtuYW1lOiBzcGVjfTtcclxuICAgIGVsc2UgcmV0dXJuIHNwZWMgfHwge25hbWU6IFwibnVsbFwifTtcclxuICB9O1xyXG5cclxuICAvLyBHaXZlbiBhIG1vZGUgc3BlYyAoYW55dGhpbmcgdGhhdCByZXNvbHZlTW9kZSBhY2NlcHRzKSwgZmluZCBhbmRcclxuICAvLyBpbml0aWFsaXplIGFuIGFjdHVhbCBtb2RlIG9iamVjdC5cclxuICBDb2RlTWlycm9yLmdldE1vZGUgPSBmdW5jdGlvbihvcHRpb25zLCBzcGVjKSB7XHJcbiAgICB2YXIgc3BlYyA9IENvZGVNaXJyb3IucmVzb2x2ZU1vZGUoc3BlYyk7XHJcbiAgICB2YXIgbWZhY3RvcnkgPSBtb2Rlc1tzcGVjLm5hbWVdO1xyXG4gICAgaWYgKCFtZmFjdG9yeSkgcmV0dXJuIENvZGVNaXJyb3IuZ2V0TW9kZShvcHRpb25zLCBcInRleHQvcGxhaW5cIik7XHJcbiAgICB2YXIgbW9kZU9iaiA9IG1mYWN0b3J5KG9wdGlvbnMsIHNwZWMpO1xyXG4gICAgaWYgKG1vZGVFeHRlbnNpb25zLmhhc093blByb3BlcnR5KHNwZWMubmFtZSkpIHtcclxuICAgICAgdmFyIGV4dHMgPSBtb2RlRXh0ZW5zaW9uc1tzcGVjLm5hbWVdO1xyXG4gICAgICBmb3IgKHZhciBwcm9wIGluIGV4dHMpIHtcclxuICAgICAgICBpZiAoIWV4dHMuaGFzT3duUHJvcGVydHkocHJvcCkpIGNvbnRpbnVlO1xyXG4gICAgICAgIGlmIChtb2RlT2JqLmhhc093blByb3BlcnR5KHByb3ApKSBtb2RlT2JqW1wiX1wiICsgcHJvcF0gPSBtb2RlT2JqW3Byb3BdO1xyXG4gICAgICAgIG1vZGVPYmpbcHJvcF0gPSBleHRzW3Byb3BdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBtb2RlT2JqLm5hbWUgPSBzcGVjLm5hbWU7XHJcbiAgICBpZiAoc3BlYy5oZWxwZXJUeXBlKSBtb2RlT2JqLmhlbHBlclR5cGUgPSBzcGVjLmhlbHBlclR5cGU7XHJcbiAgICBpZiAoc3BlYy5tb2RlUHJvcHMpIGZvciAodmFyIHByb3AgaW4gc3BlYy5tb2RlUHJvcHMpXHJcbiAgICAgIG1vZGVPYmpbcHJvcF0gPSBzcGVjLm1vZGVQcm9wc1twcm9wXTtcclxuXHJcbiAgICByZXR1cm4gbW9kZU9iajtcclxuICB9O1xyXG5cclxuICAvLyBNaW5pbWFsIGRlZmF1bHQgbW9kZS5cclxuICBDb2RlTWlycm9yLmRlZmluZU1vZGUoXCJudWxsXCIsIGZ1bmN0aW9uKCkge1xyXG4gICAgcmV0dXJuIHt0b2tlbjogZnVuY3Rpb24oc3RyZWFtKSB7c3RyZWFtLnNraXBUb0VuZCgpO319O1xyXG4gIH0pO1xyXG4gIENvZGVNaXJyb3IuZGVmaW5lTUlNRShcInRleHQvcGxhaW5cIiwgXCJudWxsXCIpO1xyXG5cclxuICAvLyBUaGlzIGNhbiBiZSB1c2VkIHRvIGF0dGFjaCBwcm9wZXJ0aWVzIHRvIG1vZGUgb2JqZWN0cyBmcm9tXHJcbiAgLy8gb3V0c2lkZSB0aGUgYWN0dWFsIG1vZGUgZGVmaW5pdGlvbi5cclxuICB2YXIgbW9kZUV4dGVuc2lvbnMgPSBDb2RlTWlycm9yLm1vZGVFeHRlbnNpb25zID0ge307XHJcbiAgQ29kZU1pcnJvci5leHRlbmRNb2RlID0gZnVuY3Rpb24obW9kZSwgcHJvcGVydGllcykge1xyXG4gICAgdmFyIGV4dHMgPSBtb2RlRXh0ZW5zaW9ucy5oYXNPd25Qcm9wZXJ0eShtb2RlKSA/IG1vZGVFeHRlbnNpb25zW21vZGVdIDogKG1vZGVFeHRlbnNpb25zW21vZGVdID0ge30pO1xyXG4gICAgY29weU9iaihwcm9wZXJ0aWVzLCBleHRzKTtcclxuICB9O1xyXG5cclxuICAvLyBFWFRFTlNJT05TXHJcblxyXG4gIENvZGVNaXJyb3IuZGVmaW5lRXh0ZW5zaW9uID0gZnVuY3Rpb24obmFtZSwgZnVuYykge1xyXG4gICAgQ29kZU1pcnJvci5wcm90b3R5cGVbbmFtZV0gPSBmdW5jO1xyXG4gIH07XHJcbiAgQ29kZU1pcnJvci5kZWZpbmVEb2NFeHRlbnNpb24gPSBmdW5jdGlvbihuYW1lLCBmdW5jKSB7XHJcbiAgICBEb2MucHJvdG90eXBlW25hbWVdID0gZnVuYztcclxuICB9O1xyXG4gIENvZGVNaXJyb3IuZGVmaW5lT3B0aW9uID0gb3B0aW9uO1xyXG5cclxuICB2YXIgaW5pdEhvb2tzID0gW107XHJcbiAgQ29kZU1pcnJvci5kZWZpbmVJbml0SG9vayA9IGZ1bmN0aW9uKGYpIHtpbml0SG9va3MucHVzaChmKTt9O1xyXG5cclxuICB2YXIgaGVscGVycyA9IENvZGVNaXJyb3IuaGVscGVycyA9IHt9O1xyXG4gIENvZGVNaXJyb3IucmVnaXN0ZXJIZWxwZXIgPSBmdW5jdGlvbih0eXBlLCBuYW1lLCB2YWx1ZSkge1xyXG4gICAgaWYgKCFoZWxwZXJzLmhhc093blByb3BlcnR5KHR5cGUpKSBoZWxwZXJzW3R5cGVdID0gQ29kZU1pcnJvclt0eXBlXSA9IHtfZ2xvYmFsOiBbXX07XHJcbiAgICBoZWxwZXJzW3R5cGVdW25hbWVdID0gdmFsdWU7XHJcbiAgfTtcclxuICBDb2RlTWlycm9yLnJlZ2lzdGVyR2xvYmFsSGVscGVyID0gZnVuY3Rpb24odHlwZSwgbmFtZSwgcHJlZGljYXRlLCB2YWx1ZSkge1xyXG4gICAgQ29kZU1pcnJvci5yZWdpc3RlckhlbHBlcih0eXBlLCBuYW1lLCB2YWx1ZSk7XHJcbiAgICBoZWxwZXJzW3R5cGVdLl9nbG9iYWwucHVzaCh7cHJlZDogcHJlZGljYXRlLCB2YWw6IHZhbHVlfSk7XHJcbiAgfTtcclxuXHJcbiAgLy8gTU9ERSBTVEFURSBIQU5ETElOR1xyXG5cclxuICAvLyBVdGlsaXR5IGZ1bmN0aW9ucyBmb3Igd29ya2luZyB3aXRoIHN0YXRlLiBFeHBvcnRlZCBiZWNhdXNlIG5lc3RlZFxyXG4gIC8vIG1vZGVzIG5lZWQgdG8gZG8gdGhpcyBmb3IgdGhlaXIgaW5uZXIgbW9kZXMuXHJcblxyXG4gIHZhciBjb3B5U3RhdGUgPSBDb2RlTWlycm9yLmNvcHlTdGF0ZSA9IGZ1bmN0aW9uKG1vZGUsIHN0YXRlKSB7XHJcbiAgICBpZiAoc3RhdGUgPT09IHRydWUpIHJldHVybiBzdGF0ZTtcclxuICAgIGlmIChtb2RlLmNvcHlTdGF0ZSkgcmV0dXJuIG1vZGUuY29weVN0YXRlKHN0YXRlKTtcclxuICAgIHZhciBuc3RhdGUgPSB7fTtcclxuICAgIGZvciAodmFyIG4gaW4gc3RhdGUpIHtcclxuICAgICAgdmFyIHZhbCA9IHN0YXRlW25dO1xyXG4gICAgICBpZiAodmFsIGluc3RhbmNlb2YgQXJyYXkpIHZhbCA9IHZhbC5jb25jYXQoW10pO1xyXG4gICAgICBuc3RhdGVbbl0gPSB2YWw7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gbnN0YXRlO1xyXG4gIH07XHJcblxyXG4gIHZhciBzdGFydFN0YXRlID0gQ29kZU1pcnJvci5zdGFydFN0YXRlID0gZnVuY3Rpb24obW9kZSwgYTEsIGEyKSB7XHJcbiAgICByZXR1cm4gbW9kZS5zdGFydFN0YXRlID8gbW9kZS5zdGFydFN0YXRlKGExLCBhMikgOiB0cnVlO1xyXG4gIH07XHJcblxyXG4gIC8vIEdpdmVuIGEgbW9kZSBhbmQgYSBzdGF0ZSAoZm9yIHRoYXQgbW9kZSksIGZpbmQgdGhlIGlubmVyIG1vZGUgYW5kXHJcbiAgLy8gc3RhdGUgYXQgdGhlIHBvc2l0aW9uIHRoYXQgdGhlIHN0YXRlIHJlZmVycyB0by5cclxuICBDb2RlTWlycm9yLmlubmVyTW9kZSA9IGZ1bmN0aW9uKG1vZGUsIHN0YXRlKSB7XHJcbiAgICB3aGlsZSAobW9kZS5pbm5lck1vZGUpIHtcclxuICAgICAgdmFyIGluZm8gPSBtb2RlLmlubmVyTW9kZShzdGF0ZSk7XHJcbiAgICAgIGlmICghaW5mbyB8fCBpbmZvLm1vZGUgPT0gbW9kZSkgYnJlYWs7XHJcbiAgICAgIHN0YXRlID0gaW5mby5zdGF0ZTtcclxuICAgICAgbW9kZSA9IGluZm8ubW9kZTtcclxuICAgIH1cclxuICAgIHJldHVybiBpbmZvIHx8IHttb2RlOiBtb2RlLCBzdGF0ZTogc3RhdGV9O1xyXG4gIH07XHJcblxyXG4gIC8vIFNUQU5EQVJEIENPTU1BTkRTXHJcblxyXG4gIC8vIENvbW1hbmRzIGFyZSBwYXJhbWV0ZXItbGVzcyBhY3Rpb25zIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBvbiBhblxyXG4gIC8vIGVkaXRvciwgbW9zdGx5IHVzZWQgZm9yIGtleWJpbmRpbmdzLlxyXG4gIHZhciBjb21tYW5kcyA9IENvZGVNaXJyb3IuY29tbWFuZHMgPSB7XHJcbiAgICBzZWxlY3RBbGw6IGZ1bmN0aW9uKGNtKSB7Y20uc2V0U2VsZWN0aW9uKFBvcyhjbS5maXJzdExpbmUoKSwgMCksIFBvcyhjbS5sYXN0TGluZSgpKSwgc2VsX2RvbnRTY3JvbGwpO30sXHJcbiAgICBzaW5nbGVTZWxlY3Rpb246IGZ1bmN0aW9uKGNtKSB7XHJcbiAgICAgIGNtLnNldFNlbGVjdGlvbihjbS5nZXRDdXJzb3IoXCJhbmNob3JcIiksIGNtLmdldEN1cnNvcihcImhlYWRcIiksIHNlbF9kb250U2Nyb2xsKTtcclxuICAgIH0sXHJcbiAgICBraWxsTGluZTogZnVuY3Rpb24oY20pIHtcclxuICAgICAgZGVsZXRlTmVhclNlbGVjdGlvbihjbSwgZnVuY3Rpb24ocmFuZ2UpIHtcclxuICAgICAgICBpZiAocmFuZ2UuZW1wdHkoKSkge1xyXG4gICAgICAgICAgdmFyIGxlbiA9IGdldExpbmUoY20uZG9jLCByYW5nZS5oZWFkLmxpbmUpLnRleHQubGVuZ3RoO1xyXG4gICAgICAgICAgaWYgKHJhbmdlLmhlYWQuY2ggPT0gbGVuICYmIHJhbmdlLmhlYWQubGluZSA8IGNtLmxhc3RMaW5lKCkpXHJcbiAgICAgICAgICAgIHJldHVybiB7ZnJvbTogcmFuZ2UuaGVhZCwgdG86IFBvcyhyYW5nZS5oZWFkLmxpbmUgKyAxLCAwKX07XHJcbiAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgIHJldHVybiB7ZnJvbTogcmFuZ2UuaGVhZCwgdG86IFBvcyhyYW5nZS5oZWFkLmxpbmUsIGxlbil9O1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICByZXR1cm4ge2Zyb206IHJhbmdlLmZyb20oKSwgdG86IHJhbmdlLnRvKCl9O1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9LFxyXG4gICAgZGVsZXRlTGluZTogZnVuY3Rpb24oY20pIHtcclxuICAgICAgZGVsZXRlTmVhclNlbGVjdGlvbihjbSwgZnVuY3Rpb24ocmFuZ2UpIHtcclxuICAgICAgICByZXR1cm4ge2Zyb206IFBvcyhyYW5nZS5mcm9tKCkubGluZSwgMCksXHJcbiAgICAgICAgICAgICAgICB0bzogY2xpcFBvcyhjbS5kb2MsIFBvcyhyYW5nZS50bygpLmxpbmUgKyAxLCAwKSl9O1xyXG4gICAgICB9KTtcclxuICAgIH0sXHJcbiAgICBkZWxMaW5lTGVmdDogZnVuY3Rpb24oY20pIHtcclxuICAgICAgZGVsZXRlTmVhclNlbGVjdGlvbihjbSwgZnVuY3Rpb24ocmFuZ2UpIHtcclxuICAgICAgICByZXR1cm4ge2Zyb206IFBvcyhyYW5nZS5mcm9tKCkubGluZSwgMCksIHRvOiByYW5nZS5mcm9tKCl9O1xyXG4gICAgICB9KTtcclxuICAgIH0sXHJcbiAgICBkZWxXcmFwcGVkTGluZUxlZnQ6IGZ1bmN0aW9uKGNtKSB7XHJcbiAgICAgIGRlbGV0ZU5lYXJTZWxlY3Rpb24oY20sIGZ1bmN0aW9uKHJhbmdlKSB7XHJcbiAgICAgICAgdmFyIHRvcCA9IGNtLmNoYXJDb29yZHMocmFuZ2UuaGVhZCwgXCJkaXZcIikudG9wICsgNTtcclxuICAgICAgICB2YXIgbGVmdFBvcyA9IGNtLmNvb3Jkc0NoYXIoe2xlZnQ6IDAsIHRvcDogdG9wfSwgXCJkaXZcIik7XHJcbiAgICAgICAgcmV0dXJuIHtmcm9tOiBsZWZ0UG9zLCB0bzogcmFuZ2UuZnJvbSgpfTtcclxuICAgICAgfSk7XHJcbiAgICB9LFxyXG4gICAgZGVsV3JhcHBlZExpbmVSaWdodDogZnVuY3Rpb24oY20pIHtcclxuICAgICAgZGVsZXRlTmVhclNlbGVjdGlvbihjbSwgZnVuY3Rpb24ocmFuZ2UpIHtcclxuICAgICAgICB2YXIgdG9wID0gY20uY2hhckNvb3JkcyhyYW5nZS5oZWFkLCBcImRpdlwiKS50b3AgKyA1O1xyXG4gICAgICAgIHZhciByaWdodFBvcyA9IGNtLmNvb3Jkc0NoYXIoe2xlZnQ6IGNtLmRpc3BsYXkubGluZURpdi5vZmZzZXRXaWR0aCArIDEwMCwgdG9wOiB0b3B9LCBcImRpdlwiKTtcclxuICAgICAgICByZXR1cm4ge2Zyb206IHJhbmdlLmZyb20oKSwgdG86IHJpZ2h0UG9zIH07XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuICAgIHVuZG86IGZ1bmN0aW9uKGNtKSB7Y20udW5kbygpO30sXHJcbiAgICByZWRvOiBmdW5jdGlvbihjbSkge2NtLnJlZG8oKTt9LFxyXG4gICAgdW5kb1NlbGVjdGlvbjogZnVuY3Rpb24oY20pIHtjbS51bmRvU2VsZWN0aW9uKCk7fSxcclxuICAgIHJlZG9TZWxlY3Rpb246IGZ1bmN0aW9uKGNtKSB7Y20ucmVkb1NlbGVjdGlvbigpO30sXHJcbiAgICBnb0RvY1N0YXJ0OiBmdW5jdGlvbihjbSkge2NtLmV4dGVuZFNlbGVjdGlvbihQb3MoY20uZmlyc3RMaW5lKCksIDApKTt9LFxyXG4gICAgZ29Eb2NFbmQ6IGZ1bmN0aW9uKGNtKSB7Y20uZXh0ZW5kU2VsZWN0aW9uKFBvcyhjbS5sYXN0TGluZSgpKSk7fSxcclxuICAgIGdvTGluZVN0YXJ0OiBmdW5jdGlvbihjbSkge1xyXG4gICAgICBjbS5leHRlbmRTZWxlY3Rpb25zQnkoZnVuY3Rpb24ocmFuZ2UpIHsgcmV0dXJuIGxpbmVTdGFydChjbSwgcmFuZ2UuaGVhZC5saW5lKTsgfSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHtvcmlnaW46IFwiK21vdmVcIiwgYmlhczogMX0pO1xyXG4gICAgfSxcclxuICAgIGdvTGluZVN0YXJ0U21hcnQ6IGZ1bmN0aW9uKGNtKSB7XHJcbiAgICAgIGNtLmV4dGVuZFNlbGVjdGlvbnNCeShmdW5jdGlvbihyYW5nZSkge1xyXG4gICAgICAgIHJldHVybiBsaW5lU3RhcnRTbWFydChjbSwgcmFuZ2UuaGVhZCk7XHJcbiAgICAgIH0sIHtvcmlnaW46IFwiK21vdmVcIiwgYmlhczogMX0pO1xyXG4gICAgfSxcclxuICAgIGdvTGluZUVuZDogZnVuY3Rpb24oY20pIHtcclxuICAgICAgY20uZXh0ZW5kU2VsZWN0aW9uc0J5KGZ1bmN0aW9uKHJhbmdlKSB7IHJldHVybiBsaW5lRW5kKGNtLCByYW5nZS5oZWFkLmxpbmUpOyB9LFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge29yaWdpbjogXCIrbW92ZVwiLCBiaWFzOiAtMX0pO1xyXG4gICAgfSxcclxuICAgIGdvTGluZVJpZ2h0OiBmdW5jdGlvbihjbSkge1xyXG4gICAgICBjbS5leHRlbmRTZWxlY3Rpb25zQnkoZnVuY3Rpb24ocmFuZ2UpIHtcclxuICAgICAgICB2YXIgdG9wID0gY20uY2hhckNvb3JkcyhyYW5nZS5oZWFkLCBcImRpdlwiKS50b3AgKyA1O1xyXG4gICAgICAgIHJldHVybiBjbS5jb29yZHNDaGFyKHtsZWZ0OiBjbS5kaXNwbGF5LmxpbmVEaXYub2Zmc2V0V2lkdGggKyAxMDAsIHRvcDogdG9wfSwgXCJkaXZcIik7XHJcbiAgICAgIH0sIHNlbF9tb3ZlKTtcclxuICAgIH0sXHJcbiAgICBnb0xpbmVMZWZ0OiBmdW5jdGlvbihjbSkge1xyXG4gICAgICBjbS5leHRlbmRTZWxlY3Rpb25zQnkoZnVuY3Rpb24ocmFuZ2UpIHtcclxuICAgICAgICB2YXIgdG9wID0gY20uY2hhckNvb3JkcyhyYW5nZS5oZWFkLCBcImRpdlwiKS50b3AgKyA1O1xyXG4gICAgICAgIHJldHVybiBjbS5jb29yZHNDaGFyKHtsZWZ0OiAwLCB0b3A6IHRvcH0sIFwiZGl2XCIpO1xyXG4gICAgICB9LCBzZWxfbW92ZSk7XHJcbiAgICB9LFxyXG4gICAgZ29MaW5lTGVmdFNtYXJ0OiBmdW5jdGlvbihjbSkge1xyXG4gICAgICBjbS5leHRlbmRTZWxlY3Rpb25zQnkoZnVuY3Rpb24ocmFuZ2UpIHtcclxuICAgICAgICB2YXIgdG9wID0gY20uY2hhckNvb3JkcyhyYW5nZS5oZWFkLCBcImRpdlwiKS50b3AgKyA1O1xyXG4gICAgICAgIHZhciBwb3MgPSBjbS5jb29yZHNDaGFyKHtsZWZ0OiAwLCB0b3A6IHRvcH0sIFwiZGl2XCIpO1xyXG4gICAgICAgIGlmIChwb3MuY2ggPCBjbS5nZXRMaW5lKHBvcy5saW5lKS5zZWFyY2goL1xcUy8pKSByZXR1cm4gbGluZVN0YXJ0U21hcnQoY20sIHJhbmdlLmhlYWQpO1xyXG4gICAgICAgIHJldHVybiBwb3M7XHJcbiAgICAgIH0sIHNlbF9tb3ZlKTtcclxuICAgIH0sXHJcbiAgICBnb0xpbmVVcDogZnVuY3Rpb24oY20pIHtjbS5tb3ZlVigtMSwgXCJsaW5lXCIpO30sXHJcbiAgICBnb0xpbmVEb3duOiBmdW5jdGlvbihjbSkge2NtLm1vdmVWKDEsIFwibGluZVwiKTt9LFxyXG4gICAgZ29QYWdlVXA6IGZ1bmN0aW9uKGNtKSB7Y20ubW92ZVYoLTEsIFwicGFnZVwiKTt9LFxyXG4gICAgZ29QYWdlRG93bjogZnVuY3Rpb24oY20pIHtjbS5tb3ZlVigxLCBcInBhZ2VcIik7fSxcclxuICAgIGdvQ2hhckxlZnQ6IGZ1bmN0aW9uKGNtKSB7Y20ubW92ZUgoLTEsIFwiY2hhclwiKTt9LFxyXG4gICAgZ29DaGFyUmlnaHQ6IGZ1bmN0aW9uKGNtKSB7Y20ubW92ZUgoMSwgXCJjaGFyXCIpO30sXHJcbiAgICBnb0NvbHVtbkxlZnQ6IGZ1bmN0aW9uKGNtKSB7Y20ubW92ZUgoLTEsIFwiY29sdW1uXCIpO30sXHJcbiAgICBnb0NvbHVtblJpZ2h0OiBmdW5jdGlvbihjbSkge2NtLm1vdmVIKDEsIFwiY29sdW1uXCIpO30sXHJcbiAgICBnb1dvcmRMZWZ0OiBmdW5jdGlvbihjbSkge2NtLm1vdmVIKC0xLCBcIndvcmRcIik7fSxcclxuICAgIGdvR3JvdXBSaWdodDogZnVuY3Rpb24oY20pIHtjbS5tb3ZlSCgxLCBcImdyb3VwXCIpO30sXHJcbiAgICBnb0dyb3VwTGVmdDogZnVuY3Rpb24oY20pIHtjbS5tb3ZlSCgtMSwgXCJncm91cFwiKTt9LFxyXG4gICAgZ29Xb3JkUmlnaHQ6IGZ1bmN0aW9uKGNtKSB7Y20ubW92ZUgoMSwgXCJ3b3JkXCIpO30sXHJcbiAgICBkZWxDaGFyQmVmb3JlOiBmdW5jdGlvbihjbSkge2NtLmRlbGV0ZUgoLTEsIFwiY2hhclwiKTt9LFxyXG4gICAgZGVsQ2hhckFmdGVyOiBmdW5jdGlvbihjbSkge2NtLmRlbGV0ZUgoMSwgXCJjaGFyXCIpO30sXHJcbiAgICBkZWxXb3JkQmVmb3JlOiBmdW5jdGlvbihjbSkge2NtLmRlbGV0ZUgoLTEsIFwid29yZFwiKTt9LFxyXG4gICAgZGVsV29yZEFmdGVyOiBmdW5jdGlvbihjbSkge2NtLmRlbGV0ZUgoMSwgXCJ3b3JkXCIpO30sXHJcbiAgICBkZWxHcm91cEJlZm9yZTogZnVuY3Rpb24oY20pIHtjbS5kZWxldGVIKC0xLCBcImdyb3VwXCIpO30sXHJcbiAgICBkZWxHcm91cEFmdGVyOiBmdW5jdGlvbihjbSkge2NtLmRlbGV0ZUgoMSwgXCJncm91cFwiKTt9LFxyXG4gICAgaW5kZW50QXV0bzogZnVuY3Rpb24oY20pIHtjbS5pbmRlbnRTZWxlY3Rpb24oXCJzbWFydFwiKTt9LFxyXG4gICAgaW5kZW50TW9yZTogZnVuY3Rpb24oY20pIHtjbS5pbmRlbnRTZWxlY3Rpb24oXCJhZGRcIik7fSxcclxuICAgIGluZGVudExlc3M6IGZ1bmN0aW9uKGNtKSB7Y20uaW5kZW50U2VsZWN0aW9uKFwic3VidHJhY3RcIik7fSxcclxuICAgIGluc2VydFRhYjogZnVuY3Rpb24oY20pIHtjbS5yZXBsYWNlU2VsZWN0aW9uKFwiXFx0XCIpO30sXHJcbiAgICBpbnNlcnRTb2Z0VGFiOiBmdW5jdGlvbihjbSkge1xyXG4gICAgICB2YXIgc3BhY2VzID0gW10sIHJhbmdlcyA9IGNtLmxpc3RTZWxlY3Rpb25zKCksIHRhYlNpemUgPSBjbS5vcHRpb25zLnRhYlNpemU7XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmFuZ2VzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgdmFyIHBvcyA9IHJhbmdlc1tpXS5mcm9tKCk7XHJcbiAgICAgICAgdmFyIGNvbCA9IGNvdW50Q29sdW1uKGNtLmdldExpbmUocG9zLmxpbmUpLCBwb3MuY2gsIHRhYlNpemUpO1xyXG4gICAgICAgIHNwYWNlcy5wdXNoKG5ldyBBcnJheSh0YWJTaXplIC0gY29sICUgdGFiU2l6ZSArIDEpLmpvaW4oXCIgXCIpKTtcclxuICAgICAgfVxyXG4gICAgICBjbS5yZXBsYWNlU2VsZWN0aW9ucyhzcGFjZXMpO1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRUYWI6IGZ1bmN0aW9uKGNtKSB7XHJcbiAgICAgIGlmIChjbS5zb21ldGhpbmdTZWxlY3RlZCgpKSBjbS5pbmRlbnRTZWxlY3Rpb24oXCJhZGRcIik7XHJcbiAgICAgIGVsc2UgY20uZXhlY0NvbW1hbmQoXCJpbnNlcnRUYWJcIik7XHJcbiAgICB9LFxyXG4gICAgdHJhbnNwb3NlQ2hhcnM6IGZ1bmN0aW9uKGNtKSB7XHJcbiAgICAgIHJ1bkluT3AoY20sIGZ1bmN0aW9uKCkge1xyXG4gICAgICAgIHZhciByYW5nZXMgPSBjbS5saXN0U2VsZWN0aW9ucygpLCBuZXdTZWwgPSBbXTtcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJhbmdlcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgdmFyIGN1ciA9IHJhbmdlc1tpXS5oZWFkLCBsaW5lID0gZ2V0TGluZShjbS5kb2MsIGN1ci5saW5lKS50ZXh0O1xyXG4gICAgICAgICAgaWYgKGxpbmUpIHtcclxuICAgICAgICAgICAgaWYgKGN1ci5jaCA9PSBsaW5lLmxlbmd0aCkgY3VyID0gbmV3IFBvcyhjdXIubGluZSwgY3VyLmNoIC0gMSk7XHJcbiAgICAgICAgICAgIGlmIChjdXIuY2ggPiAwKSB7XHJcbiAgICAgICAgICAgICAgY3VyID0gbmV3IFBvcyhjdXIubGluZSwgY3VyLmNoICsgMSk7XHJcbiAgICAgICAgICAgICAgY20ucmVwbGFjZVJhbmdlKGxpbmUuY2hhckF0KGN1ci5jaCAtIDEpICsgbGluZS5jaGFyQXQoY3VyLmNoIC0gMiksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFBvcyhjdXIubGluZSwgY3VyLmNoIC0gMiksIGN1ciwgXCIrdHJhbnNwb3NlXCIpO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGN1ci5saW5lID4gY20uZG9jLmZpcnN0KSB7XHJcbiAgICAgICAgICAgICAgdmFyIHByZXYgPSBnZXRMaW5lKGNtLmRvYywgY3VyLmxpbmUgLSAxKS50ZXh0O1xyXG4gICAgICAgICAgICAgIGlmIChwcmV2KVxyXG4gICAgICAgICAgICAgICAgY20ucmVwbGFjZVJhbmdlKGxpbmUuY2hhckF0KDApICsgY20uZG9jLmxpbmVTZXBhcmF0b3IoKSArXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldi5jaGFyQXQocHJldi5sZW5ndGggLSAxKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBQb3MoY3VyLmxpbmUgLSAxLCBwcmV2Lmxlbmd0aCAtIDEpLCBQb3MoY3VyLmxpbmUsIDEpLCBcIit0cmFuc3Bvc2VcIik7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICAgIG5ld1NlbC5wdXNoKG5ldyBSYW5nZShjdXIsIGN1cikpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjbS5zZXRTZWxlY3Rpb25zKG5ld1NlbCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuICAgIG5ld2xpbmVBbmRJbmRlbnQ6IGZ1bmN0aW9uKGNtKSB7XHJcbiAgICAgIHJ1bkluT3AoY20sIGZ1bmN0aW9uKCkge1xyXG4gICAgICAgIHZhciBsZW4gPSBjbS5saXN0U2VsZWN0aW9ucygpLmxlbmd0aDtcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgaSsrKSB7XHJcbiAgICAgICAgICB2YXIgcmFuZ2UgPSBjbS5saXN0U2VsZWN0aW9ucygpW2ldO1xyXG4gICAgICAgICAgY20ucmVwbGFjZVJhbmdlKGNtLmRvYy5saW5lU2VwYXJhdG9yKCksIHJhbmdlLmFuY2hvciwgcmFuZ2UuaGVhZCwgXCIraW5wdXRcIik7XHJcbiAgICAgICAgICBjbS5pbmRlbnRMaW5lKHJhbmdlLmZyb20oKS5saW5lICsgMSwgbnVsbCwgdHJ1ZSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGVuc3VyZUN1cnNvclZpc2libGUoY20pO1xyXG4gICAgICB9KTtcclxuICAgIH0sXHJcbiAgICB0b2dnbGVPdmVyd3JpdGU6IGZ1bmN0aW9uKGNtKSB7Y20udG9nZ2xlT3ZlcndyaXRlKCk7fVxyXG4gIH07XHJcblxyXG5cclxuICAvLyBTVEFOREFSRCBLRVlNQVBTXHJcblxyXG4gIHZhciBrZXlNYXAgPSBDb2RlTWlycm9yLmtleU1hcCA9IHt9O1xyXG5cclxuICBrZXlNYXAuYmFzaWMgPSB7XHJcbiAgICBcIkxlZnRcIjogXCJnb0NoYXJMZWZ0XCIsIFwiUmlnaHRcIjogXCJnb0NoYXJSaWdodFwiLCBcIlVwXCI6IFwiZ29MaW5lVXBcIiwgXCJEb3duXCI6IFwiZ29MaW5lRG93blwiLFxyXG4gICAgXCJFbmRcIjogXCJnb0xpbmVFbmRcIiwgXCJIb21lXCI6IFwiZ29MaW5lU3RhcnRTbWFydFwiLCBcIlBhZ2VVcFwiOiBcImdvUGFnZVVwXCIsIFwiUGFnZURvd25cIjogXCJnb1BhZ2VEb3duXCIsXHJcbiAgICBcIkRlbGV0ZVwiOiBcImRlbENoYXJBZnRlclwiLCBcIkJhY2tzcGFjZVwiOiBcImRlbENoYXJCZWZvcmVcIiwgXCJTaGlmdC1CYWNrc3BhY2VcIjogXCJkZWxDaGFyQmVmb3JlXCIsXHJcbiAgICBcIlRhYlwiOiBcImRlZmF1bHRUYWJcIiwgXCJTaGlmdC1UYWJcIjogXCJpbmRlbnRBdXRvXCIsXHJcbiAgICBcIkVudGVyXCI6IFwibmV3bGluZUFuZEluZGVudFwiLCBcIkluc2VydFwiOiBcInRvZ2dsZU92ZXJ3cml0ZVwiLFxyXG4gICAgXCJFc2NcIjogXCJzaW5nbGVTZWxlY3Rpb25cIlxyXG4gIH07XHJcbiAgLy8gTm90ZSB0aGF0IHRoZSBzYXZlIGFuZCBmaW5kLXJlbGF0ZWQgY29tbWFuZHMgYXJlbid0IGRlZmluZWQgYnlcclxuICAvLyBkZWZhdWx0LiBVc2VyIGNvZGUgb3IgYWRkb25zIGNhbiBkZWZpbmUgdGhlbS4gVW5rbm93biBjb21tYW5kc1xyXG4gIC8vIGFyZSBzaW1wbHkgaWdub3JlZC5cclxuICBrZXlNYXAucGNEZWZhdWx0ID0ge1xyXG4gICAgXCJDdHJsLUFcIjogXCJzZWxlY3RBbGxcIiwgXCJDdHJsLURcIjogXCJkZWxldGVMaW5lXCIsIFwiQ3RybC1aXCI6IFwidW5kb1wiLCBcIlNoaWZ0LUN0cmwtWlwiOiBcInJlZG9cIiwgXCJDdHJsLVlcIjogXCJyZWRvXCIsXHJcbiAgICBcIkN0cmwtSG9tZVwiOiBcImdvRG9jU3RhcnRcIiwgXCJDdHJsLUVuZFwiOiBcImdvRG9jRW5kXCIsIFwiQ3RybC1VcFwiOiBcImdvTGluZVVwXCIsIFwiQ3RybC1Eb3duXCI6IFwiZ29MaW5lRG93blwiLFxyXG4gICAgXCJDdHJsLUxlZnRcIjogXCJnb0dyb3VwTGVmdFwiLCBcIkN0cmwtUmlnaHRcIjogXCJnb0dyb3VwUmlnaHRcIiwgXCJBbHQtTGVmdFwiOiBcImdvTGluZVN0YXJ0XCIsIFwiQWx0LVJpZ2h0XCI6IFwiZ29MaW5lRW5kXCIsXHJcbiAgICBcIkN0cmwtQmFja3NwYWNlXCI6IFwiZGVsR3JvdXBCZWZvcmVcIiwgXCJDdHJsLURlbGV0ZVwiOiBcImRlbEdyb3VwQWZ0ZXJcIiwgXCJDdHJsLVNcIjogXCJzYXZlXCIsIFwiQ3RybC1GXCI6IFwiZmluZFwiLFxyXG4gICAgXCJDdHJsLUdcIjogXCJmaW5kTmV4dFwiLCBcIlNoaWZ0LUN0cmwtR1wiOiBcImZpbmRQcmV2XCIsIFwiU2hpZnQtQ3RybC1GXCI6IFwicmVwbGFjZVwiLCBcIlNoaWZ0LUN0cmwtUlwiOiBcInJlcGxhY2VBbGxcIixcclxuICAgIFwiQ3RybC1bXCI6IFwiaW5kZW50TGVzc1wiLCBcIkN0cmwtXVwiOiBcImluZGVudE1vcmVcIixcclxuICAgIFwiQ3RybC1VXCI6IFwidW5kb1NlbGVjdGlvblwiLCBcIlNoaWZ0LUN0cmwtVVwiOiBcInJlZG9TZWxlY3Rpb25cIiwgXCJBbHQtVVwiOiBcInJlZG9TZWxlY3Rpb25cIixcclxuICAgIGZhbGx0aHJvdWdoOiBcImJhc2ljXCJcclxuICB9O1xyXG4gIC8vIFZlcnkgYmFzaWMgcmVhZGxpbmUvZW1hY3Mtc3R5bGUgYmluZGluZ3MsIHdoaWNoIGFyZSBzdGFuZGFyZCBvbiBNYWMuXHJcbiAga2V5TWFwLmVtYWNzeSA9IHtcclxuICAgIFwiQ3RybC1GXCI6IFwiZ29DaGFyUmlnaHRcIiwgXCJDdHJsLUJcIjogXCJnb0NoYXJMZWZ0XCIsIFwiQ3RybC1QXCI6IFwiZ29MaW5lVXBcIiwgXCJDdHJsLU5cIjogXCJnb0xpbmVEb3duXCIsXHJcbiAgICBcIkFsdC1GXCI6IFwiZ29Xb3JkUmlnaHRcIiwgXCJBbHQtQlwiOiBcImdvV29yZExlZnRcIiwgXCJDdHJsLUFcIjogXCJnb0xpbmVTdGFydFwiLCBcIkN0cmwtRVwiOiBcImdvTGluZUVuZFwiLFxyXG4gICAgXCJDdHJsLVZcIjogXCJnb1BhZ2VEb3duXCIsIFwiU2hpZnQtQ3RybC1WXCI6IFwiZ29QYWdlVXBcIiwgXCJDdHJsLURcIjogXCJkZWxDaGFyQWZ0ZXJcIiwgXCJDdHJsLUhcIjogXCJkZWxDaGFyQmVmb3JlXCIsXHJcbiAgICBcIkFsdC1EXCI6IFwiZGVsV29yZEFmdGVyXCIsIFwiQWx0LUJhY2tzcGFjZVwiOiBcImRlbFdvcmRCZWZvcmVcIiwgXCJDdHJsLUtcIjogXCJraWxsTGluZVwiLCBcIkN0cmwtVFwiOiBcInRyYW5zcG9zZUNoYXJzXCJcclxuICB9O1xyXG4gIGtleU1hcC5tYWNEZWZhdWx0ID0ge1xyXG4gICAgXCJDbWQtQVwiOiBcInNlbGVjdEFsbFwiLCBcIkNtZC1EXCI6IFwiZGVsZXRlTGluZVwiLCBcIkNtZC1aXCI6IFwidW5kb1wiLCBcIlNoaWZ0LUNtZC1aXCI6IFwicmVkb1wiLCBcIkNtZC1ZXCI6IFwicmVkb1wiLFxyXG4gICAgXCJDbWQtSG9tZVwiOiBcImdvRG9jU3RhcnRcIiwgXCJDbWQtVXBcIjogXCJnb0RvY1N0YXJ0XCIsIFwiQ21kLUVuZFwiOiBcImdvRG9jRW5kXCIsIFwiQ21kLURvd25cIjogXCJnb0RvY0VuZFwiLCBcIkFsdC1MZWZ0XCI6IFwiZ29Hcm91cExlZnRcIixcclxuICAgIFwiQWx0LVJpZ2h0XCI6IFwiZ29Hcm91cFJpZ2h0XCIsIFwiQ21kLUxlZnRcIjogXCJnb0xpbmVMZWZ0XCIsIFwiQ21kLVJpZ2h0XCI6IFwiZ29MaW5lUmlnaHRcIiwgXCJBbHQtQmFja3NwYWNlXCI6IFwiZGVsR3JvdXBCZWZvcmVcIixcclxuICAgIFwiQ3RybC1BbHQtQmFja3NwYWNlXCI6IFwiZGVsR3JvdXBBZnRlclwiLCBcIkFsdC1EZWxldGVcIjogXCJkZWxHcm91cEFmdGVyXCIsIFwiQ21kLVNcIjogXCJzYXZlXCIsIFwiQ21kLUZcIjogXCJmaW5kXCIsXHJcbiAgICBcIkNtZC1HXCI6IFwiZmluZE5leHRcIiwgXCJTaGlmdC1DbWQtR1wiOiBcImZpbmRQcmV2XCIsIFwiQ21kLUFsdC1GXCI6IFwicmVwbGFjZVwiLCBcIlNoaWZ0LUNtZC1BbHQtRlwiOiBcInJlcGxhY2VBbGxcIixcclxuICAgIFwiQ21kLVtcIjogXCJpbmRlbnRMZXNzXCIsIFwiQ21kLV1cIjogXCJpbmRlbnRNb3JlXCIsIFwiQ21kLUJhY2tzcGFjZVwiOiBcImRlbFdyYXBwZWRMaW5lTGVmdFwiLCBcIkNtZC1EZWxldGVcIjogXCJkZWxXcmFwcGVkTGluZVJpZ2h0XCIsXHJcbiAgICBcIkNtZC1VXCI6IFwidW5kb1NlbGVjdGlvblwiLCBcIlNoaWZ0LUNtZC1VXCI6IFwicmVkb1NlbGVjdGlvblwiLCBcIkN0cmwtVXBcIjogXCJnb0RvY1N0YXJ0XCIsIFwiQ3RybC1Eb3duXCI6IFwiZ29Eb2NFbmRcIixcclxuICAgIGZhbGx0aHJvdWdoOiBbXCJiYXNpY1wiLCBcImVtYWNzeVwiXVxyXG4gIH07XHJcbiAga2V5TWFwW1wiZGVmYXVsdFwiXSA9IG1hYyA/IGtleU1hcC5tYWNEZWZhdWx0IDoga2V5TWFwLnBjRGVmYXVsdDtcclxuXHJcbiAgLy8gS0VZTUFQIERJU1BBVENIXHJcblxyXG4gIGZ1bmN0aW9uIG5vcm1hbGl6ZUtleU5hbWUobmFtZSkge1xyXG4gICAgdmFyIHBhcnRzID0gbmFtZS5zcGxpdCgvLSg/ISQpLyksIG5hbWUgPSBwYXJ0c1twYXJ0cy5sZW5ndGggLSAxXTtcclxuICAgIHZhciBhbHQsIGN0cmwsIHNoaWZ0LCBjbWQ7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHBhcnRzLmxlbmd0aCAtIDE7IGkrKykge1xyXG4gICAgICB2YXIgbW9kID0gcGFydHNbaV07XHJcbiAgICAgIGlmICgvXihjbWR8bWV0YXxtKSQvaS50ZXN0KG1vZCkpIGNtZCA9IHRydWU7XHJcbiAgICAgIGVsc2UgaWYgKC9eYShsdCk/JC9pLnRlc3QobW9kKSkgYWx0ID0gdHJ1ZTtcclxuICAgICAgZWxzZSBpZiAoL14oY3xjdHJsfGNvbnRyb2wpJC9pLnRlc3QobW9kKSkgY3RybCA9IHRydWU7XHJcbiAgICAgIGVsc2UgaWYgKC9ecyhoaWZ0KSQvaS50ZXN0KG1vZCkpIHNoaWZ0ID0gdHJ1ZTtcclxuICAgICAgZWxzZSB0aHJvdyBuZXcgRXJyb3IoXCJVbnJlY29nbml6ZWQgbW9kaWZpZXIgbmFtZTogXCIgKyBtb2QpO1xyXG4gICAgfVxyXG4gICAgaWYgKGFsdCkgbmFtZSA9IFwiQWx0LVwiICsgbmFtZTtcclxuICAgIGlmIChjdHJsKSBuYW1lID0gXCJDdHJsLVwiICsgbmFtZTtcclxuICAgIGlmIChjbWQpIG5hbWUgPSBcIkNtZC1cIiArIG5hbWU7XHJcbiAgICBpZiAoc2hpZnQpIG5hbWUgPSBcIlNoaWZ0LVwiICsgbmFtZTtcclxuICAgIHJldHVybiBuYW1lO1xyXG4gIH1cclxuXHJcbiAgLy8gVGhpcyBpcyBhIGtsdWRnZSB0byBrZWVwIGtleW1hcHMgbW9zdGx5IHdvcmtpbmcgYXMgcmF3IG9iamVjdHNcclxuICAvLyAoYmFja3dhcmRzIGNvbXBhdGliaWxpdHkpIHdoaWxlIGF0IHRoZSBzYW1lIHRpbWUgc3VwcG9ydCBmZWF0dXJlc1xyXG4gIC8vIGxpa2Ugbm9ybWFsaXphdGlvbiBhbmQgbXVsdGktc3Ryb2tlIGtleSBiaW5kaW5ncy4gSXQgY29tcGlsZXMgYVxyXG4gIC8vIG5ldyBub3JtYWxpemVkIGtleW1hcCwgYW5kIHRoZW4gdXBkYXRlcyB0aGUgb2xkIG9iamVjdCB0byByZWZsZWN0XHJcbiAgLy8gdGhpcy5cclxuICBDb2RlTWlycm9yLm5vcm1hbGl6ZUtleU1hcCA9IGZ1bmN0aW9uKGtleW1hcCkge1xyXG4gICAgdmFyIGNvcHkgPSB7fTtcclxuICAgIGZvciAodmFyIGtleW5hbWUgaW4ga2V5bWFwKSBpZiAoa2V5bWFwLmhhc093blByb3BlcnR5KGtleW5hbWUpKSB7XHJcbiAgICAgIHZhciB2YWx1ZSA9IGtleW1hcFtrZXluYW1lXTtcclxuICAgICAgaWYgKC9eKG5hbWV8ZmFsbHRocm91Z2h8KGRlfGF0KXRhY2gpJC8udGVzdChrZXluYW1lKSkgY29udGludWU7XHJcbiAgICAgIGlmICh2YWx1ZSA9PSBcIi4uLlwiKSB7IGRlbGV0ZSBrZXltYXBba2V5bmFtZV07IGNvbnRpbnVlOyB9XHJcblxyXG4gICAgICB2YXIga2V5cyA9IG1hcChrZXluYW1lLnNwbGl0KFwiIFwiKSwgbm9ybWFsaXplS2V5TmFtZSk7XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwga2V5cy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIHZhciB2YWwsIG5hbWU7XHJcbiAgICAgICAgaWYgKGkgPT0ga2V5cy5sZW5ndGggLSAxKSB7XHJcbiAgICAgICAgICBuYW1lID0ga2V5cy5qb2luKFwiIFwiKTtcclxuICAgICAgICAgIHZhbCA9IHZhbHVlO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBuYW1lID0ga2V5cy5zbGljZSgwLCBpICsgMSkuam9pbihcIiBcIik7XHJcbiAgICAgICAgICB2YWwgPSBcIi4uLlwiO1xyXG4gICAgICAgIH1cclxuICAgICAgICB2YXIgcHJldiA9IGNvcHlbbmFtZV07XHJcbiAgICAgICAgaWYgKCFwcmV2KSBjb3B5W25hbWVdID0gdmFsO1xyXG4gICAgICAgIGVsc2UgaWYgKHByZXYgIT0gdmFsKSB0aHJvdyBuZXcgRXJyb3IoXCJJbmNvbnNpc3RlbnQgYmluZGluZ3MgZm9yIFwiICsgbmFtZSk7XHJcbiAgICAgIH1cclxuICAgICAgZGVsZXRlIGtleW1hcFtrZXluYW1lXTtcclxuICAgIH1cclxuICAgIGZvciAodmFyIHByb3AgaW4gY29weSkga2V5bWFwW3Byb3BdID0gY29weVtwcm9wXTtcclxuICAgIHJldHVybiBrZXltYXA7XHJcbiAgfTtcclxuXHJcbiAgdmFyIGxvb2t1cEtleSA9IENvZGVNaXJyb3IubG9va3VwS2V5ID0gZnVuY3Rpb24oa2V5LCBtYXAsIGhhbmRsZSwgY29udGV4dCkge1xyXG4gICAgbWFwID0gZ2V0S2V5TWFwKG1hcCk7XHJcbiAgICB2YXIgZm91bmQgPSBtYXAuY2FsbCA/IG1hcC5jYWxsKGtleSwgY29udGV4dCkgOiBtYXBba2V5XTtcclxuICAgIGlmIChmb3VuZCA9PT0gZmFsc2UpIHJldHVybiBcIm5vdGhpbmdcIjtcclxuICAgIGlmIChmb3VuZCA9PT0gXCIuLi5cIikgcmV0dXJuIFwibXVsdGlcIjtcclxuICAgIGlmIChmb3VuZCAhPSBudWxsICYmIGhhbmRsZShmb3VuZCkpIHJldHVybiBcImhhbmRsZWRcIjtcclxuXHJcbiAgICBpZiAobWFwLmZhbGx0aHJvdWdoKSB7XHJcbiAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwobWFwLmZhbGx0aHJvdWdoKSAhPSBcIltvYmplY3QgQXJyYXldXCIpXHJcbiAgICAgICAgcmV0dXJuIGxvb2t1cEtleShrZXksIG1hcC5mYWxsdGhyb3VnaCwgaGFuZGxlLCBjb250ZXh0KTtcclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtYXAuZmFsbHRocm91Z2gubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICB2YXIgcmVzdWx0ID0gbG9va3VwS2V5KGtleSwgbWFwLmZhbGx0aHJvdWdoW2ldLCBoYW5kbGUsIGNvbnRleHQpO1xyXG4gICAgICAgIGlmIChyZXN1bHQpIHJldHVybiByZXN1bHQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBNb2RpZmllciBrZXkgcHJlc3NlcyBkb24ndCBjb3VudCBhcyAncmVhbCcga2V5IHByZXNzZXMgZm9yIHRoZVxyXG4gIC8vIHB1cnBvc2Ugb2Yga2V5bWFwIGZhbGx0aHJvdWdoLlxyXG4gIHZhciBpc01vZGlmaWVyS2V5ID0gQ29kZU1pcnJvci5pc01vZGlmaWVyS2V5ID0gZnVuY3Rpb24odmFsdWUpIHtcclxuICAgIHZhciBuYW1lID0gdHlwZW9mIHZhbHVlID09IFwic3RyaW5nXCIgPyB2YWx1ZSA6IGtleU5hbWVzW3ZhbHVlLmtleUNvZGVdO1xyXG4gICAgcmV0dXJuIG5hbWUgPT0gXCJDdHJsXCIgfHwgbmFtZSA9PSBcIkFsdFwiIHx8IG5hbWUgPT0gXCJTaGlmdFwiIHx8IG5hbWUgPT0gXCJNb2RcIjtcclxuICB9O1xyXG5cclxuICAvLyBMb29rIHVwIHRoZSBuYW1lIG9mIGEga2V5IGFzIGluZGljYXRlZCBieSBhbiBldmVudCBvYmplY3QuXHJcbiAgdmFyIGtleU5hbWUgPSBDb2RlTWlycm9yLmtleU5hbWUgPSBmdW5jdGlvbihldmVudCwgbm9TaGlmdCkge1xyXG4gICAgaWYgKHByZXN0byAmJiBldmVudC5rZXlDb2RlID09IDM0ICYmIGV2ZW50W1wiY2hhclwiXSkgcmV0dXJuIGZhbHNlO1xyXG4gICAgdmFyIGJhc2UgPSBrZXlOYW1lc1tldmVudC5rZXlDb2RlXSwgbmFtZSA9IGJhc2U7XHJcbiAgICBpZiAobmFtZSA9PSBudWxsIHx8IGV2ZW50LmFsdEdyYXBoS2V5KSByZXR1cm4gZmFsc2U7XHJcbiAgICBpZiAoZXZlbnQuYWx0S2V5ICYmIGJhc2UgIT0gXCJBbHRcIikgbmFtZSA9IFwiQWx0LVwiICsgbmFtZTtcclxuICAgIGlmICgoZmxpcEN0cmxDbWQgPyBldmVudC5tZXRhS2V5IDogZXZlbnQuY3RybEtleSkgJiYgYmFzZSAhPSBcIkN0cmxcIikgbmFtZSA9IFwiQ3RybC1cIiArIG5hbWU7XHJcbiAgICBpZiAoKGZsaXBDdHJsQ21kID8gZXZlbnQuY3RybEtleSA6IGV2ZW50Lm1ldGFLZXkpICYmIGJhc2UgIT0gXCJDbWRcIikgbmFtZSA9IFwiQ21kLVwiICsgbmFtZTtcclxuICAgIGlmICghbm9TaGlmdCAmJiBldmVudC5zaGlmdEtleSAmJiBiYXNlICE9IFwiU2hpZnRcIikgbmFtZSA9IFwiU2hpZnQtXCIgKyBuYW1lO1xyXG4gICAgcmV0dXJuIG5hbWU7XHJcbiAgfTtcclxuXHJcbiAgZnVuY3Rpb24gZ2V0S2V5TWFwKHZhbCkge1xyXG4gICAgcmV0dXJuIHR5cGVvZiB2YWwgPT0gXCJzdHJpbmdcIiA/IGtleU1hcFt2YWxdIDogdmFsO1xyXG4gIH1cclxuXHJcbiAgLy8gRlJPTVRFWFRBUkVBXHJcblxyXG4gIENvZGVNaXJyb3IuZnJvbVRleHRBcmVhID0gZnVuY3Rpb24odGV4dGFyZWEsIG9wdGlvbnMpIHtcclxuICAgIG9wdGlvbnMgPSBvcHRpb25zID8gY29weU9iaihvcHRpb25zKSA6IHt9O1xyXG4gICAgb3B0aW9ucy52YWx1ZSA9IHRleHRhcmVhLnZhbHVlO1xyXG4gICAgaWYgKCFvcHRpb25zLnRhYmluZGV4ICYmIHRleHRhcmVhLnRhYkluZGV4KVxyXG4gICAgICBvcHRpb25zLnRhYmluZGV4ID0gdGV4dGFyZWEudGFiSW5kZXg7XHJcbiAgICBpZiAoIW9wdGlvbnMucGxhY2Vob2xkZXIgJiYgdGV4dGFyZWEucGxhY2Vob2xkZXIpXHJcbiAgICAgIG9wdGlvbnMucGxhY2Vob2xkZXIgPSB0ZXh0YXJlYS5wbGFjZWhvbGRlcjtcclxuICAgIC8vIFNldCBhdXRvZm9jdXMgdG8gdHJ1ZSBpZiB0aGlzIHRleHRhcmVhIGlzIGZvY3VzZWQsIG9yIGlmIGl0IGhhc1xyXG4gICAgLy8gYXV0b2ZvY3VzIGFuZCBubyBvdGhlciBlbGVtZW50IGlzIGZvY3VzZWQuXHJcbiAgICBpZiAob3B0aW9ucy5hdXRvZm9jdXMgPT0gbnVsbCkge1xyXG4gICAgICB2YXIgaGFzRm9jdXMgPSBhY3RpdmVFbHQoKTtcclxuICAgICAgb3B0aW9ucy5hdXRvZm9jdXMgPSBoYXNGb2N1cyA9PSB0ZXh0YXJlYSB8fFxyXG4gICAgICAgIHRleHRhcmVhLmdldEF0dHJpYnV0ZShcImF1dG9mb2N1c1wiKSAhPSBudWxsICYmIGhhc0ZvY3VzID09IGRvY3VtZW50LmJvZHk7XHJcbiAgICB9XHJcblxyXG4gICAgZnVuY3Rpb24gc2F2ZSgpIHt0ZXh0YXJlYS52YWx1ZSA9IGNtLmdldFZhbHVlKCk7fVxyXG4gICAgaWYgKHRleHRhcmVhLmZvcm0pIHtcclxuICAgICAgb24odGV4dGFyZWEuZm9ybSwgXCJzdWJtaXRcIiwgc2F2ZSk7XHJcbiAgICAgIC8vIERlcGxvcmFibGUgaGFjayB0byBtYWtlIHRoZSBzdWJtaXQgbWV0aG9kIGRvIHRoZSByaWdodCB0aGluZy5cclxuICAgICAgaWYgKCFvcHRpb25zLmxlYXZlU3VibWl0TWV0aG9kQWxvbmUpIHtcclxuICAgICAgICB2YXIgZm9ybSA9IHRleHRhcmVhLmZvcm0sIHJlYWxTdWJtaXQgPSBmb3JtLnN1Ym1pdDtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgdmFyIHdyYXBwZWRTdWJtaXQgPSBmb3JtLnN1Ym1pdCA9IGZ1bmN0aW9uKCkge1xyXG4gICAgICAgICAgICBzYXZlKCk7XHJcbiAgICAgICAgICAgIGZvcm0uc3VibWl0ID0gcmVhbFN1Ym1pdDtcclxuICAgICAgICAgICAgZm9ybS5zdWJtaXQoKTtcclxuICAgICAgICAgICAgZm9ybS5zdWJtaXQgPSB3cmFwcGVkU3VibWl0O1xyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9IGNhdGNoKGUpIHt9XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBvcHRpb25zLmZpbmlzaEluaXQgPSBmdW5jdGlvbihjbSkge1xyXG4gICAgICBjbS5zYXZlID0gc2F2ZTtcclxuICAgICAgY20uZ2V0VGV4dEFyZWEgPSBmdW5jdGlvbigpIHsgcmV0dXJuIHRleHRhcmVhOyB9O1xyXG4gICAgICBjbS50b1RleHRBcmVhID0gZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgY20udG9UZXh0QXJlYSA9IGlzTmFOOyAvLyBQcmV2ZW50IHRoaXMgZnJvbSBiZWluZyByYW4gdHdpY2VcclxuICAgICAgICBzYXZlKCk7XHJcbiAgICAgICAgdGV4dGFyZWEucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChjbS5nZXRXcmFwcGVyRWxlbWVudCgpKTtcclxuICAgICAgICB0ZXh0YXJlYS5zdHlsZS5kaXNwbGF5ID0gXCJcIjtcclxuICAgICAgICBpZiAodGV4dGFyZWEuZm9ybSkge1xyXG4gICAgICAgICAgb2ZmKHRleHRhcmVhLmZvcm0sIFwic3VibWl0XCIsIHNhdmUpO1xyXG4gICAgICAgICAgaWYgKHR5cGVvZiB0ZXh0YXJlYS5mb3JtLnN1Ym1pdCA9PSBcImZ1bmN0aW9uXCIpXHJcbiAgICAgICAgICAgIHRleHRhcmVhLmZvcm0uc3VibWl0ID0gcmVhbFN1Ym1pdDtcclxuICAgICAgICB9XHJcbiAgICAgIH07XHJcbiAgICB9O1xyXG5cclxuICAgIHRleHRhcmVhLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcclxuICAgIHZhciBjbSA9IENvZGVNaXJyb3IoZnVuY3Rpb24obm9kZSkge1xyXG4gICAgICB0ZXh0YXJlYS5wYXJlbnROb2RlLmluc2VydEJlZm9yZShub2RlLCB0ZXh0YXJlYS5uZXh0U2libGluZyk7XHJcbiAgICB9LCBvcHRpb25zKTtcclxuICAgIHJldHVybiBjbTtcclxuICB9O1xyXG5cclxuICAvLyBTVFJJTkcgU1RSRUFNXHJcblxyXG4gIC8vIEZlZCB0byB0aGUgbW9kZSBwYXJzZXJzLCBwcm92aWRlcyBoZWxwZXIgZnVuY3Rpb25zIHRvIG1ha2VcclxuICAvLyBwYXJzZXJzIG1vcmUgc3VjY2luY3QuXHJcblxyXG4gIHZhciBTdHJpbmdTdHJlYW0gPSBDb2RlTWlycm9yLlN0cmluZ1N0cmVhbSA9IGZ1bmN0aW9uKHN0cmluZywgdGFiU2l6ZSkge1xyXG4gICAgdGhpcy5wb3MgPSB0aGlzLnN0YXJ0ID0gMDtcclxuICAgIHRoaXMuc3RyaW5nID0gc3RyaW5nO1xyXG4gICAgdGhpcy50YWJTaXplID0gdGFiU2l6ZSB8fCA4O1xyXG4gICAgdGhpcy5sYXN0Q29sdW1uUG9zID0gdGhpcy5sYXN0Q29sdW1uVmFsdWUgPSAwO1xyXG4gICAgdGhpcy5saW5lU3RhcnQgPSAwO1xyXG4gIH07XHJcblxyXG4gIFN0cmluZ1N0cmVhbS5wcm90b3R5cGUgPSB7XHJcbiAgICBlb2w6IGZ1bmN0aW9uKCkge3JldHVybiB0aGlzLnBvcyA+PSB0aGlzLnN0cmluZy5sZW5ndGg7fSxcclxuICAgIHNvbDogZnVuY3Rpb24oKSB7cmV0dXJuIHRoaXMucG9zID09IHRoaXMubGluZVN0YXJ0O30sXHJcbiAgICBwZWVrOiBmdW5jdGlvbigpIHtyZXR1cm4gdGhpcy5zdHJpbmcuY2hhckF0KHRoaXMucG9zKSB8fCB1bmRlZmluZWQ7fSxcclxuICAgIG5leHQ6IGZ1bmN0aW9uKCkge1xyXG4gICAgICBpZiAodGhpcy5wb3MgPCB0aGlzLnN0cmluZy5sZW5ndGgpXHJcbiAgICAgICAgcmV0dXJuIHRoaXMuc3RyaW5nLmNoYXJBdCh0aGlzLnBvcysrKTtcclxuICAgIH0sXHJcbiAgICBlYXQ6IGZ1bmN0aW9uKG1hdGNoKSB7XHJcbiAgICAgIHZhciBjaCA9IHRoaXMuc3RyaW5nLmNoYXJBdCh0aGlzLnBvcyk7XHJcbiAgICAgIGlmICh0eXBlb2YgbWF0Y2ggPT0gXCJzdHJpbmdcIikgdmFyIG9rID0gY2ggPT0gbWF0Y2g7XHJcbiAgICAgIGVsc2UgdmFyIG9rID0gY2ggJiYgKG1hdGNoLnRlc3QgPyBtYXRjaC50ZXN0KGNoKSA6IG1hdGNoKGNoKSk7XHJcbiAgICAgIGlmIChvaykgeysrdGhpcy5wb3M7IHJldHVybiBjaDt9XHJcbiAgICB9LFxyXG4gICAgZWF0V2hpbGU6IGZ1bmN0aW9uKG1hdGNoKSB7XHJcbiAgICAgIHZhciBzdGFydCA9IHRoaXMucG9zO1xyXG4gICAgICB3aGlsZSAodGhpcy5lYXQobWF0Y2gpKXt9XHJcbiAgICAgIHJldHVybiB0aGlzLnBvcyA+IHN0YXJ0O1xyXG4gICAgfSxcclxuICAgIGVhdFNwYWNlOiBmdW5jdGlvbigpIHtcclxuICAgICAgdmFyIHN0YXJ0ID0gdGhpcy5wb3M7XHJcbiAgICAgIHdoaWxlICgvW1xcc1xcdTAwYTBdLy50ZXN0KHRoaXMuc3RyaW5nLmNoYXJBdCh0aGlzLnBvcykpKSArK3RoaXMucG9zO1xyXG4gICAgICByZXR1cm4gdGhpcy5wb3MgPiBzdGFydDtcclxuICAgIH0sXHJcbiAgICBza2lwVG9FbmQ6IGZ1bmN0aW9uKCkge3RoaXMucG9zID0gdGhpcy5zdHJpbmcubGVuZ3RoO30sXHJcbiAgICBza2lwVG86IGZ1bmN0aW9uKGNoKSB7XHJcbiAgICAgIHZhciBmb3VuZCA9IHRoaXMuc3RyaW5nLmluZGV4T2YoY2gsIHRoaXMucG9zKTtcclxuICAgICAgaWYgKGZvdW5kID4gLTEpIHt0aGlzLnBvcyA9IGZvdW5kOyByZXR1cm4gdHJ1ZTt9XHJcbiAgICB9LFxyXG4gICAgYmFja1VwOiBmdW5jdGlvbihuKSB7dGhpcy5wb3MgLT0gbjt9LFxyXG4gICAgY29sdW1uOiBmdW5jdGlvbigpIHtcclxuICAgICAgaWYgKHRoaXMubGFzdENvbHVtblBvcyA8IHRoaXMuc3RhcnQpIHtcclxuICAgICAgICB0aGlzLmxhc3RDb2x1bW5WYWx1ZSA9IGNvdW50Q29sdW1uKHRoaXMuc3RyaW5nLCB0aGlzLnN0YXJ0LCB0aGlzLnRhYlNpemUsIHRoaXMubGFzdENvbHVtblBvcywgdGhpcy5sYXN0Q29sdW1uVmFsdWUpO1xyXG4gICAgICAgIHRoaXMubGFzdENvbHVtblBvcyA9IHRoaXMuc3RhcnQ7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRoaXMubGFzdENvbHVtblZhbHVlIC0gKHRoaXMubGluZVN0YXJ0ID8gY291bnRDb2x1bW4odGhpcy5zdHJpbmcsIHRoaXMubGluZVN0YXJ0LCB0aGlzLnRhYlNpemUpIDogMCk7XHJcbiAgICB9LFxyXG4gICAgaW5kZW50YXRpb246IGZ1bmN0aW9uKCkge1xyXG4gICAgICByZXR1cm4gY291bnRDb2x1bW4odGhpcy5zdHJpbmcsIG51bGwsIHRoaXMudGFiU2l6ZSkgLVxyXG4gICAgICAgICh0aGlzLmxpbmVTdGFydCA/IGNvdW50Q29sdW1uKHRoaXMuc3RyaW5nLCB0aGlzLmxpbmVTdGFydCwgdGhpcy50YWJTaXplKSA6IDApO1xyXG4gICAgfSxcclxuICAgIG1hdGNoOiBmdW5jdGlvbihwYXR0ZXJuLCBjb25zdW1lLCBjYXNlSW5zZW5zaXRpdmUpIHtcclxuICAgICAgaWYgKHR5cGVvZiBwYXR0ZXJuID09IFwic3RyaW5nXCIpIHtcclxuICAgICAgICB2YXIgY2FzZWQgPSBmdW5jdGlvbihzdHIpIHtyZXR1cm4gY2FzZUluc2Vuc2l0aXZlID8gc3RyLnRvTG93ZXJDYXNlKCkgOiBzdHI7fTtcclxuICAgICAgICB2YXIgc3Vic3RyID0gdGhpcy5zdHJpbmcuc3Vic3RyKHRoaXMucG9zLCBwYXR0ZXJuLmxlbmd0aCk7XHJcbiAgICAgICAgaWYgKGNhc2VkKHN1YnN0cikgPT0gY2FzZWQocGF0dGVybikpIHtcclxuICAgICAgICAgIGlmIChjb25zdW1lICE9PSBmYWxzZSkgdGhpcy5wb3MgKz0gcGF0dGVybi5sZW5ndGg7XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdmFyIG1hdGNoID0gdGhpcy5zdHJpbmcuc2xpY2UodGhpcy5wb3MpLm1hdGNoKHBhdHRlcm4pO1xyXG4gICAgICAgIGlmIChtYXRjaCAmJiBtYXRjaC5pbmRleCA+IDApIHJldHVybiBudWxsO1xyXG4gICAgICAgIGlmIChtYXRjaCAmJiBjb25zdW1lICE9PSBmYWxzZSkgdGhpcy5wb3MgKz0gbWF0Y2hbMF0ubGVuZ3RoO1xyXG4gICAgICAgIHJldHVybiBtYXRjaDtcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1cnJlbnQ6IGZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc3RyaW5nLnNsaWNlKHRoaXMuc3RhcnQsIHRoaXMucG9zKTt9LFxyXG4gICAgaGlkZUZpcnN0Q2hhcnM6IGZ1bmN0aW9uKG4sIGlubmVyKSB7XHJcbiAgICAgIHRoaXMubGluZVN0YXJ0ICs9IG47XHJcbiAgICAgIHRyeSB7IHJldHVybiBpbm5lcigpOyB9XHJcbiAgICAgIGZpbmFsbHkgeyB0aGlzLmxpbmVTdGFydCAtPSBuOyB9XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgLy8gVEVYVE1BUktFUlNcclxuXHJcbiAgLy8gQ3JlYXRlZCB3aXRoIG1hcmtUZXh0IGFuZCBzZXRCb29rbWFyayBtZXRob2RzLiBBIFRleHRNYXJrZXIgaXMgYVxyXG4gIC8vIGhhbmRsZSB0aGF0IGNhbiBiZSB1c2VkIHRvIGNsZWFyIG9yIGZpbmQgYSBtYXJrZWQgcG9zaXRpb24gaW4gdGhlXHJcbiAgLy8gZG9jdW1lbnQuIExpbmUgb2JqZWN0cyBob2xkIGFycmF5cyAobWFya2VkU3BhbnMpIGNvbnRhaW5pbmdcclxuICAvLyB7ZnJvbSwgdG8sIG1hcmtlcn0gb2JqZWN0IHBvaW50aW5nIHRvIHN1Y2ggbWFya2VyIG9iamVjdHMsIGFuZFxyXG4gIC8vIGluZGljYXRpbmcgdGhhdCBzdWNoIGEgbWFya2VyIGlzIHByZXNlbnQgb24gdGhhdCBsaW5lLiBNdWx0aXBsZVxyXG4gIC8vIGxpbmVzIG1heSBwb2ludCB0byB0aGUgc2FtZSBtYXJrZXIgd2hlbiBpdCBzcGFucyBhY3Jvc3MgbGluZXMuXHJcbiAgLy8gVGhlIHNwYW5zIHdpbGwgaGF2ZSBudWxsIGZvciB0aGVpciBmcm9tL3RvIHByb3BlcnRpZXMgd2hlbiB0aGVcclxuICAvLyBtYXJrZXIgY29udGludWVzIGJleW9uZCB0aGUgc3RhcnQvZW5kIG9mIHRoZSBsaW5lLiBNYXJrZXJzIGhhdmVcclxuICAvLyBsaW5rcyBiYWNrIHRvIHRoZSBsaW5lcyB0aGV5IGN1cnJlbnRseSB0b3VjaC5cclxuXHJcbiAgdmFyIG5leHRNYXJrZXJJZCA9IDA7XHJcblxyXG4gIHZhciBUZXh0TWFya2VyID0gQ29kZU1pcnJvci5UZXh0TWFya2VyID0gZnVuY3Rpb24oZG9jLCB0eXBlKSB7XHJcbiAgICB0aGlzLmxpbmVzID0gW107XHJcbiAgICB0aGlzLnR5cGUgPSB0eXBlO1xyXG4gICAgdGhpcy5kb2MgPSBkb2M7XHJcbiAgICB0aGlzLmlkID0gKytuZXh0TWFya2VySWQ7XHJcbiAgfTtcclxuICBldmVudE1peGluKFRleHRNYXJrZXIpO1xyXG5cclxuICAvLyBDbGVhciB0aGUgbWFya2VyLlxyXG4gIFRleHRNYXJrZXIucHJvdG90eXBlLmNsZWFyID0gZnVuY3Rpb24oKSB7XHJcbiAgICBpZiAodGhpcy5leHBsaWNpdGx5Q2xlYXJlZCkgcmV0dXJuO1xyXG4gICAgdmFyIGNtID0gdGhpcy5kb2MuY20sIHdpdGhPcCA9IGNtICYmICFjbS5jdXJPcDtcclxuICAgIGlmICh3aXRoT3ApIHN0YXJ0T3BlcmF0aW9uKGNtKTtcclxuICAgIGlmIChoYXNIYW5kbGVyKHRoaXMsIFwiY2xlYXJcIikpIHtcclxuICAgICAgdmFyIGZvdW5kID0gdGhpcy5maW5kKCk7XHJcbiAgICAgIGlmIChmb3VuZCkgc2lnbmFsTGF0ZXIodGhpcywgXCJjbGVhclwiLCBmb3VuZC5mcm9tLCBmb3VuZC50byk7XHJcbiAgICB9XHJcbiAgICB2YXIgbWluID0gbnVsbCwgbWF4ID0gbnVsbDtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5saW5lcy5sZW5ndGg7ICsraSkge1xyXG4gICAgICB2YXIgbGluZSA9IHRoaXMubGluZXNbaV07XHJcbiAgICAgIHZhciBzcGFuID0gZ2V0TWFya2VkU3BhbkZvcihsaW5lLm1hcmtlZFNwYW5zLCB0aGlzKTtcclxuICAgICAgaWYgKGNtICYmICF0aGlzLmNvbGxhcHNlZCkgcmVnTGluZUNoYW5nZShjbSwgbGluZU5vKGxpbmUpLCBcInRleHRcIik7XHJcbiAgICAgIGVsc2UgaWYgKGNtKSB7XHJcbiAgICAgICAgaWYgKHNwYW4udG8gIT0gbnVsbCkgbWF4ID0gbGluZU5vKGxpbmUpO1xyXG4gICAgICAgIGlmIChzcGFuLmZyb20gIT0gbnVsbCkgbWluID0gbGluZU5vKGxpbmUpO1xyXG4gICAgICB9XHJcbiAgICAgIGxpbmUubWFya2VkU3BhbnMgPSByZW1vdmVNYXJrZWRTcGFuKGxpbmUubWFya2VkU3BhbnMsIHNwYW4pO1xyXG4gICAgICBpZiAoc3Bhbi5mcm9tID09IG51bGwgJiYgdGhpcy5jb2xsYXBzZWQgJiYgIWxpbmVJc0hpZGRlbih0aGlzLmRvYywgbGluZSkgJiYgY20pXHJcbiAgICAgICAgdXBkYXRlTGluZUhlaWdodChsaW5lLCB0ZXh0SGVpZ2h0KGNtLmRpc3BsYXkpKTtcclxuICAgIH1cclxuICAgIGlmIChjbSAmJiB0aGlzLmNvbGxhcHNlZCAmJiAhY20ub3B0aW9ucy5saW5lV3JhcHBpbmcpIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5saW5lcy5sZW5ndGg7ICsraSkge1xyXG4gICAgICB2YXIgdmlzdWFsID0gdmlzdWFsTGluZSh0aGlzLmxpbmVzW2ldKSwgbGVuID0gbGluZUxlbmd0aCh2aXN1YWwpO1xyXG4gICAgICBpZiAobGVuID4gY20uZGlzcGxheS5tYXhMaW5lTGVuZ3RoKSB7XHJcbiAgICAgICAgY20uZGlzcGxheS5tYXhMaW5lID0gdmlzdWFsO1xyXG4gICAgICAgIGNtLmRpc3BsYXkubWF4TGluZUxlbmd0aCA9IGxlbjtcclxuICAgICAgICBjbS5kaXNwbGF5Lm1heExpbmVDaGFuZ2VkID0gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChtaW4gIT0gbnVsbCAmJiBjbSAmJiB0aGlzLmNvbGxhcHNlZCkgcmVnQ2hhbmdlKGNtLCBtaW4sIG1heCArIDEpO1xyXG4gICAgdGhpcy5saW5lcy5sZW5ndGggPSAwO1xyXG4gICAgdGhpcy5leHBsaWNpdGx5Q2xlYXJlZCA9IHRydWU7XHJcbiAgICBpZiAodGhpcy5hdG9taWMgJiYgdGhpcy5kb2MuY2FudEVkaXQpIHtcclxuICAgICAgdGhpcy5kb2MuY2FudEVkaXQgPSBmYWxzZTtcclxuICAgICAgaWYgKGNtKSByZUNoZWNrU2VsZWN0aW9uKGNtLmRvYyk7XHJcbiAgICB9XHJcbiAgICBpZiAoY20pIHNpZ25hbExhdGVyKGNtLCBcIm1hcmtlckNsZWFyZWRcIiwgY20sIHRoaXMpO1xyXG4gICAgaWYgKHdpdGhPcCkgZW5kT3BlcmF0aW9uKGNtKTtcclxuICAgIGlmICh0aGlzLnBhcmVudCkgdGhpcy5wYXJlbnQuY2xlYXIoKTtcclxuICB9O1xyXG5cclxuICAvLyBGaW5kIHRoZSBwb3NpdGlvbiBvZiB0aGUgbWFya2VyIGluIHRoZSBkb2N1bWVudC4gUmV0dXJucyBhIHtmcm9tLFxyXG4gIC8vIHRvfSBvYmplY3QgYnkgZGVmYXVsdC4gU2lkZSBjYW4gYmUgcGFzc2VkIHRvIGdldCBhIHNwZWNpZmljIHNpZGVcclxuICAvLyAtLSAwIChib3RoKSwgLTEgKGxlZnQpLCBvciAxIChyaWdodCkuIFdoZW4gbGluZU9iaiBpcyB0cnVlLCB0aGVcclxuICAvLyBQb3Mgb2JqZWN0cyByZXR1cm5lZCBjb250YWluIGEgbGluZSBvYmplY3QsIHJhdGhlciB0aGFuIGEgbGluZVxyXG4gIC8vIG51bWJlciAodXNlZCB0byBwcmV2ZW50IGxvb2tpbmcgdXAgdGhlIHNhbWUgbGluZSB0d2ljZSkuXHJcbiAgVGV4dE1hcmtlci5wcm90b3R5cGUuZmluZCA9IGZ1bmN0aW9uKHNpZGUsIGxpbmVPYmopIHtcclxuICAgIGlmIChzaWRlID09IG51bGwgJiYgdGhpcy50eXBlID09IFwiYm9va21hcmtcIikgc2lkZSA9IDE7XHJcbiAgICB2YXIgZnJvbSwgdG87XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGluZXMubGVuZ3RoOyArK2kpIHtcclxuICAgICAgdmFyIGxpbmUgPSB0aGlzLmxpbmVzW2ldO1xyXG4gICAgICB2YXIgc3BhbiA9IGdldE1hcmtlZFNwYW5Gb3IobGluZS5tYXJrZWRTcGFucywgdGhpcyk7XHJcbiAgICAgIGlmIChzcGFuLmZyb20gIT0gbnVsbCkge1xyXG4gICAgICAgIGZyb20gPSBQb3MobGluZU9iaiA/IGxpbmUgOiBsaW5lTm8obGluZSksIHNwYW4uZnJvbSk7XHJcbiAgICAgICAgaWYgKHNpZGUgPT0gLTEpIHJldHVybiBmcm9tO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChzcGFuLnRvICE9IG51bGwpIHtcclxuICAgICAgICB0byA9IFBvcyhsaW5lT2JqID8gbGluZSA6IGxpbmVObyhsaW5lKSwgc3Bhbi50byk7XHJcbiAgICAgICAgaWYgKHNpZGUgPT0gMSkgcmV0dXJuIHRvO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gZnJvbSAmJiB7ZnJvbTogZnJvbSwgdG86IHRvfTtcclxuICB9O1xyXG5cclxuICAvLyBTaWduYWxzIHRoYXQgdGhlIG1hcmtlcidzIHdpZGdldCBjaGFuZ2VkLCBhbmQgc3Vycm91bmRpbmcgbGF5b3V0XHJcbiAgLy8gc2hvdWxkIGJlIHJlY29tcHV0ZWQuXHJcbiAgVGV4dE1hcmtlci5wcm90b3R5cGUuY2hhbmdlZCA9IGZ1bmN0aW9uKCkge1xyXG4gICAgdmFyIHBvcyA9IHRoaXMuZmluZCgtMSwgdHJ1ZSksIHdpZGdldCA9IHRoaXMsIGNtID0gdGhpcy5kb2MuY207XHJcbiAgICBpZiAoIXBvcyB8fCAhY20pIHJldHVybjtcclxuICAgIHJ1bkluT3AoY20sIGZ1bmN0aW9uKCkge1xyXG4gICAgICB2YXIgbGluZSA9IHBvcy5saW5lLCBsaW5lTiA9IGxpbmVObyhwb3MubGluZSk7XHJcbiAgICAgIHZhciB2aWV3ID0gZmluZFZpZXdGb3JMaW5lKGNtLCBsaW5lTik7XHJcbiAgICAgIGlmICh2aWV3KSB7XHJcbiAgICAgICAgY2xlYXJMaW5lTWVhc3VyZW1lbnRDYWNoZUZvcih2aWV3KTtcclxuICAgICAgICBjbS5jdXJPcC5zZWxlY3Rpb25DaGFuZ2VkID0gY20uY3VyT3AuZm9yY2VVcGRhdGUgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIGNtLmN1ck9wLnVwZGF0ZU1heExpbmUgPSB0cnVlO1xyXG4gICAgICBpZiAoIWxpbmVJc0hpZGRlbih3aWRnZXQuZG9jLCBsaW5lKSAmJiB3aWRnZXQuaGVpZ2h0ICE9IG51bGwpIHtcclxuICAgICAgICB2YXIgb2xkSGVpZ2h0ID0gd2lkZ2V0LmhlaWdodDtcclxuICAgICAgICB3aWRnZXQuaGVpZ2h0ID0gbnVsbDtcclxuICAgICAgICB2YXIgZEhlaWdodCA9IHdpZGdldEhlaWdodCh3aWRnZXQpIC0gb2xkSGVpZ2h0O1xyXG4gICAgICAgIGlmIChkSGVpZ2h0KVxyXG4gICAgICAgICAgdXBkYXRlTGluZUhlaWdodChsaW5lLCBsaW5lLmhlaWdodCArIGRIZWlnaHQpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9O1xyXG5cclxuICBUZXh0TWFya2VyLnByb3RvdHlwZS5hdHRhY2hMaW5lID0gZnVuY3Rpb24obGluZSkge1xyXG4gICAgaWYgKCF0aGlzLmxpbmVzLmxlbmd0aCAmJiB0aGlzLmRvYy5jbSkge1xyXG4gICAgICB2YXIgb3AgPSB0aGlzLmRvYy5jbS5jdXJPcDtcclxuICAgICAgaWYgKCFvcC5tYXliZUhpZGRlbk1hcmtlcnMgfHwgaW5kZXhPZihvcC5tYXliZUhpZGRlbk1hcmtlcnMsIHRoaXMpID09IC0xKVxyXG4gICAgICAgIChvcC5tYXliZVVuaGlkZGVuTWFya2VycyB8fCAob3AubWF5YmVVbmhpZGRlbk1hcmtlcnMgPSBbXSkpLnB1c2godGhpcyk7XHJcbiAgICB9XHJcbiAgICB0aGlzLmxpbmVzLnB1c2gobGluZSk7XHJcbiAgfTtcclxuICBUZXh0TWFya2VyLnByb3RvdHlwZS5kZXRhY2hMaW5lID0gZnVuY3Rpb24obGluZSkge1xyXG4gICAgdGhpcy5saW5lcy5zcGxpY2UoaW5kZXhPZih0aGlzLmxpbmVzLCBsaW5lKSwgMSk7XHJcbiAgICBpZiAoIXRoaXMubGluZXMubGVuZ3RoICYmIHRoaXMuZG9jLmNtKSB7XHJcbiAgICAgIHZhciBvcCA9IHRoaXMuZG9jLmNtLmN1ck9wO1xyXG4gICAgICAob3AubWF5YmVIaWRkZW5NYXJrZXJzIHx8IChvcC5tYXliZUhpZGRlbk1hcmtlcnMgPSBbXSkpLnB1c2godGhpcyk7XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgLy8gQ29sbGFwc2VkIG1hcmtlcnMgaGF2ZSB1bmlxdWUgaWRzLCBpbiBvcmRlciB0byBiZSBhYmxlIHRvIG9yZGVyXHJcbiAgLy8gdGhlbSwgd2hpY2ggaXMgbmVlZGVkIGZvciB1bmlxdWVseSBkZXRlcm1pbmluZyBhbiBvdXRlciBtYXJrZXJcclxuICAvLyB3aGVuIHRoZXkgb3ZlcmxhcCAodGhleSBtYXkgbmVzdCwgYnV0IG5vdCBwYXJ0aWFsbHkgb3ZlcmxhcCkuXHJcbiAgdmFyIG5leHRNYXJrZXJJZCA9IDA7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1hcmtlciwgd2lyZSBpdCB1cCB0byB0aGUgcmlnaHQgbGluZXMsIGFuZFxyXG4gIGZ1bmN0aW9uIG1hcmtUZXh0KGRvYywgZnJvbSwgdG8sIG9wdGlvbnMsIHR5cGUpIHtcclxuICAgIC8vIFNoYXJlZCBtYXJrZXJzIChhY3Jvc3MgbGlua2VkIGRvY3VtZW50cykgYXJlIGhhbmRsZWQgc2VwYXJhdGVseVxyXG4gICAgLy8gKG1hcmtUZXh0U2hhcmVkIHdpbGwgY2FsbCBvdXQgdG8gdGhpcyBhZ2Fpbiwgb25jZSBwZXJcclxuICAgIC8vIGRvY3VtZW50KS5cclxuICAgIGlmIChvcHRpb25zICYmIG9wdGlvbnMuc2hhcmVkKSByZXR1cm4gbWFya1RleHRTaGFyZWQoZG9jLCBmcm9tLCB0bywgb3B0aW9ucywgdHlwZSk7XHJcbiAgICAvLyBFbnN1cmUgd2UgYXJlIGluIGFuIG9wZXJhdGlvbi5cclxuICAgIGlmIChkb2MuY20gJiYgIWRvYy5jbS5jdXJPcCkgcmV0dXJuIG9wZXJhdGlvbihkb2MuY20sIG1hcmtUZXh0KShkb2MsIGZyb20sIHRvLCBvcHRpb25zLCB0eXBlKTtcclxuXHJcbiAgICB2YXIgbWFya2VyID0gbmV3IFRleHRNYXJrZXIoZG9jLCB0eXBlKSwgZGlmZiA9IGNtcChmcm9tLCB0byk7XHJcbiAgICBpZiAob3B0aW9ucykgY29weU9iaihvcHRpb25zLCBtYXJrZXIsIGZhbHNlKTtcclxuICAgIC8vIERvbid0IGNvbm5lY3QgZW1wdHkgbWFya2VycyB1bmxlc3MgY2xlYXJXaGVuRW1wdHkgaXMgZmFsc2VcclxuICAgIGlmIChkaWZmID4gMCB8fCBkaWZmID09IDAgJiYgbWFya2VyLmNsZWFyV2hlbkVtcHR5ICE9PSBmYWxzZSlcclxuICAgICAgcmV0dXJuIG1hcmtlcjtcclxuICAgIGlmIChtYXJrZXIucmVwbGFjZWRXaXRoKSB7XHJcbiAgICAgIC8vIFNob3dpbmcgdXAgYXMgYSB3aWRnZXQgaW1wbGllcyBjb2xsYXBzZWQgKHdpZGdldCByZXBsYWNlcyB0ZXh0KVxyXG4gICAgICBtYXJrZXIuY29sbGFwc2VkID0gdHJ1ZTtcclxuICAgICAgbWFya2VyLndpZGdldE5vZGUgPSBlbHQoXCJzcGFuXCIsIFttYXJrZXIucmVwbGFjZWRXaXRoXSwgXCJDb2RlTWlycm9yLXdpZGdldFwiKTtcclxuICAgICAgaWYgKCFvcHRpb25zLmhhbmRsZU1vdXNlRXZlbnRzKSBtYXJrZXIud2lkZ2V0Tm9kZS5zZXRBdHRyaWJ1dGUoXCJjbS1pZ25vcmUtZXZlbnRzXCIsIFwidHJ1ZVwiKTtcclxuICAgICAgaWYgKG9wdGlvbnMuaW5zZXJ0TGVmdCkgbWFya2VyLndpZGdldE5vZGUuaW5zZXJ0TGVmdCA9IHRydWU7XHJcbiAgICB9XHJcbiAgICBpZiAobWFya2VyLmNvbGxhcHNlZCkge1xyXG4gICAgICBpZiAoY29uZmxpY3RpbmdDb2xsYXBzZWRSYW5nZShkb2MsIGZyb20ubGluZSwgZnJvbSwgdG8sIG1hcmtlcikgfHxcclxuICAgICAgICAgIGZyb20ubGluZSAhPSB0by5saW5lICYmIGNvbmZsaWN0aW5nQ29sbGFwc2VkUmFuZ2UoZG9jLCB0by5saW5lLCBmcm9tLCB0bywgbWFya2VyKSlcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnNlcnRpbmcgY29sbGFwc2VkIG1hcmtlciBwYXJ0aWFsbHkgb3ZlcmxhcHBpbmcgYW4gZXhpc3Rpbmcgb25lXCIpO1xyXG4gICAgICBzYXdDb2xsYXBzZWRTcGFucyA9IHRydWU7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKG1hcmtlci5hZGRUb0hpc3RvcnkpXHJcbiAgICAgIGFkZENoYW5nZVRvSGlzdG9yeShkb2MsIHtmcm9tOiBmcm9tLCB0bzogdG8sIG9yaWdpbjogXCJtYXJrVGV4dFwifSwgZG9jLnNlbCwgTmFOKTtcclxuXHJcbiAgICB2YXIgY3VyTGluZSA9IGZyb20ubGluZSwgY20gPSBkb2MuY20sIHVwZGF0ZU1heExpbmU7XHJcbiAgICBkb2MuaXRlcihjdXJMaW5lLCB0by5saW5lICsgMSwgZnVuY3Rpb24obGluZSkge1xyXG4gICAgICBpZiAoY20gJiYgbWFya2VyLmNvbGxhcHNlZCAmJiAhY20ub3B0aW9ucy5saW5lV3JhcHBpbmcgJiYgdmlzdWFsTGluZShsaW5lKSA9PSBjbS5kaXNwbGF5Lm1heExpbmUpXHJcbiAgICAgICAgdXBkYXRlTWF4TGluZSA9IHRydWU7XHJcbiAgICAgIGlmIChtYXJrZXIuY29sbGFwc2VkICYmIGN1ckxpbmUgIT0gZnJvbS5saW5lKSB1cGRhdGVMaW5lSGVpZ2h0KGxpbmUsIDApO1xyXG4gICAgICBhZGRNYXJrZWRTcGFuKGxpbmUsIG5ldyBNYXJrZWRTcGFuKG1hcmtlcixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXJMaW5lID09IGZyb20ubGluZSA/IGZyb20uY2ggOiBudWxsLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1ckxpbmUgPT0gdG8ubGluZSA/IHRvLmNoIDogbnVsbCkpO1xyXG4gICAgICArK2N1ckxpbmU7XHJcbiAgICB9KTtcclxuICAgIC8vIGxpbmVJc0hpZGRlbiBkZXBlbmRzIG9uIHRoZSBwcmVzZW5jZSBvZiB0aGUgc3BhbnMsIHNvIG5lZWRzIGEgc2Vjb25kIHBhc3NcclxuICAgIGlmIChtYXJrZXIuY29sbGFwc2VkKSBkb2MuaXRlcihmcm9tLmxpbmUsIHRvLmxpbmUgKyAxLCBmdW5jdGlvbihsaW5lKSB7XHJcbiAgICAgIGlmIChsaW5lSXNIaWRkZW4oZG9jLCBsaW5lKSkgdXBkYXRlTGluZUhlaWdodChsaW5lLCAwKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGlmIChtYXJrZXIuY2xlYXJPbkVudGVyKSBvbihtYXJrZXIsIFwiYmVmb3JlQ3Vyc29yRW50ZXJcIiwgZnVuY3Rpb24oKSB7IG1hcmtlci5jbGVhcigpOyB9KTtcclxuXHJcbiAgICBpZiAobWFya2VyLnJlYWRPbmx5KSB7XHJcbiAgICAgIHNhd1JlYWRPbmx5U3BhbnMgPSB0cnVlO1xyXG4gICAgICBpZiAoZG9jLmhpc3RvcnkuZG9uZS5sZW5ndGggfHwgZG9jLmhpc3RvcnkudW5kb25lLmxlbmd0aClcclxuICAgICAgICBkb2MuY2xlYXJIaXN0b3J5KCk7XHJcbiAgICB9XHJcbiAgICBpZiAobWFya2VyLmNvbGxhcHNlZCkge1xyXG4gICAgICBtYXJrZXIuaWQgPSArK25leHRNYXJrZXJJZDtcclxuICAgICAgbWFya2VyLmF0b21pYyA9IHRydWU7XHJcbiAgICB9XHJcbiAgICBpZiAoY20pIHtcclxuICAgICAgLy8gU3luYyBlZGl0b3Igc3RhdGVcclxuICAgICAgaWYgKHVwZGF0ZU1heExpbmUpIGNtLmN1ck9wLnVwZGF0ZU1heExpbmUgPSB0cnVlO1xyXG4gICAgICBpZiAobWFya2VyLmNvbGxhcHNlZClcclxuICAgICAgICByZWdDaGFuZ2UoY20sIGZyb20ubGluZSwgdG8ubGluZSArIDEpO1xyXG4gICAgICBlbHNlIGlmIChtYXJrZXIuY2xhc3NOYW1lIHx8IG1hcmtlci50aXRsZSB8fCBtYXJrZXIuc3RhcnRTdHlsZSB8fCBtYXJrZXIuZW5kU3R5bGUgfHwgbWFya2VyLmNzcylcclxuICAgICAgICBmb3IgKHZhciBpID0gZnJvbS5saW5lOyBpIDw9IHRvLmxpbmU7IGkrKykgcmVnTGluZUNoYW5nZShjbSwgaSwgXCJ0ZXh0XCIpO1xyXG4gICAgICBpZiAobWFya2VyLmF0b21pYykgcmVDaGVja1NlbGVjdGlvbihjbS5kb2MpO1xyXG4gICAgICBzaWduYWxMYXRlcihjbSwgXCJtYXJrZXJBZGRlZFwiLCBjbSwgbWFya2VyKTtcclxuICAgIH1cclxuICAgIHJldHVybiBtYXJrZXI7XHJcbiAgfVxyXG5cclxuICAvLyBTSEFSRUQgVEVYVE1BUktFUlNcclxuXHJcbiAgLy8gQSBzaGFyZWQgbWFya2VyIHNwYW5zIG11bHRpcGxlIGxpbmtlZCBkb2N1bWVudHMuIEl0IGlzXHJcbiAgLy8gaW1wbGVtZW50ZWQgYXMgYSBtZXRhLW1hcmtlci1vYmplY3QgY29udHJvbGxpbmcgbXVsdGlwbGUgbm9ybWFsXHJcbiAgLy8gbWFya2Vycy5cclxuICB2YXIgU2hhcmVkVGV4dE1hcmtlciA9IENvZGVNaXJyb3IuU2hhcmVkVGV4dE1hcmtlciA9IGZ1bmN0aW9uKG1hcmtlcnMsIHByaW1hcnkpIHtcclxuICAgIHRoaXMubWFya2VycyA9IG1hcmtlcnM7XHJcbiAgICB0aGlzLnByaW1hcnkgPSBwcmltYXJ5O1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtYXJrZXJzLmxlbmd0aDsgKytpKVxyXG4gICAgICBtYXJrZXJzW2ldLnBhcmVudCA9IHRoaXM7XHJcbiAgfTtcclxuICBldmVudE1peGluKFNoYXJlZFRleHRNYXJrZXIpO1xyXG5cclxuICBTaGFyZWRUZXh0TWFya2VyLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uKCkge1xyXG4gICAgaWYgKHRoaXMuZXhwbGljaXRseUNsZWFyZWQpIHJldHVybjtcclxuICAgIHRoaXMuZXhwbGljaXRseUNsZWFyZWQgPSB0cnVlO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLm1hcmtlcnMubGVuZ3RoOyArK2kpXHJcbiAgICAgIHRoaXMubWFya2Vyc1tpXS5jbGVhcigpO1xyXG4gICAgc2lnbmFsTGF0ZXIodGhpcywgXCJjbGVhclwiKTtcclxuICB9O1xyXG4gIFNoYXJlZFRleHRNYXJrZXIucHJvdG90eXBlLmZpbmQgPSBmdW5jdGlvbihzaWRlLCBsaW5lT2JqKSB7XHJcbiAgICByZXR1cm4gdGhpcy5wcmltYXJ5LmZpbmQoc2lkZSwgbGluZU9iaik7XHJcbiAgfTtcclxuXHJcbiAgZnVuY3Rpb24gbWFya1RleHRTaGFyZWQoZG9jLCBmcm9tLCB0bywgb3B0aW9ucywgdHlwZSkge1xyXG4gICAgb3B0aW9ucyA9IGNvcHlPYmoob3B0aW9ucyk7XHJcbiAgICBvcHRpb25zLnNoYXJlZCA9IGZhbHNlO1xyXG4gICAgdmFyIG1hcmtlcnMgPSBbbWFya1RleHQoZG9jLCBmcm9tLCB0bywgb3B0aW9ucywgdHlwZSldLCBwcmltYXJ5ID0gbWFya2Vyc1swXTtcclxuICAgIHZhciB3aWRnZXQgPSBvcHRpb25zLndpZGdldE5vZGU7XHJcbiAgICBsaW5rZWREb2NzKGRvYywgZnVuY3Rpb24oZG9jKSB7XHJcbiAgICAgIGlmICh3aWRnZXQpIG9wdGlvbnMud2lkZ2V0Tm9kZSA9IHdpZGdldC5jbG9uZU5vZGUodHJ1ZSk7XHJcbiAgICAgIG1hcmtlcnMucHVzaChtYXJrVGV4dChkb2MsIGNsaXBQb3MoZG9jLCBmcm9tKSwgY2xpcFBvcyhkb2MsIHRvKSwgb3B0aW9ucywgdHlwZSkpO1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGRvYy5saW5rZWQubGVuZ3RoOyArK2kpXHJcbiAgICAgICAgaWYgKGRvYy5saW5rZWRbaV0uaXNQYXJlbnQpIHJldHVybjtcclxuICAgICAgcHJpbWFyeSA9IGxzdChtYXJrZXJzKTtcclxuICAgIH0pO1xyXG4gICAgcmV0dXJuIG5ldyBTaGFyZWRUZXh0TWFya2VyKG1hcmtlcnMsIHByaW1hcnkpO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gZmluZFNoYXJlZE1hcmtlcnMoZG9jKSB7XHJcbiAgICByZXR1cm4gZG9jLmZpbmRNYXJrcyhQb3MoZG9jLmZpcnN0LCAwKSwgZG9jLmNsaXBQb3MoUG9zKGRvYy5sYXN0TGluZSgpKSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbihtKSB7IHJldHVybiBtLnBhcmVudDsgfSk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBjb3B5U2hhcmVkTWFya2Vycyhkb2MsIG1hcmtlcnMpIHtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbWFya2Vycy5sZW5ndGg7IGkrKykge1xyXG4gICAgICB2YXIgbWFya2VyID0gbWFya2Vyc1tpXSwgcG9zID0gbWFya2VyLmZpbmQoKTtcclxuICAgICAgdmFyIG1Gcm9tID0gZG9jLmNsaXBQb3MocG9zLmZyb20pLCBtVG8gPSBkb2MuY2xpcFBvcyhwb3MudG8pO1xyXG4gICAgICBpZiAoY21wKG1Gcm9tLCBtVG8pKSB7XHJcbiAgICAgICAgdmFyIHN1Yk1hcmsgPSBtYXJrVGV4dChkb2MsIG1Gcm9tLCBtVG8sIG1hcmtlci5wcmltYXJ5LCBtYXJrZXIucHJpbWFyeS50eXBlKTtcclxuICAgICAgICBtYXJrZXIubWFya2Vycy5wdXNoKHN1Yk1hcmspO1xyXG4gICAgICAgIHN1Yk1hcmsucGFyZW50ID0gbWFya2VyO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBkZXRhY2hTaGFyZWRNYXJrZXJzKG1hcmtlcnMpIHtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbWFya2Vycy5sZW5ndGg7IGkrKykge1xyXG4gICAgICB2YXIgbWFya2VyID0gbWFya2Vyc1tpXSwgbGlua2VkID0gW21hcmtlci5wcmltYXJ5LmRvY107O1xyXG4gICAgICBsaW5rZWREb2NzKG1hcmtlci5wcmltYXJ5LmRvYywgZnVuY3Rpb24oZCkgeyBsaW5rZWQucHVzaChkKTsgfSk7XHJcbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbWFya2VyLm1hcmtlcnMubGVuZ3RoOyBqKyspIHtcclxuICAgICAgICB2YXIgc3ViTWFya2VyID0gbWFya2VyLm1hcmtlcnNbal07XHJcbiAgICAgICAgaWYgKGluZGV4T2YobGlua2VkLCBzdWJNYXJrZXIuZG9jKSA9PSAtMSkge1xyXG4gICAgICAgICAgc3ViTWFya2VyLnBhcmVudCA9IG51bGw7XHJcbiAgICAgICAgICBtYXJrZXIubWFya2Vycy5zcGxpY2Uoai0tLCAxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFRFWFRNQVJLRVIgU1BBTlNcclxuXHJcbiAgZnVuY3Rpb24gTWFya2VkU3BhbihtYXJrZXIsIGZyb20sIHRvKSB7XHJcbiAgICB0aGlzLm1hcmtlciA9IG1hcmtlcjtcclxuICAgIHRoaXMuZnJvbSA9IGZyb207IHRoaXMudG8gPSB0bztcclxuICB9XHJcblxyXG4gIC8vIFNlYXJjaCBhbiBhcnJheSBvZiBzcGFucyBmb3IgYSBzcGFuIG1hdGNoaW5nIHRoZSBnaXZlbiBtYXJrZXIuXHJcbiAgZnVuY3Rpb24gZ2V0TWFya2VkU3BhbkZvcihzcGFucywgbWFya2VyKSB7XHJcbiAgICBpZiAoc3BhbnMpIGZvciAodmFyIGkgPSAwOyBpIDwgc3BhbnMubGVuZ3RoOyArK2kpIHtcclxuICAgICAgdmFyIHNwYW4gPSBzcGFuc1tpXTtcclxuICAgICAgaWYgKHNwYW4ubWFya2VyID09IG1hcmtlcikgcmV0dXJuIHNwYW47XHJcbiAgICB9XHJcbiAgfVxyXG4gIC8vIFJlbW92ZSBhIHNwYW4gZnJvbSBhbiBhcnJheSwgcmV0dXJuaW5nIHVuZGVmaW5lZCBpZiBubyBzcGFucyBhcmVcclxuICAvLyBsZWZ0ICh3ZSBkb24ndCBzdG9yZSBhcnJheXMgZm9yIGxpbmVzIHdpdGhvdXQgc3BhbnMpLlxyXG4gIGZ1bmN0aW9uIHJlbW92ZU1hcmtlZFNwYW4oc3BhbnMsIHNwYW4pIHtcclxuICAgIGZvciAodmFyIHIsIGkgPSAwOyBpIDwgc3BhbnMubGVuZ3RoOyArK2kpXHJcbiAgICAgIGlmIChzcGFuc1tpXSAhPSBzcGFuKSAociB8fCAociA9IFtdKSkucHVzaChzcGFuc1tpXSk7XHJcbiAgICByZXR1cm4gcjtcclxuICB9XHJcbiAgLy8gQWRkIGEgc3BhbiB0byBhIGxpbmUuXHJcbiAgZnVuY3Rpb24gYWRkTWFya2VkU3BhbihsaW5lLCBzcGFuKSB7XHJcbiAgICBsaW5lLm1hcmtlZFNwYW5zID0gbGluZS5tYXJrZWRTcGFucyA/IGxpbmUubWFya2VkU3BhbnMuY29uY2F0KFtzcGFuXSkgOiBbc3Bhbl07XHJcbiAgICBzcGFuLm1hcmtlci5hdHRhY2hMaW5lKGxpbmUpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXNlZCBmb3IgdGhlIGFsZ29yaXRobSB0aGF0IGFkanVzdHMgbWFya2VycyBmb3IgYSBjaGFuZ2UgaW4gdGhlXHJcbiAgLy8gZG9jdW1lbnQuIFRoZXNlIGZ1bmN0aW9ucyBjdXQgYW4gYXJyYXkgb2Ygc3BhbnMgYXQgYSBnaXZlblxyXG4gIC8vIGNoYXJhY3RlciBwb3NpdGlvbiwgcmV0dXJuaW5nIGFuIGFycmF5IG9mIHJlbWFpbmluZyBjaHVua3MgKG9yXHJcbiAgLy8gdW5kZWZpbmVkIGlmIG5vdGhpbmcgcmVtYWlucykuXHJcbiAgZnVuY3Rpb24gbWFya2VkU3BhbnNCZWZvcmUob2xkLCBzdGFydENoLCBpc0luc2VydCkge1xyXG4gICAgaWYgKG9sZCkgZm9yICh2YXIgaSA9IDAsIG53OyBpIDwgb2xkLmxlbmd0aDsgKytpKSB7XHJcbiAgICAgIHZhciBzcGFuID0gb2xkW2ldLCBtYXJrZXIgPSBzcGFuLm1hcmtlcjtcclxuICAgICAgdmFyIHN0YXJ0c0JlZm9yZSA9IHNwYW4uZnJvbSA9PSBudWxsIHx8IChtYXJrZXIuaW5jbHVzaXZlTGVmdCA/IHNwYW4uZnJvbSA8PSBzdGFydENoIDogc3Bhbi5mcm9tIDwgc3RhcnRDaCk7XHJcbiAgICAgIGlmIChzdGFydHNCZWZvcmUgfHwgc3Bhbi5mcm9tID09IHN0YXJ0Q2ggJiYgbWFya2VyLnR5cGUgPT0gXCJib29rbWFya1wiICYmICghaXNJbnNlcnQgfHwgIXNwYW4ubWFya2VyLmluc2VydExlZnQpKSB7XHJcbiAgICAgICAgdmFyIGVuZHNBZnRlciA9IHNwYW4udG8gPT0gbnVsbCB8fCAobWFya2VyLmluY2x1c2l2ZVJpZ2h0ID8gc3Bhbi50byA+PSBzdGFydENoIDogc3Bhbi50byA+IHN0YXJ0Q2gpO1xyXG4gICAgICAgIChudyB8fCAobncgPSBbXSkpLnB1c2gobmV3IE1hcmtlZFNwYW4obWFya2VyLCBzcGFuLmZyb20sIGVuZHNBZnRlciA/IG51bGwgOiBzcGFuLnRvKSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBudztcclxuICB9XHJcbiAgZnVuY3Rpb24gbWFya2VkU3BhbnNBZnRlcihvbGQsIGVuZENoLCBpc0luc2VydCkge1xyXG4gICAgaWYgKG9sZCkgZm9yICh2YXIgaSA9IDAsIG53OyBpIDwgb2xkLmxlbmd0aDsgKytpKSB7XHJcbiAgICAgIHZhciBzcGFuID0gb2xkW2ldLCBtYXJrZXIgPSBzcGFuLm1hcmtlcjtcclxuICAgICAgdmFyIGVuZHNBZnRlciA9IHNwYW4udG8gPT0gbnVsbCB8fCAobWFya2VyLmluY2x1c2l2ZVJpZ2h0ID8gc3Bhbi50byA+PSBlbmRDaCA6IHNwYW4udG8gPiBlbmRDaCk7XHJcbiAgICAgIGlmIChlbmRzQWZ0ZXIgfHwgc3Bhbi5mcm9tID09IGVuZENoICYmIG1hcmtlci50eXBlID09IFwiYm9va21hcmtcIiAmJiAoIWlzSW5zZXJ0IHx8IHNwYW4ubWFya2VyLmluc2VydExlZnQpKSB7XHJcbiAgICAgICAgdmFyIHN0YXJ0c0JlZm9yZSA9IHNwYW4uZnJvbSA9PSBudWxsIHx8IChtYXJrZXIuaW5jbHVzaXZlTGVmdCA/IHNwYW4uZnJvbSA8PSBlbmRDaCA6IHNwYW4uZnJvbSA8IGVuZENoKTtcclxuICAgICAgICAobncgfHwgKG53ID0gW10pKS5wdXNoKG5ldyBNYXJrZWRTcGFuKG1hcmtlciwgc3RhcnRzQmVmb3JlID8gbnVsbCA6IHNwYW4uZnJvbSAtIGVuZENoLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3Bhbi50byA9PSBudWxsID8gbnVsbCA6IHNwYW4udG8gLSBlbmRDaCkpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gbnc7XHJcbiAgfVxyXG5cclxuICAvLyBHaXZlbiBhIGNoYW5nZSBvYmplY3QsIGNvbXB1dGUgdGhlIG5ldyBzZXQgb2YgbWFya2VyIHNwYW5zIHRoYXRcclxuICAvLyBjb3ZlciB0aGUgbGluZSBpbiB3aGljaCB0aGUgY2hhbmdlIHRvb2sgcGxhY2UuIFJlbW92ZXMgc3BhbnNcclxuICAvLyBlbnRpcmVseSB3aXRoaW4gdGhlIGNoYW5nZSwgcmVjb25uZWN0cyBzcGFucyBiZWxvbmdpbmcgdG8gdGhlXHJcbiAgLy8gc2FtZSBtYXJrZXIgdGhhdCBhcHBlYXIgb24gYm90aCBzaWRlcyBvZiB0aGUgY2hhbmdlLCBhbmQgY3V0cyBvZmZcclxuICAvLyBzcGFucyBwYXJ0aWFsbHkgd2l0aGluIHRoZSBjaGFuZ2UuIFJldHVybnMgYW4gYXJyYXkgb2Ygc3BhblxyXG4gIC8vIGFycmF5cyB3aXRoIG9uZSBlbGVtZW50IGZvciBlYWNoIGxpbmUgaW4gKGFmdGVyKSB0aGUgY2hhbmdlLlxyXG4gIGZ1bmN0aW9uIHN0cmV0Y2hTcGFuc092ZXJDaGFuZ2UoZG9jLCBjaGFuZ2UpIHtcclxuICAgIGlmIChjaGFuZ2UuZnVsbCkgcmV0dXJuIG51bGw7XHJcbiAgICB2YXIgb2xkRmlyc3QgPSBpc0xpbmUoZG9jLCBjaGFuZ2UuZnJvbS5saW5lKSAmJiBnZXRMaW5lKGRvYywgY2hhbmdlLmZyb20ubGluZSkubWFya2VkU3BhbnM7XHJcbiAgICB2YXIgb2xkTGFzdCA9IGlzTGluZShkb2MsIGNoYW5nZS50by5saW5lKSAmJiBnZXRMaW5lKGRvYywgY2hhbmdlLnRvLmxpbmUpLm1hcmtlZFNwYW5zO1xyXG4gICAgaWYgKCFvbGRGaXJzdCAmJiAhb2xkTGFzdCkgcmV0dXJuIG51bGw7XHJcblxyXG4gICAgdmFyIHN0YXJ0Q2ggPSBjaGFuZ2UuZnJvbS5jaCwgZW5kQ2ggPSBjaGFuZ2UudG8uY2gsIGlzSW5zZXJ0ID0gY21wKGNoYW5nZS5mcm9tLCBjaGFuZ2UudG8pID09IDA7XHJcbiAgICAvLyBHZXQgdGhlIHNwYW5zIHRoYXQgJ3N0aWNrIG91dCcgb24gYm90aCBzaWRlc1xyXG4gICAgdmFyIGZpcnN0ID0gbWFya2VkU3BhbnNCZWZvcmUob2xkRmlyc3QsIHN0YXJ0Q2gsIGlzSW5zZXJ0KTtcclxuICAgIHZhciBsYXN0ID0gbWFya2VkU3BhbnNBZnRlcihvbGRMYXN0LCBlbmRDaCwgaXNJbnNlcnQpO1xyXG5cclxuICAgIC8vIE5leHQsIG1lcmdlIHRob3NlIHR3byBlbmRzXHJcbiAgICB2YXIgc2FtZUxpbmUgPSBjaGFuZ2UudGV4dC5sZW5ndGggPT0gMSwgb2Zmc2V0ID0gbHN0KGNoYW5nZS50ZXh0KS5sZW5ndGggKyAoc2FtZUxpbmUgPyBzdGFydENoIDogMCk7XHJcbiAgICBpZiAoZmlyc3QpIHtcclxuICAgICAgLy8gRml4IHVwIC50byBwcm9wZXJ0aWVzIG9mIGZpcnN0XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZmlyc3QubGVuZ3RoOyArK2kpIHtcclxuICAgICAgICB2YXIgc3BhbiA9IGZpcnN0W2ldO1xyXG4gICAgICAgIGlmIChzcGFuLnRvID09IG51bGwpIHtcclxuICAgICAgICAgIHZhciBmb3VuZCA9IGdldE1hcmtlZFNwYW5Gb3IobGFzdCwgc3Bhbi5tYXJrZXIpO1xyXG4gICAgICAgICAgaWYgKCFmb3VuZCkgc3Bhbi50byA9IHN0YXJ0Q2g7XHJcbiAgICAgICAgICBlbHNlIGlmIChzYW1lTGluZSkgc3Bhbi50byA9IGZvdW5kLnRvID09IG51bGwgPyBudWxsIDogZm91bmQudG8gKyBvZmZzZXQ7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAobGFzdCkge1xyXG4gICAgICAvLyBGaXggdXAgLmZyb20gaW4gbGFzdCAob3IgbW92ZSB0aGVtIGludG8gZmlyc3QgaW4gY2FzZSBvZiBzYW1lTGluZSlcclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsYXN0Lmxlbmd0aDsgKytpKSB7XHJcbiAgICAgICAgdmFyIHNwYW4gPSBsYXN0W2ldO1xyXG4gICAgICAgIGlmIChzcGFuLnRvICE9IG51bGwpIHNwYW4udG8gKz0gb2Zmc2V0O1xyXG4gICAgICAgIGlmIChzcGFuLmZyb20gPT0gbnVsbCkge1xyXG4gICAgICAgICAgdmFyIGZvdW5kID0gZ2V0TWFya2VkU3BhbkZvcihmaXJzdCwgc3Bhbi5tYXJrZXIpO1xyXG4gICAgICAgICAgaWYgKCFmb3VuZCkge1xyXG4gICAgICAgICAgICBzcGFuLmZyb20gPSBvZmZzZXQ7XHJcbiAgICAgICAgICAgIGlmIChzYW1lTGluZSkgKGZpcnN0IHx8IChmaXJzdCA9IFtdKSkucHVzaChzcGFuKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgc3Bhbi5mcm9tICs9IG9mZnNldDtcclxuICAgICAgICAgIGlmIChzYW1lTGluZSkgKGZpcnN0IHx8IChmaXJzdCA9IFtdKSkucHVzaChzcGFuKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIC8vIE1ha2Ugc3VyZSB3ZSBkaWRuJ3QgY3JlYXRlIGFueSB6ZXJvLWxlbmd0aCBzcGFuc1xyXG4gICAgaWYgKGZpcnN0KSBmaXJzdCA9IGNsZWFyRW1wdHlTcGFucyhmaXJzdCk7XHJcbiAgICBpZiAobGFzdCAmJiBsYXN0ICE9IGZpcnN0KSBsYXN0ID0gY2xlYXJFbXB0eVNwYW5zKGxhc3QpO1xyXG5cclxuICAgIHZhciBuZXdNYXJrZXJzID0gW2ZpcnN0XTtcclxuICAgIGlmICghc2FtZUxpbmUpIHtcclxuICAgICAgLy8gRmlsbCBnYXAgd2l0aCB3aG9sZS1saW5lLXNwYW5zXHJcbiAgICAgIHZhciBnYXAgPSBjaGFuZ2UudGV4dC5sZW5ndGggLSAyLCBnYXBNYXJrZXJzO1xyXG4gICAgICBpZiAoZ2FwID4gMCAmJiBmaXJzdClcclxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGZpcnN0Lmxlbmd0aDsgKytpKVxyXG4gICAgICAgICAgaWYgKGZpcnN0W2ldLnRvID09IG51bGwpXHJcbiAgICAgICAgICAgIChnYXBNYXJrZXJzIHx8IChnYXBNYXJrZXJzID0gW10pKS5wdXNoKG5ldyBNYXJrZWRTcGFuKGZpcnN0W2ldLm1hcmtlciwgbnVsbCwgbnVsbCkpO1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGdhcDsgKytpKVxyXG4gICAgICAgIG5ld01hcmtlcnMucHVzaChnYXBNYXJrZXJzKTtcclxuICAgICAgbmV3TWFya2Vycy5wdXNoKGxhc3QpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIG5ld01hcmtlcnM7XHJcbiAgfVxyXG5cclxuICAvLyBSZW1vdmUgc3BhbnMgdGhhdCBhcmUgZW1wdHkgYW5kIGRvbid0IGhhdmUgYSBjbGVhcldoZW5FbXB0eVxyXG4gIC8vIG9wdGlvbiBvZiBmYWxzZS5cclxuICBmdW5jdGlvbiBjbGVhckVtcHR5U3BhbnMoc3BhbnMpIHtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc3BhbnMubGVuZ3RoOyArK2kpIHtcclxuICAgICAgdmFyIHNwYW4gPSBzcGFuc1tpXTtcclxuICAgICAgaWYgKHNwYW4uZnJvbSAhPSBudWxsICYmIHNwYW4uZnJvbSA9PSBzcGFuLnRvICYmIHNwYW4ubWFya2VyLmNsZWFyV2hlbkVtcHR5ICE9PSBmYWxzZSlcclxuICAgICAgICBzcGFucy5zcGxpY2UoaS0tLCAxKTtcclxuICAgIH1cclxuICAgIGlmICghc3BhbnMubGVuZ3RoKSByZXR1cm4gbnVsbDtcclxuICAgIHJldHVybiBzcGFucztcclxuICB9XHJcblxyXG4gIC8vIFVzZWQgZm9yIHVuL3JlLWRvaW5nIGNoYW5nZXMgZnJvbSB0aGUgaGlzdG9yeS4gQ29tYmluZXMgdGhlXHJcbiAgLy8gcmVzdWx0IG9mIGNvbXB1dGluZyB0aGUgZXhpc3Rpbmcgc3BhbnMgd2l0aCB0aGUgc2V0IG9mIHNwYW5zIHRoYXRcclxuICAvLyBleGlzdGVkIGluIHRoZSBoaXN0b3J5IChzbyB0aGF0IGRlbGV0aW5nIGFyb3VuZCBhIHNwYW4gYW5kIHRoZW5cclxuICAvLyB1bmRvaW5nIGJyaW5ncyBiYWNrIHRoZSBzcGFuKS5cclxuICBmdW5jdGlvbiBtZXJnZU9sZFNwYW5zKGRvYywgY2hhbmdlKSB7XHJcbiAgICB2YXIgb2xkID0gZ2V0T2xkU3BhbnMoZG9jLCBjaGFuZ2UpO1xyXG4gICAgdmFyIHN0cmV0Y2hlZCA9IHN0cmV0Y2hTcGFuc092ZXJDaGFuZ2UoZG9jLCBjaGFuZ2UpO1xyXG4gICAgaWYgKCFvbGQpIHJldHVybiBzdHJldGNoZWQ7XHJcbiAgICBpZiAoIXN0cmV0Y2hlZCkgcmV0dXJuIG9sZDtcclxuXHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG9sZC5sZW5ndGg7ICsraSkge1xyXG4gICAgICB2YXIgb2xkQ3VyID0gb2xkW2ldLCBzdHJldGNoQ3VyID0gc3RyZXRjaGVkW2ldO1xyXG4gICAgICBpZiAob2xkQ3VyICYmIHN0cmV0Y2hDdXIpIHtcclxuICAgICAgICBzcGFuczogZm9yICh2YXIgaiA9IDA7IGogPCBzdHJldGNoQ3VyLmxlbmd0aDsgKytqKSB7XHJcbiAgICAgICAgICB2YXIgc3BhbiA9IHN0cmV0Y2hDdXJbal07XHJcbiAgICAgICAgICBmb3IgKHZhciBrID0gMDsgayA8IG9sZEN1ci5sZW5ndGg7ICsraylcclxuICAgICAgICAgICAgaWYgKG9sZEN1cltrXS5tYXJrZXIgPT0gc3Bhbi5tYXJrZXIpIGNvbnRpbnVlIHNwYW5zO1xyXG4gICAgICAgICAgb2xkQ3VyLnB1c2goc3Bhbik7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2UgaWYgKHN0cmV0Y2hDdXIpIHtcclxuICAgICAgICBvbGRbaV0gPSBzdHJldGNoQ3VyO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gb2xkO1xyXG4gIH1cclxuXHJcbiAgLy8gVXNlZCB0byAnY2xpcCcgb3V0IHJlYWRPbmx5IHJhbmdlcyB3aGVuIG1ha2luZyBhIGNoYW5nZS5cclxuICBmdW5jdGlvbiByZW1vdmVSZWFkT25seVJhbmdlcyhkb2MsIGZyb20sIHRvKSB7XHJcbiAgICB2YXIgbWFya2VycyA9IG51bGw7XHJcbiAgICBkb2MuaXRlcihmcm9tLmxpbmUsIHRvLmxpbmUgKyAxLCBmdW5jdGlvbihsaW5lKSB7XHJcbiAgICAgIGlmIChsaW5lLm1hcmtlZFNwYW5zKSBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmUubWFya2VkU3BhbnMubGVuZ3RoOyArK2kpIHtcclxuICAgICAgICB2YXIgbWFyayA9IGxpbmUubWFya2VkU3BhbnNbaV0ubWFya2VyO1xyXG4gICAgICAgIGlmIChtYXJrLnJlYWRPbmx5ICYmICghbWFya2VycyB8fCBpbmRleE9mKG1hcmtlcnMsIG1hcmspID09IC0xKSlcclxuICAgICAgICAgIChtYXJrZXJzIHx8IChtYXJrZXJzID0gW10pKS5wdXNoKG1hcmspO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICAgIGlmICghbWFya2VycykgcmV0dXJuIG51bGw7XHJcbiAgICB2YXIgcGFydHMgPSBbe2Zyb206IGZyb20sIHRvOiB0b31dO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtYXJrZXJzLmxlbmd0aDsgKytpKSB7XHJcbiAgICAgIHZhciBtayA9IG1hcmtlcnNbaV0sIG0gPSBtay5maW5kKDApO1xyXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHBhcnRzLmxlbmd0aDsgKytqKSB7XHJcbiAgICAgICAgdmFyIHAgPSBwYXJ0c1tqXTtcclxuICAgICAgICBpZiAoY21wKHAudG8sIG0uZnJvbSkgPCAwIHx8IGNtcChwLmZyb20sIG0udG8pID4gMCkgY29udGludWU7XHJcbiAgICAgICAgdmFyIG5ld1BhcnRzID0gW2osIDFdLCBkZnJvbSA9IGNtcChwLmZyb20sIG0uZnJvbSksIGR0byA9IGNtcChwLnRvLCBtLnRvKTtcclxuICAgICAgICBpZiAoZGZyb20gPCAwIHx8ICFtay5pbmNsdXNpdmVMZWZ0ICYmICFkZnJvbSlcclxuICAgICAgICAgIG5ld1BhcnRzLnB1c2goe2Zyb206IHAuZnJvbSwgdG86IG0uZnJvbX0pO1xyXG4gICAgICAgIGlmIChkdG8gPiAwIHx8ICFtay5pbmNsdXNpdmVSaWdodCAmJiAhZHRvKVxyXG4gICAgICAgICAgbmV3UGFydHMucHVzaCh7ZnJvbTogbS50bywgdG86IHAudG99KTtcclxuICAgICAgICBwYXJ0cy5zcGxpY2UuYXBwbHkocGFydHMsIG5ld1BhcnRzKTtcclxuICAgICAgICBqICs9IG5ld1BhcnRzLmxlbmd0aCAtIDE7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiBwYXJ0cztcclxuICB9XHJcblxyXG4gIC8vIENvbm5lY3Qgb3IgZGlzY29ubmVjdCBzcGFucyBmcm9tIGEgbGluZS5cclxuICBmdW5jdGlvbiBkZXRhY2hNYXJrZWRTcGFucyhsaW5lKSB7XHJcbiAgICB2YXIgc3BhbnMgPSBsaW5lLm1hcmtlZFNwYW5zO1xyXG4gICAgaWYgKCFzcGFucykgcmV0dXJuO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzcGFucy5sZW5ndGg7ICsraSlcclxuICAgICAgc3BhbnNbaV0ubWFya2VyLmRldGFjaExpbmUobGluZSk7XHJcbiAgICBsaW5lLm1hcmtlZFNwYW5zID0gbnVsbDtcclxuICB9XHJcbiAgZnVuY3Rpb24gYXR0YWNoTWFya2VkU3BhbnMobGluZSwgc3BhbnMpIHtcclxuICAgIGlmICghc3BhbnMpIHJldHVybjtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc3BhbnMubGVuZ3RoOyArK2kpXHJcbiAgICAgIHNwYW5zW2ldLm1hcmtlci5hdHRhY2hMaW5lKGxpbmUpO1xyXG4gICAgbGluZS5tYXJrZWRTcGFucyA9IHNwYW5zO1xyXG4gIH1cclxuXHJcbiAgLy8gSGVscGVycyB1c2VkIHdoZW4gY29tcHV0aW5nIHdoaWNoIG92ZXJsYXBwaW5nIGNvbGxhcHNlZCBzcGFuXHJcbiAgLy8gY291bnRzIGFzIHRoZSBsYXJnZXIgb25lLlxyXG4gIGZ1bmN0aW9uIGV4dHJhTGVmdChtYXJrZXIpIHsgcmV0dXJuIG1hcmtlci5pbmNsdXNpdmVMZWZ0ID8gLTEgOiAwOyB9XHJcbiAgZnVuY3Rpb24gZXh0cmFSaWdodChtYXJrZXIpIHsgcmV0dXJuIG1hcmtlci5pbmNsdXNpdmVSaWdodCA/IDEgOiAwOyB9XHJcblxyXG4gIC8vIFJldHVybnMgYSBudW1iZXIgaW5kaWNhdGluZyB3aGljaCBvZiB0d28gb3ZlcmxhcHBpbmcgY29sbGFwc2VkXHJcbiAgLy8gc3BhbnMgaXMgbGFyZ2VyIChhbmQgdGh1cyBpbmNsdWRlcyB0aGUgb3RoZXIpLiBGYWxscyBiYWNrIHRvXHJcbiAgLy8gY29tcGFyaW5nIGlkcyB3aGVuIHRoZSBzcGFucyBjb3ZlciBleGFjdGx5IHRoZSBzYW1lIHJhbmdlLlxyXG4gIGZ1bmN0aW9uIGNvbXBhcmVDb2xsYXBzZWRNYXJrZXJzKGEsIGIpIHtcclxuICAgIHZhciBsZW5EaWZmID0gYS5saW5lcy5sZW5ndGggLSBiLmxpbmVzLmxlbmd0aDtcclxuICAgIGlmIChsZW5EaWZmICE9IDApIHJldHVybiBsZW5EaWZmO1xyXG4gICAgdmFyIGFQb3MgPSBhLmZpbmQoKSwgYlBvcyA9IGIuZmluZCgpO1xyXG4gICAgdmFyIGZyb21DbXAgPSBjbXAoYVBvcy5mcm9tLCBiUG9zLmZyb20pIHx8IGV4dHJhTGVmdChhKSAtIGV4dHJhTGVmdChiKTtcclxuICAgIGlmIChmcm9tQ21wKSByZXR1cm4gLWZyb21DbXA7XHJcbiAgICB2YXIgdG9DbXAgPSBjbXAoYVBvcy50bywgYlBvcy50bykgfHwgZXh0cmFSaWdodChhKSAtIGV4dHJhUmlnaHQoYik7XHJcbiAgICBpZiAodG9DbXApIHJldHVybiB0b0NtcDtcclxuICAgIHJldHVybiBiLmlkIC0gYS5pZDtcclxuICB9XHJcblxyXG4gIC8vIEZpbmQgb3V0IHdoZXRoZXIgYSBsaW5lIGVuZHMgb3Igc3RhcnRzIGluIGEgY29sbGFwc2VkIHNwYW4uIElmXHJcbiAgLy8gc28sIHJldHVybiB0aGUgbWFya2VyIGZvciB0aGF0IHNwYW4uXHJcbiAgZnVuY3Rpb24gY29sbGFwc2VkU3BhbkF0U2lkZShsaW5lLCBzdGFydCkge1xyXG4gICAgdmFyIHNwcyA9IHNhd0NvbGxhcHNlZFNwYW5zICYmIGxpbmUubWFya2VkU3BhbnMsIGZvdW5kO1xyXG4gICAgaWYgKHNwcykgZm9yICh2YXIgc3AsIGkgPSAwOyBpIDwgc3BzLmxlbmd0aDsgKytpKSB7XHJcbiAgICAgIHNwID0gc3BzW2ldO1xyXG4gICAgICBpZiAoc3AubWFya2VyLmNvbGxhcHNlZCAmJiAoc3RhcnQgPyBzcC5mcm9tIDogc3AudG8pID09IG51bGwgJiZcclxuICAgICAgICAgICghZm91bmQgfHwgY29tcGFyZUNvbGxhcHNlZE1hcmtlcnMoZm91bmQsIHNwLm1hcmtlcikgPCAwKSlcclxuICAgICAgICBmb3VuZCA9IHNwLm1hcmtlcjtcclxuICAgIH1cclxuICAgIHJldHVybiBmb3VuZDtcclxuICB9XHJcbiAgZnVuY3Rpb24gY29sbGFwc2VkU3BhbkF0U3RhcnQobGluZSkgeyByZXR1cm4gY29sbGFwc2VkU3BhbkF0U2lkZShsaW5lLCB0cnVlKTsgfVxyXG4gIGZ1bmN0aW9uIGNvbGxhcHNlZFNwYW5BdEVuZChsaW5lKSB7IHJldHVybiBjb2xsYXBzZWRTcGFuQXRTaWRlKGxpbmUsIGZhbHNlKTsgfVxyXG5cclxuICAvLyBUZXN0IHdoZXRoZXIgdGhlcmUgZXhpc3RzIGEgY29sbGFwc2VkIHNwYW4gdGhhdCBwYXJ0aWFsbHlcclxuICAvLyBvdmVybGFwcyAoY292ZXJzIHRoZSBzdGFydCBvciBlbmQsIGJ1dCBub3QgYm90aCkgb2YgYSBuZXcgc3Bhbi5cclxuICAvLyBTdWNoIG92ZXJsYXAgaXMgbm90IGFsbG93ZWQuXHJcbiAgZnVuY3Rpb24gY29uZmxpY3RpbmdDb2xsYXBzZWRSYW5nZShkb2MsIGxpbmVObywgZnJvbSwgdG8sIG1hcmtlcikge1xyXG4gICAgdmFyIGxpbmUgPSBnZXRMaW5lKGRvYywgbGluZU5vKTtcclxuICAgIHZhciBzcHMgPSBzYXdDb2xsYXBzZWRTcGFucyAmJiBsaW5lLm1hcmtlZFNwYW5zO1xyXG4gICAgaWYgKHNwcykgZm9yICh2YXIgaSA9IDA7IGkgPCBzcHMubGVuZ3RoOyArK2kpIHtcclxuICAgICAgdmFyIHNwID0gc3BzW2ldO1xyXG4gICAgICBpZiAoIXNwLm1hcmtlci5jb2xsYXBzZWQpIGNvbnRpbnVlO1xyXG4gICAgICB2YXIgZm91bmQgPSBzcC5tYXJrZXIuZmluZCgwKTtcclxuICAgICAgdmFyIGZyb21DbXAgPSBjbXAoZm91bmQuZnJvbSwgZnJvbSkgfHwgZXh0cmFMZWZ0KHNwLm1hcmtlcikgLSBleHRyYUxlZnQobWFya2VyKTtcclxuICAgICAgdmFyIHRvQ21wID0gY21wKGZvdW5kLnRvLCB0bykgfHwgZXh0cmFSaWdodChzcC5tYXJrZXIpIC0gZXh0cmFSaWdodChtYXJrZXIpO1xyXG4gICAgICBpZiAoZnJvbUNtcCA+PSAwICYmIHRvQ21wIDw9IDAgfHwgZnJvbUNtcCA8PSAwICYmIHRvQ21wID49IDApIGNvbnRpbnVlO1xyXG4gICAgICBpZiAoZnJvbUNtcCA8PSAwICYmIChjbXAoZm91bmQudG8sIGZyb20pID4gMCB8fCAoc3AubWFya2VyLmluY2x1c2l2ZVJpZ2h0ICYmIG1hcmtlci5pbmNsdXNpdmVMZWZ0KSkgfHxcclxuICAgICAgICAgIGZyb21DbXAgPj0gMCAmJiAoY21wKGZvdW5kLmZyb20sIHRvKSA8IDAgfHwgKHNwLm1hcmtlci5pbmNsdXNpdmVMZWZ0ICYmIG1hcmtlci5pbmNsdXNpdmVSaWdodCkpKVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQSB2aXN1YWwgbGluZSBpcyBhIGxpbmUgYXMgZHJhd24gb24gdGhlIHNjcmVlbi4gRm9sZGluZywgZm9yXHJcbiAgLy8gZXhhbXBsZSwgY2FuIGNhdXNlIG11bHRpcGxlIGxvZ2ljYWwgbGluZXMgdG8gYXBwZWFyIG9uIHRoZSBzYW1lXHJcbiAgLy8gdmlzdWFsIGxpbmUuIFRoaXMgZmluZHMgdGhlIHN0YXJ0IG9mIHRoZSB2aXN1YWwgbGluZSB0aGF0IHRoZVxyXG4gIC8vIGdpdmVuIGxpbmUgaXMgcGFydCBvZiAodXN1YWxseSB0aGF0IGlzIHRoZSBsaW5lIGl0c2VsZikuXHJcbiAgZnVuY3Rpb24gdmlzdWFsTGluZShsaW5lKSB7XHJcbiAgICB2YXIgbWVyZ2VkO1xyXG4gICAgd2hpbGUgKG1lcmdlZCA9IGNvbGxhcHNlZFNwYW5BdFN0YXJ0KGxpbmUpKVxyXG4gICAgICBsaW5lID0gbWVyZ2VkLmZpbmQoLTEsIHRydWUpLmxpbmU7XHJcbiAgICByZXR1cm4gbGluZTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybnMgYW4gYXJyYXkgb2YgbG9naWNhbCBsaW5lcyB0aGF0IGNvbnRpbnVlIHRoZSB2aXN1YWwgbGluZVxyXG4gIC8vIHN0YXJ0ZWQgYnkgdGhlIGFyZ3VtZW50LCBvciB1bmRlZmluZWQgaWYgdGhlcmUgYXJlIG5vIHN1Y2ggbGluZXMuXHJcbiAgZnVuY3Rpb24gdmlzdWFsTGluZUNvbnRpbnVlZChsaW5lKSB7XHJcbiAgICB2YXIgbWVyZ2VkLCBsaW5lcztcclxuICAgIHdoaWxlIChtZXJnZWQgPSBjb2xsYXBzZWRTcGFuQXRFbmQobGluZSkpIHtcclxuICAgICAgbGluZSA9IG1lcmdlZC5maW5kKDEsIHRydWUpLmxpbmU7XHJcbiAgICAgIChsaW5lcyB8fCAobGluZXMgPSBbXSkpLnB1c2gobGluZSk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gbGluZXM7XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIGxpbmUgbnVtYmVyIG9mIHRoZSBzdGFydCBvZiB0aGUgdmlzdWFsIGxpbmUgdGhhdCB0aGVcclxuICAvLyBnaXZlbiBsaW5lIG51bWJlciBpcyBwYXJ0IG9mLlxyXG4gIGZ1bmN0aW9uIHZpc3VhbExpbmVObyhkb2MsIGxpbmVOKSB7XHJcbiAgICB2YXIgbGluZSA9IGdldExpbmUoZG9jLCBsaW5lTiksIHZpcyA9IHZpc3VhbExpbmUobGluZSk7XHJcbiAgICBpZiAobGluZSA9PSB2aXMpIHJldHVybiBsaW5lTjtcclxuICAgIHJldHVybiBsaW5lTm8odmlzKTtcclxuICB9XHJcbiAgLy8gR2V0IHRoZSBsaW5lIG51bWJlciBvZiB0aGUgc3RhcnQgb2YgdGhlIG5leHQgdmlzdWFsIGxpbmUgYWZ0ZXJcclxuICAvLyB0aGUgZ2l2ZW4gbGluZS5cclxuICBmdW5jdGlvbiB2aXN1YWxMaW5lRW5kTm8oZG9jLCBsaW5lTikge1xyXG4gICAgaWYgKGxpbmVOID4gZG9jLmxhc3RMaW5lKCkpIHJldHVybiBsaW5lTjtcclxuICAgIHZhciBsaW5lID0gZ2V0TGluZShkb2MsIGxpbmVOKSwgbWVyZ2VkO1xyXG4gICAgaWYgKCFsaW5lSXNIaWRkZW4oZG9jLCBsaW5lKSkgcmV0dXJuIGxpbmVOO1xyXG4gICAgd2hpbGUgKG1lcmdlZCA9IGNvbGxhcHNlZFNwYW5BdEVuZChsaW5lKSlcclxuICAgICAgbGluZSA9IG1lcmdlZC5maW5kKDEsIHRydWUpLmxpbmU7XHJcbiAgICByZXR1cm4gbGluZU5vKGxpbmUpICsgMTtcclxuICB9XHJcblxyXG4gIC8vIENvbXB1dGUgd2hldGhlciBhIGxpbmUgaXMgaGlkZGVuLiBMaW5lcyBjb3VudCBhcyBoaWRkZW4gd2hlbiB0aGV5XHJcbiAgLy8gYXJlIHBhcnQgb2YgYSB2aXN1YWwgbGluZSB0aGF0IHN0YXJ0cyB3aXRoIGFub3RoZXIgbGluZSwgb3Igd2hlblxyXG4gIC8vIHRoZXkgYXJlIGVudGlyZWx5IGNvdmVyZWQgYnkgY29sbGFwc2VkLCBub24td2lkZ2V0IHNwYW4uXHJcbiAgZnVuY3Rpb24gbGluZUlzSGlkZGVuKGRvYywgbGluZSkge1xyXG4gICAgdmFyIHNwcyA9IHNhd0NvbGxhcHNlZFNwYW5zICYmIGxpbmUubWFya2VkU3BhbnM7XHJcbiAgICBpZiAoc3BzKSBmb3IgKHZhciBzcCwgaSA9IDA7IGkgPCBzcHMubGVuZ3RoOyArK2kpIHtcclxuICAgICAgc3AgPSBzcHNbaV07XHJcbiAgICAgIGlmICghc3AubWFya2VyLmNvbGxhcHNlZCkgY29udGludWU7XHJcbiAgICAgIGlmIChzcC5mcm9tID09IG51bGwpIHJldHVybiB0cnVlO1xyXG4gICAgICBpZiAoc3AubWFya2VyLndpZGdldE5vZGUpIGNvbnRpbnVlO1xyXG4gICAgICBpZiAoc3AuZnJvbSA9PSAwICYmIHNwLm1hcmtlci5pbmNsdXNpdmVMZWZ0ICYmIGxpbmVJc0hpZGRlbklubmVyKGRvYywgbGluZSwgc3ApKVxyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuICBmdW5jdGlvbiBsaW5lSXNIaWRkZW5Jbm5lcihkb2MsIGxpbmUsIHNwYW4pIHtcclxuICAgIGlmIChzcGFuLnRvID09IG51bGwpIHtcclxuICAgICAgdmFyIGVuZCA9IHNwYW4ubWFya2VyLmZpbmQoMSwgdHJ1ZSk7XHJcbiAgICAgIHJldHVybiBsaW5lSXNIaWRkZW5Jbm5lcihkb2MsIGVuZC5saW5lLCBnZXRNYXJrZWRTcGFuRm9yKGVuZC5saW5lLm1hcmtlZFNwYW5zLCBzcGFuLm1hcmtlcikpO1xyXG4gICAgfVxyXG4gICAgaWYgKHNwYW4ubWFya2VyLmluY2x1c2l2ZVJpZ2h0ICYmIHNwYW4udG8gPT0gbGluZS50ZXh0Lmxlbmd0aClcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICBmb3IgKHZhciBzcCwgaSA9IDA7IGkgPCBsaW5lLm1hcmtlZFNwYW5zLmxlbmd0aDsgKytpKSB7XHJcbiAgICAgIHNwID0gbGluZS5tYXJrZWRTcGFuc1tpXTtcclxuICAgICAgaWYgKHNwLm1hcmtlci5jb2xsYXBzZWQgJiYgIXNwLm1hcmtlci53aWRnZXROb2RlICYmIHNwLmZyb20gPT0gc3Bhbi50byAmJlxyXG4gICAgICAgICAgKHNwLnRvID09IG51bGwgfHwgc3AudG8gIT0gc3Bhbi5mcm9tKSAmJlxyXG4gICAgICAgICAgKHNwLm1hcmtlci5pbmNsdXNpdmVMZWZ0IHx8IHNwYW4ubWFya2VyLmluY2x1c2l2ZVJpZ2h0KSAmJlxyXG4gICAgICAgICAgbGluZUlzSGlkZGVuSW5uZXIoZG9jLCBsaW5lLCBzcCkpIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTElORSBXSURHRVRTXHJcblxyXG4gIC8vIExpbmUgd2lkZ2V0cyBhcmUgYmxvY2sgZWxlbWVudHMgZGlzcGxheWVkIGFib3ZlIG9yIGJlbG93IGEgbGluZS5cclxuXHJcbiAgdmFyIExpbmVXaWRnZXQgPSBDb2RlTWlycm9yLkxpbmVXaWRnZXQgPSBmdW5jdGlvbihkb2MsIG5vZGUsIG9wdGlvbnMpIHtcclxuICAgIGlmIChvcHRpb25zKSBmb3IgKHZhciBvcHQgaW4gb3B0aW9ucykgaWYgKG9wdGlvbnMuaGFzT3duUHJvcGVydHkob3B0KSlcclxuICAgICAgdGhpc1tvcHRdID0gb3B0aW9uc1tvcHRdO1xyXG4gICAgdGhpcy5kb2MgPSBkb2M7XHJcbiAgICB0aGlzLm5vZGUgPSBub2RlO1xyXG4gIH07XHJcbiAgZXZlbnRNaXhpbihMaW5lV2lkZ2V0KTtcclxuXHJcbiAgZnVuY3Rpb24gYWRqdXN0U2Nyb2xsV2hlbkFib3ZlVmlzaWJsZShjbSwgbGluZSwgZGlmZikge1xyXG4gICAgaWYgKGhlaWdodEF0TGluZShsaW5lKSA8ICgoY20uY3VyT3AgJiYgY20uY3VyT3Auc2Nyb2xsVG9wKSB8fCBjbS5kb2Muc2Nyb2xsVG9wKSlcclxuICAgICAgYWRkVG9TY3JvbGxQb3MoY20sIG51bGwsIGRpZmYpO1xyXG4gIH1cclxuXHJcbiAgTGluZVdpZGdldC5wcm90b3R5cGUuY2xlYXIgPSBmdW5jdGlvbigpIHtcclxuICAgIHZhciBjbSA9IHRoaXMuZG9jLmNtLCB3cyA9IHRoaXMubGluZS53aWRnZXRzLCBsaW5lID0gdGhpcy5saW5lLCBubyA9IGxpbmVObyhsaW5lKTtcclxuICAgIGlmIChubyA9PSBudWxsIHx8ICF3cykgcmV0dXJuO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB3cy5sZW5ndGg7ICsraSkgaWYgKHdzW2ldID09IHRoaXMpIHdzLnNwbGljZShpLS0sIDEpO1xyXG4gICAgaWYgKCF3cy5sZW5ndGgpIGxpbmUud2lkZ2V0cyA9IG51bGw7XHJcbiAgICB2YXIgaGVpZ2h0ID0gd2lkZ2V0SGVpZ2h0KHRoaXMpO1xyXG4gICAgdXBkYXRlTGluZUhlaWdodChsaW5lLCBNYXRoLm1heCgwLCBsaW5lLmhlaWdodCAtIGhlaWdodCkpO1xyXG4gICAgaWYgKGNtKSBydW5Jbk9wKGNtLCBmdW5jdGlvbigpIHtcclxuICAgICAgYWRqdXN0U2Nyb2xsV2hlbkFib3ZlVmlzaWJsZShjbSwgbGluZSwgLWhlaWdodCk7XHJcbiAgICAgIHJlZ0xpbmVDaGFuZ2UoY20sIG5vLCBcIndpZGdldFwiKTtcclxuICAgIH0pO1xyXG4gIH07XHJcbiAgTGluZVdpZGdldC5wcm90b3R5cGUuY2hhbmdlZCA9IGZ1bmN0aW9uKCkge1xyXG4gICAgdmFyIG9sZEggPSB0aGlzLmhlaWdodCwgY20gPSB0aGlzLmRvYy5jbSwgbGluZSA9IHRoaXMubGluZTtcclxuICAgIHRoaXMuaGVpZ2h0ID0gbnVsbDtcclxuICAgIHZhciBkaWZmID0gd2lkZ2V0SGVpZ2h0KHRoaXMpIC0gb2xkSDtcclxuICAgIGlmICghZGlmZikgcmV0dXJuO1xyXG4gICAgdXBkYXRlTGluZUhlaWdodChsaW5lLCBsaW5lLmhlaWdodCArIGRpZmYpO1xyXG4gICAgaWYgKGNtKSBydW5Jbk9wKGNtLCBmdW5jdGlvbigpIHtcclxuICAgICAgY20uY3VyT3AuZm9yY2VVcGRhdGUgPSB0cnVlO1xyXG4gICAgICBhZGp1c3RTY3JvbGxXaGVuQWJvdmVWaXNpYmxlKGNtLCBsaW5lLCBkaWZmKTtcclxuICAgIH0pO1xyXG4gIH07XHJcblxyXG4gIGZ1bmN0aW9uIHdpZGdldEhlaWdodCh3aWRnZXQpIHtcclxuICAgIGlmICh3aWRnZXQuaGVpZ2h0ICE9IG51bGwpIHJldHVybiB3aWRnZXQuaGVpZ2h0O1xyXG4gICAgdmFyIGNtID0gd2lkZ2V0LmRvYy5jbTtcclxuICAgIGlmICghY20pIHJldHVybiAwO1xyXG4gICAgaWYgKCFjb250YWlucyhkb2N1bWVudC5ib2R5LCB3aWRnZXQubm9kZSkpIHtcclxuICAgICAgdmFyIHBhcmVudFN0eWxlID0gXCJwb3NpdGlvbjogcmVsYXRpdmU7XCI7XHJcbiAgICAgIGlmICh3aWRnZXQuY292ZXJHdXR0ZXIpXHJcbiAgICAgICAgcGFyZW50U3R5bGUgKz0gXCJtYXJnaW4tbGVmdDogLVwiICsgY20uZGlzcGxheS5ndXR0ZXJzLm9mZnNldFdpZHRoICsgXCJweDtcIjtcclxuICAgICAgaWYgKHdpZGdldC5ub0hTY3JvbGwpXHJcbiAgICAgICAgcGFyZW50U3R5bGUgKz0gXCJ3aWR0aDogXCIgKyBjbS5kaXNwbGF5LndyYXBwZXIuY2xpZW50V2lkdGggKyBcInB4O1wiO1xyXG4gICAgICByZW1vdmVDaGlsZHJlbkFuZEFkZChjbS5kaXNwbGF5Lm1lYXN1cmUsIGVsdChcImRpdlwiLCBbd2lkZ2V0Lm5vZGVdLCBudWxsLCBwYXJlbnRTdHlsZSkpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHdpZGdldC5oZWlnaHQgPSB3aWRnZXQubm9kZS5wYXJlbnROb2RlLm9mZnNldEhlaWdodDtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGFkZExpbmVXaWRnZXQoZG9jLCBoYW5kbGUsIG5vZGUsIG9wdGlvbnMpIHtcclxuICAgIHZhciB3aWRnZXQgPSBuZXcgTGluZVdpZGdldChkb2MsIG5vZGUsIG9wdGlvbnMpO1xyXG4gICAgdmFyIGNtID0gZG9jLmNtO1xyXG4gICAgaWYgKGNtICYmIHdpZGdldC5ub0hTY3JvbGwpIGNtLmRpc3BsYXkuYWxpZ25XaWRnZXRzID0gdHJ1ZTtcclxuICAgIGNoYW5nZUxpbmUoZG9jLCBoYW5kbGUsIFwid2lkZ2V0XCIsIGZ1bmN0aW9uKGxpbmUpIHtcclxuICAgICAgdmFyIHdpZGdldHMgPSBsaW5lLndpZGdldHMgfHwgKGxpbmUud2lkZ2V0cyA9IFtdKTtcclxuICAgICAgaWYgKHdpZGdldC5pbnNlcnRBdCA9PSBudWxsKSB3aWRnZXRzLnB1c2god2lkZ2V0KTtcclxuICAgICAgZWxzZSB3aWRnZXRzLnNwbGljZShNYXRoLm1pbih3aWRnZXRzLmxlbmd0aCAtIDEsIE1hdGgubWF4KDAsIHdpZGdldC5pbnNlcnRBdCkpLCAwLCB3aWRnZXQpO1xyXG4gICAgICB3aWRnZXQubGluZSA9IGxpbmU7XHJcbiAgICAgIGlmIChjbSAmJiAhbGluZUlzSGlkZGVuKGRvYywgbGluZSkpIHtcclxuICAgICAgICB2YXIgYWJvdmVWaXNpYmxlID0gaGVpZ2h0QXRMaW5lKGxpbmUpIDwgZG9jLnNjcm9sbFRvcDtcclxuICAgICAgICB1cGRhdGVMaW5lSGVpZ2h0KGxpbmUsIGxpbmUuaGVpZ2h0ICsgd2lkZ2V0SGVpZ2h0KHdpZGdldCkpO1xyXG4gICAgICAgIGlmIChhYm92ZVZpc2libGUpIGFkZFRvU2Nyb2xsUG9zKGNtLCBudWxsLCB3aWRnZXQuaGVpZ2h0KTtcclxuICAgICAgICBjbS5jdXJPcC5mb3JjZVVwZGF0ZSA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9KTtcclxuICAgIHJldHVybiB3aWRnZXQ7XHJcbiAgfVxyXG5cclxuICAvLyBMSU5FIERBVEEgU1RSVUNUVVJFXHJcblxyXG4gIC8vIExpbmUgb2JqZWN0cy4gVGhlc2UgaG9sZCBzdGF0ZSByZWxhdGVkIHRvIGEgbGluZSwgaW5jbHVkaW5nXHJcbiAgLy8gaGlnaGxpZ2h0aW5nIGluZm8gKHRoZSBzdHlsZXMgYXJyYXkpLlxyXG4gIHZhciBMaW5lID0gQ29kZU1pcnJvci5MaW5lID0gZnVuY3Rpb24odGV4dCwgbWFya2VkU3BhbnMsIGVzdGltYXRlSGVpZ2h0KSB7XHJcbiAgICB0aGlzLnRleHQgPSB0ZXh0O1xyXG4gICAgYXR0YWNoTWFya2VkU3BhbnModGhpcywgbWFya2VkU3BhbnMpO1xyXG4gICAgdGhpcy5oZWlnaHQgPSBlc3RpbWF0ZUhlaWdodCA/IGVzdGltYXRlSGVpZ2h0KHRoaXMpIDogMTtcclxuICB9O1xyXG4gIGV2ZW50TWl4aW4oTGluZSk7XHJcbiAgTGluZS5wcm90b3R5cGUubGluZU5vID0gZnVuY3Rpb24oKSB7IHJldHVybiBsaW5lTm8odGhpcyk7IH07XHJcblxyXG4gIC8vIENoYW5nZSB0aGUgY29udGVudCAodGV4dCwgbWFya2Vycykgb2YgYSBsaW5lLiBBdXRvbWF0aWNhbGx5XHJcbiAgLy8gaW52YWxpZGF0ZXMgY2FjaGVkIGluZm9ybWF0aW9uIGFuZCB0cmllcyB0byByZS1lc3RpbWF0ZSB0aGVcclxuICAvLyBsaW5lJ3MgaGVpZ2h0LlxyXG4gIGZ1bmN0aW9uIHVwZGF0ZUxpbmUobGluZSwgdGV4dCwgbWFya2VkU3BhbnMsIGVzdGltYXRlSGVpZ2h0KSB7XHJcbiAgICBsaW5lLnRleHQgPSB0ZXh0O1xyXG4gICAgaWYgKGxpbmUuc3RhdGVBZnRlcikgbGluZS5zdGF0ZUFmdGVyID0gbnVsbDtcclxuICAgIGlmIChsaW5lLnN0eWxlcykgbGluZS5zdHlsZXMgPSBudWxsO1xyXG4gICAgaWYgKGxpbmUub3JkZXIgIT0gbnVsbCkgbGluZS5vcmRlciA9IG51bGw7XHJcbiAgICBkZXRhY2hNYXJrZWRTcGFucyhsaW5lKTtcclxuICAgIGF0dGFjaE1hcmtlZFNwYW5zKGxpbmUsIG1hcmtlZFNwYW5zKTtcclxuICAgIHZhciBlc3RIZWlnaHQgPSBlc3RpbWF0ZUhlaWdodCA/IGVzdGltYXRlSGVpZ2h0KGxpbmUpIDogMTtcclxuICAgIGlmIChlc3RIZWlnaHQgIT0gbGluZS5oZWlnaHQpIHVwZGF0ZUxpbmVIZWlnaHQobGluZSwgZXN0SGVpZ2h0KTtcclxuICB9XHJcblxyXG4gIC8vIERldGFjaCBhIGxpbmUgZnJvbSB0aGUgZG9jdW1lbnQgdHJlZSBhbmQgaXRzIG1hcmtlcnMuXHJcbiAgZnVuY3Rpb24gY2xlYW5VcExpbmUobGluZSkge1xyXG4gICAgbGluZS5wYXJlbnQgPSBudWxsO1xyXG4gICAgZGV0YWNoTWFya2VkU3BhbnMobGluZSk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBleHRyYWN0TGluZUNsYXNzZXModHlwZSwgb3V0cHV0KSB7XHJcbiAgICBpZiAodHlwZSkgZm9yICg7Oykge1xyXG4gICAgICB2YXIgbGluZUNsYXNzID0gdHlwZS5tYXRjaCgvKD86XnxcXHMrKWxpbmUtKGJhY2tncm91bmQtKT8oXFxTKykvKTtcclxuICAgICAgaWYgKCFsaW5lQ2xhc3MpIGJyZWFrO1xyXG4gICAgICB0eXBlID0gdHlwZS5zbGljZSgwLCBsaW5lQ2xhc3MuaW5kZXgpICsgdHlwZS5zbGljZShsaW5lQ2xhc3MuaW5kZXggKyBsaW5lQ2xhc3NbMF0ubGVuZ3RoKTtcclxuICAgICAgdmFyIHByb3AgPSBsaW5lQ2xhc3NbMV0gPyBcImJnQ2xhc3NcIiA6IFwidGV4dENsYXNzXCI7XHJcbiAgICAgIGlmIChvdXRwdXRbcHJvcF0gPT0gbnVsbClcclxuICAgICAgICBvdXRwdXRbcHJvcF0gPSBsaW5lQ2xhc3NbMl07XHJcbiAgICAgIGVsc2UgaWYgKCEobmV3IFJlZ0V4cChcIig/Ol58XFxzKVwiICsgbGluZUNsYXNzWzJdICsgXCIoPzokfFxccylcIikpLnRlc3Qob3V0cHV0W3Byb3BdKSlcclxuICAgICAgICBvdXRwdXRbcHJvcF0gKz0gXCIgXCIgKyBsaW5lQ2xhc3NbMl07XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdHlwZTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGNhbGxCbGFua0xpbmUobW9kZSwgc3RhdGUpIHtcclxuICAgIGlmIChtb2RlLmJsYW5rTGluZSkgcmV0dXJuIG1vZGUuYmxhbmtMaW5lKHN0YXRlKTtcclxuICAgIGlmICghbW9kZS5pbm5lck1vZGUpIHJldHVybjtcclxuICAgIHZhciBpbm5lciA9IENvZGVNaXJyb3IuaW5uZXJNb2RlKG1vZGUsIHN0YXRlKTtcclxuICAgIGlmIChpbm5lci5tb2RlLmJsYW5rTGluZSkgcmV0dXJuIGlubmVyLm1vZGUuYmxhbmtMaW5lKGlubmVyLnN0YXRlKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIHJlYWRUb2tlbihtb2RlLCBzdHJlYW0sIHN0YXRlLCBpbm5lcikge1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCAxMDsgaSsrKSB7XHJcbiAgICAgIGlmIChpbm5lcikgaW5uZXJbMF0gPSBDb2RlTWlycm9yLmlubmVyTW9kZShtb2RlLCBzdGF0ZSkubW9kZTtcclxuICAgICAgdmFyIHN0eWxlID0gbW9kZS50b2tlbihzdHJlYW0sIHN0YXRlKTtcclxuICAgICAgaWYgKHN0cmVhbS5wb3MgPiBzdHJlYW0uc3RhcnQpIHJldHVybiBzdHlsZTtcclxuICAgIH1cclxuICAgIHRocm93IG5ldyBFcnJvcihcIk1vZGUgXCIgKyBtb2RlLm5hbWUgKyBcIiBmYWlsZWQgdG8gYWR2YW5jZSBzdHJlYW0uXCIpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXRpbGl0eSBmb3IgZ2V0VG9rZW5BdCBhbmQgZ2V0TGluZVRva2Vuc1xyXG4gIGZ1bmN0aW9uIHRha2VUb2tlbihjbSwgcG9zLCBwcmVjaXNlLCBhc0FycmF5KSB7XHJcbiAgICBmdW5jdGlvbiBnZXRPYmooY29weSkge1xyXG4gICAgICByZXR1cm4ge3N0YXJ0OiBzdHJlYW0uc3RhcnQsIGVuZDogc3RyZWFtLnBvcyxcclxuICAgICAgICAgICAgICBzdHJpbmc6IHN0cmVhbS5jdXJyZW50KCksXHJcbiAgICAgICAgICAgICAgdHlwZTogc3R5bGUgfHwgbnVsbCxcclxuICAgICAgICAgICAgICBzdGF0ZTogY29weSA/IGNvcHlTdGF0ZShkb2MubW9kZSwgc3RhdGUpIDogc3RhdGV9O1xyXG4gICAgfVxyXG5cclxuICAgIHZhciBkb2MgPSBjbS5kb2MsIG1vZGUgPSBkb2MubW9kZSwgc3R5bGU7XHJcbiAgICBwb3MgPSBjbGlwUG9zKGRvYywgcG9zKTtcclxuICAgIHZhciBsaW5lID0gZ2V0TGluZShkb2MsIHBvcy5saW5lKSwgc3RhdGUgPSBnZXRTdGF0ZUJlZm9yZShjbSwgcG9zLmxpbmUsIHByZWNpc2UpO1xyXG4gICAgdmFyIHN0cmVhbSA9IG5ldyBTdHJpbmdTdHJlYW0obGluZS50ZXh0LCBjbS5vcHRpb25zLnRhYlNpemUpLCB0b2tlbnM7XHJcbiAgICBpZiAoYXNBcnJheSkgdG9rZW5zID0gW107XHJcbiAgICB3aGlsZSAoKGFzQXJyYXkgfHwgc3RyZWFtLnBvcyA8IHBvcy5jaCkgJiYgIXN0cmVhbS5lb2woKSkge1xyXG4gICAgICBzdHJlYW0uc3RhcnQgPSBzdHJlYW0ucG9zO1xyXG4gICAgICBzdHlsZSA9IHJlYWRUb2tlbihtb2RlLCBzdHJlYW0sIHN0YXRlKTtcclxuICAgICAgaWYgKGFzQXJyYXkpIHRva2Vucy5wdXNoKGdldE9iaih0cnVlKSk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gYXNBcnJheSA/IHRva2VucyA6IGdldE9iaigpO1xyXG4gIH1cclxuXHJcbiAgLy8gUnVuIHRoZSBnaXZlbiBtb2RlJ3MgcGFyc2VyIG92ZXIgYSBsaW5lLCBjYWxsaW5nIGYgZm9yIGVhY2ggdG9rZW4uXHJcbiAgZnVuY3Rpb24gcnVuTW9kZShjbSwgdGV4dCwgbW9kZSwgc3RhdGUsIGYsIGxpbmVDbGFzc2VzLCBmb3JjZVRvRW5kKSB7XHJcbiAgICB2YXIgZmxhdHRlblNwYW5zID0gbW9kZS5mbGF0dGVuU3BhbnM7XHJcbiAgICBpZiAoZmxhdHRlblNwYW5zID09IG51bGwpIGZsYXR0ZW5TcGFucyA9IGNtLm9wdGlvbnMuZmxhdHRlblNwYW5zO1xyXG4gICAgdmFyIGN1clN0YXJ0ID0gMCwgY3VyU3R5bGUgPSBudWxsO1xyXG4gICAgdmFyIHN0cmVhbSA9IG5ldyBTdHJpbmdTdHJlYW0odGV4dCwgY20ub3B0aW9ucy50YWJTaXplKSwgc3R5bGU7XHJcbiAgICB2YXIgaW5uZXIgPSBjbS5vcHRpb25zLmFkZE1vZGVDbGFzcyAmJiBbbnVsbF07XHJcbiAgICBpZiAodGV4dCA9PSBcIlwiKSBleHRyYWN0TGluZUNsYXNzZXMoY2FsbEJsYW5rTGluZShtb2RlLCBzdGF0ZSksIGxpbmVDbGFzc2VzKTtcclxuICAgIHdoaWxlICghc3RyZWFtLmVvbCgpKSB7XHJcbiAgICAgIGlmIChzdHJlYW0ucG9zID4gY20ub3B0aW9ucy5tYXhIaWdobGlnaHRMZW5ndGgpIHtcclxuICAgICAgICBmbGF0dGVuU3BhbnMgPSBmYWxzZTtcclxuICAgICAgICBpZiAoZm9yY2VUb0VuZCkgcHJvY2Vzc0xpbmUoY20sIHRleHQsIHN0YXRlLCBzdHJlYW0ucG9zKTtcclxuICAgICAgICBzdHJlYW0ucG9zID0gdGV4dC5sZW5ndGg7XHJcbiAgICAgICAgc3R5bGUgPSBudWxsO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHN0eWxlID0gZXh0cmFjdExpbmVDbGFzc2VzKHJlYWRUb2tlbihtb2RlLCBzdHJlYW0sIHN0YXRlLCBpbm5lciksIGxpbmVDbGFzc2VzKTtcclxuICAgICAgfVxyXG4gICAgICBpZiAoaW5uZXIpIHtcclxuICAgICAgICB2YXIgbU5hbWUgPSBpbm5lclswXS5uYW1lO1xyXG4gICAgICAgIGlmIChtTmFtZSkgc3R5bGUgPSBcIm0tXCIgKyAoc3R5bGUgPyBtTmFtZSArIFwiIFwiICsgc3R5bGUgOiBtTmFtZSk7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKCFmbGF0dGVuU3BhbnMgfHwgY3VyU3R5bGUgIT0gc3R5bGUpIHtcclxuICAgICAgICB3aGlsZSAoY3VyU3RhcnQgPCBzdHJlYW0uc3RhcnQpIHtcclxuICAgICAgICAgIGN1clN0YXJ0ID0gTWF0aC5taW4oc3RyZWFtLnN0YXJ0LCBjdXJTdGFydCArIDUwMDAwKTtcclxuICAgICAgICAgIGYoY3VyU3RhcnQsIGN1clN0eWxlKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgY3VyU3R5bGUgPSBzdHlsZTtcclxuICAgICAgfVxyXG4gICAgICBzdHJlYW0uc3RhcnQgPSBzdHJlYW0ucG9zO1xyXG4gICAgfVxyXG4gICAgd2hpbGUgKGN1clN0YXJ0IDwgc3RyZWFtLnBvcykge1xyXG4gICAgICAvLyBXZWJraXQgc2VlbXMgdG8gcmVmdXNlIHRvIHJlbmRlciB0ZXh0IG5vZGVzIGxvbmdlciB0aGFuIDU3NDQ0IGNoYXJhY3RlcnNcclxuICAgICAgdmFyIHBvcyA9IE1hdGgubWluKHN0cmVhbS5wb3MsIGN1clN0YXJ0ICsgNTAwMDApO1xyXG4gICAgICBmKHBvcywgY3VyU3R5bGUpO1xyXG4gICAgICBjdXJTdGFydCA9IHBvcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENvbXB1dGUgYSBzdHlsZSBhcnJheSAoYW4gYXJyYXkgc3RhcnRpbmcgd2l0aCBhIG1vZGUgZ2VuZXJhdGlvblxyXG4gIC8vIC0tIGZvciBpbnZhbGlkYXRpb24gLS0gZm9sbG93ZWQgYnkgcGFpcnMgb2YgZW5kIHBvc2l0aW9ucyBhbmRcclxuICAvLyBzdHlsZSBzdHJpbmdzKSwgd2hpY2ggaXMgdXNlZCB0byBoaWdobGlnaHQgdGhlIHRva2VucyBvbiB0aGVcclxuICAvLyBsaW5lLlxyXG4gIGZ1bmN0aW9uIGhpZ2hsaWdodExpbmUoY20sIGxpbmUsIHN0YXRlLCBmb3JjZVRvRW5kKSB7XHJcbiAgICAvLyBBIHN0eWxlcyBhcnJheSBhbHdheXMgc3RhcnRzIHdpdGggYSBudW1iZXIgaWRlbnRpZnlpbmcgdGhlXHJcbiAgICAvLyBtb2RlL292ZXJsYXlzIHRoYXQgaXQgaXMgYmFzZWQgb24gKGZvciBlYXN5IGludmFsaWRhdGlvbikuXHJcbiAgICB2YXIgc3QgPSBbY20uc3RhdGUubW9kZUdlbl0sIGxpbmVDbGFzc2VzID0ge307XHJcbiAgICAvLyBDb21wdXRlIHRoZSBiYXNlIGFycmF5IG9mIHN0eWxlc1xyXG4gICAgcnVuTW9kZShjbSwgbGluZS50ZXh0LCBjbS5kb2MubW9kZSwgc3RhdGUsIGZ1bmN0aW9uKGVuZCwgc3R5bGUpIHtcclxuICAgICAgc3QucHVzaChlbmQsIHN0eWxlKTtcclxuICAgIH0sIGxpbmVDbGFzc2VzLCBmb3JjZVRvRW5kKTtcclxuXHJcbiAgICAvLyBSdW4gb3ZlcmxheXMsIGFkanVzdCBzdHlsZSBhcnJheS5cclxuICAgIGZvciAodmFyIG8gPSAwOyBvIDwgY20uc3RhdGUub3ZlcmxheXMubGVuZ3RoOyArK28pIHtcclxuICAgICAgdmFyIG92ZXJsYXkgPSBjbS5zdGF0ZS5vdmVybGF5c1tvXSwgaSA9IDEsIGF0ID0gMDtcclxuICAgICAgcnVuTW9kZShjbSwgbGluZS50ZXh0LCBvdmVybGF5Lm1vZGUsIHRydWUsIGZ1bmN0aW9uKGVuZCwgc3R5bGUpIHtcclxuICAgICAgICB2YXIgc3RhcnQgPSBpO1xyXG4gICAgICAgIC8vIEVuc3VyZSB0aGVyZSdzIGEgdG9rZW4gZW5kIGF0IHRoZSBjdXJyZW50IHBvc2l0aW9uLCBhbmQgdGhhdCBpIHBvaW50cyBhdCBpdFxyXG4gICAgICAgIHdoaWxlIChhdCA8IGVuZCkge1xyXG4gICAgICAgICAgdmFyIGlfZW5kID0gc3RbaV07XHJcbiAgICAgICAgICBpZiAoaV9lbmQgPiBlbmQpXHJcbiAgICAgICAgICAgIHN0LnNwbGljZShpLCAxLCBlbmQsIHN0W2krMV0sIGlfZW5kKTtcclxuICAgICAgICAgIGkgKz0gMjtcclxuICAgICAgICAgIGF0ID0gTWF0aC5taW4oZW5kLCBpX2VuZCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmICghc3R5bGUpIHJldHVybjtcclxuICAgICAgICBpZiAob3ZlcmxheS5vcGFxdWUpIHtcclxuICAgICAgICAgIHN0LnNwbGljZShzdGFydCwgaSAtIHN0YXJ0LCBlbmQsIFwiY20tb3ZlcmxheSBcIiArIHN0eWxlKTtcclxuICAgICAgICAgIGkgPSBzdGFydCArIDI7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGZvciAoOyBzdGFydCA8IGk7IHN0YXJ0ICs9IDIpIHtcclxuICAgICAgICAgICAgdmFyIGN1ciA9IHN0W3N0YXJ0KzFdO1xyXG4gICAgICAgICAgICBzdFtzdGFydCsxXSA9IChjdXIgPyBjdXIgKyBcIiBcIiA6IFwiXCIpICsgXCJjbS1vdmVybGF5IFwiICsgc3R5bGU7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9LCBsaW5lQ2xhc3Nlcyk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHtzdHlsZXM6IHN0LCBjbGFzc2VzOiBsaW5lQ2xhc3Nlcy5iZ0NsYXNzIHx8IGxpbmVDbGFzc2VzLnRleHRDbGFzcyA/IGxpbmVDbGFzc2VzIDogbnVsbH07XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBnZXRMaW5lU3R5bGVzKGNtLCBsaW5lLCB1cGRhdGVGcm9udGllcikge1xyXG4gICAgaWYgKCFsaW5lLnN0eWxlcyB8fCBsaW5lLnN0eWxlc1swXSAhPSBjbS5zdGF0ZS5tb2RlR2VuKSB7XHJcbiAgICAgIHZhciBzdGF0ZSA9IGdldFN0YXRlQmVmb3JlKGNtLCBsaW5lTm8obGluZSkpO1xyXG4gICAgICB2YXIgcmVzdWx0ID0gaGlnaGxpZ2h0TGluZShjbSwgbGluZSwgbGluZS50ZXh0Lmxlbmd0aCA+IGNtLm9wdGlvbnMubWF4SGlnaGxpZ2h0TGVuZ3RoID8gY29weVN0YXRlKGNtLmRvYy5tb2RlLCBzdGF0ZSkgOiBzdGF0ZSk7XHJcbiAgICAgIGxpbmUuc3RhdGVBZnRlciA9IHN0YXRlO1xyXG4gICAgICBsaW5lLnN0eWxlcyA9IHJlc3VsdC5zdHlsZXM7XHJcbiAgICAgIGlmIChyZXN1bHQuY2xhc3NlcykgbGluZS5zdHlsZUNsYXNzZXMgPSByZXN1bHQuY2xhc3NlcztcclxuICAgICAgZWxzZSBpZiAobGluZS5zdHlsZUNsYXNzZXMpIGxpbmUuc3R5bGVDbGFzc2VzID0gbnVsbDtcclxuICAgICAgaWYgKHVwZGF0ZUZyb250aWVyID09PSBjbS5kb2MuZnJvbnRpZXIpIGNtLmRvYy5mcm9udGllcisrO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGxpbmUuc3R5bGVzO1xyXG4gIH1cclxuXHJcbiAgLy8gTGlnaHR3ZWlnaHQgZm9ybSBvZiBoaWdobGlnaHQgLS0gcHJvY2VlZCBvdmVyIHRoaXMgbGluZSBhbmRcclxuICAvLyB1cGRhdGUgc3RhdGUsIGJ1dCBkb24ndCBzYXZlIGEgc3R5bGUgYXJyYXkuIFVzZWQgZm9yIGxpbmVzIHRoYXRcclxuICAvLyBhcmVuJ3QgY3VycmVudGx5IHZpc2libGUuXHJcbiAgZnVuY3Rpb24gcHJvY2Vzc0xpbmUoY20sIHRleHQsIHN0YXRlLCBzdGFydEF0KSB7XHJcbiAgICB2YXIgbW9kZSA9IGNtLmRvYy5tb2RlO1xyXG4gICAgdmFyIHN0cmVhbSA9IG5ldyBTdHJpbmdTdHJlYW0odGV4dCwgY20ub3B0aW9ucy50YWJTaXplKTtcclxuICAgIHN0cmVhbS5zdGFydCA9IHN0cmVhbS5wb3MgPSBzdGFydEF0IHx8IDA7XHJcbiAgICBpZiAodGV4dCA9PSBcIlwiKSBjYWxsQmxhbmtMaW5lKG1vZGUsIHN0YXRlKTtcclxuICAgIHdoaWxlICghc3RyZWFtLmVvbCgpKSB7XHJcbiAgICAgIHJlYWRUb2tlbihtb2RlLCBzdHJlYW0sIHN0YXRlKTtcclxuICAgICAgc3RyZWFtLnN0YXJ0ID0gc3RyZWFtLnBvcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENvbnZlcnQgYSBzdHlsZSBhcyByZXR1cm5lZCBieSBhIG1vZGUgKGVpdGhlciBudWxsLCBvciBhIHN0cmluZ1xyXG4gIC8vIGNvbnRhaW5pbmcgb25lIG9yIG1vcmUgc3R5bGVzKSB0byBhIENTUyBzdHlsZS4gVGhpcyBpcyBjYWNoZWQsXHJcbiAgLy8gYW5kIGFsc28gbG9va3MgZm9yIGxpbmUtd2lkZSBzdHlsZXMuXHJcbiAgdmFyIHN0eWxlVG9DbGFzc0NhY2hlID0ge30sIHN0eWxlVG9DbGFzc0NhY2hlV2l0aE1vZGUgPSB7fTtcclxuICBmdW5jdGlvbiBpbnRlcnByZXRUb2tlblN0eWxlKHN0eWxlLCBvcHRpb25zKSB7XHJcbiAgICBpZiAoIXN0eWxlIHx8IC9eXFxzKiQvLnRlc3Qoc3R5bGUpKSByZXR1cm4gbnVsbDtcclxuICAgIHZhciBjYWNoZSA9IG9wdGlvbnMuYWRkTW9kZUNsYXNzID8gc3R5bGVUb0NsYXNzQ2FjaGVXaXRoTW9kZSA6IHN0eWxlVG9DbGFzc0NhY2hlO1xyXG4gICAgcmV0dXJuIGNhY2hlW3N0eWxlXSB8fFxyXG4gICAgICAoY2FjaGVbc3R5bGVdID0gc3R5bGUucmVwbGFjZSgvXFxTKy9nLCBcImNtLSQmXCIpKTtcclxuICB9XHJcblxyXG4gIC8vIFJlbmRlciB0aGUgRE9NIHJlcHJlc2VudGF0aW9uIG9mIHRoZSB0ZXh0IG9mIGEgbGluZS4gQWxzbyBidWlsZHNcclxuICAvLyB1cCBhICdsaW5lIG1hcCcsIHdoaWNoIHBvaW50cyBhdCB0aGUgRE9NIG5vZGVzIHRoYXQgcmVwcmVzZW50XHJcbiAgLy8gc3BlY2lmaWMgc3RyZXRjaGVzIG9mIHRleHQsIGFuZCBpcyB1c2VkIGJ5IHRoZSBtZWFzdXJpbmcgY29kZS5cclxuICAvLyBUaGUgcmV0dXJuZWQgb2JqZWN0IGNvbnRhaW5zIHRoZSBET00gbm9kZSwgdGhpcyBtYXAsIGFuZFxyXG4gIC8vIGluZm9ybWF0aW9uIGFib3V0IGxpbmUtd2lkZSBzdHlsZXMgdGhhdCB3ZXJlIHNldCBieSB0aGUgbW9kZS5cclxuICBmdW5jdGlvbiBidWlsZExpbmVDb250ZW50KGNtLCBsaW5lVmlldykge1xyXG4gICAgLy8gVGhlIHBhZGRpbmctcmlnaHQgZm9yY2VzIHRoZSBlbGVtZW50IHRvIGhhdmUgYSAnYm9yZGVyJywgd2hpY2hcclxuICAgIC8vIGlzIG5lZWRlZCBvbiBXZWJraXQgdG8gYmUgYWJsZSB0byBnZXQgbGluZS1sZXZlbCBib3VuZGluZ1xyXG4gICAgLy8gcmVjdGFuZ2xlcyBmb3IgaXQgKGluIG1lYXN1cmVDaGFyKS5cclxuICAgIHZhciBjb250ZW50ID0gZWx0KFwic3BhblwiLCBudWxsLCBudWxsLCB3ZWJraXQgPyBcInBhZGRpbmctcmlnaHQ6IC4xcHhcIiA6IG51bGwpO1xyXG4gICAgdmFyIGJ1aWxkZXIgPSB7cHJlOiBlbHQoXCJwcmVcIiwgW2NvbnRlbnRdLCBcIkNvZGVNaXJyb3ItbGluZVwiKSwgY29udGVudDogY29udGVudCxcclxuICAgICAgICAgICAgICAgICAgIGNvbDogMCwgcG9zOiAwLCBjbTogY20sXHJcbiAgICAgICAgICAgICAgICAgICBzcGxpdFNwYWNlczogKGllIHx8IHdlYmtpdCkgJiYgY20uZ2V0T3B0aW9uKFwibGluZVdyYXBwaW5nXCIpfTtcclxuICAgIGxpbmVWaWV3Lm1lYXN1cmUgPSB7fTtcclxuXHJcbiAgICAvLyBJdGVyYXRlIG92ZXIgdGhlIGxvZ2ljYWwgbGluZXMgdGhhdCBtYWtlIHVwIHRoaXMgdmlzdWFsIGxpbmUuXHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8PSAobGluZVZpZXcucmVzdCA/IGxpbmVWaWV3LnJlc3QubGVuZ3RoIDogMCk7IGkrKykge1xyXG4gICAgICB2YXIgbGluZSA9IGkgPyBsaW5lVmlldy5yZXN0W2kgLSAxXSA6IGxpbmVWaWV3LmxpbmUsIG9yZGVyO1xyXG4gICAgICBidWlsZGVyLnBvcyA9IDA7XHJcbiAgICAgIGJ1aWxkZXIuYWRkVG9rZW4gPSBidWlsZFRva2VuO1xyXG4gICAgICAvLyBPcHRpb25hbGx5IHdpcmUgaW4gc29tZSBoYWNrcyBpbnRvIHRoZSB0b2tlbi1yZW5kZXJpbmdcclxuICAgICAgLy8gYWxnb3JpdGhtLCB0byBkZWFsIHdpdGggYnJvd3NlciBxdWlya3MuXHJcbiAgICAgIGlmIChoYXNCYWRCaWRpUmVjdHMoY20uZGlzcGxheS5tZWFzdXJlKSAmJiAob3JkZXIgPSBnZXRPcmRlcihsaW5lKSkpXHJcbiAgICAgICAgYnVpbGRlci5hZGRUb2tlbiA9IGJ1aWxkVG9rZW5CYWRCaWRpKGJ1aWxkZXIuYWRkVG9rZW4sIG9yZGVyKTtcclxuICAgICAgYnVpbGRlci5tYXAgPSBbXTtcclxuICAgICAgdmFyIGFsbG93RnJvbnRpZXJVcGRhdGUgPSBsaW5lVmlldyAhPSBjbS5kaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQgJiYgbGluZU5vKGxpbmUpO1xyXG4gICAgICBpbnNlcnRMaW5lQ29udGVudChsaW5lLCBidWlsZGVyLCBnZXRMaW5lU3R5bGVzKGNtLCBsaW5lLCBhbGxvd0Zyb250aWVyVXBkYXRlKSk7XHJcbiAgICAgIGlmIChsaW5lLnN0eWxlQ2xhc3Nlcykge1xyXG4gICAgICAgIGlmIChsaW5lLnN0eWxlQ2xhc3Nlcy5iZ0NsYXNzKVxyXG4gICAgICAgICAgYnVpbGRlci5iZ0NsYXNzID0gam9pbkNsYXNzZXMobGluZS5zdHlsZUNsYXNzZXMuYmdDbGFzcywgYnVpbGRlci5iZ0NsYXNzIHx8IFwiXCIpO1xyXG4gICAgICAgIGlmIChsaW5lLnN0eWxlQ2xhc3Nlcy50ZXh0Q2xhc3MpXHJcbiAgICAgICAgICBidWlsZGVyLnRleHRDbGFzcyA9IGpvaW5DbGFzc2VzKGxpbmUuc3R5bGVDbGFzc2VzLnRleHRDbGFzcywgYnVpbGRlci50ZXh0Q2xhc3MgfHwgXCJcIik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEVuc3VyZSBhdCBsZWFzdCBhIHNpbmdsZSBub2RlIGlzIHByZXNlbnQsIGZvciBtZWFzdXJpbmcuXHJcbiAgICAgIGlmIChidWlsZGVyLm1hcC5sZW5ndGggPT0gMClcclxuICAgICAgICBidWlsZGVyLm1hcC5wdXNoKDAsIDAsIGJ1aWxkZXIuY29udGVudC5hcHBlbmRDaGlsZCh6ZXJvV2lkdGhFbGVtZW50KGNtLmRpc3BsYXkubWVhc3VyZSkpKTtcclxuXHJcbiAgICAgIC8vIFN0b3JlIHRoZSBtYXAgYW5kIGEgY2FjaGUgb2JqZWN0IGZvciB0aGUgY3VycmVudCBsb2dpY2FsIGxpbmVcclxuICAgICAgaWYgKGkgPT0gMCkge1xyXG4gICAgICAgIGxpbmVWaWV3Lm1lYXN1cmUubWFwID0gYnVpbGRlci5tYXA7XHJcbiAgICAgICAgbGluZVZpZXcubWVhc3VyZS5jYWNoZSA9IHt9O1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIChsaW5lVmlldy5tZWFzdXJlLm1hcHMgfHwgKGxpbmVWaWV3Lm1lYXN1cmUubWFwcyA9IFtdKSkucHVzaChidWlsZGVyLm1hcCk7XHJcbiAgICAgICAgKGxpbmVWaWV3Lm1lYXN1cmUuY2FjaGVzIHx8IChsaW5lVmlldy5tZWFzdXJlLmNhY2hlcyA9IFtdKSkucHVzaCh7fSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBTZWUgaXNzdWUgIzI5MDFcclxuICAgIGlmICh3ZWJraXQgJiYgL1xcYmNtLXRhYlxcYi8udGVzdChidWlsZGVyLmNvbnRlbnQubGFzdENoaWxkLmNsYXNzTmFtZSkpXHJcbiAgICAgIGJ1aWxkZXIuY29udGVudC5jbGFzc05hbWUgPSBcImNtLXRhYi13cmFwLWhhY2tcIjtcclxuXHJcbiAgICBzaWduYWwoY20sIFwicmVuZGVyTGluZVwiLCBjbSwgbGluZVZpZXcubGluZSwgYnVpbGRlci5wcmUpO1xyXG4gICAgaWYgKGJ1aWxkZXIucHJlLmNsYXNzTmFtZSlcclxuICAgICAgYnVpbGRlci50ZXh0Q2xhc3MgPSBqb2luQ2xhc3NlcyhidWlsZGVyLnByZS5jbGFzc05hbWUsIGJ1aWxkZXIudGV4dENsYXNzIHx8IFwiXCIpO1xyXG5cclxuICAgIHJldHVybiBidWlsZGVyO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gZGVmYXVsdFNwZWNpYWxDaGFyUGxhY2Vob2xkZXIoY2gpIHtcclxuICAgIHZhciB0b2tlbiA9IGVsdChcInNwYW5cIiwgXCJcXHUyMDIyXCIsIFwiY20taW52YWxpZGNoYXJcIik7XHJcbiAgICB0b2tlbi50aXRsZSA9IFwiXFxcXHVcIiArIGNoLmNoYXJDb2RlQXQoMCkudG9TdHJpbmcoMTYpO1xyXG4gICAgdG9rZW4uc2V0QXR0cmlidXRlKFwiYXJpYS1sYWJlbFwiLCB0b2tlbi50aXRsZSk7XHJcbiAgICByZXR1cm4gdG9rZW47XHJcbiAgfVxyXG5cclxuICAvLyBCdWlsZCB1cCB0aGUgRE9NIHJlcHJlc2VudGF0aW9uIGZvciBhIHNpbmdsZSB0b2tlbiwgYW5kIGFkZCBpdCB0b1xyXG4gIC8vIHRoZSBsaW5lIG1hcC4gVGFrZXMgY2FyZSB0byByZW5kZXIgc3BlY2lhbCBjaGFyYWN0ZXJzIHNlcGFyYXRlbHkuXHJcbiAgZnVuY3Rpb24gYnVpbGRUb2tlbihidWlsZGVyLCB0ZXh0LCBzdHlsZSwgc3RhcnRTdHlsZSwgZW5kU3R5bGUsIHRpdGxlLCBjc3MpIHtcclxuICAgIGlmICghdGV4dCkgcmV0dXJuO1xyXG4gICAgdmFyIGRpc3BsYXlUZXh0ID0gYnVpbGRlci5zcGxpdFNwYWNlcyA/IHRleHQucmVwbGFjZSgvIHszLH0vZywgc3BsaXRTcGFjZXMpIDogdGV4dDtcclxuICAgIHZhciBzcGVjaWFsID0gYnVpbGRlci5jbS5zdGF0ZS5zcGVjaWFsQ2hhcnMsIG11c3RXcmFwID0gZmFsc2U7XHJcbiAgICBpZiAoIXNwZWNpYWwudGVzdCh0ZXh0KSkge1xyXG4gICAgICBidWlsZGVyLmNvbCArPSB0ZXh0Lmxlbmd0aDtcclxuICAgICAgdmFyIGNvbnRlbnQgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShkaXNwbGF5VGV4dCk7XHJcbiAgICAgIGJ1aWxkZXIubWFwLnB1c2goYnVpbGRlci5wb3MsIGJ1aWxkZXIucG9zICsgdGV4dC5sZW5ndGgsIGNvbnRlbnQpO1xyXG4gICAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA8IDkpIG11c3RXcmFwID0gdHJ1ZTtcclxuICAgICAgYnVpbGRlci5wb3MgKz0gdGV4dC5sZW5ndGg7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB2YXIgY29udGVudCA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKSwgcG9zID0gMDtcclxuICAgICAgd2hpbGUgKHRydWUpIHtcclxuICAgICAgICBzcGVjaWFsLmxhc3RJbmRleCA9IHBvcztcclxuICAgICAgICB2YXIgbSA9IHNwZWNpYWwuZXhlYyh0ZXh0KTtcclxuICAgICAgICB2YXIgc2tpcHBlZCA9IG0gPyBtLmluZGV4IC0gcG9zIDogdGV4dC5sZW5ndGggLSBwb3M7XHJcbiAgICAgICAgaWYgKHNraXBwZWQpIHtcclxuICAgICAgICAgIHZhciB0eHQgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShkaXNwbGF5VGV4dC5zbGljZShwb3MsIHBvcyArIHNraXBwZWQpKTtcclxuICAgICAgICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uIDwgOSkgY29udGVudC5hcHBlbmRDaGlsZChlbHQoXCJzcGFuXCIsIFt0eHRdKSk7XHJcbiAgICAgICAgICBlbHNlIGNvbnRlbnQuYXBwZW5kQ2hpbGQodHh0KTtcclxuICAgICAgICAgIGJ1aWxkZXIubWFwLnB1c2goYnVpbGRlci5wb3MsIGJ1aWxkZXIucG9zICsgc2tpcHBlZCwgdHh0KTtcclxuICAgICAgICAgIGJ1aWxkZXIuY29sICs9IHNraXBwZWQ7XHJcbiAgICAgICAgICBidWlsZGVyLnBvcyArPSBza2lwcGVkO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoIW0pIGJyZWFrO1xyXG4gICAgICAgIHBvcyArPSBza2lwcGVkICsgMTtcclxuICAgICAgICBpZiAobVswXSA9PSBcIlxcdFwiKSB7XHJcbiAgICAgICAgICB2YXIgdGFiU2l6ZSA9IGJ1aWxkZXIuY20ub3B0aW9ucy50YWJTaXplLCB0YWJXaWR0aCA9IHRhYlNpemUgLSBidWlsZGVyLmNvbCAlIHRhYlNpemU7XHJcbiAgICAgICAgICB2YXIgdHh0ID0gY29udGVudC5hcHBlbmRDaGlsZChlbHQoXCJzcGFuXCIsIHNwYWNlU3RyKHRhYldpZHRoKSwgXCJjbS10YWJcIikpO1xyXG4gICAgICAgICAgdHh0LnNldEF0dHJpYnV0ZShcInJvbGVcIiwgXCJwcmVzZW50YXRpb25cIik7XHJcbiAgICAgICAgICB0eHQuc2V0QXR0cmlidXRlKFwiY20tdGV4dFwiLCBcIlxcdFwiKTtcclxuICAgICAgICAgIGJ1aWxkZXIuY29sICs9IHRhYldpZHRoO1xyXG4gICAgICAgIH0gZWxzZSBpZiAobVswXSA9PSBcIlxcclwiIHx8IG1bMF0gPT0gXCJcXG5cIikge1xyXG4gICAgICAgICAgdmFyIHR4dCA9IGNvbnRlbnQuYXBwZW5kQ2hpbGQoZWx0KFwic3BhblwiLCBtWzBdID09IFwiXFxyXCIgPyBcIlxcdTI0MGRcIiA6IFwiXFx1MjQyNFwiLCBcImNtLWludmFsaWRjaGFyXCIpKTtcclxuICAgICAgICAgIHR4dC5zZXRBdHRyaWJ1dGUoXCJjbS10ZXh0XCIsIG1bMF0pO1xyXG4gICAgICAgICAgYnVpbGRlci5jb2wgKz0gMTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdmFyIHR4dCA9IGJ1aWxkZXIuY20ub3B0aW9ucy5zcGVjaWFsQ2hhclBsYWNlaG9sZGVyKG1bMF0pO1xyXG4gICAgICAgICAgdHh0LnNldEF0dHJpYnV0ZShcImNtLXRleHRcIiwgbVswXSk7XHJcbiAgICAgICAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA8IDkpIGNvbnRlbnQuYXBwZW5kQ2hpbGQoZWx0KFwic3BhblwiLCBbdHh0XSkpO1xyXG4gICAgICAgICAgZWxzZSBjb250ZW50LmFwcGVuZENoaWxkKHR4dCk7XHJcbiAgICAgICAgICBidWlsZGVyLmNvbCArPSAxO1xyXG4gICAgICAgIH1cclxuICAgICAgICBidWlsZGVyLm1hcC5wdXNoKGJ1aWxkZXIucG9zLCBidWlsZGVyLnBvcyArIDEsIHR4dCk7XHJcbiAgICAgICAgYnVpbGRlci5wb3MrKztcclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgaWYgKHN0eWxlIHx8IHN0YXJ0U3R5bGUgfHwgZW5kU3R5bGUgfHwgbXVzdFdyYXAgfHwgY3NzKSB7XHJcbiAgICAgIHZhciBmdWxsU3R5bGUgPSBzdHlsZSB8fCBcIlwiO1xyXG4gICAgICBpZiAoc3RhcnRTdHlsZSkgZnVsbFN0eWxlICs9IHN0YXJ0U3R5bGU7XHJcbiAgICAgIGlmIChlbmRTdHlsZSkgZnVsbFN0eWxlICs9IGVuZFN0eWxlO1xyXG4gICAgICB2YXIgdG9rZW4gPSBlbHQoXCJzcGFuXCIsIFtjb250ZW50XSwgZnVsbFN0eWxlLCBjc3MpO1xyXG4gICAgICBpZiAodGl0bGUpIHRva2VuLnRpdGxlID0gdGl0bGU7XHJcbiAgICAgIHJldHVybiBidWlsZGVyLmNvbnRlbnQuYXBwZW5kQ2hpbGQodG9rZW4pO1xyXG4gICAgfVxyXG4gICAgYnVpbGRlci5jb250ZW50LmFwcGVuZENoaWxkKGNvbnRlbnQpO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gc3BsaXRTcGFjZXMob2xkKSB7XHJcbiAgICB2YXIgb3V0ID0gXCIgXCI7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG9sZC5sZW5ndGggLSAyOyArK2kpIG91dCArPSBpICUgMiA/IFwiIFwiIDogXCJcXHUwMGEwXCI7XHJcbiAgICBvdXQgKz0gXCIgXCI7XHJcbiAgICByZXR1cm4gb3V0O1xyXG4gIH1cclxuXHJcbiAgLy8gV29yayBhcm91bmQgbm9uc2Vuc2UgZGltZW5zaW9ucyBiZWluZyByZXBvcnRlZCBmb3Igc3RyZXRjaGVzIG9mXHJcbiAgLy8gcmlnaHQtdG8tbGVmdCB0ZXh0LlxyXG4gIGZ1bmN0aW9uIGJ1aWxkVG9rZW5CYWRCaWRpKGlubmVyLCBvcmRlcikge1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uKGJ1aWxkZXIsIHRleHQsIHN0eWxlLCBzdGFydFN0eWxlLCBlbmRTdHlsZSwgdGl0bGUsIGNzcykge1xyXG4gICAgICBzdHlsZSA9IHN0eWxlID8gc3R5bGUgKyBcIiBjbS1mb3JjZS1ib3JkZXJcIiA6IFwiY20tZm9yY2UtYm9yZGVyXCI7XHJcbiAgICAgIHZhciBzdGFydCA9IGJ1aWxkZXIucG9zLCBlbmQgPSBzdGFydCArIHRleHQubGVuZ3RoO1xyXG4gICAgICBmb3IgKDs7KSB7XHJcbiAgICAgICAgLy8gRmluZCB0aGUgcGFydCB0aGF0IG92ZXJsYXBzIHdpdGggdGhlIHN0YXJ0IG9mIHRoaXMgdGV4dFxyXG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgb3JkZXIubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgIHZhciBwYXJ0ID0gb3JkZXJbaV07XHJcbiAgICAgICAgICBpZiAocGFydC50byA+IHN0YXJ0ICYmIHBhcnQuZnJvbSA8PSBzdGFydCkgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChwYXJ0LnRvID49IGVuZCkgcmV0dXJuIGlubmVyKGJ1aWxkZXIsIHRleHQsIHN0eWxlLCBzdGFydFN0eWxlLCBlbmRTdHlsZSwgdGl0bGUsIGNzcyk7XHJcbiAgICAgICAgaW5uZXIoYnVpbGRlciwgdGV4dC5zbGljZSgwLCBwYXJ0LnRvIC0gc3RhcnQpLCBzdHlsZSwgc3RhcnRTdHlsZSwgbnVsbCwgdGl0bGUsIGNzcyk7XHJcbiAgICAgICAgc3RhcnRTdHlsZSA9IG51bGw7XHJcbiAgICAgICAgdGV4dCA9IHRleHQuc2xpY2UocGFydC50byAtIHN0YXJ0KTtcclxuICAgICAgICBzdGFydCA9IHBhcnQudG87XHJcbiAgICAgIH1cclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBidWlsZENvbGxhcHNlZFNwYW4oYnVpbGRlciwgc2l6ZSwgbWFya2VyLCBpZ25vcmVXaWRnZXQpIHtcclxuICAgIHZhciB3aWRnZXQgPSAhaWdub3JlV2lkZ2V0ICYmIG1hcmtlci53aWRnZXROb2RlO1xyXG4gICAgaWYgKHdpZGdldCkgYnVpbGRlci5tYXAucHVzaChidWlsZGVyLnBvcywgYnVpbGRlci5wb3MgKyBzaXplLCB3aWRnZXQpO1xyXG4gICAgaWYgKCFpZ25vcmVXaWRnZXQgJiYgYnVpbGRlci5jbS5kaXNwbGF5LmlucHV0Lm5lZWRzQ29udGVudEF0dHJpYnV0ZSkge1xyXG4gICAgICBpZiAoIXdpZGdldClcclxuICAgICAgICB3aWRnZXQgPSBidWlsZGVyLmNvbnRlbnQuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInNwYW5cIikpO1xyXG4gICAgICB3aWRnZXQuc2V0QXR0cmlidXRlKFwiY20tbWFya2VyXCIsIG1hcmtlci5pZCk7XHJcbiAgICB9XHJcbiAgICBpZiAod2lkZ2V0KSB7XHJcbiAgICAgIGJ1aWxkZXIuY20uZGlzcGxheS5pbnB1dC5zZXRVbmVkaXRhYmxlKHdpZGdldCk7XHJcbiAgICAgIGJ1aWxkZXIuY29udGVudC5hcHBlbmRDaGlsZCh3aWRnZXQpO1xyXG4gICAgfVxyXG4gICAgYnVpbGRlci5wb3MgKz0gc2l6ZTtcclxuICB9XHJcblxyXG4gIC8vIE91dHB1dHMgYSBudW1iZXIgb2Ygc3BhbnMgdG8gbWFrZSB1cCBhIGxpbmUsIHRha2luZyBoaWdobGlnaHRpbmdcclxuICAvLyBhbmQgbWFya2VkIHRleHQgaW50byBhY2NvdW50LlxyXG4gIGZ1bmN0aW9uIGluc2VydExpbmVDb250ZW50KGxpbmUsIGJ1aWxkZXIsIHN0eWxlcykge1xyXG4gICAgdmFyIHNwYW5zID0gbGluZS5tYXJrZWRTcGFucywgYWxsVGV4dCA9IGxpbmUudGV4dCwgYXQgPSAwO1xyXG4gICAgaWYgKCFzcGFucykge1xyXG4gICAgICBmb3IgKHZhciBpID0gMTsgaSA8IHN0eWxlcy5sZW5ndGg7IGkrPTIpXHJcbiAgICAgICAgYnVpbGRlci5hZGRUb2tlbihidWlsZGVyLCBhbGxUZXh0LnNsaWNlKGF0LCBhdCA9IHN0eWxlc1tpXSksIGludGVycHJldFRva2VuU3R5bGUoc3R5bGVzW2krMV0sIGJ1aWxkZXIuY20ub3B0aW9ucykpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdmFyIGxlbiA9IGFsbFRleHQubGVuZ3RoLCBwb3MgPSAwLCBpID0gMSwgdGV4dCA9IFwiXCIsIHN0eWxlLCBjc3M7XHJcbiAgICB2YXIgbmV4dENoYW5nZSA9IDAsIHNwYW5TdHlsZSwgc3BhbkVuZFN0eWxlLCBzcGFuU3RhcnRTdHlsZSwgdGl0bGUsIGNvbGxhcHNlZDtcclxuICAgIGZvciAoOzspIHtcclxuICAgICAgaWYgKG5leHRDaGFuZ2UgPT0gcG9zKSB7IC8vIFVwZGF0ZSBjdXJyZW50IG1hcmtlciBzZXRcclxuICAgICAgICBzcGFuU3R5bGUgPSBzcGFuRW5kU3R5bGUgPSBzcGFuU3RhcnRTdHlsZSA9IHRpdGxlID0gY3NzID0gXCJcIjtcclxuICAgICAgICBjb2xsYXBzZWQgPSBudWxsOyBuZXh0Q2hhbmdlID0gSW5maW5pdHk7XHJcbiAgICAgICAgdmFyIGZvdW5kQm9va21hcmtzID0gW107XHJcbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBzcGFucy5sZW5ndGg7ICsraikge1xyXG4gICAgICAgICAgdmFyIHNwID0gc3BhbnNbal0sIG0gPSBzcC5tYXJrZXI7XHJcbiAgICAgICAgICBpZiAobS50eXBlID09IFwiYm9va21hcmtcIiAmJiBzcC5mcm9tID09IHBvcyAmJiBtLndpZGdldE5vZGUpIHtcclxuICAgICAgICAgICAgZm91bmRCb29rbWFya3MucHVzaChtKTtcclxuICAgICAgICAgIH0gZWxzZSBpZiAoc3AuZnJvbSA8PSBwb3MgJiYgKHNwLnRvID09IG51bGwgfHwgc3AudG8gPiBwb3MgfHwgbS5jb2xsYXBzZWQgJiYgc3AudG8gPT0gcG9zICYmIHNwLmZyb20gPT0gcG9zKSkge1xyXG4gICAgICAgICAgICBpZiAoc3AudG8gIT0gbnVsbCAmJiBzcC50byAhPSBwb3MgJiYgbmV4dENoYW5nZSA+IHNwLnRvKSB7XHJcbiAgICAgICAgICAgICAgbmV4dENoYW5nZSA9IHNwLnRvO1xyXG4gICAgICAgICAgICAgIHNwYW5FbmRTdHlsZSA9IFwiXCI7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgaWYgKG0uY2xhc3NOYW1lKSBzcGFuU3R5bGUgKz0gXCIgXCIgKyBtLmNsYXNzTmFtZTtcclxuICAgICAgICAgICAgaWYgKG0uY3NzKSBjc3MgPSAoY3NzID8gY3NzICsgXCI7XCIgOiBcIlwiKSArIG0uY3NzO1xyXG4gICAgICAgICAgICBpZiAobS5zdGFydFN0eWxlICYmIHNwLmZyb20gPT0gcG9zKSBzcGFuU3RhcnRTdHlsZSArPSBcIiBcIiArIG0uc3RhcnRTdHlsZTtcclxuICAgICAgICAgICAgaWYgKG0uZW5kU3R5bGUgJiYgc3AudG8gPT0gbmV4dENoYW5nZSkgc3BhbkVuZFN0eWxlICs9IFwiIFwiICsgbS5lbmRTdHlsZTtcclxuICAgICAgICAgICAgaWYgKG0udGl0bGUgJiYgIXRpdGxlKSB0aXRsZSA9IG0udGl0bGU7XHJcbiAgICAgICAgICAgIGlmIChtLmNvbGxhcHNlZCAmJiAoIWNvbGxhcHNlZCB8fCBjb21wYXJlQ29sbGFwc2VkTWFya2Vycyhjb2xsYXBzZWQubWFya2VyLCBtKSA8IDApKVxyXG4gICAgICAgICAgICAgIGNvbGxhcHNlZCA9IHNwO1xyXG4gICAgICAgICAgfSBlbHNlIGlmIChzcC5mcm9tID4gcG9zICYmIG5leHRDaGFuZ2UgPiBzcC5mcm9tKSB7XHJcbiAgICAgICAgICAgIG5leHRDaGFuZ2UgPSBzcC5mcm9tO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoY29sbGFwc2VkICYmIChjb2xsYXBzZWQuZnJvbSB8fCAwKSA9PSBwb3MpIHtcclxuICAgICAgICAgIGJ1aWxkQ29sbGFwc2VkU3BhbihidWlsZGVyLCAoY29sbGFwc2VkLnRvID09IG51bGwgPyBsZW4gKyAxIDogY29sbGFwc2VkLnRvKSAtIHBvcyxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2xsYXBzZWQubWFya2VyLCBjb2xsYXBzZWQuZnJvbSA9PSBudWxsKTtcclxuICAgICAgICAgIGlmIChjb2xsYXBzZWQudG8gPT0gbnVsbCkgcmV0dXJuO1xyXG4gICAgICAgICAgaWYgKGNvbGxhcHNlZC50byA9PSBwb3MpIGNvbGxhcHNlZCA9IGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoIWNvbGxhcHNlZCAmJiBmb3VuZEJvb2ttYXJrcy5sZW5ndGgpIGZvciAodmFyIGogPSAwOyBqIDwgZm91bmRCb29rbWFya3MubGVuZ3RoOyArK2opXHJcbiAgICAgICAgICBidWlsZENvbGxhcHNlZFNwYW4oYnVpbGRlciwgMCwgZm91bmRCb29rbWFya3Nbal0pO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChwb3MgPj0gbGVuKSBicmVhaztcclxuXHJcbiAgICAgIHZhciB1cHRvID0gTWF0aC5taW4obGVuLCBuZXh0Q2hhbmdlKTtcclxuICAgICAgd2hpbGUgKHRydWUpIHtcclxuICAgICAgICBpZiAodGV4dCkge1xyXG4gICAgICAgICAgdmFyIGVuZCA9IHBvcyArIHRleHQubGVuZ3RoO1xyXG4gICAgICAgICAgaWYgKCFjb2xsYXBzZWQpIHtcclxuICAgICAgICAgICAgdmFyIHRva2VuVGV4dCA9IGVuZCA+IHVwdG8gPyB0ZXh0LnNsaWNlKDAsIHVwdG8gLSBwb3MpIDogdGV4dDtcclxuICAgICAgICAgICAgYnVpbGRlci5hZGRUb2tlbihidWlsZGVyLCB0b2tlblRleHQsIHN0eWxlID8gc3R5bGUgKyBzcGFuU3R5bGUgOiBzcGFuU3R5bGUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BhblN0YXJ0U3R5bGUsIHBvcyArIHRva2VuVGV4dC5sZW5ndGggPT0gbmV4dENoYW5nZSA/IHNwYW5FbmRTdHlsZSA6IFwiXCIsIHRpdGxlLCBjc3MpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgaWYgKGVuZCA+PSB1cHRvKSB7dGV4dCA9IHRleHQuc2xpY2UodXB0byAtIHBvcyk7IHBvcyA9IHVwdG87IGJyZWFrO31cclxuICAgICAgICAgIHBvcyA9IGVuZDtcclxuICAgICAgICAgIHNwYW5TdGFydFN0eWxlID0gXCJcIjtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGV4dCA9IGFsbFRleHQuc2xpY2UoYXQsIGF0ID0gc3R5bGVzW2krK10pO1xyXG4gICAgICAgIHN0eWxlID0gaW50ZXJwcmV0VG9rZW5TdHlsZShzdHlsZXNbaSsrXSwgYnVpbGRlci5jbS5vcHRpb25zKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRE9DVU1FTlQgREFUQSBTVFJVQ1RVUkVcclxuXHJcbiAgLy8gQnkgZGVmYXVsdCwgdXBkYXRlcyB0aGF0IHN0YXJ0IGFuZCBlbmQgYXQgdGhlIGJlZ2lubmluZyBvZiBhIGxpbmVcclxuICAvLyBhcmUgdHJlYXRlZCBzcGVjaWFsbHksIGluIG9yZGVyIHRvIG1ha2UgdGhlIGFzc29jaWF0aW9uIG9mIGxpbmVcclxuICAvLyB3aWRnZXRzIGFuZCBtYXJrZXIgZWxlbWVudHMgd2l0aCB0aGUgdGV4dCBiZWhhdmUgbW9yZSBpbnR1aXRpdmUuXHJcbiAgZnVuY3Rpb24gaXNXaG9sZUxpbmVVcGRhdGUoZG9jLCBjaGFuZ2UpIHtcclxuICAgIHJldHVybiBjaGFuZ2UuZnJvbS5jaCA9PSAwICYmIGNoYW5nZS50by5jaCA9PSAwICYmIGxzdChjaGFuZ2UudGV4dCkgPT0gXCJcIiAmJlxyXG4gICAgICAoIWRvYy5jbSB8fCBkb2MuY20ub3B0aW9ucy53aG9sZUxpbmVVcGRhdGVCZWZvcmUpO1xyXG4gIH1cclxuXHJcbiAgLy8gUGVyZm9ybSBhIGNoYW5nZSBvbiB0aGUgZG9jdW1lbnQgZGF0YSBzdHJ1Y3R1cmUuXHJcbiAgZnVuY3Rpb24gdXBkYXRlRG9jKGRvYywgY2hhbmdlLCBtYXJrZWRTcGFucywgZXN0aW1hdGVIZWlnaHQpIHtcclxuICAgIGZ1bmN0aW9uIHNwYW5zRm9yKG4pIHtyZXR1cm4gbWFya2VkU3BhbnMgPyBtYXJrZWRTcGFuc1tuXSA6IG51bGw7fVxyXG4gICAgZnVuY3Rpb24gdXBkYXRlKGxpbmUsIHRleHQsIHNwYW5zKSB7XHJcbiAgICAgIHVwZGF0ZUxpbmUobGluZSwgdGV4dCwgc3BhbnMsIGVzdGltYXRlSGVpZ2h0KTtcclxuICAgICAgc2lnbmFsTGF0ZXIobGluZSwgXCJjaGFuZ2VcIiwgbGluZSwgY2hhbmdlKTtcclxuICAgIH1cclxuICAgIGZ1bmN0aW9uIGxpbmVzRm9yKHN0YXJ0LCBlbmQpIHtcclxuICAgICAgZm9yICh2YXIgaSA9IHN0YXJ0LCByZXN1bHQgPSBbXTsgaSA8IGVuZDsgKytpKVxyXG4gICAgICAgIHJlc3VsdC5wdXNoKG5ldyBMaW5lKHRleHRbaV0sIHNwYW5zRm9yKGkpLCBlc3RpbWF0ZUhlaWdodCkpO1xyXG4gICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfVxyXG5cclxuICAgIHZhciBmcm9tID0gY2hhbmdlLmZyb20sIHRvID0gY2hhbmdlLnRvLCB0ZXh0ID0gY2hhbmdlLnRleHQ7XHJcbiAgICB2YXIgZmlyc3RMaW5lID0gZ2V0TGluZShkb2MsIGZyb20ubGluZSksIGxhc3RMaW5lID0gZ2V0TGluZShkb2MsIHRvLmxpbmUpO1xyXG4gICAgdmFyIGxhc3RUZXh0ID0gbHN0KHRleHQpLCBsYXN0U3BhbnMgPSBzcGFuc0Zvcih0ZXh0Lmxlbmd0aCAtIDEpLCBubGluZXMgPSB0by5saW5lIC0gZnJvbS5saW5lO1xyXG5cclxuICAgIC8vIEFkanVzdCB0aGUgbGluZSBzdHJ1Y3R1cmVcclxuICAgIGlmIChjaGFuZ2UuZnVsbCkge1xyXG4gICAgICBkb2MuaW5zZXJ0KDAsIGxpbmVzRm9yKDAsIHRleHQubGVuZ3RoKSk7XHJcbiAgICAgIGRvYy5yZW1vdmUodGV4dC5sZW5ndGgsIGRvYy5zaXplIC0gdGV4dC5sZW5ndGgpO1xyXG4gICAgfSBlbHNlIGlmIChpc1dob2xlTGluZVVwZGF0ZShkb2MsIGNoYW5nZSkpIHtcclxuICAgICAgLy8gVGhpcyBpcyBhIHdob2xlLWxpbmUgcmVwbGFjZS4gVHJlYXRlZCBzcGVjaWFsbHkgdG8gbWFrZVxyXG4gICAgICAvLyBzdXJlIGxpbmUgb2JqZWN0cyBtb3ZlIHRoZSB3YXkgdGhleSBhcmUgc3VwcG9zZWQgdG8uXHJcbiAgICAgIHZhciBhZGRlZCA9IGxpbmVzRm9yKDAsIHRleHQubGVuZ3RoIC0gMSk7XHJcbiAgICAgIHVwZGF0ZShsYXN0TGluZSwgbGFzdExpbmUudGV4dCwgbGFzdFNwYW5zKTtcclxuICAgICAgaWYgKG5saW5lcykgZG9jLnJlbW92ZShmcm9tLmxpbmUsIG5saW5lcyk7XHJcbiAgICAgIGlmIChhZGRlZC5sZW5ndGgpIGRvYy5pbnNlcnQoZnJvbS5saW5lLCBhZGRlZCk7XHJcbiAgICB9IGVsc2UgaWYgKGZpcnN0TGluZSA9PSBsYXN0TGluZSkge1xyXG4gICAgICBpZiAodGV4dC5sZW5ndGggPT0gMSkge1xyXG4gICAgICAgIHVwZGF0ZShmaXJzdExpbmUsIGZpcnN0TGluZS50ZXh0LnNsaWNlKDAsIGZyb20uY2gpICsgbGFzdFRleHQgKyBmaXJzdExpbmUudGV4dC5zbGljZSh0by5jaCksIGxhc3RTcGFucyk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdmFyIGFkZGVkID0gbGluZXNGb3IoMSwgdGV4dC5sZW5ndGggLSAxKTtcclxuICAgICAgICBhZGRlZC5wdXNoKG5ldyBMaW5lKGxhc3RUZXh0ICsgZmlyc3RMaW5lLnRleHQuc2xpY2UodG8uY2gpLCBsYXN0U3BhbnMsIGVzdGltYXRlSGVpZ2h0KSk7XHJcbiAgICAgICAgdXBkYXRlKGZpcnN0TGluZSwgZmlyc3RMaW5lLnRleHQuc2xpY2UoMCwgZnJvbS5jaCkgKyB0ZXh0WzBdLCBzcGFuc0ZvcigwKSk7XHJcbiAgICAgICAgZG9jLmluc2VydChmcm9tLmxpbmUgKyAxLCBhZGRlZCk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSBpZiAodGV4dC5sZW5ndGggPT0gMSkge1xyXG4gICAgICB1cGRhdGUoZmlyc3RMaW5lLCBmaXJzdExpbmUudGV4dC5zbGljZSgwLCBmcm9tLmNoKSArIHRleHRbMF0gKyBsYXN0TGluZS50ZXh0LnNsaWNlKHRvLmNoKSwgc3BhbnNGb3IoMCkpO1xyXG4gICAgICBkb2MucmVtb3ZlKGZyb20ubGluZSArIDEsIG5saW5lcyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB1cGRhdGUoZmlyc3RMaW5lLCBmaXJzdExpbmUudGV4dC5zbGljZSgwLCBmcm9tLmNoKSArIHRleHRbMF0sIHNwYW5zRm9yKDApKTtcclxuICAgICAgdXBkYXRlKGxhc3RMaW5lLCBsYXN0VGV4dCArIGxhc3RMaW5lLnRleHQuc2xpY2UodG8uY2gpLCBsYXN0U3BhbnMpO1xyXG4gICAgICB2YXIgYWRkZWQgPSBsaW5lc0ZvcigxLCB0ZXh0Lmxlbmd0aCAtIDEpO1xyXG4gICAgICBpZiAobmxpbmVzID4gMSkgZG9jLnJlbW92ZShmcm9tLmxpbmUgKyAxLCBubGluZXMgLSAxKTtcclxuICAgICAgZG9jLmluc2VydChmcm9tLmxpbmUgKyAxLCBhZGRlZCk7XHJcbiAgICB9XHJcblxyXG4gICAgc2lnbmFsTGF0ZXIoZG9jLCBcImNoYW5nZVwiLCBkb2MsIGNoYW5nZSk7XHJcbiAgfVxyXG5cclxuICAvLyBUaGUgZG9jdW1lbnQgaXMgcmVwcmVzZW50ZWQgYXMgYSBCVHJlZSBjb25zaXN0aW5nIG9mIGxlYXZlcywgd2l0aFxyXG4gIC8vIGNodW5rIG9mIGxpbmVzIGluIHRoZW0sIGFuZCBicmFuY2hlcywgd2l0aCB1cCB0byB0ZW4gbGVhdmVzIG9yXHJcbiAgLy8gb3RoZXIgYnJhbmNoIG5vZGVzIGJlbG93IHRoZW0uIFRoZSB0b3Agbm9kZSBpcyBhbHdheXMgYSBicmFuY2hcclxuICAvLyBub2RlLCBhbmQgaXMgdGhlIGRvY3VtZW50IG9iamVjdCBpdHNlbGYgKG1lYW5pbmcgaXQgaGFzXHJcbiAgLy8gYWRkaXRpb25hbCBtZXRob2RzIGFuZCBwcm9wZXJ0aWVzKS5cclxuICAvL1xyXG4gIC8vIEFsbCBub2RlcyBoYXZlIHBhcmVudCBsaW5rcy4gVGhlIHRyZWUgaXMgdXNlZCBib3RoIHRvIGdvIGZyb21cclxuICAvLyBsaW5lIG51bWJlcnMgdG8gbGluZSBvYmplY3RzLCBhbmQgdG8gZ28gZnJvbSBvYmplY3RzIHRvIG51bWJlcnMuXHJcbiAgLy8gSXQgYWxzbyBpbmRleGVzIGJ5IGhlaWdodCwgYW5kIGlzIHVzZWQgdG8gY29udmVydCBiZXR3ZWVuIGhlaWdodFxyXG4gIC8vIGFuZCBsaW5lIG9iamVjdCwgYW5kIHRvIGZpbmQgdGhlIHRvdGFsIGhlaWdodCBvZiB0aGUgZG9jdW1lbnQuXHJcbiAgLy9cclxuICAvLyBTZWUgYWxzbyBodHRwOi8vbWFyaWpuaGF2ZXJiZWtlLm5sL2Jsb2cvY29kZW1pcnJvci1saW5lLXRyZWUuaHRtbFxyXG5cclxuICBmdW5jdGlvbiBMZWFmQ2h1bmsobGluZXMpIHtcclxuICAgIHRoaXMubGluZXMgPSBsaW5lcztcclxuICAgIHRoaXMucGFyZW50ID0gbnVsbDtcclxuICAgIGZvciAodmFyIGkgPSAwLCBoZWlnaHQgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyArK2kpIHtcclxuICAgICAgbGluZXNbaV0ucGFyZW50ID0gdGhpcztcclxuICAgICAgaGVpZ2h0ICs9IGxpbmVzW2ldLmhlaWdodDtcclxuICAgIH1cclxuICAgIHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG4gIH1cclxuXHJcbiAgTGVhZkNodW5rLnByb3RvdHlwZSA9IHtcclxuICAgIGNodW5rU2l6ZTogZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzLmxpbmVzLmxlbmd0aDsgfSxcclxuICAgIC8vIFJlbW92ZSB0aGUgbiBsaW5lcyBhdCBvZmZzZXQgJ2F0Jy5cclxuICAgIHJlbW92ZUlubmVyOiBmdW5jdGlvbihhdCwgbikge1xyXG4gICAgICBmb3IgKHZhciBpID0gYXQsIGUgPSBhdCArIG47IGkgPCBlOyArK2kpIHtcclxuICAgICAgICB2YXIgbGluZSA9IHRoaXMubGluZXNbaV07XHJcbiAgICAgICAgdGhpcy5oZWlnaHQgLT0gbGluZS5oZWlnaHQ7XHJcbiAgICAgICAgY2xlYW5VcExpbmUobGluZSk7XHJcbiAgICAgICAgc2lnbmFsTGF0ZXIobGluZSwgXCJkZWxldGVcIik7XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy5saW5lcy5zcGxpY2UoYXQsIG4pO1xyXG4gICAgfSxcclxuICAgIC8vIEhlbHBlciB1c2VkIHRvIGNvbGxhcHNlIGEgc21hbGwgYnJhbmNoIGludG8gYSBzaW5nbGUgbGVhZi5cclxuICAgIGNvbGxhcHNlOiBmdW5jdGlvbihsaW5lcykge1xyXG4gICAgICBsaW5lcy5wdXNoLmFwcGx5KGxpbmVzLCB0aGlzLmxpbmVzKTtcclxuICAgIH0sXHJcbiAgICAvLyBJbnNlcnQgdGhlIGdpdmVuIGFycmF5IG9mIGxpbmVzIGF0IG9mZnNldCAnYXQnLCBjb3VudCB0aGVtIGFzXHJcbiAgICAvLyBoYXZpbmcgdGhlIGdpdmVuIGhlaWdodC5cclxuICAgIGluc2VydElubmVyOiBmdW5jdGlvbihhdCwgbGluZXMsIGhlaWdodCkge1xyXG4gICAgICB0aGlzLmhlaWdodCArPSBoZWlnaHQ7XHJcbiAgICAgIHRoaXMubGluZXMgPSB0aGlzLmxpbmVzLnNsaWNlKDAsIGF0KS5jb25jYXQobGluZXMpLmNvbmNhdCh0aGlzLmxpbmVzLnNsaWNlKGF0KSk7XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyArK2kpIGxpbmVzW2ldLnBhcmVudCA9IHRoaXM7XHJcbiAgICB9LFxyXG4gICAgLy8gVXNlZCB0byBpdGVyYXRlIG92ZXIgYSBwYXJ0IG9mIHRoZSB0cmVlLlxyXG4gICAgaXRlck46IGZ1bmN0aW9uKGF0LCBuLCBvcCkge1xyXG4gICAgICBmb3IgKHZhciBlID0gYXQgKyBuOyBhdCA8IGU7ICsrYXQpXHJcbiAgICAgICAgaWYgKG9wKHRoaXMubGluZXNbYXRdKSkgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgZnVuY3Rpb24gQnJhbmNoQ2h1bmsoY2hpbGRyZW4pIHtcclxuICAgIHRoaXMuY2hpbGRyZW4gPSBjaGlsZHJlbjtcclxuICAgIHZhciBzaXplID0gMCwgaGVpZ2h0ID0gMDtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyArK2kpIHtcclxuICAgICAgdmFyIGNoID0gY2hpbGRyZW5baV07XHJcbiAgICAgIHNpemUgKz0gY2guY2h1bmtTaXplKCk7IGhlaWdodCArPSBjaC5oZWlnaHQ7XHJcbiAgICAgIGNoLnBhcmVudCA9IHRoaXM7XHJcbiAgICB9XHJcbiAgICB0aGlzLnNpemUgPSBzaXplO1xyXG4gICAgdGhpcy5oZWlnaHQgPSBoZWlnaHQ7XHJcbiAgICB0aGlzLnBhcmVudCA9IG51bGw7XHJcbiAgfVxyXG5cclxuICBCcmFuY2hDaHVuay5wcm90b3R5cGUgPSB7XHJcbiAgICBjaHVua1NpemU6IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpcy5zaXplOyB9LFxyXG4gICAgcmVtb3ZlSW5uZXI6IGZ1bmN0aW9uKGF0LCBuKSB7XHJcbiAgICAgIHRoaXMuc2l6ZSAtPSBuO1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyArK2kpIHtcclxuICAgICAgICB2YXIgY2hpbGQgPSB0aGlzLmNoaWxkcmVuW2ldLCBzeiA9IGNoaWxkLmNodW5rU2l6ZSgpO1xyXG4gICAgICAgIGlmIChhdCA8IHN6KSB7XHJcbiAgICAgICAgICB2YXIgcm0gPSBNYXRoLm1pbihuLCBzeiAtIGF0KSwgb2xkSGVpZ2h0ID0gY2hpbGQuaGVpZ2h0O1xyXG4gICAgICAgICAgY2hpbGQucmVtb3ZlSW5uZXIoYXQsIHJtKTtcclxuICAgICAgICAgIHRoaXMuaGVpZ2h0IC09IG9sZEhlaWdodCAtIGNoaWxkLmhlaWdodDtcclxuICAgICAgICAgIGlmIChzeiA9PSBybSkgeyB0aGlzLmNoaWxkcmVuLnNwbGljZShpLS0sIDEpOyBjaGlsZC5wYXJlbnQgPSBudWxsOyB9XHJcbiAgICAgICAgICBpZiAoKG4gLT0gcm0pID09IDApIGJyZWFrO1xyXG4gICAgICAgICAgYXQgPSAwO1xyXG4gICAgICAgIH0gZWxzZSBhdCAtPSBzejtcclxuICAgICAgfVxyXG4gICAgICAvLyBJZiB0aGUgcmVzdWx0IGlzIHNtYWxsZXIgdGhhbiAyNSBsaW5lcywgZW5zdXJlIHRoYXQgaXQgaXMgYVxyXG4gICAgICAvLyBzaW5nbGUgbGVhZiBub2RlLlxyXG4gICAgICBpZiAodGhpcy5zaXplIC0gbiA8IDI1ICYmXHJcbiAgICAgICAgICAodGhpcy5jaGlsZHJlbi5sZW5ndGggPiAxIHx8ICEodGhpcy5jaGlsZHJlblswXSBpbnN0YW5jZW9mIExlYWZDaHVuaykpKSB7XHJcbiAgICAgICAgdmFyIGxpbmVzID0gW107XHJcbiAgICAgICAgdGhpcy5jb2xsYXBzZShsaW5lcyk7XHJcbiAgICAgICAgdGhpcy5jaGlsZHJlbiA9IFtuZXcgTGVhZkNodW5rKGxpbmVzKV07XHJcbiAgICAgICAgdGhpcy5jaGlsZHJlblswXS5wYXJlbnQgPSB0aGlzO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY29sbGFwc2U6IGZ1bmN0aW9uKGxpbmVzKSB7XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jaGlsZHJlbi5sZW5ndGg7ICsraSkgdGhpcy5jaGlsZHJlbltpXS5jb2xsYXBzZShsaW5lcyk7XHJcbiAgICB9LFxyXG4gICAgaW5zZXJ0SW5uZXI6IGZ1bmN0aW9uKGF0LCBsaW5lcywgaGVpZ2h0KSB7XHJcbiAgICAgIHRoaXMuc2l6ZSArPSBsaW5lcy5sZW5ndGg7XHJcbiAgICAgIHRoaXMuaGVpZ2h0ICs9IGhlaWdodDtcclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgKytpKSB7XHJcbiAgICAgICAgdmFyIGNoaWxkID0gdGhpcy5jaGlsZHJlbltpXSwgc3ogPSBjaGlsZC5jaHVua1NpemUoKTtcclxuICAgICAgICBpZiAoYXQgPD0gc3opIHtcclxuICAgICAgICAgIGNoaWxkLmluc2VydElubmVyKGF0LCBsaW5lcywgaGVpZ2h0KTtcclxuICAgICAgICAgIGlmIChjaGlsZC5saW5lcyAmJiBjaGlsZC5saW5lcy5sZW5ndGggPiA1MCkge1xyXG4gICAgICAgICAgICB3aGlsZSAoY2hpbGQubGluZXMubGVuZ3RoID4gNTApIHtcclxuICAgICAgICAgICAgICB2YXIgc3BpbGxlZCA9IGNoaWxkLmxpbmVzLnNwbGljZShjaGlsZC5saW5lcy5sZW5ndGggLSAyNSwgMjUpO1xyXG4gICAgICAgICAgICAgIHZhciBuZXdsZWFmID0gbmV3IExlYWZDaHVuayhzcGlsbGVkKTtcclxuICAgICAgICAgICAgICBjaGlsZC5oZWlnaHQgLT0gbmV3bGVhZi5oZWlnaHQ7XHJcbiAgICAgICAgICAgICAgdGhpcy5jaGlsZHJlbi5zcGxpY2UoaSArIDEsIDAsIG5ld2xlYWYpO1xyXG4gICAgICAgICAgICAgIG5ld2xlYWYucGFyZW50ID0gdGhpcztcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB0aGlzLm1heWJlU3BpbGwoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgICBhdCAtPSBzejtcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIC8vIFdoZW4gYSBub2RlIGhhcyBncm93biwgY2hlY2sgd2hldGhlciBpdCBzaG91bGQgYmUgc3BsaXQuXHJcbiAgICBtYXliZVNwaWxsOiBmdW5jdGlvbigpIHtcclxuICAgICAgaWYgKHRoaXMuY2hpbGRyZW4ubGVuZ3RoIDw9IDEwKSByZXR1cm47XHJcbiAgICAgIHZhciBtZSA9IHRoaXM7XHJcbiAgICAgIGRvIHtcclxuICAgICAgICB2YXIgc3BpbGxlZCA9IG1lLmNoaWxkcmVuLnNwbGljZShtZS5jaGlsZHJlbi5sZW5ndGggLSA1LCA1KTtcclxuICAgICAgICB2YXIgc2libGluZyA9IG5ldyBCcmFuY2hDaHVuayhzcGlsbGVkKTtcclxuICAgICAgICBpZiAoIW1lLnBhcmVudCkgeyAvLyBCZWNvbWUgdGhlIHBhcmVudCBub2RlXHJcbiAgICAgICAgICB2YXIgY29weSA9IG5ldyBCcmFuY2hDaHVuayhtZS5jaGlsZHJlbik7XHJcbiAgICAgICAgICBjb3B5LnBhcmVudCA9IG1lO1xyXG4gICAgICAgICAgbWUuY2hpbGRyZW4gPSBbY29weSwgc2libGluZ107XHJcbiAgICAgICAgICBtZSA9IGNvcHk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIG1lLnNpemUgLT0gc2libGluZy5zaXplO1xyXG4gICAgICAgICAgbWUuaGVpZ2h0IC09IHNpYmxpbmcuaGVpZ2h0O1xyXG4gICAgICAgICAgdmFyIG15SW5kZXggPSBpbmRleE9mKG1lLnBhcmVudC5jaGlsZHJlbiwgbWUpO1xyXG4gICAgICAgICAgbWUucGFyZW50LmNoaWxkcmVuLnNwbGljZShteUluZGV4ICsgMSwgMCwgc2libGluZyk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHNpYmxpbmcucGFyZW50ID0gbWUucGFyZW50O1xyXG4gICAgICB9IHdoaWxlIChtZS5jaGlsZHJlbi5sZW5ndGggPiAxMCk7XHJcbiAgICAgIG1lLnBhcmVudC5tYXliZVNwaWxsKCk7XHJcbiAgICB9LFxyXG4gICAgaXRlck46IGZ1bmN0aW9uKGF0LCBuLCBvcCkge1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyArK2kpIHtcclxuICAgICAgICB2YXIgY2hpbGQgPSB0aGlzLmNoaWxkcmVuW2ldLCBzeiA9IGNoaWxkLmNodW5rU2l6ZSgpO1xyXG4gICAgICAgIGlmIChhdCA8IHN6KSB7XHJcbiAgICAgICAgICB2YXIgdXNlZCA9IE1hdGgubWluKG4sIHN6IC0gYXQpO1xyXG4gICAgICAgICAgaWYgKGNoaWxkLml0ZXJOKGF0LCB1c2VkLCBvcCkpIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgaWYgKChuIC09IHVzZWQpID09IDApIGJyZWFrO1xyXG4gICAgICAgICAgYXQgPSAwO1xyXG4gICAgICAgIH0gZWxzZSBhdCAtPSBzejtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIHZhciBuZXh0RG9jSWQgPSAwO1xyXG4gIHZhciBEb2MgPSBDb2RlTWlycm9yLkRvYyA9IGZ1bmN0aW9uKHRleHQsIG1vZGUsIGZpcnN0TGluZSwgbGluZVNlcCkge1xyXG4gICAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIERvYykpIHJldHVybiBuZXcgRG9jKHRleHQsIG1vZGUsIGZpcnN0TGluZSwgbGluZVNlcCk7XHJcbiAgICBpZiAoZmlyc3RMaW5lID09IG51bGwpIGZpcnN0TGluZSA9IDA7XHJcblxyXG4gICAgQnJhbmNoQ2h1bmsuY2FsbCh0aGlzLCBbbmV3IExlYWZDaHVuayhbbmV3IExpbmUoXCJcIiwgbnVsbCldKV0pO1xyXG4gICAgdGhpcy5maXJzdCA9IGZpcnN0TGluZTtcclxuICAgIHRoaXMuc2Nyb2xsVG9wID0gdGhpcy5zY3JvbGxMZWZ0ID0gMDtcclxuICAgIHRoaXMuY2FudEVkaXQgPSBmYWxzZTtcclxuICAgIHRoaXMuY2xlYW5HZW5lcmF0aW9uID0gMTtcclxuICAgIHRoaXMuZnJvbnRpZXIgPSBmaXJzdExpbmU7XHJcbiAgICB2YXIgc3RhcnQgPSBQb3MoZmlyc3RMaW5lLCAwKTtcclxuICAgIHRoaXMuc2VsID0gc2ltcGxlU2VsZWN0aW9uKHN0YXJ0KTtcclxuICAgIHRoaXMuaGlzdG9yeSA9IG5ldyBIaXN0b3J5KG51bGwpO1xyXG4gICAgdGhpcy5pZCA9ICsrbmV4dERvY0lkO1xyXG4gICAgdGhpcy5tb2RlT3B0aW9uID0gbW9kZTtcclxuICAgIHRoaXMubGluZVNlcCA9IGxpbmVTZXA7XHJcbiAgICB0aGlzLmV4dGVuZCA9IGZhbHNlO1xyXG5cclxuICAgIGlmICh0eXBlb2YgdGV4dCA9PSBcInN0cmluZ1wiKSB0ZXh0ID0gdGhpcy5zcGxpdExpbmVzKHRleHQpO1xyXG4gICAgdXBkYXRlRG9jKHRoaXMsIHtmcm9tOiBzdGFydCwgdG86IHN0YXJ0LCB0ZXh0OiB0ZXh0fSk7XHJcbiAgICBzZXRTZWxlY3Rpb24odGhpcywgc2ltcGxlU2VsZWN0aW9uKHN0YXJ0KSwgc2VsX2RvbnRTY3JvbGwpO1xyXG4gIH07XHJcblxyXG4gIERvYy5wcm90b3R5cGUgPSBjcmVhdGVPYmooQnJhbmNoQ2h1bmsucHJvdG90eXBlLCB7XHJcbiAgICBjb25zdHJ1Y3RvcjogRG9jLFxyXG4gICAgLy8gSXRlcmF0ZSBvdmVyIHRoZSBkb2N1bWVudC4gU3VwcG9ydHMgdHdvIGZvcm1zIC0tIHdpdGggb25seSBvbmVcclxuICAgIC8vIGFyZ3VtZW50LCBpdCBjYWxscyB0aGF0IGZvciBlYWNoIGxpbmUgaW4gdGhlIGRvY3VtZW50LiBXaXRoXHJcbiAgICAvLyB0aHJlZSwgaXQgaXRlcmF0ZXMgb3ZlciB0aGUgcmFuZ2UgZ2l2ZW4gYnkgdGhlIGZpcnN0IHR3byAod2l0aFxyXG4gICAgLy8gdGhlIHNlY29uZCBiZWluZyBub24taW5jbHVzaXZlKS5cclxuICAgIGl0ZXI6IGZ1bmN0aW9uKGZyb20sIHRvLCBvcCkge1xyXG4gICAgICBpZiAob3ApIHRoaXMuaXRlck4oZnJvbSAtIHRoaXMuZmlyc3QsIHRvIC0gZnJvbSwgb3ApO1xyXG4gICAgICBlbHNlIHRoaXMuaXRlck4odGhpcy5maXJzdCwgdGhpcy5maXJzdCArIHRoaXMuc2l6ZSwgZnJvbSk7XHJcbiAgICB9LFxyXG5cclxuICAgIC8vIE5vbi1wdWJsaWMgaW50ZXJmYWNlIGZvciBhZGRpbmcgYW5kIHJlbW92aW5nIGxpbmVzLlxyXG4gICAgaW5zZXJ0OiBmdW5jdGlvbihhdCwgbGluZXMpIHtcclxuICAgICAgdmFyIGhlaWdodCA9IDA7XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyArK2kpIGhlaWdodCArPSBsaW5lc1tpXS5oZWlnaHQ7XHJcbiAgICAgIHRoaXMuaW5zZXJ0SW5uZXIoYXQgLSB0aGlzLmZpcnN0LCBsaW5lcywgaGVpZ2h0KTtcclxuICAgIH0sXHJcbiAgICByZW1vdmU6IGZ1bmN0aW9uKGF0LCBuKSB7IHRoaXMucmVtb3ZlSW5uZXIoYXQgLSB0aGlzLmZpcnN0LCBuKTsgfSxcclxuXHJcbiAgICAvLyBGcm9tIGhlcmUsIHRoZSBtZXRob2RzIGFyZSBwYXJ0IG9mIHRoZSBwdWJsaWMgaW50ZXJmYWNlLiBNb3N0XHJcbiAgICAvLyBhcmUgYWxzbyBhdmFpbGFibGUgZnJvbSBDb2RlTWlycm9yIChlZGl0b3IpIGluc3RhbmNlcy5cclxuXHJcbiAgICBnZXRWYWx1ZTogZnVuY3Rpb24obGluZVNlcCkge1xyXG4gICAgICB2YXIgbGluZXMgPSBnZXRMaW5lcyh0aGlzLCB0aGlzLmZpcnN0LCB0aGlzLmZpcnN0ICsgdGhpcy5zaXplKTtcclxuICAgICAgaWYgKGxpbmVTZXAgPT09IGZhbHNlKSByZXR1cm4gbGluZXM7XHJcbiAgICAgIHJldHVybiBsaW5lcy5qb2luKGxpbmVTZXAgfHwgdGhpcy5saW5lU2VwYXJhdG9yKCkpO1xyXG4gICAgfSxcclxuICAgIHNldFZhbHVlOiBkb2NNZXRob2RPcChmdW5jdGlvbihjb2RlKSB7XHJcbiAgICAgIHZhciB0b3AgPSBQb3ModGhpcy5maXJzdCwgMCksIGxhc3QgPSB0aGlzLmZpcnN0ICsgdGhpcy5zaXplIC0gMTtcclxuICAgICAgbWFrZUNoYW5nZSh0aGlzLCB7ZnJvbTogdG9wLCB0bzogUG9zKGxhc3QsIGdldExpbmUodGhpcywgbGFzdCkudGV4dC5sZW5ndGgpLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiB0aGlzLnNwbGl0TGluZXMoY29kZSksIG9yaWdpbjogXCJzZXRWYWx1ZVwiLCBmdWxsOiB0cnVlfSwgdHJ1ZSk7XHJcbiAgICAgIHNldFNlbGVjdGlvbih0aGlzLCBzaW1wbGVTZWxlY3Rpb24odG9wKSk7XHJcbiAgICB9KSxcclxuICAgIHJlcGxhY2VSYW5nZTogZnVuY3Rpb24oY29kZSwgZnJvbSwgdG8sIG9yaWdpbikge1xyXG4gICAgICBmcm9tID0gY2xpcFBvcyh0aGlzLCBmcm9tKTtcclxuICAgICAgdG8gPSB0byA/IGNsaXBQb3ModGhpcywgdG8pIDogZnJvbTtcclxuICAgICAgcmVwbGFjZVJhbmdlKHRoaXMsIGNvZGUsIGZyb20sIHRvLCBvcmlnaW4pO1xyXG4gICAgfSxcclxuICAgIGdldFJhbmdlOiBmdW5jdGlvbihmcm9tLCB0bywgbGluZVNlcCkge1xyXG4gICAgICB2YXIgbGluZXMgPSBnZXRCZXR3ZWVuKHRoaXMsIGNsaXBQb3ModGhpcywgZnJvbSksIGNsaXBQb3ModGhpcywgdG8pKTtcclxuICAgICAgaWYgKGxpbmVTZXAgPT09IGZhbHNlKSByZXR1cm4gbGluZXM7XHJcbiAgICAgIHJldHVybiBsaW5lcy5qb2luKGxpbmVTZXAgfHwgdGhpcy5saW5lU2VwYXJhdG9yKCkpO1xyXG4gICAgfSxcclxuXHJcbiAgICBnZXRMaW5lOiBmdW5jdGlvbihsaW5lKSB7dmFyIGwgPSB0aGlzLmdldExpbmVIYW5kbGUobGluZSk7IHJldHVybiBsICYmIGwudGV4dDt9LFxyXG5cclxuICAgIGdldExpbmVIYW5kbGU6IGZ1bmN0aW9uKGxpbmUpIHtpZiAoaXNMaW5lKHRoaXMsIGxpbmUpKSByZXR1cm4gZ2V0TGluZSh0aGlzLCBsaW5lKTt9LFxyXG4gICAgZ2V0TGluZU51bWJlcjogZnVuY3Rpb24obGluZSkge3JldHVybiBsaW5lTm8obGluZSk7fSxcclxuXHJcbiAgICBnZXRMaW5lSGFuZGxlVmlzdWFsU3RhcnQ6IGZ1bmN0aW9uKGxpbmUpIHtcclxuICAgICAgaWYgKHR5cGVvZiBsaW5lID09IFwibnVtYmVyXCIpIGxpbmUgPSBnZXRMaW5lKHRoaXMsIGxpbmUpO1xyXG4gICAgICByZXR1cm4gdmlzdWFsTGluZShsaW5lKTtcclxuICAgIH0sXHJcblxyXG4gICAgbGluZUNvdW50OiBmdW5jdGlvbigpIHtyZXR1cm4gdGhpcy5zaXplO30sXHJcbiAgICBmaXJzdExpbmU6IGZ1bmN0aW9uKCkge3JldHVybiB0aGlzLmZpcnN0O30sXHJcbiAgICBsYXN0TGluZTogZnVuY3Rpb24oKSB7cmV0dXJuIHRoaXMuZmlyc3QgKyB0aGlzLnNpemUgLSAxO30sXHJcblxyXG4gICAgY2xpcFBvczogZnVuY3Rpb24ocG9zKSB7cmV0dXJuIGNsaXBQb3ModGhpcywgcG9zKTt9LFxyXG5cclxuICAgIGdldEN1cnNvcjogZnVuY3Rpb24oc3RhcnQpIHtcclxuICAgICAgdmFyIHJhbmdlID0gdGhpcy5zZWwucHJpbWFyeSgpLCBwb3M7XHJcbiAgICAgIGlmIChzdGFydCA9PSBudWxsIHx8IHN0YXJ0ID09IFwiaGVhZFwiKSBwb3MgPSByYW5nZS5oZWFkO1xyXG4gICAgICBlbHNlIGlmIChzdGFydCA9PSBcImFuY2hvclwiKSBwb3MgPSByYW5nZS5hbmNob3I7XHJcbiAgICAgIGVsc2UgaWYgKHN0YXJ0ID09IFwiZW5kXCIgfHwgc3RhcnQgPT0gXCJ0b1wiIHx8IHN0YXJ0ID09PSBmYWxzZSkgcG9zID0gcmFuZ2UudG8oKTtcclxuICAgICAgZWxzZSBwb3MgPSByYW5nZS5mcm9tKCk7XHJcbiAgICAgIHJldHVybiBwb3M7XHJcbiAgICB9LFxyXG4gICAgbGlzdFNlbGVjdGlvbnM6IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpcy5zZWwucmFuZ2VzOyB9LFxyXG4gICAgc29tZXRoaW5nU2VsZWN0ZWQ6IGZ1bmN0aW9uKCkge3JldHVybiB0aGlzLnNlbC5zb21ldGhpbmdTZWxlY3RlZCgpO30sXHJcblxyXG4gICAgc2V0Q3Vyc29yOiBkb2NNZXRob2RPcChmdW5jdGlvbihsaW5lLCBjaCwgb3B0aW9ucykge1xyXG4gICAgICBzZXRTaW1wbGVTZWxlY3Rpb24odGhpcywgY2xpcFBvcyh0aGlzLCB0eXBlb2YgbGluZSA9PSBcIm51bWJlclwiID8gUG9zKGxpbmUsIGNoIHx8IDApIDogbGluZSksIG51bGwsIG9wdGlvbnMpO1xyXG4gICAgfSksXHJcbiAgICBzZXRTZWxlY3Rpb246IGRvY01ldGhvZE9wKGZ1bmN0aW9uKGFuY2hvciwgaGVhZCwgb3B0aW9ucykge1xyXG4gICAgICBzZXRTaW1wbGVTZWxlY3Rpb24odGhpcywgY2xpcFBvcyh0aGlzLCBhbmNob3IpLCBjbGlwUG9zKHRoaXMsIGhlYWQgfHwgYW5jaG9yKSwgb3B0aW9ucyk7XHJcbiAgICB9KSxcclxuICAgIGV4dGVuZFNlbGVjdGlvbjogZG9jTWV0aG9kT3AoZnVuY3Rpb24oaGVhZCwgb3RoZXIsIG9wdGlvbnMpIHtcclxuICAgICAgZXh0ZW5kU2VsZWN0aW9uKHRoaXMsIGNsaXBQb3ModGhpcywgaGVhZCksIG90aGVyICYmIGNsaXBQb3ModGhpcywgb3RoZXIpLCBvcHRpb25zKTtcclxuICAgIH0pLFxyXG4gICAgZXh0ZW5kU2VsZWN0aW9uczogZG9jTWV0aG9kT3AoZnVuY3Rpb24oaGVhZHMsIG9wdGlvbnMpIHtcclxuICAgICAgZXh0ZW5kU2VsZWN0aW9ucyh0aGlzLCBjbGlwUG9zQXJyYXkodGhpcywgaGVhZHMsIG9wdGlvbnMpKTtcclxuICAgIH0pLFxyXG4gICAgZXh0ZW5kU2VsZWN0aW9uc0J5OiBkb2NNZXRob2RPcChmdW5jdGlvbihmLCBvcHRpb25zKSB7XHJcbiAgICAgIGV4dGVuZFNlbGVjdGlvbnModGhpcywgbWFwKHRoaXMuc2VsLnJhbmdlcywgZiksIG9wdGlvbnMpO1xyXG4gICAgfSksXHJcbiAgICBzZXRTZWxlY3Rpb25zOiBkb2NNZXRob2RPcChmdW5jdGlvbihyYW5nZXMsIHByaW1hcnksIG9wdGlvbnMpIHtcclxuICAgICAgaWYgKCFyYW5nZXMubGVuZ3RoKSByZXR1cm47XHJcbiAgICAgIGZvciAodmFyIGkgPSAwLCBvdXQgPSBbXTsgaSA8IHJhbmdlcy5sZW5ndGg7IGkrKylcclxuICAgICAgICBvdXRbaV0gPSBuZXcgUmFuZ2UoY2xpcFBvcyh0aGlzLCByYW5nZXNbaV0uYW5jaG9yKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpcFBvcyh0aGlzLCByYW5nZXNbaV0uaGVhZCkpO1xyXG4gICAgICBpZiAocHJpbWFyeSA9PSBudWxsKSBwcmltYXJ5ID0gTWF0aC5taW4ocmFuZ2VzLmxlbmd0aCAtIDEsIHRoaXMuc2VsLnByaW1JbmRleCk7XHJcbiAgICAgIHNldFNlbGVjdGlvbih0aGlzLCBub3JtYWxpemVTZWxlY3Rpb24ob3V0LCBwcmltYXJ5KSwgb3B0aW9ucyk7XHJcbiAgICB9KSxcclxuICAgIGFkZFNlbGVjdGlvbjogZG9jTWV0aG9kT3AoZnVuY3Rpb24oYW5jaG9yLCBoZWFkLCBvcHRpb25zKSB7XHJcbiAgICAgIHZhciByYW5nZXMgPSB0aGlzLnNlbC5yYW5nZXMuc2xpY2UoMCk7XHJcbiAgICAgIHJhbmdlcy5wdXNoKG5ldyBSYW5nZShjbGlwUG9zKHRoaXMsIGFuY2hvciksIGNsaXBQb3ModGhpcywgaGVhZCB8fCBhbmNob3IpKSk7XHJcbiAgICAgIHNldFNlbGVjdGlvbih0aGlzLCBub3JtYWxpemVTZWxlY3Rpb24ocmFuZ2VzLCByYW5nZXMubGVuZ3RoIC0gMSksIG9wdGlvbnMpO1xyXG4gICAgfSksXHJcblxyXG4gICAgZ2V0U2VsZWN0aW9uOiBmdW5jdGlvbihsaW5lU2VwKSB7XHJcbiAgICAgIHZhciByYW5nZXMgPSB0aGlzLnNlbC5yYW5nZXMsIGxpbmVzO1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJhbmdlcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIHZhciBzZWwgPSBnZXRCZXR3ZWVuKHRoaXMsIHJhbmdlc1tpXS5mcm9tKCksIHJhbmdlc1tpXS50bygpKTtcclxuICAgICAgICBsaW5lcyA9IGxpbmVzID8gbGluZXMuY29uY2F0KHNlbCkgOiBzZWw7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKGxpbmVTZXAgPT09IGZhbHNlKSByZXR1cm4gbGluZXM7XHJcbiAgICAgIGVsc2UgcmV0dXJuIGxpbmVzLmpvaW4obGluZVNlcCB8fCB0aGlzLmxpbmVTZXBhcmF0b3IoKSk7XHJcbiAgICB9LFxyXG4gICAgZ2V0U2VsZWN0aW9uczogZnVuY3Rpb24obGluZVNlcCkge1xyXG4gICAgICB2YXIgcGFydHMgPSBbXSwgcmFuZ2VzID0gdGhpcy5zZWwucmFuZ2VzO1xyXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJhbmdlcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIHZhciBzZWwgPSBnZXRCZXR3ZWVuKHRoaXMsIHJhbmdlc1tpXS5mcm9tKCksIHJhbmdlc1tpXS50bygpKTtcclxuICAgICAgICBpZiAobGluZVNlcCAhPT0gZmFsc2UpIHNlbCA9IHNlbC5qb2luKGxpbmVTZXAgfHwgdGhpcy5saW5lU2VwYXJhdG9yKCkpO1xyXG4gICAgICAgIHBhcnRzW2ldID0gc2VsO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBwYXJ0cztcclxuICAgIH0sXHJcbiAgICByZXBsYWNlU2VsZWN0aW9uOiBmdW5jdGlvbihjb2RlLCBjb2xsYXBzZSwgb3JpZ2luKSB7XHJcbiAgICAgIHZhciBkdXAgPSBbXTtcclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnNlbC5yYW5nZXMubGVuZ3RoOyBpKyspXHJcbiAgICAgICAgZHVwW2ldID0gY29kZTtcclxuICAgICAgdGhpcy5yZXBsYWNlU2VsZWN0aW9ucyhkdXAsIGNvbGxhcHNlLCBvcmlnaW4gfHwgXCIraW5wdXRcIik7XHJcbiAgICB9LFxyXG4gICAgcmVwbGFjZVNlbGVjdGlvbnM6IGRvY01ldGhvZE9wKGZ1bmN0aW9uKGNvZGUsIGNvbGxhcHNlLCBvcmlnaW4pIHtcclxuICAgICAgdmFyIGNoYW5nZXMgPSBbXSwgc2VsID0gdGhpcy5zZWw7XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgc2VsLnJhbmdlcy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIHZhciByYW5nZSA9IHNlbC5yYW5nZXNbaV07XHJcbiAgICAgICAgY2hhbmdlc1tpXSA9IHtmcm9tOiByYW5nZS5mcm9tKCksIHRvOiByYW5nZS50bygpLCB0ZXh0OiB0aGlzLnNwbGl0TGluZXMoY29kZVtpXSksIG9yaWdpbjogb3JpZ2lufTtcclxuICAgICAgfVxyXG4gICAgICB2YXIgbmV3U2VsID0gY29sbGFwc2UgJiYgY29sbGFwc2UgIT0gXCJlbmRcIiAmJiBjb21wdXRlUmVwbGFjZWRTZWwodGhpcywgY2hhbmdlcywgY29sbGFwc2UpO1xyXG4gICAgICBmb3IgKHZhciBpID0gY2hhbmdlcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSlcclxuICAgICAgICBtYWtlQ2hhbmdlKHRoaXMsIGNoYW5nZXNbaV0pO1xyXG4gICAgICBpZiAobmV3U2VsKSBzZXRTZWxlY3Rpb25SZXBsYWNlSGlzdG9yeSh0aGlzLCBuZXdTZWwpO1xyXG4gICAgICBlbHNlIGlmICh0aGlzLmNtKSBlbnN1cmVDdXJzb3JWaXNpYmxlKHRoaXMuY20pO1xyXG4gICAgfSksXHJcbiAgICB1bmRvOiBkb2NNZXRob2RPcChmdW5jdGlvbigpIHttYWtlQ2hhbmdlRnJvbUhpc3RvcnkodGhpcywgXCJ1bmRvXCIpO30pLFxyXG4gICAgcmVkbzogZG9jTWV0aG9kT3AoZnVuY3Rpb24oKSB7bWFrZUNoYW5nZUZyb21IaXN0b3J5KHRoaXMsIFwicmVkb1wiKTt9KSxcclxuICAgIHVuZG9TZWxlY3Rpb246IGRvY01ldGhvZE9wKGZ1bmN0aW9uKCkge21ha2VDaGFuZ2VGcm9tSGlzdG9yeSh0aGlzLCBcInVuZG9cIiwgdHJ1ZSk7fSksXHJcbiAgICByZWRvU2VsZWN0aW9uOiBkb2NNZXRob2RPcChmdW5jdGlvbigpIHttYWtlQ2hhbmdlRnJvbUhpc3RvcnkodGhpcywgXCJyZWRvXCIsIHRydWUpO30pLFxyXG5cclxuICAgIHNldEV4dGVuZGluZzogZnVuY3Rpb24odmFsKSB7dGhpcy5leHRlbmQgPSB2YWw7fSxcclxuICAgIGdldEV4dGVuZGluZzogZnVuY3Rpb24oKSB7cmV0dXJuIHRoaXMuZXh0ZW5kO30sXHJcblxyXG4gICAgaGlzdG9yeVNpemU6IGZ1bmN0aW9uKCkge1xyXG4gICAgICB2YXIgaGlzdCA9IHRoaXMuaGlzdG9yeSwgZG9uZSA9IDAsIHVuZG9uZSA9IDA7XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaGlzdC5kb25lLmxlbmd0aDsgaSsrKSBpZiAoIWhpc3QuZG9uZVtpXS5yYW5nZXMpICsrZG9uZTtcclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoaXN0LnVuZG9uZS5sZW5ndGg7IGkrKykgaWYgKCFoaXN0LnVuZG9uZVtpXS5yYW5nZXMpICsrdW5kb25lO1xyXG4gICAgICByZXR1cm4ge3VuZG86IGRvbmUsIHJlZG86IHVuZG9uZX07XHJcbiAgICB9LFxyXG4gICAgY2xlYXJIaXN0b3J5OiBmdW5jdGlvbigpIHt0aGlzLmhpc3RvcnkgPSBuZXcgSGlzdG9yeSh0aGlzLmhpc3RvcnkubWF4R2VuZXJhdGlvbik7fSxcclxuXHJcbiAgICBtYXJrQ2xlYW46IGZ1bmN0aW9uKCkge1xyXG4gICAgICB0aGlzLmNsZWFuR2VuZXJhdGlvbiA9IHRoaXMuY2hhbmdlR2VuZXJhdGlvbih0cnVlKTtcclxuICAgIH0sXHJcbiAgICBjaGFuZ2VHZW5lcmF0aW9uOiBmdW5jdGlvbihmb3JjZVNwbGl0KSB7XHJcbiAgICAgIGlmIChmb3JjZVNwbGl0KVxyXG4gICAgICAgIHRoaXMuaGlzdG9yeS5sYXN0T3AgPSB0aGlzLmhpc3RvcnkubGFzdFNlbE9wID0gdGhpcy5oaXN0b3J5Lmxhc3RPcmlnaW4gPSBudWxsO1xyXG4gICAgICByZXR1cm4gdGhpcy5oaXN0b3J5LmdlbmVyYXRpb247XHJcbiAgICB9LFxyXG4gICAgaXNDbGVhbjogZnVuY3Rpb24gKGdlbikge1xyXG4gICAgICByZXR1cm4gdGhpcy5oaXN0b3J5LmdlbmVyYXRpb24gPT0gKGdlbiB8fCB0aGlzLmNsZWFuR2VuZXJhdGlvbik7XHJcbiAgICB9LFxyXG5cclxuICAgIGdldEhpc3Rvcnk6IGZ1bmN0aW9uKCkge1xyXG4gICAgICByZXR1cm4ge2RvbmU6IGNvcHlIaXN0b3J5QXJyYXkodGhpcy5oaXN0b3J5LmRvbmUpLFxyXG4gICAgICAgICAgICAgIHVuZG9uZTogY29weUhpc3RvcnlBcnJheSh0aGlzLmhpc3RvcnkudW5kb25lKX07XHJcbiAgICB9LFxyXG4gICAgc2V0SGlzdG9yeTogZnVuY3Rpb24oaGlzdERhdGEpIHtcclxuICAgICAgdmFyIGhpc3QgPSB0aGlzLmhpc3RvcnkgPSBuZXcgSGlzdG9yeSh0aGlzLmhpc3RvcnkubWF4R2VuZXJhdGlvbik7XHJcbiAgICAgIGhpc3QuZG9uZSA9IGNvcHlIaXN0b3J5QXJyYXkoaGlzdERhdGEuZG9uZS5zbGljZSgwKSwgbnVsbCwgdHJ1ZSk7XHJcbiAgICAgIGhpc3QudW5kb25lID0gY29weUhpc3RvcnlBcnJheShoaXN0RGF0YS51bmRvbmUuc2xpY2UoMCksIG51bGwsIHRydWUpO1xyXG4gICAgfSxcclxuXHJcbiAgICBhZGRMaW5lQ2xhc3M6IGRvY01ldGhvZE9wKGZ1bmN0aW9uKGhhbmRsZSwgd2hlcmUsIGNscykge1xyXG4gICAgICByZXR1cm4gY2hhbmdlTGluZSh0aGlzLCBoYW5kbGUsIHdoZXJlID09IFwiZ3V0dGVyXCIgPyBcImd1dHRlclwiIDogXCJjbGFzc1wiLCBmdW5jdGlvbihsaW5lKSB7XHJcbiAgICAgICAgdmFyIHByb3AgPSB3aGVyZSA9PSBcInRleHRcIiA/IFwidGV4dENsYXNzXCJcclxuICAgICAgICAgICAgICAgICA6IHdoZXJlID09IFwiYmFja2dyb3VuZFwiID8gXCJiZ0NsYXNzXCJcclxuICAgICAgICAgICAgICAgICA6IHdoZXJlID09IFwiZ3V0dGVyXCIgPyBcImd1dHRlckNsYXNzXCIgOiBcIndyYXBDbGFzc1wiO1xyXG4gICAgICAgIGlmICghbGluZVtwcm9wXSkgbGluZVtwcm9wXSA9IGNscztcclxuICAgICAgICBlbHNlIGlmIChjbGFzc1Rlc3QoY2xzKS50ZXN0KGxpbmVbcHJvcF0pKSByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgZWxzZSBsaW5lW3Byb3BdICs9IFwiIFwiICsgY2xzO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH0pLFxyXG4gICAgcmVtb3ZlTGluZUNsYXNzOiBkb2NNZXRob2RPcChmdW5jdGlvbihoYW5kbGUsIHdoZXJlLCBjbHMpIHtcclxuICAgICAgcmV0dXJuIGNoYW5nZUxpbmUodGhpcywgaGFuZGxlLCB3aGVyZSA9PSBcImd1dHRlclwiID8gXCJndXR0ZXJcIiA6IFwiY2xhc3NcIiwgZnVuY3Rpb24obGluZSkge1xyXG4gICAgICAgIHZhciBwcm9wID0gd2hlcmUgPT0gXCJ0ZXh0XCIgPyBcInRleHRDbGFzc1wiXHJcbiAgICAgICAgICAgICAgICAgOiB3aGVyZSA9PSBcImJhY2tncm91bmRcIiA/IFwiYmdDbGFzc1wiXHJcbiAgICAgICAgICAgICAgICAgOiB3aGVyZSA9PSBcImd1dHRlclwiID8gXCJndXR0ZXJDbGFzc1wiIDogXCJ3cmFwQ2xhc3NcIjtcclxuICAgICAgICB2YXIgY3VyID0gbGluZVtwcm9wXTtcclxuICAgICAgICBpZiAoIWN1cikgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIGVsc2UgaWYgKGNscyA9PSBudWxsKSBsaW5lW3Byb3BdID0gbnVsbDtcclxuICAgICAgICBlbHNlIHtcclxuICAgICAgICAgIHZhciBmb3VuZCA9IGN1ci5tYXRjaChjbGFzc1Rlc3QoY2xzKSk7XHJcbiAgICAgICAgICBpZiAoIWZvdW5kKSByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgICB2YXIgZW5kID0gZm91bmQuaW5kZXggKyBmb3VuZFswXS5sZW5ndGg7XHJcbiAgICAgICAgICBsaW5lW3Byb3BdID0gY3VyLnNsaWNlKDAsIGZvdW5kLmluZGV4KSArICghZm91bmQuaW5kZXggfHwgZW5kID09IGN1ci5sZW5ndGggPyBcIlwiIDogXCIgXCIpICsgY3VyLnNsaWNlKGVuZCkgfHwgbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgIH0pO1xyXG4gICAgfSksXHJcblxyXG4gICAgYWRkTGluZVdpZGdldDogZG9jTWV0aG9kT3AoZnVuY3Rpb24oaGFuZGxlLCBub2RlLCBvcHRpb25zKSB7XHJcbiAgICAgIHJldHVybiBhZGRMaW5lV2lkZ2V0KHRoaXMsIGhhbmRsZSwgbm9kZSwgb3B0aW9ucyk7XHJcbiAgICB9KSxcclxuICAgIHJlbW92ZUxpbmVXaWRnZXQ6IGZ1bmN0aW9uKHdpZGdldCkgeyB3aWRnZXQuY2xlYXIoKTsgfSxcclxuXHJcbiAgICBtYXJrVGV4dDogZnVuY3Rpb24oZnJvbSwgdG8sIG9wdGlvbnMpIHtcclxuICAgICAgcmV0dXJuIG1hcmtUZXh0KHRoaXMsIGNsaXBQb3ModGhpcywgZnJvbSksIGNsaXBQb3ModGhpcywgdG8pLCBvcHRpb25zLCBvcHRpb25zICYmIG9wdGlvbnMudHlwZSB8fCBcInJhbmdlXCIpO1xyXG4gICAgfSxcclxuICAgIHNldEJvb2ttYXJrOiBmdW5jdGlvbihwb3MsIG9wdGlvbnMpIHtcclxuICAgICAgdmFyIHJlYWxPcHRzID0ge3JlcGxhY2VkV2l0aDogb3B0aW9ucyAmJiAob3B0aW9ucy5ub2RlVHlwZSA9PSBudWxsID8gb3B0aW9ucy53aWRnZXQgOiBvcHRpb25zKSxcclxuICAgICAgICAgICAgICAgICAgICAgIGluc2VydExlZnQ6IG9wdGlvbnMgJiYgb3B0aW9ucy5pbnNlcnRMZWZ0LFxyXG4gICAgICAgICAgICAgICAgICAgICAgY2xlYXJXaGVuRW1wdHk6IGZhbHNlLCBzaGFyZWQ6IG9wdGlvbnMgJiYgb3B0aW9ucy5zaGFyZWQsXHJcbiAgICAgICAgICAgICAgICAgICAgICBoYW5kbGVNb3VzZUV2ZW50czogb3B0aW9ucyAmJiBvcHRpb25zLmhhbmRsZU1vdXNlRXZlbnRzfTtcclxuICAgICAgcG9zID0gY2xpcFBvcyh0aGlzLCBwb3MpO1xyXG4gICAgICByZXR1cm4gbWFya1RleHQodGhpcywgcG9zLCBwb3MsIHJlYWxPcHRzLCBcImJvb2ttYXJrXCIpO1xyXG4gICAgfSxcclxuICAgIGZpbmRNYXJrc0F0OiBmdW5jdGlvbihwb3MpIHtcclxuICAgICAgcG9zID0gY2xpcFBvcyh0aGlzLCBwb3MpO1xyXG4gICAgICB2YXIgbWFya2VycyA9IFtdLCBzcGFucyA9IGdldExpbmUodGhpcywgcG9zLmxpbmUpLm1hcmtlZFNwYW5zO1xyXG4gICAgICBpZiAoc3BhbnMpIGZvciAodmFyIGkgPSAwOyBpIDwgc3BhbnMubGVuZ3RoOyArK2kpIHtcclxuICAgICAgICB2YXIgc3BhbiA9IHNwYW5zW2ldO1xyXG4gICAgICAgIGlmICgoc3Bhbi5mcm9tID09IG51bGwgfHwgc3Bhbi5mcm9tIDw9IHBvcy5jaCkgJiZcclxuICAgICAgICAgICAgKHNwYW4udG8gPT0gbnVsbCB8fCBzcGFuLnRvID49IHBvcy5jaCkpXHJcbiAgICAgICAgICBtYXJrZXJzLnB1c2goc3Bhbi5tYXJrZXIucGFyZW50IHx8IHNwYW4ubWFya2VyKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gbWFya2VycztcclxuICAgIH0sXHJcbiAgICBmaW5kTWFya3M6IGZ1bmN0aW9uKGZyb20sIHRvLCBmaWx0ZXIpIHtcclxuICAgICAgZnJvbSA9IGNsaXBQb3ModGhpcywgZnJvbSk7IHRvID0gY2xpcFBvcyh0aGlzLCB0byk7XHJcbiAgICAgIHZhciBmb3VuZCA9IFtdLCBsaW5lTm8gPSBmcm9tLmxpbmU7XHJcbiAgICAgIHRoaXMuaXRlcihmcm9tLmxpbmUsIHRvLmxpbmUgKyAxLCBmdW5jdGlvbihsaW5lKSB7XHJcbiAgICAgICAgdmFyIHNwYW5zID0gbGluZS5tYXJrZWRTcGFucztcclxuICAgICAgICBpZiAoc3BhbnMpIGZvciAodmFyIGkgPSAwOyBpIDwgc3BhbnMubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICAgIHZhciBzcGFuID0gc3BhbnNbaV07XHJcbiAgICAgICAgICBpZiAoIShsaW5lTm8gPT0gZnJvbS5saW5lICYmIGZyb20uY2ggPiBzcGFuLnRvIHx8XHJcbiAgICAgICAgICAgICAgICBzcGFuLmZyb20gPT0gbnVsbCAmJiBsaW5lTm8gIT0gZnJvbS5saW5lfHxcclxuICAgICAgICAgICAgICAgIGxpbmVObyA9PSB0by5saW5lICYmIHNwYW4uZnJvbSA+IHRvLmNoKSAmJlxyXG4gICAgICAgICAgICAgICghZmlsdGVyIHx8IGZpbHRlcihzcGFuLm1hcmtlcikpKVxyXG4gICAgICAgICAgICBmb3VuZC5wdXNoKHNwYW4ubWFya2VyLnBhcmVudCB8fCBzcGFuLm1hcmtlcik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgICsrbGluZU5vO1xyXG4gICAgICB9KTtcclxuICAgICAgcmV0dXJuIGZvdW5kO1xyXG4gICAgfSxcclxuICAgIGdldEFsbE1hcmtzOiBmdW5jdGlvbigpIHtcclxuICAgICAgdmFyIG1hcmtlcnMgPSBbXTtcclxuICAgICAgdGhpcy5pdGVyKGZ1bmN0aW9uKGxpbmUpIHtcclxuICAgICAgICB2YXIgc3BzID0gbGluZS5tYXJrZWRTcGFucztcclxuICAgICAgICBpZiAoc3BzKSBmb3IgKHZhciBpID0gMDsgaSA8IHNwcy5sZW5ndGg7ICsraSlcclxuICAgICAgICAgIGlmIChzcHNbaV0uZnJvbSAhPSBudWxsKSBtYXJrZXJzLnB1c2goc3BzW2ldLm1hcmtlcik7XHJcbiAgICAgIH0pO1xyXG4gICAgICByZXR1cm4gbWFya2VycztcclxuICAgIH0sXHJcblxyXG4gICAgcG9zRnJvbUluZGV4OiBmdW5jdGlvbihvZmYpIHtcclxuICAgICAgdmFyIGNoLCBsaW5lTm8gPSB0aGlzLmZpcnN0O1xyXG4gICAgICB0aGlzLml0ZXIoZnVuY3Rpb24obGluZSkge1xyXG4gICAgICAgIHZhciBzeiA9IGxpbmUudGV4dC5sZW5ndGggKyAxO1xyXG4gICAgICAgIGlmIChzeiA+IG9mZikgeyBjaCA9IG9mZjsgcmV0dXJuIHRydWU7IH1cclxuICAgICAgICBvZmYgLT0gc3o7XHJcbiAgICAgICAgKytsaW5lTm87XHJcbiAgICAgIH0pO1xyXG4gICAgICByZXR1cm4gY2xpcFBvcyh0aGlzLCBQb3MobGluZU5vLCBjaCkpO1xyXG4gICAgfSxcclxuICAgIGluZGV4RnJvbVBvczogZnVuY3Rpb24gKGNvb3Jkcykge1xyXG4gICAgICBjb29yZHMgPSBjbGlwUG9zKHRoaXMsIGNvb3Jkcyk7XHJcbiAgICAgIHZhciBpbmRleCA9IGNvb3Jkcy5jaDtcclxuICAgICAgaWYgKGNvb3Jkcy5saW5lIDwgdGhpcy5maXJzdCB8fCBjb29yZHMuY2ggPCAwKSByZXR1cm4gMDtcclxuICAgICAgdGhpcy5pdGVyKHRoaXMuZmlyc3QsIGNvb3Jkcy5saW5lLCBmdW5jdGlvbiAobGluZSkge1xyXG4gICAgICAgIGluZGV4ICs9IGxpbmUudGV4dC5sZW5ndGggKyAxO1xyXG4gICAgICB9KTtcclxuICAgICAgcmV0dXJuIGluZGV4O1xyXG4gICAgfSxcclxuXHJcbiAgICBjb3B5OiBmdW5jdGlvbihjb3B5SGlzdG9yeSkge1xyXG4gICAgICB2YXIgZG9jID0gbmV3IERvYyhnZXRMaW5lcyh0aGlzLCB0aGlzLmZpcnN0LCB0aGlzLmZpcnN0ICsgdGhpcy5zaXplKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5tb2RlT3B0aW9uLCB0aGlzLmZpcnN0LCB0aGlzLmxpbmVTZXApO1xyXG4gICAgICBkb2Muc2Nyb2xsVG9wID0gdGhpcy5zY3JvbGxUb3A7IGRvYy5zY3JvbGxMZWZ0ID0gdGhpcy5zY3JvbGxMZWZ0O1xyXG4gICAgICBkb2Muc2VsID0gdGhpcy5zZWw7XHJcbiAgICAgIGRvYy5leHRlbmQgPSBmYWxzZTtcclxuICAgICAgaWYgKGNvcHlIaXN0b3J5KSB7XHJcbiAgICAgICAgZG9jLmhpc3RvcnkudW5kb0RlcHRoID0gdGhpcy5oaXN0b3J5LnVuZG9EZXB0aDtcclxuICAgICAgICBkb2Muc2V0SGlzdG9yeSh0aGlzLmdldEhpc3RvcnkoKSk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIGRvYztcclxuICAgIH0sXHJcblxyXG4gICAgbGlua2VkRG9jOiBmdW5jdGlvbihvcHRpb25zKSB7XHJcbiAgICAgIGlmICghb3B0aW9ucykgb3B0aW9ucyA9IHt9O1xyXG4gICAgICB2YXIgZnJvbSA9IHRoaXMuZmlyc3QsIHRvID0gdGhpcy5maXJzdCArIHRoaXMuc2l6ZTtcclxuICAgICAgaWYgKG9wdGlvbnMuZnJvbSAhPSBudWxsICYmIG9wdGlvbnMuZnJvbSA+IGZyb20pIGZyb20gPSBvcHRpb25zLmZyb207XHJcbiAgICAgIGlmIChvcHRpb25zLnRvICE9IG51bGwgJiYgb3B0aW9ucy50byA8IHRvKSB0byA9IG9wdGlvbnMudG87XHJcbiAgICAgIHZhciBjb3B5ID0gbmV3IERvYyhnZXRMaW5lcyh0aGlzLCBmcm9tLCB0byksIG9wdGlvbnMubW9kZSB8fCB0aGlzLm1vZGVPcHRpb24sIGZyb20sIHRoaXMubGluZVNlcCk7XHJcbiAgICAgIGlmIChvcHRpb25zLnNoYXJlZEhpc3QpIGNvcHkuaGlzdG9yeSA9IHRoaXMuaGlzdG9yeTtcclxuICAgICAgKHRoaXMubGlua2VkIHx8ICh0aGlzLmxpbmtlZCA9IFtdKSkucHVzaCh7ZG9jOiBjb3B5LCBzaGFyZWRIaXN0OiBvcHRpb25zLnNoYXJlZEhpc3R9KTtcclxuICAgICAgY29weS5saW5rZWQgPSBbe2RvYzogdGhpcywgaXNQYXJlbnQ6IHRydWUsIHNoYXJlZEhpc3Q6IG9wdGlvbnMuc2hhcmVkSGlzdH1dO1xyXG4gICAgICBjb3B5U2hhcmVkTWFya2Vycyhjb3B5LCBmaW5kU2hhcmVkTWFya2Vycyh0aGlzKSk7XHJcbiAgICAgIHJldHVybiBjb3B5O1xyXG4gICAgfSxcclxuICAgIHVubGlua0RvYzogZnVuY3Rpb24ob3RoZXIpIHtcclxuICAgICAgaWYgKG90aGVyIGluc3RhbmNlb2YgQ29kZU1pcnJvcikgb3RoZXIgPSBvdGhlci5kb2M7XHJcbiAgICAgIGlmICh0aGlzLmxpbmtlZCkgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxpbmtlZC5sZW5ndGg7ICsraSkge1xyXG4gICAgICAgIHZhciBsaW5rID0gdGhpcy5saW5rZWRbaV07XHJcbiAgICAgICAgaWYgKGxpbmsuZG9jICE9IG90aGVyKSBjb250aW51ZTtcclxuICAgICAgICB0aGlzLmxpbmtlZC5zcGxpY2UoaSwgMSk7XHJcbiAgICAgICAgb3RoZXIudW5saW5rRG9jKHRoaXMpO1xyXG4gICAgICAgIGRldGFjaFNoYXJlZE1hcmtlcnMoZmluZFNoYXJlZE1hcmtlcnModGhpcykpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICB9XHJcbiAgICAgIC8vIElmIHRoZSBoaXN0b3JpZXMgd2VyZSBzaGFyZWQsIHNwbGl0IHRoZW0gYWdhaW5cclxuICAgICAgaWYgKG90aGVyLmhpc3RvcnkgPT0gdGhpcy5oaXN0b3J5KSB7XHJcbiAgICAgICAgdmFyIHNwbGl0SWRzID0gW290aGVyLmlkXTtcclxuICAgICAgICBsaW5rZWREb2NzKG90aGVyLCBmdW5jdGlvbihkb2MpIHtzcGxpdElkcy5wdXNoKGRvYy5pZCk7fSwgdHJ1ZSk7XHJcbiAgICAgICAgb3RoZXIuaGlzdG9yeSA9IG5ldyBIaXN0b3J5KG51bGwpO1xyXG4gICAgICAgIG90aGVyLmhpc3RvcnkuZG9uZSA9IGNvcHlIaXN0b3J5QXJyYXkodGhpcy5oaXN0b3J5LmRvbmUsIHNwbGl0SWRzKTtcclxuICAgICAgICBvdGhlci5oaXN0b3J5LnVuZG9uZSA9IGNvcHlIaXN0b3J5QXJyYXkodGhpcy5oaXN0b3J5LnVuZG9uZSwgc3BsaXRJZHMpO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaXRlckxpbmtlZERvY3M6IGZ1bmN0aW9uKGYpIHtsaW5rZWREb2NzKHRoaXMsIGYpO30sXHJcblxyXG4gICAgZ2V0TW9kZTogZnVuY3Rpb24oKSB7cmV0dXJuIHRoaXMubW9kZTt9LFxyXG4gICAgZ2V0RWRpdG9yOiBmdW5jdGlvbigpIHtyZXR1cm4gdGhpcy5jbTt9LFxyXG5cclxuICAgIHNwbGl0TGluZXM6IGZ1bmN0aW9uKHN0cikge1xyXG4gICAgICBpZiAodGhpcy5saW5lU2VwKSByZXR1cm4gc3RyLnNwbGl0KHRoaXMubGluZVNlcCk7XHJcbiAgICAgIHJldHVybiBzcGxpdExpbmVzQXV0byhzdHIpO1xyXG4gICAgfSxcclxuICAgIGxpbmVTZXBhcmF0b3I6IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpcy5saW5lU2VwIHx8IFwiXFxuXCI7IH1cclxuICB9KTtcclxuXHJcbiAgLy8gUHVibGljIGFsaWFzLlxyXG4gIERvYy5wcm90b3R5cGUuZWFjaExpbmUgPSBEb2MucHJvdG90eXBlLml0ZXI7XHJcblxyXG4gIC8vIFNldCB1cCBtZXRob2RzIG9uIENvZGVNaXJyb3IncyBwcm90b3R5cGUgdG8gcmVkaXJlY3QgdG8gdGhlIGVkaXRvcidzIGRvY3VtZW50LlxyXG4gIHZhciBkb250RGVsZWdhdGUgPSBcIml0ZXIgaW5zZXJ0IHJlbW92ZSBjb3B5IGdldEVkaXRvciBjb25zdHJ1Y3RvclwiLnNwbGl0KFwiIFwiKTtcclxuICBmb3IgKHZhciBwcm9wIGluIERvYy5wcm90b3R5cGUpIGlmIChEb2MucHJvdG90eXBlLmhhc093blByb3BlcnR5KHByb3ApICYmIGluZGV4T2YoZG9udERlbGVnYXRlLCBwcm9wKSA8IDApXHJcbiAgICBDb2RlTWlycm9yLnByb3RvdHlwZVtwcm9wXSA9IChmdW5jdGlvbihtZXRob2QpIHtcclxuICAgICAgcmV0dXJuIGZ1bmN0aW9uKCkge3JldHVybiBtZXRob2QuYXBwbHkodGhpcy5kb2MsIGFyZ3VtZW50cyk7fTtcclxuICAgIH0pKERvYy5wcm90b3R5cGVbcHJvcF0pO1xyXG5cclxuICBldmVudE1peGluKERvYyk7XHJcblxyXG4gIC8vIENhbGwgZiBmb3IgYWxsIGxpbmtlZCBkb2N1bWVudHMuXHJcbiAgZnVuY3Rpb24gbGlua2VkRG9jcyhkb2MsIGYsIHNoYXJlZEhpc3RPbmx5KSB7XHJcbiAgICBmdW5jdGlvbiBwcm9wYWdhdGUoZG9jLCBza2lwLCBzaGFyZWRIaXN0KSB7XHJcbiAgICAgIGlmIChkb2MubGlua2VkKSBmb3IgKHZhciBpID0gMDsgaSA8IGRvYy5saW5rZWQubGVuZ3RoOyArK2kpIHtcclxuICAgICAgICB2YXIgcmVsID0gZG9jLmxpbmtlZFtpXTtcclxuICAgICAgICBpZiAocmVsLmRvYyA9PSBza2lwKSBjb250aW51ZTtcclxuICAgICAgICB2YXIgc2hhcmVkID0gc2hhcmVkSGlzdCAmJiByZWwuc2hhcmVkSGlzdDtcclxuICAgICAgICBpZiAoc2hhcmVkSGlzdE9ubHkgJiYgIXNoYXJlZCkgY29udGludWU7XHJcbiAgICAgICAgZihyZWwuZG9jLCBzaGFyZWQpO1xyXG4gICAgICAgIHByb3BhZ2F0ZShyZWwuZG9jLCBkb2MsIHNoYXJlZCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHByb3BhZ2F0ZShkb2MsIG51bGwsIHRydWUpO1xyXG4gIH1cclxuXHJcbiAgLy8gQXR0YWNoIGEgZG9jdW1lbnQgdG8gYW4gZWRpdG9yLlxyXG4gIGZ1bmN0aW9uIGF0dGFjaERvYyhjbSwgZG9jKSB7XHJcbiAgICBpZiAoZG9jLmNtKSB0aHJvdyBuZXcgRXJyb3IoXCJUaGlzIGRvY3VtZW50IGlzIGFscmVhZHkgaW4gdXNlLlwiKTtcclxuICAgIGNtLmRvYyA9IGRvYztcclxuICAgIGRvYy5jbSA9IGNtO1xyXG4gICAgZXN0aW1hdGVMaW5lSGVpZ2h0cyhjbSk7XHJcbiAgICBsb2FkTW9kZShjbSk7XHJcbiAgICBpZiAoIWNtLm9wdGlvbnMubGluZVdyYXBwaW5nKSBmaW5kTWF4TGluZShjbSk7XHJcbiAgICBjbS5vcHRpb25zLm1vZGUgPSBkb2MubW9kZU9wdGlvbjtcclxuICAgIHJlZ0NoYW5nZShjbSk7XHJcbiAgfVxyXG5cclxuICAvLyBMSU5FIFVUSUxJVElFU1xyXG5cclxuICAvLyBGaW5kIHRoZSBsaW5lIG9iamVjdCBjb3JyZXNwb25kaW5nIHRvIHRoZSBnaXZlbiBsaW5lIG51bWJlci5cclxuICBmdW5jdGlvbiBnZXRMaW5lKGRvYywgbikge1xyXG4gICAgbiAtPSBkb2MuZmlyc3Q7XHJcbiAgICBpZiAobiA8IDAgfHwgbiA+PSBkb2Muc2l6ZSkgdGhyb3cgbmV3IEVycm9yKFwiVGhlcmUgaXMgbm8gbGluZSBcIiArIChuICsgZG9jLmZpcnN0KSArIFwiIGluIHRoZSBkb2N1bWVudC5cIik7XHJcbiAgICBmb3IgKHZhciBjaHVuayA9IGRvYzsgIWNodW5rLmxpbmVzOykge1xyXG4gICAgICBmb3IgKHZhciBpID0gMDs7ICsraSkge1xyXG4gICAgICAgIHZhciBjaGlsZCA9IGNodW5rLmNoaWxkcmVuW2ldLCBzeiA9IGNoaWxkLmNodW5rU2l6ZSgpO1xyXG4gICAgICAgIGlmIChuIDwgc3opIHsgY2h1bmsgPSBjaGlsZDsgYnJlYWs7IH1cclxuICAgICAgICBuIC09IHN6O1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gY2h1bmsubGluZXNbbl07XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIHBhcnQgb2YgYSBkb2N1bWVudCBiZXR3ZWVuIHR3byBwb3NpdGlvbnMsIGFzIGFuIGFycmF5IG9mXHJcbiAgLy8gc3RyaW5ncy5cclxuICBmdW5jdGlvbiBnZXRCZXR3ZWVuKGRvYywgc3RhcnQsIGVuZCkge1xyXG4gICAgdmFyIG91dCA9IFtdLCBuID0gc3RhcnQubGluZTtcclxuICAgIGRvYy5pdGVyKHN0YXJ0LmxpbmUsIGVuZC5saW5lICsgMSwgZnVuY3Rpb24obGluZSkge1xyXG4gICAgICB2YXIgdGV4dCA9IGxpbmUudGV4dDtcclxuICAgICAgaWYgKG4gPT0gZW5kLmxpbmUpIHRleHQgPSB0ZXh0LnNsaWNlKDAsIGVuZC5jaCk7XHJcbiAgICAgIGlmIChuID09IHN0YXJ0LmxpbmUpIHRleHQgPSB0ZXh0LnNsaWNlKHN0YXJ0LmNoKTtcclxuICAgICAgb3V0LnB1c2godGV4dCk7XHJcbiAgICAgICsrbjtcclxuICAgIH0pO1xyXG4gICAgcmV0dXJuIG91dDtcclxuICB9XHJcbiAgLy8gR2V0IHRoZSBsaW5lcyBiZXR3ZWVuIGZyb20gYW5kIHRvLCBhcyBhcnJheSBvZiBzdHJpbmdzLlxyXG4gIGZ1bmN0aW9uIGdldExpbmVzKGRvYywgZnJvbSwgdG8pIHtcclxuICAgIHZhciBvdXQgPSBbXTtcclxuICAgIGRvYy5pdGVyKGZyb20sIHRvLCBmdW5jdGlvbihsaW5lKSB7IG91dC5wdXNoKGxpbmUudGV4dCk7IH0pO1xyXG4gICAgcmV0dXJuIG91dDtcclxuICB9XHJcblxyXG4gIC8vIFVwZGF0ZSB0aGUgaGVpZ2h0IG9mIGEgbGluZSwgcHJvcGFnYXRpbmcgdGhlIGhlaWdodCBjaGFuZ2VcclxuICAvLyB1cHdhcmRzIHRvIHBhcmVudCBub2Rlcy5cclxuICBmdW5jdGlvbiB1cGRhdGVMaW5lSGVpZ2h0KGxpbmUsIGhlaWdodCkge1xyXG4gICAgdmFyIGRpZmYgPSBoZWlnaHQgLSBsaW5lLmhlaWdodDtcclxuICAgIGlmIChkaWZmKSBmb3IgKHZhciBuID0gbGluZTsgbjsgbiA9IG4ucGFyZW50KSBuLmhlaWdodCArPSBkaWZmO1xyXG4gIH1cclxuXHJcbiAgLy8gR2l2ZW4gYSBsaW5lIG9iamVjdCwgZmluZCBpdHMgbGluZSBudW1iZXIgYnkgd2Fsa2luZyB1cCB0aHJvdWdoXHJcbiAgLy8gaXRzIHBhcmVudCBsaW5rcy5cclxuICBmdW5jdGlvbiBsaW5lTm8obGluZSkge1xyXG4gICAgaWYgKGxpbmUucGFyZW50ID09IG51bGwpIHJldHVybiBudWxsO1xyXG4gICAgdmFyIGN1ciA9IGxpbmUucGFyZW50LCBubyA9IGluZGV4T2YoY3VyLmxpbmVzLCBsaW5lKTtcclxuICAgIGZvciAodmFyIGNodW5rID0gY3VyLnBhcmVudDsgY2h1bms7IGN1ciA9IGNodW5rLCBjaHVuayA9IGNodW5rLnBhcmVudCkge1xyXG4gICAgICBmb3IgKHZhciBpID0gMDs7ICsraSkge1xyXG4gICAgICAgIGlmIChjaHVuay5jaGlsZHJlbltpXSA9PSBjdXIpIGJyZWFrO1xyXG4gICAgICAgIG5vICs9IGNodW5rLmNoaWxkcmVuW2ldLmNodW5rU2l6ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gbm8gKyBjdXIuZmlyc3Q7XHJcbiAgfVxyXG5cclxuICAvLyBGaW5kIHRoZSBsaW5lIGF0IHRoZSBnaXZlbiB2ZXJ0aWNhbCBwb3NpdGlvbiwgdXNpbmcgdGhlIGhlaWdodFxyXG4gIC8vIGluZm9ybWF0aW9uIGluIHRoZSBkb2N1bWVudCB0cmVlLlxyXG4gIGZ1bmN0aW9uIGxpbmVBdEhlaWdodChjaHVuaywgaCkge1xyXG4gICAgdmFyIG4gPSBjaHVuay5maXJzdDtcclxuICAgIG91dGVyOiBkbyB7XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2h1bmsuY2hpbGRyZW4ubGVuZ3RoOyArK2kpIHtcclxuICAgICAgICB2YXIgY2hpbGQgPSBjaHVuay5jaGlsZHJlbltpXSwgY2ggPSBjaGlsZC5oZWlnaHQ7XHJcbiAgICAgICAgaWYgKGggPCBjaCkgeyBjaHVuayA9IGNoaWxkOyBjb250aW51ZSBvdXRlcjsgfVxyXG4gICAgICAgIGggLT0gY2g7XHJcbiAgICAgICAgbiArPSBjaGlsZC5jaHVua1NpemUoKTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gbjtcclxuICAgIH0gd2hpbGUgKCFjaHVuay5saW5lcyk7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNodW5rLmxpbmVzLmxlbmd0aDsgKytpKSB7XHJcbiAgICAgIHZhciBsaW5lID0gY2h1bmsubGluZXNbaV0sIGxoID0gbGluZS5oZWlnaHQ7XHJcbiAgICAgIGlmIChoIDwgbGgpIGJyZWFrO1xyXG4gICAgICBoIC09IGxoO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIG4gKyBpO1xyXG4gIH1cclxuXHJcblxyXG4gIC8vIEZpbmQgdGhlIGhlaWdodCBhYm92ZSB0aGUgZ2l2ZW4gbGluZS5cclxuICBmdW5jdGlvbiBoZWlnaHRBdExpbmUobGluZU9iaikge1xyXG4gICAgbGluZU9iaiA9IHZpc3VhbExpbmUobGluZU9iaik7XHJcblxyXG4gICAgdmFyIGggPSAwLCBjaHVuayA9IGxpbmVPYmoucGFyZW50O1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjaHVuay5saW5lcy5sZW5ndGg7ICsraSkge1xyXG4gICAgICB2YXIgbGluZSA9IGNodW5rLmxpbmVzW2ldO1xyXG4gICAgICBpZiAobGluZSA9PSBsaW5lT2JqKSBicmVhaztcclxuICAgICAgZWxzZSBoICs9IGxpbmUuaGVpZ2h0O1xyXG4gICAgfVxyXG4gICAgZm9yICh2YXIgcCA9IGNodW5rLnBhcmVudDsgcDsgY2h1bmsgPSBwLCBwID0gY2h1bmsucGFyZW50KSB7XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcC5jaGlsZHJlbi5sZW5ndGg7ICsraSkge1xyXG4gICAgICAgIHZhciBjdXIgPSBwLmNoaWxkcmVuW2ldO1xyXG4gICAgICAgIGlmIChjdXIgPT0gY2h1bmspIGJyZWFrO1xyXG4gICAgICAgIGVsc2UgaCArPSBjdXIuaGVpZ2h0O1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gaDtcclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgYmlkaSBvcmRlcmluZyBmb3IgdGhlIGdpdmVuIGxpbmUgKGFuZCBjYWNoZSBpdCkuIFJldHVybnNcclxuICAvLyBmYWxzZSBmb3IgbGluZXMgdGhhdCBhcmUgZnVsbHkgbGVmdC10by1yaWdodCwgYW5kIGFuIGFycmF5IG9mXHJcbiAgLy8gQmlkaVNwYW4gb2JqZWN0cyBvdGhlcndpc2UuXHJcbiAgZnVuY3Rpb24gZ2V0T3JkZXIobGluZSkge1xyXG4gICAgdmFyIG9yZGVyID0gbGluZS5vcmRlcjtcclxuICAgIGlmIChvcmRlciA9PSBudWxsKSBvcmRlciA9IGxpbmUub3JkZXIgPSBiaWRpT3JkZXJpbmcobGluZS50ZXh0KTtcclxuICAgIHJldHVybiBvcmRlcjtcclxuICB9XHJcblxyXG4gIC8vIEhJU1RPUllcclxuXHJcbiAgZnVuY3Rpb24gSGlzdG9yeShzdGFydEdlbikge1xyXG4gICAgLy8gQXJyYXlzIG9mIGNoYW5nZSBldmVudHMgYW5kIHNlbGVjdGlvbnMuIERvaW5nIHNvbWV0aGluZyBhZGRzIGFuXHJcbiAgICAvLyBldmVudCB0byBkb25lIGFuZCBjbGVhcnMgdW5kby4gVW5kb2luZyBtb3ZlcyBldmVudHMgZnJvbSBkb25lXHJcbiAgICAvLyB0byB1bmRvbmUsIHJlZG9pbmcgbW92ZXMgdGhlbSBpbiB0aGUgb3RoZXIgZGlyZWN0aW9uLlxyXG4gICAgdGhpcy5kb25lID0gW107IHRoaXMudW5kb25lID0gW107XHJcbiAgICB0aGlzLnVuZG9EZXB0aCA9IEluZmluaXR5O1xyXG4gICAgLy8gVXNlZCB0byB0cmFjayB3aGVuIGNoYW5nZXMgY2FuIGJlIG1lcmdlZCBpbnRvIGEgc2luZ2xlIHVuZG9cclxuICAgIC8vIGV2ZW50XHJcbiAgICB0aGlzLmxhc3RNb2RUaW1lID0gdGhpcy5sYXN0U2VsVGltZSA9IDA7XHJcbiAgICB0aGlzLmxhc3RPcCA9IHRoaXMubGFzdFNlbE9wID0gbnVsbDtcclxuICAgIHRoaXMubGFzdE9yaWdpbiA9IHRoaXMubGFzdFNlbE9yaWdpbiA9IG51bGw7XHJcbiAgICAvLyBVc2VkIGJ5IHRoZSBpc0NsZWFuKCkgbWV0aG9kXHJcbiAgICB0aGlzLmdlbmVyYXRpb24gPSB0aGlzLm1heEdlbmVyYXRpb24gPSBzdGFydEdlbiB8fCAxO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgaGlzdG9yeSBjaGFuZ2UgZXZlbnQgZnJvbSBhbiB1cGRhdGVEb2Mtc3R5bGUgY2hhbmdlXHJcbiAgLy8gb2JqZWN0LlxyXG4gIGZ1bmN0aW9uIGhpc3RvcnlDaGFuZ2VGcm9tQ2hhbmdlKGRvYywgY2hhbmdlKSB7XHJcbiAgICB2YXIgaGlzdENoYW5nZSA9IHtmcm9tOiBjb3B5UG9zKGNoYW5nZS5mcm9tKSwgdG86IGNoYW5nZUVuZChjaGFuZ2UpLCB0ZXh0OiBnZXRCZXR3ZWVuKGRvYywgY2hhbmdlLmZyb20sIGNoYW5nZS50byl9O1xyXG4gICAgYXR0YWNoTG9jYWxTcGFucyhkb2MsIGhpc3RDaGFuZ2UsIGNoYW5nZS5mcm9tLmxpbmUsIGNoYW5nZS50by5saW5lICsgMSk7XHJcbiAgICBsaW5rZWREb2NzKGRvYywgZnVuY3Rpb24oZG9jKSB7YXR0YWNoTG9jYWxTcGFucyhkb2MsIGhpc3RDaGFuZ2UsIGNoYW5nZS5mcm9tLmxpbmUsIGNoYW5nZS50by5saW5lICsgMSk7fSwgdHJ1ZSk7XHJcbiAgICByZXR1cm4gaGlzdENoYW5nZTtcclxuICB9XHJcblxyXG4gIC8vIFBvcCBhbGwgc2VsZWN0aW9uIGV2ZW50cyBvZmYgdGhlIGVuZCBvZiBhIGhpc3RvcnkgYXJyYXkuIFN0b3AgYXRcclxuICAvLyBhIGNoYW5nZSBldmVudC5cclxuICBmdW5jdGlvbiBjbGVhclNlbGVjdGlvbkV2ZW50cyhhcnJheSkge1xyXG4gICAgd2hpbGUgKGFycmF5Lmxlbmd0aCkge1xyXG4gICAgICB2YXIgbGFzdCA9IGxzdChhcnJheSk7XHJcbiAgICAgIGlmIChsYXN0LnJhbmdlcykgYXJyYXkucG9wKCk7XHJcbiAgICAgIGVsc2UgYnJlYWs7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5kIHRoZSB0b3AgY2hhbmdlIGV2ZW50IGluIHRoZSBoaXN0b3J5LiBQb3Agb2ZmIHNlbGVjdGlvblxyXG4gIC8vIGV2ZW50cyB0aGF0IGFyZSBpbiB0aGUgd2F5LlxyXG4gIGZ1bmN0aW9uIGxhc3RDaGFuZ2VFdmVudChoaXN0LCBmb3JjZSkge1xyXG4gICAgaWYgKGZvcmNlKSB7XHJcbiAgICAgIGNsZWFyU2VsZWN0aW9uRXZlbnRzKGhpc3QuZG9uZSk7XHJcbiAgICAgIHJldHVybiBsc3QoaGlzdC5kb25lKTtcclxuICAgIH0gZWxzZSBpZiAoaGlzdC5kb25lLmxlbmd0aCAmJiAhbHN0KGhpc3QuZG9uZSkucmFuZ2VzKSB7XHJcbiAgICAgIHJldHVybiBsc3QoaGlzdC5kb25lKTtcclxuICAgIH0gZWxzZSBpZiAoaGlzdC5kb25lLmxlbmd0aCA+IDEgJiYgIWhpc3QuZG9uZVtoaXN0LmRvbmUubGVuZ3RoIC0gMl0ucmFuZ2VzKSB7XHJcbiAgICAgIGhpc3QuZG9uZS5wb3AoKTtcclxuICAgICAgcmV0dXJuIGxzdChoaXN0LmRvbmUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmVnaXN0ZXIgYSBjaGFuZ2UgaW4gdGhlIGhpc3RvcnkuIE1lcmdlcyBjaGFuZ2VzIHRoYXQgYXJlIHdpdGhpblxyXG4gIC8vIGEgc2luZ2xlIG9wZXJhdGlvbiwgb3JlIGFyZSBjbG9zZSB0b2dldGhlciB3aXRoIGFuIG9yaWdpbiB0aGF0XHJcbiAgLy8gYWxsb3dzIG1lcmdpbmcgKHN0YXJ0aW5nIHdpdGggXCIrXCIpIGludG8gYSBzaW5nbGUgZXZlbnQuXHJcbiAgZnVuY3Rpb24gYWRkQ2hhbmdlVG9IaXN0b3J5KGRvYywgY2hhbmdlLCBzZWxBZnRlciwgb3BJZCkge1xyXG4gICAgdmFyIGhpc3QgPSBkb2MuaGlzdG9yeTtcclxuICAgIGhpc3QudW5kb25lLmxlbmd0aCA9IDA7XHJcbiAgICB2YXIgdGltZSA9ICtuZXcgRGF0ZSwgY3VyO1xyXG5cclxuICAgIGlmICgoaGlzdC5sYXN0T3AgPT0gb3BJZCB8fFxyXG4gICAgICAgICBoaXN0Lmxhc3RPcmlnaW4gPT0gY2hhbmdlLm9yaWdpbiAmJiBjaGFuZ2Uub3JpZ2luICYmXHJcbiAgICAgICAgICgoY2hhbmdlLm9yaWdpbi5jaGFyQXQoMCkgPT0gXCIrXCIgJiYgZG9jLmNtICYmIGhpc3QubGFzdE1vZFRpbWUgPiB0aW1lIC0gZG9jLmNtLm9wdGlvbnMuaGlzdG9yeUV2ZW50RGVsYXkpIHx8XHJcbiAgICAgICAgICBjaGFuZ2Uub3JpZ2luLmNoYXJBdCgwKSA9PSBcIipcIikpICYmXHJcbiAgICAgICAgKGN1ciA9IGxhc3RDaGFuZ2VFdmVudChoaXN0LCBoaXN0Lmxhc3RPcCA9PSBvcElkKSkpIHtcclxuICAgICAgLy8gTWVyZ2UgdGhpcyBjaGFuZ2UgaW50byB0aGUgbGFzdCBldmVudFxyXG4gICAgICB2YXIgbGFzdCA9IGxzdChjdXIuY2hhbmdlcyk7XHJcbiAgICAgIGlmIChjbXAoY2hhbmdlLmZyb20sIGNoYW5nZS50bykgPT0gMCAmJiBjbXAoY2hhbmdlLmZyb20sIGxhc3QudG8pID09IDApIHtcclxuICAgICAgICAvLyBPcHRpbWl6ZWQgY2FzZSBmb3Igc2ltcGxlIGluc2VydGlvbiAtLSBkb24ndCB3YW50IHRvIGFkZFxyXG4gICAgICAgIC8vIG5ldyBjaGFuZ2VzZXRzIGZvciBldmVyeSBjaGFyYWN0ZXIgdHlwZWRcclxuICAgICAgICBsYXN0LnRvID0gY2hhbmdlRW5kKGNoYW5nZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQWRkIG5ldyBzdWItZXZlbnRcclxuICAgICAgICBjdXIuY2hhbmdlcy5wdXNoKGhpc3RvcnlDaGFuZ2VGcm9tQ2hhbmdlKGRvYywgY2hhbmdlKSk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENhbiBub3QgYmUgbWVyZ2VkLCBzdGFydCBhIG5ldyBldmVudC5cclxuICAgICAgdmFyIGJlZm9yZSA9IGxzdChoaXN0LmRvbmUpO1xyXG4gICAgICBpZiAoIWJlZm9yZSB8fCAhYmVmb3JlLnJhbmdlcylcclxuICAgICAgICBwdXNoU2VsZWN0aW9uVG9IaXN0b3J5KGRvYy5zZWwsIGhpc3QuZG9uZSk7XHJcbiAgICAgIGN1ciA9IHtjaGFuZ2VzOiBbaGlzdG9yeUNoYW5nZUZyb21DaGFuZ2UoZG9jLCBjaGFuZ2UpXSxcclxuICAgICAgICAgICAgIGdlbmVyYXRpb246IGhpc3QuZ2VuZXJhdGlvbn07XHJcbiAgICAgIGhpc3QuZG9uZS5wdXNoKGN1cik7XHJcbiAgICAgIHdoaWxlIChoaXN0LmRvbmUubGVuZ3RoID4gaGlzdC51bmRvRGVwdGgpIHtcclxuICAgICAgICBoaXN0LmRvbmUuc2hpZnQoKTtcclxuICAgICAgICBpZiAoIWhpc3QuZG9uZVswXS5yYW5nZXMpIGhpc3QuZG9uZS5zaGlmdCgpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBoaXN0LmRvbmUucHVzaChzZWxBZnRlcik7XHJcbiAgICBoaXN0LmdlbmVyYXRpb24gPSArK2hpc3QubWF4R2VuZXJhdGlvbjtcclxuICAgIGhpc3QubGFzdE1vZFRpbWUgPSBoaXN0Lmxhc3RTZWxUaW1lID0gdGltZTtcclxuICAgIGhpc3QubGFzdE9wID0gaGlzdC5sYXN0U2VsT3AgPSBvcElkO1xyXG4gICAgaGlzdC5sYXN0T3JpZ2luID0gaGlzdC5sYXN0U2VsT3JpZ2luID0gY2hhbmdlLm9yaWdpbjtcclxuXHJcbiAgICBpZiAoIWxhc3QpIHNpZ25hbChkb2MsIFwiaGlzdG9yeUFkZGVkXCIpO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gc2VsZWN0aW9uRXZlbnRDYW5CZU1lcmdlZChkb2MsIG9yaWdpbiwgcHJldiwgc2VsKSB7XHJcbiAgICB2YXIgY2ggPSBvcmlnaW4uY2hhckF0KDApO1xyXG4gICAgcmV0dXJuIGNoID09IFwiKlwiIHx8XHJcbiAgICAgIGNoID09IFwiK1wiICYmXHJcbiAgICAgIHByZXYucmFuZ2VzLmxlbmd0aCA9PSBzZWwucmFuZ2VzLmxlbmd0aCAmJlxyXG4gICAgICBwcmV2LnNvbWV0aGluZ1NlbGVjdGVkKCkgPT0gc2VsLnNvbWV0aGluZ1NlbGVjdGVkKCkgJiZcclxuICAgICAgbmV3IERhdGUgLSBkb2MuaGlzdG9yeS5sYXN0U2VsVGltZSA8PSAoZG9jLmNtID8gZG9jLmNtLm9wdGlvbnMuaGlzdG9yeUV2ZW50RGVsYXkgOiA1MDApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbGVkIHdoZW5ldmVyIHRoZSBzZWxlY3Rpb24gY2hhbmdlcywgc2V0cyB0aGUgbmV3IHNlbGVjdGlvbiBhc1xyXG4gIC8vIHRoZSBwZW5kaW5nIHNlbGVjdGlvbiBpbiB0aGUgaGlzdG9yeSwgYW5kIHB1c2hlcyB0aGUgb2xkIHBlbmRpbmdcclxuICAvLyBzZWxlY3Rpb24gaW50byB0aGUgJ2RvbmUnIGFycmF5IHdoZW4gaXQgd2FzIHNpZ25pZmljYW50bHlcclxuICAvLyBkaWZmZXJlbnQgKGluIG51bWJlciBvZiBzZWxlY3RlZCByYW5nZXMsIGVtcHRpbmVzcywgb3IgdGltZSkuXHJcbiAgZnVuY3Rpb24gYWRkU2VsZWN0aW9uVG9IaXN0b3J5KGRvYywgc2VsLCBvcElkLCBvcHRpb25zKSB7XHJcbiAgICB2YXIgaGlzdCA9IGRvYy5oaXN0b3J5LCBvcmlnaW4gPSBvcHRpb25zICYmIG9wdGlvbnMub3JpZ2luO1xyXG5cclxuICAgIC8vIEEgbmV3IGV2ZW50IGlzIHN0YXJ0ZWQgd2hlbiB0aGUgcHJldmlvdXMgb3JpZ2luIGRvZXMgbm90IG1hdGNoXHJcbiAgICAvLyB0aGUgY3VycmVudCwgb3IgdGhlIG9yaWdpbnMgZG9uJ3QgYWxsb3cgbWF0Y2hpbmcuIE9yaWdpbnNcclxuICAgIC8vIHN0YXJ0aW5nIHdpdGggKiBhcmUgYWx3YXlzIG1lcmdlZCwgdGhvc2Ugc3RhcnRpbmcgd2l0aCArIGFyZVxyXG4gICAgLy8gbWVyZ2VkIHdoZW4gc2ltaWxhciBhbmQgY2xvc2UgdG9nZXRoZXIgaW4gdGltZS5cclxuICAgIGlmIChvcElkID09IGhpc3QubGFzdFNlbE9wIHx8XHJcbiAgICAgICAgKG9yaWdpbiAmJiBoaXN0Lmxhc3RTZWxPcmlnaW4gPT0gb3JpZ2luICYmXHJcbiAgICAgICAgIChoaXN0Lmxhc3RNb2RUaW1lID09IGhpc3QubGFzdFNlbFRpbWUgJiYgaGlzdC5sYXN0T3JpZ2luID09IG9yaWdpbiB8fFxyXG4gICAgICAgICAgc2VsZWN0aW9uRXZlbnRDYW5CZU1lcmdlZChkb2MsIG9yaWdpbiwgbHN0KGhpc3QuZG9uZSksIHNlbCkpKSlcclxuICAgICAgaGlzdC5kb25lW2hpc3QuZG9uZS5sZW5ndGggLSAxXSA9IHNlbDtcclxuICAgIGVsc2VcclxuICAgICAgcHVzaFNlbGVjdGlvblRvSGlzdG9yeShzZWwsIGhpc3QuZG9uZSk7XHJcblxyXG4gICAgaGlzdC5sYXN0U2VsVGltZSA9ICtuZXcgRGF0ZTtcclxuICAgIGhpc3QubGFzdFNlbE9yaWdpbiA9IG9yaWdpbjtcclxuICAgIGhpc3QubGFzdFNlbE9wID0gb3BJZDtcclxuICAgIGlmIChvcHRpb25zICYmIG9wdGlvbnMuY2xlYXJSZWRvICE9PSBmYWxzZSlcclxuICAgICAgY2xlYXJTZWxlY3Rpb25FdmVudHMoaGlzdC51bmRvbmUpO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gcHVzaFNlbGVjdGlvblRvSGlzdG9yeShzZWwsIGRlc3QpIHtcclxuICAgIHZhciB0b3AgPSBsc3QoZGVzdCk7XHJcbiAgICBpZiAoISh0b3AgJiYgdG9wLnJhbmdlcyAmJiB0b3AuZXF1YWxzKHNlbCkpKVxyXG4gICAgICBkZXN0LnB1c2goc2VsKTtcclxuICB9XHJcblxyXG4gIC8vIFVzZWQgdG8gc3RvcmUgbWFya2VkIHNwYW4gaW5mb3JtYXRpb24gaW4gdGhlIGhpc3RvcnkuXHJcbiAgZnVuY3Rpb24gYXR0YWNoTG9jYWxTcGFucyhkb2MsIGNoYW5nZSwgZnJvbSwgdG8pIHtcclxuICAgIHZhciBleGlzdGluZyA9IGNoYW5nZVtcInNwYW5zX1wiICsgZG9jLmlkXSwgbiA9IDA7XHJcbiAgICBkb2MuaXRlcihNYXRoLm1heChkb2MuZmlyc3QsIGZyb20pLCBNYXRoLm1pbihkb2MuZmlyc3QgKyBkb2Muc2l6ZSwgdG8pLCBmdW5jdGlvbihsaW5lKSB7XHJcbiAgICAgIGlmIChsaW5lLm1hcmtlZFNwYW5zKVxyXG4gICAgICAgIChleGlzdGluZyB8fCAoZXhpc3RpbmcgPSBjaGFuZ2VbXCJzcGFuc19cIiArIGRvYy5pZF0gPSB7fSkpW25dID0gbGluZS5tYXJrZWRTcGFucztcclxuICAgICAgKytuO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICAvLyBXaGVuIHVuL3JlLWRvaW5nIHJlc3RvcmVzIHRleHQgY29udGFpbmluZyBtYXJrZWQgc3BhbnMsIHRob3NlXHJcbiAgLy8gdGhhdCBoYXZlIGJlZW4gZXhwbGljaXRseSBjbGVhcmVkIHNob3VsZCBub3QgYmUgcmVzdG9yZWQuXHJcbiAgZnVuY3Rpb24gcmVtb3ZlQ2xlYXJlZFNwYW5zKHNwYW5zKSB7XHJcbiAgICBpZiAoIXNwYW5zKSByZXR1cm4gbnVsbDtcclxuICAgIGZvciAodmFyIGkgPSAwLCBvdXQ7IGkgPCBzcGFucy5sZW5ndGg7ICsraSkge1xyXG4gICAgICBpZiAoc3BhbnNbaV0ubWFya2VyLmV4cGxpY2l0bHlDbGVhcmVkKSB7IGlmICghb3V0KSBvdXQgPSBzcGFucy5zbGljZSgwLCBpKTsgfVxyXG4gICAgICBlbHNlIGlmIChvdXQpIG91dC5wdXNoKHNwYW5zW2ldKTtcclxuICAgIH1cclxuICAgIHJldHVybiAhb3V0ID8gc3BhbnMgOiBvdXQubGVuZ3RoID8gb3V0IDogbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIFJldHJpZXZlIGFuZCBmaWx0ZXIgdGhlIG9sZCBtYXJrZWQgc3BhbnMgc3RvcmVkIGluIGEgY2hhbmdlIGV2ZW50LlxyXG4gIGZ1bmN0aW9uIGdldE9sZFNwYW5zKGRvYywgY2hhbmdlKSB7XHJcbiAgICB2YXIgZm91bmQgPSBjaGFuZ2VbXCJzcGFuc19cIiArIGRvYy5pZF07XHJcbiAgICBpZiAoIWZvdW5kKSByZXR1cm4gbnVsbDtcclxuICAgIGZvciAodmFyIGkgPSAwLCBudyA9IFtdOyBpIDwgY2hhbmdlLnRleHQubGVuZ3RoOyArK2kpXHJcbiAgICAgIG53LnB1c2gocmVtb3ZlQ2xlYXJlZFNwYW5zKGZvdW5kW2ldKSk7XHJcbiAgICByZXR1cm4gbnc7XHJcbiAgfVxyXG5cclxuICAvLyBVc2VkIGJvdGggdG8gcHJvdmlkZSBhIEpTT04tc2FmZSBvYmplY3QgaW4gLmdldEhpc3RvcnksIGFuZCwgd2hlblxyXG4gIC8vIGRldGFjaGluZyBhIGRvY3VtZW50LCB0byBzcGxpdCB0aGUgaGlzdG9yeSBpbiB0d29cclxuICBmdW5jdGlvbiBjb3B5SGlzdG9yeUFycmF5KGV2ZW50cywgbmV3R3JvdXAsIGluc3RhbnRpYXRlU2VsKSB7XHJcbiAgICBmb3IgKHZhciBpID0gMCwgY29weSA9IFtdOyBpIDwgZXZlbnRzLmxlbmd0aDsgKytpKSB7XHJcbiAgICAgIHZhciBldmVudCA9IGV2ZW50c1tpXTtcclxuICAgICAgaWYgKGV2ZW50LnJhbmdlcykge1xyXG4gICAgICAgIGNvcHkucHVzaChpbnN0YW50aWF0ZVNlbCA/IFNlbGVjdGlvbi5wcm90b3R5cGUuZGVlcENvcHkuY2FsbChldmVudCkgOiBldmVudCk7XHJcbiAgICAgICAgY29udGludWU7XHJcbiAgICAgIH1cclxuICAgICAgdmFyIGNoYW5nZXMgPSBldmVudC5jaGFuZ2VzLCBuZXdDaGFuZ2VzID0gW107XHJcbiAgICAgIGNvcHkucHVzaCh7Y2hhbmdlczogbmV3Q2hhbmdlc30pO1xyXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGNoYW5nZXMubGVuZ3RoOyArK2opIHtcclxuICAgICAgICB2YXIgY2hhbmdlID0gY2hhbmdlc1tqXSwgbTtcclxuICAgICAgICBuZXdDaGFuZ2VzLnB1c2goe2Zyb206IGNoYW5nZS5mcm9tLCB0bzogY2hhbmdlLnRvLCB0ZXh0OiBjaGFuZ2UudGV4dH0pO1xyXG4gICAgICAgIGlmIChuZXdHcm91cCkgZm9yICh2YXIgcHJvcCBpbiBjaGFuZ2UpIGlmIChtID0gcHJvcC5tYXRjaCgvXnNwYW5zXyhcXGQrKSQvKSkge1xyXG4gICAgICAgICAgaWYgKGluZGV4T2YobmV3R3JvdXAsIE51bWJlcihtWzFdKSkgPiAtMSkge1xyXG4gICAgICAgICAgICBsc3QobmV3Q2hhbmdlcylbcHJvcF0gPSBjaGFuZ2VbcHJvcF07XHJcbiAgICAgICAgICAgIGRlbGV0ZSBjaGFuZ2VbcHJvcF07XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gY29weTtcclxuICB9XHJcblxyXG4gIC8vIFJlYmFzaW5nL3Jlc2V0dGluZyBoaXN0b3J5IHRvIGRlYWwgd2l0aCBleHRlcm5hbGx5LXNvdXJjZWQgY2hhbmdlc1xyXG5cclxuICBmdW5jdGlvbiByZWJhc2VIaXN0U2VsU2luZ2xlKHBvcywgZnJvbSwgdG8sIGRpZmYpIHtcclxuICAgIGlmICh0byA8IHBvcy5saW5lKSB7XHJcbiAgICAgIHBvcy5saW5lICs9IGRpZmY7XHJcbiAgICB9IGVsc2UgaWYgKGZyb20gPCBwb3MubGluZSkge1xyXG4gICAgICBwb3MubGluZSA9IGZyb207XHJcbiAgICAgIHBvcy5jaCA9IDA7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBUcmllcyB0byByZWJhc2UgYW4gYXJyYXkgb2YgaGlzdG9yeSBldmVudHMgZ2l2ZW4gYSBjaGFuZ2UgaW4gdGhlXHJcbiAgLy8gZG9jdW1lbnQuIElmIHRoZSBjaGFuZ2UgdG91Y2hlcyB0aGUgc2FtZSBsaW5lcyBhcyB0aGUgZXZlbnQsIHRoZVxyXG4gIC8vIGV2ZW50LCBhbmQgZXZlcnl0aGluZyAnYmVoaW5kJyBpdCwgaXMgZGlzY2FyZGVkLiBJZiB0aGUgY2hhbmdlIGlzXHJcbiAgLy8gYmVmb3JlIHRoZSBldmVudCwgdGhlIGV2ZW50J3MgcG9zaXRpb25zIGFyZSB1cGRhdGVkLiBVc2VzIGFcclxuICAvLyBjb3B5LW9uLXdyaXRlIHNjaGVtZSBmb3IgdGhlIHBvc2l0aW9ucywgdG8gYXZvaWQgaGF2aW5nIHRvXHJcbiAgLy8gcmVhbGxvY2F0ZSB0aGVtIGFsbCBvbiBldmVyeSByZWJhc2UsIGJ1dCBhbHNvIGF2b2lkIHByb2JsZW1zIHdpdGhcclxuICAvLyBzaGFyZWQgcG9zaXRpb24gb2JqZWN0cyBiZWluZyB1bnNhZmVseSB1cGRhdGVkLlxyXG4gIGZ1bmN0aW9uIHJlYmFzZUhpc3RBcnJheShhcnJheSwgZnJvbSwgdG8sIGRpZmYpIHtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYXJyYXkubGVuZ3RoOyArK2kpIHtcclxuICAgICAgdmFyIHN1YiA9IGFycmF5W2ldLCBvayA9IHRydWU7XHJcbiAgICAgIGlmIChzdWIucmFuZ2VzKSB7XHJcbiAgICAgICAgaWYgKCFzdWIuY29waWVkKSB7IHN1YiA9IGFycmF5W2ldID0gc3ViLmRlZXBDb3B5KCk7IHN1Yi5jb3BpZWQgPSB0cnVlOyB9XHJcbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBzdWIucmFuZ2VzLmxlbmd0aDsgaisrKSB7XHJcbiAgICAgICAgICByZWJhc2VIaXN0U2VsU2luZ2xlKHN1Yi5yYW5nZXNbal0uYW5jaG9yLCBmcm9tLCB0bywgZGlmZik7XHJcbiAgICAgICAgICByZWJhc2VIaXN0U2VsU2luZ2xlKHN1Yi5yYW5nZXNbal0uaGVhZCwgZnJvbSwgdG8sIGRpZmYpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBjb250aW51ZTtcclxuICAgICAgfVxyXG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IHN1Yi5jaGFuZ2VzLmxlbmd0aDsgKytqKSB7XHJcbiAgICAgICAgdmFyIGN1ciA9IHN1Yi5jaGFuZ2VzW2pdO1xyXG4gICAgICAgIGlmICh0byA8IGN1ci5mcm9tLmxpbmUpIHtcclxuICAgICAgICAgIGN1ci5mcm9tID0gUG9zKGN1ci5mcm9tLmxpbmUgKyBkaWZmLCBjdXIuZnJvbS5jaCk7XHJcbiAgICAgICAgICBjdXIudG8gPSBQb3MoY3VyLnRvLmxpbmUgKyBkaWZmLCBjdXIudG8uY2gpO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoZnJvbSA8PSBjdXIudG8ubGluZSkge1xyXG4gICAgICAgICAgb2sgPSBmYWxzZTtcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpZiAoIW9rKSB7XHJcbiAgICAgICAgYXJyYXkuc3BsaWNlKDAsIGkgKyAxKTtcclxuICAgICAgICBpID0gMDtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gcmViYXNlSGlzdChoaXN0LCBjaGFuZ2UpIHtcclxuICAgIHZhciBmcm9tID0gY2hhbmdlLmZyb20ubGluZSwgdG8gPSBjaGFuZ2UudG8ubGluZSwgZGlmZiA9IGNoYW5nZS50ZXh0Lmxlbmd0aCAtICh0byAtIGZyb20pIC0gMTtcclxuICAgIHJlYmFzZUhpc3RBcnJheShoaXN0LmRvbmUsIGZyb20sIHRvLCBkaWZmKTtcclxuICAgIHJlYmFzZUhpc3RBcnJheShoaXN0LnVuZG9uZSwgZnJvbSwgdG8sIGRpZmYpO1xyXG4gIH1cclxuXHJcbiAgLy8gRVZFTlQgVVRJTElUSUVTXHJcblxyXG4gIC8vIER1ZSB0byB0aGUgZmFjdCB0aGF0IHdlIHN0aWxsIHN1cHBvcnQganVyYXNzaWMgSUUgdmVyc2lvbnMsIHNvbWVcclxuICAvLyBjb21wYXRpYmlsaXR5IHdyYXBwZXJzIGFyZSBuZWVkZWQuXHJcblxyXG4gIHZhciBlX3ByZXZlbnREZWZhdWx0ID0gQ29kZU1pcnJvci5lX3ByZXZlbnREZWZhdWx0ID0gZnVuY3Rpb24oZSkge1xyXG4gICAgaWYgKGUucHJldmVudERlZmF1bHQpIGUucHJldmVudERlZmF1bHQoKTtcclxuICAgIGVsc2UgZS5yZXR1cm5WYWx1ZSA9IGZhbHNlO1xyXG4gIH07XHJcbiAgdmFyIGVfc3RvcFByb3BhZ2F0aW9uID0gQ29kZU1pcnJvci5lX3N0b3BQcm9wYWdhdGlvbiA9IGZ1bmN0aW9uKGUpIHtcclxuICAgIGlmIChlLnN0b3BQcm9wYWdhdGlvbikgZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuICAgIGVsc2UgZS5jYW5jZWxCdWJibGUgPSB0cnVlO1xyXG4gIH07XHJcbiAgZnVuY3Rpb24gZV9kZWZhdWx0UHJldmVudGVkKGUpIHtcclxuICAgIHJldHVybiBlLmRlZmF1bHRQcmV2ZW50ZWQgIT0gbnVsbCA/IGUuZGVmYXVsdFByZXZlbnRlZCA6IGUucmV0dXJuVmFsdWUgPT0gZmFsc2U7XHJcbiAgfVxyXG4gIHZhciBlX3N0b3AgPSBDb2RlTWlycm9yLmVfc3RvcCA9IGZ1bmN0aW9uKGUpIHtlX3ByZXZlbnREZWZhdWx0KGUpOyBlX3N0b3BQcm9wYWdhdGlvbihlKTt9O1xyXG5cclxuICBmdW5jdGlvbiBlX3RhcmdldChlKSB7cmV0dXJuIGUudGFyZ2V0IHx8IGUuc3JjRWxlbWVudDt9XHJcbiAgZnVuY3Rpb24gZV9idXR0b24oZSkge1xyXG4gICAgdmFyIGIgPSBlLndoaWNoO1xyXG4gICAgaWYgKGIgPT0gbnVsbCkge1xyXG4gICAgICBpZiAoZS5idXR0b24gJiAxKSBiID0gMTtcclxuICAgICAgZWxzZSBpZiAoZS5idXR0b24gJiAyKSBiID0gMztcclxuICAgICAgZWxzZSBpZiAoZS5idXR0b24gJiA0KSBiID0gMjtcclxuICAgIH1cclxuICAgIGlmIChtYWMgJiYgZS5jdHJsS2V5ICYmIGIgPT0gMSkgYiA9IDM7XHJcbiAgICByZXR1cm4gYjtcclxuICB9XHJcblxyXG4gIC8vIEVWRU5UIEhBTkRMSU5HXHJcblxyXG4gIC8vIExpZ2h0d2VpZ2h0IGV2ZW50IGZyYW1ld29yay4gb24vb2ZmIGFsc28gd29yayBvbiBET00gbm9kZXMsXHJcbiAgLy8gcmVnaXN0ZXJpbmcgbmF0aXZlIERPTSBoYW5kbGVycy5cclxuXHJcbiAgdmFyIG9uID0gQ29kZU1pcnJvci5vbiA9IGZ1bmN0aW9uKGVtaXR0ZXIsIHR5cGUsIGYpIHtcclxuICAgIGlmIChlbWl0dGVyLmFkZEV2ZW50TGlzdGVuZXIpXHJcbiAgICAgIGVtaXR0ZXIuYWRkRXZlbnRMaXN0ZW5lcih0eXBlLCBmLCBmYWxzZSk7XHJcbiAgICBlbHNlIGlmIChlbWl0dGVyLmF0dGFjaEV2ZW50KVxyXG4gICAgICBlbWl0dGVyLmF0dGFjaEV2ZW50KFwib25cIiArIHR5cGUsIGYpO1xyXG4gICAgZWxzZSB7XHJcbiAgICAgIHZhciBtYXAgPSBlbWl0dGVyLl9oYW5kbGVycyB8fCAoZW1pdHRlci5faGFuZGxlcnMgPSB7fSk7XHJcbiAgICAgIHZhciBhcnIgPSBtYXBbdHlwZV0gfHwgKG1hcFt0eXBlXSA9IFtdKTtcclxuICAgICAgYXJyLnB1c2goZik7XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgdmFyIG5vSGFuZGxlcnMgPSBbXVxyXG4gIGZ1bmN0aW9uIGdldEhhbmRsZXJzKGVtaXR0ZXIsIHR5cGUsIGNvcHkpIHtcclxuICAgIHZhciBhcnIgPSBlbWl0dGVyLl9oYW5kbGVycyAmJiBlbWl0dGVyLl9oYW5kbGVyc1t0eXBlXVxyXG4gICAgaWYgKGNvcHkpIHJldHVybiBhcnIgJiYgYXJyLmxlbmd0aCA+IDAgPyBhcnIuc2xpY2UoKSA6IG5vSGFuZGxlcnNcclxuICAgIGVsc2UgcmV0dXJuIGFyciB8fCBub0hhbmRsZXJzXHJcbiAgfVxyXG5cclxuICB2YXIgb2ZmID0gQ29kZU1pcnJvci5vZmYgPSBmdW5jdGlvbihlbWl0dGVyLCB0eXBlLCBmKSB7XHJcbiAgICBpZiAoZW1pdHRlci5yZW1vdmVFdmVudExpc3RlbmVyKVxyXG4gICAgICBlbWl0dGVyLnJlbW92ZUV2ZW50TGlzdGVuZXIodHlwZSwgZiwgZmFsc2UpO1xyXG4gICAgZWxzZSBpZiAoZW1pdHRlci5kZXRhY2hFdmVudClcclxuICAgICAgZW1pdHRlci5kZXRhY2hFdmVudChcIm9uXCIgKyB0eXBlLCBmKTtcclxuICAgIGVsc2Uge1xyXG4gICAgICB2YXIgaGFuZGxlcnMgPSBnZXRIYW5kbGVycyhlbWl0dGVyLCB0eXBlLCBmYWxzZSlcclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoYW5kbGVycy5sZW5ndGg7ICsraSlcclxuICAgICAgICBpZiAoaGFuZGxlcnNbaV0gPT0gZikgeyBoYW5kbGVycy5zcGxpY2UoaSwgMSk7IGJyZWFrOyB9XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgdmFyIHNpZ25hbCA9IENvZGVNaXJyb3Iuc2lnbmFsID0gZnVuY3Rpb24oZW1pdHRlciwgdHlwZSAvKiwgdmFsdWVzLi4uKi8pIHtcclxuICAgIHZhciBoYW5kbGVycyA9IGdldEhhbmRsZXJzKGVtaXR0ZXIsIHR5cGUsIHRydWUpXHJcbiAgICBpZiAoIWhhbmRsZXJzLmxlbmd0aCkgcmV0dXJuO1xyXG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoYW5kbGVycy5sZW5ndGg7ICsraSkgaGFuZGxlcnNbaV0uYXBwbHkobnVsbCwgYXJncyk7XHJcbiAgfTtcclxuXHJcbiAgdmFyIG9ycGhhbkRlbGF5ZWRDYWxsYmFja3MgPSBudWxsO1xyXG5cclxuICAvLyBPZnRlbiwgd2Ugd2FudCB0byBzaWduYWwgZXZlbnRzIGF0IGEgcG9pbnQgd2hlcmUgd2UgYXJlIGluIHRoZVxyXG4gIC8vIG1pZGRsZSBvZiBzb21lIHdvcmssIGJ1dCBkb24ndCB3YW50IHRoZSBoYW5kbGVyIHRvIHN0YXJ0IGNhbGxpbmdcclxuICAvLyBvdGhlciBtZXRob2RzIG9uIHRoZSBlZGl0b3IsIHdoaWNoIG1pZ2h0IGJlIGluIGFuIGluY29uc2lzdGVudFxyXG4gIC8vIHN0YXRlIG9yIHNpbXBseSBub3QgZXhwZWN0IGFueSBvdGhlciBldmVudHMgdG8gaGFwcGVuLlxyXG4gIC8vIHNpZ25hbExhdGVyIGxvb2tzIHdoZXRoZXIgdGhlcmUgYXJlIGFueSBoYW5kbGVycywgYW5kIHNjaGVkdWxlc1xyXG4gIC8vIHRoZW0gdG8gYmUgZXhlY3V0ZWQgd2hlbiB0aGUgbGFzdCBvcGVyYXRpb24gZW5kcywgb3IsIGlmIG5vXHJcbiAgLy8gb3BlcmF0aW9uIGlzIGFjdGl2ZSwgd2hlbiBhIHRpbWVvdXQgZmlyZXMuXHJcbiAgZnVuY3Rpb24gc2lnbmFsTGF0ZXIoZW1pdHRlciwgdHlwZSAvKiwgdmFsdWVzLi4uKi8pIHtcclxuICAgIHZhciBhcnIgPSBnZXRIYW5kbGVycyhlbWl0dGVyLCB0eXBlLCBmYWxzZSlcclxuICAgIGlmICghYXJyLmxlbmd0aCkgcmV0dXJuO1xyXG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpLCBsaXN0O1xyXG4gICAgaWYgKG9wZXJhdGlvbkdyb3VwKSB7XHJcbiAgICAgIGxpc3QgPSBvcGVyYXRpb25Hcm91cC5kZWxheWVkQ2FsbGJhY2tzO1xyXG4gICAgfSBlbHNlIGlmIChvcnBoYW5EZWxheWVkQ2FsbGJhY2tzKSB7XHJcbiAgICAgIGxpc3QgPSBvcnBoYW5EZWxheWVkQ2FsbGJhY2tzO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbGlzdCA9IG9ycGhhbkRlbGF5ZWRDYWxsYmFja3MgPSBbXTtcclxuICAgICAgc2V0VGltZW91dChmaXJlT3JwaGFuRGVsYXllZCwgMCk7XHJcbiAgICB9XHJcbiAgICBmdW5jdGlvbiBibmQoZikge3JldHVybiBmdW5jdGlvbigpe2YuYXBwbHkobnVsbCwgYXJncyk7fTt9O1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcnIubGVuZ3RoOyArK2kpXHJcbiAgICAgIGxpc3QucHVzaChibmQoYXJyW2ldKSk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBmaXJlT3JwaGFuRGVsYXllZCgpIHtcclxuICAgIHZhciBkZWxheWVkID0gb3JwaGFuRGVsYXllZENhbGxiYWNrcztcclxuICAgIG9ycGhhbkRlbGF5ZWRDYWxsYmFja3MgPSBudWxsO1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBkZWxheWVkLmxlbmd0aDsgKytpKSBkZWxheWVkW2ldKCk7XHJcbiAgfVxyXG5cclxuICAvLyBUaGUgRE9NIGV2ZW50cyB0aGF0IENvZGVNaXJyb3IgaGFuZGxlcyBjYW4gYmUgb3ZlcnJpZGRlbiBieVxyXG4gIC8vIHJlZ2lzdGVyaW5nIGEgKG5vbi1ET00pIGhhbmRsZXIgb24gdGhlIGVkaXRvciBmb3IgdGhlIGV2ZW50IG5hbWUsXHJcbiAgLy8gYW5kIHByZXZlbnREZWZhdWx0LWluZyB0aGUgZXZlbnQgaW4gdGhhdCBoYW5kbGVyLlxyXG4gIGZ1bmN0aW9uIHNpZ25hbERPTUV2ZW50KGNtLCBlLCBvdmVycmlkZSkge1xyXG4gICAgaWYgKHR5cGVvZiBlID09IFwic3RyaW5nXCIpXHJcbiAgICAgIGUgPSB7dHlwZTogZSwgcHJldmVudERlZmF1bHQ6IGZ1bmN0aW9uKCkgeyB0aGlzLmRlZmF1bHRQcmV2ZW50ZWQgPSB0cnVlOyB9fTtcclxuICAgIHNpZ25hbChjbSwgb3ZlcnJpZGUgfHwgZS50eXBlLCBjbSwgZSk7XHJcbiAgICByZXR1cm4gZV9kZWZhdWx0UHJldmVudGVkKGUpIHx8IGUuY29kZW1pcnJvcklnbm9yZTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIHNpZ25hbEN1cnNvckFjdGl2aXR5KGNtKSB7XHJcbiAgICB2YXIgYXJyID0gY20uX2hhbmRsZXJzICYmIGNtLl9oYW5kbGVycy5jdXJzb3JBY3Rpdml0eTtcclxuICAgIGlmICghYXJyKSByZXR1cm47XHJcbiAgICB2YXIgc2V0ID0gY20uY3VyT3AuY3Vyc29yQWN0aXZpdHlIYW5kbGVycyB8fCAoY20uY3VyT3AuY3Vyc29yQWN0aXZpdHlIYW5kbGVycyA9IFtdKTtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYXJyLmxlbmd0aDsgKytpKSBpZiAoaW5kZXhPZihzZXQsIGFycltpXSkgPT0gLTEpXHJcbiAgICAgIHNldC5wdXNoKGFycltpXSk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBoYXNIYW5kbGVyKGVtaXR0ZXIsIHR5cGUpIHtcclxuICAgIHJldHVybiBnZXRIYW5kbGVycyhlbWl0dGVyLCB0eXBlKS5sZW5ndGggPiAwXHJcbiAgfVxyXG5cclxuICAvLyBBZGQgb24gYW5kIG9mZiBtZXRob2RzIHRvIGEgY29uc3RydWN0b3IncyBwcm90b3R5cGUsIHRvIG1ha2VcclxuICAvLyByZWdpc3RlcmluZyBldmVudHMgb24gc3VjaCBvYmplY3RzIG1vcmUgY29udmVuaWVudC5cclxuICBmdW5jdGlvbiBldmVudE1peGluKGN0b3IpIHtcclxuICAgIGN0b3IucHJvdG90eXBlLm9uID0gZnVuY3Rpb24odHlwZSwgZikge29uKHRoaXMsIHR5cGUsIGYpO307XHJcbiAgICBjdG9yLnByb3RvdHlwZS5vZmYgPSBmdW5jdGlvbih0eXBlLCBmKSB7b2ZmKHRoaXMsIHR5cGUsIGYpO307XHJcbiAgfVxyXG5cclxuICAvLyBNSVNDIFVUSUxJVElFU1xyXG5cclxuICAvLyBOdW1iZXIgb2YgcGl4ZWxzIGFkZGVkIHRvIHNjcm9sbGVyIGFuZCBzaXplciB0byBoaWRlIHNjcm9sbGJhclxyXG4gIHZhciBzY3JvbGxlckdhcCA9IDMwO1xyXG5cclxuICAvLyBSZXR1cm5lZCBvciB0aHJvd24gYnkgdmFyaW91cyBwcm90b2NvbHMgdG8gc2lnbmFsICdJJ20gbm90XHJcbiAgLy8gaGFuZGxpbmcgdGhpcycuXHJcbiAgdmFyIFBhc3MgPSBDb2RlTWlycm9yLlBhc3MgPSB7dG9TdHJpbmc6IGZ1bmN0aW9uKCl7cmV0dXJuIFwiQ29kZU1pcnJvci5QYXNzXCI7fX07XHJcblxyXG4gIC8vIFJldXNlZCBvcHRpb24gb2JqZWN0cyBmb3Igc2V0U2VsZWN0aW9uICYgZnJpZW5kc1xyXG4gIHZhciBzZWxfZG9udFNjcm9sbCA9IHtzY3JvbGw6IGZhbHNlfSwgc2VsX21vdXNlID0ge29yaWdpbjogXCIqbW91c2VcIn0sIHNlbF9tb3ZlID0ge29yaWdpbjogXCIrbW92ZVwifTtcclxuXHJcbiAgZnVuY3Rpb24gRGVsYXllZCgpIHt0aGlzLmlkID0gbnVsbDt9XHJcbiAgRGVsYXllZC5wcm90b3R5cGUuc2V0ID0gZnVuY3Rpb24obXMsIGYpIHtcclxuICAgIGNsZWFyVGltZW91dCh0aGlzLmlkKTtcclxuICAgIHRoaXMuaWQgPSBzZXRUaW1lb3V0KGYsIG1zKTtcclxuICB9O1xyXG5cclxuICAvLyBDb3VudHMgdGhlIGNvbHVtbiBvZmZzZXQgaW4gYSBzdHJpbmcsIHRha2luZyB0YWJzIGludG8gYWNjb3VudC5cclxuICAvLyBVc2VkIG1vc3RseSB0byBmaW5kIGluZGVudGF0aW9uLlxyXG4gIHZhciBjb3VudENvbHVtbiA9IENvZGVNaXJyb3IuY291bnRDb2x1bW4gPSBmdW5jdGlvbihzdHJpbmcsIGVuZCwgdGFiU2l6ZSwgc3RhcnRJbmRleCwgc3RhcnRWYWx1ZSkge1xyXG4gICAgaWYgKGVuZCA9PSBudWxsKSB7XHJcbiAgICAgIGVuZCA9IHN0cmluZy5zZWFyY2goL1teXFxzXFx1MDBhMF0vKTtcclxuICAgICAgaWYgKGVuZCA9PSAtMSkgZW5kID0gc3RyaW5nLmxlbmd0aDtcclxuICAgIH1cclxuICAgIGZvciAodmFyIGkgPSBzdGFydEluZGV4IHx8IDAsIG4gPSBzdGFydFZhbHVlIHx8IDA7Oykge1xyXG4gICAgICB2YXIgbmV4dFRhYiA9IHN0cmluZy5pbmRleE9mKFwiXFx0XCIsIGkpO1xyXG4gICAgICBpZiAobmV4dFRhYiA8IDAgfHwgbmV4dFRhYiA+PSBlbmQpXHJcbiAgICAgICAgcmV0dXJuIG4gKyAoZW5kIC0gaSk7XHJcbiAgICAgIG4gKz0gbmV4dFRhYiAtIGk7XHJcbiAgICAgIG4gKz0gdGFiU2l6ZSAtIChuICUgdGFiU2l6ZSk7XHJcbiAgICAgIGkgPSBuZXh0VGFiICsgMTtcclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBUaGUgaW52ZXJzZSBvZiBjb3VudENvbHVtbiAtLSBmaW5kIHRoZSBvZmZzZXQgdGhhdCBjb3JyZXNwb25kcyB0b1xyXG4gIC8vIGEgcGFydGljdWxhciBjb2x1bW4uXHJcbiAgdmFyIGZpbmRDb2x1bW4gPSBDb2RlTWlycm9yLmZpbmRDb2x1bW4gPSBmdW5jdGlvbihzdHJpbmcsIGdvYWwsIHRhYlNpemUpIHtcclxuICAgIGZvciAodmFyIHBvcyA9IDAsIGNvbCA9IDA7Oykge1xyXG4gICAgICB2YXIgbmV4dFRhYiA9IHN0cmluZy5pbmRleE9mKFwiXFx0XCIsIHBvcyk7XHJcbiAgICAgIGlmIChuZXh0VGFiID09IC0xKSBuZXh0VGFiID0gc3RyaW5nLmxlbmd0aDtcclxuICAgICAgdmFyIHNraXBwZWQgPSBuZXh0VGFiIC0gcG9zO1xyXG4gICAgICBpZiAobmV4dFRhYiA9PSBzdHJpbmcubGVuZ3RoIHx8IGNvbCArIHNraXBwZWQgPj0gZ29hbClcclxuICAgICAgICByZXR1cm4gcG9zICsgTWF0aC5taW4oc2tpcHBlZCwgZ29hbCAtIGNvbCk7XHJcbiAgICAgIGNvbCArPSBuZXh0VGFiIC0gcG9zO1xyXG4gICAgICBjb2wgKz0gdGFiU2l6ZSAtIChjb2wgJSB0YWJTaXplKTtcclxuICAgICAgcG9zID0gbmV4dFRhYiArIDE7XHJcbiAgICAgIGlmIChjb2wgPj0gZ29hbCkgcmV0dXJuIHBvcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHZhciBzcGFjZVN0cnMgPSBbXCJcIl07XHJcbiAgZnVuY3Rpb24gc3BhY2VTdHIobikge1xyXG4gICAgd2hpbGUgKHNwYWNlU3Rycy5sZW5ndGggPD0gbilcclxuICAgICAgc3BhY2VTdHJzLnB1c2gobHN0KHNwYWNlU3RycykgKyBcIiBcIik7XHJcbiAgICByZXR1cm4gc3BhY2VTdHJzW25dO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gbHN0KGFycikgeyByZXR1cm4gYXJyW2Fyci5sZW5ndGgtMV07IH1cclxuXHJcbiAgdmFyIHNlbGVjdElucHV0ID0gZnVuY3Rpb24obm9kZSkgeyBub2RlLnNlbGVjdCgpOyB9O1xyXG4gIGlmIChpb3MpIC8vIE1vYmlsZSBTYWZhcmkgYXBwYXJlbnRseSBoYXMgYSBidWcgd2hlcmUgc2VsZWN0KCkgaXMgYnJva2VuLlxyXG4gICAgc2VsZWN0SW5wdXQgPSBmdW5jdGlvbihub2RlKSB7IG5vZGUuc2VsZWN0aW9uU3RhcnQgPSAwOyBub2RlLnNlbGVjdGlvbkVuZCA9IG5vZGUudmFsdWUubGVuZ3RoOyB9O1xyXG4gIGVsc2UgaWYgKGllKSAvLyBTdXBwcmVzcyBteXN0ZXJpb3VzIElFMTAgZXJyb3JzXHJcbiAgICBzZWxlY3RJbnB1dCA9IGZ1bmN0aW9uKG5vZGUpIHsgdHJ5IHsgbm9kZS5zZWxlY3QoKTsgfSBjYXRjaChfZSkge30gfTtcclxuXHJcbiAgZnVuY3Rpb24gaW5kZXhPZihhcnJheSwgZWx0KSB7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFycmF5Lmxlbmd0aDsgKytpKVxyXG4gICAgICBpZiAoYXJyYXlbaV0gPT0gZWx0KSByZXR1cm4gaTtcclxuICAgIHJldHVybiAtMTtcclxuICB9XHJcbiAgZnVuY3Rpb24gbWFwKGFycmF5LCBmKSB7XHJcbiAgICB2YXIgb3V0ID0gW107XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFycmF5Lmxlbmd0aDsgaSsrKSBvdXRbaV0gPSBmKGFycmF5W2ldLCBpKTtcclxuICAgIHJldHVybiBvdXQ7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBub3RoaW5nKCkge31cclxuXHJcbiAgZnVuY3Rpb24gY3JlYXRlT2JqKGJhc2UsIHByb3BzKSB7XHJcbiAgICB2YXIgaW5zdDtcclxuICAgIGlmIChPYmplY3QuY3JlYXRlKSB7XHJcbiAgICAgIGluc3QgPSBPYmplY3QuY3JlYXRlKGJhc2UpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbm90aGluZy5wcm90b3R5cGUgPSBiYXNlO1xyXG4gICAgICBpbnN0ID0gbmV3IG5vdGhpbmcoKTtcclxuICAgIH1cclxuICAgIGlmIChwcm9wcykgY29weU9iaihwcm9wcywgaW5zdCk7XHJcbiAgICByZXR1cm4gaW5zdDtcclxuICB9O1xyXG5cclxuICBmdW5jdGlvbiBjb3B5T2JqKG9iaiwgdGFyZ2V0LCBvdmVyd3JpdGUpIHtcclxuICAgIGlmICghdGFyZ2V0KSB0YXJnZXQgPSB7fTtcclxuICAgIGZvciAodmFyIHByb3AgaW4gb2JqKVxyXG4gICAgICBpZiAob2JqLmhhc093blByb3BlcnR5KHByb3ApICYmIChvdmVyd3JpdGUgIT09IGZhbHNlIHx8ICF0YXJnZXQuaGFzT3duUHJvcGVydHkocHJvcCkpKVxyXG4gICAgICAgIHRhcmdldFtwcm9wXSA9IG9ialtwcm9wXTtcclxuICAgIHJldHVybiB0YXJnZXQ7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBiaW5kKGYpIHtcclxuICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcclxuICAgIHJldHVybiBmdW5jdGlvbigpe3JldHVybiBmLmFwcGx5KG51bGwsIGFyZ3MpO307XHJcbiAgfVxyXG5cclxuICB2YXIgbm9uQVNDSUlTaW5nbGVDYXNlV29yZENoYXIgPSAvW1xcdTAwZGZcXHUwNTg3XFx1MDU5MC1cXHUwNWY0XFx1MDYwMC1cXHUwNmZmXFx1MzA0MC1cXHUzMDlmXFx1MzBhMC1cXHUzMGZmXFx1MzQwMC1cXHU0ZGI1XFx1NGUwMC1cXHU5ZmNjXFx1YWMwMC1cXHVkN2FmXS87XHJcbiAgdmFyIGlzV29yZENoYXJCYXNpYyA9IENvZGVNaXJyb3IuaXNXb3JkQ2hhciA9IGZ1bmN0aW9uKGNoKSB7XHJcbiAgICByZXR1cm4gL1xcdy8udGVzdChjaCkgfHwgY2ggPiBcIlxceDgwXCIgJiZcclxuICAgICAgKGNoLnRvVXBwZXJDYXNlKCkgIT0gY2gudG9Mb3dlckNhc2UoKSB8fCBub25BU0NJSVNpbmdsZUNhc2VXb3JkQ2hhci50ZXN0KGNoKSk7XHJcbiAgfTtcclxuICBmdW5jdGlvbiBpc1dvcmRDaGFyKGNoLCBoZWxwZXIpIHtcclxuICAgIGlmICghaGVscGVyKSByZXR1cm4gaXNXb3JkQ2hhckJhc2ljKGNoKTtcclxuICAgIGlmIChoZWxwZXIuc291cmNlLmluZGV4T2YoXCJcXFxcd1wiKSA+IC0xICYmIGlzV29yZENoYXJCYXNpYyhjaCkpIHJldHVybiB0cnVlO1xyXG4gICAgcmV0dXJuIGhlbHBlci50ZXN0KGNoKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGlzRW1wdHkob2JqKSB7XHJcbiAgICBmb3IgKHZhciBuIGluIG9iaikgaWYgKG9iai5oYXNPd25Qcm9wZXJ0eShuKSAmJiBvYmpbbl0pIHJldHVybiBmYWxzZTtcclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH1cclxuXHJcbiAgLy8gRXh0ZW5kaW5nIHVuaWNvZGUgY2hhcmFjdGVycy4gQSBzZXJpZXMgb2YgYSBub24tZXh0ZW5kaW5nIGNoYXIgK1xyXG4gIC8vIGFueSBudW1iZXIgb2YgZXh0ZW5kaW5nIGNoYXJzIGlzIHRyZWF0ZWQgYXMgYSBzaW5nbGUgdW5pdCBhcyBmYXJcclxuICAvLyBhcyBlZGl0aW5nIGFuZCBtZWFzdXJpbmcgaXMgY29uY2VybmVkLiBUaGlzIGlzIG5vdCBmdWxseSBjb3JyZWN0LFxyXG4gIC8vIHNpbmNlIHNvbWUgc2NyaXB0cy9mb250cy9icm93c2VycyBhbHNvIHRyZWF0IG90aGVyIGNvbmZpZ3VyYXRpb25zXHJcbiAgLy8gb2YgY29kZSBwb2ludHMgYXMgYSBncm91cC5cclxuICB2YXIgZXh0ZW5kaW5nQ2hhcnMgPSAvW1xcdTAzMDAtXFx1MDM2ZlxcdTA0ODMtXFx1MDQ4OVxcdTA1OTEtXFx1MDViZFxcdTA1YmZcXHUwNWMxXFx1MDVjMlxcdTA1YzRcXHUwNWM1XFx1MDVjN1xcdTA2MTAtXFx1MDYxYVxcdTA2NGItXFx1MDY1ZVxcdTA2NzBcXHUwNmQ2LVxcdTA2ZGNcXHUwNmRlLVxcdTA2ZTRcXHUwNmU3XFx1MDZlOFxcdTA2ZWEtXFx1MDZlZFxcdTA3MTFcXHUwNzMwLVxcdTA3NGFcXHUwN2E2LVxcdTA3YjBcXHUwN2ViLVxcdTA3ZjNcXHUwODE2LVxcdTA4MTlcXHUwODFiLVxcdTA4MjNcXHUwODI1LVxcdTA4MjdcXHUwODI5LVxcdTA4MmRcXHUwOTAwLVxcdTA5MDJcXHUwOTNjXFx1MDk0MS1cXHUwOTQ4XFx1MDk0ZFxcdTA5NTEtXFx1MDk1NVxcdTA5NjJcXHUwOTYzXFx1MDk4MVxcdTA5YmNcXHUwOWJlXFx1MDljMS1cXHUwOWM0XFx1MDljZFxcdTA5ZDdcXHUwOWUyXFx1MDllM1xcdTBhMDFcXHUwYTAyXFx1MGEzY1xcdTBhNDFcXHUwYTQyXFx1MGE0N1xcdTBhNDhcXHUwYTRiLVxcdTBhNGRcXHUwYTUxXFx1MGE3MFxcdTBhNzFcXHUwYTc1XFx1MGE4MVxcdTBhODJcXHUwYWJjXFx1MGFjMS1cXHUwYWM1XFx1MGFjN1xcdTBhYzhcXHUwYWNkXFx1MGFlMlxcdTBhZTNcXHUwYjAxXFx1MGIzY1xcdTBiM2VcXHUwYjNmXFx1MGI0MS1cXHUwYjQ0XFx1MGI0ZFxcdTBiNTZcXHUwYjU3XFx1MGI2MlxcdTBiNjNcXHUwYjgyXFx1MGJiZVxcdTBiYzBcXHUwYmNkXFx1MGJkN1xcdTBjM2UtXFx1MGM0MFxcdTBjNDYtXFx1MGM0OFxcdTBjNGEtXFx1MGM0ZFxcdTBjNTVcXHUwYzU2XFx1MGM2MlxcdTBjNjNcXHUwY2JjXFx1MGNiZlxcdTBjYzJcXHUwY2M2XFx1MGNjY1xcdTBjY2RcXHUwY2Q1XFx1MGNkNlxcdTBjZTJcXHUwY2UzXFx1MGQzZVxcdTBkNDEtXFx1MGQ0NFxcdTBkNGRcXHUwZDU3XFx1MGQ2MlxcdTBkNjNcXHUwZGNhXFx1MGRjZlxcdTBkZDItXFx1MGRkNFxcdTBkZDZcXHUwZGRmXFx1MGUzMVxcdTBlMzQtXFx1MGUzYVxcdTBlNDctXFx1MGU0ZVxcdTBlYjFcXHUwZWI0LVxcdTBlYjlcXHUwZWJiXFx1MGViY1xcdTBlYzgtXFx1MGVjZFxcdTBmMThcXHUwZjE5XFx1MGYzNVxcdTBmMzdcXHUwZjM5XFx1MGY3MS1cXHUwZjdlXFx1MGY4MC1cXHUwZjg0XFx1MGY4NlxcdTBmODdcXHUwZjkwLVxcdTBmOTdcXHUwZjk5LVxcdTBmYmNcXHUwZmM2XFx1MTAyZC1cXHUxMDMwXFx1MTAzMi1cXHUxMDM3XFx1MTAzOVxcdTEwM2FcXHUxMDNkXFx1MTAzZVxcdTEwNThcXHUxMDU5XFx1MTA1ZS1cXHUxMDYwXFx1MTA3MS1cXHUxMDc0XFx1MTA4MlxcdTEwODVcXHUxMDg2XFx1MTA4ZFxcdTEwOWRcXHUxMzVmXFx1MTcxMi1cXHUxNzE0XFx1MTczMi1cXHUxNzM0XFx1MTc1MlxcdTE3NTNcXHUxNzcyXFx1MTc3M1xcdTE3YjctXFx1MTdiZFxcdTE3YzZcXHUxN2M5LVxcdTE3ZDNcXHUxN2RkXFx1MTgwYi1cXHUxODBkXFx1MThhOVxcdTE5MjAtXFx1MTkyMlxcdTE5MjdcXHUxOTI4XFx1MTkzMlxcdTE5MzktXFx1MTkzYlxcdTFhMTdcXHUxYTE4XFx1MWE1NlxcdTFhNTgtXFx1MWE1ZVxcdTFhNjBcXHUxYTYyXFx1MWE2NS1cXHUxYTZjXFx1MWE3My1cXHUxYTdjXFx1MWE3ZlxcdTFiMDAtXFx1MWIwM1xcdTFiMzRcXHUxYjM2LVxcdTFiM2FcXHUxYjNjXFx1MWI0MlxcdTFiNmItXFx1MWI3M1xcdTFiODBcXHUxYjgxXFx1MWJhMi1cXHUxYmE1XFx1MWJhOFxcdTFiYTlcXHUxYzJjLVxcdTFjMzNcXHUxYzM2XFx1MWMzN1xcdTFjZDAtXFx1MWNkMlxcdTFjZDQtXFx1MWNlMFxcdTFjZTItXFx1MWNlOFxcdTFjZWRcXHUxZGMwLVxcdTFkZTZcXHUxZGZkLVxcdTFkZmZcXHUyMDBjXFx1MjAwZFxcdTIwZDAtXFx1MjBmMFxcdTJjZWYtXFx1MmNmMVxcdTJkZTAtXFx1MmRmZlxcdTMwMmEtXFx1MzAyZlxcdTMwOTlcXHUzMDlhXFx1YTY2Zi1cXHVhNjcyXFx1YTY3Y1xcdWE2N2RcXHVhNmYwXFx1YTZmMVxcdWE4MDJcXHVhODA2XFx1YTgwYlxcdWE4MjVcXHVhODI2XFx1YThjNFxcdWE4ZTAtXFx1YThmMVxcdWE5MjYtXFx1YTkyZFxcdWE5NDctXFx1YTk1MVxcdWE5ODAtXFx1YTk4MlxcdWE5YjNcXHVhOWI2LVxcdWE5YjlcXHVhOWJjXFx1YWEyOS1cXHVhYTJlXFx1YWEzMVxcdWFhMzJcXHVhYTM1XFx1YWEzNlxcdWFhNDNcXHVhYTRjXFx1YWFiMFxcdWFhYjItXFx1YWFiNFxcdWFhYjdcXHVhYWI4XFx1YWFiZVxcdWFhYmZcXHVhYWMxXFx1YWJlNVxcdWFiZThcXHVhYmVkXFx1ZGMwMC1cXHVkZmZmXFx1ZmIxZVxcdWZlMDAtXFx1ZmUwZlxcdWZlMjAtXFx1ZmUyNlxcdWZmOWVcXHVmZjlmXS87XHJcbiAgZnVuY3Rpb24gaXNFeHRlbmRpbmdDaGFyKGNoKSB7IHJldHVybiBjaC5jaGFyQ29kZUF0KDApID49IDc2OCAmJiBleHRlbmRpbmdDaGFycy50ZXN0KGNoKTsgfVxyXG5cclxuICAvLyBET00gVVRJTElUSUVTXHJcblxyXG4gIGZ1bmN0aW9uIGVsdCh0YWcsIGNvbnRlbnQsIGNsYXNzTmFtZSwgc3R5bGUpIHtcclxuICAgIHZhciBlID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCh0YWcpO1xyXG4gICAgaWYgKGNsYXNzTmFtZSkgZS5jbGFzc05hbWUgPSBjbGFzc05hbWU7XHJcbiAgICBpZiAoc3R5bGUpIGUuc3R5bGUuY3NzVGV4dCA9IHN0eWxlO1xyXG4gICAgaWYgKHR5cGVvZiBjb250ZW50ID09IFwic3RyaW5nXCIpIGUuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoY29udGVudCkpO1xyXG4gICAgZWxzZSBpZiAoY29udGVudCkgZm9yICh2YXIgaSA9IDA7IGkgPCBjb250ZW50Lmxlbmd0aDsgKytpKSBlLmFwcGVuZENoaWxkKGNvbnRlbnRbaV0pO1xyXG4gICAgcmV0dXJuIGU7XHJcbiAgfVxyXG5cclxuICB2YXIgcmFuZ2U7XHJcbiAgaWYgKGRvY3VtZW50LmNyZWF0ZVJhbmdlKSByYW5nZSA9IGZ1bmN0aW9uKG5vZGUsIHN0YXJ0LCBlbmQsIGVuZE5vZGUpIHtcclxuICAgIHZhciByID0gZG9jdW1lbnQuY3JlYXRlUmFuZ2UoKTtcclxuICAgIHIuc2V0RW5kKGVuZE5vZGUgfHwgbm9kZSwgZW5kKTtcclxuICAgIHIuc2V0U3RhcnQobm9kZSwgc3RhcnQpO1xyXG4gICAgcmV0dXJuIHI7XHJcbiAgfTtcclxuICBlbHNlIHJhbmdlID0gZnVuY3Rpb24obm9kZSwgc3RhcnQsIGVuZCkge1xyXG4gICAgdmFyIHIgPSBkb2N1bWVudC5ib2R5LmNyZWF0ZVRleHRSYW5nZSgpO1xyXG4gICAgdHJ5IHsgci5tb3ZlVG9FbGVtZW50VGV4dChub2RlLnBhcmVudE5vZGUpOyB9XHJcbiAgICBjYXRjaChlKSB7IHJldHVybiByOyB9XHJcbiAgICByLmNvbGxhcHNlKHRydWUpO1xyXG4gICAgci5tb3ZlRW5kKFwiY2hhcmFjdGVyXCIsIGVuZCk7XHJcbiAgICByLm1vdmVTdGFydChcImNoYXJhY3RlclwiLCBzdGFydCk7XHJcbiAgICByZXR1cm4gcjtcclxuICB9O1xyXG5cclxuICBmdW5jdGlvbiByZW1vdmVDaGlsZHJlbihlKSB7XHJcbiAgICBmb3IgKHZhciBjb3VudCA9IGUuY2hpbGROb2Rlcy5sZW5ndGg7IGNvdW50ID4gMDsgLS1jb3VudClcclxuICAgICAgZS5yZW1vdmVDaGlsZChlLmZpcnN0Q2hpbGQpO1xyXG4gICAgcmV0dXJuIGU7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiByZW1vdmVDaGlsZHJlbkFuZEFkZChwYXJlbnQsIGUpIHtcclxuICAgIHJldHVybiByZW1vdmVDaGlsZHJlbihwYXJlbnQpLmFwcGVuZENoaWxkKGUpO1xyXG4gIH1cclxuXHJcbiAgdmFyIGNvbnRhaW5zID0gQ29kZU1pcnJvci5jb250YWlucyA9IGZ1bmN0aW9uKHBhcmVudCwgY2hpbGQpIHtcclxuICAgIGlmIChjaGlsZC5ub2RlVHlwZSA9PSAzKSAvLyBBbmRyb2lkIGJyb3dzZXIgYWx3YXlzIHJldHVybnMgZmFsc2Ugd2hlbiBjaGlsZCBpcyBhIHRleHRub2RlXHJcbiAgICAgIGNoaWxkID0gY2hpbGQucGFyZW50Tm9kZTtcclxuICAgIGlmIChwYXJlbnQuY29udGFpbnMpXHJcbiAgICAgIHJldHVybiBwYXJlbnQuY29udGFpbnMoY2hpbGQpO1xyXG4gICAgZG8ge1xyXG4gICAgICBpZiAoY2hpbGQubm9kZVR5cGUgPT0gMTEpIGNoaWxkID0gY2hpbGQuaG9zdDtcclxuICAgICAgaWYgKGNoaWxkID09IHBhcmVudCkgcmV0dXJuIHRydWU7XHJcbiAgICB9IHdoaWxlIChjaGlsZCA9IGNoaWxkLnBhcmVudE5vZGUpO1xyXG4gIH07XHJcblxyXG4gIGZ1bmN0aW9uIGFjdGl2ZUVsdCgpIHtcclxuICAgIHZhciBhY3RpdmVFbGVtZW50ID0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudDtcclxuICAgIHdoaWxlIChhY3RpdmVFbGVtZW50ICYmIGFjdGl2ZUVsZW1lbnQucm9vdCAmJiBhY3RpdmVFbGVtZW50LnJvb3QuYWN0aXZlRWxlbWVudClcclxuICAgICAgYWN0aXZlRWxlbWVudCA9IGFjdGl2ZUVsZW1lbnQucm9vdC5hY3RpdmVFbGVtZW50O1xyXG4gICAgcmV0dXJuIGFjdGl2ZUVsZW1lbnQ7XHJcbiAgfVxyXG4gIC8vIE9sZGVyIHZlcnNpb25zIG9mIElFIHRocm93cyB1bnNwZWNpZmllZCBlcnJvciB3aGVuIHRvdWNoaW5nXHJcbiAgLy8gZG9jdW1lbnQuYWN0aXZlRWxlbWVudCBpbiBzb21lIGNhc2VzIChkdXJpbmcgbG9hZGluZywgaW4gaWZyYW1lKVxyXG4gIGlmIChpZSAmJiBpZV92ZXJzaW9uIDwgMTEpIGFjdGl2ZUVsdCA9IGZ1bmN0aW9uKCkge1xyXG4gICAgdHJ5IHsgcmV0dXJuIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7IH1cclxuICAgIGNhdGNoKGUpIHsgcmV0dXJuIGRvY3VtZW50LmJvZHk7IH1cclxuICB9O1xyXG5cclxuICBmdW5jdGlvbiBjbGFzc1Rlc3QoY2xzKSB7IHJldHVybiBuZXcgUmVnRXhwKFwiKF58XFxcXHMpXCIgKyBjbHMgKyBcIig/OiR8XFxcXHMpXFxcXHMqXCIpOyB9XHJcbiAgdmFyIHJtQ2xhc3MgPSBDb2RlTWlycm9yLnJtQ2xhc3MgPSBmdW5jdGlvbihub2RlLCBjbHMpIHtcclxuICAgIHZhciBjdXJyZW50ID0gbm9kZS5jbGFzc05hbWU7XHJcbiAgICB2YXIgbWF0Y2ggPSBjbGFzc1Rlc3QoY2xzKS5leGVjKGN1cnJlbnQpO1xyXG4gICAgaWYgKG1hdGNoKSB7XHJcbiAgICAgIHZhciBhZnRlciA9IGN1cnJlbnQuc2xpY2UobWF0Y2guaW5kZXggKyBtYXRjaFswXS5sZW5ndGgpO1xyXG4gICAgICBub2RlLmNsYXNzTmFtZSA9IGN1cnJlbnQuc2xpY2UoMCwgbWF0Y2guaW5kZXgpICsgKGFmdGVyID8gbWF0Y2hbMV0gKyBhZnRlciA6IFwiXCIpO1xyXG4gICAgfVxyXG4gIH07XHJcbiAgdmFyIGFkZENsYXNzID0gQ29kZU1pcnJvci5hZGRDbGFzcyA9IGZ1bmN0aW9uKG5vZGUsIGNscykge1xyXG4gICAgdmFyIGN1cnJlbnQgPSBub2RlLmNsYXNzTmFtZTtcclxuICAgIGlmICghY2xhc3NUZXN0KGNscykudGVzdChjdXJyZW50KSkgbm9kZS5jbGFzc05hbWUgKz0gKGN1cnJlbnQgPyBcIiBcIiA6IFwiXCIpICsgY2xzO1xyXG4gIH07XHJcbiAgZnVuY3Rpb24gam9pbkNsYXNzZXMoYSwgYikge1xyXG4gICAgdmFyIGFzID0gYS5zcGxpdChcIiBcIik7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFzLmxlbmd0aDsgaSsrKVxyXG4gICAgICBpZiAoYXNbaV0gJiYgIWNsYXNzVGVzdChhc1tpXSkudGVzdChiKSkgYiArPSBcIiBcIiArIGFzW2ldO1xyXG4gICAgcmV0dXJuIGI7XHJcbiAgfVxyXG5cclxuICAvLyBXSU5ET1ctV0lERSBFVkVOVFNcclxuXHJcbiAgLy8gVGhlc2UgbXVzdCBiZSBoYW5kbGVkIGNhcmVmdWxseSwgYmVjYXVzZSBuYWl2ZWx5IHJlZ2lzdGVyaW5nIGFcclxuICAvLyBoYW5kbGVyIGZvciBlYWNoIGVkaXRvciB3aWxsIGNhdXNlIHRoZSBlZGl0b3JzIHRvIG5ldmVyIGJlXHJcbiAgLy8gZ2FyYmFnZSBjb2xsZWN0ZWQuXHJcblxyXG4gIGZ1bmN0aW9uIGZvckVhY2hDb2RlTWlycm9yKGYpIHtcclxuICAgIGlmICghZG9jdW1lbnQuYm9keS5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKSByZXR1cm47XHJcbiAgICB2YXIgYnlDbGFzcyA9IGRvY3VtZW50LmJvZHkuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZShcIkNvZGVNaXJyb3JcIik7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJ5Q2xhc3MubGVuZ3RoOyBpKyspIHtcclxuICAgICAgdmFyIGNtID0gYnlDbGFzc1tpXS5Db2RlTWlycm9yO1xyXG4gICAgICBpZiAoY20pIGYoY20pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdmFyIGdsb2JhbHNSZWdpc3RlcmVkID0gZmFsc2U7XHJcbiAgZnVuY3Rpb24gZW5zdXJlR2xvYmFsSGFuZGxlcnMoKSB7XHJcbiAgICBpZiAoZ2xvYmFsc1JlZ2lzdGVyZWQpIHJldHVybjtcclxuICAgIHJlZ2lzdGVyR2xvYmFsSGFuZGxlcnMoKTtcclxuICAgIGdsb2JhbHNSZWdpc3RlcmVkID0gdHJ1ZTtcclxuICB9XHJcbiAgZnVuY3Rpb24gcmVnaXN0ZXJHbG9iYWxIYW5kbGVycygpIHtcclxuICAgIC8vIFdoZW4gdGhlIHdpbmRvdyByZXNpemVzLCB3ZSBuZWVkIHRvIHJlZnJlc2ggYWN0aXZlIGVkaXRvcnMuXHJcbiAgICB2YXIgcmVzaXplVGltZXI7XHJcbiAgICBvbih3aW5kb3csIFwicmVzaXplXCIsIGZ1bmN0aW9uKCkge1xyXG4gICAgICBpZiAocmVzaXplVGltZXIgPT0gbnVsbCkgcmVzaXplVGltZXIgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xyXG4gICAgICAgIHJlc2l6ZVRpbWVyID0gbnVsbDtcclxuICAgICAgICBmb3JFYWNoQ29kZU1pcnJvcihvblJlc2l6ZSk7XHJcbiAgICAgIH0sIDEwMCk7XHJcbiAgICB9KTtcclxuICAgIC8vIFdoZW4gdGhlIHdpbmRvdyBsb3NlcyBmb2N1cywgd2Ugd2FudCB0byBzaG93IHRoZSBlZGl0b3IgYXMgYmx1cnJlZFxyXG4gICAgb24od2luZG93LCBcImJsdXJcIiwgZnVuY3Rpb24oKSB7XHJcbiAgICAgIGZvckVhY2hDb2RlTWlycm9yKG9uQmx1cik7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8vIEZFQVRVUkUgREVURUNUSU9OXHJcblxyXG4gIC8vIERldGVjdCBkcmFnLWFuZC1kcm9wXHJcbiAgdmFyIGRyYWdBbmREcm9wID0gZnVuY3Rpb24oKSB7XHJcbiAgICAvLyBUaGVyZSBpcyAqc29tZSoga2luZCBvZiBkcmFnLWFuZC1kcm9wIHN1cHBvcnQgaW4gSUU2LTgsIGJ1dCBJXHJcbiAgICAvLyBjb3VsZG4ndCBnZXQgaXQgdG8gd29yayB5ZXQuXHJcbiAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA8IDkpIHJldHVybiBmYWxzZTtcclxuICAgIHZhciBkaXYgPSBlbHQoJ2RpdicpO1xyXG4gICAgcmV0dXJuIFwiZHJhZ2dhYmxlXCIgaW4gZGl2IHx8IFwiZHJhZ0Ryb3BcIiBpbiBkaXY7XHJcbiAgfSgpO1xyXG5cclxuICB2YXIgendzcFN1cHBvcnRlZDtcclxuICBmdW5jdGlvbiB6ZXJvV2lkdGhFbGVtZW50KG1lYXN1cmUpIHtcclxuICAgIGlmICh6d3NwU3VwcG9ydGVkID09IG51bGwpIHtcclxuICAgICAgdmFyIHRlc3QgPSBlbHQoXCJzcGFuXCIsIFwiXFx1MjAwYlwiKTtcclxuICAgICAgcmVtb3ZlQ2hpbGRyZW5BbmRBZGQobWVhc3VyZSwgZWx0KFwic3BhblwiLCBbdGVzdCwgZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoXCJ4XCIpXSkpO1xyXG4gICAgICBpZiAobWVhc3VyZS5maXJzdENoaWxkLm9mZnNldEhlaWdodCAhPSAwKVxyXG4gICAgICAgIHp3c3BTdXBwb3J0ZWQgPSB0ZXN0Lm9mZnNldFdpZHRoIDw9IDEgJiYgdGVzdC5vZmZzZXRIZWlnaHQgPiAyICYmICEoaWUgJiYgaWVfdmVyc2lvbiA8IDgpO1xyXG4gICAgfVxyXG4gICAgdmFyIG5vZGUgPSB6d3NwU3VwcG9ydGVkID8gZWx0KFwic3BhblwiLCBcIlxcdTIwMGJcIikgOlxyXG4gICAgICBlbHQoXCJzcGFuXCIsIFwiXFx1MDBhMFwiLCBudWxsLCBcImRpc3BsYXk6IGlubGluZS1ibG9jazsgd2lkdGg6IDFweDsgbWFyZ2luLXJpZ2h0OiAtMXB4XCIpO1xyXG4gICAgbm9kZS5zZXRBdHRyaWJ1dGUoXCJjbS10ZXh0XCIsIFwiXCIpO1xyXG4gICAgcmV0dXJuIG5vZGU7XHJcbiAgfVxyXG5cclxuICAvLyBGZWF0dXJlLWRldGVjdCBJRSdzIGNydW1teSBjbGllbnQgcmVjdCByZXBvcnRpbmcgZm9yIGJpZGkgdGV4dFxyXG4gIHZhciBiYWRCaWRpUmVjdHM7XHJcbiAgZnVuY3Rpb24gaGFzQmFkQmlkaVJlY3RzKG1lYXN1cmUpIHtcclxuICAgIGlmIChiYWRCaWRpUmVjdHMgIT0gbnVsbCkgcmV0dXJuIGJhZEJpZGlSZWN0cztcclxuICAgIHZhciB0eHQgPSByZW1vdmVDaGlsZHJlbkFuZEFkZChtZWFzdXJlLCBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShcIkFcXHUwNjJlQVwiKSk7XHJcbiAgICB2YXIgcjAgPSByYW5nZSh0eHQsIDAsIDEpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgaWYgKCFyMCB8fCByMC5sZWZ0ID09IHIwLnJpZ2h0KSByZXR1cm4gZmFsc2U7IC8vIFNhZmFyaSByZXR1cm5zIG51bGwgaW4gc29tZSBjYXNlcyAoIzI3ODApXHJcbiAgICB2YXIgcjEgPSByYW5nZSh0eHQsIDEsIDIpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIGJhZEJpZGlSZWN0cyA9IChyMS5yaWdodCAtIHIwLnJpZ2h0IDwgMyk7XHJcbiAgfVxyXG5cclxuICAvLyBTZWUgaWYgXCJcIi5zcGxpdCBpcyB0aGUgYnJva2VuIElFIHZlcnNpb24sIGlmIHNvLCBwcm92aWRlIGFuXHJcbiAgLy8gYWx0ZXJuYXRpdmUgd2F5IHRvIHNwbGl0IGxpbmVzLlxyXG4gIHZhciBzcGxpdExpbmVzQXV0byA9IENvZGVNaXJyb3Iuc3BsaXRMaW5lcyA9IFwiXFxuXFxuYlwiLnNwbGl0KC9cXG4vKS5sZW5ndGggIT0gMyA/IGZ1bmN0aW9uKHN0cmluZykge1xyXG4gICAgdmFyIHBvcyA9IDAsIHJlc3VsdCA9IFtdLCBsID0gc3RyaW5nLmxlbmd0aDtcclxuICAgIHdoaWxlIChwb3MgPD0gbCkge1xyXG4gICAgICB2YXIgbmwgPSBzdHJpbmcuaW5kZXhPZihcIlxcblwiLCBwb3MpO1xyXG4gICAgICBpZiAobmwgPT0gLTEpIG5sID0gc3RyaW5nLmxlbmd0aDtcclxuICAgICAgdmFyIGxpbmUgPSBzdHJpbmcuc2xpY2UocG9zLCBzdHJpbmcuY2hhckF0KG5sIC0gMSkgPT0gXCJcXHJcIiA/IG5sIC0gMSA6IG5sKTtcclxuICAgICAgdmFyIHJ0ID0gbGluZS5pbmRleE9mKFwiXFxyXCIpO1xyXG4gICAgICBpZiAocnQgIT0gLTEpIHtcclxuICAgICAgICByZXN1bHQucHVzaChsaW5lLnNsaWNlKDAsIHJ0KSk7XHJcbiAgICAgICAgcG9zICs9IHJ0ICsgMTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICByZXN1bHQucHVzaChsaW5lKTtcclxuICAgICAgICBwb3MgPSBubCArIDE7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfSA6IGZ1bmN0aW9uKHN0cmluZyl7cmV0dXJuIHN0cmluZy5zcGxpdCgvXFxyXFxuP3xcXG4vKTt9O1xyXG5cclxuICB2YXIgaGFzU2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbiA/IGZ1bmN0aW9uKHRlKSB7XHJcbiAgICB0cnkgeyByZXR1cm4gdGUuc2VsZWN0aW9uU3RhcnQgIT0gdGUuc2VsZWN0aW9uRW5kOyB9XHJcbiAgICBjYXRjaChlKSB7IHJldHVybiBmYWxzZTsgfVxyXG4gIH0gOiBmdW5jdGlvbih0ZSkge1xyXG4gICAgdHJ5IHt2YXIgcmFuZ2UgPSB0ZS5vd25lckRvY3VtZW50LnNlbGVjdGlvbi5jcmVhdGVSYW5nZSgpO31cclxuICAgIGNhdGNoKGUpIHt9XHJcbiAgICBpZiAoIXJhbmdlIHx8IHJhbmdlLnBhcmVudEVsZW1lbnQoKSAhPSB0ZSkgcmV0dXJuIGZhbHNlO1xyXG4gICAgcmV0dXJuIHJhbmdlLmNvbXBhcmVFbmRQb2ludHMoXCJTdGFydFRvRW5kXCIsIHJhbmdlKSAhPSAwO1xyXG4gIH07XHJcblxyXG4gIHZhciBoYXNDb3B5RXZlbnQgPSAoZnVuY3Rpb24oKSB7XHJcbiAgICB2YXIgZSA9IGVsdChcImRpdlwiKTtcclxuICAgIGlmIChcIm9uY29weVwiIGluIGUpIHJldHVybiB0cnVlO1xyXG4gICAgZS5zZXRBdHRyaWJ1dGUoXCJvbmNvcHlcIiwgXCJyZXR1cm47XCIpO1xyXG4gICAgcmV0dXJuIHR5cGVvZiBlLm9uY29weSA9PSBcImZ1bmN0aW9uXCI7XHJcbiAgfSkoKTtcclxuXHJcbiAgdmFyIGJhZFpvb21lZFJlY3RzID0gbnVsbDtcclxuICBmdW5jdGlvbiBoYXNCYWRab29tZWRSZWN0cyhtZWFzdXJlKSB7XHJcbiAgICBpZiAoYmFkWm9vbWVkUmVjdHMgIT0gbnVsbCkgcmV0dXJuIGJhZFpvb21lZFJlY3RzO1xyXG4gICAgdmFyIG5vZGUgPSByZW1vdmVDaGlsZHJlbkFuZEFkZChtZWFzdXJlLCBlbHQoXCJzcGFuXCIsIFwieFwiKSk7XHJcbiAgICB2YXIgbm9ybWFsID0gbm9kZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHZhciBmcm9tUmFuZ2UgPSByYW5nZShub2RlLCAwLCAxKS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHJldHVybiBiYWRab29tZWRSZWN0cyA9IE1hdGguYWJzKG5vcm1hbC5sZWZ0IC0gZnJvbVJhbmdlLmxlZnQpID4gMTtcclxuICB9XHJcblxyXG4gIC8vIEtFWSBOQU1FU1xyXG5cclxuICB2YXIga2V5TmFtZXMgPSBDb2RlTWlycm9yLmtleU5hbWVzID0ge1xyXG4gICAgMzogXCJFbnRlclwiLCA4OiBcIkJhY2tzcGFjZVwiLCA5OiBcIlRhYlwiLCAxMzogXCJFbnRlclwiLCAxNjogXCJTaGlmdFwiLCAxNzogXCJDdHJsXCIsIDE4OiBcIkFsdFwiLFxyXG4gICAgMTk6IFwiUGF1c2VcIiwgMjA6IFwiQ2Fwc0xvY2tcIiwgMjc6IFwiRXNjXCIsIDMyOiBcIlNwYWNlXCIsIDMzOiBcIlBhZ2VVcFwiLCAzNDogXCJQYWdlRG93blwiLCAzNTogXCJFbmRcIixcclxuICAgIDM2OiBcIkhvbWVcIiwgMzc6IFwiTGVmdFwiLCAzODogXCJVcFwiLCAzOTogXCJSaWdodFwiLCA0MDogXCJEb3duXCIsIDQ0OiBcIlByaW50U2NyblwiLCA0NTogXCJJbnNlcnRcIixcclxuICAgIDQ2OiBcIkRlbGV0ZVwiLCA1OTogXCI7XCIsIDYxOiBcIj1cIiwgOTE6IFwiTW9kXCIsIDkyOiBcIk1vZFwiLCA5MzogXCJNb2RcIixcclxuICAgIDEwNjogXCIqXCIsIDEwNzogXCI9XCIsIDEwOTogXCItXCIsIDExMDogXCIuXCIsIDExMTogXCIvXCIsIDEyNzogXCJEZWxldGVcIixcclxuICAgIDE3MzogXCItXCIsIDE4NjogXCI7XCIsIDE4NzogXCI9XCIsIDE4ODogXCIsXCIsIDE4OTogXCItXCIsIDE5MDogXCIuXCIsIDE5MTogXCIvXCIsIDE5MjogXCJgXCIsIDIxOTogXCJbXCIsIDIyMDogXCJcXFxcXCIsXHJcbiAgICAyMjE6IFwiXVwiLCAyMjI6IFwiJ1wiLCA2MzIzMjogXCJVcFwiLCA2MzIzMzogXCJEb3duXCIsIDYzMjM0OiBcIkxlZnRcIiwgNjMyMzU6IFwiUmlnaHRcIiwgNjMyNzI6IFwiRGVsZXRlXCIsXHJcbiAgICA2MzI3MzogXCJIb21lXCIsIDYzMjc1OiBcIkVuZFwiLCA2MzI3NjogXCJQYWdlVXBcIiwgNjMyNzc6IFwiUGFnZURvd25cIiwgNjMzMDI6IFwiSW5zZXJ0XCJcclxuICB9O1xyXG4gIChmdW5jdGlvbigpIHtcclxuICAgIC8vIE51bWJlciBrZXlzXHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IDEwOyBpKyspIGtleU5hbWVzW2kgKyA0OF0gPSBrZXlOYW1lc1tpICsgOTZdID0gU3RyaW5nKGkpO1xyXG4gICAgLy8gQWxwaGFiZXRpYyBrZXlzXHJcbiAgICBmb3IgKHZhciBpID0gNjU7IGkgPD0gOTA7IGkrKykga2V5TmFtZXNbaV0gPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGkpO1xyXG4gICAgLy8gRnVuY3Rpb24ga2V5c1xyXG4gICAgZm9yICh2YXIgaSA9IDE7IGkgPD0gMTI7IGkrKykga2V5TmFtZXNbaSArIDExMV0gPSBrZXlOYW1lc1tpICsgNjMyMzVdID0gXCJGXCIgKyBpO1xyXG4gIH0pKCk7XHJcblxyXG4gIC8vIEJJREkgSEVMUEVSU1xyXG5cclxuICBmdW5jdGlvbiBpdGVyYXRlQmlkaVNlY3Rpb25zKG9yZGVyLCBmcm9tLCB0bywgZikge1xyXG4gICAgaWYgKCFvcmRlcikgcmV0dXJuIGYoZnJvbSwgdG8sIFwibHRyXCIpO1xyXG4gICAgdmFyIGZvdW5kID0gZmFsc2U7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG9yZGVyLmxlbmd0aDsgKytpKSB7XHJcbiAgICAgIHZhciBwYXJ0ID0gb3JkZXJbaV07XHJcbiAgICAgIGlmIChwYXJ0LmZyb20gPCB0byAmJiBwYXJ0LnRvID4gZnJvbSB8fCBmcm9tID09IHRvICYmIHBhcnQudG8gPT0gZnJvbSkge1xyXG4gICAgICAgIGYoTWF0aC5tYXgocGFydC5mcm9tLCBmcm9tKSwgTWF0aC5taW4ocGFydC50bywgdG8pLCBwYXJ0LmxldmVsID09IDEgPyBcInJ0bFwiIDogXCJsdHJcIik7XHJcbiAgICAgICAgZm91bmQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAoIWZvdW5kKSBmKGZyb20sIHRvLCBcImx0clwiKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGJpZGlMZWZ0KHBhcnQpIHsgcmV0dXJuIHBhcnQubGV2ZWwgJSAyID8gcGFydC50byA6IHBhcnQuZnJvbTsgfVxyXG4gIGZ1bmN0aW9uIGJpZGlSaWdodChwYXJ0KSB7IHJldHVybiBwYXJ0LmxldmVsICUgMiA/IHBhcnQuZnJvbSA6IHBhcnQudG87IH1cclxuXHJcbiAgZnVuY3Rpb24gbGluZUxlZnQobGluZSkgeyB2YXIgb3JkZXIgPSBnZXRPcmRlcihsaW5lKTsgcmV0dXJuIG9yZGVyID8gYmlkaUxlZnQob3JkZXJbMF0pIDogMDsgfVxyXG4gIGZ1bmN0aW9uIGxpbmVSaWdodChsaW5lKSB7XHJcbiAgICB2YXIgb3JkZXIgPSBnZXRPcmRlcihsaW5lKTtcclxuICAgIGlmICghb3JkZXIpIHJldHVybiBsaW5lLnRleHQubGVuZ3RoO1xyXG4gICAgcmV0dXJuIGJpZGlSaWdodChsc3Qob3JkZXIpKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGxpbmVTdGFydChjbSwgbGluZU4pIHtcclxuICAgIHZhciBsaW5lID0gZ2V0TGluZShjbS5kb2MsIGxpbmVOKTtcclxuICAgIHZhciB2aXN1YWwgPSB2aXN1YWxMaW5lKGxpbmUpO1xyXG4gICAgaWYgKHZpc3VhbCAhPSBsaW5lKSBsaW5lTiA9IGxpbmVObyh2aXN1YWwpO1xyXG4gICAgdmFyIG9yZGVyID0gZ2V0T3JkZXIodmlzdWFsKTtcclxuICAgIHZhciBjaCA9ICFvcmRlciA/IDAgOiBvcmRlclswXS5sZXZlbCAlIDIgPyBsaW5lUmlnaHQodmlzdWFsKSA6IGxpbmVMZWZ0KHZpc3VhbCk7XHJcbiAgICByZXR1cm4gUG9zKGxpbmVOLCBjaCk7XHJcbiAgfVxyXG4gIGZ1bmN0aW9uIGxpbmVFbmQoY20sIGxpbmVOKSB7XHJcbiAgICB2YXIgbWVyZ2VkLCBsaW5lID0gZ2V0TGluZShjbS5kb2MsIGxpbmVOKTtcclxuICAgIHdoaWxlIChtZXJnZWQgPSBjb2xsYXBzZWRTcGFuQXRFbmQobGluZSkpIHtcclxuICAgICAgbGluZSA9IG1lcmdlZC5maW5kKDEsIHRydWUpLmxpbmU7XHJcbiAgICAgIGxpbmVOID0gbnVsbDtcclxuICAgIH1cclxuICAgIHZhciBvcmRlciA9IGdldE9yZGVyKGxpbmUpO1xyXG4gICAgdmFyIGNoID0gIW9yZGVyID8gbGluZS50ZXh0Lmxlbmd0aCA6IG9yZGVyWzBdLmxldmVsICUgMiA/IGxpbmVMZWZ0KGxpbmUpIDogbGluZVJpZ2h0KGxpbmUpO1xyXG4gICAgcmV0dXJuIFBvcyhsaW5lTiA9PSBudWxsID8gbGluZU5vKGxpbmUpIDogbGluZU4sIGNoKTtcclxuICB9XHJcbiAgZnVuY3Rpb24gbGluZVN0YXJ0U21hcnQoY20sIHBvcykge1xyXG4gICAgdmFyIHN0YXJ0ID0gbGluZVN0YXJ0KGNtLCBwb3MubGluZSk7XHJcbiAgICB2YXIgbGluZSA9IGdldExpbmUoY20uZG9jLCBzdGFydC5saW5lKTtcclxuICAgIHZhciBvcmRlciA9IGdldE9yZGVyKGxpbmUpO1xyXG4gICAgaWYgKCFvcmRlciB8fCBvcmRlclswXS5sZXZlbCA9PSAwKSB7XHJcbiAgICAgIHZhciBmaXJzdE5vbldTID0gTWF0aC5tYXgoMCwgbGluZS50ZXh0LnNlYXJjaCgvXFxTLykpO1xyXG4gICAgICB2YXIgaW5XUyA9IHBvcy5saW5lID09IHN0YXJ0LmxpbmUgJiYgcG9zLmNoIDw9IGZpcnN0Tm9uV1MgJiYgcG9zLmNoO1xyXG4gICAgICByZXR1cm4gUG9zKHN0YXJ0LmxpbmUsIGluV1MgPyAwIDogZmlyc3ROb25XUyk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gc3RhcnQ7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBjb21wYXJlQmlkaUxldmVsKG9yZGVyLCBhLCBiKSB7XHJcbiAgICB2YXIgbGluZWRpciA9IG9yZGVyWzBdLmxldmVsO1xyXG4gICAgaWYgKGEgPT0gbGluZWRpcikgcmV0dXJuIHRydWU7XHJcbiAgICBpZiAoYiA9PSBsaW5lZGlyKSByZXR1cm4gZmFsc2U7XHJcbiAgICByZXR1cm4gYSA8IGI7XHJcbiAgfVxyXG4gIHZhciBiaWRpT3RoZXI7XHJcbiAgZnVuY3Rpb24gZ2V0QmlkaVBhcnRBdChvcmRlciwgcG9zKSB7XHJcbiAgICBiaWRpT3RoZXIgPSBudWxsO1xyXG4gICAgZm9yICh2YXIgaSA9IDAsIGZvdW5kOyBpIDwgb3JkZXIubGVuZ3RoOyArK2kpIHtcclxuICAgICAgdmFyIGN1ciA9IG9yZGVyW2ldO1xyXG4gICAgICBpZiAoY3VyLmZyb20gPCBwb3MgJiYgY3VyLnRvID4gcG9zKSByZXR1cm4gaTtcclxuICAgICAgaWYgKChjdXIuZnJvbSA9PSBwb3MgfHwgY3VyLnRvID09IHBvcykpIHtcclxuICAgICAgICBpZiAoZm91bmQgPT0gbnVsbCkge1xyXG4gICAgICAgICAgZm91bmQgPSBpO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoY29tcGFyZUJpZGlMZXZlbChvcmRlciwgY3VyLmxldmVsLCBvcmRlcltmb3VuZF0ubGV2ZWwpKSB7XHJcbiAgICAgICAgICBpZiAoY3VyLmZyb20gIT0gY3VyLnRvKSBiaWRpT3RoZXIgPSBmb3VuZDtcclxuICAgICAgICAgIHJldHVybiBpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBpZiAoY3VyLmZyb20gIT0gY3VyLnRvKSBiaWRpT3RoZXIgPSBpO1xyXG4gICAgICAgICAgcmV0dXJuIGZvdW5kO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gICAgcmV0dXJuIGZvdW5kO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gbW92ZUluTGluZShsaW5lLCBwb3MsIGRpciwgYnlVbml0KSB7XHJcbiAgICBpZiAoIWJ5VW5pdCkgcmV0dXJuIHBvcyArIGRpcjtcclxuICAgIGRvIHBvcyArPSBkaXI7XHJcbiAgICB3aGlsZSAocG9zID4gMCAmJiBpc0V4dGVuZGluZ0NoYXIobGluZS50ZXh0LmNoYXJBdChwb3MpKSk7XHJcbiAgICByZXR1cm4gcG9zO1xyXG4gIH1cclxuXHJcbiAgLy8gVGhpcyBpcyBuZWVkZWQgaW4gb3JkZXIgdG8gbW92ZSAndmlzdWFsbHknIHRocm91Z2ggYmktZGlyZWN0aW9uYWxcclxuICAvLyB0ZXh0IC0tIGkuZS4sIHByZXNzaW5nIGxlZnQgc2hvdWxkIG1ha2UgdGhlIGN1cnNvciBnbyBsZWZ0LCBldmVuXHJcbiAgLy8gd2hlbiBpbiBSVEwgdGV4dC4gVGhlIHRyaWNreSBwYXJ0IGlzIHRoZSAnanVtcHMnLCB3aGVyZSBSVEwgYW5kXHJcbiAgLy8gTFRSIHRleHQgdG91Y2ggZWFjaCBvdGhlci4gVGhpcyBvZnRlbiByZXF1aXJlcyB0aGUgY3Vyc29yIG9mZnNldFxyXG4gIC8vIHRvIG1vdmUgbW9yZSB0aGFuIG9uZSB1bml0LCBpbiBvcmRlciB0byB2aXN1YWxseSBtb3ZlIG9uZSB1bml0LlxyXG4gIGZ1bmN0aW9uIG1vdmVWaXN1YWxseShsaW5lLCBzdGFydCwgZGlyLCBieVVuaXQpIHtcclxuICAgIHZhciBiaWRpID0gZ2V0T3JkZXIobGluZSk7XHJcbiAgICBpZiAoIWJpZGkpIHJldHVybiBtb3ZlTG9naWNhbGx5KGxpbmUsIHN0YXJ0LCBkaXIsIGJ5VW5pdCk7XHJcbiAgICB2YXIgcG9zID0gZ2V0QmlkaVBhcnRBdChiaWRpLCBzdGFydCksIHBhcnQgPSBiaWRpW3Bvc107XHJcbiAgICB2YXIgdGFyZ2V0ID0gbW92ZUluTGluZShsaW5lLCBzdGFydCwgcGFydC5sZXZlbCAlIDIgPyAtZGlyIDogZGlyLCBieVVuaXQpO1xyXG5cclxuICAgIGZvciAoOzspIHtcclxuICAgICAgaWYgKHRhcmdldCA+IHBhcnQuZnJvbSAmJiB0YXJnZXQgPCBwYXJ0LnRvKSByZXR1cm4gdGFyZ2V0O1xyXG4gICAgICBpZiAodGFyZ2V0ID09IHBhcnQuZnJvbSB8fCB0YXJnZXQgPT0gcGFydC50bykge1xyXG4gICAgICAgIGlmIChnZXRCaWRpUGFydEF0KGJpZGksIHRhcmdldCkgPT0gcG9zKSByZXR1cm4gdGFyZ2V0O1xyXG4gICAgICAgIHBhcnQgPSBiaWRpW3BvcyArPSBkaXJdO1xyXG4gICAgICAgIHJldHVybiAoZGlyID4gMCkgPT0gcGFydC5sZXZlbCAlIDIgPyBwYXJ0LnRvIDogcGFydC5mcm9tO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHBhcnQgPSBiaWRpW3BvcyArPSBkaXJdO1xyXG4gICAgICAgIGlmICghcGFydCkgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgaWYgKChkaXIgPiAwKSA9PSBwYXJ0LmxldmVsICUgMilcclxuICAgICAgICAgIHRhcmdldCA9IG1vdmVJbkxpbmUobGluZSwgcGFydC50bywgLTEsIGJ5VW5pdCk7XHJcbiAgICAgICAgZWxzZVxyXG4gICAgICAgICAgdGFyZ2V0ID0gbW92ZUluTGluZShsaW5lLCBwYXJ0LmZyb20sIDEsIGJ5VW5pdCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIG1vdmVMb2dpY2FsbHkobGluZSwgc3RhcnQsIGRpciwgYnlVbml0KSB7XHJcbiAgICB2YXIgdGFyZ2V0ID0gc3RhcnQgKyBkaXI7XHJcbiAgICBpZiAoYnlVbml0KSB3aGlsZSAodGFyZ2V0ID4gMCAmJiBpc0V4dGVuZGluZ0NoYXIobGluZS50ZXh0LmNoYXJBdCh0YXJnZXQpKSkgdGFyZ2V0ICs9IGRpcjtcclxuICAgIHJldHVybiB0YXJnZXQgPCAwIHx8IHRhcmdldCA+IGxpbmUudGV4dC5sZW5ndGggPyBudWxsIDogdGFyZ2V0O1xyXG4gIH1cclxuXHJcbiAgLy8gQmlkaXJlY3Rpb25hbCBvcmRlcmluZyBhbGdvcml0aG1cclxuICAvLyBTZWUgaHR0cDovL3VuaWNvZGUub3JnL3JlcG9ydHMvdHI5L3RyOS0xMy5odG1sIGZvciB0aGUgYWxnb3JpdGhtXHJcbiAgLy8gdGhhdCB0aGlzIChwYXJ0aWFsbHkpIGltcGxlbWVudHMuXHJcblxyXG4gIC8vIE9uZS1jaGFyIGNvZGVzIHVzZWQgZm9yIGNoYXJhY3RlciB0eXBlczpcclxuICAvLyBMIChMKTogICBMZWZ0LXRvLVJpZ2h0XHJcbiAgLy8gUiAoUik6ICAgUmlnaHQtdG8tTGVmdFxyXG4gIC8vIHIgKEFMKTogIFJpZ2h0LXRvLUxlZnQgQXJhYmljXHJcbiAgLy8gMSAoRU4pOiAgRXVyb3BlYW4gTnVtYmVyXHJcbiAgLy8gKyAoRVMpOiAgRXVyb3BlYW4gTnVtYmVyIFNlcGFyYXRvclxyXG4gIC8vICUgKEVUKTogIEV1cm9wZWFuIE51bWJlciBUZXJtaW5hdG9yXHJcbiAgLy8gbiAoQU4pOiAgQXJhYmljIE51bWJlclxyXG4gIC8vICwgKENTKTogIENvbW1vbiBOdW1iZXIgU2VwYXJhdG9yXHJcbiAgLy8gbSAoTlNNKTogTm9uLVNwYWNpbmcgTWFya1xyXG4gIC8vIGIgKEJOKTogIEJvdW5kYXJ5IE5ldXRyYWxcclxuICAvLyBzIChCKTogICBQYXJhZ3JhcGggU2VwYXJhdG9yXHJcbiAgLy8gdCAoUyk6ICAgU2VnbWVudCBTZXBhcmF0b3JcclxuICAvLyB3IChXUyk6ICBXaGl0ZXNwYWNlXHJcbiAgLy8gTiAoT04pOiAgT3RoZXIgTmV1dHJhbHNcclxuXHJcbiAgLy8gUmV0dXJucyBudWxsIGlmIGNoYXJhY3RlcnMgYXJlIG9yZGVyZWQgYXMgdGhleSBhcHBlYXJcclxuICAvLyAobGVmdC10by1yaWdodCksIG9yIGFuIGFycmF5IG9mIHNlY3Rpb25zICh7ZnJvbSwgdG8sIGxldmVsfVxyXG4gIC8vIG9iamVjdHMpIGluIHRoZSBvcmRlciBpbiB3aGljaCB0aGV5IG9jY3VyIHZpc3VhbGx5LlxyXG4gIHZhciBiaWRpT3JkZXJpbmcgPSAoZnVuY3Rpb24oKSB7XHJcbiAgICAvLyBDaGFyYWN0ZXIgdHlwZXMgZm9yIGNvZGVwb2ludHMgMCB0byAweGZmXHJcbiAgICB2YXIgbG93VHlwZXMgPSBcImJiYmJiYmJiYnRzdHdzYmJiYmJiYmJiYmJiYmJzc3N0d05OJSUlTk5OTk5OLE4sTjExMTExMTExMTFOTk5OTk5OTExMTExMTExMTExMTExMTExMTExMTExMTExOTk5OTk5MTExMTExMTExMTExMTExMTExMTExMTExMTE5OTk5iYmJiYmJzYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmIsTiUlJSVOTk5OTE5OTk5OJSUxMU5MTk5OMUxOTk5OTkxMTExMTExMTExMTExMTExMTExMTExMTkxMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExOXCI7XHJcbiAgICAvLyBDaGFyYWN0ZXIgdHlwZXMgZm9yIGNvZGVwb2ludHMgMHg2MDAgdG8gMHg2ZmZcclxuICAgIHZhciBhcmFiaWNUeXBlcyA9IFwicnJycnJycnJycnJyLHJOTm1tbW1tbXJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJybW1tbW1tbW1tbW1tbW1ycnJycnJybm5ubm5ubm5ubiVubnJycm1ycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycm1tbW1tbW1tbW1tbW1tbW1tbW1ObW1tbVwiO1xyXG4gICAgZnVuY3Rpb24gY2hhclR5cGUoY29kZSkge1xyXG4gICAgICBpZiAoY29kZSA8PSAweGY3KSByZXR1cm4gbG93VHlwZXMuY2hhckF0KGNvZGUpO1xyXG4gICAgICBlbHNlIGlmICgweDU5MCA8PSBjb2RlICYmIGNvZGUgPD0gMHg1ZjQpIHJldHVybiBcIlJcIjtcclxuICAgICAgZWxzZSBpZiAoMHg2MDAgPD0gY29kZSAmJiBjb2RlIDw9IDB4NmVkKSByZXR1cm4gYXJhYmljVHlwZXMuY2hhckF0KGNvZGUgLSAweDYwMCk7XHJcbiAgICAgIGVsc2UgaWYgKDB4NmVlIDw9IGNvZGUgJiYgY29kZSA8PSAweDhhYykgcmV0dXJuIFwiclwiO1xyXG4gICAgICBlbHNlIGlmICgweDIwMDAgPD0gY29kZSAmJiBjb2RlIDw9IDB4MjAwYikgcmV0dXJuIFwid1wiO1xyXG4gICAgICBlbHNlIGlmIChjb2RlID09IDB4MjAwYykgcmV0dXJuIFwiYlwiO1xyXG4gICAgICBlbHNlIHJldHVybiBcIkxcIjtcclxuICAgIH1cclxuXHJcbiAgICB2YXIgYmlkaVJFID0gL1tcXHUwNTkwLVxcdTA1ZjRcXHUwNjAwLVxcdTA2ZmZcXHUwNzAwLVxcdTA4YWNdLztcclxuICAgIHZhciBpc05ldXRyYWwgPSAvW3N0d05dLywgaXNTdHJvbmcgPSAvW0xScl0vLCBjb3VudHNBc0xlZnQgPSAvW0xiMW5dLywgY291bnRzQXNOdW0gPSAvWzFuXS87XHJcbiAgICAvLyBCcm93c2VycyBzZWVtIHRvIGFsd2F5cyB0cmVhdCB0aGUgYm91bmRhcmllcyBvZiBibG9jayBlbGVtZW50cyBhcyBiZWluZyBMLlxyXG4gICAgdmFyIG91dGVyVHlwZSA9IFwiTFwiO1xyXG5cclxuICAgIGZ1bmN0aW9uIEJpZGlTcGFuKGxldmVsLCBmcm9tLCB0bykge1xyXG4gICAgICB0aGlzLmxldmVsID0gbGV2ZWw7XHJcbiAgICAgIHRoaXMuZnJvbSA9IGZyb207IHRoaXMudG8gPSB0bztcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gZnVuY3Rpb24oc3RyKSB7XHJcbiAgICAgIGlmICghYmlkaVJFLnRlc3Qoc3RyKSkgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB2YXIgbGVuID0gc3RyLmxlbmd0aCwgdHlwZXMgPSBbXTtcclxuICAgICAgZm9yICh2YXIgaSA9IDAsIHR5cGU7IGkgPCBsZW47ICsraSlcclxuICAgICAgICB0eXBlcy5wdXNoKHR5cGUgPSBjaGFyVHlwZShzdHIuY2hhckNvZGVBdChpKSkpO1xyXG5cclxuICAgICAgLy8gVzEuIEV4YW1pbmUgZWFjaCBub24tc3BhY2luZyBtYXJrIChOU00pIGluIHRoZSBsZXZlbCBydW4sIGFuZFxyXG4gICAgICAvLyBjaGFuZ2UgdGhlIHR5cGUgb2YgdGhlIE5TTSB0byB0aGUgdHlwZSBvZiB0aGUgcHJldmlvdXNcclxuICAgICAgLy8gY2hhcmFjdGVyLiBJZiB0aGUgTlNNIGlzIGF0IHRoZSBzdGFydCBvZiB0aGUgbGV2ZWwgcnVuLCBpdCB3aWxsXHJcbiAgICAgIC8vIGdldCB0aGUgdHlwZSBvZiBzb3IuXHJcbiAgICAgIGZvciAodmFyIGkgPSAwLCBwcmV2ID0gb3V0ZXJUeXBlOyBpIDwgbGVuOyArK2kpIHtcclxuICAgICAgICB2YXIgdHlwZSA9IHR5cGVzW2ldO1xyXG4gICAgICAgIGlmICh0eXBlID09IFwibVwiKSB0eXBlc1tpXSA9IHByZXY7XHJcbiAgICAgICAgZWxzZSBwcmV2ID0gdHlwZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVzIuIFNlYXJjaCBiYWNrd2FyZHMgZnJvbSBlYWNoIGluc3RhbmNlIG9mIGEgRXVyb3BlYW4gbnVtYmVyXHJcbiAgICAgIC8vIHVudGlsIHRoZSBmaXJzdCBzdHJvbmcgdHlwZSAoUiwgTCwgQUwsIG9yIHNvcikgaXMgZm91bmQuIElmIGFuXHJcbiAgICAgIC8vIEFMIGlzIGZvdW5kLCBjaGFuZ2UgdGhlIHR5cGUgb2YgdGhlIEV1cm9wZWFuIG51bWJlciB0byBBcmFiaWNcclxuICAgICAgLy8gbnVtYmVyLlxyXG4gICAgICAvLyBXMy4gQ2hhbmdlIGFsbCBBTHMgdG8gUi5cclxuICAgICAgZm9yICh2YXIgaSA9IDAsIGN1ciA9IG91dGVyVHlwZTsgaSA8IGxlbjsgKytpKSB7XHJcbiAgICAgICAgdmFyIHR5cGUgPSB0eXBlc1tpXTtcclxuICAgICAgICBpZiAodHlwZSA9PSBcIjFcIiAmJiBjdXIgPT0gXCJyXCIpIHR5cGVzW2ldID0gXCJuXCI7XHJcbiAgICAgICAgZWxzZSBpZiAoaXNTdHJvbmcudGVzdCh0eXBlKSkgeyBjdXIgPSB0eXBlOyBpZiAodHlwZSA9PSBcInJcIikgdHlwZXNbaV0gPSBcIlJcIjsgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBXNC4gQSBzaW5nbGUgRXVyb3BlYW4gc2VwYXJhdG9yIGJldHdlZW4gdHdvIEV1cm9wZWFuIG51bWJlcnNcclxuICAgICAgLy8gY2hhbmdlcyB0byBhIEV1cm9wZWFuIG51bWJlci4gQSBzaW5nbGUgY29tbW9uIHNlcGFyYXRvciBiZXR3ZWVuXHJcbiAgICAgIC8vIHR3byBudW1iZXJzIG9mIHRoZSBzYW1lIHR5cGUgY2hhbmdlcyB0byB0aGF0IHR5cGUuXHJcbiAgICAgIGZvciAodmFyIGkgPSAxLCBwcmV2ID0gdHlwZXNbMF07IGkgPCBsZW4gLSAxOyArK2kpIHtcclxuICAgICAgICB2YXIgdHlwZSA9IHR5cGVzW2ldO1xyXG4gICAgICAgIGlmICh0eXBlID09IFwiK1wiICYmIHByZXYgPT0gXCIxXCIgJiYgdHlwZXNbaSsxXSA9PSBcIjFcIikgdHlwZXNbaV0gPSBcIjFcIjtcclxuICAgICAgICBlbHNlIGlmICh0eXBlID09IFwiLFwiICYmIHByZXYgPT0gdHlwZXNbaSsxXSAmJlxyXG4gICAgICAgICAgICAgICAgIChwcmV2ID09IFwiMVwiIHx8IHByZXYgPT0gXCJuXCIpKSB0eXBlc1tpXSA9IHByZXY7XHJcbiAgICAgICAgcHJldiA9IHR5cGU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFc1LiBBIHNlcXVlbmNlIG9mIEV1cm9wZWFuIHRlcm1pbmF0b3JzIGFkamFjZW50IHRvIEV1cm9wZWFuXHJcbiAgICAgIC8vIG51bWJlcnMgY2hhbmdlcyB0byBhbGwgRXVyb3BlYW4gbnVtYmVycy5cclxuICAgICAgLy8gVzYuIE90aGVyd2lzZSwgc2VwYXJhdG9ycyBhbmQgdGVybWluYXRvcnMgY2hhbmdlIHRvIE90aGVyXHJcbiAgICAgIC8vIE5ldXRyYWwuXHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOyArK2kpIHtcclxuICAgICAgICB2YXIgdHlwZSA9IHR5cGVzW2ldO1xyXG4gICAgICAgIGlmICh0eXBlID09IFwiLFwiKSB0eXBlc1tpXSA9IFwiTlwiO1xyXG4gICAgICAgIGVsc2UgaWYgKHR5cGUgPT0gXCIlXCIpIHtcclxuICAgICAgICAgIGZvciAodmFyIGVuZCA9IGkgKyAxOyBlbmQgPCBsZW4gJiYgdHlwZXNbZW5kXSA9PSBcIiVcIjsgKytlbmQpIHt9XHJcbiAgICAgICAgICB2YXIgcmVwbGFjZSA9IChpICYmIHR5cGVzW2ktMV0gPT0gXCIhXCIpIHx8IChlbmQgPCBsZW4gJiYgdHlwZXNbZW5kXSA9PSBcIjFcIikgPyBcIjFcIiA6IFwiTlwiO1xyXG4gICAgICAgICAgZm9yICh2YXIgaiA9IGk7IGogPCBlbmQ7ICsraikgdHlwZXNbal0gPSByZXBsYWNlO1xyXG4gICAgICAgICAgaSA9IGVuZCAtIDE7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBXNy4gU2VhcmNoIGJhY2t3YXJkcyBmcm9tIGVhY2ggaW5zdGFuY2Ugb2YgYSBFdXJvcGVhbiBudW1iZXJcclxuICAgICAgLy8gdW50aWwgdGhlIGZpcnN0IHN0cm9uZyB0eXBlIChSLCBMLCBvciBzb3IpIGlzIGZvdW5kLiBJZiBhbiBMIGlzXHJcbiAgICAgIC8vIGZvdW5kLCB0aGVuIGNoYW5nZSB0aGUgdHlwZSBvZiB0aGUgRXVyb3BlYW4gbnVtYmVyIHRvIEwuXHJcbiAgICAgIGZvciAodmFyIGkgPSAwLCBjdXIgPSBvdXRlclR5cGU7IGkgPCBsZW47ICsraSkge1xyXG4gICAgICAgIHZhciB0eXBlID0gdHlwZXNbaV07XHJcbiAgICAgICAgaWYgKGN1ciA9PSBcIkxcIiAmJiB0eXBlID09IFwiMVwiKSB0eXBlc1tpXSA9IFwiTFwiO1xyXG4gICAgICAgIGVsc2UgaWYgKGlzU3Ryb25nLnRlc3QodHlwZSkpIGN1ciA9IHR5cGU7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIE4xLiBBIHNlcXVlbmNlIG9mIG5ldXRyYWxzIHRha2VzIHRoZSBkaXJlY3Rpb24gb2YgdGhlXHJcbiAgICAgIC8vIHN1cnJvdW5kaW5nIHN0cm9uZyB0ZXh0IGlmIHRoZSB0ZXh0IG9uIGJvdGggc2lkZXMgaGFzIHRoZSBzYW1lXHJcbiAgICAgIC8vIGRpcmVjdGlvbi4gRXVyb3BlYW4gYW5kIEFyYWJpYyBudW1iZXJzIGFjdCBhcyBpZiB0aGV5IHdlcmUgUiBpblxyXG4gICAgICAvLyB0ZXJtcyBvZiB0aGVpciBpbmZsdWVuY2Ugb24gbmV1dHJhbHMuIFN0YXJ0LW9mLWxldmVsLXJ1biAoc29yKVxyXG4gICAgICAvLyBhbmQgZW5kLW9mLWxldmVsLXJ1biAoZW9yKSBhcmUgdXNlZCBhdCBsZXZlbCBydW4gYm91bmRhcmllcy5cclxuICAgICAgLy8gTjIuIEFueSByZW1haW5pbmcgbmV1dHJhbHMgdGFrZSB0aGUgZW1iZWRkaW5nIGRpcmVjdGlvbi5cclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsZW47ICsraSkge1xyXG4gICAgICAgIGlmIChpc05ldXRyYWwudGVzdCh0eXBlc1tpXSkpIHtcclxuICAgICAgICAgIGZvciAodmFyIGVuZCA9IGkgKyAxOyBlbmQgPCBsZW4gJiYgaXNOZXV0cmFsLnRlc3QodHlwZXNbZW5kXSk7ICsrZW5kKSB7fVxyXG4gICAgICAgICAgdmFyIGJlZm9yZSA9IChpID8gdHlwZXNbaS0xXSA6IG91dGVyVHlwZSkgPT0gXCJMXCI7XHJcbiAgICAgICAgICB2YXIgYWZ0ZXIgPSAoZW5kIDwgbGVuID8gdHlwZXNbZW5kXSA6IG91dGVyVHlwZSkgPT0gXCJMXCI7XHJcbiAgICAgICAgICB2YXIgcmVwbGFjZSA9IGJlZm9yZSB8fCBhZnRlciA/IFwiTFwiIDogXCJSXCI7XHJcbiAgICAgICAgICBmb3IgKHZhciBqID0gaTsgaiA8IGVuZDsgKytqKSB0eXBlc1tqXSA9IHJlcGxhY2U7XHJcbiAgICAgICAgICBpID0gZW5kIC0gMTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEhlcmUgd2UgZGVwYXJ0IGZyb20gdGhlIGRvY3VtZW50ZWQgYWxnb3JpdGhtLCBpbiBvcmRlciB0byBhdm9pZFxyXG4gICAgICAvLyBidWlsZGluZyB1cCBhbiBhY3R1YWwgbGV2ZWxzIGFycmF5LiBTaW5jZSB0aGVyZSBhcmUgb25seSB0aHJlZVxyXG4gICAgICAvLyBsZXZlbHMgKDAsIDEsIDIpIGluIGFuIGltcGxlbWVudGF0aW9uIHRoYXQgZG9lc24ndCB0YWtlXHJcbiAgICAgIC8vIGV4cGxpY2l0IGVtYmVkZGluZyBpbnRvIGFjY291bnQsIHdlIGNhbiBidWlsZCB1cCB0aGUgb3JkZXIgb25cclxuICAgICAgLy8gdGhlIGZseSwgd2l0aG91dCBmb2xsb3dpbmcgdGhlIGxldmVsLWJhc2VkIGFsZ29yaXRobS5cclxuICAgICAgdmFyIG9yZGVyID0gW10sIG07XHJcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOykge1xyXG4gICAgICAgIGlmIChjb3VudHNBc0xlZnQudGVzdCh0eXBlc1tpXSkpIHtcclxuICAgICAgICAgIHZhciBzdGFydCA9IGk7XHJcbiAgICAgICAgICBmb3IgKCsraTsgaSA8IGxlbiAmJiBjb3VudHNBc0xlZnQudGVzdCh0eXBlc1tpXSk7ICsraSkge31cclxuICAgICAgICAgIG9yZGVyLnB1c2gobmV3IEJpZGlTcGFuKDAsIHN0YXJ0LCBpKSk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHZhciBwb3MgPSBpLCBhdCA9IG9yZGVyLmxlbmd0aDtcclxuICAgICAgICAgIGZvciAoKytpOyBpIDwgbGVuICYmIHR5cGVzW2ldICE9IFwiTFwiOyArK2kpIHt9XHJcbiAgICAgICAgICBmb3IgKHZhciBqID0gcG9zOyBqIDwgaTspIHtcclxuICAgICAgICAgICAgaWYgKGNvdW50c0FzTnVtLnRlc3QodHlwZXNbal0pKSB7XHJcbiAgICAgICAgICAgICAgaWYgKHBvcyA8IGopIG9yZGVyLnNwbGljZShhdCwgMCwgbmV3IEJpZGlTcGFuKDEsIHBvcywgaikpO1xyXG4gICAgICAgICAgICAgIHZhciBuc3RhcnQgPSBqO1xyXG4gICAgICAgICAgICAgIGZvciAoKytqOyBqIDwgaSAmJiBjb3VudHNBc051bS50ZXN0KHR5cGVzW2pdKTsgKytqKSB7fVxyXG4gICAgICAgICAgICAgIG9yZGVyLnNwbGljZShhdCwgMCwgbmV3IEJpZGlTcGFuKDIsIG5zdGFydCwgaikpO1xyXG4gICAgICAgICAgICAgIHBvcyA9IGo7XHJcbiAgICAgICAgICAgIH0gZWxzZSArK2o7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICBpZiAocG9zIDwgaSkgb3JkZXIuc3BsaWNlKGF0LCAwLCBuZXcgQmlkaVNwYW4oMSwgcG9zLCBpKSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGlmIChvcmRlclswXS5sZXZlbCA9PSAxICYmIChtID0gc3RyLm1hdGNoKC9eXFxzKy8pKSkge1xyXG4gICAgICAgIG9yZGVyWzBdLmZyb20gPSBtWzBdLmxlbmd0aDtcclxuICAgICAgICBvcmRlci51bnNoaWZ0KG5ldyBCaWRpU3BhbigwLCAwLCBtWzBdLmxlbmd0aCkpO1xyXG4gICAgICB9XHJcbiAgICAgIGlmIChsc3Qob3JkZXIpLmxldmVsID09IDEgJiYgKG0gPSBzdHIubWF0Y2goL1xccyskLykpKSB7XHJcbiAgICAgICAgbHN0KG9yZGVyKS50byAtPSBtWzBdLmxlbmd0aDtcclxuICAgICAgICBvcmRlci5wdXNoKG5ldyBCaWRpU3BhbigwLCBsZW4gLSBtWzBdLmxlbmd0aCwgbGVuKSk7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKG9yZGVyWzBdLmxldmVsID09IDIpXHJcbiAgICAgICAgb3JkZXIudW5zaGlmdChuZXcgQmlkaVNwYW4oMSwgb3JkZXJbMF0udG8sIG9yZGVyWzBdLnRvKSk7XHJcbiAgICAgIGlmIChvcmRlclswXS5sZXZlbCAhPSBsc3Qob3JkZXIpLmxldmVsKVxyXG4gICAgICAgIG9yZGVyLnB1c2gobmV3IEJpZGlTcGFuKG9yZGVyWzBdLmxldmVsLCBsZW4sIGxlbikpO1xyXG5cclxuICAgICAgcmV0dXJuIG9yZGVyO1xyXG4gICAgfTtcclxuICB9KSgpO1xyXG5cclxuICAvLyBUSEUgRU5EXHJcblxyXG4gIENvZGVNaXJyb3IudmVyc2lvbiA9IFwiNS45LjFcIjtcclxuXHJcbiAgcmV0dXJuIENvZGVNaXJyb3I7XHJcbn0pO1xyXG4iLCIvLyBDb2RlTWlycm9yLCBjb3B5cmlnaHQgKGMpIGJ5IE1hcmlqbiBIYXZlcmJla2UgYW5kIG90aGVyc1xyXG4vLyBEaXN0cmlidXRlZCB1bmRlciBhbiBNSVQgbGljZW5zZTogaHR0cDovL2NvZGVtaXJyb3IubmV0L0xJQ0VOU0VcclxuXHJcbihmdW5jdGlvbihtb2QpIHtcclxuICBpZiAodHlwZW9mIGV4cG9ydHMgPT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgbW9kdWxlID09IFwib2JqZWN0XCIpIC8vIENvbW1vbkpTXHJcbiAgICBtb2QocmVxdWlyZShcIi4uLy4uL2xpYi9jb2RlbWlycm9yXCIpLCByZXF1aXJlKFwiLi4vbWFya2Rvd24vbWFya2Rvd25cIiksIHJlcXVpcmUoXCIuLi8uLi9hZGRvbi9tb2RlL292ZXJsYXlcIikpO1xyXG4gIGVsc2UgaWYgKHR5cGVvZiBkZWZpbmUgPT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQpIC8vIEFNRFxyXG4gICAgZGVmaW5lKFtcIi4uLy4uL2xpYi9jb2RlbWlycm9yXCIsIFwiLi4vbWFya2Rvd24vbWFya2Rvd25cIiwgXCIuLi8uLi9hZGRvbi9tb2RlL292ZXJsYXlcIl0sIG1vZCk7XHJcbiAgZWxzZSAvLyBQbGFpbiBicm93c2VyIGVudlxyXG4gICAgbW9kKENvZGVNaXJyb3IpO1xyXG59KShmdW5jdGlvbihDb2RlTWlycm9yKSB7XHJcblwidXNlIHN0cmljdFwiO1xyXG5cclxudmFyIHVybFJFID0gL14oKD86KD86YWFhcz98YWJvdXR8YWNhcHxhZGl1bXh0cmF8YWZbcHNdfGFpbXxhcHR8YXR0YWNobWVudHxhd3xiZXNoYXJlfGJpdGNvaW58Ym9sb3xjYWxsdG98Y2FwfGNocm9tZSg/Oi1leHRlbnNpb24pP3xjaWR8Y29hcHxjb20tZXZlbnRicml0ZS1hdHRlbmRlZXxjb250ZW50fGNyaWR8Y3ZzfGRhdGF8ZGF2fGRpY3R8ZGxuYS0oPzpwbGF5Y29udGFpbmVyfHBsYXlzaW5nbGUpfGRuc3xkb2l8ZHRufGR2YnxlZDJrfGZhY2V0aW1lfGZlZWR8ZmlsZXxmaW5nZXJ8ZmlzaHxmdHB8Z2VvfGdnfGdpdHxnaXptb3Byb2plY3R8Z298Z29waGVyfGd0YWxrfGgzMjN8aGNwfGh0dHBzP3xpYXh8aWNhcHxpY29ufGltfGltYXB8aW5mb3xpcG58aXBwfGlyY1s2c10/fGlyaXMoPzpcXC5iZWVwfFxcLmx3enxcXC54cGN8XFwueHBjcyk/fGl0bXN8amFyfGphdmFzY3JpcHR8am1zfGtleXBhcmN8bGFzdGZtfGxkYXBzP3xtYWduZXR8bWFpbHRvfG1hcHN8bWFya2V0fG1lc3NhZ2V8bWlkfG1tc3xtcy1oZWxwfG1zbmltfG1zcnBzP3xtdHFwfG11bWJsZXxtdXBkYXRlfG12bnxuZXdzfG5mc3xuaWg/fG5udHB8bm90ZXN8b2lkfG9wYXF1ZWxvY2t0b2tlbnxwYWxtfHBhcGFyYXp6aXxwbGF0Zm9ybXxwb3B8cHJlc3xwcm94eXxwc3ljfHF1ZXJ5fHJlcyg/Om91cmNlKT98cm1pfHJzeW5jfHJ0bXB8cnRzcHxzZWNvbmRsaWZlfHNlcnZpY2V8c2Vzc2lvbnxzZnRwfHNnbnxzaHR0cHxzaWV2ZXxzaXBzP3xza3lwZXxzbVtic118c25tcHxzb2FwXFwuYmVlcHM/fHNvbGRhdHxzcG90aWZ5fHNzaHxzdGVhbXxzdm58dGFnfHRlYW1zcGVha3x0ZWwoPzpuZXQpP3x0ZnRwfHRoaW5nc3x0aGlzbWVzc2FnZXx0aXB8dG4zMjcwfHR2fHVkcHx1bnJlYWx8dXJufHV0MjAwNHx2ZW1taXx2ZW50cmlsb3x2aWV3LXNvdXJjZXx3ZWJjYWx8d3NzP3x3dGFpfHd5Y2l3eWd8eGNvbig/Oi11c2VyaWQpP3x4ZmlyZXx4bWxycGNcXC5iZWVwcz98eG1wcHx4cml8eW1zZ3J8ejM5XFwuNTBbcnNdPyk6KD86XFwvezEsM318W2EtejAtOSVdKXx3d3dcXGR7MCwzfVsuXXxbYS16MC05LlxcLV0rWy5dW2Etel17Miw0fVxcLykoPzpbXlxccygpPD5dfFxcKFteXFxzKCk8Pl0qXFwpKSsoPzpcXChbXlxccygpPD5dKlxcKXxbXlxcc2AqISgpXFxbXFxde307OidcIi4sPD4/wqvCu+KAnOKAneKAmOKAmV0pKS9pXHJcblxyXG5Db2RlTWlycm9yLmRlZmluZU1vZGUoXCJnZm1cIiwgZnVuY3Rpb24oY29uZmlnLCBtb2RlQ29uZmlnKSB7XHJcbiAgdmFyIGNvZGVEZXB0aCA9IDA7XHJcbiAgZnVuY3Rpb24gYmxhbmtMaW5lKHN0YXRlKSB7XHJcbiAgICBzdGF0ZS5jb2RlID0gZmFsc2U7XHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcbiAgdmFyIGdmbU92ZXJsYXkgPSB7XHJcbiAgICBzdGFydFN0YXRlOiBmdW5jdGlvbigpIHtcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBjb2RlOiBmYWxzZSxcclxuICAgICAgICBjb2RlQmxvY2s6IGZhbHNlLFxyXG4gICAgICAgIGF0ZVNwYWNlOiBmYWxzZVxyXG4gICAgICB9O1xyXG4gICAgfSxcclxuICAgIGNvcHlTdGF0ZTogZnVuY3Rpb24ocykge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIGNvZGU6IHMuY29kZSxcclxuICAgICAgICBjb2RlQmxvY2s6IHMuY29kZUJsb2NrLFxyXG4gICAgICAgIGF0ZVNwYWNlOiBzLmF0ZVNwYWNlXHJcbiAgICAgIH07XHJcbiAgICB9LFxyXG4gICAgdG9rZW46IGZ1bmN0aW9uKHN0cmVhbSwgc3RhdGUpIHtcclxuICAgICAgc3RhdGUuY29tYmluZVRva2VucyA9IG51bGw7XHJcblxyXG4gICAgICAvLyBIYWNrIHRvIHByZXZlbnQgZm9ybWF0dGluZyBvdmVycmlkZSBpbnNpZGUgY29kZSBibG9ja3MgKGJsb2NrIGFuZCBpbmxpbmUpXHJcbiAgICAgIGlmIChzdGF0ZS5jb2RlQmxvY2spIHtcclxuICAgICAgICBpZiAoc3RyZWFtLm1hdGNoKC9eYGBgKy8pKSB7XHJcbiAgICAgICAgICBzdGF0ZS5jb2RlQmxvY2sgPSBmYWxzZTtcclxuICAgICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgICAgIH1cclxuICAgICAgICBzdHJlYW0uc2tpcFRvRW5kKCk7XHJcbiAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKHN0cmVhbS5zb2woKSkge1xyXG4gICAgICAgIHN0YXRlLmNvZGUgPSBmYWxzZTtcclxuICAgICAgfVxyXG4gICAgICBpZiAoc3RyZWFtLnNvbCgpICYmIHN0cmVhbS5tYXRjaCgvXmBgYCsvKSkge1xyXG4gICAgICAgIHN0cmVhbS5za2lwVG9FbmQoKTtcclxuICAgICAgICBzdGF0ZS5jb2RlQmxvY2sgPSB0cnVlO1xyXG4gICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgICB9XHJcbiAgICAgIC8vIElmIHRoaXMgYmxvY2sgaXMgY2hhbmdlZCwgaXQgbWF5IG5lZWQgdG8gYmUgdXBkYXRlZCBpbiBNYXJrZG93biBtb2RlXHJcbiAgICAgIGlmIChzdHJlYW0ucGVlaygpID09PSAnYCcpIHtcclxuICAgICAgICBzdHJlYW0ubmV4dCgpO1xyXG4gICAgICAgIHZhciBiZWZvcmUgPSBzdHJlYW0ucG9zO1xyXG4gICAgICAgIHN0cmVhbS5lYXRXaGlsZSgnYCcpO1xyXG4gICAgICAgIHZhciBkaWZmZXJlbmNlID0gMSArIHN0cmVhbS5wb3MgLSBiZWZvcmU7XHJcbiAgICAgICAgaWYgKCFzdGF0ZS5jb2RlKSB7XHJcbiAgICAgICAgICBjb2RlRGVwdGggPSBkaWZmZXJlbmNlO1xyXG4gICAgICAgICAgc3RhdGUuY29kZSA9IHRydWU7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGlmIChkaWZmZXJlbmNlID09PSBjb2RlRGVwdGgpIHsgLy8gTXVzdCBiZSBleGFjdFxyXG4gICAgICAgICAgICBzdGF0ZS5jb2RlID0gZmFsc2U7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgICB9IGVsc2UgaWYgKHN0YXRlLmNvZGUpIHtcclxuICAgICAgICBzdHJlYW0ubmV4dCgpO1xyXG4gICAgICAgIHJldHVybiBudWxsO1xyXG4gICAgICB9XHJcbiAgICAgIC8vIENoZWNrIGlmIHNwYWNlLiBJZiBzbywgbGlua3MgY2FuIGJlIGZvcm1hdHRlZCBsYXRlciBvblxyXG4gICAgICBpZiAoc3RyZWFtLmVhdFNwYWNlKCkpIHtcclxuICAgICAgICBzdGF0ZS5hdGVTcGFjZSA9IHRydWU7XHJcbiAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKHN0cmVhbS5zb2woKSB8fCBzdGF0ZS5hdGVTcGFjZSkge1xyXG4gICAgICAgIHN0YXRlLmF0ZVNwYWNlID0gZmFsc2U7XHJcbiAgICAgICAgaWYgKG1vZGVDb25maWcuZ2l0SHViU3BpY2UgIT09IGZhbHNlKSB7XHJcbiAgICAgICAgICBpZihzdHJlYW0ubWF0Y2goL14oPzpbYS16QS1aMC05XFwtX10rXFwvKT8oPzpbYS16QS1aMC05XFwtX10rQCk/KD86W2EtZjAtOV17Nyw0MH1cXGIpLykpIHtcclxuICAgICAgICAgICAgLy8gVXNlci9Qcm9qZWN0QFNIQVxyXG4gICAgICAgICAgICAvLyBVc2VyQFNIQVxyXG4gICAgICAgICAgICAvLyBTSEFcclxuICAgICAgICAgICAgc3RhdGUuY29tYmluZVRva2VucyA9IHRydWU7XHJcbiAgICAgICAgICAgIHJldHVybiBcImxpbmtcIjtcclxuICAgICAgICAgIH0gZWxzZSBpZiAoc3RyZWFtLm1hdGNoKC9eKD86W2EtekEtWjAtOVxcLV9dK1xcLyk/KD86W2EtekEtWjAtOVxcLV9dKyk/I1swLTldK1xcYi8pKSB7XHJcbiAgICAgICAgICAgIC8vIFVzZXIvUHJvamVjdCNOdW1cclxuICAgICAgICAgICAgLy8gVXNlciNOdW1cclxuICAgICAgICAgICAgLy8gI051bVxyXG4gICAgICAgICAgICBzdGF0ZS5jb21iaW5lVG9rZW5zID0gdHJ1ZTtcclxuICAgICAgICAgICAgcmV0dXJuIFwibGlua1wiO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpZiAoc3RyZWFtLm1hdGNoKHVybFJFKSAmJlxyXG4gICAgICAgICAgc3RyZWFtLnN0cmluZy5zbGljZShzdHJlYW0uc3RhcnQgLSAyLCBzdHJlYW0uc3RhcnQpICE9IFwiXShcIiAmJlxyXG4gICAgICAgICAgKHN0cmVhbS5zdGFydCA9PSAwIHx8IC9cXFcvLnRlc3Qoc3RyZWFtLnN0cmluZy5jaGFyQXQoc3RyZWFtLnN0YXJ0IC0gMSkpKSkge1xyXG4gICAgICAgIC8vIFVSTHNcclxuICAgICAgICAvLyBUYWtlbiBmcm9tIGh0dHA6Ly9kYXJpbmdmaXJlYmFsbC5uZXQvMjAxMC8wNy9pbXByb3ZlZF9yZWdleF9mb3JfbWF0Y2hpbmdfdXJsc1xyXG4gICAgICAgIC8vIEFuZCB0aGVuIChpc3N1ZSAjMTE2MCkgc2ltcGxpZmllZCB0byBtYWtlIGl0IG5vdCBjcmFzaCB0aGUgQ2hyb21lIFJlZ2V4cCBlbmdpbmVcclxuICAgICAgICAvLyBBbmQgdGhlbiBsaW1pdGVkIHVybCBzY2hlbWVzIHRvIHRoZSBDb21tb25NYXJrIGxpc3QsIHNvIGZvbzpiYXIgaXNuJ3QgbWF0Y2hlZCBhcyBhIFVSTFxyXG4gICAgICAgIHN0YXRlLmNvbWJpbmVUb2tlbnMgPSB0cnVlO1xyXG4gICAgICAgIHJldHVybiBcImxpbmtcIjtcclxuICAgICAgfVxyXG4gICAgICBzdHJlYW0ubmV4dCgpO1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH0sXHJcbiAgICBibGFua0xpbmU6IGJsYW5rTGluZVxyXG4gIH07XHJcblxyXG4gIHZhciBtYXJrZG93bkNvbmZpZyA9IHtcclxuICAgIHVuZGVyc2NvcmVzQnJlYWtXb3JkczogZmFsc2UsXHJcbiAgICB0YXNrTGlzdHM6IHRydWUsXHJcbiAgICBmZW5jZWRDb2RlQmxvY2tzOiAnYGBgJyxcclxuICAgIHN0cmlrZXRocm91Z2g6IHRydWVcclxuICB9O1xyXG4gIGZvciAodmFyIGF0dHIgaW4gbW9kZUNvbmZpZykge1xyXG4gICAgbWFya2Rvd25Db25maWdbYXR0cl0gPSBtb2RlQ29uZmlnW2F0dHJdO1xyXG4gIH1cclxuICBtYXJrZG93bkNvbmZpZy5uYW1lID0gXCJtYXJrZG93blwiO1xyXG4gIHJldHVybiBDb2RlTWlycm9yLm92ZXJsYXlNb2RlKENvZGVNaXJyb3IuZ2V0TW9kZShjb25maWcsIG1hcmtkb3duQ29uZmlnKSwgZ2ZtT3ZlcmxheSk7XHJcblxyXG59LCBcIm1hcmtkb3duXCIpO1xyXG5cclxuICBDb2RlTWlycm9yLmRlZmluZU1JTUUoXCJ0ZXh0L3gtZ2ZtXCIsIFwiZ2ZtXCIpO1xyXG59KTtcclxuIiwiLy8gQ29kZU1pcnJvciwgY29weXJpZ2h0IChjKSBieSBNYXJpam4gSGF2ZXJiZWtlIGFuZCBvdGhlcnNcclxuLy8gRGlzdHJpYnV0ZWQgdW5kZXIgYW4gTUlUIGxpY2Vuc2U6IGh0dHA6Ly9jb2RlbWlycm9yLm5ldC9MSUNFTlNFXHJcblxyXG4oZnVuY3Rpb24obW9kKSB7XHJcbiAgaWYgKHR5cGVvZiBleHBvcnRzID09IFwib2JqZWN0XCIgJiYgdHlwZW9mIG1vZHVsZSA9PSBcIm9iamVjdFwiKSAvLyBDb21tb25KU1xyXG4gICAgbW9kKHJlcXVpcmUoXCIuLi8uLi9saWIvY29kZW1pcnJvclwiKSwgcmVxdWlyZShcIi4uL3htbC94bWxcIiksIHJlcXVpcmUoXCIuLi9tZXRhXCIpKTtcclxuICBlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kKSAvLyBBTURcclxuICAgIGRlZmluZShbXCIuLi8uLi9saWIvY29kZW1pcnJvclwiLCBcIi4uL3htbC94bWxcIiwgXCIuLi9tZXRhXCJdLCBtb2QpO1xyXG4gIGVsc2UgLy8gUGxhaW4gYnJvd3NlciBlbnZcclxuICAgIG1vZChDb2RlTWlycm9yKTtcclxufSkoZnVuY3Rpb24oQ29kZU1pcnJvcikge1xyXG5cInVzZSBzdHJpY3RcIjtcclxuXHJcbkNvZGVNaXJyb3IuZGVmaW5lTW9kZShcIm1hcmtkb3duXCIsIGZ1bmN0aW9uKGNtQ2ZnLCBtb2RlQ2ZnKSB7XHJcblxyXG4gIHZhciBodG1sRm91bmQgPSBDb2RlTWlycm9yLm1vZGVzLmhhc093blByb3BlcnR5KFwieG1sXCIpO1xyXG4gIHZhciBodG1sTW9kZSA9IENvZGVNaXJyb3IuZ2V0TW9kZShjbUNmZywgaHRtbEZvdW5kID8ge25hbWU6IFwieG1sXCIsIGh0bWxNb2RlOiB0cnVlfSA6IFwidGV4dC9wbGFpblwiKTtcclxuXHJcbiAgZnVuY3Rpb24gZ2V0TW9kZShuYW1lKSB7XHJcbiAgICBpZiAoQ29kZU1pcnJvci5maW5kTW9kZUJ5TmFtZSkge1xyXG4gICAgICB2YXIgZm91bmQgPSBDb2RlTWlycm9yLmZpbmRNb2RlQnlOYW1lKG5hbWUpO1xyXG4gICAgICBpZiAoZm91bmQpIG5hbWUgPSBmb3VuZC5taW1lIHx8IGZvdW5kLm1pbWVzWzBdO1xyXG4gICAgfVxyXG4gICAgdmFyIG1vZGUgPSBDb2RlTWlycm9yLmdldE1vZGUoY21DZmcsIG5hbWUpO1xyXG4gICAgcmV0dXJuIG1vZGUubmFtZSA9PSBcIm51bGxcIiA/IG51bGwgOiBtb2RlO1xyXG4gIH1cclxuXHJcbiAgLy8gU2hvdWxkIGNoYXJhY3RlcnMgdGhhdCBhZmZlY3QgaGlnaGxpZ2h0aW5nIGJlIGhpZ2hsaWdodGVkIHNlcGFyYXRlP1xyXG4gIC8vIERvZXMgbm90IGluY2x1ZGUgY2hhcmFjdGVycyB0aGF0IHdpbGwgYmUgb3V0cHV0IChzdWNoIGFzIGAxLmAgYW5kIGAtYCBmb3IgbGlzdHMpXHJcbiAgaWYgKG1vZGVDZmcuaGlnaGxpZ2h0Rm9ybWF0dGluZyA9PT0gdW5kZWZpbmVkKVxyXG4gICAgbW9kZUNmZy5oaWdobGlnaHRGb3JtYXR0aW5nID0gZmFsc2U7XHJcblxyXG4gIC8vIE1heGltdW0gbnVtYmVyIG9mIG5lc3RlZCBibG9ja3F1b3Rlcy4gU2V0IHRvIDAgZm9yIGluZmluaXRlIG5lc3RpbmcuXHJcbiAgLy8gRXhjZXNzIGA+YCB3aWxsIGVtaXQgYGVycm9yYCB0b2tlbi5cclxuICBpZiAobW9kZUNmZy5tYXhCbG9ja3F1b3RlRGVwdGggPT09IHVuZGVmaW5lZClcclxuICAgIG1vZGVDZmcubWF4QmxvY2txdW90ZURlcHRoID0gMDtcclxuXHJcbiAgLy8gU2hvdWxkIHVuZGVyc2NvcmVzIGluIHdvcmRzIG9wZW4vY2xvc2UgZW0vc3Ryb25nP1xyXG4gIGlmIChtb2RlQ2ZnLnVuZGVyc2NvcmVzQnJlYWtXb3JkcyA9PT0gdW5kZWZpbmVkKVxyXG4gICAgbW9kZUNmZy51bmRlcnNjb3Jlc0JyZWFrV29yZHMgPSB0cnVlO1xyXG5cclxuICAvLyBVc2UgYGZlbmNlZENvZGVCbG9ja3NgIHRvIGNvbmZpZ3VyZSBmZW5jZWQgY29kZSBibG9ja3MuIGZhbHNlIHRvXHJcbiAgLy8gZGlzYWJsZSwgc3RyaW5nIHRvIHNwZWNpZnkgYSBwcmVjaXNlIHJlZ2V4cCB0aGF0IHRoZSBmZW5jZSBzaG91bGRcclxuICAvLyBtYXRjaCwgYW5kIHRydWUgdG8gYWxsb3cgdGhyZWUgb3IgbW9yZSBiYWNrdGlja3Mgb3IgdGlsZGVzIChhc1xyXG4gIC8vIHBlciBDb21tb25NYXJrKS5cclxuXHJcbiAgLy8gVHVybiBvbiB0YXNrIGxpc3RzPyAoXCItIFsgXSBcIiBhbmQgXCItIFt4XSBcIilcclxuICBpZiAobW9kZUNmZy50YXNrTGlzdHMgPT09IHVuZGVmaW5lZCkgbW9kZUNmZy50YXNrTGlzdHMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHVybiBvbiBzdHJpa2V0aHJvdWdoIHN5bnRheFxyXG4gIGlmIChtb2RlQ2ZnLnN0cmlrZXRocm91Z2ggPT09IHVuZGVmaW5lZClcclxuICAgIG1vZGVDZmcuc3RyaWtldGhyb3VnaCA9IGZhbHNlO1xyXG5cclxuICAvLyBBbGxvdyB0b2tlbiB0eXBlcyB0byBiZSBvdmVycmlkZGVuIGJ5IHVzZXItcHJvdmlkZWQgdG9rZW4gdHlwZXMuXHJcbiAgaWYgKG1vZGVDZmcudG9rZW5UeXBlT3ZlcnJpZGVzID09PSB1bmRlZmluZWQpXHJcbiAgICBtb2RlQ2ZnLnRva2VuVHlwZU92ZXJyaWRlcyA9IHt9O1xyXG5cclxuICB2YXIgY29kZURlcHRoID0gMDtcclxuXHJcbiAgdmFyIHRva2VuVHlwZXMgPSB7XHJcbiAgICBoZWFkZXI6IFwiaGVhZGVyXCIsXHJcbiAgICBjb2RlOiBcImNvbW1lbnRcIixcclxuICAgIHF1b3RlOiBcInF1b3RlXCIsXHJcbiAgICBsaXN0MTogXCJ2YXJpYWJsZS0yXCIsXHJcbiAgICBsaXN0MjogXCJ2YXJpYWJsZS0zXCIsXHJcbiAgICBsaXN0MzogXCJrZXl3b3JkXCIsXHJcbiAgICBocjogXCJoclwiLFxyXG4gICAgaW1hZ2U6IFwidGFnXCIsXHJcbiAgICBmb3JtYXR0aW5nOiBcImZvcm1hdHRpbmdcIixcclxuICAgIGxpbmtJbmxpbmU6IFwibGlua1wiLFxyXG4gICAgbGlua0VtYWlsOiBcImxpbmtcIixcclxuICAgIGxpbmtUZXh0OiBcImxpbmtcIixcclxuICAgIGxpbmtIcmVmOiBcInN0cmluZ1wiLFxyXG4gICAgZW06IFwiZW1cIixcclxuICAgIHN0cm9uZzogXCJzdHJvbmdcIixcclxuICAgIHN0cmlrZXRocm91Z2g6IFwic3RyaWtldGhyb3VnaFwiXHJcbiAgfTtcclxuXHJcbiAgZm9yICh2YXIgdG9rZW5UeXBlIGluIHRva2VuVHlwZXMpIHtcclxuICAgIGlmICh0b2tlblR5cGVzLmhhc093blByb3BlcnR5KHRva2VuVHlwZSkgJiYgbW9kZUNmZy50b2tlblR5cGVPdmVycmlkZXNbdG9rZW5UeXBlXSkge1xyXG4gICAgICB0b2tlblR5cGVzW3Rva2VuVHlwZV0gPSBtb2RlQ2ZnLnRva2VuVHlwZU92ZXJyaWRlc1t0b2tlblR5cGVdO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgdmFyIGhyUkUgPSAvXihbKlxcLV9dKSg/OlxccypcXDEpezIsfVxccyokL1xyXG4gICwgICB1bFJFID0gL15bKlxcLStdXFxzKy9cclxuICAsICAgb2xSRSA9IC9eWzAtOV0rKFsuKV0pXFxzKy9cclxuICAsICAgdGFza0xpc3RSRSA9IC9eXFxbKHh8IClcXF0oPz1cXHMpLyAvLyBNdXN0IGZvbGxvdyB1bFJFIG9yIG9sUkVcclxuICAsICAgYXR4SGVhZGVyUkUgPSBtb2RlQ2ZnLmFsbG93QXR4SGVhZGVyV2l0aG91dFNwYWNlID8gL14oIyspLyA6IC9eKCMrKSg/OiB8JCkvXHJcbiAgLCAgIHNldGV4dEhlYWRlclJFID0gL14gKig/OlxcPXsxLH18LXsxLH0pXFxzKiQvXHJcbiAgLCAgIHRleHRSRSA9IC9eW14jIVxcW1xcXSpfXFxcXDw+YCBcIicofl0rL1xyXG4gICwgICBmZW5jZWRDb2RlUkUgPSBuZXcgUmVnRXhwKFwiXihcIiArIChtb2RlQ2ZnLmZlbmNlZENvZGVCbG9ja3MgPT09IHRydWUgPyBcIn5+fit8YGBgK1wiIDogbW9kZUNmZy5mZW5jZWRDb2RlQmxvY2tzKSArXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCIpWyBcXFxcdF0qKFtcXFxcdysjXSopXCIpO1xyXG5cclxuICBmdW5jdGlvbiBzd2l0Y2hJbmxpbmUoc3RyZWFtLCBzdGF0ZSwgZikge1xyXG4gICAgc3RhdGUuZiA9IHN0YXRlLmlubGluZSA9IGY7XHJcbiAgICByZXR1cm4gZihzdHJlYW0sIHN0YXRlKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIHN3aXRjaEJsb2NrKHN0cmVhbSwgc3RhdGUsIGYpIHtcclxuICAgIHN0YXRlLmYgPSBzdGF0ZS5ibG9jayA9IGY7XHJcbiAgICByZXR1cm4gZihzdHJlYW0sIHN0YXRlKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGxpbmVJc0VtcHR5KGxpbmUpIHtcclxuICAgIHJldHVybiAhbGluZSB8fCAhL1xcUy8udGVzdChsaW5lLnN0cmluZylcclxuICB9XHJcblxyXG4gIC8vIEJsb2Nrc1xyXG5cclxuICBmdW5jdGlvbiBibGFua0xpbmUoc3RhdGUpIHtcclxuICAgIC8vIFJlc2V0IGxpbmtUaXRsZSBzdGF0ZVxyXG4gICAgc3RhdGUubGlua1RpdGxlID0gZmFsc2U7XHJcbiAgICAvLyBSZXNldCBFTSBzdGF0ZVxyXG4gICAgc3RhdGUuZW0gPSBmYWxzZTtcclxuICAgIC8vIFJlc2V0IFNUUk9ORyBzdGF0ZVxyXG4gICAgc3RhdGUuc3Ryb25nID0gZmFsc2U7XHJcbiAgICAvLyBSZXNldCBzdHJpa2V0aHJvdWdoIHN0YXRlXHJcbiAgICBzdGF0ZS5zdHJpa2V0aHJvdWdoID0gZmFsc2U7XHJcbiAgICAvLyBSZXNldCBzdGF0ZS5xdW90ZVxyXG4gICAgc3RhdGUucXVvdGUgPSAwO1xyXG4gICAgLy8gUmVzZXQgc3RhdGUuaW5kZW50ZWRDb2RlXHJcbiAgICBzdGF0ZS5pbmRlbnRlZENvZGUgPSBmYWxzZTtcclxuICAgIGlmICghaHRtbEZvdW5kICYmIHN0YXRlLmYgPT0gaHRtbEJsb2NrKSB7XHJcbiAgICAgIHN0YXRlLmYgPSBpbmxpbmVOb3JtYWw7XHJcbiAgICAgIHN0YXRlLmJsb2NrID0gYmxvY2tOb3JtYWw7XHJcbiAgICB9XHJcbiAgICAvLyBSZXNldCBzdGF0ZS50cmFpbGluZ1NwYWNlXHJcbiAgICBzdGF0ZS50cmFpbGluZ1NwYWNlID0gMDtcclxuICAgIHN0YXRlLnRyYWlsaW5nU3BhY2VOZXdMaW5lID0gZmFsc2U7XHJcbiAgICAvLyBNYXJrIHRoaXMgbGluZSBhcyBibGFua1xyXG4gICAgc3RhdGUucHJldkxpbmUgPSBzdGF0ZS50aGlzTGluZVxyXG4gICAgc3RhdGUudGhpc0xpbmUgPSBudWxsXHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGJsb2NrTm9ybWFsKHN0cmVhbSwgc3RhdGUpIHtcclxuXHJcbiAgICB2YXIgc29sID0gc3RyZWFtLnNvbCgpO1xyXG5cclxuICAgIHZhciBwcmV2TGluZUlzTGlzdCA9IHN0YXRlLmxpc3QgIT09IGZhbHNlLFxyXG4gICAgICAgIHByZXZMaW5lSXNJbmRlbnRlZENvZGUgPSBzdGF0ZS5pbmRlbnRlZENvZGU7XHJcblxyXG4gICAgc3RhdGUuaW5kZW50ZWRDb2RlID0gZmFsc2U7XHJcblxyXG4gICAgaWYgKHByZXZMaW5lSXNMaXN0KSB7XHJcbiAgICAgIGlmIChzdGF0ZS5pbmRlbnRhdGlvbkRpZmYgPj0gMCkgeyAvLyBDb250aW51ZWQgbGlzdFxyXG4gICAgICAgIGlmIChzdGF0ZS5pbmRlbnRhdGlvbkRpZmYgPCA0KSB7IC8vIE9ubHkgYWRqdXN0IGluZGVudGF0aW9uIGlmICpub3QqIGEgY29kZSBibG9ja1xyXG4gICAgICAgICAgc3RhdGUuaW5kZW50YXRpb24gLT0gc3RhdGUuaW5kZW50YXRpb25EaWZmO1xyXG4gICAgICAgIH1cclxuICAgICAgICBzdGF0ZS5saXN0ID0gbnVsbDtcclxuICAgICAgfSBlbHNlIGlmIChzdGF0ZS5pbmRlbnRhdGlvbiA+IDApIHtcclxuICAgICAgICBzdGF0ZS5saXN0ID0gbnVsbDtcclxuICAgICAgICBzdGF0ZS5saXN0RGVwdGggPSBNYXRoLmZsb29yKHN0YXRlLmluZGVudGF0aW9uIC8gNCk7XHJcbiAgICAgIH0gZWxzZSB7IC8vIE5vIGxvbmdlciBhIGxpc3RcclxuICAgICAgICBzdGF0ZS5saXN0ID0gZmFsc2U7XHJcbiAgICAgICAgc3RhdGUubGlzdERlcHRoID0gMDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHZhciBtYXRjaCA9IG51bGw7XHJcbiAgICBpZiAoc3RhdGUuaW5kZW50YXRpb25EaWZmID49IDQpIHtcclxuICAgICAgc3RyZWFtLnNraXBUb0VuZCgpO1xyXG4gICAgICBpZiAocHJldkxpbmVJc0luZGVudGVkQ29kZSB8fCBsaW5lSXNFbXB0eShzdGF0ZS5wcmV2TGluZSkpIHtcclxuICAgICAgICBzdGF0ZS5pbmRlbnRhdGlvbiAtPSA0O1xyXG4gICAgICAgIHN0YXRlLmluZGVudGVkQ29kZSA9IHRydWU7XHJcbiAgICAgICAgcmV0dXJuIHRva2VuVHlwZXMuY29kZTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICByZXR1cm4gbnVsbDtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIGlmIChzdHJlYW0uZWF0U3BhY2UoKSkge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH0gZWxzZSBpZiAoKG1hdGNoID0gc3RyZWFtLm1hdGNoKGF0eEhlYWRlclJFKSkgJiYgbWF0Y2hbMV0ubGVuZ3RoIDw9IDYpIHtcclxuICAgICAgc3RhdGUuaGVhZGVyID0gbWF0Y2hbMV0ubGVuZ3RoO1xyXG4gICAgICBpZiAobW9kZUNmZy5oaWdobGlnaHRGb3JtYXR0aW5nKSBzdGF0ZS5mb3JtYXR0aW5nID0gXCJoZWFkZXJcIjtcclxuICAgICAgc3RhdGUuZiA9IHN0YXRlLmlubGluZTtcclxuICAgICAgcmV0dXJuIGdldFR5cGUoc3RhdGUpO1xyXG4gICAgfSBlbHNlIGlmICghbGluZUlzRW1wdHkoc3RhdGUucHJldkxpbmUpICYmICFzdGF0ZS5xdW90ZSAmJiAhcHJldkxpbmVJc0xpc3QgJiZcclxuICAgICAgICAgICAgICAgIXByZXZMaW5lSXNJbmRlbnRlZENvZGUgJiYgKG1hdGNoID0gc3RyZWFtLm1hdGNoKHNldGV4dEhlYWRlclJFKSkpIHtcclxuICAgICAgc3RhdGUuaGVhZGVyID0gbWF0Y2hbMF0uY2hhckF0KDApID09ICc9JyA/IDEgOiAyO1xyXG4gICAgICBpZiAobW9kZUNmZy5oaWdobGlnaHRGb3JtYXR0aW5nKSBzdGF0ZS5mb3JtYXR0aW5nID0gXCJoZWFkZXJcIjtcclxuICAgICAgc3RhdGUuZiA9IHN0YXRlLmlubGluZTtcclxuICAgICAgcmV0dXJuIGdldFR5cGUoc3RhdGUpO1xyXG4gICAgfSBlbHNlIGlmIChzdHJlYW0uZWF0KCc+JykpIHtcclxuICAgICAgc3RhdGUucXVvdGUgPSBzb2wgPyAxIDogc3RhdGUucXVvdGUgKyAxO1xyXG4gICAgICBpZiAobW9kZUNmZy5oaWdobGlnaHRGb3JtYXR0aW5nKSBzdGF0ZS5mb3JtYXR0aW5nID0gXCJxdW90ZVwiO1xyXG4gICAgICBzdHJlYW0uZWF0U3BhY2UoKTtcclxuICAgICAgcmV0dXJuIGdldFR5cGUoc3RhdGUpO1xyXG4gICAgfSBlbHNlIGlmIChzdHJlYW0ucGVlaygpID09PSAnWycpIHtcclxuICAgICAgcmV0dXJuIHN3aXRjaElubGluZShzdHJlYW0sIHN0YXRlLCBmb290bm90ZUxpbmspO1xyXG4gICAgfSBlbHNlIGlmIChzdHJlYW0ubWF0Y2goaHJSRSwgdHJ1ZSkpIHtcclxuICAgICAgc3RhdGUuaHIgPSB0cnVlO1xyXG4gICAgICByZXR1cm4gdG9rZW5UeXBlcy5ocjtcclxuICAgIH0gZWxzZSBpZiAoKGxpbmVJc0VtcHR5KHN0YXRlLnByZXZMaW5lKSB8fCBwcmV2TGluZUlzTGlzdCkgJiYgKHN0cmVhbS5tYXRjaCh1bFJFLCBmYWxzZSkgfHwgc3RyZWFtLm1hdGNoKG9sUkUsIGZhbHNlKSkpIHtcclxuICAgICAgdmFyIGxpc3RUeXBlID0gbnVsbDtcclxuICAgICAgaWYgKHN0cmVhbS5tYXRjaCh1bFJFLCB0cnVlKSkge1xyXG4gICAgICAgIGxpc3RUeXBlID0gJ3VsJztcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzdHJlYW0ubWF0Y2gob2xSRSwgdHJ1ZSk7XHJcbiAgICAgICAgbGlzdFR5cGUgPSAnb2wnO1xyXG4gICAgICB9XHJcbiAgICAgIHN0YXRlLmluZGVudGF0aW9uID0gc3RyZWFtLmNvbHVtbigpICsgc3RyZWFtLmN1cnJlbnQoKS5sZW5ndGg7XHJcbiAgICAgIHN0YXRlLmxpc3QgPSB0cnVlO1xyXG4gICAgICBzdGF0ZS5saXN0RGVwdGgrKztcclxuICAgICAgaWYgKG1vZGVDZmcudGFza0xpc3RzICYmIHN0cmVhbS5tYXRjaCh0YXNrTGlzdFJFLCBmYWxzZSkpIHtcclxuICAgICAgICBzdGF0ZS50YXNrTGlzdCA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgICAgc3RhdGUuZiA9IHN0YXRlLmlubGluZTtcclxuICAgICAgaWYgKG1vZGVDZmcuaGlnaGxpZ2h0Rm9ybWF0dGluZykgc3RhdGUuZm9ybWF0dGluZyA9IFtcImxpc3RcIiwgXCJsaXN0LVwiICsgbGlzdFR5cGVdO1xyXG4gICAgICByZXR1cm4gZ2V0VHlwZShzdGF0ZSk7XHJcbiAgICB9IGVsc2UgaWYgKG1vZGVDZmcuZmVuY2VkQ29kZUJsb2NrcyAmJiAobWF0Y2ggPSBzdHJlYW0ubWF0Y2goZmVuY2VkQ29kZVJFLCB0cnVlKSkpIHtcclxuICAgICAgc3RhdGUuZmVuY2VkQ2hhcnMgPSBtYXRjaFsxXVxyXG4gICAgICAvLyB0cnkgc3dpdGNoaW5nIG1vZGVcclxuICAgICAgc3RhdGUubG9jYWxNb2RlID0gZ2V0TW9kZShtYXRjaFsyXSk7XHJcbiAgICAgIGlmIChzdGF0ZS5sb2NhbE1vZGUpIHN0YXRlLmxvY2FsU3RhdGUgPSBzdGF0ZS5sb2NhbE1vZGUuc3RhcnRTdGF0ZSgpO1xyXG4gICAgICBzdGF0ZS5mID0gc3RhdGUuYmxvY2sgPSBsb2NhbDtcclxuICAgICAgaWYgKG1vZGVDZmcuaGlnaGxpZ2h0Rm9ybWF0dGluZykgc3RhdGUuZm9ybWF0dGluZyA9IFwiY29kZS1ibG9ja1wiO1xyXG4gICAgICBzdGF0ZS5jb2RlID0gdHJ1ZTtcclxuICAgICAgcmV0dXJuIGdldFR5cGUoc3RhdGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBzd2l0Y2hJbmxpbmUoc3RyZWFtLCBzdGF0ZSwgc3RhdGUuaW5saW5lKTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGh0bWxCbG9jayhzdHJlYW0sIHN0YXRlKSB7XHJcbiAgICB2YXIgc3R5bGUgPSBodG1sTW9kZS50b2tlbihzdHJlYW0sIHN0YXRlLmh0bWxTdGF0ZSk7XHJcbiAgICBpZiAoKGh0bWxGb3VuZCAmJiBzdGF0ZS5odG1sU3RhdGUudGFnU3RhcnQgPT09IG51bGwgJiZcclxuICAgICAgICAgKCFzdGF0ZS5odG1sU3RhdGUuY29udGV4dCAmJiBzdGF0ZS5odG1sU3RhdGUudG9rZW5pemUuaXNJblRleHQpKSB8fFxyXG4gICAgICAgIChzdGF0ZS5tZF9pbnNpZGUgJiYgc3RyZWFtLmN1cnJlbnQoKS5pbmRleE9mKFwiPlwiKSA+IC0xKSkge1xyXG4gICAgICBzdGF0ZS5mID0gaW5saW5lTm9ybWFsO1xyXG4gICAgICBzdGF0ZS5ibG9jayA9IGJsb2NrTm9ybWFsO1xyXG4gICAgICBzdGF0ZS5odG1sU3RhdGUgPSBudWxsO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHN0eWxlO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gbG9jYWwoc3RyZWFtLCBzdGF0ZSkge1xyXG4gICAgaWYgKHN0cmVhbS5zb2woKSAmJiBzdGF0ZS5mZW5jZWRDaGFycyAmJiBzdHJlYW0ubWF0Y2goc3RhdGUuZmVuY2VkQ2hhcnMsIGZhbHNlKSkge1xyXG4gICAgICBzdGF0ZS5sb2NhbE1vZGUgPSBzdGF0ZS5sb2NhbFN0YXRlID0gbnVsbDtcclxuICAgICAgc3RhdGUuZiA9IHN0YXRlLmJsb2NrID0gbGVhdmluZ0xvY2FsO1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH0gZWxzZSBpZiAoc3RhdGUubG9jYWxNb2RlKSB7XHJcbiAgICAgIHJldHVybiBzdGF0ZS5sb2NhbE1vZGUudG9rZW4oc3RyZWFtLCBzdGF0ZS5sb2NhbFN0YXRlKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHN0cmVhbS5za2lwVG9FbmQoKTtcclxuICAgICAgcmV0dXJuIHRva2VuVHlwZXMuY29kZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGxlYXZpbmdMb2NhbChzdHJlYW0sIHN0YXRlKSB7XHJcbiAgICBzdHJlYW0ubWF0Y2goc3RhdGUuZmVuY2VkQ2hhcnMpO1xyXG4gICAgc3RhdGUuYmxvY2sgPSBibG9ja05vcm1hbDtcclxuICAgIHN0YXRlLmYgPSBpbmxpbmVOb3JtYWw7XHJcbiAgICBzdGF0ZS5mZW5jZWRDaGFycyA9IG51bGw7XHJcbiAgICBpZiAobW9kZUNmZy5oaWdobGlnaHRGb3JtYXR0aW5nKSBzdGF0ZS5mb3JtYXR0aW5nID0gXCJjb2RlLWJsb2NrXCI7XHJcbiAgICBzdGF0ZS5jb2RlID0gdHJ1ZTtcclxuICAgIHZhciByZXR1cm5UeXBlID0gZ2V0VHlwZShzdGF0ZSk7XHJcbiAgICBzdGF0ZS5jb2RlID0gZmFsc2U7XHJcbiAgICByZXR1cm4gcmV0dXJuVHlwZTtcclxuICB9XHJcblxyXG4gIC8vIElubGluZVxyXG4gIGZ1bmN0aW9uIGdldFR5cGUoc3RhdGUpIHtcclxuICAgIHZhciBzdHlsZXMgPSBbXTtcclxuXHJcbiAgICBpZiAoc3RhdGUuZm9ybWF0dGluZykge1xyXG4gICAgICBzdHlsZXMucHVzaCh0b2tlblR5cGVzLmZvcm1hdHRpbmcpO1xyXG5cclxuICAgICAgaWYgKHR5cGVvZiBzdGF0ZS5mb3JtYXR0aW5nID09PSBcInN0cmluZ1wiKSBzdGF0ZS5mb3JtYXR0aW5nID0gW3N0YXRlLmZvcm1hdHRpbmddO1xyXG5cclxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdGF0ZS5mb3JtYXR0aW5nLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgc3R5bGVzLnB1c2godG9rZW5UeXBlcy5mb3JtYXR0aW5nICsgXCItXCIgKyBzdGF0ZS5mb3JtYXR0aW5nW2ldKTtcclxuXHJcbiAgICAgICAgaWYgKHN0YXRlLmZvcm1hdHRpbmdbaV0gPT09IFwiaGVhZGVyXCIpIHtcclxuICAgICAgICAgIHN0eWxlcy5wdXNoKHRva2VuVHlwZXMuZm9ybWF0dGluZyArIFwiLVwiICsgc3RhdGUuZm9ybWF0dGluZ1tpXSArIFwiLVwiICsgc3RhdGUuaGVhZGVyKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEFkZCBgZm9ybWF0dGluZy1xdW90ZWAgYW5kIGBmb3JtYXR0aW5nLXF1b3RlLSNgIGZvciBibG9ja3F1b3Rlc1xyXG4gICAgICAgIC8vIEFkZCBgZXJyb3JgIGluc3RlYWQgaWYgdGhlIG1heGltdW0gYmxvY2txdW90ZSBuZXN0aW5nIGRlcHRoIGlzIHBhc3NlZFxyXG4gICAgICAgIGlmIChzdGF0ZS5mb3JtYXR0aW5nW2ldID09PSBcInF1b3RlXCIpIHtcclxuICAgICAgICAgIGlmICghbW9kZUNmZy5tYXhCbG9ja3F1b3RlRGVwdGggfHwgbW9kZUNmZy5tYXhCbG9ja3F1b3RlRGVwdGggPj0gc3RhdGUucXVvdGUpIHtcclxuICAgICAgICAgICAgc3R5bGVzLnB1c2godG9rZW5UeXBlcy5mb3JtYXR0aW5nICsgXCItXCIgKyBzdGF0ZS5mb3JtYXR0aW5nW2ldICsgXCItXCIgKyBzdGF0ZS5xdW90ZSk7XHJcbiAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICBzdHlsZXMucHVzaChcImVycm9yXCIpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChzdGF0ZS50YXNrT3Blbikge1xyXG4gICAgICBzdHlsZXMucHVzaChcIm1ldGFcIik7XHJcbiAgICAgIHJldHVybiBzdHlsZXMubGVuZ3RoID8gc3R5bGVzLmpvaW4oJyAnKSA6IG51bGw7XHJcbiAgICB9XHJcbiAgICBpZiAoc3RhdGUudGFza0Nsb3NlZCkge1xyXG4gICAgICBzdHlsZXMucHVzaChcInByb3BlcnR5XCIpO1xyXG4gICAgICByZXR1cm4gc3R5bGVzLmxlbmd0aCA/IHN0eWxlcy5qb2luKCcgJykgOiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChzdGF0ZS5saW5rSHJlZikge1xyXG4gICAgICBzdHlsZXMucHVzaCh0b2tlblR5cGVzLmxpbmtIcmVmLCBcInVybFwiKTtcclxuICAgIH0gZWxzZSB7IC8vIE9ubHkgYXBwbHkgaW5saW5lIHN0eWxlcyB0byBub24tdXJsIHRleHRcclxuICAgICAgaWYgKHN0YXRlLnN0cm9uZykgeyBzdHlsZXMucHVzaCh0b2tlblR5cGVzLnN0cm9uZyk7IH1cclxuICAgICAgaWYgKHN0YXRlLmVtKSB7IHN0eWxlcy5wdXNoKHRva2VuVHlwZXMuZW0pOyB9XHJcbiAgICAgIGlmIChzdGF0ZS5zdHJpa2V0aHJvdWdoKSB7IHN0eWxlcy5wdXNoKHRva2VuVHlwZXMuc3RyaWtldGhyb3VnaCk7IH1cclxuICAgICAgaWYgKHN0YXRlLmxpbmtUZXh0KSB7IHN0eWxlcy5wdXNoKHRva2VuVHlwZXMubGlua1RleHQpOyB9XHJcbiAgICAgIGlmIChzdGF0ZS5jb2RlKSB7IHN0eWxlcy5wdXNoKHRva2VuVHlwZXMuY29kZSk7IH1cclxuICAgIH1cclxuXHJcbiAgICBpZiAoc3RhdGUuaGVhZGVyKSB7IHN0eWxlcy5wdXNoKHRva2VuVHlwZXMuaGVhZGVyLCB0b2tlblR5cGVzLmhlYWRlciArIFwiLVwiICsgc3RhdGUuaGVhZGVyKTsgfVxyXG5cclxuICAgIGlmIChzdGF0ZS5xdW90ZSkge1xyXG4gICAgICBzdHlsZXMucHVzaCh0b2tlblR5cGVzLnF1b3RlKTtcclxuXHJcbiAgICAgIC8vIEFkZCBgcXVvdGUtI2Agd2hlcmUgdGhlIG1heGltdW0gZm9yIGAjYCBpcyBtb2RlQ2ZnLm1heEJsb2NrcXVvdGVEZXB0aFxyXG4gICAgICBpZiAoIW1vZGVDZmcubWF4QmxvY2txdW90ZURlcHRoIHx8IG1vZGVDZmcubWF4QmxvY2txdW90ZURlcHRoID49IHN0YXRlLnF1b3RlKSB7XHJcbiAgICAgICAgc3R5bGVzLnB1c2godG9rZW5UeXBlcy5xdW90ZSArIFwiLVwiICsgc3RhdGUucXVvdGUpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHN0eWxlcy5wdXNoKHRva2VuVHlwZXMucXVvdGUgKyBcIi1cIiArIG1vZGVDZmcubWF4QmxvY2txdW90ZURlcHRoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChzdGF0ZS5saXN0ICE9PSBmYWxzZSkge1xyXG4gICAgICB2YXIgbGlzdE1vZCA9IChzdGF0ZS5saXN0RGVwdGggLSAxKSAlIDM7XHJcbiAgICAgIGlmICghbGlzdE1vZCkge1xyXG4gICAgICAgIHN0eWxlcy5wdXNoKHRva2VuVHlwZXMubGlzdDEpO1xyXG4gICAgICB9IGVsc2UgaWYgKGxpc3RNb2QgPT09IDEpIHtcclxuICAgICAgICBzdHlsZXMucHVzaCh0b2tlblR5cGVzLmxpc3QyKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBzdHlsZXMucHVzaCh0b2tlblR5cGVzLmxpc3QzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChzdGF0ZS50cmFpbGluZ1NwYWNlTmV3TGluZSkge1xyXG4gICAgICBzdHlsZXMucHVzaChcInRyYWlsaW5nLXNwYWNlLW5ldy1saW5lXCIpO1xyXG4gICAgfSBlbHNlIGlmIChzdGF0ZS50cmFpbGluZ1NwYWNlKSB7XHJcbiAgICAgIHN0eWxlcy5wdXNoKFwidHJhaWxpbmctc3BhY2UtXCIgKyAoc3RhdGUudHJhaWxpbmdTcGFjZSAlIDIgPyBcImFcIiA6IFwiYlwiKSk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHN0eWxlcy5sZW5ndGggPyBzdHlsZXMuam9pbignICcpIDogbnVsbDtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGhhbmRsZVRleHQoc3RyZWFtLCBzdGF0ZSkge1xyXG4gICAgaWYgKHN0cmVhbS5tYXRjaCh0ZXh0UkUsIHRydWUpKSB7XHJcbiAgICAgIHJldHVybiBnZXRUeXBlKHN0YXRlKTtcclxuICAgIH1cclxuICAgIHJldHVybiB1bmRlZmluZWQ7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBpbmxpbmVOb3JtYWwoc3RyZWFtLCBzdGF0ZSkge1xyXG4gICAgdmFyIHN0eWxlID0gc3RhdGUudGV4dChzdHJlYW0sIHN0YXRlKTtcclxuICAgIGlmICh0eXBlb2Ygc3R5bGUgIT09ICd1bmRlZmluZWQnKVxyXG4gICAgICByZXR1cm4gc3R5bGU7XHJcblxyXG4gICAgaWYgKHN0YXRlLmxpc3QpIHsgLy8gTGlzdCBtYXJrZXIgKCosICssIC0sIDEuLCBldGMpXHJcbiAgICAgIHN0YXRlLmxpc3QgPSBudWxsO1xyXG4gICAgICByZXR1cm4gZ2V0VHlwZShzdGF0ZSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHN0YXRlLnRhc2tMaXN0KSB7XHJcbiAgICAgIHZhciB0YXNrT3BlbiA9IHN0cmVhbS5tYXRjaCh0YXNrTGlzdFJFLCB0cnVlKVsxXSAhPT0gXCJ4XCI7XHJcbiAgICAgIGlmICh0YXNrT3Blbikgc3RhdGUudGFza09wZW4gPSB0cnVlO1xyXG4gICAgICBlbHNlIHN0YXRlLnRhc2tDbG9zZWQgPSB0cnVlO1xyXG4gICAgICBpZiAobW9kZUNmZy5oaWdobGlnaHRGb3JtYXR0aW5nKSBzdGF0ZS5mb3JtYXR0aW5nID0gXCJ0YXNrXCI7XHJcbiAgICAgIHN0YXRlLnRhc2tMaXN0ID0gZmFsc2U7XHJcbiAgICAgIHJldHVybiBnZXRUeXBlKHN0YXRlKTtcclxuICAgIH1cclxuXHJcbiAgICBzdGF0ZS50YXNrT3BlbiA9IGZhbHNlO1xyXG4gICAgc3RhdGUudGFza0Nsb3NlZCA9IGZhbHNlO1xyXG5cclxuICAgIGlmIChzdGF0ZS5oZWFkZXIgJiYgc3RyZWFtLm1hdGNoKC9eIyskLywgdHJ1ZSkpIHtcclxuICAgICAgaWYgKG1vZGVDZmcuaGlnaGxpZ2h0Rm9ybWF0dGluZykgc3RhdGUuZm9ybWF0dGluZyA9IFwiaGVhZGVyXCI7XHJcbiAgICAgIHJldHVybiBnZXRUeXBlKHN0YXRlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgc29sKCkgdmFsdWUgbm93LCBiZWZvcmUgY2hhcmFjdGVyIGlzIGNvbnN1bWVkXHJcbiAgICB2YXIgc29sID0gc3RyZWFtLnNvbCgpO1xyXG5cclxuICAgIHZhciBjaCA9IHN0cmVhbS5uZXh0KCk7XHJcblxyXG4gICAgaWYgKGNoID09PSAnXFxcXCcpIHtcclxuICAgICAgc3RyZWFtLm5leHQoKTtcclxuICAgICAgaWYgKG1vZGVDZmcuaGlnaGxpZ2h0Rm9ybWF0dGluZykge1xyXG4gICAgICAgIHZhciB0eXBlID0gZ2V0VHlwZShzdGF0ZSk7XHJcbiAgICAgICAgdmFyIGZvcm1hdHRpbmdFc2NhcGUgPSB0b2tlblR5cGVzLmZvcm1hdHRpbmcgKyBcIi1lc2NhcGVcIjtcclxuICAgICAgICByZXR1cm4gdHlwZSA/IHR5cGUgKyBcIiBcIiArIGZvcm1hdHRpbmdFc2NhcGUgOiBmb3JtYXR0aW5nRXNjYXBlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTWF0Y2hlcyBsaW5rIHRpdGxlcyBwcmVzZW50IG9uIG5leHQgbGluZVxyXG4gICAgaWYgKHN0YXRlLmxpbmtUaXRsZSkge1xyXG4gICAgICBzdGF0ZS5saW5rVGl0bGUgPSBmYWxzZTtcclxuICAgICAgdmFyIG1hdGNoQ2ggPSBjaDtcclxuICAgICAgaWYgKGNoID09PSAnKCcpIHtcclxuICAgICAgICBtYXRjaENoID0gJyknO1xyXG4gICAgICB9XHJcbiAgICAgIG1hdGNoQ2ggPSAobWF0Y2hDaCsnJykucmVwbGFjZSgvKFsuPyorXiRbXFxdXFxcXCgpe318LV0pL2csIFwiXFxcXCQxXCIpO1xyXG4gICAgICB2YXIgcmVnZXggPSAnXlxcXFxzKig/OlteJyArIG1hdGNoQ2ggKyAnXFxcXFxcXFxdK3xcXFxcXFxcXFxcXFxcXFxcfFxcXFxcXFxcLiknICsgbWF0Y2hDaDtcclxuICAgICAgaWYgKHN0cmVhbS5tYXRjaChuZXcgUmVnRXhwKHJlZ2V4KSwgdHJ1ZSkpIHtcclxuICAgICAgICByZXR1cm4gdG9rZW5UeXBlcy5saW5rSHJlZjtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIElmIHRoaXMgYmxvY2sgaXMgY2hhbmdlZCwgaXQgbWF5IG5lZWQgdG8gYmUgdXBkYXRlZCBpbiBHRk0gbW9kZVxyXG4gICAgaWYgKGNoID09PSAnYCcpIHtcclxuICAgICAgdmFyIHByZXZpb3VzRm9ybWF0dGluZyA9IHN0YXRlLmZvcm1hdHRpbmc7XHJcbiAgICAgIGlmIChtb2RlQ2ZnLmhpZ2hsaWdodEZvcm1hdHRpbmcpIHN0YXRlLmZvcm1hdHRpbmcgPSBcImNvZGVcIjtcclxuICAgICAgdmFyIHQgPSBnZXRUeXBlKHN0YXRlKTtcclxuICAgICAgdmFyIGJlZm9yZSA9IHN0cmVhbS5wb3M7XHJcbiAgICAgIHN0cmVhbS5lYXRXaGlsZSgnYCcpO1xyXG4gICAgICB2YXIgZGlmZmVyZW5jZSA9IDEgKyBzdHJlYW0ucG9zIC0gYmVmb3JlO1xyXG4gICAgICBpZiAoIXN0YXRlLmNvZGUpIHtcclxuICAgICAgICBjb2RlRGVwdGggPSBkaWZmZXJlbmNlO1xyXG4gICAgICAgIHN0YXRlLmNvZGUgPSB0cnVlO1xyXG4gICAgICAgIHJldHVybiBnZXRUeXBlKHN0YXRlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBpZiAoZGlmZmVyZW5jZSA9PT0gY29kZURlcHRoKSB7IC8vIE11c3QgYmUgZXhhY3RcclxuICAgICAgICAgIHN0YXRlLmNvZGUgPSBmYWxzZTtcclxuICAgICAgICAgIHJldHVybiB0O1xyXG4gICAgICAgIH1cclxuICAgICAgICBzdGF0ZS5mb3JtYXR0aW5nID0gcHJldmlvdXNGb3JtYXR0aW5nO1xyXG4gICAgICAgIHJldHVybiBnZXRUeXBlKHN0YXRlKTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIGlmIChzdGF0ZS5jb2RlKSB7XHJcbiAgICAgIHJldHVybiBnZXRUeXBlKHN0YXRlKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoY2ggPT09ICchJyAmJiBzdHJlYW0ubWF0Y2goL1xcW1teXFxdXSpcXF0gPyg/OlxcKHxcXFspLywgZmFsc2UpKSB7XHJcbiAgICAgIHN0cmVhbS5tYXRjaCgvXFxbW15cXF1dKlxcXS8pO1xyXG4gICAgICBzdGF0ZS5pbmxpbmUgPSBzdGF0ZS5mID0gbGlua0hyZWY7XHJcbiAgICAgIHJldHVybiB0b2tlblR5cGVzLmltYWdlO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChjaCA9PT0gJ1snICYmIHN0cmVhbS5tYXRjaCgvLipcXF0oXFwoLipcXCl8ID9cXFsuKlxcXSkvLCBmYWxzZSkpIHtcclxuICAgICAgc3RhdGUubGlua1RleHQgPSB0cnVlO1xyXG4gICAgICBpZiAobW9kZUNmZy5oaWdobGlnaHRGb3JtYXR0aW5nKSBzdGF0ZS5mb3JtYXR0aW5nID0gXCJsaW5rXCI7XHJcbiAgICAgIHJldHVybiBnZXRUeXBlKHN0YXRlKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoY2ggPT09ICddJyAmJiBzdGF0ZS5saW5rVGV4dCAmJiBzdHJlYW0ubWF0Y2goL1xcKC4qXFwpfCA/XFxbLipcXF0vLCBmYWxzZSkpIHtcclxuICAgICAgaWYgKG1vZGVDZmcuaGlnaGxpZ2h0Rm9ybWF0dGluZykgc3RhdGUuZm9ybWF0dGluZyA9IFwibGlua1wiO1xyXG4gICAgICB2YXIgdHlwZSA9IGdldFR5cGUoc3RhdGUpO1xyXG4gICAgICBzdGF0ZS5saW5rVGV4dCA9IGZhbHNlO1xyXG4gICAgICBzdGF0ZS5pbmxpbmUgPSBzdGF0ZS5mID0gbGlua0hyZWY7XHJcbiAgICAgIHJldHVybiB0eXBlO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChjaCA9PT0gJzwnICYmIHN0cmVhbS5tYXRjaCgvXihodHRwcz98ZnRwcz8pOlxcL1xcLyg/OlteXFxcXD5dfFxcXFwuKSs+LywgZmFsc2UpKSB7XHJcbiAgICAgIHN0YXRlLmYgPSBzdGF0ZS5pbmxpbmUgPSBsaW5rSW5saW5lO1xyXG4gICAgICBpZiAobW9kZUNmZy5oaWdobGlnaHRGb3JtYXR0aW5nKSBzdGF0ZS5mb3JtYXR0aW5nID0gXCJsaW5rXCI7XHJcbiAgICAgIHZhciB0eXBlID0gZ2V0VHlwZShzdGF0ZSk7XHJcbiAgICAgIGlmICh0eXBlKXtcclxuICAgICAgICB0eXBlICs9IFwiIFwiO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHR5cGUgPSBcIlwiO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiB0eXBlICsgdG9rZW5UeXBlcy5saW5rSW5saW5lO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChjaCA9PT0gJzwnICYmIHN0cmVhbS5tYXRjaCgvXltePiBcXFxcXStAKD86W15cXFxcPl18XFxcXC4pKz4vLCBmYWxzZSkpIHtcclxuICAgICAgc3RhdGUuZiA9IHN0YXRlLmlubGluZSA9IGxpbmtJbmxpbmU7XHJcbiAgICAgIGlmIChtb2RlQ2ZnLmhpZ2hsaWdodEZvcm1hdHRpbmcpIHN0YXRlLmZvcm1hdHRpbmcgPSBcImxpbmtcIjtcclxuICAgICAgdmFyIHR5cGUgPSBnZXRUeXBlKHN0YXRlKTtcclxuICAgICAgaWYgKHR5cGUpe1xyXG4gICAgICAgIHR5cGUgKz0gXCIgXCI7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdHlwZSA9IFwiXCI7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHR5cGUgKyB0b2tlblR5cGVzLmxpbmtFbWFpbDtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoY2ggPT09ICc8JyAmJiBzdHJlYW0ubWF0Y2goL14oIS0tfFxcdykvLCBmYWxzZSkpIHtcclxuICAgICAgdmFyIGVuZCA9IHN0cmVhbS5zdHJpbmcuaW5kZXhPZihcIj5cIiwgc3RyZWFtLnBvcyk7XHJcbiAgICAgIGlmIChlbmQgIT0gLTEpIHtcclxuICAgICAgICB2YXIgYXR0cyA9IHN0cmVhbS5zdHJpbmcuc3Vic3RyaW5nKHN0cmVhbS5zdGFydCwgZW5kKTtcclxuICAgICAgICBpZiAoL21hcmtkb3duXFxzKj1cXHMqKCd8XCIpezAsMX0xKCd8XCIpezAsMX0vLnRlc3QoYXR0cykpIHN0YXRlLm1kX2luc2lkZSA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgICAgc3RyZWFtLmJhY2tVcCgxKTtcclxuICAgICAgc3RhdGUuaHRtbFN0YXRlID0gQ29kZU1pcnJvci5zdGFydFN0YXRlKGh0bWxNb2RlKTtcclxuICAgICAgcmV0dXJuIHN3aXRjaEJsb2NrKHN0cmVhbSwgc3RhdGUsIGh0bWxCbG9jayk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGNoID09PSAnPCcgJiYgc3RyZWFtLm1hdGNoKC9eXFwvXFx3Kj8+LykpIHtcclxuICAgICAgc3RhdGUubWRfaW5zaWRlID0gZmFsc2U7XHJcbiAgICAgIHJldHVybiBcInRhZ1wiO1xyXG4gICAgfVxyXG5cclxuICAgIHZhciBpZ25vcmVVbmRlcnNjb3JlID0gZmFsc2U7XHJcbiAgICBpZiAoIW1vZGVDZmcudW5kZXJzY29yZXNCcmVha1dvcmRzKSB7XHJcbiAgICAgIGlmIChjaCA9PT0gJ18nICYmIHN0cmVhbS5wZWVrKCkgIT09ICdfJyAmJiBzdHJlYW0ubWF0Y2goLyhcXHcpLywgZmFsc2UpKSB7XHJcbiAgICAgICAgdmFyIHByZXZQb3MgPSBzdHJlYW0ucG9zIC0gMjtcclxuICAgICAgICBpZiAocHJldlBvcyA+PSAwKSB7XHJcbiAgICAgICAgICB2YXIgcHJldkNoID0gc3RyZWFtLnN0cmluZy5jaGFyQXQocHJldlBvcyk7XHJcbiAgICAgICAgICBpZiAocHJldkNoICE9PSAnXycgJiYgcHJldkNoLm1hdGNoKC8oXFx3KS8sIGZhbHNlKSkge1xyXG4gICAgICAgICAgICBpZ25vcmVVbmRlcnNjb3JlID0gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGlmIChjaCA9PT0gJyonIHx8IChjaCA9PT0gJ18nICYmICFpZ25vcmVVbmRlcnNjb3JlKSkge1xyXG4gICAgICBpZiAoc29sICYmIHN0cmVhbS5wZWVrKCkgPT09ICcgJykge1xyXG4gICAgICAgIC8vIERvIG5vdGhpbmcsIHN1cnJvdW5kZWQgYnkgbmV3bGluZSBhbmQgc3BhY2VcclxuICAgICAgfSBlbHNlIGlmIChzdGF0ZS5zdHJvbmcgPT09IGNoICYmIHN0cmVhbS5lYXQoY2gpKSB7IC8vIFJlbW92ZSBTVFJPTkdcclxuICAgICAgICBpZiAobW9kZUNmZy5oaWdobGlnaHRGb3JtYXR0aW5nKSBzdGF0ZS5mb3JtYXR0aW5nID0gXCJzdHJvbmdcIjtcclxuICAgICAgICB2YXIgdCA9IGdldFR5cGUoc3RhdGUpO1xyXG4gICAgICAgIHN0YXRlLnN0cm9uZyA9IGZhbHNlO1xyXG4gICAgICAgIHJldHVybiB0O1xyXG4gICAgICB9IGVsc2UgaWYgKCFzdGF0ZS5zdHJvbmcgJiYgc3RyZWFtLmVhdChjaCkpIHsgLy8gQWRkIFNUUk9OR1xyXG4gICAgICAgIHN0YXRlLnN0cm9uZyA9IGNoO1xyXG4gICAgICAgIGlmIChtb2RlQ2ZnLmhpZ2hsaWdodEZvcm1hdHRpbmcpIHN0YXRlLmZvcm1hdHRpbmcgPSBcInN0cm9uZ1wiO1xyXG4gICAgICAgIHJldHVybiBnZXRUeXBlKHN0YXRlKTtcclxuICAgICAgfSBlbHNlIGlmIChzdGF0ZS5lbSA9PT0gY2gpIHsgLy8gUmVtb3ZlIEVNXHJcbiAgICAgICAgaWYgKG1vZGVDZmcuaGlnaGxpZ2h0Rm9ybWF0dGluZykgc3RhdGUuZm9ybWF0dGluZyA9IFwiZW1cIjtcclxuICAgICAgICB2YXIgdCA9IGdldFR5cGUoc3RhdGUpO1xyXG4gICAgICAgIHN0YXRlLmVtID0gZmFsc2U7XHJcbiAgICAgICAgcmV0dXJuIHQ7XHJcbiAgICAgIH0gZWxzZSBpZiAoIXN0YXRlLmVtKSB7IC8vIEFkZCBFTVxyXG4gICAgICAgIHN0YXRlLmVtID0gY2g7XHJcbiAgICAgICAgaWYgKG1vZGVDZmcuaGlnaGxpZ2h0Rm9ybWF0dGluZykgc3RhdGUuZm9ybWF0dGluZyA9IFwiZW1cIjtcclxuICAgICAgICByZXR1cm4gZ2V0VHlwZShzdGF0ZSk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSBpZiAoY2ggPT09ICcgJykge1xyXG4gICAgICBpZiAoc3RyZWFtLmVhdCgnKicpIHx8IHN0cmVhbS5lYXQoJ18nKSkgeyAvLyBQcm9iYWJseSBzdXJyb3VuZGVkIGJ5IHNwYWNlc1xyXG4gICAgICAgIGlmIChzdHJlYW0ucGVlaygpID09PSAnICcpIHsgLy8gU3Vycm91bmRlZCBieSBzcGFjZXMsIGlnbm9yZVxyXG4gICAgICAgICAgcmV0dXJuIGdldFR5cGUoc3RhdGUpO1xyXG4gICAgICAgIH0gZWxzZSB7IC8vIE5vdCBzdXJyb3VuZGVkIGJ5IHNwYWNlcywgYmFjayB1cCBwb2ludGVyXHJcbiAgICAgICAgICBzdHJlYW0uYmFja1VwKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChtb2RlQ2ZnLnN0cmlrZXRocm91Z2gpIHtcclxuICAgICAgaWYgKGNoID09PSAnficgJiYgc3RyZWFtLmVhdFdoaWxlKGNoKSkge1xyXG4gICAgICAgIGlmIChzdGF0ZS5zdHJpa2V0aHJvdWdoKSB7Ly8gUmVtb3ZlIHN0cmlrZXRocm91Z2hcclxuICAgICAgICAgIGlmIChtb2RlQ2ZnLmhpZ2hsaWdodEZvcm1hdHRpbmcpIHN0YXRlLmZvcm1hdHRpbmcgPSBcInN0cmlrZXRocm91Z2hcIjtcclxuICAgICAgICAgIHZhciB0ID0gZ2V0VHlwZShzdGF0ZSk7XHJcbiAgICAgICAgICBzdGF0ZS5zdHJpa2V0aHJvdWdoID0gZmFsc2U7XHJcbiAgICAgICAgICByZXR1cm4gdDtcclxuICAgICAgICB9IGVsc2UgaWYgKHN0cmVhbS5tYXRjaCgvXlteXFxzXS8sIGZhbHNlKSkgey8vIEFkZCBzdHJpa2V0aHJvdWdoXHJcbiAgICAgICAgICBzdGF0ZS5zdHJpa2V0aHJvdWdoID0gdHJ1ZTtcclxuICAgICAgICAgIGlmIChtb2RlQ2ZnLmhpZ2hsaWdodEZvcm1hdHRpbmcpIHN0YXRlLmZvcm1hdHRpbmcgPSBcInN0cmlrZXRocm91Z2hcIjtcclxuICAgICAgICAgIHJldHVybiBnZXRUeXBlKHN0YXRlKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0gZWxzZSBpZiAoY2ggPT09ICcgJykge1xyXG4gICAgICAgIGlmIChzdHJlYW0ubWF0Y2goL15+fi8sIHRydWUpKSB7IC8vIFByb2JhYmx5IHN1cnJvdW5kZWQgYnkgc3BhY2VcclxuICAgICAgICAgIGlmIChzdHJlYW0ucGVlaygpID09PSAnICcpIHsgLy8gU3Vycm91bmRlZCBieSBzcGFjZXMsIGlnbm9yZVxyXG4gICAgICAgICAgICByZXR1cm4gZ2V0VHlwZShzdGF0ZSk7XHJcbiAgICAgICAgICB9IGVsc2UgeyAvLyBOb3Qgc3Vycm91bmRlZCBieSBzcGFjZXMsIGJhY2sgdXAgcG9pbnRlclxyXG4gICAgICAgICAgICBzdHJlYW0uYmFja1VwKDIpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGlmIChjaCA9PT0gJyAnKSB7XHJcbiAgICAgIGlmIChzdHJlYW0ubWF0Y2goLyArJC8sIGZhbHNlKSkge1xyXG4gICAgICAgIHN0YXRlLnRyYWlsaW5nU3BhY2UrKztcclxuICAgICAgfSBlbHNlIGlmIChzdGF0ZS50cmFpbGluZ1NwYWNlKSB7XHJcbiAgICAgICAgc3RhdGUudHJhaWxpbmdTcGFjZU5ld0xpbmUgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIGdldFR5cGUoc3RhdGUpO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gbGlua0lubGluZShzdHJlYW0sIHN0YXRlKSB7XHJcbiAgICB2YXIgY2ggPSBzdHJlYW0ubmV4dCgpO1xyXG5cclxuICAgIGlmIChjaCA9PT0gXCI+XCIpIHtcclxuICAgICAgc3RhdGUuZiA9IHN0YXRlLmlubGluZSA9IGlubGluZU5vcm1hbDtcclxuICAgICAgaWYgKG1vZGVDZmcuaGlnaGxpZ2h0Rm9ybWF0dGluZykgc3RhdGUuZm9ybWF0dGluZyA9IFwibGlua1wiO1xyXG4gICAgICB2YXIgdHlwZSA9IGdldFR5cGUoc3RhdGUpO1xyXG4gICAgICBpZiAodHlwZSl7XHJcbiAgICAgICAgdHlwZSArPSBcIiBcIjtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0eXBlID0gXCJcIjtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gdHlwZSArIHRva2VuVHlwZXMubGlua0lubGluZTtcclxuICAgIH1cclxuXHJcbiAgICBzdHJlYW0ubWF0Y2goL15bXj5dKy8sIHRydWUpO1xyXG5cclxuICAgIHJldHVybiB0b2tlblR5cGVzLmxpbmtJbmxpbmU7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBsaW5rSHJlZihzdHJlYW0sIHN0YXRlKSB7XHJcbiAgICAvLyBDaGVjayBpZiBzcGFjZSwgYW5kIHJldHVybiBOVUxMIGlmIHNvICh0byBhdm9pZCBtYXJraW5nIHRoZSBzcGFjZSlcclxuICAgIGlmKHN0cmVhbS5lYXRTcGFjZSgpKXtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9XHJcbiAgICB2YXIgY2ggPSBzdHJlYW0ubmV4dCgpO1xyXG4gICAgaWYgKGNoID09PSAnKCcgfHwgY2ggPT09ICdbJykge1xyXG4gICAgICBzdGF0ZS5mID0gc3RhdGUuaW5saW5lID0gZ2V0TGlua0hyZWZJbnNpZGUoY2ggPT09IFwiKFwiID8gXCIpXCIgOiBcIl1cIik7XHJcbiAgICAgIGlmIChtb2RlQ2ZnLmhpZ2hsaWdodEZvcm1hdHRpbmcpIHN0YXRlLmZvcm1hdHRpbmcgPSBcImxpbmstc3RyaW5nXCI7XHJcbiAgICAgIHN0YXRlLmxpbmtIcmVmID0gdHJ1ZTtcclxuICAgICAgcmV0dXJuIGdldFR5cGUoc3RhdGUpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuICdlcnJvcic7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBnZXRMaW5rSHJlZkluc2lkZShlbmRDaGFyKSB7XHJcbiAgICByZXR1cm4gZnVuY3Rpb24oc3RyZWFtLCBzdGF0ZSkge1xyXG4gICAgICB2YXIgY2ggPSBzdHJlYW0ubmV4dCgpO1xyXG5cclxuICAgICAgaWYgKGNoID09PSBlbmRDaGFyKSB7XHJcbiAgICAgICAgc3RhdGUuZiA9IHN0YXRlLmlubGluZSA9IGlubGluZU5vcm1hbDtcclxuICAgICAgICBpZiAobW9kZUNmZy5oaWdobGlnaHRGb3JtYXR0aW5nKSBzdGF0ZS5mb3JtYXR0aW5nID0gXCJsaW5rLXN0cmluZ1wiO1xyXG4gICAgICAgIHZhciByZXR1cm5TdGF0ZSA9IGdldFR5cGUoc3RhdGUpO1xyXG4gICAgICAgIHN0YXRlLmxpbmtIcmVmID0gZmFsc2U7XHJcbiAgICAgICAgcmV0dXJuIHJldHVyblN0YXRlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoc3RyZWFtLm1hdGNoKGlubGluZVJFKGVuZENoYXIpLCB0cnVlKSkge1xyXG4gICAgICAgIHN0cmVhbS5iYWNrVXAoMSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHN0YXRlLmxpbmtIcmVmID0gdHJ1ZTtcclxuICAgICAgcmV0dXJuIGdldFR5cGUoc3RhdGUpO1xyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGZvb3Rub3RlTGluayhzdHJlYW0sIHN0YXRlKSB7XHJcbiAgICBpZiAoc3RyZWFtLm1hdGNoKC9eW15cXF1dKlxcXTovLCBmYWxzZSkpIHtcclxuICAgICAgc3RhdGUuZiA9IGZvb3Rub3RlTGlua0luc2lkZTtcclxuICAgICAgc3RyZWFtLm5leHQoKTsgLy8gQ29uc3VtZSBbXHJcbiAgICAgIGlmIChtb2RlQ2ZnLmhpZ2hsaWdodEZvcm1hdHRpbmcpIHN0YXRlLmZvcm1hdHRpbmcgPSBcImxpbmtcIjtcclxuICAgICAgc3RhdGUubGlua1RleHQgPSB0cnVlO1xyXG4gICAgICByZXR1cm4gZ2V0VHlwZShzdGF0ZSk7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gc3dpdGNoSW5saW5lKHN0cmVhbSwgc3RhdGUsIGlubGluZU5vcm1hbCk7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBmb290bm90ZUxpbmtJbnNpZGUoc3RyZWFtLCBzdGF0ZSkge1xyXG4gICAgaWYgKHN0cmVhbS5tYXRjaCgvXlxcXTovLCB0cnVlKSkge1xyXG4gICAgICBzdGF0ZS5mID0gc3RhdGUuaW5saW5lID0gZm9vdG5vdGVVcmw7XHJcbiAgICAgIGlmIChtb2RlQ2ZnLmhpZ2hsaWdodEZvcm1hdHRpbmcpIHN0YXRlLmZvcm1hdHRpbmcgPSBcImxpbmtcIjtcclxuICAgICAgdmFyIHJldHVyblR5cGUgPSBnZXRUeXBlKHN0YXRlKTtcclxuICAgICAgc3RhdGUubGlua1RleHQgPSBmYWxzZTtcclxuICAgICAgcmV0dXJuIHJldHVyblR5cGU7XHJcbiAgICB9XHJcblxyXG4gICAgc3RyZWFtLm1hdGNoKC9eW15cXF1dKy8sIHRydWUpO1xyXG5cclxuICAgIHJldHVybiB0b2tlblR5cGVzLmxpbmtUZXh0O1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gZm9vdG5vdGVVcmwoc3RyZWFtLCBzdGF0ZSkge1xyXG4gICAgLy8gQ2hlY2sgaWYgc3BhY2UsIGFuZCByZXR1cm4gTlVMTCBpZiBzbyAodG8gYXZvaWQgbWFya2luZyB0aGUgc3BhY2UpXHJcbiAgICBpZihzdHJlYW0uZWF0U3BhY2UoKSl7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG4gICAgLy8gTWF0Y2ggVVJMXHJcbiAgICBzdHJlYW0ubWF0Y2goL15bXlxcc10rLywgdHJ1ZSk7XHJcbiAgICAvLyBDaGVjayBmb3IgbGluayB0aXRsZVxyXG4gICAgaWYgKHN0cmVhbS5wZWVrKCkgPT09IHVuZGVmaW5lZCkgeyAvLyBFbmQgb2YgbGluZSwgc2V0IGZsYWcgdG8gY2hlY2sgbmV4dCBsaW5lXHJcbiAgICAgIHN0YXRlLmxpbmtUaXRsZSA9IHRydWU7XHJcbiAgICB9IGVsc2UgeyAvLyBNb3JlIGNvbnRlbnQgb24gbGluZSwgY2hlY2sgaWYgbGluayB0aXRsZVxyXG4gICAgICBzdHJlYW0ubWF0Y2goL14oPzpcXHMrKD86XCIoPzpbXlwiXFxcXF18XFxcXFxcXFx8XFxcXC4pK1wifCcoPzpbXidcXFxcXXxcXFxcXFxcXHxcXFxcLikrJ3xcXCgoPzpbXilcXFxcXXxcXFxcXFxcXHxcXFxcLikrXFwpKSk/LywgdHJ1ZSk7XHJcbiAgICB9XHJcbiAgICBzdGF0ZS5mID0gc3RhdGUuaW5saW5lID0gaW5saW5lTm9ybWFsO1xyXG4gICAgcmV0dXJuIHRva2VuVHlwZXMubGlua0hyZWYgKyBcIiB1cmxcIjtcclxuICB9XHJcblxyXG4gIHZhciBzYXZlZElubGluZVJFID0gW107XHJcbiAgZnVuY3Rpb24gaW5saW5lUkUoZW5kQ2hhcikge1xyXG4gICAgaWYgKCFzYXZlZElubGluZVJFW2VuZENoYXJdKSB7XHJcbiAgICAgIC8vIEVzY2FwZSBlbmRDaGFyIGZvciBSZWdFeHAgKHRha2VuIGZyb20gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvNDk0MTIyLzUyNjc0MSlcclxuICAgICAgZW5kQ2hhciA9IChlbmRDaGFyKycnKS5yZXBsYWNlKC8oWy4/KiteJFtcXF1cXFxcKCl7fXwtXSkvZywgXCJcXFxcJDFcIik7XHJcbiAgICAgIC8vIE1hdGNoIGFueSBub24tZW5kQ2hhciwgZXNjYXBlZCBjaGFyYWN0ZXIsIGFzIHdlbGwgYXMgdGhlIGNsb3NpbmdcclxuICAgICAgLy8gZW5kQ2hhci5cclxuICAgICAgc2F2ZWRJbmxpbmVSRVtlbmRDaGFyXSA9IG5ldyBSZWdFeHAoJ14oPzpbXlxcXFxcXFxcXXxcXFxcXFxcXC4pKj8oJyArIGVuZENoYXIgKyAnKScpO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHNhdmVkSW5saW5lUkVbZW5kQ2hhcl07XHJcbiAgfVxyXG5cclxuICB2YXIgbW9kZSA9IHtcclxuICAgIHN0YXJ0U3RhdGU6IGZ1bmN0aW9uKCkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIGY6IGJsb2NrTm9ybWFsLFxyXG5cclxuICAgICAgICBwcmV2TGluZTogbnVsbCxcclxuICAgICAgICB0aGlzTGluZTogbnVsbCxcclxuXHJcbiAgICAgICAgYmxvY2s6IGJsb2NrTm9ybWFsLFxyXG4gICAgICAgIGh0bWxTdGF0ZTogbnVsbCxcclxuICAgICAgICBpbmRlbnRhdGlvbjogMCxcclxuXHJcbiAgICAgICAgaW5saW5lOiBpbmxpbmVOb3JtYWwsXHJcbiAgICAgICAgdGV4dDogaGFuZGxlVGV4dCxcclxuXHJcbiAgICAgICAgZm9ybWF0dGluZzogZmFsc2UsXHJcbiAgICAgICAgbGlua1RleHQ6IGZhbHNlLFxyXG4gICAgICAgIGxpbmtIcmVmOiBmYWxzZSxcclxuICAgICAgICBsaW5rVGl0bGU6IGZhbHNlLFxyXG4gICAgICAgIGVtOiBmYWxzZSxcclxuICAgICAgICBzdHJvbmc6IGZhbHNlLFxyXG4gICAgICAgIGhlYWRlcjogMCxcclxuICAgICAgICBocjogZmFsc2UsXHJcbiAgICAgICAgdGFza0xpc3Q6IGZhbHNlLFxyXG4gICAgICAgIGxpc3Q6IGZhbHNlLFxyXG4gICAgICAgIGxpc3REZXB0aDogMCxcclxuICAgICAgICBxdW90ZTogMCxcclxuICAgICAgICB0cmFpbGluZ1NwYWNlOiAwLFxyXG4gICAgICAgIHRyYWlsaW5nU3BhY2VOZXdMaW5lOiBmYWxzZSxcclxuICAgICAgICBzdHJpa2V0aHJvdWdoOiBmYWxzZSxcclxuICAgICAgICBmZW5jZWRDaGFyczogbnVsbFxyXG4gICAgICB9O1xyXG4gICAgfSxcclxuXHJcbiAgICBjb3B5U3RhdGU6IGZ1bmN0aW9uKHMpIHtcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBmOiBzLmYsXHJcblxyXG4gICAgICAgIHByZXZMaW5lOiBzLnByZXZMaW5lLFxyXG4gICAgICAgIHRoaXNMaW5lOiBzLnRoaXNMaW5lLFxyXG5cclxuICAgICAgICBibG9jazogcy5ibG9jayxcclxuICAgICAgICBodG1sU3RhdGU6IHMuaHRtbFN0YXRlICYmIENvZGVNaXJyb3IuY29weVN0YXRlKGh0bWxNb2RlLCBzLmh0bWxTdGF0ZSksXHJcbiAgICAgICAgaW5kZW50YXRpb246IHMuaW5kZW50YXRpb24sXHJcblxyXG4gICAgICAgIGxvY2FsTW9kZTogcy5sb2NhbE1vZGUsXHJcbiAgICAgICAgbG9jYWxTdGF0ZTogcy5sb2NhbE1vZGUgPyBDb2RlTWlycm9yLmNvcHlTdGF0ZShzLmxvY2FsTW9kZSwgcy5sb2NhbFN0YXRlKSA6IG51bGwsXHJcblxyXG4gICAgICAgIGlubGluZTogcy5pbmxpbmUsXHJcbiAgICAgICAgdGV4dDogcy50ZXh0LFxyXG4gICAgICAgIGZvcm1hdHRpbmc6IGZhbHNlLFxyXG4gICAgICAgIGxpbmtUaXRsZTogcy5saW5rVGl0bGUsXHJcbiAgICAgICAgY29kZTogcy5jb2RlLFxyXG4gICAgICAgIGVtOiBzLmVtLFxyXG4gICAgICAgIHN0cm9uZzogcy5zdHJvbmcsXHJcbiAgICAgICAgc3RyaWtldGhyb3VnaDogcy5zdHJpa2V0aHJvdWdoLFxyXG4gICAgICAgIGhlYWRlcjogcy5oZWFkZXIsXHJcbiAgICAgICAgaHI6IHMuaHIsXHJcbiAgICAgICAgdGFza0xpc3Q6IHMudGFza0xpc3QsXHJcbiAgICAgICAgbGlzdDogcy5saXN0LFxyXG4gICAgICAgIGxpc3REZXB0aDogcy5saXN0RGVwdGgsXHJcbiAgICAgICAgcXVvdGU6IHMucXVvdGUsXHJcbiAgICAgICAgaW5kZW50ZWRDb2RlOiBzLmluZGVudGVkQ29kZSxcclxuICAgICAgICB0cmFpbGluZ1NwYWNlOiBzLnRyYWlsaW5nU3BhY2UsXHJcbiAgICAgICAgdHJhaWxpbmdTcGFjZU5ld0xpbmU6IHMudHJhaWxpbmdTcGFjZU5ld0xpbmUsXHJcbiAgICAgICAgbWRfaW5zaWRlOiBzLm1kX2luc2lkZSxcclxuICAgICAgICBmZW5jZWRDaGFyczogcy5mZW5jZWRDaGFyc1xyXG4gICAgICB9O1xyXG4gICAgfSxcclxuXHJcbiAgICB0b2tlbjogZnVuY3Rpb24oc3RyZWFtLCBzdGF0ZSkge1xyXG5cclxuICAgICAgLy8gUmVzZXQgc3RhdGUuZm9ybWF0dGluZ1xyXG4gICAgICBzdGF0ZS5mb3JtYXR0aW5nID0gZmFsc2U7XHJcblxyXG4gICAgICBpZiAoc3RyZWFtICE9IHN0YXRlLnRoaXNMaW5lKSB7XHJcbiAgICAgICAgdmFyIGZvcmNlQmxhbmtMaW5lID0gc3RhdGUuaGVhZGVyIHx8IHN0YXRlLmhyO1xyXG5cclxuICAgICAgICAvLyBSZXNldCBzdGF0ZS5oZWFkZXIgYW5kIHN0YXRlLmhyXHJcbiAgICAgICAgc3RhdGUuaGVhZGVyID0gMDtcclxuICAgICAgICBzdGF0ZS5ociA9IGZhbHNlO1xyXG5cclxuICAgICAgICBpZiAoc3RyZWFtLm1hdGNoKC9eXFxzKiQvLCB0cnVlKSB8fCBmb3JjZUJsYW5rTGluZSkge1xyXG4gICAgICAgICAgYmxhbmtMaW5lKHN0YXRlKTtcclxuICAgICAgICAgIGlmICghZm9yY2VCbGFua0xpbmUpIHJldHVybiBudWxsXHJcbiAgICAgICAgICBzdGF0ZS5wcmV2TGluZSA9IG51bGxcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHN0YXRlLnByZXZMaW5lID0gc3RhdGUudGhpc0xpbmVcclxuICAgICAgICBzdGF0ZS50aGlzTGluZSA9IHN0cmVhbVxyXG5cclxuICAgICAgICAvLyBSZXNldCBzdGF0ZS50YXNrTGlzdFxyXG4gICAgICAgIHN0YXRlLnRhc2tMaXN0ID0gZmFsc2U7XHJcblxyXG4gICAgICAgIC8vIFJlc2V0IHN0YXRlLnRyYWlsaW5nU3BhY2VcclxuICAgICAgICBzdGF0ZS50cmFpbGluZ1NwYWNlID0gMDtcclxuICAgICAgICBzdGF0ZS50cmFpbGluZ1NwYWNlTmV3TGluZSA9IGZhbHNlO1xyXG5cclxuICAgICAgICBzdGF0ZS5mID0gc3RhdGUuYmxvY2s7XHJcbiAgICAgICAgdmFyIGluZGVudGF0aW9uID0gc3RyZWFtLm1hdGNoKC9eXFxzKi8sIHRydWUpWzBdLnJlcGxhY2UoL1xcdC9nLCAnICAgICcpLmxlbmd0aDtcclxuICAgICAgICB2YXIgZGlmZmVyZW5jZSA9IE1hdGguZmxvb3IoKGluZGVudGF0aW9uIC0gc3RhdGUuaW5kZW50YXRpb24pIC8gNCkgKiA0O1xyXG4gICAgICAgIGlmIChkaWZmZXJlbmNlID4gNCkgZGlmZmVyZW5jZSA9IDQ7XHJcbiAgICAgICAgdmFyIGFkanVzdGVkSW5kZW50YXRpb24gPSBzdGF0ZS5pbmRlbnRhdGlvbiArIGRpZmZlcmVuY2U7XHJcbiAgICAgICAgc3RhdGUuaW5kZW50YXRpb25EaWZmID0gYWRqdXN0ZWRJbmRlbnRhdGlvbiAtIHN0YXRlLmluZGVudGF0aW9uO1xyXG4gICAgICAgIHN0YXRlLmluZGVudGF0aW9uID0gYWRqdXN0ZWRJbmRlbnRhdGlvbjtcclxuICAgICAgICBpZiAoaW5kZW50YXRpb24gPiAwKSByZXR1cm4gbnVsbDtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gc3RhdGUuZihzdHJlYW0sIHN0YXRlKTtcclxuICAgIH0sXHJcblxyXG4gICAgaW5uZXJNb2RlOiBmdW5jdGlvbihzdGF0ZSkge1xyXG4gICAgICBpZiAoc3RhdGUuYmxvY2sgPT0gaHRtbEJsb2NrKSByZXR1cm4ge3N0YXRlOiBzdGF0ZS5odG1sU3RhdGUsIG1vZGU6IGh0bWxNb2RlfTtcclxuICAgICAgaWYgKHN0YXRlLmxvY2FsU3RhdGUpIHJldHVybiB7c3RhdGU6IHN0YXRlLmxvY2FsU3RhdGUsIG1vZGU6IHN0YXRlLmxvY2FsTW9kZX07XHJcbiAgICAgIHJldHVybiB7c3RhdGU6IHN0YXRlLCBtb2RlOiBtb2RlfTtcclxuICAgIH0sXHJcblxyXG4gICAgYmxhbmtMaW5lOiBibGFua0xpbmUsXHJcblxyXG4gICAgZ2V0VHlwZTogZ2V0VHlwZSxcclxuXHJcbiAgICBmb2xkOiBcIm1hcmtkb3duXCJcclxuICB9O1xyXG4gIHJldHVybiBtb2RlO1xyXG59LCBcInhtbFwiKTtcclxuXHJcbkNvZGVNaXJyb3IuZGVmaW5lTUlNRShcInRleHQveC1tYXJrZG93blwiLCBcIm1hcmtkb3duXCIpO1xyXG5cclxufSk7XHJcbiIsIi8vIENvZGVNaXJyb3IsIGNvcHlyaWdodCAoYykgYnkgTWFyaWpuIEhhdmVyYmVrZSBhbmQgb3RoZXJzXHJcbi8vIERpc3RyaWJ1dGVkIHVuZGVyIGFuIE1JVCBsaWNlbnNlOiBodHRwOi8vY29kZW1pcnJvci5uZXQvTElDRU5TRVxyXG5cclxuKGZ1bmN0aW9uKG1vZCkge1xyXG4gIGlmICh0eXBlb2YgZXhwb3J0cyA9PSBcIm9iamVjdFwiICYmIHR5cGVvZiBtb2R1bGUgPT0gXCJvYmplY3RcIikgLy8gQ29tbW9uSlNcclxuICAgIG1vZChyZXF1aXJlKFwiLi4vbGliL2NvZGVtaXJyb3JcIikpO1xyXG4gIGVsc2UgaWYgKHR5cGVvZiBkZWZpbmUgPT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQpIC8vIEFNRFxyXG4gICAgZGVmaW5lKFtcIi4uL2xpYi9jb2RlbWlycm9yXCJdLCBtb2QpO1xyXG4gIGVsc2UgLy8gUGxhaW4gYnJvd3NlciBlbnZcclxuICAgIG1vZChDb2RlTWlycm9yKTtcclxufSkoZnVuY3Rpb24oQ29kZU1pcnJvcikge1xyXG4gIFwidXNlIHN0cmljdFwiO1xyXG5cclxuICBDb2RlTWlycm9yLm1vZGVJbmZvID0gW1xyXG4gICAge25hbWU6IFwiQVBMXCIsIG1pbWU6IFwidGV4dC9hcGxcIiwgbW9kZTogXCJhcGxcIiwgZXh0OiBbXCJkeWFsb2dcIiwgXCJhcGxcIl19LFxyXG4gICAge25hbWU6IFwiUEdQXCIsIG1pbWVzOiBbXCJhcHBsaWNhdGlvbi9wZ3BcIiwgXCJhcHBsaWNhdGlvbi9wZ3Ata2V5c1wiLCBcImFwcGxpY2F0aW9uL3BncC1zaWduYXR1cmVcIl0sIG1vZGU6IFwiYXNjaWlhcm1vclwiLCBleHQ6IFtcInBncFwiXX0sXHJcbiAgICB7bmFtZTogXCJBU04uMVwiLCBtaW1lOiBcInRleHQveC10dGNuLWFzblwiLCBtb2RlOiBcImFzbi4xXCIsIGV4dDogW1wiYXNuXCIsIFwiYXNuMVwiXX0sXHJcbiAgICB7bmFtZTogXCJBc3Rlcmlza1wiLCBtaW1lOiBcInRleHQveC1hc3Rlcmlza1wiLCBtb2RlOiBcImFzdGVyaXNrXCIsIGZpbGU6IC9eZXh0ZW5zaW9uc1xcLmNvbmYkL2l9LFxyXG4gICAge25hbWU6IFwiQnJhaW5mdWNrXCIsIG1pbWU6IFwidGV4dC94LWJyYWluZnVja1wiLCBtb2RlOiBcImJyYWluZnVja1wiLCBleHQ6IFtcImJcIiwgXCJiZlwiXX0sXHJcbiAgICB7bmFtZTogXCJDXCIsIG1pbWU6IFwidGV4dC94LWNzcmNcIiwgbW9kZTogXCJjbGlrZVwiLCBleHQ6IFtcImNcIiwgXCJoXCJdfSxcclxuICAgIHtuYW1lOiBcIkMrK1wiLCBtaW1lOiBcInRleHQveC1jKytzcmNcIiwgbW9kZTogXCJjbGlrZVwiLCBleHQ6IFtcImNwcFwiLCBcImMrK1wiLCBcImNjXCIsIFwiY3h4XCIsIFwiaHBwXCIsIFwiaCsrXCIsIFwiaGhcIiwgXCJoeHhcIl0sIGFsaWFzOiBbXCJjcHBcIl19LFxyXG4gICAge25hbWU6IFwiQ29ib2xcIiwgbWltZTogXCJ0ZXh0L3gtY29ib2xcIiwgbW9kZTogXCJjb2JvbFwiLCBleHQ6IFtcImNvYlwiLCBcImNweVwiXX0sXHJcbiAgICB7bmFtZTogXCJDI1wiLCBtaW1lOiBcInRleHQveC1jc2hhcnBcIiwgbW9kZTogXCJjbGlrZVwiLCBleHQ6IFtcImNzXCJdLCBhbGlhczogW1wiY3NoYXJwXCJdfSxcclxuICAgIHtuYW1lOiBcIkNsb2p1cmVcIiwgbWltZTogXCJ0ZXh0L3gtY2xvanVyZVwiLCBtb2RlOiBcImNsb2p1cmVcIiwgZXh0OiBbXCJjbGpcIl19LFxyXG4gICAge25hbWU6IFwiQ2xvc3VyZSBTdHlsZXNoZWV0cyAoR1NTKVwiLCBtaW1lOiBcInRleHQveC1nc3NcIiwgbW9kZTogXCJjc3NcIiwgZXh0OiBbXCJnc3NcIl19LFxyXG4gICAge25hbWU6IFwiQ01ha2VcIiwgbWltZTogXCJ0ZXh0L3gtY21ha2VcIiwgbW9kZTogXCJjbWFrZVwiLCBleHQ6IFtcImNtYWtlXCIsIFwiY21ha2UuaW5cIl0sIGZpbGU6IC9eQ01ha2VMaXN0cy50eHQkL30sXHJcbiAgICB7bmFtZTogXCJDb2ZmZWVTY3JpcHRcIiwgbWltZTogXCJ0ZXh0L3gtY29mZmVlc2NyaXB0XCIsIG1vZGU6IFwiY29mZmVlc2NyaXB0XCIsIGV4dDogW1wiY29mZmVlXCJdLCBhbGlhczogW1wiY29mZmVlXCIsIFwiY29mZmVlLXNjcmlwdFwiXX0sXHJcbiAgICB7bmFtZTogXCJDb21tb24gTGlzcFwiLCBtaW1lOiBcInRleHQveC1jb21tb24tbGlzcFwiLCBtb2RlOiBcImNvbW1vbmxpc3BcIiwgZXh0OiBbXCJjbFwiLCBcImxpc3BcIiwgXCJlbFwiXSwgYWxpYXM6IFtcImxpc3BcIl19LFxyXG4gICAge25hbWU6IFwiQ3lwaGVyXCIsIG1pbWU6IFwiYXBwbGljYXRpb24veC1jeXBoZXItcXVlcnlcIiwgbW9kZTogXCJjeXBoZXJcIiwgZXh0OiBbXCJjeXBcIiwgXCJjeXBoZXJcIl19LFxyXG4gICAge25hbWU6IFwiQ3l0aG9uXCIsIG1pbWU6IFwidGV4dC94LWN5dGhvblwiLCBtb2RlOiBcInB5dGhvblwiLCBleHQ6IFtcInB5eFwiLCBcInB4ZFwiLCBcInB4aVwiXX0sXHJcbiAgICB7bmFtZTogXCJDU1NcIiwgbWltZTogXCJ0ZXh0L2Nzc1wiLCBtb2RlOiBcImNzc1wiLCBleHQ6IFtcImNzc1wiXX0sXHJcbiAgICB7bmFtZTogXCJDUUxcIiwgbWltZTogXCJ0ZXh0L3gtY2Fzc2FuZHJhXCIsIG1vZGU6IFwic3FsXCIsIGV4dDogW1wiY3FsXCJdfSxcclxuICAgIHtuYW1lOiBcIkRcIiwgbWltZTogXCJ0ZXh0L3gtZFwiLCBtb2RlOiBcImRcIiwgZXh0OiBbXCJkXCJdfSxcclxuICAgIHtuYW1lOiBcIkRhcnRcIiwgbWltZXM6IFtcImFwcGxpY2F0aW9uL2RhcnRcIiwgXCJ0ZXh0L3gtZGFydFwiXSwgbW9kZTogXCJkYXJ0XCIsIGV4dDogW1wiZGFydFwiXX0sXHJcbiAgICB7bmFtZTogXCJkaWZmXCIsIG1pbWU6IFwidGV4dC94LWRpZmZcIiwgbW9kZTogXCJkaWZmXCIsIGV4dDogW1wiZGlmZlwiLCBcInBhdGNoXCJdfSxcclxuICAgIHtuYW1lOiBcIkRqYW5nb1wiLCBtaW1lOiBcInRleHQveC1kamFuZ29cIiwgbW9kZTogXCJkamFuZ29cIn0sXHJcbiAgICB7bmFtZTogXCJEb2NrZXJmaWxlXCIsIG1pbWU6IFwidGV4dC94LWRvY2tlcmZpbGVcIiwgbW9kZTogXCJkb2NrZXJmaWxlXCIsIGZpbGU6IC9eRG9ja2VyZmlsZSQvfSxcclxuICAgIHtuYW1lOiBcIkRURFwiLCBtaW1lOiBcImFwcGxpY2F0aW9uL3htbC1kdGRcIiwgbW9kZTogXCJkdGRcIiwgZXh0OiBbXCJkdGRcIl19LFxyXG4gICAge25hbWU6IFwiRHlsYW5cIiwgbWltZTogXCJ0ZXh0L3gtZHlsYW5cIiwgbW9kZTogXCJkeWxhblwiLCBleHQ6IFtcImR5bGFuXCIsIFwiZHlsXCIsIFwiaW50clwiXX0sXHJcbiAgICB7bmFtZTogXCJFQk5GXCIsIG1pbWU6IFwidGV4dC94LWVibmZcIiwgbW9kZTogXCJlYm5mXCJ9LFxyXG4gICAge25hbWU6IFwiRUNMXCIsIG1pbWU6IFwidGV4dC94LWVjbFwiLCBtb2RlOiBcImVjbFwiLCBleHQ6IFtcImVjbFwiXX0sXHJcbiAgICB7bmFtZTogXCJFaWZmZWxcIiwgbWltZTogXCJ0ZXh0L3gtZWlmZmVsXCIsIG1vZGU6IFwiZWlmZmVsXCIsIGV4dDogW1wiZVwiXX0sXHJcbiAgICB7bmFtZTogXCJFbG1cIiwgbWltZTogXCJ0ZXh0L3gtZWxtXCIsIG1vZGU6IFwiZWxtXCIsIGV4dDogW1wiZWxtXCJdfSxcclxuICAgIHtuYW1lOiBcIkVtYmVkZGVkIEphdmFzY3JpcHRcIiwgbWltZTogXCJhcHBsaWNhdGlvbi94LWVqc1wiLCBtb2RlOiBcImh0bWxlbWJlZGRlZFwiLCBleHQ6IFtcImVqc1wiXX0sXHJcbiAgICB7bmFtZTogXCJFbWJlZGRlZCBSdWJ5XCIsIG1pbWU6IFwiYXBwbGljYXRpb24veC1lcmJcIiwgbW9kZTogXCJodG1sZW1iZWRkZWRcIiwgZXh0OiBbXCJlcmJcIl19LFxyXG4gICAge25hbWU6IFwiRXJsYW5nXCIsIG1pbWU6IFwidGV4dC94LWVybGFuZ1wiLCBtb2RlOiBcImVybGFuZ1wiLCBleHQ6IFtcImVybFwiXX0sXHJcbiAgICB7bmFtZTogXCJGYWN0b3JcIiwgbWltZTogXCJ0ZXh0L3gtZmFjdG9yXCIsIG1vZGU6IFwiZmFjdG9yXCIsIGV4dDogW1wiZmFjdG9yXCJdfSxcclxuICAgIHtuYW1lOiBcIkZvcnRoXCIsIG1pbWU6IFwidGV4dC94LWZvcnRoXCIsIG1vZGU6IFwiZm9ydGhcIiwgZXh0OiBbXCJmb3J0aFwiLCBcImZ0aFwiLCBcIjR0aFwiXX0sXHJcbiAgICB7bmFtZTogXCJGb3J0cmFuXCIsIG1pbWU6IFwidGV4dC94LWZvcnRyYW5cIiwgbW9kZTogXCJmb3J0cmFuXCIsIGV4dDogW1wiZlwiLCBcImZvclwiLCBcImY3N1wiLCBcImY5MFwiXX0sXHJcbiAgICB7bmFtZTogXCJGI1wiLCBtaW1lOiBcInRleHQveC1mc2hhcnBcIiwgbW9kZTogXCJtbGxpa2VcIiwgZXh0OiBbXCJmc1wiXSwgYWxpYXM6IFtcImZzaGFycFwiXX0sXHJcbiAgICB7bmFtZTogXCJHYXNcIiwgbWltZTogXCJ0ZXh0L3gtZ2FzXCIsIG1vZGU6IFwiZ2FzXCIsIGV4dDogW1wic1wiXX0sXHJcbiAgICB7bmFtZTogXCJHaGVya2luXCIsIG1pbWU6IFwidGV4dC94LWZlYXR1cmVcIiwgbW9kZTogXCJnaGVya2luXCIsIGV4dDogW1wiZmVhdHVyZVwiXX0sXHJcbiAgICB7bmFtZTogXCJHaXRIdWIgRmxhdm9yZWQgTWFya2Rvd25cIiwgbWltZTogXCJ0ZXh0L3gtZ2ZtXCIsIG1vZGU6IFwiZ2ZtXCIsIGZpbGU6IC9eKHJlYWRtZXxjb250cmlidXRpbmd8aGlzdG9yeSkubWQkL2l9LFxyXG4gICAge25hbWU6IFwiR29cIiwgbWltZTogXCJ0ZXh0L3gtZ29cIiwgbW9kZTogXCJnb1wiLCBleHQ6IFtcImdvXCJdfSxcclxuICAgIHtuYW1lOiBcIkdyb292eVwiLCBtaW1lOiBcInRleHQveC1ncm9vdnlcIiwgbW9kZTogXCJncm9vdnlcIiwgZXh0OiBbXCJncm9vdnlcIl19LFxyXG4gICAge25hbWU6IFwiSEFNTFwiLCBtaW1lOiBcInRleHQveC1oYW1sXCIsIG1vZGU6IFwiaGFtbFwiLCBleHQ6IFtcImhhbWxcIl19LFxyXG4gICAge25hbWU6IFwiSGFza2VsbFwiLCBtaW1lOiBcInRleHQveC1oYXNrZWxsXCIsIG1vZGU6IFwiaGFza2VsbFwiLCBleHQ6IFtcImhzXCJdfSxcclxuICAgIHtuYW1lOiBcIkhheGVcIiwgbWltZTogXCJ0ZXh0L3gtaGF4ZVwiLCBtb2RlOiBcImhheGVcIiwgZXh0OiBbXCJoeFwiXX0sXHJcbiAgICB7bmFtZTogXCJIWE1MXCIsIG1pbWU6IFwidGV4dC94LWh4bWxcIiwgbW9kZTogXCJoYXhlXCIsIGV4dDogW1wiaHhtbFwiXX0sXHJcbiAgICB7bmFtZTogXCJBU1AuTkVUXCIsIG1pbWU6IFwiYXBwbGljYXRpb24veC1hc3B4XCIsIG1vZGU6IFwiaHRtbGVtYmVkZGVkXCIsIGV4dDogW1wiYXNweFwiXSwgYWxpYXM6IFtcImFzcFwiLCBcImFzcHhcIl19LFxyXG4gICAge25hbWU6IFwiSFRNTFwiLCBtaW1lOiBcInRleHQvaHRtbFwiLCBtb2RlOiBcImh0bWxtaXhlZFwiLCBleHQ6IFtcImh0bWxcIiwgXCJodG1cIl0sIGFsaWFzOiBbXCJ4aHRtbFwiXX0sXHJcbiAgICB7bmFtZTogXCJIVFRQXCIsIG1pbWU6IFwibWVzc2FnZS9odHRwXCIsIG1vZGU6IFwiaHR0cFwifSxcclxuICAgIHtuYW1lOiBcIklETFwiLCBtaW1lOiBcInRleHQveC1pZGxcIiwgbW9kZTogXCJpZGxcIiwgZXh0OiBbXCJwcm9cIl19LFxyXG4gICAge25hbWU6IFwiSmFkZVwiLCBtaW1lOiBcInRleHQveC1qYWRlXCIsIG1vZGU6IFwiamFkZVwiLCBleHQ6IFtcImphZGVcIl19LFxyXG4gICAge25hbWU6IFwiSmF2YVwiLCBtaW1lOiBcInRleHQveC1qYXZhXCIsIG1vZGU6IFwiY2xpa2VcIiwgZXh0OiBbXCJqYXZhXCJdfSxcclxuICAgIHtuYW1lOiBcIkphdmEgU2VydmVyIFBhZ2VzXCIsIG1pbWU6IFwiYXBwbGljYXRpb24veC1qc3BcIiwgbW9kZTogXCJodG1sZW1iZWRkZWRcIiwgZXh0OiBbXCJqc3BcIl0sIGFsaWFzOiBbXCJqc3BcIl19LFxyXG4gICAge25hbWU6IFwiSmF2YVNjcmlwdFwiLCBtaW1lczogW1widGV4dC9qYXZhc2NyaXB0XCIsIFwidGV4dC9lY21hc2NyaXB0XCIsIFwiYXBwbGljYXRpb24vamF2YXNjcmlwdFwiLCBcImFwcGxpY2F0aW9uL3gtamF2YXNjcmlwdFwiLCBcImFwcGxpY2F0aW9uL2VjbWFzY3JpcHRcIl0sXHJcbiAgICAgbW9kZTogXCJqYXZhc2NyaXB0XCIsIGV4dDogW1wianNcIl0sIGFsaWFzOiBbXCJlY21hc2NyaXB0XCIsIFwianNcIiwgXCJub2RlXCJdfSxcclxuICAgIHtuYW1lOiBcIkpTT05cIiwgbWltZXM6IFtcImFwcGxpY2F0aW9uL2pzb25cIiwgXCJhcHBsaWNhdGlvbi94LWpzb25cIl0sIG1vZGU6IFwiamF2YXNjcmlwdFwiLCBleHQ6IFtcImpzb25cIiwgXCJtYXBcIl0sIGFsaWFzOiBbXCJqc29uNVwiXX0sXHJcbiAgICB7bmFtZTogXCJKU09OLUxEXCIsIG1pbWU6IFwiYXBwbGljYXRpb24vbGQranNvblwiLCBtb2RlOiBcImphdmFzY3JpcHRcIiwgZXh0OiBbXCJqc29ubGRcIl0sIGFsaWFzOiBbXCJqc29ubGRcIl19LFxyXG4gICAge25hbWU6IFwiSmluamEyXCIsIG1pbWU6IFwibnVsbFwiLCBtb2RlOiBcImppbmphMlwifSxcclxuICAgIHtuYW1lOiBcIkp1bGlhXCIsIG1pbWU6IFwidGV4dC94LWp1bGlhXCIsIG1vZGU6IFwianVsaWFcIiwgZXh0OiBbXCJqbFwiXX0sXHJcbiAgICB7bmFtZTogXCJLb3RsaW5cIiwgbWltZTogXCJ0ZXh0L3gta290bGluXCIsIG1vZGU6IFwiY2xpa2VcIiwgZXh0OiBbXCJrdFwiXX0sXHJcbiAgICB7bmFtZTogXCJMRVNTXCIsIG1pbWU6IFwidGV4dC94LWxlc3NcIiwgbW9kZTogXCJjc3NcIiwgZXh0OiBbXCJsZXNzXCJdfSxcclxuICAgIHtuYW1lOiBcIkxpdmVTY3JpcHRcIiwgbWltZTogXCJ0ZXh0L3gtbGl2ZXNjcmlwdFwiLCBtb2RlOiBcImxpdmVzY3JpcHRcIiwgZXh0OiBbXCJsc1wiXSwgYWxpYXM6IFtcImxzXCJdfSxcclxuICAgIHtuYW1lOiBcIkx1YVwiLCBtaW1lOiBcInRleHQveC1sdWFcIiwgbW9kZTogXCJsdWFcIiwgZXh0OiBbXCJsdWFcIl19LFxyXG4gICAge25hbWU6IFwiTWFya2Rvd25cIiwgbWltZTogXCJ0ZXh0L3gtbWFya2Rvd25cIiwgbW9kZTogXCJtYXJrZG93blwiLCBleHQ6IFtcIm1hcmtkb3duXCIsIFwibWRcIiwgXCJta2RcIl19LFxyXG4gICAge25hbWU6IFwibUlSQ1wiLCBtaW1lOiBcInRleHQvbWlyY1wiLCBtb2RlOiBcIm1pcmNcIn0sXHJcbiAgICB7bmFtZTogXCJNYXJpYURCIFNRTFwiLCBtaW1lOiBcInRleHQveC1tYXJpYWRiXCIsIG1vZGU6IFwic3FsXCJ9LFxyXG4gICAge25hbWU6IFwiTWF0aGVtYXRpY2FcIiwgbWltZTogXCJ0ZXh0L3gtbWF0aGVtYXRpY2FcIiwgbW9kZTogXCJtYXRoZW1hdGljYVwiLCBleHQ6IFtcIm1cIiwgXCJuYlwiXX0sXHJcbiAgICB7bmFtZTogXCJNb2RlbGljYVwiLCBtaW1lOiBcInRleHQveC1tb2RlbGljYVwiLCBtb2RlOiBcIm1vZGVsaWNhXCIsIGV4dDogW1wibW9cIl19LFxyXG4gICAge25hbWU6IFwiTVVNUFNcIiwgbWltZTogXCJ0ZXh0L3gtbXVtcHNcIiwgbW9kZTogXCJtdW1wc1wifSxcclxuICAgIHtuYW1lOiBcIk1TIFNRTFwiLCBtaW1lOiBcInRleHQveC1tc3NxbFwiLCBtb2RlOiBcInNxbFwifSxcclxuICAgIHtuYW1lOiBcIk15U1FMXCIsIG1pbWU6IFwidGV4dC94LW15c3FsXCIsIG1vZGU6IFwic3FsXCJ9LFxyXG4gICAge25hbWU6IFwiTmdpbnhcIiwgbWltZTogXCJ0ZXh0L3gtbmdpbngtY29uZlwiLCBtb2RlOiBcIm5naW54XCIsIGZpbGU6IC9uZ2lueC4qXFwuY29uZiQvaX0sXHJcbiAgICB7bmFtZTogXCJOU0lTXCIsIG1pbWU6IFwidGV4dC94LW5zaXNcIiwgbW9kZTogXCJuc2lzXCIsIGV4dDogW1wibnNoXCIsIFwibnNpXCJdfSxcclxuICAgIHtuYW1lOiBcIk5UcmlwbGVzXCIsIG1pbWU6IFwidGV4dC9uLXRyaXBsZXNcIiwgbW9kZTogXCJudHJpcGxlc1wiLCBleHQ6IFtcIm50XCJdfSxcclxuICAgIHtuYW1lOiBcIk9iamVjdGl2ZSBDXCIsIG1pbWU6IFwidGV4dC94LW9iamVjdGl2ZWNcIiwgbW9kZTogXCJjbGlrZVwiLCBleHQ6IFtcIm1cIiwgXCJtbVwiXX0sXHJcbiAgICB7bmFtZTogXCJPQ2FtbFwiLCBtaW1lOiBcInRleHQveC1vY2FtbFwiLCBtb2RlOiBcIm1sbGlrZVwiLCBleHQ6IFtcIm1sXCIsIFwibWxpXCIsIFwibWxsXCIsIFwibWx5XCJdfSxcclxuICAgIHtuYW1lOiBcIk9jdGF2ZVwiLCBtaW1lOiBcInRleHQveC1vY3RhdmVcIiwgbW9kZTogXCJvY3RhdmVcIiwgZXh0OiBbXCJtXCJdfSxcclxuICAgIHtuYW1lOiBcIk96XCIsIG1pbWU6IFwidGV4dC94LW96XCIsIG1vZGU6IFwib3pcIiwgZXh0OiBbXCJvelwiXX0sXHJcbiAgICB7bmFtZTogXCJQYXNjYWxcIiwgbWltZTogXCJ0ZXh0L3gtcGFzY2FsXCIsIG1vZGU6IFwicGFzY2FsXCIsIGV4dDogW1wicFwiLCBcInBhc1wiXX0sXHJcbiAgICB7bmFtZTogXCJQRUcuanNcIiwgbWltZTogXCJudWxsXCIsIG1vZGU6IFwicGVnanNcIiwgZXh0OiBbXCJqc29ubGRcIl19LFxyXG4gICAge25hbWU6IFwiUGVybFwiLCBtaW1lOiBcInRleHQveC1wZXJsXCIsIG1vZGU6IFwicGVybFwiLCBleHQ6IFtcInBsXCIsIFwicG1cIl19LFxyXG4gICAge25hbWU6IFwiUEhQXCIsIG1pbWU6IFwiYXBwbGljYXRpb24veC1odHRwZC1waHBcIiwgbW9kZTogXCJwaHBcIiwgZXh0OiBbXCJwaHBcIiwgXCJwaHAzXCIsIFwicGhwNFwiLCBcInBocDVcIiwgXCJwaHRtbFwiXX0sXHJcbiAgICB7bmFtZTogXCJQaWdcIiwgbWltZTogXCJ0ZXh0L3gtcGlnXCIsIG1vZGU6IFwicGlnXCIsIGV4dDogW1wicGlnXCJdfSxcclxuICAgIHtuYW1lOiBcIlBsYWluIFRleHRcIiwgbWltZTogXCJ0ZXh0L3BsYWluXCIsIG1vZGU6IFwibnVsbFwiLCBleHQ6IFtcInR4dFwiLCBcInRleHRcIiwgXCJjb25mXCIsIFwiZGVmXCIsIFwibGlzdFwiLCBcImxvZ1wiXX0sXHJcbiAgICB7bmFtZTogXCJQTFNRTFwiLCBtaW1lOiBcInRleHQveC1wbHNxbFwiLCBtb2RlOiBcInNxbFwiLCBleHQ6IFtcInBsc1wiXX0sXHJcbiAgICB7bmFtZTogXCJQcm9wZXJ0aWVzIGZpbGVzXCIsIG1pbWU6IFwidGV4dC94LXByb3BlcnRpZXNcIiwgbW9kZTogXCJwcm9wZXJ0aWVzXCIsIGV4dDogW1wicHJvcGVydGllc1wiLCBcImluaVwiLCBcImluXCJdLCBhbGlhczogW1wiaW5pXCIsIFwicHJvcGVydGllc1wiXX0sXHJcbiAgICB7bmFtZTogXCJQeXRob25cIiwgbWltZTogXCJ0ZXh0L3gtcHl0aG9uXCIsIG1vZGU6IFwicHl0aG9uXCIsIGV4dDogW1wicHlcIiwgXCJweXdcIl19LFxyXG4gICAge25hbWU6IFwiUHVwcGV0XCIsIG1pbWU6IFwidGV4dC94LXB1cHBldFwiLCBtb2RlOiBcInB1cHBldFwiLCBleHQ6IFtcInBwXCJdfSxcclxuICAgIHtuYW1lOiBcIlFcIiwgbWltZTogXCJ0ZXh0L3gtcVwiLCBtb2RlOiBcInFcIiwgZXh0OiBbXCJxXCJdfSxcclxuICAgIHtuYW1lOiBcIlJcIiwgbWltZTogXCJ0ZXh0L3gtcnNyY1wiLCBtb2RlOiBcInJcIiwgZXh0OiBbXCJyXCJdLCBhbGlhczogW1wicnNjcmlwdFwiXX0sXHJcbiAgICB7bmFtZTogXCJyZVN0cnVjdHVyZWRUZXh0XCIsIG1pbWU6IFwidGV4dC94LXJzdFwiLCBtb2RlOiBcInJzdFwiLCBleHQ6IFtcInJzdFwiXSwgYWxpYXM6IFtcInJzdFwiXX0sXHJcbiAgICB7bmFtZTogXCJSUE0gQ2hhbmdlc1wiLCBtaW1lOiBcInRleHQveC1ycG0tY2hhbmdlc1wiLCBtb2RlOiBcInJwbVwifSxcclxuICAgIHtuYW1lOiBcIlJQTSBTcGVjXCIsIG1pbWU6IFwidGV4dC94LXJwbS1zcGVjXCIsIG1vZGU6IFwicnBtXCIsIGV4dDogW1wic3BlY1wiXX0sXHJcbiAgICB7bmFtZTogXCJSdWJ5XCIsIG1pbWU6IFwidGV4dC94LXJ1YnlcIiwgbW9kZTogXCJydWJ5XCIsIGV4dDogW1wicmJcIl0sIGFsaWFzOiBbXCJqcnVieVwiLCBcIm1hY3J1YnlcIiwgXCJyYWtlXCIsIFwicmJcIiwgXCJyYnhcIl19LFxyXG4gICAge25hbWU6IFwiUnVzdFwiLCBtaW1lOiBcInRleHQveC1ydXN0c3JjXCIsIG1vZGU6IFwicnVzdFwiLCBleHQ6IFtcInJzXCJdfSxcclxuICAgIHtuYW1lOiBcIlNhc3NcIiwgbWltZTogXCJ0ZXh0L3gtc2Fzc1wiLCBtb2RlOiBcInNhc3NcIiwgZXh0OiBbXCJzYXNzXCJdfSxcclxuICAgIHtuYW1lOiBcIlNjYWxhXCIsIG1pbWU6IFwidGV4dC94LXNjYWxhXCIsIG1vZGU6IFwiY2xpa2VcIiwgZXh0OiBbXCJzY2FsYVwiXX0sXHJcbiAgICB7bmFtZTogXCJTY2hlbWVcIiwgbWltZTogXCJ0ZXh0L3gtc2NoZW1lXCIsIG1vZGU6IFwic2NoZW1lXCIsIGV4dDogW1wic2NtXCIsIFwic3NcIl19LFxyXG4gICAge25hbWU6IFwiU0NTU1wiLCBtaW1lOiBcInRleHQveC1zY3NzXCIsIG1vZGU6IFwiY3NzXCIsIGV4dDogW1wic2Nzc1wiXX0sXHJcbiAgICB7bmFtZTogXCJTaGVsbFwiLCBtaW1lOiBcInRleHQveC1zaFwiLCBtb2RlOiBcInNoZWxsXCIsIGV4dDogW1wic2hcIiwgXCJrc2hcIiwgXCJiYXNoXCJdLCBhbGlhczogW1wiYmFzaFwiLCBcInNoXCIsIFwienNoXCJdLCBmaWxlOiAvXlBLR0JVSUxEJC99LFxyXG4gICAge25hbWU6IFwiU2lldmVcIiwgbWltZTogXCJhcHBsaWNhdGlvbi9zaWV2ZVwiLCBtb2RlOiBcInNpZXZlXCIsIGV4dDogW1wic2l2XCIsIFwic2lldmVcIl19LFxyXG4gICAge25hbWU6IFwiU2xpbVwiLCBtaW1lczogW1widGV4dC94LXNsaW1cIiwgXCJhcHBsaWNhdGlvbi94LXNsaW1cIl0sIG1vZGU6IFwic2xpbVwiLCBleHQ6IFtcInNsaW1cIl19LFxyXG4gICAge25hbWU6IFwiU21hbGx0YWxrXCIsIG1pbWU6IFwidGV4dC94LXN0c3JjXCIsIG1vZGU6IFwic21hbGx0YWxrXCIsIGV4dDogW1wic3RcIl19LFxyXG4gICAge25hbWU6IFwiU21hcnR5XCIsIG1pbWU6IFwidGV4dC94LXNtYXJ0eVwiLCBtb2RlOiBcInNtYXJ0eVwiLCBleHQ6IFtcInRwbFwiXX0sXHJcbiAgICB7bmFtZTogXCJTb2xyXCIsIG1pbWU6IFwidGV4dC94LXNvbHJcIiwgbW9kZTogXCJzb2xyXCJ9LFxyXG4gICAge25hbWU6IFwiU295XCIsIG1pbWU6IFwidGV4dC94LXNveVwiLCBtb2RlOiBcInNveVwiLCBleHQ6IFtcInNveVwiXSwgYWxpYXM6IFtcImNsb3N1cmUgdGVtcGxhdGVcIl19LFxyXG4gICAge25hbWU6IFwiU1BBUlFMXCIsIG1pbWU6IFwiYXBwbGljYXRpb24vc3BhcnFsLXF1ZXJ5XCIsIG1vZGU6IFwic3BhcnFsXCIsIGV4dDogW1wicnFcIiwgXCJzcGFycWxcIl0sIGFsaWFzOiBbXCJzcGFydWxcIl19LFxyXG4gICAge25hbWU6IFwiU3ByZWFkc2hlZXRcIiwgbWltZTogXCJ0ZXh0L3gtc3ByZWFkc2hlZXRcIiwgbW9kZTogXCJzcHJlYWRzaGVldFwiLCBhbGlhczogW1wiZXhjZWxcIiwgXCJmb3JtdWxhXCJdfSxcclxuICAgIHtuYW1lOiBcIlNRTFwiLCBtaW1lOiBcInRleHQveC1zcWxcIiwgbW9kZTogXCJzcWxcIiwgZXh0OiBbXCJzcWxcIl19LFxyXG4gICAge25hbWU6IFwiU3F1aXJyZWxcIiwgbWltZTogXCJ0ZXh0L3gtc3F1aXJyZWxcIiwgbW9kZTogXCJjbGlrZVwiLCBleHQ6IFtcIm51dFwiXX0sXHJcbiAgICB7bmFtZTogXCJTd2lmdFwiLCBtaW1lOiBcInRleHQveC1zd2lmdFwiLCBtb2RlOiBcInN3aWZ0XCIsIGV4dDogW1wic3dpZnRcIl19LFxyXG4gICAge25hbWU6IFwiTWFyaWFEQlwiLCBtaW1lOiBcInRleHQveC1tYXJpYWRiXCIsIG1vZGU6IFwic3FsXCJ9LFxyXG4gICAge25hbWU6IFwic1RlWFwiLCBtaW1lOiBcInRleHQveC1zdGV4XCIsIG1vZGU6IFwic3RleFwifSxcclxuICAgIHtuYW1lOiBcIkxhVGVYXCIsIG1pbWU6IFwidGV4dC94LWxhdGV4XCIsIG1vZGU6IFwic3RleFwiLCBleHQ6IFtcInRleHRcIiwgXCJsdHhcIl0sIGFsaWFzOiBbXCJ0ZXhcIl19LFxyXG4gICAge25hbWU6IFwiU3lzdGVtVmVyaWxvZ1wiLCBtaW1lOiBcInRleHQveC1zeXN0ZW12ZXJpbG9nXCIsIG1vZGU6IFwidmVyaWxvZ1wiLCBleHQ6IFtcInZcIl19LFxyXG4gICAge25hbWU6IFwiVGNsXCIsIG1pbWU6IFwidGV4dC94LXRjbFwiLCBtb2RlOiBcInRjbFwiLCBleHQ6IFtcInRjbFwiXX0sXHJcbiAgICB7bmFtZTogXCJUZXh0aWxlXCIsIG1pbWU6IFwidGV4dC94LXRleHRpbGVcIiwgbW9kZTogXCJ0ZXh0aWxlXCIsIGV4dDogW1widGV4dGlsZVwiXX0sXHJcbiAgICB7bmFtZTogXCJUaWRkbHlXaWtpIFwiLCBtaW1lOiBcInRleHQveC10aWRkbHl3aWtpXCIsIG1vZGU6IFwidGlkZGx5d2lraVwifSxcclxuICAgIHtuYW1lOiBcIlRpa2kgd2lraVwiLCBtaW1lOiBcInRleHQvdGlraVwiLCBtb2RlOiBcInRpa2lcIn0sXHJcbiAgICB7bmFtZTogXCJUT01MXCIsIG1pbWU6IFwidGV4dC94LXRvbWxcIiwgbW9kZTogXCJ0b21sXCIsIGV4dDogW1widG9tbFwiXX0sXHJcbiAgICB7bmFtZTogXCJUb3JuYWRvXCIsIG1pbWU6IFwidGV4dC94LXRvcm5hZG9cIiwgbW9kZTogXCJ0b3JuYWRvXCJ9LFxyXG4gICAge25hbWU6IFwidHJvZmZcIiwgbWltZTogXCJ0cm9mZlwiLCBtb2RlOiBcInRyb2ZmXCIsIGV4dDogW1wiMVwiLCBcIjJcIiwgXCIzXCIsIFwiNFwiLCBcIjVcIiwgXCI2XCIsIFwiN1wiLCBcIjhcIiwgXCI5XCJdfSxcclxuICAgIHtuYW1lOiBcIlRUQ05cIiwgbWltZTogXCJ0ZXh0L3gtdHRjblwiLCBtb2RlOiBcInR0Y25cIiwgZXh0OiBbXCJ0dGNuXCIsIFwidHRjbjNcIiwgXCJ0dGNucHBcIl19LFxyXG4gICAge25hbWU6IFwiVFRDTl9DRkdcIiwgbWltZTogXCJ0ZXh0L3gtdHRjbi1jZmdcIiwgbW9kZTogXCJ0dGNuLWNmZ1wiLCBleHQ6IFtcImNmZ1wiXX0sXHJcbiAgICB7bmFtZTogXCJUdXJ0bGVcIiwgbWltZTogXCJ0ZXh0L3R1cnRsZVwiLCBtb2RlOiBcInR1cnRsZVwiLCBleHQ6IFtcInR0bFwiXX0sXHJcbiAgICB7bmFtZTogXCJUeXBlU2NyaXB0XCIsIG1pbWU6IFwiYXBwbGljYXRpb24vdHlwZXNjcmlwdFwiLCBtb2RlOiBcImphdmFzY3JpcHRcIiwgZXh0OiBbXCJ0c1wiXSwgYWxpYXM6IFtcInRzXCJdfSxcclxuICAgIHtuYW1lOiBcIlR3aWdcIiwgbWltZTogXCJ0ZXh0L3gtdHdpZ1wiLCBtb2RlOiBcInR3aWdcIn0sXHJcbiAgICB7bmFtZTogXCJWQi5ORVRcIiwgbWltZTogXCJ0ZXh0L3gtdmJcIiwgbW9kZTogXCJ2YlwiLCBleHQ6IFtcInZiXCJdfSxcclxuICAgIHtuYW1lOiBcIlZCU2NyaXB0XCIsIG1pbWU6IFwidGV4dC92YnNjcmlwdFwiLCBtb2RlOiBcInZic2NyaXB0XCIsIGV4dDogW1widmJzXCJdfSxcclxuICAgIHtuYW1lOiBcIlZlbG9jaXR5XCIsIG1pbWU6IFwidGV4dC92ZWxvY2l0eVwiLCBtb2RlOiBcInZlbG9jaXR5XCIsIGV4dDogW1widnRsXCJdfSxcclxuICAgIHtuYW1lOiBcIlZlcmlsb2dcIiwgbWltZTogXCJ0ZXh0L3gtdmVyaWxvZ1wiLCBtb2RlOiBcInZlcmlsb2dcIiwgZXh0OiBbXCJ2XCJdfSxcclxuICAgIHtuYW1lOiBcIlZIRExcIiwgbWltZTogXCJ0ZXh0L3gtdmhkbFwiLCBtb2RlOiBcInZoZGxcIiwgZXh0OiBbXCJ2aGRcIiwgXCJ2aGRsXCJdfSxcclxuICAgIHtuYW1lOiBcIlhNTFwiLCBtaW1lczogW1wiYXBwbGljYXRpb24veG1sXCIsIFwidGV4dC94bWxcIl0sIG1vZGU6IFwieG1sXCIsIGV4dDogW1wieG1sXCIsIFwieHNsXCIsIFwieHNkXCJdLCBhbGlhczogW1wicnNzXCIsIFwid3NkbFwiLCBcInhzZFwiXX0sXHJcbiAgICB7bmFtZTogXCJYUXVlcnlcIiwgbWltZTogXCJhcHBsaWNhdGlvbi94cXVlcnlcIiwgbW9kZTogXCJ4cXVlcnlcIiwgZXh0OiBbXCJ4eVwiLCBcInhxdWVyeVwiXX0sXHJcbiAgICB7bmFtZTogXCJZQU1MXCIsIG1pbWU6IFwidGV4dC94LXlhbWxcIiwgbW9kZTogXCJ5YW1sXCIsIGV4dDogW1wieWFtbFwiLCBcInltbFwiXSwgYWxpYXM6IFtcInltbFwiXX0sXHJcbiAgICB7bmFtZTogXCJaODBcIiwgbWltZTogXCJ0ZXh0L3gtejgwXCIsIG1vZGU6IFwiejgwXCIsIGV4dDogW1wiejgwXCJdfSxcclxuICAgIHtuYW1lOiBcIm1zY2dlblwiLCBtaW1lOiBcInRleHQveC1tc2NnZW5cIiwgbW9kZTogXCJtc2NnZW5cIiwgZXh0OiBbXCJtc2NnZW5cIiwgXCJtc2NpblwiLCBcIm1zY1wiXX0sXHJcbiAgICB7bmFtZTogXCJ4dVwiLCBtaW1lOiBcInRleHQveC14dVwiLCBtb2RlOiBcIm1zY2dlblwiLCBleHQ6IFtcInh1XCJdfSxcclxuICAgIHtuYW1lOiBcIm1zZ2VubnlcIiwgbWltZTogXCJ0ZXh0L3gtbXNnZW5ueVwiLCBtb2RlOiBcIm1zY2dlblwiLCBleHQ6IFtcIm1zZ2VubnlcIl19XHJcbiAgXTtcclxuICAvLyBFbnN1cmUgYWxsIG1vZGVzIGhhdmUgYSBtaW1lIHByb3BlcnR5IGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eVxyXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgQ29kZU1pcnJvci5tb2RlSW5mby5sZW5ndGg7IGkrKykge1xyXG4gICAgdmFyIGluZm8gPSBDb2RlTWlycm9yLm1vZGVJbmZvW2ldO1xyXG4gICAgaWYgKGluZm8ubWltZXMpIGluZm8ubWltZSA9IGluZm8ubWltZXNbMF07XHJcbiAgfVxyXG5cclxuICBDb2RlTWlycm9yLmZpbmRNb2RlQnlNSU1FID0gZnVuY3Rpb24obWltZSkge1xyXG4gICAgbWltZSA9IG1pbWUudG9Mb3dlckNhc2UoKTtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgQ29kZU1pcnJvci5tb2RlSW5mby5sZW5ndGg7IGkrKykge1xyXG4gICAgICB2YXIgaW5mbyA9IENvZGVNaXJyb3IubW9kZUluZm9baV07XHJcbiAgICAgIGlmIChpbmZvLm1pbWUgPT0gbWltZSkgcmV0dXJuIGluZm87XHJcbiAgICAgIGlmIChpbmZvLm1pbWVzKSBmb3IgKHZhciBqID0gMDsgaiA8IGluZm8ubWltZXMubGVuZ3RoOyBqKyspXHJcbiAgICAgICAgaWYgKGluZm8ubWltZXNbal0gPT0gbWltZSkgcmV0dXJuIGluZm87XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgQ29kZU1pcnJvci5maW5kTW9kZUJ5RXh0ZW5zaW9uID0gZnVuY3Rpb24oZXh0KSB7XHJcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IENvZGVNaXJyb3IubW9kZUluZm8ubGVuZ3RoOyBpKyspIHtcclxuICAgICAgdmFyIGluZm8gPSBDb2RlTWlycm9yLm1vZGVJbmZvW2ldO1xyXG4gICAgICBpZiAoaW5mby5leHQpIGZvciAodmFyIGogPSAwOyBqIDwgaW5mby5leHQubGVuZ3RoOyBqKyspXHJcbiAgICAgICAgaWYgKGluZm8uZXh0W2pdID09IGV4dCkgcmV0dXJuIGluZm87XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgQ29kZU1pcnJvci5maW5kTW9kZUJ5RmlsZU5hbWUgPSBmdW5jdGlvbihmaWxlbmFtZSkge1xyXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBDb2RlTWlycm9yLm1vZGVJbmZvLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIHZhciBpbmZvID0gQ29kZU1pcnJvci5tb2RlSW5mb1tpXTtcclxuICAgICAgaWYgKGluZm8uZmlsZSAmJiBpbmZvLmZpbGUudGVzdChmaWxlbmFtZSkpIHJldHVybiBpbmZvO1xyXG4gICAgfVxyXG4gICAgdmFyIGRvdCA9IGZpbGVuYW1lLmxhc3RJbmRleE9mKFwiLlwiKTtcclxuICAgIHZhciBleHQgPSBkb3QgPiAtMSAmJiBmaWxlbmFtZS5zdWJzdHJpbmcoZG90ICsgMSwgZmlsZW5hbWUubGVuZ3RoKTtcclxuICAgIGlmIChleHQpIHJldHVybiBDb2RlTWlycm9yLmZpbmRNb2RlQnlFeHRlbnNpb24oZXh0KTtcclxuICB9O1xyXG5cclxuICBDb2RlTWlycm9yLmZpbmRNb2RlQnlOYW1lID0gZnVuY3Rpb24obmFtZSkge1xyXG4gICAgbmFtZSA9IG5hbWUudG9Mb3dlckNhc2UoKTtcclxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgQ29kZU1pcnJvci5tb2RlSW5mby5sZW5ndGg7IGkrKykge1xyXG4gICAgICB2YXIgaW5mbyA9IENvZGVNaXJyb3IubW9kZUluZm9baV07XHJcbiAgICAgIGlmIChpbmZvLm5hbWUudG9Mb3dlckNhc2UoKSA9PSBuYW1lKSByZXR1cm4gaW5mbztcclxuICAgICAgaWYgKGluZm8uYWxpYXMpIGZvciAodmFyIGogPSAwOyBqIDwgaW5mby5hbGlhcy5sZW5ndGg7IGorKylcclxuICAgICAgICBpZiAoaW5mby5hbGlhc1tqXS50b0xvd2VyQ2FzZSgpID09IG5hbWUpIHJldHVybiBpbmZvO1xyXG4gICAgfVxyXG4gIH07XHJcbn0pO1xyXG4iLCIvLyBDb2RlTWlycm9yLCBjb3B5cmlnaHQgKGMpIGJ5IE1hcmlqbiBIYXZlcmJla2UgYW5kIG90aGVyc1xyXG4vLyBEaXN0cmlidXRlZCB1bmRlciBhbiBNSVQgbGljZW5zZTogaHR0cDovL2NvZGVtaXJyb3IubmV0L0xJQ0VOU0VcclxuXHJcbihmdW5jdGlvbihtb2QpIHtcclxuICBpZiAodHlwZW9mIGV4cG9ydHMgPT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgbW9kdWxlID09IFwib2JqZWN0XCIpIC8vIENvbW1vbkpTXHJcbiAgICBtb2QocmVxdWlyZShcIi4uLy4uL2xpYi9jb2RlbWlycm9yXCIpKTtcclxuICBlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kKSAvLyBBTURcclxuICAgIGRlZmluZShbXCIuLi8uLi9saWIvY29kZW1pcnJvclwiXSwgbW9kKTtcclxuICBlbHNlIC8vIFBsYWluIGJyb3dzZXIgZW52XHJcbiAgICBtb2QoQ29kZU1pcnJvcik7XHJcbn0pKGZ1bmN0aW9uKENvZGVNaXJyb3IpIHtcclxuXCJ1c2Ugc3RyaWN0XCI7XHJcblxyXG5Db2RlTWlycm9yLmRlZmluZU1vZGUoXCJ4bWxcIiwgZnVuY3Rpb24oY29uZmlnLCBwYXJzZXJDb25maWcpIHtcclxuICB2YXIgaW5kZW50VW5pdCA9IGNvbmZpZy5pbmRlbnRVbml0O1xyXG4gIHZhciBtdWx0aWxpbmVUYWdJbmRlbnRGYWN0b3IgPSBwYXJzZXJDb25maWcubXVsdGlsaW5lVGFnSW5kZW50RmFjdG9yIHx8IDE7XHJcbiAgdmFyIG11bHRpbGluZVRhZ0luZGVudFBhc3RUYWcgPSBwYXJzZXJDb25maWcubXVsdGlsaW5lVGFnSW5kZW50UGFzdFRhZztcclxuICBpZiAobXVsdGlsaW5lVGFnSW5kZW50UGFzdFRhZyA9PSBudWxsKSBtdWx0aWxpbmVUYWdJbmRlbnRQYXN0VGFnID0gdHJ1ZTtcclxuXHJcbiAgdmFyIEtsdWRnZXMgPSBwYXJzZXJDb25maWcuaHRtbE1vZGUgPyB7XHJcbiAgICBhdXRvU2VsZkNsb3NlcnM6IHsnYXJlYSc6IHRydWUsICdiYXNlJzogdHJ1ZSwgJ2JyJzogdHJ1ZSwgJ2NvbCc6IHRydWUsICdjb21tYW5kJzogdHJ1ZSxcclxuICAgICAgICAgICAgICAgICAgICAgICdlbWJlZCc6IHRydWUsICdmcmFtZSc6IHRydWUsICdocic6IHRydWUsICdpbWcnOiB0cnVlLCAnaW5wdXQnOiB0cnVlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgJ2tleWdlbic6IHRydWUsICdsaW5rJzogdHJ1ZSwgJ21ldGEnOiB0cnVlLCAncGFyYW0nOiB0cnVlLCAnc291cmNlJzogdHJ1ZSxcclxuICAgICAgICAgICAgICAgICAgICAgICd0cmFjayc6IHRydWUsICd3YnInOiB0cnVlLCAnbWVudWl0ZW0nOiB0cnVlfSxcclxuICAgIGltcGxpY2l0bHlDbG9zZWQ6IHsnZGQnOiB0cnVlLCAnbGknOiB0cnVlLCAnb3B0Z3JvdXAnOiB0cnVlLCAnb3B0aW9uJzogdHJ1ZSwgJ3AnOiB0cnVlLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICdycCc6IHRydWUsICdydCc6IHRydWUsICd0Ym9keSc6IHRydWUsICd0ZCc6IHRydWUsICd0Zm9vdCc6IHRydWUsXHJcbiAgICAgICAgICAgICAgICAgICAgICAgJ3RoJzogdHJ1ZSwgJ3RyJzogdHJ1ZX0sXHJcbiAgICBjb250ZXh0R3JhYmJlcnM6IHtcclxuICAgICAgJ2RkJzogeydkZCc6IHRydWUsICdkdCc6IHRydWV9LFxyXG4gICAgICAnZHQnOiB7J2RkJzogdHJ1ZSwgJ2R0JzogdHJ1ZX0sXHJcbiAgICAgICdsaSc6IHsnbGknOiB0cnVlfSxcclxuICAgICAgJ29wdGlvbic6IHsnb3B0aW9uJzogdHJ1ZSwgJ29wdGdyb3VwJzogdHJ1ZX0sXHJcbiAgICAgICdvcHRncm91cCc6IHsnb3B0Z3JvdXAnOiB0cnVlfSxcclxuICAgICAgJ3AnOiB7J2FkZHJlc3MnOiB0cnVlLCAnYXJ0aWNsZSc6IHRydWUsICdhc2lkZSc6IHRydWUsICdibG9ja3F1b3RlJzogdHJ1ZSwgJ2Rpcic6IHRydWUsXHJcbiAgICAgICAgICAgICdkaXYnOiB0cnVlLCAnZGwnOiB0cnVlLCAnZmllbGRzZXQnOiB0cnVlLCAnZm9vdGVyJzogdHJ1ZSwgJ2Zvcm0nOiB0cnVlLFxyXG4gICAgICAgICAgICAnaDEnOiB0cnVlLCAnaDInOiB0cnVlLCAnaDMnOiB0cnVlLCAnaDQnOiB0cnVlLCAnaDUnOiB0cnVlLCAnaDYnOiB0cnVlLFxyXG4gICAgICAgICAgICAnaGVhZGVyJzogdHJ1ZSwgJ2hncm91cCc6IHRydWUsICdocic6IHRydWUsICdtZW51JzogdHJ1ZSwgJ25hdic6IHRydWUsICdvbCc6IHRydWUsXHJcbiAgICAgICAgICAgICdwJzogdHJ1ZSwgJ3ByZSc6IHRydWUsICdzZWN0aW9uJzogdHJ1ZSwgJ3RhYmxlJzogdHJ1ZSwgJ3VsJzogdHJ1ZX0sXHJcbiAgICAgICdycCc6IHsncnAnOiB0cnVlLCAncnQnOiB0cnVlfSxcclxuICAgICAgJ3J0JzogeydycCc6IHRydWUsICdydCc6IHRydWV9LFxyXG4gICAgICAndGJvZHknOiB7J3Rib2R5JzogdHJ1ZSwgJ3Rmb290JzogdHJ1ZX0sXHJcbiAgICAgICd0ZCc6IHsndGQnOiB0cnVlLCAndGgnOiB0cnVlfSxcclxuICAgICAgJ3Rmb290Jzogeyd0Ym9keSc6IHRydWV9LFxyXG4gICAgICAndGgnOiB7J3RkJzogdHJ1ZSwgJ3RoJzogdHJ1ZX0sXHJcbiAgICAgICd0aGVhZCc6IHsndGJvZHknOiB0cnVlLCAndGZvb3QnOiB0cnVlfSxcclxuICAgICAgJ3RyJzogeyd0cic6IHRydWV9XHJcbiAgICB9LFxyXG4gICAgZG9Ob3RJbmRlbnQ6IHtcInByZVwiOiB0cnVlfSxcclxuICAgIGFsbG93VW5xdW90ZWQ6IHRydWUsXHJcbiAgICBhbGxvd01pc3Npbmc6IHRydWUsXHJcbiAgICBjYXNlRm9sZDogdHJ1ZVxyXG4gIH0gOiB7XHJcbiAgICBhdXRvU2VsZkNsb3NlcnM6IHt9LFxyXG4gICAgaW1wbGljaXRseUNsb3NlZDoge30sXHJcbiAgICBjb250ZXh0R3JhYmJlcnM6IHt9LFxyXG4gICAgZG9Ob3RJbmRlbnQ6IHt9LFxyXG4gICAgYWxsb3dVbnF1b3RlZDogZmFsc2UsXHJcbiAgICBhbGxvd01pc3Npbmc6IGZhbHNlLFxyXG4gICAgY2FzZUZvbGQ6IGZhbHNlXHJcbiAgfTtcclxuICB2YXIgYWxpZ25DREFUQSA9IHBhcnNlckNvbmZpZy5hbGlnbkNEQVRBO1xyXG5cclxuICAvLyBSZXR1cm4gdmFyaWFibGVzIGZvciB0b2tlbml6ZXJzXHJcbiAgdmFyIHR5cGUsIHNldFN0eWxlO1xyXG5cclxuICBmdW5jdGlvbiBpblRleHQoc3RyZWFtLCBzdGF0ZSkge1xyXG4gICAgZnVuY3Rpb24gY2hhaW4ocGFyc2VyKSB7XHJcbiAgICAgIHN0YXRlLnRva2VuaXplID0gcGFyc2VyO1xyXG4gICAgICByZXR1cm4gcGFyc2VyKHN0cmVhbSwgc3RhdGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHZhciBjaCA9IHN0cmVhbS5uZXh0KCk7XHJcbiAgICBpZiAoY2ggPT0gXCI8XCIpIHtcclxuICAgICAgaWYgKHN0cmVhbS5lYXQoXCIhXCIpKSB7XHJcbiAgICAgICAgaWYgKHN0cmVhbS5lYXQoXCJbXCIpKSB7XHJcbiAgICAgICAgICBpZiAoc3RyZWFtLm1hdGNoKFwiQ0RBVEFbXCIpKSByZXR1cm4gY2hhaW4oaW5CbG9jayhcImF0b21cIiwgXCJdXT5cIikpO1xyXG4gICAgICAgICAgZWxzZSByZXR1cm4gbnVsbDtcclxuICAgICAgICB9IGVsc2UgaWYgKHN0cmVhbS5tYXRjaChcIi0tXCIpKSB7XHJcbiAgICAgICAgICByZXR1cm4gY2hhaW4oaW5CbG9jayhcImNvbW1lbnRcIiwgXCItLT5cIikpO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoc3RyZWFtLm1hdGNoKFwiRE9DVFlQRVwiLCB0cnVlLCB0cnVlKSkge1xyXG4gICAgICAgICAgc3RyZWFtLmVhdFdoaWxlKC9bXFx3XFwuX1xcLV0vKTtcclxuICAgICAgICAgIHJldHVybiBjaGFpbihkb2N0eXBlKDEpKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2UgaWYgKHN0cmVhbS5lYXQoXCI/XCIpKSB7XHJcbiAgICAgICAgc3RyZWFtLmVhdFdoaWxlKC9bXFx3XFwuX1xcLV0vKTtcclxuICAgICAgICBzdGF0ZS50b2tlbml6ZSA9IGluQmxvY2soXCJtZXRhXCIsIFwiPz5cIik7XHJcbiAgICAgICAgcmV0dXJuIFwibWV0YVwiO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHR5cGUgPSBzdHJlYW0uZWF0KFwiL1wiKSA/IFwiY2xvc2VUYWdcIiA6IFwib3BlblRhZ1wiO1xyXG4gICAgICAgIHN0YXRlLnRva2VuaXplID0gaW5UYWc7XHJcbiAgICAgICAgcmV0dXJuIFwidGFnIGJyYWNrZXRcIjtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIGlmIChjaCA9PSBcIiZcIikge1xyXG4gICAgICB2YXIgb2s7XHJcbiAgICAgIGlmIChzdHJlYW0uZWF0KFwiI1wiKSkge1xyXG4gICAgICAgIGlmIChzdHJlYW0uZWF0KFwieFwiKSkge1xyXG4gICAgICAgICAgb2sgPSBzdHJlYW0uZWF0V2hpbGUoL1thLWZBLUZcXGRdLykgJiYgc3RyZWFtLmVhdChcIjtcIik7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIG9rID0gc3RyZWFtLmVhdFdoaWxlKC9bXFxkXS8pICYmIHN0cmVhbS5lYXQoXCI7XCIpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBvayA9IHN0cmVhbS5lYXRXaGlsZSgvW1xcd1xcLlxcLTpdLykgJiYgc3RyZWFtLmVhdChcIjtcIik7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9rID8gXCJhdG9tXCIgOiBcImVycm9yXCI7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBzdHJlYW0uZWF0V2hpbGUoL1teJjxdLyk7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG4gIH1cclxuICBpblRleHQuaXNJblRleHQgPSB0cnVlO1xyXG5cclxuICBmdW5jdGlvbiBpblRhZyhzdHJlYW0sIHN0YXRlKSB7XHJcbiAgICB2YXIgY2ggPSBzdHJlYW0ubmV4dCgpO1xyXG4gICAgaWYgKGNoID09IFwiPlwiIHx8IChjaCA9PSBcIi9cIiAmJiBzdHJlYW0uZWF0KFwiPlwiKSkpIHtcclxuICAgICAgc3RhdGUudG9rZW5pemUgPSBpblRleHQ7XHJcbiAgICAgIHR5cGUgPSBjaCA9PSBcIj5cIiA/IFwiZW5kVGFnXCIgOiBcInNlbGZjbG9zZVRhZ1wiO1xyXG4gICAgICByZXR1cm4gXCJ0YWcgYnJhY2tldFwiO1xyXG4gICAgfSBlbHNlIGlmIChjaCA9PSBcIj1cIikge1xyXG4gICAgICB0eXBlID0gXCJlcXVhbHNcIjtcclxuICAgICAgcmV0dXJuIG51bGw7XHJcbiAgICB9IGVsc2UgaWYgKGNoID09IFwiPFwiKSB7XHJcbiAgICAgIHN0YXRlLnRva2VuaXplID0gaW5UZXh0O1xyXG4gICAgICBzdGF0ZS5zdGF0ZSA9IGJhc2VTdGF0ZTtcclxuICAgICAgc3RhdGUudGFnTmFtZSA9IHN0YXRlLnRhZ1N0YXJ0ID0gbnVsbDtcclxuICAgICAgdmFyIG5leHQgPSBzdGF0ZS50b2tlbml6ZShzdHJlYW0sIHN0YXRlKTtcclxuICAgICAgcmV0dXJuIG5leHQgPyBuZXh0ICsgXCIgdGFnIGVycm9yXCIgOiBcInRhZyBlcnJvclwiO1xyXG4gICAgfSBlbHNlIGlmICgvW1xcJ1xcXCJdLy50ZXN0KGNoKSkge1xyXG4gICAgICBzdGF0ZS50b2tlbml6ZSA9IGluQXR0cmlidXRlKGNoKTtcclxuICAgICAgc3RhdGUuc3RyaW5nU3RhcnRDb2wgPSBzdHJlYW0uY29sdW1uKCk7XHJcbiAgICAgIHJldHVybiBzdGF0ZS50b2tlbml6ZShzdHJlYW0sIHN0YXRlKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHN0cmVhbS5tYXRjaCgvXlteXFxzXFx1MDBhMD08PlxcXCJcXCddKlteXFxzXFx1MDBhMD08PlxcXCJcXCdcXC9dLyk7XHJcbiAgICAgIHJldHVybiBcIndvcmRcIjtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIGluQXR0cmlidXRlKHF1b3RlKSB7XHJcbiAgICB2YXIgY2xvc3VyZSA9IGZ1bmN0aW9uKHN0cmVhbSwgc3RhdGUpIHtcclxuICAgICAgd2hpbGUgKCFzdHJlYW0uZW9sKCkpIHtcclxuICAgICAgICBpZiAoc3RyZWFtLm5leHQoKSA9PSBxdW90ZSkge1xyXG4gICAgICAgICAgc3RhdGUudG9rZW5pemUgPSBpblRhZztcclxuICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gXCJzdHJpbmdcIjtcclxuICAgIH07XHJcbiAgICBjbG9zdXJlLmlzSW5BdHRyaWJ1dGUgPSB0cnVlO1xyXG4gICAgcmV0dXJuIGNsb3N1cmU7XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBpbkJsb2NrKHN0eWxlLCB0ZXJtaW5hdG9yKSB7XHJcbiAgICByZXR1cm4gZnVuY3Rpb24oc3RyZWFtLCBzdGF0ZSkge1xyXG4gICAgICB3aGlsZSAoIXN0cmVhbS5lb2woKSkge1xyXG4gICAgICAgIGlmIChzdHJlYW0ubWF0Y2godGVybWluYXRvcikpIHtcclxuICAgICAgICAgIHN0YXRlLnRva2VuaXplID0gaW5UZXh0O1xyXG4gICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHN0cmVhbS5uZXh0KCk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHN0eWxlO1xyXG4gICAgfTtcclxuICB9XHJcbiAgZnVuY3Rpb24gZG9jdHlwZShkZXB0aCkge1xyXG4gICAgcmV0dXJuIGZ1bmN0aW9uKHN0cmVhbSwgc3RhdGUpIHtcclxuICAgICAgdmFyIGNoO1xyXG4gICAgICB3aGlsZSAoKGNoID0gc3RyZWFtLm5leHQoKSkgIT0gbnVsbCkge1xyXG4gICAgICAgIGlmIChjaCA9PSBcIjxcIikge1xyXG4gICAgICAgICAgc3RhdGUudG9rZW5pemUgPSBkb2N0eXBlKGRlcHRoICsgMSk7XHJcbiAgICAgICAgICByZXR1cm4gc3RhdGUudG9rZW5pemUoc3RyZWFtLCBzdGF0ZSk7XHJcbiAgICAgICAgfSBlbHNlIGlmIChjaCA9PSBcIj5cIikge1xyXG4gICAgICAgICAgaWYgKGRlcHRoID09IDEpIHtcclxuICAgICAgICAgICAgc3RhdGUudG9rZW5pemUgPSBpblRleHQ7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgc3RhdGUudG9rZW5pemUgPSBkb2N0eXBlKGRlcHRoIC0gMSk7XHJcbiAgICAgICAgICAgIHJldHVybiBzdGF0ZS50b2tlbml6ZShzdHJlYW0sIHN0YXRlKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIFwibWV0YVwiO1xyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIGZ1bmN0aW9uIENvbnRleHQoc3RhdGUsIHRhZ05hbWUsIHN0YXJ0T2ZMaW5lKSB7XHJcbiAgICB0aGlzLnByZXYgPSBzdGF0ZS5jb250ZXh0O1xyXG4gICAgdGhpcy50YWdOYW1lID0gdGFnTmFtZTtcclxuICAgIHRoaXMuaW5kZW50ID0gc3RhdGUuaW5kZW50ZWQ7XHJcbiAgICB0aGlzLnN0YXJ0T2ZMaW5lID0gc3RhcnRPZkxpbmU7XHJcbiAgICBpZiAoS2x1ZGdlcy5kb05vdEluZGVudC5oYXNPd25Qcm9wZXJ0eSh0YWdOYW1lKSB8fCAoc3RhdGUuY29udGV4dCAmJiBzdGF0ZS5jb250ZXh0Lm5vSW5kZW50KSlcclxuICAgICAgdGhpcy5ub0luZGVudCA9IHRydWU7XHJcbiAgfVxyXG4gIGZ1bmN0aW9uIHBvcENvbnRleHQoc3RhdGUpIHtcclxuICAgIGlmIChzdGF0ZS5jb250ZXh0KSBzdGF0ZS5jb250ZXh0ID0gc3RhdGUuY29udGV4dC5wcmV2O1xyXG4gIH1cclxuICBmdW5jdGlvbiBtYXliZVBvcENvbnRleHQoc3RhdGUsIG5leHRUYWdOYW1lKSB7XHJcbiAgICB2YXIgcGFyZW50VGFnTmFtZTtcclxuICAgIHdoaWxlICh0cnVlKSB7XHJcbiAgICAgIGlmICghc3RhdGUuY29udGV4dCkge1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG4gICAgICBwYXJlbnRUYWdOYW1lID0gc3RhdGUuY29udGV4dC50YWdOYW1lO1xyXG4gICAgICBpZiAoIUtsdWRnZXMuY29udGV4dEdyYWJiZXJzLmhhc093blByb3BlcnR5KHBhcmVudFRhZ05hbWUpIHx8XHJcbiAgICAgICAgICAhS2x1ZGdlcy5jb250ZXh0R3JhYmJlcnNbcGFyZW50VGFnTmFtZV0uaGFzT3duUHJvcGVydHkobmV4dFRhZ05hbWUpKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcbiAgICAgIHBvcENvbnRleHQoc3RhdGUpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gYmFzZVN0YXRlKHR5cGUsIHN0cmVhbSwgc3RhdGUpIHtcclxuICAgIGlmICh0eXBlID09IFwib3BlblRhZ1wiKSB7XHJcbiAgICAgIHN0YXRlLnRhZ1N0YXJ0ID0gc3RyZWFtLmNvbHVtbigpO1xyXG4gICAgICByZXR1cm4gdGFnTmFtZVN0YXRlO1xyXG4gICAgfSBlbHNlIGlmICh0eXBlID09IFwiY2xvc2VUYWdcIikge1xyXG4gICAgICByZXR1cm4gY2xvc2VUYWdOYW1lU3RhdGU7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICByZXR1cm4gYmFzZVN0YXRlO1xyXG4gICAgfVxyXG4gIH1cclxuICBmdW5jdGlvbiB0YWdOYW1lU3RhdGUodHlwZSwgc3RyZWFtLCBzdGF0ZSkge1xyXG4gICAgaWYgKHR5cGUgPT0gXCJ3b3JkXCIpIHtcclxuICAgICAgc3RhdGUudGFnTmFtZSA9IHN0cmVhbS5jdXJyZW50KCk7XHJcbiAgICAgIHNldFN0eWxlID0gXCJ0YWdcIjtcclxuICAgICAgcmV0dXJuIGF0dHJTdGF0ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHNldFN0eWxlID0gXCJlcnJvclwiO1xyXG4gICAgICByZXR1cm4gdGFnTmFtZVN0YXRlO1xyXG4gICAgfVxyXG4gIH1cclxuICBmdW5jdGlvbiBjbG9zZVRhZ05hbWVTdGF0ZSh0eXBlLCBzdHJlYW0sIHN0YXRlKSB7XHJcbiAgICBpZiAodHlwZSA9PSBcIndvcmRcIikge1xyXG4gICAgICB2YXIgdGFnTmFtZSA9IHN0cmVhbS5jdXJyZW50KCk7XHJcbiAgICAgIGlmIChzdGF0ZS5jb250ZXh0ICYmIHN0YXRlLmNvbnRleHQudGFnTmFtZSAhPSB0YWdOYW1lICYmXHJcbiAgICAgICAgICBLbHVkZ2VzLmltcGxpY2l0bHlDbG9zZWQuaGFzT3duUHJvcGVydHkoc3RhdGUuY29udGV4dC50YWdOYW1lKSlcclxuICAgICAgICBwb3BDb250ZXh0KHN0YXRlKTtcclxuICAgICAgaWYgKHN0YXRlLmNvbnRleHQgJiYgc3RhdGUuY29udGV4dC50YWdOYW1lID09IHRhZ05hbWUpIHtcclxuICAgICAgICBzZXRTdHlsZSA9IFwidGFnXCI7XHJcbiAgICAgICAgcmV0dXJuIGNsb3NlU3RhdGU7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgc2V0U3R5bGUgPSBcInRhZyBlcnJvclwiO1xyXG4gICAgICAgIHJldHVybiBjbG9zZVN0YXRlRXJyO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBzZXRTdHlsZSA9IFwiZXJyb3JcIjtcclxuICAgICAgcmV0dXJuIGNsb3NlU3RhdGVFcnI7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBmdW5jdGlvbiBjbG9zZVN0YXRlKHR5cGUsIF9zdHJlYW0sIHN0YXRlKSB7XHJcbiAgICBpZiAodHlwZSAhPSBcImVuZFRhZ1wiKSB7XHJcbiAgICAgIHNldFN0eWxlID0gXCJlcnJvclwiO1xyXG4gICAgICByZXR1cm4gY2xvc2VTdGF0ZTtcclxuICAgIH1cclxuICAgIHBvcENvbnRleHQoc3RhdGUpO1xyXG4gICAgcmV0dXJuIGJhc2VTdGF0ZTtcclxuICB9XHJcbiAgZnVuY3Rpb24gY2xvc2VTdGF0ZUVycih0eXBlLCBzdHJlYW0sIHN0YXRlKSB7XHJcbiAgICBzZXRTdHlsZSA9IFwiZXJyb3JcIjtcclxuICAgIHJldHVybiBjbG9zZVN0YXRlKHR5cGUsIHN0cmVhbSwgc3RhdGUpO1xyXG4gIH1cclxuXHJcbiAgZnVuY3Rpb24gYXR0clN0YXRlKHR5cGUsIF9zdHJlYW0sIHN0YXRlKSB7XHJcbiAgICBpZiAodHlwZSA9PSBcIndvcmRcIikge1xyXG4gICAgICBzZXRTdHlsZSA9IFwiYXR0cmlidXRlXCI7XHJcbiAgICAgIHJldHVybiBhdHRyRXFTdGF0ZTtcclxuICAgIH0gZWxzZSBpZiAodHlwZSA9PSBcImVuZFRhZ1wiIHx8IHR5cGUgPT0gXCJzZWxmY2xvc2VUYWdcIikge1xyXG4gICAgICB2YXIgdGFnTmFtZSA9IHN0YXRlLnRhZ05hbWUsIHRhZ1N0YXJ0ID0gc3RhdGUudGFnU3RhcnQ7XHJcbiAgICAgIHN0YXRlLnRhZ05hbWUgPSBzdGF0ZS50YWdTdGFydCA9IG51bGw7XHJcbiAgICAgIGlmICh0eXBlID09IFwic2VsZmNsb3NlVGFnXCIgfHxcclxuICAgICAgICAgIEtsdWRnZXMuYXV0b1NlbGZDbG9zZXJzLmhhc093blByb3BlcnR5KHRhZ05hbWUpKSB7XHJcbiAgICAgICAgbWF5YmVQb3BDb250ZXh0KHN0YXRlLCB0YWdOYW1lKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBtYXliZVBvcENvbnRleHQoc3RhdGUsIHRhZ05hbWUpO1xyXG4gICAgICAgIHN0YXRlLmNvbnRleHQgPSBuZXcgQ29udGV4dChzdGF0ZSwgdGFnTmFtZSwgdGFnU3RhcnQgPT0gc3RhdGUuaW5kZW50ZWQpO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBiYXNlU3RhdGU7XHJcbiAgICB9XHJcbiAgICBzZXRTdHlsZSA9IFwiZXJyb3JcIjtcclxuICAgIHJldHVybiBhdHRyU3RhdGU7XHJcbiAgfVxyXG4gIGZ1bmN0aW9uIGF0dHJFcVN0YXRlKHR5cGUsIHN0cmVhbSwgc3RhdGUpIHtcclxuICAgIGlmICh0eXBlID09IFwiZXF1YWxzXCIpIHJldHVybiBhdHRyVmFsdWVTdGF0ZTtcclxuICAgIGlmICghS2x1ZGdlcy5hbGxvd01pc3NpbmcpIHNldFN0eWxlID0gXCJlcnJvclwiO1xyXG4gICAgcmV0dXJuIGF0dHJTdGF0ZSh0eXBlLCBzdHJlYW0sIHN0YXRlKTtcclxuICB9XHJcbiAgZnVuY3Rpb24gYXR0clZhbHVlU3RhdGUodHlwZSwgc3RyZWFtLCBzdGF0ZSkge1xyXG4gICAgaWYgKHR5cGUgPT0gXCJzdHJpbmdcIikgcmV0dXJuIGF0dHJDb250aW51ZWRTdGF0ZTtcclxuICAgIGlmICh0eXBlID09IFwid29yZFwiICYmIEtsdWRnZXMuYWxsb3dVbnF1b3RlZCkge3NldFN0eWxlID0gXCJzdHJpbmdcIjsgcmV0dXJuIGF0dHJTdGF0ZTt9XHJcbiAgICBzZXRTdHlsZSA9IFwiZXJyb3JcIjtcclxuICAgIHJldHVybiBhdHRyU3RhdGUodHlwZSwgc3RyZWFtLCBzdGF0ZSk7XHJcbiAgfVxyXG4gIGZ1bmN0aW9uIGF0dHJDb250aW51ZWRTdGF0ZSh0eXBlLCBzdHJlYW0sIHN0YXRlKSB7XHJcbiAgICBpZiAodHlwZSA9PSBcInN0cmluZ1wiKSByZXR1cm4gYXR0ckNvbnRpbnVlZFN0YXRlO1xyXG4gICAgcmV0dXJuIGF0dHJTdGF0ZSh0eXBlLCBzdHJlYW0sIHN0YXRlKTtcclxuICB9XHJcblxyXG4gIHJldHVybiB7XHJcbiAgICBzdGFydFN0YXRlOiBmdW5jdGlvbigpIHtcclxuICAgICAgcmV0dXJuIHt0b2tlbml6ZTogaW5UZXh0LFxyXG4gICAgICAgICAgICAgIHN0YXRlOiBiYXNlU3RhdGUsXHJcbiAgICAgICAgICAgICAgaW5kZW50ZWQ6IDAsXHJcbiAgICAgICAgICAgICAgdGFnTmFtZTogbnVsbCwgdGFnU3RhcnQ6IG51bGwsXHJcbiAgICAgICAgICAgICAgY29udGV4dDogbnVsbH07XHJcbiAgICB9LFxyXG5cclxuICAgIHRva2VuOiBmdW5jdGlvbihzdHJlYW0sIHN0YXRlKSB7XHJcbiAgICAgIGlmICghc3RhdGUudGFnTmFtZSAmJiBzdHJlYW0uc29sKCkpXHJcbiAgICAgICAgc3RhdGUuaW5kZW50ZWQgPSBzdHJlYW0uaW5kZW50YXRpb24oKTtcclxuXHJcbiAgICAgIGlmIChzdHJlYW0uZWF0U3BhY2UoKSkgcmV0dXJuIG51bGw7XHJcbiAgICAgIHR5cGUgPSBudWxsO1xyXG4gICAgICB2YXIgc3R5bGUgPSBzdGF0ZS50b2tlbml6ZShzdHJlYW0sIHN0YXRlKTtcclxuICAgICAgaWYgKChzdHlsZSB8fCB0eXBlKSAmJiBzdHlsZSAhPSBcImNvbW1lbnRcIikge1xyXG4gICAgICAgIHNldFN0eWxlID0gbnVsbDtcclxuICAgICAgICBzdGF0ZS5zdGF0ZSA9IHN0YXRlLnN0YXRlKHR5cGUgfHwgc3R5bGUsIHN0cmVhbSwgc3RhdGUpO1xyXG4gICAgICAgIGlmIChzZXRTdHlsZSlcclxuICAgICAgICAgIHN0eWxlID0gc2V0U3R5bGUgPT0gXCJlcnJvclwiID8gc3R5bGUgKyBcIiBlcnJvclwiIDogc2V0U3R5bGU7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHN0eWxlO1xyXG4gICAgfSxcclxuXHJcbiAgICBpbmRlbnQ6IGZ1bmN0aW9uKHN0YXRlLCB0ZXh0QWZ0ZXIsIGZ1bGxMaW5lKSB7XHJcbiAgICAgIHZhciBjb250ZXh0ID0gc3RhdGUuY29udGV4dDtcclxuICAgICAgLy8gSW5kZW50IG11bHRpLWxpbmUgc3RyaW5ncyAoZS5nLiBjc3MpLlxyXG4gICAgICBpZiAoc3RhdGUudG9rZW5pemUuaXNJbkF0dHJpYnV0ZSkge1xyXG4gICAgICAgIGlmIChzdGF0ZS50YWdTdGFydCA9PSBzdGF0ZS5pbmRlbnRlZClcclxuICAgICAgICAgIHJldHVybiBzdGF0ZS5zdHJpbmdTdGFydENvbCArIDE7XHJcbiAgICAgICAgZWxzZVxyXG4gICAgICAgICAgcmV0dXJuIHN0YXRlLmluZGVudGVkICsgaW5kZW50VW5pdDtcclxuICAgICAgfVxyXG4gICAgICBpZiAoY29udGV4dCAmJiBjb250ZXh0Lm5vSW5kZW50KSByZXR1cm4gQ29kZU1pcnJvci5QYXNzO1xyXG4gICAgICBpZiAoc3RhdGUudG9rZW5pemUgIT0gaW5UYWcgJiYgc3RhdGUudG9rZW5pemUgIT0gaW5UZXh0KVxyXG4gICAgICAgIHJldHVybiBmdWxsTGluZSA/IGZ1bGxMaW5lLm1hdGNoKC9eKFxccyopLylbMF0ubGVuZ3RoIDogMDtcclxuICAgICAgLy8gSW5kZW50IHRoZSBzdGFydHMgb2YgYXR0cmlidXRlIG5hbWVzLlxyXG4gICAgICBpZiAoc3RhdGUudGFnTmFtZSkge1xyXG4gICAgICAgIGlmIChtdWx0aWxpbmVUYWdJbmRlbnRQYXN0VGFnKVxyXG4gICAgICAgICAgcmV0dXJuIHN0YXRlLnRhZ1N0YXJ0ICsgc3RhdGUudGFnTmFtZS5sZW5ndGggKyAyO1xyXG4gICAgICAgIGVsc2VcclxuICAgICAgICAgIHJldHVybiBzdGF0ZS50YWdTdGFydCArIGluZGVudFVuaXQgKiBtdWx0aWxpbmVUYWdJbmRlbnRGYWN0b3I7XHJcbiAgICAgIH1cclxuICAgICAgaWYgKGFsaWduQ0RBVEEgJiYgLzwhXFxbQ0RBVEFcXFsvLnRlc3QodGV4dEFmdGVyKSkgcmV0dXJuIDA7XHJcbiAgICAgIHZhciB0YWdBZnRlciA9IHRleHRBZnRlciAmJiAvXjwoXFwvKT8oW1xcd186XFwuLV0qKS8uZXhlYyh0ZXh0QWZ0ZXIpO1xyXG4gICAgICBpZiAodGFnQWZ0ZXIgJiYgdGFnQWZ0ZXJbMV0pIHsgLy8gQ2xvc2luZyB0YWcgc3BvdHRlZFxyXG4gICAgICAgIHdoaWxlIChjb250ZXh0KSB7XHJcbiAgICAgICAgICBpZiAoY29udGV4dC50YWdOYW1lID09IHRhZ0FmdGVyWzJdKSB7XHJcbiAgICAgICAgICAgIGNvbnRleHQgPSBjb250ZXh0LnByZXY7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgfSBlbHNlIGlmIChLbHVkZ2VzLmltcGxpY2l0bHlDbG9zZWQuaGFzT3duUHJvcGVydHkoY29udGV4dC50YWdOYW1lKSkge1xyXG4gICAgICAgICAgICBjb250ZXh0ID0gY29udGV4dC5wcmV2O1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2UgaWYgKHRhZ0FmdGVyKSB7IC8vIE9wZW5pbmcgdGFnIHNwb3R0ZWRcclxuICAgICAgICB3aGlsZSAoY29udGV4dCkge1xyXG4gICAgICAgICAgdmFyIGdyYWJiZXJzID0gS2x1ZGdlcy5jb250ZXh0R3JhYmJlcnNbY29udGV4dC50YWdOYW1lXTtcclxuICAgICAgICAgIGlmIChncmFiYmVycyAmJiBncmFiYmVycy5oYXNPd25Qcm9wZXJ0eSh0YWdBZnRlclsyXSkpXHJcbiAgICAgICAgICAgIGNvbnRleHQgPSBjb250ZXh0LnByZXY7XHJcbiAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICB3aGlsZSAoY29udGV4dCAmJiAhY29udGV4dC5zdGFydE9mTGluZSlcclxuICAgICAgICBjb250ZXh0ID0gY29udGV4dC5wcmV2O1xyXG4gICAgICBpZiAoY29udGV4dCkgcmV0dXJuIGNvbnRleHQuaW5kZW50ICsgaW5kZW50VW5pdDtcclxuICAgICAgZWxzZSByZXR1cm4gMDtcclxuICAgIH0sXHJcblxyXG4gICAgZWxlY3RyaWNJbnB1dDogLzxcXC9bXFxzXFx3Ol0rPiQvLFxyXG4gICAgYmxvY2tDb21tZW50U3RhcnQ6IFwiPCEtLVwiLFxyXG4gICAgYmxvY2tDb21tZW50RW5kOiBcIi0tPlwiLFxyXG5cclxuICAgIGNvbmZpZ3VyYXRpb246IHBhcnNlckNvbmZpZy5odG1sTW9kZSA/IFwiaHRtbFwiIDogXCJ4bWxcIixcclxuICAgIGhlbHBlclR5cGU6IHBhcnNlckNvbmZpZy5odG1sTW9kZSA/IFwiaHRtbFwiIDogXCJ4bWxcIlxyXG4gIH07XHJcbn0pO1xyXG5cclxuQ29kZU1pcnJvci5kZWZpbmVNSU1FKFwidGV4dC94bWxcIiwgXCJ4bWxcIik7XHJcbkNvZGVNaXJyb3IuZGVmaW5lTUlNRShcImFwcGxpY2F0aW9uL3htbFwiLCBcInhtbFwiKTtcclxuaWYgKCFDb2RlTWlycm9yLm1pbWVNb2Rlcy5oYXNPd25Qcm9wZXJ0eShcInRleHQvaHRtbFwiKSlcclxuICBDb2RlTWlycm9yLmRlZmluZU1JTUUoXCJ0ZXh0L2h0bWxcIiwge25hbWU6IFwieG1sXCIsIGh0bWxNb2RlOiB0cnVlfSk7XHJcblxyXG59KTtcclxuIiwiLyoqXHJcbiAqIG1hcmtlZCAtIGEgbWFya2Rvd24gcGFyc2VyXHJcbiAqIENvcHlyaWdodCAoYykgMjAxMS0yMDE0LCBDaHJpc3RvcGhlciBKZWZmcmV5LiAoTUlUIExpY2Vuc2VkKVxyXG4gKiBodHRwczovL2dpdGh1Yi5jb20vY2hqai9tYXJrZWRcclxuICovXHJcblxyXG47KGZ1bmN0aW9uKCkge1xyXG5cclxuLyoqXHJcbiAqIEJsb2NrLUxldmVsIEdyYW1tYXJcclxuICovXHJcblxyXG52YXIgYmxvY2sgPSB7XHJcbiAgbmV3bGluZTogL15cXG4rLyxcclxuICBjb2RlOiAvXiggezR9W15cXG5dK1xcbiopKy8sXHJcbiAgZmVuY2VzOiBub29wLFxyXG4gIGhyOiAvXiggKlstKl9dKXszLH0gKig/Olxcbit8JCkvLFxyXG4gIGhlYWRpbmc6IC9eICooI3sxLDZ9KSAqKFteXFxuXSs/KSAqIyogKig/Olxcbit8JCkvLFxyXG4gIG5wdGFibGU6IG5vb3AsXHJcbiAgbGhlYWRpbmc6IC9eKFteXFxuXSspXFxuICooPXwtKXsyLH0gKig/Olxcbit8JCkvLFxyXG4gIGJsb2NrcXVvdGU6IC9eKCAqPlteXFxuXSsoXFxuKD8hZGVmKVteXFxuXSspKlxcbiopKy8sXHJcbiAgbGlzdDogL14oICopKGJ1bGwpIFtcXHNcXFNdKz8oPzpocnxkZWZ8XFxuezIsfSg/ISApKD8hXFwxYnVsbCApXFxuKnxcXHMqJCkvLFxyXG4gIGh0bWw6IC9eICooPzpjb21tZW50ICooPzpcXG58XFxzKiQpfGNsb3NlZCAqKD86XFxuezIsfXxcXHMqJCl8Y2xvc2luZyAqKD86XFxuezIsfXxcXHMqJCkpLyxcclxuICBkZWY6IC9eICpcXFsoW15cXF1dKylcXF06ICo8PyhbXlxccz5dKyk+Pyg/OiArW1wiKF0oW15cXG5dKylbXCIpXSk/ICooPzpcXG4rfCQpLyxcclxuICB0YWJsZTogbm9vcCxcclxuICBwYXJhZ3JhcGg6IC9eKCg/OlteXFxuXStcXG4/KD8haHJ8aGVhZGluZ3xsaGVhZGluZ3xibG9ja3F1b3RlfHRhZ3xkZWYpKSspXFxuKi8sXHJcbiAgdGV4dDogL15bXlxcbl0rL1xyXG59O1xyXG5cclxuYmxvY2suYnVsbGV0ID0gLyg/OlsqKy1dfFxcZCtcXC4pLztcclxuYmxvY2suaXRlbSA9IC9eKCAqKShidWxsKSBbXlxcbl0qKD86XFxuKD8hXFwxYnVsbCApW15cXG5dKikqLztcclxuYmxvY2suaXRlbSA9IHJlcGxhY2UoYmxvY2suaXRlbSwgJ2dtJylcclxuICAoL2J1bGwvZywgYmxvY2suYnVsbGV0KVxyXG4gICgpO1xyXG5cclxuYmxvY2subGlzdCA9IHJlcGxhY2UoYmxvY2subGlzdClcclxuICAoL2J1bGwvZywgYmxvY2suYnVsbGV0KVxyXG4gICgnaHInLCAnXFxcXG4rKD89XFxcXDE/KD86Wy0qX10gKil7Myx9KD86XFxcXG4rfCQpKScpXHJcbiAgKCdkZWYnLCAnXFxcXG4rKD89JyArIGJsb2NrLmRlZi5zb3VyY2UgKyAnKScpXHJcbiAgKCk7XHJcblxyXG5ibG9jay5ibG9ja3F1b3RlID0gcmVwbGFjZShibG9jay5ibG9ja3F1b3RlKVxyXG4gICgnZGVmJywgYmxvY2suZGVmKVxyXG4gICgpO1xyXG5cclxuYmxvY2suX3RhZyA9ICcoPyEoPzonXHJcbiAgKyAnYXxlbXxzdHJvbmd8c21hbGx8c3xjaXRlfHF8ZGZufGFiYnJ8ZGF0YXx0aW1lfGNvZGUnXHJcbiAgKyAnfHZhcnxzYW1wfGtiZHxzdWJ8c3VwfGl8Ynx1fG1hcmt8cnVieXxydHxycHxiZGl8YmRvJ1xyXG4gICsgJ3xzcGFufGJyfHdicnxpbnN8ZGVsfGltZylcXFxcYilcXFxcdysoPyE6L3xbXlxcXFx3XFxcXHNAXSpAKVxcXFxiJztcclxuXHJcbmJsb2NrLmh0bWwgPSByZXBsYWNlKGJsb2NrLmh0bWwpXHJcbiAgKCdjb21tZW50JywgLzwhLS1bXFxzXFxTXSo/LS0+LylcclxuICAoJ2Nsb3NlZCcsIC88KHRhZylbXFxzXFxTXSs/PFxcL1xcMT4vKVxyXG4gICgnY2xvc2luZycsIC88dGFnKD86XCJbXlwiXSpcInwnW14nXSonfFteJ1wiPl0pKj8+LylcclxuICAoL3RhZy9nLCBibG9jay5fdGFnKVxyXG4gICgpO1xyXG5cclxuYmxvY2sucGFyYWdyYXBoID0gcmVwbGFjZShibG9jay5wYXJhZ3JhcGgpXHJcbiAgKCdocicsIGJsb2NrLmhyKVxyXG4gICgnaGVhZGluZycsIGJsb2NrLmhlYWRpbmcpXHJcbiAgKCdsaGVhZGluZycsIGJsb2NrLmxoZWFkaW5nKVxyXG4gICgnYmxvY2txdW90ZScsIGJsb2NrLmJsb2NrcXVvdGUpXHJcbiAgKCd0YWcnLCAnPCcgKyBibG9jay5fdGFnKVxyXG4gICgnZGVmJywgYmxvY2suZGVmKVxyXG4gICgpO1xyXG5cclxuLyoqXHJcbiAqIE5vcm1hbCBCbG9jayBHcmFtbWFyXHJcbiAqL1xyXG5cclxuYmxvY2subm9ybWFsID0gbWVyZ2Uoe30sIGJsb2NrKTtcclxuXHJcbi8qKlxyXG4gKiBHRk0gQmxvY2sgR3JhbW1hclxyXG4gKi9cclxuXHJcbmJsb2NrLmdmbSA9IG1lcmdlKHt9LCBibG9jay5ub3JtYWwsIHtcclxuICBmZW5jZXM6IC9eICooYHszLH18fnszLH0pWyBcXC5dKihcXFMrKT8gKlxcbihbXFxzXFxTXSo/KVxccypcXDEgKig/Olxcbit8JCkvLFxyXG4gIHBhcmFncmFwaDogL14vLFxyXG4gIGhlYWRpbmc6IC9eICooI3sxLDZ9KSArKFteXFxuXSs/KSAqIyogKig/Olxcbit8JCkvXHJcbn0pO1xyXG5cclxuYmxvY2suZ2ZtLnBhcmFncmFwaCA9IHJlcGxhY2UoYmxvY2sucGFyYWdyYXBoKVxyXG4gICgnKD8hJywgJyg/ISdcclxuICAgICsgYmxvY2suZ2ZtLmZlbmNlcy5zb3VyY2UucmVwbGFjZSgnXFxcXDEnLCAnXFxcXDInKSArICd8J1xyXG4gICAgKyBibG9jay5saXN0LnNvdXJjZS5yZXBsYWNlKCdcXFxcMScsICdcXFxcMycpICsgJ3wnKVxyXG4gICgpO1xyXG5cclxuLyoqXHJcbiAqIEdGTSArIFRhYmxlcyBCbG9jayBHcmFtbWFyXHJcbiAqL1xyXG5cclxuYmxvY2sudGFibGVzID0gbWVyZ2Uoe30sIGJsb2NrLmdmbSwge1xyXG4gIG5wdGFibGU6IC9eICooXFxTLipcXHwuKilcXG4gKihbLTpdKyAqXFx8Wy18IDpdKilcXG4oKD86LipcXHwuKig/OlxcbnwkKSkqKVxcbiovLFxyXG4gIHRhYmxlOiAvXiAqXFx8KC4rKVxcbiAqXFx8KCAqWy06XStbLXwgOl0qKVxcbigoPzogKlxcfC4qKD86XFxufCQpKSopXFxuKi9cclxufSk7XHJcblxyXG4vKipcclxuICogQmxvY2sgTGV4ZXJcclxuICovXHJcblxyXG5mdW5jdGlvbiBMZXhlcihvcHRpb25zKSB7XHJcbiAgdGhpcy50b2tlbnMgPSBbXTtcclxuICB0aGlzLnRva2Vucy5saW5rcyA9IHt9O1xyXG4gIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgfHwgbWFya2VkLmRlZmF1bHRzO1xyXG4gIHRoaXMucnVsZXMgPSBibG9jay5ub3JtYWw7XHJcblxyXG4gIGlmICh0aGlzLm9wdGlvbnMuZ2ZtKSB7XHJcbiAgICBpZiAodGhpcy5vcHRpb25zLnRhYmxlcykge1xyXG4gICAgICB0aGlzLnJ1bGVzID0gYmxvY2sudGFibGVzO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5ydWxlcyA9IGJsb2NrLmdmbTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBvc2UgQmxvY2sgUnVsZXNcclxuICovXHJcblxyXG5MZXhlci5ydWxlcyA9IGJsb2NrO1xyXG5cclxuLyoqXHJcbiAqIFN0YXRpYyBMZXggTWV0aG9kXHJcbiAqL1xyXG5cclxuTGV4ZXIubGV4ID0gZnVuY3Rpb24oc3JjLCBvcHRpb25zKSB7XHJcbiAgdmFyIGxleGVyID0gbmV3IExleGVyKG9wdGlvbnMpO1xyXG4gIHJldHVybiBsZXhlci5sZXgoc3JjKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBQcmVwcm9jZXNzaW5nXHJcbiAqL1xyXG5cclxuTGV4ZXIucHJvdG90eXBlLmxleCA9IGZ1bmN0aW9uKHNyYykge1xyXG4gIHNyYyA9IHNyY1xyXG4gICAgLnJlcGxhY2UoL1xcclxcbnxcXHIvZywgJ1xcbicpXHJcbiAgICAucmVwbGFjZSgvXFx0L2csICcgICAgJylcclxuICAgIC5yZXBsYWNlKC9cXHUwMGEwL2csICcgJylcclxuICAgIC5yZXBsYWNlKC9cXHUyNDI0L2csICdcXG4nKTtcclxuXHJcbiAgcmV0dXJuIHRoaXMudG9rZW4oc3JjLCB0cnVlKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMZXhpbmdcclxuICovXHJcblxyXG5MZXhlci5wcm90b3R5cGUudG9rZW4gPSBmdW5jdGlvbihzcmMsIHRvcCwgYnEpIHtcclxuICB2YXIgc3JjID0gc3JjLnJlcGxhY2UoL14gKyQvZ20sICcnKVxyXG4gICAgLCBuZXh0XHJcbiAgICAsIGxvb3NlXHJcbiAgICAsIGNhcFxyXG4gICAgLCBidWxsXHJcbiAgICAsIGJcclxuICAgICwgaXRlbVxyXG4gICAgLCBzcGFjZVxyXG4gICAgLCBpXHJcbiAgICAsIGw7XHJcblxyXG4gIHdoaWxlIChzcmMpIHtcclxuICAgIC8vIG5ld2xpbmVcclxuICAgIGlmIChjYXAgPSB0aGlzLnJ1bGVzLm5ld2xpbmUuZXhlYyhzcmMpKSB7XHJcbiAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcoY2FwWzBdLmxlbmd0aCk7XHJcbiAgICAgIGlmIChjYXBbMF0ubGVuZ3RoID4gMSkge1xyXG4gICAgICAgIHRoaXMudG9rZW5zLnB1c2goe1xyXG4gICAgICAgICAgdHlwZTogJ3NwYWNlJ1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gY29kZVxyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMuY29kZS5leGVjKHNyYykpIHtcclxuICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyhjYXBbMF0ubGVuZ3RoKTtcclxuICAgICAgY2FwID0gY2FwWzBdLnJlcGxhY2UoL14gezR9L2dtLCAnJyk7XHJcbiAgICAgIHRoaXMudG9rZW5zLnB1c2goe1xyXG4gICAgICAgIHR5cGU6ICdjb2RlJyxcclxuICAgICAgICB0ZXh0OiAhdGhpcy5vcHRpb25zLnBlZGFudGljXHJcbiAgICAgICAgICA/IGNhcC5yZXBsYWNlKC9cXG4rJC8sICcnKVxyXG4gICAgICAgICAgOiBjYXBcclxuICAgICAgfSk7XHJcbiAgICAgIGNvbnRpbnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGZlbmNlcyAoZ2ZtKVxyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMuZmVuY2VzLmV4ZWMoc3JjKSkge1xyXG4gICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKGNhcFswXS5sZW5ndGgpO1xyXG4gICAgICB0aGlzLnRva2Vucy5wdXNoKHtcclxuICAgICAgICB0eXBlOiAnY29kZScsXHJcbiAgICAgICAgbGFuZzogY2FwWzJdLFxyXG4gICAgICAgIHRleHQ6IGNhcFszXSB8fCAnJ1xyXG4gICAgICB9KTtcclxuICAgICAgY29udGludWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gaGVhZGluZ1xyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMuaGVhZGluZy5leGVjKHNyYykpIHtcclxuICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyhjYXBbMF0ubGVuZ3RoKTtcclxuICAgICAgdGhpcy50b2tlbnMucHVzaCh7XHJcbiAgICAgICAgdHlwZTogJ2hlYWRpbmcnLFxyXG4gICAgICAgIGRlcHRoOiBjYXBbMV0ubGVuZ3RoLFxyXG4gICAgICAgIHRleHQ6IGNhcFsyXVxyXG4gICAgICB9KTtcclxuICAgICAgY29udGludWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gdGFibGUgbm8gbGVhZGluZyBwaXBlIChnZm0pXHJcbiAgICBpZiAodG9wICYmIChjYXAgPSB0aGlzLnJ1bGVzLm5wdGFibGUuZXhlYyhzcmMpKSkge1xyXG4gICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKGNhcFswXS5sZW5ndGgpO1xyXG5cclxuICAgICAgaXRlbSA9IHtcclxuICAgICAgICB0eXBlOiAndGFibGUnLFxyXG4gICAgICAgIGhlYWRlcjogY2FwWzFdLnJlcGxhY2UoL14gKnwgKlxcfCAqJC9nLCAnJykuc3BsaXQoLyAqXFx8ICovKSxcclxuICAgICAgICBhbGlnbjogY2FwWzJdLnJlcGxhY2UoL14gKnxcXHwgKiQvZywgJycpLnNwbGl0KC8gKlxcfCAqLyksXHJcbiAgICAgICAgY2VsbHM6IGNhcFszXS5yZXBsYWNlKC9cXG4kLywgJycpLnNwbGl0KCdcXG4nKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgZm9yIChpID0gMDsgaSA8IGl0ZW0uYWxpZ24ubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICBpZiAoL14gKi0rOiAqJC8udGVzdChpdGVtLmFsaWduW2ldKSkge1xyXG4gICAgICAgICAgaXRlbS5hbGlnbltpXSA9ICdyaWdodCc7XHJcbiAgICAgICAgfSBlbHNlIGlmICgvXiAqOi0rOiAqJC8udGVzdChpdGVtLmFsaWduW2ldKSkge1xyXG4gICAgICAgICAgaXRlbS5hbGlnbltpXSA9ICdjZW50ZXInO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoL14gKjotKyAqJC8udGVzdChpdGVtLmFsaWduW2ldKSkge1xyXG4gICAgICAgICAgaXRlbS5hbGlnbltpXSA9ICdsZWZ0JztcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgaXRlbS5hbGlnbltpXSA9IG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBmb3IgKGkgPSAwOyBpIDwgaXRlbS5jZWxscy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIGl0ZW0uY2VsbHNbaV0gPSBpdGVtLmNlbGxzW2ldLnNwbGl0KC8gKlxcfCAqLyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMudG9rZW5zLnB1c2goaXRlbSk7XHJcblxyXG4gICAgICBjb250aW51ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBsaGVhZGluZ1xyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMubGhlYWRpbmcuZXhlYyhzcmMpKSB7XHJcbiAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcoY2FwWzBdLmxlbmd0aCk7XHJcbiAgICAgIHRoaXMudG9rZW5zLnB1c2goe1xyXG4gICAgICAgIHR5cGU6ICdoZWFkaW5nJyxcclxuICAgICAgICBkZXB0aDogY2FwWzJdID09PSAnPScgPyAxIDogMixcclxuICAgICAgICB0ZXh0OiBjYXBbMV1cclxuICAgICAgfSk7XHJcbiAgICAgIGNvbnRpbnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGhyXHJcbiAgICBpZiAoY2FwID0gdGhpcy5ydWxlcy5oci5leGVjKHNyYykpIHtcclxuICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyhjYXBbMF0ubGVuZ3RoKTtcclxuICAgICAgdGhpcy50b2tlbnMucHVzaCh7XHJcbiAgICAgICAgdHlwZTogJ2hyJ1xyXG4gICAgICB9KTtcclxuICAgICAgY29udGludWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gYmxvY2txdW90ZVxyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMuYmxvY2txdW90ZS5leGVjKHNyYykpIHtcclxuICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyhjYXBbMF0ubGVuZ3RoKTtcclxuXHJcbiAgICAgIHRoaXMudG9rZW5zLnB1c2goe1xyXG4gICAgICAgIHR5cGU6ICdibG9ja3F1b3RlX3N0YXJ0J1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGNhcCA9IGNhcFswXS5yZXBsYWNlKC9eICo+ID8vZ20sICcnKTtcclxuXHJcbiAgICAgIC8vIFBhc3MgYHRvcGAgdG8ga2VlcCB0aGUgY3VycmVudFxyXG4gICAgICAvLyBcInRvcGxldmVsXCIgc3RhdGUuIFRoaXMgaXMgZXhhY3RseVxyXG4gICAgICAvLyBob3cgbWFya2Rvd24ucGwgd29ya3MuXHJcbiAgICAgIHRoaXMudG9rZW4oY2FwLCB0b3AsIHRydWUpO1xyXG5cclxuICAgICAgdGhpcy50b2tlbnMucHVzaCh7XHJcbiAgICAgICAgdHlwZTogJ2Jsb2NrcXVvdGVfZW5kJ1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAgIGNvbnRpbnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGxpc3RcclxuICAgIGlmIChjYXAgPSB0aGlzLnJ1bGVzLmxpc3QuZXhlYyhzcmMpKSB7XHJcbiAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcoY2FwWzBdLmxlbmd0aCk7XHJcbiAgICAgIGJ1bGwgPSBjYXBbMl07XHJcblxyXG4gICAgICB0aGlzLnRva2Vucy5wdXNoKHtcclxuICAgICAgICB0eXBlOiAnbGlzdF9zdGFydCcsXHJcbiAgICAgICAgb3JkZXJlZDogYnVsbC5sZW5ndGggPiAxXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgLy8gR2V0IGVhY2ggdG9wLWxldmVsIGl0ZW0uXHJcbiAgICAgIGNhcCA9IGNhcFswXS5tYXRjaCh0aGlzLnJ1bGVzLml0ZW0pO1xyXG5cclxuICAgICAgbmV4dCA9IGZhbHNlO1xyXG4gICAgICBsID0gY2FwLmxlbmd0aDtcclxuICAgICAgaSA9IDA7XHJcblxyXG4gICAgICBmb3IgKDsgaSA8IGw7IGkrKykge1xyXG4gICAgICAgIGl0ZW0gPSBjYXBbaV07XHJcblxyXG4gICAgICAgIC8vIFJlbW92ZSB0aGUgbGlzdCBpdGVtJ3MgYnVsbGV0XHJcbiAgICAgICAgLy8gc28gaXQgaXMgc2VlbiBhcyB0aGUgbmV4dCB0b2tlbi5cclxuICAgICAgICBzcGFjZSA9IGl0ZW0ubGVuZ3RoO1xyXG4gICAgICAgIGl0ZW0gPSBpdGVtLnJlcGxhY2UoL14gKihbKistXXxcXGQrXFwuKSArLywgJycpO1xyXG5cclxuICAgICAgICAvLyBPdXRkZW50IHdoYXRldmVyIHRoZVxyXG4gICAgICAgIC8vIGxpc3QgaXRlbSBjb250YWlucy4gSGFja3kuXHJcbiAgICAgICAgaWYgKH5pdGVtLmluZGV4T2YoJ1xcbiAnKSkge1xyXG4gICAgICAgICAgc3BhY2UgLT0gaXRlbS5sZW5ndGg7XHJcbiAgICAgICAgICBpdGVtID0gIXRoaXMub3B0aW9ucy5wZWRhbnRpY1xyXG4gICAgICAgICAgICA/IGl0ZW0ucmVwbGFjZShuZXcgUmVnRXhwKCdeIHsxLCcgKyBzcGFjZSArICd9JywgJ2dtJyksICcnKVxyXG4gICAgICAgICAgICA6IGl0ZW0ucmVwbGFjZSgvXiB7MSw0fS9nbSwgJycpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRGV0ZXJtaW5lIHdoZXRoZXIgdGhlIG5leHQgbGlzdCBpdGVtIGJlbG9uZ3MgaGVyZS5cclxuICAgICAgICAvLyBCYWNrcGVkYWwgaWYgaXQgZG9lcyBub3QgYmVsb25nIGluIHRoaXMgbGlzdC5cclxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLnNtYXJ0TGlzdHMgJiYgaSAhPT0gbCAtIDEpIHtcclxuICAgICAgICAgIGIgPSBibG9jay5idWxsZXQuZXhlYyhjYXBbaSArIDFdKVswXTtcclxuICAgICAgICAgIGlmIChidWxsICE9PSBiICYmICEoYnVsbC5sZW5ndGggPiAxICYmIGIubGVuZ3RoID4gMSkpIHtcclxuICAgICAgICAgICAgc3JjID0gY2FwLnNsaWNlKGkgKyAxKS5qb2luKCdcXG4nKSArIHNyYztcclxuICAgICAgICAgICAgaSA9IGwgLSAxO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gRGV0ZXJtaW5lIHdoZXRoZXIgaXRlbSBpcyBsb29zZSBvciBub3QuXHJcbiAgICAgICAgLy8gVXNlOiAvKF58XFxuKSg/ISApW15cXG5dK1xcblxcbig/IVxccyokKS9cclxuICAgICAgICAvLyBmb3IgZGlzY291bnQgYmVoYXZpb3IuXHJcbiAgICAgICAgbG9vc2UgPSBuZXh0IHx8IC9cXG5cXG4oPyFcXHMqJCkvLnRlc3QoaXRlbSk7XHJcbiAgICAgICAgaWYgKGkgIT09IGwgLSAxKSB7XHJcbiAgICAgICAgICBuZXh0ID0gaXRlbS5jaGFyQXQoaXRlbS5sZW5ndGggLSAxKSA9PT0gJ1xcbic7XHJcbiAgICAgICAgICBpZiAoIWxvb3NlKSBsb29zZSA9IG5leHQ7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICB0aGlzLnRva2Vucy5wdXNoKHtcclxuICAgICAgICAgIHR5cGU6IGxvb3NlXHJcbiAgICAgICAgICAgID8gJ2xvb3NlX2l0ZW1fc3RhcnQnXHJcbiAgICAgICAgICAgIDogJ2xpc3RfaXRlbV9zdGFydCdcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gUmVjdXJzZS5cclxuICAgICAgICB0aGlzLnRva2VuKGl0ZW0sIGZhbHNlLCBicSk7XHJcblxyXG4gICAgICAgIHRoaXMudG9rZW5zLnB1c2goe1xyXG4gICAgICAgICAgdHlwZTogJ2xpc3RfaXRlbV9lbmQnXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRoaXMudG9rZW5zLnB1c2goe1xyXG4gICAgICAgIHR5cGU6ICdsaXN0X2VuZCdcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBjb250aW51ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBodG1sXHJcbiAgICBpZiAoY2FwID0gdGhpcy5ydWxlcy5odG1sLmV4ZWMoc3JjKSkge1xyXG4gICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKGNhcFswXS5sZW5ndGgpO1xyXG4gICAgICB0aGlzLnRva2Vucy5wdXNoKHtcclxuICAgICAgICB0eXBlOiB0aGlzLm9wdGlvbnMuc2FuaXRpemVcclxuICAgICAgICAgID8gJ3BhcmFncmFwaCdcclxuICAgICAgICAgIDogJ2h0bWwnLFxyXG4gICAgICAgIHByZTogIXRoaXMub3B0aW9ucy5zYW5pdGl6ZXJcclxuICAgICAgICAgICYmIChjYXBbMV0gPT09ICdwcmUnIHx8IGNhcFsxXSA9PT0gJ3NjcmlwdCcgfHwgY2FwWzFdID09PSAnc3R5bGUnKSxcclxuICAgICAgICB0ZXh0OiBjYXBbMF1cclxuICAgICAgfSk7XHJcbiAgICAgIGNvbnRpbnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGRlZlxyXG4gICAgaWYgKCghYnEgJiYgdG9wKSAmJiAoY2FwID0gdGhpcy5ydWxlcy5kZWYuZXhlYyhzcmMpKSkge1xyXG4gICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKGNhcFswXS5sZW5ndGgpO1xyXG4gICAgICB0aGlzLnRva2Vucy5saW5rc1tjYXBbMV0udG9Mb3dlckNhc2UoKV0gPSB7XHJcbiAgICAgICAgaHJlZjogY2FwWzJdLFxyXG4gICAgICAgIHRpdGxlOiBjYXBbM11cclxuICAgICAgfTtcclxuICAgICAgY29udGludWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gdGFibGUgKGdmbSlcclxuICAgIGlmICh0b3AgJiYgKGNhcCA9IHRoaXMucnVsZXMudGFibGUuZXhlYyhzcmMpKSkge1xyXG4gICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKGNhcFswXS5sZW5ndGgpO1xyXG5cclxuICAgICAgaXRlbSA9IHtcclxuICAgICAgICB0eXBlOiAndGFibGUnLFxyXG4gICAgICAgIGhlYWRlcjogY2FwWzFdLnJlcGxhY2UoL14gKnwgKlxcfCAqJC9nLCAnJykuc3BsaXQoLyAqXFx8ICovKSxcclxuICAgICAgICBhbGlnbjogY2FwWzJdLnJlcGxhY2UoL14gKnxcXHwgKiQvZywgJycpLnNwbGl0KC8gKlxcfCAqLyksXHJcbiAgICAgICAgY2VsbHM6IGNhcFszXS5yZXBsYWNlKC8oPzogKlxcfCAqKT9cXG4kLywgJycpLnNwbGl0KCdcXG4nKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgZm9yIChpID0gMDsgaSA8IGl0ZW0uYWxpZ24ubGVuZ3RoOyBpKyspIHtcclxuICAgICAgICBpZiAoL14gKi0rOiAqJC8udGVzdChpdGVtLmFsaWduW2ldKSkge1xyXG4gICAgICAgICAgaXRlbS5hbGlnbltpXSA9ICdyaWdodCc7XHJcbiAgICAgICAgfSBlbHNlIGlmICgvXiAqOi0rOiAqJC8udGVzdChpdGVtLmFsaWduW2ldKSkge1xyXG4gICAgICAgICAgaXRlbS5hbGlnbltpXSA9ICdjZW50ZXInO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoL14gKjotKyAqJC8udGVzdChpdGVtLmFsaWduW2ldKSkge1xyXG4gICAgICAgICAgaXRlbS5hbGlnbltpXSA9ICdsZWZ0JztcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgaXRlbS5hbGlnbltpXSA9IG51bGw7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICBmb3IgKGkgPSAwOyBpIDwgaXRlbS5jZWxscy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIGl0ZW0uY2VsbHNbaV0gPSBpdGVtLmNlbGxzW2ldXHJcbiAgICAgICAgICAucmVwbGFjZSgvXiAqXFx8ICp8ICpcXHwgKiQvZywgJycpXHJcbiAgICAgICAgICAuc3BsaXQoLyAqXFx8ICovKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdGhpcy50b2tlbnMucHVzaChpdGVtKTtcclxuXHJcbiAgICAgIGNvbnRpbnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHRvcC1sZXZlbCBwYXJhZ3JhcGhcclxuICAgIGlmICh0b3AgJiYgKGNhcCA9IHRoaXMucnVsZXMucGFyYWdyYXBoLmV4ZWMoc3JjKSkpIHtcclxuICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyhjYXBbMF0ubGVuZ3RoKTtcclxuICAgICAgdGhpcy50b2tlbnMucHVzaCh7XHJcbiAgICAgICAgdHlwZTogJ3BhcmFncmFwaCcsXHJcbiAgICAgICAgdGV4dDogY2FwWzFdLmNoYXJBdChjYXBbMV0ubGVuZ3RoIC0gMSkgPT09ICdcXG4nXHJcbiAgICAgICAgICA/IGNhcFsxXS5zbGljZSgwLCAtMSlcclxuICAgICAgICAgIDogY2FwWzFdXHJcbiAgICAgIH0pO1xyXG4gICAgICBjb250aW51ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyB0ZXh0XHJcbiAgICBpZiAoY2FwID0gdGhpcy5ydWxlcy50ZXh0LmV4ZWMoc3JjKSkge1xyXG4gICAgICAvLyBUb3AtbGV2ZWwgc2hvdWxkIG5ldmVyIHJlYWNoIGhlcmUuXHJcbiAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcoY2FwWzBdLmxlbmd0aCk7XHJcbiAgICAgIHRoaXMudG9rZW5zLnB1c2goe1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgICB0ZXh0OiBjYXBbMF1cclxuICAgICAgfSk7XHJcbiAgICAgIGNvbnRpbnVlO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChzcmMpIHtcclxuICAgICAgdGhyb3cgbmV3XHJcbiAgICAgICAgRXJyb3IoJ0luZmluaXRlIGxvb3Agb24gYnl0ZTogJyArIHNyYy5jaGFyQ29kZUF0KDApKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJldHVybiB0aGlzLnRva2VucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbmxpbmUtTGV2ZWwgR3JhbW1hclxyXG4gKi9cclxuXHJcbnZhciBpbmxpbmUgPSB7XHJcbiAgZXNjYXBlOiAvXlxcXFwoW1xcXFxgKnt9XFxbXFxdKCkjK1xcLS4hXz5dKS8sXHJcbiAgYXV0b2xpbms6IC9ePChbXiA+XSsoQHw6XFwvKVteID5dKyk+LyxcclxuICB1cmw6IG5vb3AsXHJcbiAgdGFnOiAvXjwhLS1bXFxzXFxTXSo/LS0+fF48XFwvP1xcdysoPzpcIlteXCJdKlwifCdbXiddKid8W14nXCI+XSkqPz4vLFxyXG4gIGxpbms6IC9eIT9cXFsoaW5zaWRlKVxcXVxcKGhyZWZcXCkvLFxyXG4gIHJlZmxpbms6IC9eIT9cXFsoaW5zaWRlKVxcXVxccypcXFsoW15cXF1dKilcXF0vLFxyXG4gIG5vbGluazogL14hP1xcWygoPzpcXFtbXlxcXV0qXFxdfFteXFxbXFxdXSkqKVxcXS8sXHJcbiAgc3Ryb25nOiAvXl9fKFtcXHNcXFNdKz8pX18oPyFfKXxeXFwqXFwqKFtcXHNcXFNdKz8pXFwqXFwqKD8hXFwqKS8sXHJcbiAgZW06IC9eXFxiXygoPzpbXl9dfF9fKSs/KV9cXGJ8XlxcKigoPzpcXCpcXCp8W1xcc1xcU10pKz8pXFwqKD8hXFwqKS8sXHJcbiAgY29kZTogL14oYCspXFxzKihbXFxzXFxTXSo/W15gXSlcXHMqXFwxKD8hYCkvLFxyXG4gIGJyOiAvXiB7Mix9XFxuKD8hXFxzKiQpLyxcclxuICBkZWw6IG5vb3AsXHJcbiAgdGV4dDogL15bXFxzXFxTXSs/KD89W1xcXFw8IVxcW18qYF18IHsyLH1cXG58JCkvXHJcbn07XHJcblxyXG5pbmxpbmUuX2luc2lkZSA9IC8oPzpcXFtbXlxcXV0qXFxdfFteXFxbXFxdXXxcXF0oPz1bXlxcW10qXFxdKSkqLztcclxuaW5saW5lLl9ocmVmID0gL1xccyo8PyhbXFxzXFxTXSo/KT4/KD86XFxzK1snXCJdKFtcXHNcXFNdKj8pWydcIl0pP1xccyovO1xyXG5cclxuaW5saW5lLmxpbmsgPSByZXBsYWNlKGlubGluZS5saW5rKVxyXG4gICgnaW5zaWRlJywgaW5saW5lLl9pbnNpZGUpXHJcbiAgKCdocmVmJywgaW5saW5lLl9ocmVmKVxyXG4gICgpO1xyXG5cclxuaW5saW5lLnJlZmxpbmsgPSByZXBsYWNlKGlubGluZS5yZWZsaW5rKVxyXG4gICgnaW5zaWRlJywgaW5saW5lLl9pbnNpZGUpXHJcbiAgKCk7XHJcblxyXG4vKipcclxuICogTm9ybWFsIElubGluZSBHcmFtbWFyXHJcbiAqL1xyXG5cclxuaW5saW5lLm5vcm1hbCA9IG1lcmdlKHt9LCBpbmxpbmUpO1xyXG5cclxuLyoqXHJcbiAqIFBlZGFudGljIElubGluZSBHcmFtbWFyXHJcbiAqL1xyXG5cclxuaW5saW5lLnBlZGFudGljID0gbWVyZ2Uoe30sIGlubGluZS5ub3JtYWwsIHtcclxuICBzdHJvbmc6IC9eX18oPz1cXFMpKFtcXHNcXFNdKj9cXFMpX18oPyFfKXxeXFwqXFwqKD89XFxTKShbXFxzXFxTXSo/XFxTKVxcKlxcKig/IVxcKikvLFxyXG4gIGVtOiAvXl8oPz1cXFMpKFtcXHNcXFNdKj9cXFMpXyg/IV8pfF5cXCooPz1cXFMpKFtcXHNcXFNdKj9cXFMpXFwqKD8hXFwqKS9cclxufSk7XHJcblxyXG4vKipcclxuICogR0ZNIElubGluZSBHcmFtbWFyXHJcbiAqL1xyXG5cclxuaW5saW5lLmdmbSA9IG1lcmdlKHt9LCBpbmxpbmUubm9ybWFsLCB7XHJcbiAgZXNjYXBlOiByZXBsYWNlKGlubGluZS5lc2NhcGUpKCddKScsICd+fF0pJykoKSxcclxuICB1cmw6IC9eKGh0dHBzPzpcXC9cXC9bXlxcczxdK1tePC4sOjtcIicpXFxdXFxzXSkvLFxyXG4gIGRlbDogL15+fig/PVxcUykoW1xcc1xcU10qP1xcUyl+fi8sXHJcbiAgdGV4dDogcmVwbGFjZShpbmxpbmUudGV4dClcclxuICAgICgnXXwnLCAnfl18JylcclxuICAgICgnfCcsICd8aHR0cHM/Oi8vfCcpXHJcbiAgICAoKVxyXG59KTtcclxuXHJcbi8qKlxyXG4gKiBHRk0gKyBMaW5lIEJyZWFrcyBJbmxpbmUgR3JhbW1hclxyXG4gKi9cclxuXHJcbmlubGluZS5icmVha3MgPSBtZXJnZSh7fSwgaW5saW5lLmdmbSwge1xyXG4gIGJyOiByZXBsYWNlKGlubGluZS5icikoJ3syLH0nLCAnKicpKCksXHJcbiAgdGV4dDogcmVwbGFjZShpbmxpbmUuZ2ZtLnRleHQpKCd7Mix9JywgJyonKSgpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIElubGluZSBMZXhlciAmIENvbXBpbGVyXHJcbiAqL1xyXG5cclxuZnVuY3Rpb24gSW5saW5lTGV4ZXIobGlua3MsIG9wdGlvbnMpIHtcclxuICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zIHx8IG1hcmtlZC5kZWZhdWx0cztcclxuICB0aGlzLmxpbmtzID0gbGlua3M7XHJcbiAgdGhpcy5ydWxlcyA9IGlubGluZS5ub3JtYWw7XHJcbiAgdGhpcy5yZW5kZXJlciA9IHRoaXMub3B0aW9ucy5yZW5kZXJlciB8fCBuZXcgUmVuZGVyZXI7XHJcbiAgdGhpcy5yZW5kZXJlci5vcHRpb25zID0gdGhpcy5vcHRpb25zO1xyXG5cclxuICBpZiAoIXRoaXMubGlua3MpIHtcclxuICAgIHRocm93IG5ld1xyXG4gICAgICBFcnJvcignVG9rZW5zIGFycmF5IHJlcXVpcmVzIGEgYGxpbmtzYCBwcm9wZXJ0eS4nKTtcclxuICB9XHJcblxyXG4gIGlmICh0aGlzLm9wdGlvbnMuZ2ZtKSB7XHJcbiAgICBpZiAodGhpcy5vcHRpb25zLmJyZWFrcykge1xyXG4gICAgICB0aGlzLnJ1bGVzID0gaW5saW5lLmJyZWFrcztcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMucnVsZXMgPSBpbmxpbmUuZ2ZtO1xyXG4gICAgfVxyXG4gIH0gZWxzZSBpZiAodGhpcy5vcHRpb25zLnBlZGFudGljKSB7XHJcbiAgICB0aGlzLnJ1bGVzID0gaW5saW5lLnBlZGFudGljO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEV4cG9zZSBJbmxpbmUgUnVsZXNcclxuICovXHJcblxyXG5JbmxpbmVMZXhlci5ydWxlcyA9IGlubGluZTtcclxuXHJcbi8qKlxyXG4gKiBTdGF0aWMgTGV4aW5nL0NvbXBpbGluZyBNZXRob2RcclxuICovXHJcblxyXG5JbmxpbmVMZXhlci5vdXRwdXQgPSBmdW5jdGlvbihzcmMsIGxpbmtzLCBvcHRpb25zKSB7XHJcbiAgdmFyIGlubGluZSA9IG5ldyBJbmxpbmVMZXhlcihsaW5rcywgb3B0aW9ucyk7XHJcbiAgcmV0dXJuIGlubGluZS5vdXRwdXQoc3JjKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMZXhpbmcvQ29tcGlsaW5nXHJcbiAqL1xyXG5cclxuSW5saW5lTGV4ZXIucHJvdG90eXBlLm91dHB1dCA9IGZ1bmN0aW9uKHNyYykge1xyXG4gIHZhciBvdXQgPSAnJ1xyXG4gICAgLCBsaW5rXHJcbiAgICAsIHRleHRcclxuICAgICwgaHJlZlxyXG4gICAgLCBjYXA7XHJcblxyXG4gIHdoaWxlIChzcmMpIHtcclxuICAgIC8vIGVzY2FwZVxyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMuZXNjYXBlLmV4ZWMoc3JjKSkge1xyXG4gICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKGNhcFswXS5sZW5ndGgpO1xyXG4gICAgICBvdXQgKz0gY2FwWzFdO1xyXG4gICAgICBjb250aW51ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBhdXRvbGlua1xyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMuYXV0b2xpbmsuZXhlYyhzcmMpKSB7XHJcbiAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcoY2FwWzBdLmxlbmd0aCk7XHJcbiAgICAgIGlmIChjYXBbMl0gPT09ICdAJykge1xyXG4gICAgICAgIHRleHQgPSBjYXBbMV0uY2hhckF0KDYpID09PSAnOidcclxuICAgICAgICAgID8gdGhpcy5tYW5nbGUoY2FwWzFdLnN1YnN0cmluZyg3KSlcclxuICAgICAgICAgIDogdGhpcy5tYW5nbGUoY2FwWzFdKTtcclxuICAgICAgICBocmVmID0gdGhpcy5tYW5nbGUoJ21haWx0bzonKSArIHRleHQ7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGV4dCA9IGVzY2FwZShjYXBbMV0pO1xyXG4gICAgICAgIGhyZWYgPSB0ZXh0O1xyXG4gICAgICB9XHJcbiAgICAgIG91dCArPSB0aGlzLnJlbmRlcmVyLmxpbmsoaHJlZiwgbnVsbCwgdGV4dCk7XHJcbiAgICAgIGNvbnRpbnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHVybCAoZ2ZtKVxyXG4gICAgaWYgKCF0aGlzLmluTGluayAmJiAoY2FwID0gdGhpcy5ydWxlcy51cmwuZXhlYyhzcmMpKSkge1xyXG4gICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKGNhcFswXS5sZW5ndGgpO1xyXG4gICAgICB0ZXh0ID0gZXNjYXBlKGNhcFsxXSk7XHJcbiAgICAgIGhyZWYgPSB0ZXh0O1xyXG4gICAgICBvdXQgKz0gdGhpcy5yZW5kZXJlci5saW5rKGhyZWYsIG51bGwsIHRleHQpO1xyXG4gICAgICBjb250aW51ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyB0YWdcclxuICAgIGlmIChjYXAgPSB0aGlzLnJ1bGVzLnRhZy5leGVjKHNyYykpIHtcclxuICAgICAgaWYgKCF0aGlzLmluTGluayAmJiAvXjxhIC9pLnRlc3QoY2FwWzBdKSkge1xyXG4gICAgICAgIHRoaXMuaW5MaW5rID0gdHJ1ZTtcclxuICAgICAgfSBlbHNlIGlmICh0aGlzLmluTGluayAmJiAvXjxcXC9hPi9pLnRlc3QoY2FwWzBdKSkge1xyXG4gICAgICAgIHRoaXMuaW5MaW5rID0gZmFsc2U7XHJcbiAgICAgIH1cclxuICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyhjYXBbMF0ubGVuZ3RoKTtcclxuICAgICAgb3V0ICs9IHRoaXMub3B0aW9ucy5zYW5pdGl6ZVxyXG4gICAgICAgID8gdGhpcy5vcHRpb25zLnNhbml0aXplclxyXG4gICAgICAgICAgPyB0aGlzLm9wdGlvbnMuc2FuaXRpemVyKGNhcFswXSlcclxuICAgICAgICAgIDogZXNjYXBlKGNhcFswXSlcclxuICAgICAgICA6IGNhcFswXVxyXG4gICAgICBjb250aW51ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBsaW5rXHJcbiAgICBpZiAoY2FwID0gdGhpcy5ydWxlcy5saW5rLmV4ZWMoc3JjKSkge1xyXG4gICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKGNhcFswXS5sZW5ndGgpO1xyXG4gICAgICB0aGlzLmluTGluayA9IHRydWU7XHJcbiAgICAgIG91dCArPSB0aGlzLm91dHB1dExpbmsoY2FwLCB7XHJcbiAgICAgICAgaHJlZjogY2FwWzJdLFxyXG4gICAgICAgIHRpdGxlOiBjYXBbM11cclxuICAgICAgfSk7XHJcbiAgICAgIHRoaXMuaW5MaW5rID0gZmFsc2U7XHJcbiAgICAgIGNvbnRpbnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHJlZmxpbmssIG5vbGlua1xyXG4gICAgaWYgKChjYXAgPSB0aGlzLnJ1bGVzLnJlZmxpbmsuZXhlYyhzcmMpKVxyXG4gICAgICAgIHx8IChjYXAgPSB0aGlzLnJ1bGVzLm5vbGluay5leGVjKHNyYykpKSB7XHJcbiAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcoY2FwWzBdLmxlbmd0aCk7XHJcbiAgICAgIGxpbmsgPSAoY2FwWzJdIHx8IGNhcFsxXSkucmVwbGFjZSgvXFxzKy9nLCAnICcpO1xyXG4gICAgICBsaW5rID0gdGhpcy5saW5rc1tsaW5rLnRvTG93ZXJDYXNlKCldO1xyXG4gICAgICBpZiAoIWxpbmsgfHwgIWxpbmsuaHJlZikge1xyXG4gICAgICAgIG91dCArPSBjYXBbMF0uY2hhckF0KDApO1xyXG4gICAgICAgIHNyYyA9IGNhcFswXS5zdWJzdHJpbmcoMSkgKyBzcmM7XHJcbiAgICAgICAgY29udGludWU7XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy5pbkxpbmsgPSB0cnVlO1xyXG4gICAgICBvdXQgKz0gdGhpcy5vdXRwdXRMaW5rKGNhcCwgbGluayk7XHJcbiAgICAgIHRoaXMuaW5MaW5rID0gZmFsc2U7XHJcbiAgICAgIGNvbnRpbnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHN0cm9uZ1xyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMuc3Ryb25nLmV4ZWMoc3JjKSkge1xyXG4gICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKGNhcFswXS5sZW5ndGgpO1xyXG4gICAgICBvdXQgKz0gdGhpcy5yZW5kZXJlci5zdHJvbmcodGhpcy5vdXRwdXQoY2FwWzJdIHx8IGNhcFsxXSkpO1xyXG4gICAgICBjb250aW51ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBlbVxyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMuZW0uZXhlYyhzcmMpKSB7XHJcbiAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcoY2FwWzBdLmxlbmd0aCk7XHJcbiAgICAgIG91dCArPSB0aGlzLnJlbmRlcmVyLmVtKHRoaXMub3V0cHV0KGNhcFsyXSB8fCBjYXBbMV0pKTtcclxuICAgICAgY29udGludWU7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gY29kZVxyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMuY29kZS5leGVjKHNyYykpIHtcclxuICAgICAgc3JjID0gc3JjLnN1YnN0cmluZyhjYXBbMF0ubGVuZ3RoKTtcclxuICAgICAgb3V0ICs9IHRoaXMucmVuZGVyZXIuY29kZXNwYW4oZXNjYXBlKGNhcFsyXSwgdHJ1ZSkpO1xyXG4gICAgICBjb250aW51ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBiclxyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMuYnIuZXhlYyhzcmMpKSB7XHJcbiAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcoY2FwWzBdLmxlbmd0aCk7XHJcbiAgICAgIG91dCArPSB0aGlzLnJlbmRlcmVyLmJyKCk7XHJcbiAgICAgIGNvbnRpbnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIGRlbCAoZ2ZtKVxyXG4gICAgaWYgKGNhcCA9IHRoaXMucnVsZXMuZGVsLmV4ZWMoc3JjKSkge1xyXG4gICAgICBzcmMgPSBzcmMuc3Vic3RyaW5nKGNhcFswXS5sZW5ndGgpO1xyXG4gICAgICBvdXQgKz0gdGhpcy5yZW5kZXJlci5kZWwodGhpcy5vdXRwdXQoY2FwWzFdKSk7XHJcbiAgICAgIGNvbnRpbnVlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHRleHRcclxuICAgIGlmIChjYXAgPSB0aGlzLnJ1bGVzLnRleHQuZXhlYyhzcmMpKSB7XHJcbiAgICAgIHNyYyA9IHNyYy5zdWJzdHJpbmcoY2FwWzBdLmxlbmd0aCk7XHJcbiAgICAgIG91dCArPSB0aGlzLnJlbmRlcmVyLnRleHQoZXNjYXBlKHRoaXMuc21hcnR5cGFudHMoY2FwWzBdKSkpO1xyXG4gICAgICBjb250aW51ZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoc3JjKSB7XHJcbiAgICAgIHRocm93IG5ld1xyXG4gICAgICAgIEVycm9yKCdJbmZpbml0ZSBsb29wIG9uIGJ5dGU6ICcgKyBzcmMuY2hhckNvZGVBdCgwKSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4gb3V0O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENvbXBpbGUgTGlua1xyXG4gKi9cclxuXHJcbklubGluZUxleGVyLnByb3RvdHlwZS5vdXRwdXRMaW5rID0gZnVuY3Rpb24oY2FwLCBsaW5rKSB7XHJcbiAgdmFyIGhyZWYgPSBlc2NhcGUobGluay5ocmVmKVxyXG4gICAgLCB0aXRsZSA9IGxpbmsudGl0bGUgPyBlc2NhcGUobGluay50aXRsZSkgOiBudWxsO1xyXG5cclxuICByZXR1cm4gY2FwWzBdLmNoYXJBdCgwKSAhPT0gJyEnXHJcbiAgICA/IHRoaXMucmVuZGVyZXIubGluayhocmVmLCB0aXRsZSwgdGhpcy5vdXRwdXQoY2FwWzFdKSlcclxuICAgIDogdGhpcy5yZW5kZXJlci5pbWFnZShocmVmLCB0aXRsZSwgZXNjYXBlKGNhcFsxXSkpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNtYXJ0eXBhbnRzIFRyYW5zZm9ybWF0aW9uc1xyXG4gKi9cclxuXHJcbklubGluZUxleGVyLnByb3RvdHlwZS5zbWFydHlwYW50cyA9IGZ1bmN0aW9uKHRleHQpIHtcclxuICBpZiAoIXRoaXMub3B0aW9ucy5zbWFydHlwYW50cykgcmV0dXJuIHRleHQ7XHJcbiAgcmV0dXJuIHRleHRcclxuICAgIC8vIGVtLWRhc2hlc1xyXG4gICAgLnJlcGxhY2UoLy0tLS9nLCAnXFx1MjAxNCcpXHJcbiAgICAvLyBlbi1kYXNoZXNcclxuICAgIC5yZXBsYWNlKC8tLS9nLCAnXFx1MjAxMycpXHJcbiAgICAvLyBvcGVuaW5nIHNpbmdsZXNcclxuICAgIC5yZXBsYWNlKC8oXnxbLVxcdTIwMTQvKFxcW3tcIlxcc10pJy9nLCAnJDFcXHUyMDE4JylcclxuICAgIC8vIGNsb3Npbmcgc2luZ2xlcyAmIGFwb3N0cm9waGVzXHJcbiAgICAucmVwbGFjZSgvJy9nLCAnXFx1MjAxOScpXHJcbiAgICAvLyBvcGVuaW5nIGRvdWJsZXNcclxuICAgIC5yZXBsYWNlKC8oXnxbLVxcdTIwMTQvKFxcW3tcXHUyMDE4XFxzXSlcIi9nLCAnJDFcXHUyMDFjJylcclxuICAgIC8vIGNsb3NpbmcgZG91Ymxlc1xyXG4gICAgLnJlcGxhY2UoL1wiL2csICdcXHUyMDFkJylcclxuICAgIC8vIGVsbGlwc2VzXHJcbiAgICAucmVwbGFjZSgvXFwuezN9L2csICdcXHUyMDI2Jyk7XHJcbn07XHJcblxyXG4vKipcclxuICogTWFuZ2xlIExpbmtzXHJcbiAqL1xyXG5cclxuSW5saW5lTGV4ZXIucHJvdG90eXBlLm1hbmdsZSA9IGZ1bmN0aW9uKHRleHQpIHtcclxuICBpZiAoIXRoaXMub3B0aW9ucy5tYW5nbGUpIHJldHVybiB0ZXh0O1xyXG4gIHZhciBvdXQgPSAnJ1xyXG4gICAgLCBsID0gdGV4dC5sZW5ndGhcclxuICAgICwgaSA9IDBcclxuICAgICwgY2g7XHJcblxyXG4gIGZvciAoOyBpIDwgbDsgaSsrKSB7XHJcbiAgICBjaCA9IHRleHQuY2hhckNvZGVBdChpKTtcclxuICAgIGlmIChNYXRoLnJhbmRvbSgpID4gMC41KSB7XHJcbiAgICAgIGNoID0gJ3gnICsgY2gudG9TdHJpbmcoMTYpO1xyXG4gICAgfVxyXG4gICAgb3V0ICs9ICcmIycgKyBjaCArICc7JztcclxuICB9XHJcblxyXG4gIHJldHVybiBvdXQ7XHJcbn07XHJcblxyXG4vKipcclxuICogUmVuZGVyZXJcclxuICovXHJcblxyXG5mdW5jdGlvbiBSZW5kZXJlcihvcHRpb25zKSB7XHJcbiAgdGhpcy5vcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcclxufVxyXG5cclxuUmVuZGVyZXIucHJvdG90eXBlLmNvZGUgPSBmdW5jdGlvbihjb2RlLCBsYW5nLCBlc2NhcGVkKSB7XHJcbiAgaWYgKHRoaXMub3B0aW9ucy5oaWdobGlnaHQpIHtcclxuICAgIHZhciBvdXQgPSB0aGlzLm9wdGlvbnMuaGlnaGxpZ2h0KGNvZGUsIGxhbmcpO1xyXG4gICAgaWYgKG91dCAhPSBudWxsICYmIG91dCAhPT0gY29kZSkge1xyXG4gICAgICBlc2NhcGVkID0gdHJ1ZTtcclxuICAgICAgY29kZSA9IG91dDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGlmICghbGFuZykge1xyXG4gICAgcmV0dXJuICc8cHJlPjxjb2RlPidcclxuICAgICAgKyAoZXNjYXBlZCA/IGNvZGUgOiBlc2NhcGUoY29kZSwgdHJ1ZSkpXHJcbiAgICAgICsgJ1xcbjwvY29kZT48L3ByZT4nO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuICc8cHJlPjxjb2RlIGNsYXNzPVwiJ1xyXG4gICAgKyB0aGlzLm9wdGlvbnMubGFuZ1ByZWZpeFxyXG4gICAgKyBlc2NhcGUobGFuZywgdHJ1ZSlcclxuICAgICsgJ1wiPidcclxuICAgICsgKGVzY2FwZWQgPyBjb2RlIDogZXNjYXBlKGNvZGUsIHRydWUpKVxyXG4gICAgKyAnXFxuPC9jb2RlPjwvcHJlPlxcbic7XHJcbn07XHJcblxyXG5SZW5kZXJlci5wcm90b3R5cGUuYmxvY2txdW90ZSA9IGZ1bmN0aW9uKHF1b3RlKSB7XHJcbiAgcmV0dXJuICc8YmxvY2txdW90ZT5cXG4nICsgcXVvdGUgKyAnPC9ibG9ja3F1b3RlPlxcbic7XHJcbn07XHJcblxyXG5SZW5kZXJlci5wcm90b3R5cGUuaHRtbCA9IGZ1bmN0aW9uKGh0bWwpIHtcclxuICByZXR1cm4gaHRtbDtcclxufTtcclxuXHJcblJlbmRlcmVyLnByb3RvdHlwZS5oZWFkaW5nID0gZnVuY3Rpb24odGV4dCwgbGV2ZWwsIHJhdykge1xyXG4gIHJldHVybiAnPGgnXHJcbiAgICArIGxldmVsXHJcbiAgICArICcgaWQ9XCInXHJcbiAgICArIHRoaXMub3B0aW9ucy5oZWFkZXJQcmVmaXhcclxuICAgICsgcmF3LnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvW15cXHddKy9nLCAnLScpXHJcbiAgICArICdcIj4nXHJcbiAgICArIHRleHRcclxuICAgICsgJzwvaCdcclxuICAgICsgbGV2ZWxcclxuICAgICsgJz5cXG4nO1xyXG59O1xyXG5cclxuUmVuZGVyZXIucHJvdG90eXBlLmhyID0gZnVuY3Rpb24oKSB7XHJcbiAgcmV0dXJuIHRoaXMub3B0aW9ucy54aHRtbCA/ICc8aHIvPlxcbicgOiAnPGhyPlxcbic7XHJcbn07XHJcblxyXG5SZW5kZXJlci5wcm90b3R5cGUubGlzdCA9IGZ1bmN0aW9uKGJvZHksIG9yZGVyZWQpIHtcclxuICB2YXIgdHlwZSA9IG9yZGVyZWQgPyAnb2wnIDogJ3VsJztcclxuICByZXR1cm4gJzwnICsgdHlwZSArICc+XFxuJyArIGJvZHkgKyAnPC8nICsgdHlwZSArICc+XFxuJztcclxufTtcclxuXHJcblJlbmRlcmVyLnByb3RvdHlwZS5saXN0aXRlbSA9IGZ1bmN0aW9uKHRleHQpIHtcclxuICByZXR1cm4gJzxsaT4nICsgdGV4dCArICc8L2xpPlxcbic7XHJcbn07XHJcblxyXG5SZW5kZXJlci5wcm90b3R5cGUucGFyYWdyYXBoID0gZnVuY3Rpb24odGV4dCkge1xyXG4gIHJldHVybiAnPHA+JyArIHRleHQgKyAnPC9wPlxcbic7XHJcbn07XHJcblxyXG5SZW5kZXJlci5wcm90b3R5cGUudGFibGUgPSBmdW5jdGlvbihoZWFkZXIsIGJvZHkpIHtcclxuICByZXR1cm4gJzx0YWJsZT5cXG4nXHJcbiAgICArICc8dGhlYWQ+XFxuJ1xyXG4gICAgKyBoZWFkZXJcclxuICAgICsgJzwvdGhlYWQ+XFxuJ1xyXG4gICAgKyAnPHRib2R5PlxcbidcclxuICAgICsgYm9keVxyXG4gICAgKyAnPC90Ym9keT5cXG4nXHJcbiAgICArICc8L3RhYmxlPlxcbic7XHJcbn07XHJcblxyXG5SZW5kZXJlci5wcm90b3R5cGUudGFibGVyb3cgPSBmdW5jdGlvbihjb250ZW50KSB7XHJcbiAgcmV0dXJuICc8dHI+XFxuJyArIGNvbnRlbnQgKyAnPC90cj5cXG4nO1xyXG59O1xyXG5cclxuUmVuZGVyZXIucHJvdG90eXBlLnRhYmxlY2VsbCA9IGZ1bmN0aW9uKGNvbnRlbnQsIGZsYWdzKSB7XHJcbiAgdmFyIHR5cGUgPSBmbGFncy5oZWFkZXIgPyAndGgnIDogJ3RkJztcclxuICB2YXIgdGFnID0gZmxhZ3MuYWxpZ25cclxuICAgID8gJzwnICsgdHlwZSArICcgc3R5bGU9XCJ0ZXh0LWFsaWduOicgKyBmbGFncy5hbGlnbiArICdcIj4nXHJcbiAgICA6ICc8JyArIHR5cGUgKyAnPic7XHJcbiAgcmV0dXJuIHRhZyArIGNvbnRlbnQgKyAnPC8nICsgdHlwZSArICc+XFxuJztcclxufTtcclxuXHJcbi8vIHNwYW4gbGV2ZWwgcmVuZGVyZXJcclxuUmVuZGVyZXIucHJvdG90eXBlLnN0cm9uZyA9IGZ1bmN0aW9uKHRleHQpIHtcclxuICByZXR1cm4gJzxzdHJvbmc+JyArIHRleHQgKyAnPC9zdHJvbmc+JztcclxufTtcclxuXHJcblJlbmRlcmVyLnByb3RvdHlwZS5lbSA9IGZ1bmN0aW9uKHRleHQpIHtcclxuICByZXR1cm4gJzxlbT4nICsgdGV4dCArICc8L2VtPic7XHJcbn07XHJcblxyXG5SZW5kZXJlci5wcm90b3R5cGUuY29kZXNwYW4gPSBmdW5jdGlvbih0ZXh0KSB7XHJcbiAgcmV0dXJuICc8Y29kZT4nICsgdGV4dCArICc8L2NvZGU+JztcclxufTtcclxuXHJcblJlbmRlcmVyLnByb3RvdHlwZS5iciA9IGZ1bmN0aW9uKCkge1xyXG4gIHJldHVybiB0aGlzLm9wdGlvbnMueGh0bWwgPyAnPGJyLz4nIDogJzxicj4nO1xyXG59O1xyXG5cclxuUmVuZGVyZXIucHJvdG90eXBlLmRlbCA9IGZ1bmN0aW9uKHRleHQpIHtcclxuICByZXR1cm4gJzxkZWw+JyArIHRleHQgKyAnPC9kZWw+JztcclxufTtcclxuXHJcblJlbmRlcmVyLnByb3RvdHlwZS5saW5rID0gZnVuY3Rpb24oaHJlZiwgdGl0bGUsIHRleHQpIHtcclxuICBpZiAodGhpcy5vcHRpb25zLnNhbml0aXplKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICB2YXIgcHJvdCA9IGRlY29kZVVSSUNvbXBvbmVudCh1bmVzY2FwZShocmVmKSlcclxuICAgICAgICAucmVwbGFjZSgvW15cXHc6XS9nLCAnJylcclxuICAgICAgICAudG9Mb3dlckNhc2UoKTtcclxuICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgcmV0dXJuICcnO1xyXG4gICAgfVxyXG4gICAgaWYgKHByb3QuaW5kZXhPZignamF2YXNjcmlwdDonKSA9PT0gMCB8fCBwcm90LmluZGV4T2YoJ3Zic2NyaXB0OicpID09PSAwKSB7XHJcbiAgICAgIHJldHVybiAnJztcclxuICAgIH1cclxuICB9XHJcbiAgdmFyIG91dCA9ICc8YSBocmVmPVwiJyArIGhyZWYgKyAnXCInO1xyXG4gIGlmICh0aXRsZSkge1xyXG4gICAgb3V0ICs9ICcgdGl0bGU9XCInICsgdGl0bGUgKyAnXCInO1xyXG4gIH1cclxuICBvdXQgKz0gJz4nICsgdGV4dCArICc8L2E+JztcclxuICByZXR1cm4gb3V0O1xyXG59O1xyXG5cclxuUmVuZGVyZXIucHJvdG90eXBlLmltYWdlID0gZnVuY3Rpb24oaHJlZiwgdGl0bGUsIHRleHQpIHtcclxuICB2YXIgb3V0ID0gJzxpbWcgc3JjPVwiJyArIGhyZWYgKyAnXCIgYWx0PVwiJyArIHRleHQgKyAnXCInO1xyXG4gIGlmICh0aXRsZSkge1xyXG4gICAgb3V0ICs9ICcgdGl0bGU9XCInICsgdGl0bGUgKyAnXCInO1xyXG4gIH1cclxuICBvdXQgKz0gdGhpcy5vcHRpb25zLnhodG1sID8gJy8+JyA6ICc+JztcclxuICByZXR1cm4gb3V0O1xyXG59O1xyXG5cclxuUmVuZGVyZXIucHJvdG90eXBlLnRleHQgPSBmdW5jdGlvbih0ZXh0KSB7XHJcbiAgcmV0dXJuIHRleHQ7XHJcbn07XHJcblxyXG4vKipcclxuICogUGFyc2luZyAmIENvbXBpbGluZ1xyXG4gKi9cclxuXHJcbmZ1bmN0aW9uIFBhcnNlcihvcHRpb25zKSB7XHJcbiAgdGhpcy50b2tlbnMgPSBbXTtcclxuICB0aGlzLnRva2VuID0gbnVsbDtcclxuICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zIHx8IG1hcmtlZC5kZWZhdWx0cztcclxuICB0aGlzLm9wdGlvbnMucmVuZGVyZXIgPSB0aGlzLm9wdGlvbnMucmVuZGVyZXIgfHwgbmV3IFJlbmRlcmVyO1xyXG4gIHRoaXMucmVuZGVyZXIgPSB0aGlzLm9wdGlvbnMucmVuZGVyZXI7XHJcbiAgdGhpcy5yZW5kZXJlci5vcHRpb25zID0gdGhpcy5vcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogU3RhdGljIFBhcnNlIE1ldGhvZFxyXG4gKi9cclxuXHJcblBhcnNlci5wYXJzZSA9IGZ1bmN0aW9uKHNyYywgb3B0aW9ucywgcmVuZGVyZXIpIHtcclxuICB2YXIgcGFyc2VyID0gbmV3IFBhcnNlcihvcHRpb25zLCByZW5kZXJlcik7XHJcbiAgcmV0dXJuIHBhcnNlci5wYXJzZShzcmMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFBhcnNlIExvb3BcclxuICovXHJcblxyXG5QYXJzZXIucHJvdG90eXBlLnBhcnNlID0gZnVuY3Rpb24oc3JjKSB7XHJcbiAgdGhpcy5pbmxpbmUgPSBuZXcgSW5saW5lTGV4ZXIoc3JjLmxpbmtzLCB0aGlzLm9wdGlvbnMsIHRoaXMucmVuZGVyZXIpO1xyXG4gIHRoaXMudG9rZW5zID0gc3JjLnJldmVyc2UoKTtcclxuXHJcbiAgdmFyIG91dCA9ICcnO1xyXG4gIHdoaWxlICh0aGlzLm5leHQoKSkge1xyXG4gICAgb3V0ICs9IHRoaXMudG9rKCk7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gb3V0O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE5leHQgVG9rZW5cclxuICovXHJcblxyXG5QYXJzZXIucHJvdG90eXBlLm5leHQgPSBmdW5jdGlvbigpIHtcclxuICByZXR1cm4gdGhpcy50b2tlbiA9IHRoaXMudG9rZW5zLnBvcCgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByZXZpZXcgTmV4dCBUb2tlblxyXG4gKi9cclxuXHJcblBhcnNlci5wcm90b3R5cGUucGVlayA9IGZ1bmN0aW9uKCkge1xyXG4gIHJldHVybiB0aGlzLnRva2Vuc1t0aGlzLnRva2Vucy5sZW5ndGggLSAxXSB8fCAwO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFBhcnNlIFRleHQgVG9rZW5zXHJcbiAqL1xyXG5cclxuUGFyc2VyLnByb3RvdHlwZS5wYXJzZVRleHQgPSBmdW5jdGlvbigpIHtcclxuICB2YXIgYm9keSA9IHRoaXMudG9rZW4udGV4dDtcclxuXHJcbiAgd2hpbGUgKHRoaXMucGVlaygpLnR5cGUgPT09ICd0ZXh0Jykge1xyXG4gICAgYm9keSArPSAnXFxuJyArIHRoaXMubmV4dCgpLnRleHQ7XHJcbiAgfVxyXG5cclxuICByZXR1cm4gdGhpcy5pbmxpbmUub3V0cHV0KGJvZHkpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFBhcnNlIEN1cnJlbnQgVG9rZW5cclxuICovXHJcblxyXG5QYXJzZXIucHJvdG90eXBlLnRvayA9IGZ1bmN0aW9uKCkge1xyXG4gIHN3aXRjaCAodGhpcy50b2tlbi50eXBlKSB7XHJcbiAgICBjYXNlICdzcGFjZSc6IHtcclxuICAgICAgcmV0dXJuICcnO1xyXG4gICAgfVxyXG4gICAgY2FzZSAnaHInOiB7XHJcbiAgICAgIHJldHVybiB0aGlzLnJlbmRlcmVyLmhyKCk7XHJcbiAgICB9XHJcbiAgICBjYXNlICdoZWFkaW5nJzoge1xyXG4gICAgICByZXR1cm4gdGhpcy5yZW5kZXJlci5oZWFkaW5nKFxyXG4gICAgICAgIHRoaXMuaW5saW5lLm91dHB1dCh0aGlzLnRva2VuLnRleHQpLFxyXG4gICAgICAgIHRoaXMudG9rZW4uZGVwdGgsXHJcbiAgICAgICAgdGhpcy50b2tlbi50ZXh0KTtcclxuICAgIH1cclxuICAgIGNhc2UgJ2NvZGUnOiB7XHJcbiAgICAgIHJldHVybiB0aGlzLnJlbmRlcmVyLmNvZGUodGhpcy50b2tlbi50ZXh0LFxyXG4gICAgICAgIHRoaXMudG9rZW4ubGFuZyxcclxuICAgICAgICB0aGlzLnRva2VuLmVzY2FwZWQpO1xyXG4gICAgfVxyXG4gICAgY2FzZSAndGFibGUnOiB7XHJcbiAgICAgIHZhciBoZWFkZXIgPSAnJ1xyXG4gICAgICAgICwgYm9keSA9ICcnXHJcbiAgICAgICAgLCBpXHJcbiAgICAgICAgLCByb3dcclxuICAgICAgICAsIGNlbGxcclxuICAgICAgICAsIGZsYWdzXHJcbiAgICAgICAgLCBqO1xyXG5cclxuICAgICAgLy8gaGVhZGVyXHJcbiAgICAgIGNlbGwgPSAnJztcclxuICAgICAgZm9yIChpID0gMDsgaSA8IHRoaXMudG9rZW4uaGVhZGVyLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgZmxhZ3MgPSB7IGhlYWRlcjogdHJ1ZSwgYWxpZ246IHRoaXMudG9rZW4uYWxpZ25baV0gfTtcclxuICAgICAgICBjZWxsICs9IHRoaXMucmVuZGVyZXIudGFibGVjZWxsKFxyXG4gICAgICAgICAgdGhpcy5pbmxpbmUub3V0cHV0KHRoaXMudG9rZW4uaGVhZGVyW2ldKSxcclxuICAgICAgICAgIHsgaGVhZGVyOiB0cnVlLCBhbGlnbjogdGhpcy50b2tlbi5hbGlnbltpXSB9XHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgICBoZWFkZXIgKz0gdGhpcy5yZW5kZXJlci50YWJsZXJvdyhjZWxsKTtcclxuXHJcbiAgICAgIGZvciAoaSA9IDA7IGkgPCB0aGlzLnRva2VuLmNlbGxzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgICAgcm93ID0gdGhpcy50b2tlbi5jZWxsc1tpXTtcclxuXHJcbiAgICAgICAgY2VsbCA9ICcnO1xyXG4gICAgICAgIGZvciAoaiA9IDA7IGogPCByb3cubGVuZ3RoOyBqKyspIHtcclxuICAgICAgICAgIGNlbGwgKz0gdGhpcy5yZW5kZXJlci50YWJsZWNlbGwoXHJcbiAgICAgICAgICAgIHRoaXMuaW5saW5lLm91dHB1dChyb3dbal0pLFxyXG4gICAgICAgICAgICB7IGhlYWRlcjogZmFsc2UsIGFsaWduOiB0aGlzLnRva2VuLmFsaWduW2pdIH1cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBib2R5ICs9IHRoaXMucmVuZGVyZXIudGFibGVyb3coY2VsbCk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRoaXMucmVuZGVyZXIudGFibGUoaGVhZGVyLCBib2R5KTtcclxuICAgIH1cclxuICAgIGNhc2UgJ2Jsb2NrcXVvdGVfc3RhcnQnOiB7XHJcbiAgICAgIHZhciBib2R5ID0gJyc7XHJcblxyXG4gICAgICB3aGlsZSAodGhpcy5uZXh0KCkudHlwZSAhPT0gJ2Jsb2NrcXVvdGVfZW5kJykge1xyXG4gICAgICAgIGJvZHkgKz0gdGhpcy50b2soKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRoaXMucmVuZGVyZXIuYmxvY2txdW90ZShib2R5KTtcclxuICAgIH1cclxuICAgIGNhc2UgJ2xpc3Rfc3RhcnQnOiB7XHJcbiAgICAgIHZhciBib2R5ID0gJydcclxuICAgICAgICAsIG9yZGVyZWQgPSB0aGlzLnRva2VuLm9yZGVyZWQ7XHJcblxyXG4gICAgICB3aGlsZSAodGhpcy5uZXh0KCkudHlwZSAhPT0gJ2xpc3RfZW5kJykge1xyXG4gICAgICAgIGJvZHkgKz0gdGhpcy50b2soKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRoaXMucmVuZGVyZXIubGlzdChib2R5LCBvcmRlcmVkKTtcclxuICAgIH1cclxuICAgIGNhc2UgJ2xpc3RfaXRlbV9zdGFydCc6IHtcclxuICAgICAgdmFyIGJvZHkgPSAnJztcclxuXHJcbiAgICAgIHdoaWxlICh0aGlzLm5leHQoKS50eXBlICE9PSAnbGlzdF9pdGVtX2VuZCcpIHtcclxuICAgICAgICBib2R5ICs9IHRoaXMudG9rZW4udHlwZSA9PT0gJ3RleHQnXHJcbiAgICAgICAgICA/IHRoaXMucGFyc2VUZXh0KClcclxuICAgICAgICAgIDogdGhpcy50b2soKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRoaXMucmVuZGVyZXIubGlzdGl0ZW0oYm9keSk7XHJcbiAgICB9XHJcbiAgICBjYXNlICdsb29zZV9pdGVtX3N0YXJ0Jzoge1xyXG4gICAgICB2YXIgYm9keSA9ICcnO1xyXG5cclxuICAgICAgd2hpbGUgKHRoaXMubmV4dCgpLnR5cGUgIT09ICdsaXN0X2l0ZW1fZW5kJykge1xyXG4gICAgICAgIGJvZHkgKz0gdGhpcy50b2soKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgcmV0dXJuIHRoaXMucmVuZGVyZXIubGlzdGl0ZW0oYm9keSk7XHJcbiAgICB9XHJcbiAgICBjYXNlICdodG1sJzoge1xyXG4gICAgICB2YXIgaHRtbCA9ICF0aGlzLnRva2VuLnByZSAmJiAhdGhpcy5vcHRpb25zLnBlZGFudGljXHJcbiAgICAgICAgPyB0aGlzLmlubGluZS5vdXRwdXQodGhpcy50b2tlbi50ZXh0KVxyXG4gICAgICAgIDogdGhpcy50b2tlbi50ZXh0O1xyXG4gICAgICByZXR1cm4gdGhpcy5yZW5kZXJlci5odG1sKGh0bWwpO1xyXG4gICAgfVxyXG4gICAgY2FzZSAncGFyYWdyYXBoJzoge1xyXG4gICAgICByZXR1cm4gdGhpcy5yZW5kZXJlci5wYXJhZ3JhcGgodGhpcy5pbmxpbmUub3V0cHV0KHRoaXMudG9rZW4udGV4dCkpO1xyXG4gICAgfVxyXG4gICAgY2FzZSAndGV4dCc6IHtcclxuICAgICAgcmV0dXJuIHRoaXMucmVuZGVyZXIucGFyYWdyYXBoKHRoaXMucGFyc2VUZXh0KCkpO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBIZWxwZXJzXHJcbiAqL1xyXG5cclxuZnVuY3Rpb24gZXNjYXBlKGh0bWwsIGVuY29kZSkge1xyXG4gIHJldHVybiBodG1sXHJcbiAgICAucmVwbGFjZSghZW5jb2RlID8gLyYoPyEjP1xcdys7KS9nIDogLyYvZywgJyZhbXA7JylcclxuICAgIC5yZXBsYWNlKC88L2csICcmbHQ7JylcclxuICAgIC5yZXBsYWNlKC8+L2csICcmZ3Q7JylcclxuICAgIC5yZXBsYWNlKC9cIi9nLCAnJnF1b3Q7JylcclxuICAgIC5yZXBsYWNlKC8nL2csICcmIzM5OycpO1xyXG59XHJcblxyXG5mdW5jdGlvbiB1bmVzY2FwZShodG1sKSB7XHJcbiAgcmV0dXJuIGh0bWwucmVwbGFjZSgvJihbI1xcd10rKTsvZywgZnVuY3Rpb24oXywgbikge1xyXG4gICAgbiA9IG4udG9Mb3dlckNhc2UoKTtcclxuICAgIGlmIChuID09PSAnY29sb24nKSByZXR1cm4gJzonO1xyXG4gICAgaWYgKG4uY2hhckF0KDApID09PSAnIycpIHtcclxuICAgICAgcmV0dXJuIG4uY2hhckF0KDEpID09PSAneCdcclxuICAgICAgICA/IFN0cmluZy5mcm9tQ2hhckNvZGUocGFyc2VJbnQobi5zdWJzdHJpbmcoMiksIDE2KSlcclxuICAgICAgICA6IFN0cmluZy5mcm9tQ2hhckNvZGUoK24uc3Vic3RyaW5nKDEpKTtcclxuICAgIH1cclxuICAgIHJldHVybiAnJztcclxuICB9KTtcclxufVxyXG5cclxuZnVuY3Rpb24gcmVwbGFjZShyZWdleCwgb3B0KSB7XHJcbiAgcmVnZXggPSByZWdleC5zb3VyY2U7XHJcbiAgb3B0ID0gb3B0IHx8ICcnO1xyXG4gIHJldHVybiBmdW5jdGlvbiBzZWxmKG5hbWUsIHZhbCkge1xyXG4gICAgaWYgKCFuYW1lKSByZXR1cm4gbmV3IFJlZ0V4cChyZWdleCwgb3B0KTtcclxuICAgIHZhbCA9IHZhbC5zb3VyY2UgfHwgdmFsO1xyXG4gICAgdmFsID0gdmFsLnJlcGxhY2UoLyhefFteXFxbXSlcXF4vZywgJyQxJyk7XHJcbiAgICByZWdleCA9IHJlZ2V4LnJlcGxhY2UobmFtZSwgdmFsKTtcclxuICAgIHJldHVybiBzZWxmO1xyXG4gIH07XHJcbn1cclxuXHJcbmZ1bmN0aW9uIG5vb3AoKSB7fVxyXG5ub29wLmV4ZWMgPSBub29wO1xyXG5cclxuZnVuY3Rpb24gbWVyZ2Uob2JqKSB7XHJcbiAgdmFyIGkgPSAxXHJcbiAgICAsIHRhcmdldFxyXG4gICAgLCBrZXk7XHJcblxyXG4gIGZvciAoOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICB0YXJnZXQgPSBhcmd1bWVudHNbaV07XHJcbiAgICBmb3IgKGtleSBpbiB0YXJnZXQpIHtcclxuICAgICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0YXJnZXQsIGtleSkpIHtcclxuICAgICAgICBvYmpba2V5XSA9IHRhcmdldFtrZXldO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4gb2JqO1xyXG59XHJcblxyXG5cclxuLyoqXHJcbiAqIE1hcmtlZFxyXG4gKi9cclxuXHJcbmZ1bmN0aW9uIG1hcmtlZChzcmMsIG9wdCwgY2FsbGJhY2spIHtcclxuICBpZiAoY2FsbGJhY2sgfHwgdHlwZW9mIG9wdCA9PT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgaWYgKCFjYWxsYmFjaykge1xyXG4gICAgICBjYWxsYmFjayA9IG9wdDtcclxuICAgICAgb3B0ID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICBvcHQgPSBtZXJnZSh7fSwgbWFya2VkLmRlZmF1bHRzLCBvcHQgfHwge30pO1xyXG5cclxuICAgIHZhciBoaWdobGlnaHQgPSBvcHQuaGlnaGxpZ2h0XHJcbiAgICAgICwgdG9rZW5zXHJcbiAgICAgICwgcGVuZGluZ1xyXG4gICAgICAsIGkgPSAwO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHRva2VucyA9IExleGVyLmxleChzcmMsIG9wdClcclxuICAgIH0gY2F0Y2ggKGUpIHtcclxuICAgICAgcmV0dXJuIGNhbGxiYWNrKGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHBlbmRpbmcgPSB0b2tlbnMubGVuZ3RoO1xyXG5cclxuICAgIHZhciBkb25lID0gZnVuY3Rpb24oZXJyKSB7XHJcbiAgICAgIGlmIChlcnIpIHtcclxuICAgICAgICBvcHQuaGlnaGxpZ2h0ID0gaGlnaGxpZ2h0O1xyXG4gICAgICAgIHJldHVybiBjYWxsYmFjayhlcnIpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICB2YXIgb3V0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICBvdXQgPSBQYXJzZXIucGFyc2UodG9rZW5zLCBvcHQpO1xyXG4gICAgICB9IGNhdGNoIChlKSB7XHJcbiAgICAgICAgZXJyID0gZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgb3B0LmhpZ2hsaWdodCA9IGhpZ2hsaWdodDtcclxuXHJcbiAgICAgIHJldHVybiBlcnJcclxuICAgICAgICA/IGNhbGxiYWNrKGVycilcclxuICAgICAgICA6IGNhbGxiYWNrKG51bGwsIG91dCk7XHJcbiAgICB9O1xyXG5cclxuICAgIGlmICghaGlnaGxpZ2h0IHx8IGhpZ2hsaWdodC5sZW5ndGggPCAzKSB7XHJcbiAgICAgIHJldHVybiBkb25lKCk7XHJcbiAgICB9XHJcblxyXG4gICAgZGVsZXRlIG9wdC5oaWdobGlnaHQ7XHJcblxyXG4gICAgaWYgKCFwZW5kaW5nKSByZXR1cm4gZG9uZSgpO1xyXG5cclxuICAgIGZvciAoOyBpIDwgdG9rZW5zLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIChmdW5jdGlvbih0b2tlbikge1xyXG4gICAgICAgIGlmICh0b2tlbi50eXBlICE9PSAnY29kZScpIHtcclxuICAgICAgICAgIHJldHVybiAtLXBlbmRpbmcgfHwgZG9uZSgpO1xyXG4gICAgICAgIH1cclxuICAgICAgICByZXR1cm4gaGlnaGxpZ2h0KHRva2VuLnRleHQsIHRva2VuLmxhbmcsIGZ1bmN0aW9uKGVyciwgY29kZSkge1xyXG4gICAgICAgICAgaWYgKGVycikgcmV0dXJuIGRvbmUoZXJyKTtcclxuICAgICAgICAgIGlmIChjb2RlID09IG51bGwgfHwgY29kZSA9PT0gdG9rZW4udGV4dCkge1xyXG4gICAgICAgICAgICByZXR1cm4gLS1wZW5kaW5nIHx8IGRvbmUoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHRva2VuLnRleHQgPSBjb2RlO1xyXG4gICAgICAgICAgdG9rZW4uZXNjYXBlZCA9IHRydWU7XHJcbiAgICAgICAgICAtLXBlbmRpbmcgfHwgZG9uZSgpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KSh0b2tlbnNbaV0pO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybjtcclxuICB9XHJcbiAgdHJ5IHtcclxuICAgIGlmIChvcHQpIG9wdCA9IG1lcmdlKHt9LCBtYXJrZWQuZGVmYXVsdHMsIG9wdCk7XHJcbiAgICByZXR1cm4gUGFyc2VyLnBhcnNlKExleGVyLmxleChzcmMsIG9wdCksIG9wdCk7XHJcbiAgfSBjYXRjaCAoZSkge1xyXG4gICAgZS5tZXNzYWdlICs9ICdcXG5QbGVhc2UgcmVwb3J0IHRoaXMgdG8gaHR0cHM6Ly9naXRodWIuY29tL2NoamovbWFya2VkLic7XHJcbiAgICBpZiAoKG9wdCB8fCBtYXJrZWQuZGVmYXVsdHMpLnNpbGVudCkge1xyXG4gICAgICByZXR1cm4gJzxwPkFuIGVycm9yIG9jY3VyZWQ6PC9wPjxwcmU+J1xyXG4gICAgICAgICsgZXNjYXBlKGUubWVzc2FnZSArICcnLCB0cnVlKVxyXG4gICAgICAgICsgJzwvcHJlPic7XHJcbiAgICB9XHJcbiAgICB0aHJvdyBlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIE9wdGlvbnNcclxuICovXHJcblxyXG5tYXJrZWQub3B0aW9ucyA9XHJcbm1hcmtlZC5zZXRPcHRpb25zID0gZnVuY3Rpb24ob3B0KSB7XHJcbiAgbWVyZ2UobWFya2VkLmRlZmF1bHRzLCBvcHQpO1xyXG4gIHJldHVybiBtYXJrZWQ7XHJcbn07XHJcblxyXG5tYXJrZWQuZGVmYXVsdHMgPSB7XHJcbiAgZ2ZtOiB0cnVlLFxyXG4gIHRhYmxlczogdHJ1ZSxcclxuICBicmVha3M6IGZhbHNlLFxyXG4gIHBlZGFudGljOiBmYWxzZSxcclxuICBzYW5pdGl6ZTogZmFsc2UsXHJcbiAgc2FuaXRpemVyOiBudWxsLFxyXG4gIG1hbmdsZTogdHJ1ZSxcclxuICBzbWFydExpc3RzOiBmYWxzZSxcclxuICBzaWxlbnQ6IGZhbHNlLFxyXG4gIGhpZ2hsaWdodDogbnVsbCxcclxuICBsYW5nUHJlZml4OiAnbGFuZy0nLFxyXG4gIHNtYXJ0eXBhbnRzOiBmYWxzZSxcclxuICBoZWFkZXJQcmVmaXg6ICcnLFxyXG4gIHJlbmRlcmVyOiBuZXcgUmVuZGVyZXIsXHJcbiAgeGh0bWw6IGZhbHNlXHJcbn07XHJcblxyXG4vKipcclxuICogRXhwb3NlXHJcbiAqL1xyXG5cclxubWFya2VkLlBhcnNlciA9IFBhcnNlcjtcclxubWFya2VkLnBhcnNlciA9IFBhcnNlci5wYXJzZTtcclxuXHJcbm1hcmtlZC5SZW5kZXJlciA9IFJlbmRlcmVyO1xyXG5cclxubWFya2VkLkxleGVyID0gTGV4ZXI7XHJcbm1hcmtlZC5sZXhlciA9IExleGVyLmxleDtcclxuXHJcbm1hcmtlZC5JbmxpbmVMZXhlciA9IElubGluZUxleGVyO1xyXG5tYXJrZWQuaW5saW5lTGV4ZXIgPSBJbmxpbmVMZXhlci5vdXRwdXQ7XHJcblxyXG5tYXJrZWQucGFyc2UgPSBtYXJrZWQ7XHJcblxyXG5pZiAodHlwZW9mIG1vZHVsZSAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIGV4cG9ydHMgPT09ICdvYmplY3QnKSB7XHJcbiAgbW9kdWxlLmV4cG9ydHMgPSBtYXJrZWQ7XHJcbn0gZWxzZSBpZiAodHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kKSB7XHJcbiAgZGVmaW5lKGZ1bmN0aW9uKCkgeyByZXR1cm4gbWFya2VkOyB9KTtcclxufSBlbHNlIHtcclxuICB0aGlzLm1hcmtlZCA9IG1hcmtlZDtcclxufVxyXG5cclxufSkuY2FsbChmdW5jdGlvbigpIHtcclxuICByZXR1cm4gdGhpcyB8fCAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgPyB3aW5kb3cgOiBnbG9iYWwpO1xyXG59KCkpO1xyXG4iLCIvLyBDb2RlTWlycm9yLCBjb3B5cmlnaHQgKGMpIGJ5IE1hcmlqbiBIYXZlcmJla2UgYW5kIG90aGVyc1xyXG4vLyBEaXN0cmlidXRlZCB1bmRlciBhbiBNSVQgbGljZW5zZTogaHR0cDovL2NvZGVtaXJyb3IubmV0L0xJQ0VOU0VcclxuXHJcbnZhciBDb2RlTWlycm9yID0gcmVxdWlyZShcImNvZGVtaXJyb3JcIik7XHJcblxyXG5Db2RlTWlycm9yLmNvbW1hbmRzLnRhYkFuZEluZGVudE1hcmtkb3duTGlzdCA9IGZ1bmN0aW9uIChjbSkge1xyXG5cdHZhciByYW5nZXMgPSBjbS5saXN0U2VsZWN0aW9ucygpO1xyXG5cdHZhciBwb3MgPSByYW5nZXNbMF0uaGVhZDtcclxuXHR2YXIgZW9sU3RhdGUgPSBjbS5nZXRTdGF0ZUFmdGVyKHBvcy5saW5lKTtcclxuXHR2YXIgaW5MaXN0ID0gZW9sU3RhdGUubGlzdCAhPT0gZmFsc2U7XHJcblxyXG5cdGlmIChpbkxpc3QpIHtcclxuXHRcdGNtLmV4ZWNDb21tYW5kKFwiaW5kZW50TW9yZVwiKTtcclxuXHRcdHJldHVybjtcclxuXHR9XHJcblxyXG5cdGlmIChjbS5vcHRpb25zLmluZGVudFdpdGhUYWJzKSB7XHJcblx0XHRjbS5leGVjQ29tbWFuZChcImluc2VydFRhYlwiKTtcclxuXHR9XHJcblx0ZWxzZSB7XHJcblx0XHR2YXIgc3BhY2VzID0gQXJyYXkoY20ub3B0aW9ucy50YWJTaXplICsgMSkuam9pbihcIiBcIik7XHJcblx0XHRjbS5yZXBsYWNlU2VsZWN0aW9uKHNwYWNlcyk7XHJcblx0fVxyXG59O1xyXG5cclxuQ29kZU1pcnJvci5jb21tYW5kcy5zaGlmdFRhYkFuZFVuaW5kZW50TWFya2Rvd25MaXN0ID0gZnVuY3Rpb24gKGNtKSB7XHJcblx0dmFyIHJhbmdlcyA9IGNtLmxpc3RTZWxlY3Rpb25zKCk7XHJcblx0dmFyIHBvcyA9IHJhbmdlc1swXS5oZWFkO1xyXG5cdHZhciBlb2xTdGF0ZSA9IGNtLmdldFN0YXRlQWZ0ZXIocG9zLmxpbmUpO1xyXG5cdHZhciBpbkxpc3QgPSBlb2xTdGF0ZS5saXN0ICE9PSBmYWxzZTtcclxuXHJcblx0aWYgKGluTGlzdCkge1xyXG5cdFx0Y20uZXhlY0NvbW1hbmQoXCJpbmRlbnRMZXNzXCIpO1xyXG5cdFx0cmV0dXJuO1xyXG5cdH1cclxuXHJcblx0aWYgKGNtLm9wdGlvbnMuaW5kZW50V2l0aFRhYnMpIHtcclxuXHRcdGNtLmV4ZWNDb21tYW5kKFwiaW5zZXJ0VGFiXCIpO1xyXG5cdH1cclxuXHRlbHNlIHtcclxuXHRcdHZhciBzcGFjZXMgPSBBcnJheShjbS5vcHRpb25zLnRhYlNpemUgKyAxKS5qb2luKFwiIFwiKTtcclxuXHRcdGNtLnJlcGxhY2VTZWxlY3Rpb24oc3BhY2VzKTtcclxuXHR9XHJcbn07XHJcbiIsIi8qZ2xvYmFsIHJlcXVpcmUsbW9kdWxlKi9cblwidXNlIHN0cmljdFwiO1xudmFyIENvZGVNaXJyb3IgPSByZXF1aXJlKFwiY29kZW1pcnJvclwiKTtcbnJlcXVpcmUoXCJjb2RlbWlycm9yL2FkZG9uL2VkaXQvY29udGludWVsaXN0LmpzXCIpO1xucmVxdWlyZShcIi4vY29kZW1pcnJvci90YWJsaXN0XCIpO1xucmVxdWlyZShcImNvZGVtaXJyb3IvYWRkb24vZGlzcGxheS9mdWxsc2NyZWVuLmpzXCIpO1xucmVxdWlyZShcImNvZGVtaXJyb3IvbW9kZS9tYXJrZG93bi9tYXJrZG93bi5qc1wiKTtcbnJlcXVpcmUoXCJjb2RlbWlycm9yL2FkZG9uL21vZGUvb3ZlcmxheS5qc1wiKTtcbnJlcXVpcmUoXCJjb2RlbWlycm9yL21vZGUvZ2ZtL2dmbS5qc1wiKTtcbnJlcXVpcmUoXCJjb2RlbWlycm9yL21vZGUveG1sL3htbC5qc1wiKTtcbnJlcXVpcmUoXCJzcGVsbC1jaGVja2VyXCIpO1xudmFyIG1hcmtlZCA9IHJlcXVpcmUoXCJtYXJrZWRcIik7XG5cblxuLy8gU29tZSB2YXJpYWJsZXNcbnZhciBpc01hYyA9IC9NYWMvLnRlc3QobmF2aWdhdG9yLnBsYXRmb3JtKTtcblxudmFyIHNob3J0Y3V0cyA9IHtcblx0XCJDbWQtQlwiOiB0b2dnbGVCb2xkLFxuXHRcIkNtZC1JXCI6IHRvZ2dsZUl0YWxpYyxcblx0XCJDbWQtS1wiOiBkcmF3TGluayxcblx0XCJDbWQtSFwiOiB0b2dnbGVIZWFkaW5nU21hbGxlcixcblx0XCJTaGlmdC1DbWQtSFwiOiB0b2dnbGVIZWFkaW5nQmlnZ2VyLFxuXHRcIkNtZC1BbHQtSVwiOiBkcmF3SW1hZ2UsXG5cdFwiQ21kLSdcIjogdG9nZ2xlQmxvY2txdW90ZSxcblx0XCJDbWQtQWx0LUxcIjogdG9nZ2xlT3JkZXJlZExpc3QsXG5cdFwiQ21kLUxcIjogdG9nZ2xlVW5vcmRlcmVkTGlzdCxcblx0XCJDbWQtQWx0LUNcIjogdG9nZ2xlQ29kZUJsb2NrLFxuXHRcIkNtZC1QXCI6IHRvZ2dsZVByZXZpZXdcbn07XG5cbnZhciBpc01vYmlsZSA9IGZ1bmN0aW9uKCkge1xuXHR2YXIgY2hlY2sgPSBmYWxzZTtcblx0KGZ1bmN0aW9uKGEpIHtcblx0XHRpZigvKGFuZHJvaWR8YmJcXGQrfG1lZWdvKS4rbW9iaWxlfGF2YW50Z298YmFkYVxcL3xibGFja2JlcnJ5fGJsYXplcnxjb21wYWx8ZWxhaW5lfGZlbm5lY3xoaXB0b3B8aWVtb2JpbGV8aXAoaG9uZXxvZCl8aXJpc3xraW5kbGV8bGdlIHxtYWVtb3xtaWRwfG1tcHxtb2JpbGUuK2ZpcmVmb3h8bmV0ZnJvbnR8b3BlcmEgbShvYnxpbilpfHBhbG0oIG9zKT98cGhvbmV8cChpeGl8cmUpXFwvfHBsdWNrZXJ8cG9ja2V0fHBzcHxzZXJpZXMoNHw2KTB8c3ltYmlhbnx0cmVvfHVwXFwuKGJyb3dzZXJ8bGluayl8dm9kYWZvbmV8d2FwfHdpbmRvd3MgY2V8eGRhfHhpaW5vfGFuZHJvaWR8aXBhZHxwbGF5Ym9va3xzaWxrL2kudGVzdChhKSB8fCAvMTIwN3w2MzEwfDY1OTB8M2dzb3w0dGhwfDUwWzEtNl1pfDc3MHN8ODAyc3xhIHdhfGFiYWN8YWMoZXJ8b298c1xcLSl8YWkoa298cm4pfGFsKGF2fGNhfGNvKXxhbW9pfGFuKGV4fG55fHl3KXxhcHR1fGFyKGNofGdvKXxhcyh0ZXx1cyl8YXR0d3xhdShkaXxcXC1tfHIgfHMgKXxhdmFufGJlKGNrfGxsfG5xKXxiaShsYnxyZCl8YmwoYWN8YXopfGJyKGV8dil3fGJ1bWJ8YndcXC0obnx1KXxjNTVcXC98Y2FwaXxjY3dhfGNkbVxcLXxjZWxsfGNodG18Y2xkY3xjbWRcXC18Y28obXB8bmQpfGNyYXd8ZGEoaXR8bGx8bmcpfGRidGV8ZGNcXC1zfGRldml8ZGljYXxkbW9ifGRvKGN8cClvfGRzKDEyfFxcLWQpfGVsKDQ5fGFpKXxlbShsMnx1bCl8ZXIoaWN8azApfGVzbDh8ZXooWzQtN10wfG9zfHdhfHplKXxmZXRjfGZseShcXC18Xyl8ZzEgdXxnNTYwfGdlbmV8Z2ZcXC01fGdcXC1tb3xnbyhcXC53fG9kKXxncihhZHx1bil8aGFpZXxoY2l0fGhkXFwtKG18cHx0KXxoZWlcXC18aGkocHR8dGEpfGhwKCBpfGlwKXxoc1xcLWN8aHQoYyhcXC18IHxffGF8Z3xwfHN8dCl8dHApfGh1KGF3fHRjKXxpXFwtKDIwfGdvfG1hKXxpMjMwfGlhYyggfFxcLXxcXC8pfGlicm98aWRlYXxpZzAxfGlrb218aW0xa3xpbm5vfGlwYXF8aXJpc3xqYSh0fHYpYXxqYnJvfGplbXV8amlnc3xrZGRpfGtlaml8a2d0KCB8XFwvKXxrbG9ufGtwdCB8a3djXFwtfGt5byhjfGspfGxlKG5vfHhpKXxsZyggZ3xcXC8oa3xsfHUpfDUwfDU0fFxcLVthLXddKXxsaWJ3fGx5bnh8bTFcXC13fG0zZ2F8bTUwXFwvfG1hKHRlfHVpfHhvKXxtYygwMXwyMXxjYSl8bVxcLWNyfG1lKHJjfHJpKXxtaShvOHxvYXx0cyl8bW1lZnxtbygwMXwwMnxiaXxkZXxkb3x0KFxcLXwgfG98dil8enopfG10KDUwfHAxfHYgKXxtd2JwfG15d2F8bjEwWzAtMl18bjIwWzItM118bjMwKDB8Mil8bjUwKDB8Mnw1KXxuNygwKDB8MSl8MTApfG5lKChjfG0pXFwtfG9ufHRmfHdmfHdnfHd0KXxub2soNnxpKXxuenBofG8yaW18b3AodGl8d3YpfG9yYW58b3dnMXxwODAwfHBhbihhfGR8dCl8cGR4Z3xwZygxM3xcXC0oWzEtOF18YykpfHBoaWx8cGlyZXxwbChheXx1Yyl8cG5cXC0yfHBvKGNrfHJ0fHNlKXxwcm94fHBzaW98cHRcXC1nfHFhXFwtYXxxYygwN3wxMnwyMXwzMnw2MHxcXC1bMi03XXxpXFwtKXxxdGVrfHIzODB8cjYwMHxyYWtzfHJpbTl8cm8odmV8em8pfHM1NVxcL3xzYShnZXxtYXxtbXxtc3xueXx2YSl8c2MoMDF8aFxcLXxvb3xwXFwtKXxzZGtcXC98c2UoYyhcXC18MHwxKXw0N3xtY3xuZHxyaSl8c2doXFwtfHNoYXJ8c2llKFxcLXxtKXxza1xcLTB8c2woNDV8aWQpfHNtKGFsfGFyfGIzfGl0fHQ1KXxzbyhmdHxueSl8c3AoMDF8aFxcLXx2XFwtfHYgKXxzeSgwMXxtYil8dDIoMTh8NTApfHQ2KDAwfDEwfDE4KXx0YShndHxsayl8dGNsXFwtfHRkZ1xcLXx0ZWwoaXxtKXx0aW1cXC18dFxcLW1vfHRvKHBsfHNoKXx0cyg3MHxtXFwtfG0zfG01KXx0eFxcLTl8dXAoXFwuYnxnMXxzaSl8dXRzdHx2NDAwfHY3NTB8dmVyaXx2aShyZ3x0ZSl8dmsoNDB8NVswLTNdfFxcLXYpfHZtNDB8dm9kYXx2dWxjfHZ4KDUyfDUzfDYwfDYxfDcwfDgwfDgxfDgzfDg1fDk4KXx3M2MoXFwtfCApfHdlYmN8d2hpdHx3aShnIHxuY3xudyl8d21sYnx3b251fHg3MDB8eWFzXFwtfHlvdXJ8emV0b3x6dGVcXC0vaS50ZXN0KGEuc3Vic3RyKDAsIDQpKSkgY2hlY2sgPSB0cnVlO1xuXHR9KShuYXZpZ2F0b3IudXNlckFnZW50IHx8IG5hdmlnYXRvci52ZW5kb3IgfHwgd2luZG93Lm9wZXJhKTtcblx0cmV0dXJuIGNoZWNrO1xufTtcblxuXG4vKipcbiAqIEZpeCBzaG9ydGN1dC4gTWFjIHVzZSBDb21tYW5kLCBvdGhlcnMgdXNlIEN0cmwuXG4gKi9cbmZ1bmN0aW9uIGZpeFNob3J0Y3V0KG5hbWUpIHtcblx0aWYoaXNNYWMpIHtcblx0XHRuYW1lID0gbmFtZS5yZXBsYWNlKFwiQ3RybFwiLCBcIkNtZFwiKTtcblx0fSBlbHNlIHtcblx0XHRuYW1lID0gbmFtZS5yZXBsYWNlKFwiQ21kXCIsIFwiQ3RybFwiKTtcblx0fVxuXHRyZXR1cm4gbmFtZTtcbn1cblxuXG4vKipcbiAqIENyZWF0ZSBpY29uIGVsZW1lbnQgZm9yIHRvb2xiYXIuXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUljb24ob3B0aW9ucywgZW5hYmxlVG9vbHRpcHMpIHtcblx0b3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cdHZhciBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJhXCIpO1xuXHRlbmFibGVUb29sdGlwcyA9IChlbmFibGVUb29sdGlwcyA9PSB1bmRlZmluZWQpID8gdHJ1ZSA6IGVuYWJsZVRvb2x0aXBzO1xuXG5cdGlmKG9wdGlvbnMudGl0bGUgJiYgZW5hYmxlVG9vbHRpcHMpIHtcblx0XHRlbC50aXRsZSA9IG9wdGlvbnMudGl0bGU7XG5cblx0XHRpZihpc01hYykge1xuXHRcdFx0ZWwudGl0bGUgPSBlbC50aXRsZS5yZXBsYWNlKFwiQ3RybFwiLCBcIuKMmFwiKTtcblx0XHRcdGVsLnRpdGxlID0gZWwudGl0bGUucmVwbGFjZShcIkFsdFwiLCBcIuKMpVwiKTtcblx0XHR9XG5cdH1cblxuXHRlbC5jbGFzc05hbWUgPSBvcHRpb25zLmNsYXNzTmFtZTtcblx0cmV0dXJuIGVsO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVTZXAoKSB7XG5cdHZhciBlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJpXCIpO1xuXHRlbC5jbGFzc05hbWUgPSBcInNlcGFyYXRvclwiO1xuXHRlbC5pbm5lckhUTUwgPSBcInxcIjtcblx0cmV0dXJuIGVsO1xufVxuXG5cbi8qKlxuICogVGhlIHN0YXRlIG9mIENvZGVNaXJyb3IgYXQgdGhlIGdpdmVuIHBvc2l0aW9uLlxuICovXG5mdW5jdGlvbiBnZXRTdGF0ZShjbSwgcG9zKSB7XG5cdHBvcyA9IHBvcyB8fCBjbS5nZXRDdXJzb3IoXCJzdGFydFwiKTtcblx0dmFyIHN0YXQgPSBjbS5nZXRUb2tlbkF0KHBvcyk7XG5cdGlmKCFzdGF0LnR5cGUpIHJldHVybiB7fTtcblxuXHR2YXIgdHlwZXMgPSBzdGF0LnR5cGUuc3BsaXQoXCIgXCIpO1xuXG5cdHZhciByZXQgPSB7fSxcblx0XHRkYXRhLCB0ZXh0O1xuXHRmb3IodmFyIGkgPSAwOyBpIDwgdHlwZXMubGVuZ3RoOyBpKyspIHtcblx0XHRkYXRhID0gdHlwZXNbaV07XG5cdFx0aWYoZGF0YSA9PT0gXCJzdHJvbmdcIikge1xuXHRcdFx0cmV0LmJvbGQgPSB0cnVlO1xuXHRcdH0gZWxzZSBpZihkYXRhID09PSBcInZhcmlhYmxlLTJcIikge1xuXHRcdFx0dGV4dCA9IGNtLmdldExpbmUocG9zLmxpbmUpO1xuXHRcdFx0aWYoL15cXHMqXFxkK1xcLlxccy8udGVzdCh0ZXh0KSkge1xuXHRcdFx0XHRyZXRbXCJvcmRlcmVkLWxpc3RcIl0gPSB0cnVlO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmV0W1widW5vcmRlcmVkLWxpc3RcIl0gPSB0cnVlO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSBpZihkYXRhID09PSBcImF0b21cIikge1xuXHRcdFx0cmV0LnF1b3RlID0gdHJ1ZTtcblx0XHR9IGVsc2UgaWYoZGF0YSA9PT0gXCJlbVwiKSB7XG5cdFx0XHRyZXQuaXRhbGljID0gdHJ1ZTtcblx0XHR9IGVsc2UgaWYoZGF0YSA9PT0gXCJxdW90ZVwiKSB7XG5cdFx0XHRyZXQucXVvdGUgPSB0cnVlO1xuXHRcdH0gZWxzZSBpZihkYXRhID09PSBcInN0cmlrZXRocm91Z2hcIikge1xuXHRcdFx0cmV0LnN0cmlrZXRocm91Z2ggPSB0cnVlO1xuXHRcdH0gZWxzZSBpZihkYXRhID09PSBcImNvbW1lbnRcIikge1xuXHRcdFx0cmV0LmNvZGUgPSB0cnVlO1xuXHRcdH1cblx0fVxuXHRyZXR1cm4gcmV0O1xufVxuXG5cbi8vIFNhdmVkIG92ZXJmbG93IHNldHRpbmdcbnZhciBzYXZlZF9vdmVyZmxvdyA9IFwiXCI7XG5cbi8qKlxuICogVG9nZ2xlIGZ1bGwgc2NyZWVuIG9mIHRoZSBlZGl0b3IuXG4gKi9cbmZ1bmN0aW9uIHRvZ2dsZUZ1bGxTY3JlZW4oZWRpdG9yKSB7XG5cdC8vIFNldCBmdWxsc2NyZWVuXG5cdHZhciBjbSA9IGVkaXRvci5jb2RlbWlycm9yO1xuXHRjbS5zZXRPcHRpb24oXCJmdWxsU2NyZWVuXCIsICFjbS5nZXRPcHRpb24oXCJmdWxsU2NyZWVuXCIpKTtcblxuXG5cdC8vIFByZXZlbnQgc2Nyb2xsaW5nIG9uIGJvZHkgZHVyaW5nIGZ1bGxzY3JlZW4gYWN0aXZlXG5cdGlmKGNtLmdldE9wdGlvbihcImZ1bGxTY3JlZW5cIikpIHtcblx0XHRzYXZlZF9vdmVyZmxvdyA9IGRvY3VtZW50LmJvZHkuc3R5bGUub3ZlcmZsb3c7XG5cdFx0ZG9jdW1lbnQuYm9keS5zdHlsZS5vdmVyZmxvdyA9IFwiaGlkZGVuXCI7XG5cdH0gZWxzZSB7XG5cdFx0ZG9jdW1lbnQuYm9keS5zdHlsZS5vdmVyZmxvdyA9IHNhdmVkX292ZXJmbG93O1xuXHR9XG5cblxuXHQvLyBVcGRhdGUgdG9vbGJhciBjbGFzc1xuXHR2YXIgd3JhcCA9IGNtLmdldFdyYXBwZXJFbGVtZW50KCk7XG5cblx0aWYoIS9mdWxsc2NyZWVuLy50ZXN0KHdyYXAucHJldmlvdXNTaWJsaW5nLmNsYXNzTmFtZSkpIHtcblx0XHR3cmFwLnByZXZpb3VzU2libGluZy5jbGFzc05hbWUgKz0gXCIgZnVsbHNjcmVlblwiO1xuXHR9IGVsc2Uge1xuXHRcdHdyYXAucHJldmlvdXNTaWJsaW5nLmNsYXNzTmFtZSA9IHdyYXAucHJldmlvdXNTaWJsaW5nLmNsYXNzTmFtZS5yZXBsYWNlKC9cXHMqZnVsbHNjcmVlblxcYi8sIFwiXCIpO1xuXHR9XG5cblxuXHQvLyBVcGRhdGUgdG9vbGJhciBidXR0b25cblx0dmFyIHRvb2xiYXJCdXR0b24gPSBlZGl0b3IudG9vbGJhckVsZW1lbnRzLmZ1bGxzY3JlZW47XG5cblx0aWYoIS9hY3RpdmUvLnRlc3QodG9vbGJhckJ1dHRvbi5jbGFzc05hbWUpKSB7XG5cdFx0dG9vbGJhckJ1dHRvbi5jbGFzc05hbWUgKz0gXCIgYWN0aXZlXCI7XG5cdH0gZWxzZSB7XG5cdFx0dG9vbGJhckJ1dHRvbi5jbGFzc05hbWUgPSB0b29sYmFyQnV0dG9uLmNsYXNzTmFtZS5yZXBsYWNlKC9cXHMqYWN0aXZlXFxzKi9nLCBcIlwiKTtcblx0fVxuXG5cblx0Ly8gSGlkZSBzaWRlIGJ5IHNpZGUgaWYgbmVlZGVkXG5cdHZhciBzaWRlYnlzaWRlID0gY20uZ2V0V3JhcHBlckVsZW1lbnQoKS5uZXh0U2libGluZztcblx0aWYoL2VkaXRvci1wcmV2aWV3LWFjdGl2ZS1zaWRlLy50ZXN0KHNpZGVieXNpZGUuY2xhc3NOYW1lKSlcblx0XHR0b2dnbGVTaWRlQnlTaWRlKGVkaXRvcik7XG59XG5cblxuLyoqXG4gKiBBY3Rpb24gZm9yIHRvZ2dsaW5nIGJvbGQuXG4gKi9cbmZ1bmN0aW9uIHRvZ2dsZUJvbGQoZWRpdG9yKSB7XG5cdF90b2dnbGVCbG9jayhlZGl0b3IsIFwiYm9sZFwiLCBlZGl0b3Iub3B0aW9ucy5ibG9ja1N0eWxlcy5ib2xkKTtcbn1cblxuXG4vKipcbiAqIEFjdGlvbiBmb3IgdG9nZ2xpbmcgaXRhbGljLlxuICovXG5mdW5jdGlvbiB0b2dnbGVJdGFsaWMoZWRpdG9yKSB7XG5cdF90b2dnbGVCbG9jayhlZGl0b3IsIFwiaXRhbGljXCIsIGVkaXRvci5vcHRpb25zLmJsb2NrU3R5bGVzLml0YWxpYyk7XG59XG5cblxuLyoqXG4gKiBBY3Rpb24gZm9yIHRvZ2dsaW5nIHN0cmlrZXRocm91Z2guXG4gKi9cbmZ1bmN0aW9uIHRvZ2dsZVN0cmlrZXRocm91Z2goZWRpdG9yKSB7XG5cdF90b2dnbGVCbG9jayhlZGl0b3IsIFwic3RyaWtldGhyb3VnaFwiLCBcIn5+XCIpO1xufVxuXG4vKipcbiAqIEFjdGlvbiBmb3IgdG9nZ2xpbmcgY29kZSBibG9jay5cbiAqL1xuZnVuY3Rpb24gdG9nZ2xlQ29kZUJsb2NrKGVkaXRvcikge1xuXHRfdG9nZ2xlQmxvY2soZWRpdG9yLCBcImNvZGVcIiwgXCJgYGBcXHJcXG5cIiwgXCJcXHJcXG5gYGBcIik7XG59XG5cbi8qKlxuICogQWN0aW9uIGZvciB0b2dnbGluZyBibG9ja3F1b3RlLlxuICovXG5mdW5jdGlvbiB0b2dnbGVCbG9ja3F1b3RlKGVkaXRvcikge1xuXHR2YXIgY20gPSBlZGl0b3IuY29kZW1pcnJvcjtcblx0X3RvZ2dsZUxpbmUoY20sIFwicXVvdGVcIik7XG59XG5cbi8qKlxuICogQWN0aW9uIGZvciB0b2dnbGluZyBoZWFkaW5nIHNpemU6IG5vcm1hbCAtPiBoMSAtPiBoMiAtPiBoMyAtPiBoNCAtPiBoNSAtPiBoNiAtPiBub3JtYWxcbiAqL1xuZnVuY3Rpb24gdG9nZ2xlSGVhZGluZ1NtYWxsZXIoZWRpdG9yKSB7XG5cdHZhciBjbSA9IGVkaXRvci5jb2RlbWlycm9yO1xuXHRfdG9nZ2xlSGVhZGluZyhjbSwgXCJzbWFsbGVyXCIpO1xufVxuXG4vKipcbiAqIEFjdGlvbiBmb3IgdG9nZ2xpbmcgaGVhZGluZyBzaXplOiBub3JtYWwgLT4gaDYgLT4gaDUgLT4gaDQgLT4gaDMgLT4gaDIgLT4gaDEgLT4gbm9ybWFsXG4gKi9cbmZ1bmN0aW9uIHRvZ2dsZUhlYWRpbmdCaWdnZXIoZWRpdG9yKSB7XG5cdHZhciBjbSA9IGVkaXRvci5jb2RlbWlycm9yO1xuXHRfdG9nZ2xlSGVhZGluZyhjbSwgXCJiaWdnZXJcIik7XG59XG5cbi8qKlxuICogQWN0aW9uIGZvciB0b2dnbGluZyBoZWFkaW5nIHNpemUgMVxuICovXG5mdW5jdGlvbiB0b2dnbGVIZWFkaW5nMShlZGl0b3IpIHtcblx0dmFyIGNtID0gZWRpdG9yLmNvZGVtaXJyb3I7XG5cdF90b2dnbGVIZWFkaW5nKGNtLCB1bmRlZmluZWQsIDEpO1xufVxuXG4vKipcbiAqIEFjdGlvbiBmb3IgdG9nZ2xpbmcgaGVhZGluZyBzaXplIDJcbiAqL1xuZnVuY3Rpb24gdG9nZ2xlSGVhZGluZzIoZWRpdG9yKSB7XG5cdHZhciBjbSA9IGVkaXRvci5jb2RlbWlycm9yO1xuXHRfdG9nZ2xlSGVhZGluZyhjbSwgdW5kZWZpbmVkLCAyKTtcbn1cblxuLyoqXG4gKiBBY3Rpb24gZm9yIHRvZ2dsaW5nIGhlYWRpbmcgc2l6ZSAzXG4gKi9cbmZ1bmN0aW9uIHRvZ2dsZUhlYWRpbmczKGVkaXRvcikge1xuXHR2YXIgY20gPSBlZGl0b3IuY29kZW1pcnJvcjtcblx0X3RvZ2dsZUhlYWRpbmcoY20sIHVuZGVmaW5lZCwgMyk7XG59XG5cblxuLyoqXG4gKiBBY3Rpb24gZm9yIHRvZ2dsaW5nIHVsLlxuICovXG5mdW5jdGlvbiB0b2dnbGVVbm9yZGVyZWRMaXN0KGVkaXRvcikge1xuXHR2YXIgY20gPSBlZGl0b3IuY29kZW1pcnJvcjtcblx0X3RvZ2dsZUxpbmUoY20sIFwidW5vcmRlcmVkLWxpc3RcIik7XG59XG5cblxuLyoqXG4gKiBBY3Rpb24gZm9yIHRvZ2dsaW5nIG9sLlxuICovXG5mdW5jdGlvbiB0b2dnbGVPcmRlcmVkTGlzdChlZGl0b3IpIHtcblx0dmFyIGNtID0gZWRpdG9yLmNvZGVtaXJyb3I7XG5cdF90b2dnbGVMaW5lKGNtLCBcIm9yZGVyZWQtbGlzdFwiKTtcbn1cblxuLyoqXG4gKiBBY3Rpb24gZm9yIGRyYXdpbmcgYSBsaW5rLlxuICovXG5mdW5jdGlvbiBkcmF3TGluayhlZGl0b3IpIHtcblx0dmFyIGNtID0gZWRpdG9yLmNvZGVtaXJyb3I7XG5cdHZhciBzdGF0ID0gZ2V0U3RhdGUoY20pO1xuXHR2YXIgb3B0aW9ucyA9IGVkaXRvci5vcHRpb25zO1xuXHRfcmVwbGFjZVNlbGVjdGlvbihjbSwgc3RhdC5saW5rLCBvcHRpb25zLmluc2VydFRleHRzLmxpbmspO1xufVxuXG4vKipcbiAqIEFjdGlvbiBmb3IgZHJhd2luZyBhbiBpbWcuXG4gKi9cbmZ1bmN0aW9uIGRyYXdJbWFnZShlZGl0b3IpIHtcblx0dmFyIGNtID0gZWRpdG9yLmNvZGVtaXJyb3I7XG5cdHZhciBzdGF0ID0gZ2V0U3RhdGUoY20pO1xuXHR2YXIgb3B0aW9ucyA9IGVkaXRvci5vcHRpb25zO1xuXHRfcmVwbGFjZVNlbGVjdGlvbihjbSwgc3RhdC5pbWFnZSwgb3B0aW9ucy5pbnNlcnRUZXh0cy5pbWFnZSk7XG59XG5cbi8qKlxuICogQWN0aW9uIGZvciBkcmF3aW5nIGEgdGFibGUuXG4gKi9cbmZ1bmN0aW9uIGRyYXdUYWJsZShlZGl0b3IpIHtcblx0dmFyIGNtID0gZWRpdG9yLmNvZGVtaXJyb3I7XG5cdHZhciBzdGF0ID0gZ2V0U3RhdGUoY20pO1xuXHR2YXIgb3B0aW9ucyA9IGVkaXRvci5vcHRpb25zO1xuXHRfcmVwbGFjZVNlbGVjdGlvbihjbSwgc3RhdC50YWJsZSwgb3B0aW9ucy5pbnNlcnRUZXh0cy50YWJsZSk7XG59XG5cbi8qKlxuICogQWN0aW9uIGZvciBkcmF3aW5nIGEgaG9yaXpvbnRhbCBydWxlLlxuICovXG5mdW5jdGlvbiBkcmF3SG9yaXpvbnRhbFJ1bGUoZWRpdG9yKSB7XG5cdHZhciBjbSA9IGVkaXRvci5jb2RlbWlycm9yO1xuXHR2YXIgc3RhdCA9IGdldFN0YXRlKGNtKTtcblx0dmFyIG9wdGlvbnMgPSBlZGl0b3Iub3B0aW9ucztcblx0X3JlcGxhY2VTZWxlY3Rpb24oY20sIHN0YXQuaW1hZ2UsIG9wdGlvbnMuaW5zZXJ0VGV4dHMuaG9yaXpvbnRhbFJ1bGUpO1xufVxuXG5cbi8qKlxuICogVW5kbyBhY3Rpb24uXG4gKi9cbmZ1bmN0aW9uIHVuZG8oZWRpdG9yKSB7XG5cdHZhciBjbSA9IGVkaXRvci5jb2RlbWlycm9yO1xuXHRjbS51bmRvKCk7XG5cdGNtLmZvY3VzKCk7XG59XG5cblxuLyoqXG4gKiBSZWRvIGFjdGlvbi5cbiAqL1xuZnVuY3Rpb24gcmVkbyhlZGl0b3IpIHtcblx0dmFyIGNtID0gZWRpdG9yLmNvZGVtaXJyb3I7XG5cdGNtLnJlZG8oKTtcblx0Y20uZm9jdXMoKTtcbn1cblxuXG4vKipcbiAqIFRvZ2dsZSBzaWRlIGJ5IHNpZGUgcHJldmlld1xuICovXG5mdW5jdGlvbiB0b2dnbGVTaWRlQnlTaWRlKGVkaXRvcikge1xuXHR2YXIgY20gPSBlZGl0b3IuY29kZW1pcnJvcjtcblx0dmFyIHdyYXBwZXIgPSBjbS5nZXRXcmFwcGVyRWxlbWVudCgpO1xuXHR2YXIgcHJldmlldyA9IHdyYXBwZXIubmV4dFNpYmxpbmc7XG5cdHZhciB0b29sYmFyQnV0dG9uID0gZWRpdG9yLnRvb2xiYXJFbGVtZW50c1tcInNpZGUtYnktc2lkZVwiXTtcblxuXHRpZigvZWRpdG9yLXByZXZpZXctYWN0aXZlLXNpZGUvLnRlc3QocHJldmlldy5jbGFzc05hbWUpKSB7XG5cdFx0cHJldmlldy5jbGFzc05hbWUgPSBwcmV2aWV3LmNsYXNzTmFtZS5yZXBsYWNlKFxuXHRcdFx0L1xccyplZGl0b3ItcHJldmlldy1hY3RpdmUtc2lkZVxccyovZywgXCJcIlxuXHRcdCk7XG5cdFx0dG9vbGJhckJ1dHRvbi5jbGFzc05hbWUgPSB0b29sYmFyQnV0dG9uLmNsYXNzTmFtZS5yZXBsYWNlKC9cXHMqYWN0aXZlXFxzKi9nLCBcIlwiKTtcblx0XHR3cmFwcGVyLmNsYXNzTmFtZSA9IHdyYXBwZXIuY2xhc3NOYW1lLnJlcGxhY2UoL1xccypDb2RlTWlycm9yLXNpZGVkXFxzKi9nLCBcIiBcIik7XG5cdH0gZWxzZSB7XG5cdFx0Ly8gV2hlbiB0aGUgcHJldmlldyBidXR0b24gaXMgY2xpY2tlZCBmb3IgdGhlIGZpcnN0IHRpbWUsXG5cdFx0Ly8gZ2l2ZSBzb21lIHRpbWUgZm9yIHRoZSB0cmFuc2l0aW9uIGZyb20gZWRpdG9yLmNzcyB0byBmaXJlIGFuZCB0aGUgdmlldyB0byBzbGlkZSBmcm9tIHJpZ2h0IHRvIGxlZnQsXG5cdFx0Ly8gaW5zdGVhZCBvZiBqdXN0IGFwcGVhcmluZy5cblx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYoIWNtLmdldE9wdGlvbihcImZ1bGxTY3JlZW5cIikpXG5cdFx0XHRcdHRvZ2dsZUZ1bGxTY3JlZW4oZWRpdG9yKTtcblx0XHRcdHByZXZpZXcuY2xhc3NOYW1lICs9IFwiIGVkaXRvci1wcmV2aWV3LWFjdGl2ZS1zaWRlXCI7XG5cdFx0fSwgMSk7XG5cdFx0dG9vbGJhckJ1dHRvbi5jbGFzc05hbWUgKz0gXCIgYWN0aXZlXCI7XG5cdFx0d3JhcHBlci5jbGFzc05hbWUgKz0gXCIgQ29kZU1pcnJvci1zaWRlZFwiO1xuXHR9XG5cblx0Ly8gSGlkZSBub3JtYWwgcHJldmlldyBpZiBhY3RpdmVcblx0dmFyIHByZXZpZXdOb3JtYWwgPSB3cmFwcGVyLmxhc3RDaGlsZDtcblx0aWYoL2VkaXRvci1wcmV2aWV3LWFjdGl2ZS8udGVzdChwcmV2aWV3Tm9ybWFsLmNsYXNzTmFtZSkpIHtcblx0XHRwcmV2aWV3Tm9ybWFsLmNsYXNzTmFtZSA9IHByZXZpZXdOb3JtYWwuY2xhc3NOYW1lLnJlcGxhY2UoXG5cdFx0XHQvXFxzKmVkaXRvci1wcmV2aWV3LWFjdGl2ZVxccyovZywgXCJcIlxuXHRcdCk7XG5cdFx0dmFyIHRvb2xiYXIgPSBlZGl0b3IudG9vbGJhckVsZW1lbnRzLnByZXZpZXc7XG5cdFx0dmFyIHRvb2xiYXJfZGl2ID0gd3JhcHBlci5wcmV2aW91c1NpYmxpbmc7XG5cdFx0dG9vbGJhci5jbGFzc05hbWUgPSB0b29sYmFyLmNsYXNzTmFtZS5yZXBsYWNlKC9cXHMqYWN0aXZlXFxzKi9nLCBcIlwiKTtcblx0XHR0b29sYmFyX2Rpdi5jbGFzc05hbWUgPSB0b29sYmFyX2Rpdi5jbGFzc05hbWUucmVwbGFjZSgvXFxzKmRpc2FibGVkLWZvci1wcmV2aWV3Ki9nLCBcIlwiKTtcblx0fVxuXG5cdC8vIFN0YXJ0IHByZXZpZXcgd2l0aCB0aGUgY3VycmVudCB0ZXh0XG5cdHByZXZpZXcuaW5uZXJIVE1MID0gZWRpdG9yLm9wdGlvbnMucHJldmlld1JlbmRlcihlZGl0b3IudmFsdWUoKSwgcHJldmlldyk7XG5cblx0Ly8gVXBkYXRlcyBwcmV2aWV3XG5cdGNtLm9uKFwidXBkYXRlXCIsIGZ1bmN0aW9uKCkge1xuXHRcdHByZXZpZXcuaW5uZXJIVE1MID0gZWRpdG9yLm9wdGlvbnMucHJldmlld1JlbmRlcihlZGl0b3IudmFsdWUoKSwgcHJldmlldyk7XG5cdH0pO1xufVxuXG5cbi8qKlxuICogUHJldmlldyBhY3Rpb24uXG4gKi9cbmZ1bmN0aW9uIHRvZ2dsZVByZXZpZXcoZWRpdG9yKSB7XG5cdHZhciBjbSA9IGVkaXRvci5jb2RlbWlycm9yO1xuXHR2YXIgd3JhcHBlciA9IGNtLmdldFdyYXBwZXJFbGVtZW50KCk7XG5cdHZhciB0b29sYmFyX2RpdiA9IHdyYXBwZXIucHJldmlvdXNTaWJsaW5nO1xuXHR2YXIgdG9vbGJhciA9IGVkaXRvci50b29sYmFyRWxlbWVudHMucHJldmlldztcblx0dmFyIHByZXZpZXcgPSB3cmFwcGVyLmxhc3RDaGlsZDtcblx0aWYoIXByZXZpZXcgfHwgIS9lZGl0b3ItcHJldmlldy8udGVzdChwcmV2aWV3LmNsYXNzTmFtZSkpIHtcblx0XHRwcmV2aWV3ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcblx0XHRwcmV2aWV3LmNsYXNzTmFtZSA9IFwiZWRpdG9yLXByZXZpZXdcIjtcblx0XHR3cmFwcGVyLmFwcGVuZENoaWxkKHByZXZpZXcpO1xuXHR9XG5cdGlmKC9lZGl0b3ItcHJldmlldy1hY3RpdmUvLnRlc3QocHJldmlldy5jbGFzc05hbWUpKSB7XG5cdFx0cHJldmlldy5jbGFzc05hbWUgPSBwcmV2aWV3LmNsYXNzTmFtZS5yZXBsYWNlKFxuXHRcdFx0L1xccyplZGl0b3ItcHJldmlldy1hY3RpdmVcXHMqL2csIFwiXCJcblx0XHQpO1xuXHRcdHRvb2xiYXIuY2xhc3NOYW1lID0gdG9vbGJhci5jbGFzc05hbWUucmVwbGFjZSgvXFxzKmFjdGl2ZVxccyovZywgXCJcIik7XG5cdFx0dG9vbGJhcl9kaXYuY2xhc3NOYW1lID0gdG9vbGJhcl9kaXYuY2xhc3NOYW1lLnJlcGxhY2UoL1xccypkaXNhYmxlZC1mb3ItcHJldmlldyovZywgXCJcIik7XG5cdH0gZWxzZSB7XG5cdFx0Ly8gV2hlbiB0aGUgcHJldmlldyBidXR0b24gaXMgY2xpY2tlZCBmb3IgdGhlIGZpcnN0IHRpbWUsXG5cdFx0Ly8gZ2l2ZSBzb21lIHRpbWUgZm9yIHRoZSB0cmFuc2l0aW9uIGZyb20gZWRpdG9yLmNzcyB0byBmaXJlIGFuZCB0aGUgdmlldyB0byBzbGlkZSBmcm9tIHJpZ2h0IHRvIGxlZnQsXG5cdFx0Ly8gaW5zdGVhZCBvZiBqdXN0IGFwcGVhcmluZy5cblx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuXHRcdFx0cHJldmlldy5jbGFzc05hbWUgKz0gXCIgZWRpdG9yLXByZXZpZXctYWN0aXZlXCI7XG5cdFx0fSwgMSk7XG5cdFx0dG9vbGJhci5jbGFzc05hbWUgKz0gXCIgYWN0aXZlXCI7XG5cdFx0dG9vbGJhcl9kaXYuY2xhc3NOYW1lICs9IFwiIGRpc2FibGVkLWZvci1wcmV2aWV3XCI7XG5cdH1cblx0cHJldmlldy5pbm5lckhUTUwgPSBlZGl0b3Iub3B0aW9ucy5wcmV2aWV3UmVuZGVyKGVkaXRvci52YWx1ZSgpLCBwcmV2aWV3KTtcblxuXHQvLyBUdXJuIG9mZiBzaWRlIGJ5IHNpZGUgaWYgbmVlZGVkXG5cdHZhciBzaWRlYnlzaWRlID0gY20uZ2V0V3JhcHBlckVsZW1lbnQoKS5uZXh0U2libGluZztcblx0aWYoL2VkaXRvci1wcmV2aWV3LWFjdGl2ZS1zaWRlLy50ZXN0KHNpZGVieXNpZGUuY2xhc3NOYW1lKSlcblx0XHR0b2dnbGVTaWRlQnlTaWRlKGVkaXRvcik7XG59XG5cbmZ1bmN0aW9uIF9yZXBsYWNlU2VsZWN0aW9uKGNtLCBhY3RpdmUsIHN0YXJ0RW5kKSB7XG5cdGlmKC9lZGl0b3ItcHJldmlldy1hY3RpdmUvLnRlc3QoY20uZ2V0V3JhcHBlckVsZW1lbnQoKS5sYXN0Q2hpbGQuY2xhc3NOYW1lKSlcblx0XHRyZXR1cm47XG5cblx0dmFyIHRleHQ7XG5cdHZhciBzdGFydCA9IHN0YXJ0RW5kWzBdO1xuXHR2YXIgZW5kID0gc3RhcnRFbmRbMV07XG5cdHZhciBzdGFydFBvaW50ID0gY20uZ2V0Q3Vyc29yKFwic3RhcnRcIik7XG5cdHZhciBlbmRQb2ludCA9IGNtLmdldEN1cnNvcihcImVuZFwiKTtcblx0aWYoYWN0aXZlKSB7XG5cdFx0dGV4dCA9IGNtLmdldExpbmUoc3RhcnRQb2ludC5saW5lKTtcblx0XHRzdGFydCA9IHRleHQuc2xpY2UoMCwgc3RhcnRQb2ludC5jaCk7XG5cdFx0ZW5kID0gdGV4dC5zbGljZShzdGFydFBvaW50LmNoKTtcblx0XHRjbS5yZXBsYWNlUmFuZ2Uoc3RhcnQgKyBlbmQsIHtcblx0XHRcdGxpbmU6IHN0YXJ0UG9pbnQubGluZSxcblx0XHRcdGNoOiAwXG5cdFx0fSk7XG5cdH0gZWxzZSB7XG5cdFx0dGV4dCA9IGNtLmdldFNlbGVjdGlvbigpO1xuXHRcdGNtLnJlcGxhY2VTZWxlY3Rpb24oc3RhcnQgKyB0ZXh0ICsgZW5kKTtcblxuXHRcdHN0YXJ0UG9pbnQuY2ggKz0gc3RhcnQubGVuZ3RoO1xuXHRcdGlmKHN0YXJ0UG9pbnQgIT09IGVuZFBvaW50KSB7XG5cdFx0XHRlbmRQb2ludC5jaCArPSBzdGFydC5sZW5ndGg7XG5cdFx0fVxuXHR9XG5cdGNtLnNldFNlbGVjdGlvbihzdGFydFBvaW50LCBlbmRQb2ludCk7XG5cdGNtLmZvY3VzKCk7XG59XG5cblxuZnVuY3Rpb24gX3RvZ2dsZUhlYWRpbmcoY20sIGRpcmVjdGlvbiwgc2l6ZSkge1xuXHRpZigvZWRpdG9yLXByZXZpZXctYWN0aXZlLy50ZXN0KGNtLmdldFdyYXBwZXJFbGVtZW50KCkubGFzdENoaWxkLmNsYXNzTmFtZSkpXG5cdFx0cmV0dXJuO1xuXG5cdHZhciBzdGFydFBvaW50ID0gY20uZ2V0Q3Vyc29yKFwic3RhcnRcIik7XG5cdHZhciBlbmRQb2ludCA9IGNtLmdldEN1cnNvcihcImVuZFwiKTtcblx0Zm9yKHZhciBpID0gc3RhcnRQb2ludC5saW5lOyBpIDw9IGVuZFBvaW50LmxpbmU7IGkrKykge1xuXHRcdChmdW5jdGlvbihpKSB7XG5cdFx0XHR2YXIgdGV4dCA9IGNtLmdldExpbmUoaSk7XG5cdFx0XHR2YXIgY3VyckhlYWRpbmdMZXZlbCA9IHRleHQuc2VhcmNoKC9bXiNdLyk7XG5cblx0XHRcdGlmKGRpcmVjdGlvbiAhPT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRcdGlmKGN1cnJIZWFkaW5nTGV2ZWwgPD0gMCkge1xuXHRcdFx0XHRcdGlmKGRpcmVjdGlvbiA9PSBcImJpZ2dlclwiKSB7XG5cdFx0XHRcdFx0XHR0ZXh0ID0gXCIjIyMjIyMgXCIgKyB0ZXh0O1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHR0ZXh0ID0gXCIjIFwiICsgdGV4dDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gZWxzZSBpZihjdXJySGVhZGluZ0xldmVsID09IDYgJiYgZGlyZWN0aW9uID09IFwic21hbGxlclwiKSB7XG5cdFx0XHRcdFx0dGV4dCA9IHRleHQuc3Vic3RyKDcpO1xuXHRcdFx0XHR9IGVsc2UgaWYoY3VyckhlYWRpbmdMZXZlbCA9PSAxICYmIGRpcmVjdGlvbiA9PSBcImJpZ2dlclwiKSB7XG5cdFx0XHRcdFx0dGV4dCA9IHRleHQuc3Vic3RyKDIpO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGlmKGRpcmVjdGlvbiA9PSBcImJpZ2dlclwiKSB7XG5cdFx0XHRcdFx0XHR0ZXh0ID0gdGV4dC5zdWJzdHIoMSk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHRleHQgPSBcIiNcIiArIHRleHQ7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRpZihzaXplID09IDEpIHtcblx0XHRcdFx0XHRpZihjdXJySGVhZGluZ0xldmVsIDw9IDApIHtcblx0XHRcdFx0XHRcdHRleHQgPSBcIiMgXCIgKyB0ZXh0O1xuXHRcdFx0XHRcdH0gZWxzZSBpZihjdXJySGVhZGluZ0xldmVsID09IHNpemUpIHtcblx0XHRcdFx0XHRcdHRleHQgPSB0ZXh0LnN1YnN0cihjdXJySGVhZGluZ0xldmVsICsgMSk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHRleHQgPSBcIiMgXCIgKyB0ZXh0LnN1YnN0cihjdXJySGVhZGluZ0xldmVsICsgMSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGVsc2UgaWYoc2l6ZSA9PSAyKSB7XG5cdFx0XHRcdFx0aWYoY3VyckhlYWRpbmdMZXZlbCA8PSAwKSB7XG5cdFx0XHRcdFx0XHR0ZXh0ID0gXCIjIyBcIiArIHRleHQ7XG5cdFx0XHRcdFx0fSBlbHNlIGlmKGN1cnJIZWFkaW5nTGV2ZWwgPT0gc2l6ZSkge1xuXHRcdFx0XHRcdFx0dGV4dCA9IHRleHQuc3Vic3RyKGN1cnJIZWFkaW5nTGV2ZWwgKyAxKTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0dGV4dCA9IFwiIyMgXCIgKyB0ZXh0LnN1YnN0cihjdXJySGVhZGluZ0xldmVsICsgMSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGlmKGN1cnJIZWFkaW5nTGV2ZWwgPD0gMCkge1xuXHRcdFx0XHRcdFx0dGV4dCA9IFwiIyMjIFwiICsgdGV4dDtcblx0XHRcdFx0XHR9IGVsc2UgaWYoY3VyckhlYWRpbmdMZXZlbCA9PSBzaXplKSB7XG5cdFx0XHRcdFx0XHR0ZXh0ID0gdGV4dC5zdWJzdHIoY3VyckhlYWRpbmdMZXZlbCArIDEpO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHR0ZXh0ID0gXCIjIyMgXCIgKyB0ZXh0LnN1YnN0cihjdXJySGVhZGluZ0xldmVsICsgMSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGNtLnJlcGxhY2VSYW5nZSh0ZXh0LCB7XG5cdFx0XHRcdGxpbmU6IGksXG5cdFx0XHRcdGNoOiAwXG5cdFx0XHR9LCB7XG5cdFx0XHRcdGxpbmU6IGksXG5cdFx0XHRcdGNoOiA5OTk5OTk5OTk5OTk5OVxuXHRcdFx0fSk7XG5cdFx0fSkoaSk7XG5cdH1cblx0Y20uZm9jdXMoKTtcbn1cblxuXG5mdW5jdGlvbiBfdG9nZ2xlTGluZShjbSwgbmFtZSkge1xuXHRpZigvZWRpdG9yLXByZXZpZXctYWN0aXZlLy50ZXN0KGNtLmdldFdyYXBwZXJFbGVtZW50KCkubGFzdENoaWxkLmNsYXNzTmFtZSkpXG5cdFx0cmV0dXJuO1xuXG5cdHZhciBzdGF0ID0gZ2V0U3RhdGUoY20pO1xuXHR2YXIgc3RhcnRQb2ludCA9IGNtLmdldEN1cnNvcihcInN0YXJ0XCIpO1xuXHR2YXIgZW5kUG9pbnQgPSBjbS5nZXRDdXJzb3IoXCJlbmRcIik7XG5cdHZhciByZXBsID0ge1xuXHRcdFwicXVvdGVcIjogL14oXFxzKilcXD5cXHMrLyxcblx0XHRcInVub3JkZXJlZC1saXN0XCI6IC9eKFxccyopKFxcKnxcXC18XFwrKVxccysvLFxuXHRcdFwib3JkZXJlZC1saXN0XCI6IC9eKFxccyopXFxkK1xcLlxccysvXG5cdH07XG5cdHZhciBtYXAgPSB7XG5cdFx0XCJxdW90ZVwiOiBcIj4gXCIsXG5cdFx0XCJ1bm9yZGVyZWQtbGlzdFwiOiBcIiogXCIsXG5cdFx0XCJvcmRlcmVkLWxpc3RcIjogXCIxLiBcIlxuXHR9O1xuXHRmb3IodmFyIGkgPSBzdGFydFBvaW50LmxpbmU7IGkgPD0gZW5kUG9pbnQubGluZTsgaSsrKSB7XG5cdFx0KGZ1bmN0aW9uKGkpIHtcblx0XHRcdHZhciB0ZXh0ID0gY20uZ2V0TGluZShpKTtcblx0XHRcdGlmKHN0YXRbbmFtZV0pIHtcblx0XHRcdFx0dGV4dCA9IHRleHQucmVwbGFjZShyZXBsW25hbWVdLCBcIiQxXCIpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGV4dCA9IG1hcFtuYW1lXSArIHRleHQ7XG5cdFx0XHR9XG5cdFx0XHRjbS5yZXBsYWNlUmFuZ2UodGV4dCwge1xuXHRcdFx0XHRsaW5lOiBpLFxuXHRcdFx0XHRjaDogMFxuXHRcdFx0fSwge1xuXHRcdFx0XHRsaW5lOiBpLFxuXHRcdFx0XHRjaDogOTk5OTk5OTk5OTk5OTlcblx0XHRcdH0pO1xuXHRcdH0pKGkpO1xuXHR9XG5cdGNtLmZvY3VzKCk7XG59XG5cbmZ1bmN0aW9uIF90b2dnbGVCbG9jayhlZGl0b3IsIHR5cGUsIHN0YXJ0X2NoYXJzLCBlbmRfY2hhcnMpIHtcblx0aWYoL2VkaXRvci1wcmV2aWV3LWFjdGl2ZS8udGVzdChlZGl0b3IuY29kZW1pcnJvci5nZXRXcmFwcGVyRWxlbWVudCgpLmxhc3RDaGlsZC5jbGFzc05hbWUpKVxuXHRcdHJldHVybjtcblxuXHRlbmRfY2hhcnMgPSAodHlwZW9mIGVuZF9jaGFycyA9PT0gXCJ1bmRlZmluZWRcIikgPyBzdGFydF9jaGFycyA6IGVuZF9jaGFycztcblx0dmFyIGNtID0gZWRpdG9yLmNvZGVtaXJyb3I7XG5cdHZhciBzdGF0ID0gZ2V0U3RhdGUoY20pO1xuXG5cdHZhciB0ZXh0O1xuXHR2YXIgc3RhcnQgPSBzdGFydF9jaGFycztcblx0dmFyIGVuZCA9IGVuZF9jaGFycztcblxuXHR2YXIgc3RhcnRQb2ludCA9IGNtLmdldEN1cnNvcihcInN0YXJ0XCIpO1xuXHR2YXIgZW5kUG9pbnQgPSBjbS5nZXRDdXJzb3IoXCJlbmRcIik7XG5cblx0aWYoc3RhdFt0eXBlXSkge1xuXHRcdHRleHQgPSBjbS5nZXRMaW5lKHN0YXJ0UG9pbnQubGluZSk7XG5cdFx0c3RhcnQgPSB0ZXh0LnNsaWNlKDAsIHN0YXJ0UG9pbnQuY2gpO1xuXHRcdGVuZCA9IHRleHQuc2xpY2Uoc3RhcnRQb2ludC5jaCk7XG5cdFx0aWYodHlwZSA9PSBcImJvbGRcIikge1xuXHRcdFx0c3RhcnQgPSBzdGFydC5yZXBsYWNlKC8oXFwqXFwqfF9fKSg/IVtcXHNcXFNdKihcXCpcXCp8X18pKS8sIFwiXCIpO1xuXHRcdFx0ZW5kID0gZW5kLnJlcGxhY2UoLyhcXCpcXCp8X18pLywgXCJcIik7XG5cdFx0fSBlbHNlIGlmKHR5cGUgPT0gXCJpdGFsaWNcIikge1xuXHRcdFx0c3RhcnQgPSBzdGFydC5yZXBsYWNlKC8oXFwqfF8pKD8hW1xcc1xcU10qKFxcKnxfKSkvLCBcIlwiKTtcblx0XHRcdGVuZCA9IGVuZC5yZXBsYWNlKC8oXFwqfF8pLywgXCJcIik7XG5cdFx0fSBlbHNlIGlmKHR5cGUgPT0gXCJzdHJpa2V0aHJvdWdoXCIpIHtcblx0XHRcdHN0YXJ0ID0gc3RhcnQucmVwbGFjZSgvKFxcKlxcKnx+fikoPyFbXFxzXFxTXSooXFwqXFwqfH5+KSkvLCBcIlwiKTtcblx0XHRcdGVuZCA9IGVuZC5yZXBsYWNlKC8oXFwqXFwqfH5+KS8sIFwiXCIpO1xuXHRcdH1cblx0XHRjbS5yZXBsYWNlUmFuZ2Uoc3RhcnQgKyBlbmQsIHtcblx0XHRcdGxpbmU6IHN0YXJ0UG9pbnQubGluZSxcblx0XHRcdGNoOiAwXG5cdFx0fSwge1xuXHRcdFx0bGluZTogc3RhcnRQb2ludC5saW5lLFxuXHRcdFx0Y2g6IDk5OTk5OTk5OTk5OTk5XG5cdFx0fSk7XG5cblx0XHRpZih0eXBlID09IFwiYm9sZFwiIHx8IHR5cGUgPT0gXCJzdHJpa2V0aHJvdWdoXCIpIHtcblx0XHRcdHN0YXJ0UG9pbnQuY2ggLT0gMjtcblx0XHRcdGlmKHN0YXJ0UG9pbnQgIT09IGVuZFBvaW50KSB7XG5cdFx0XHRcdGVuZFBvaW50LmNoIC09IDI7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIGlmKHR5cGUgPT0gXCJpdGFsaWNcIikge1xuXHRcdFx0c3RhcnRQb2ludC5jaCAtPSAxO1xuXHRcdFx0aWYoc3RhcnRQb2ludCAhPT0gZW5kUG9pbnQpIHtcblx0XHRcdFx0ZW5kUG9pbnQuY2ggLT0gMTtcblx0XHRcdH1cblx0XHR9XG5cdH0gZWxzZSB7XG5cdFx0dGV4dCA9IGNtLmdldFNlbGVjdGlvbigpO1xuXHRcdGlmKHR5cGUgPT0gXCJib2xkXCIpIHtcblx0XHRcdHRleHQgPSB0ZXh0LnNwbGl0KFwiKipcIikuam9pbihcIlwiKTtcblx0XHRcdHRleHQgPSB0ZXh0LnNwbGl0KFwiX19cIikuam9pbihcIlwiKTtcblx0XHR9IGVsc2UgaWYodHlwZSA9PSBcIml0YWxpY1wiKSB7XG5cdFx0XHR0ZXh0ID0gdGV4dC5zcGxpdChcIipcIikuam9pbihcIlwiKTtcblx0XHRcdHRleHQgPSB0ZXh0LnNwbGl0KFwiX1wiKS5qb2luKFwiXCIpO1xuXHRcdH0gZWxzZSBpZih0eXBlID09IFwic3RyaWtldGhyb3VnaFwiKSB7XG5cdFx0XHR0ZXh0ID0gdGV4dC5zcGxpdChcIn5+XCIpLmpvaW4oXCJcIik7XG5cdFx0fVxuXHRcdGNtLnJlcGxhY2VTZWxlY3Rpb24oc3RhcnQgKyB0ZXh0ICsgZW5kKTtcblxuXHRcdHN0YXJ0UG9pbnQuY2ggKz0gc3RhcnRfY2hhcnMubGVuZ3RoO1xuXHRcdGVuZFBvaW50LmNoID0gc3RhcnRQb2ludC5jaCArIHRleHQubGVuZ3RoO1xuXHR9XG5cblx0Y20uc2V0U2VsZWN0aW9uKHN0YXJ0UG9pbnQsIGVuZFBvaW50KTtcblx0Y20uZm9jdXMoKTtcbn1cblxuLy8gTWVyZ2UgdGhlIHByb3BlcnRpZXMgb2Ygb25lIG9iamVjdCBpbnRvIGFub3RoZXIuXG5mdW5jdGlvbiBfbWVyZ2VQcm9wZXJ0aWVzKHRhcmdldCwgc291cmNlKSB7XG5cdGZvcih2YXIgcHJvcGVydHkgaW4gc291cmNlKSB7XG5cdFx0aWYoc291cmNlLmhhc093blByb3BlcnR5KHByb3BlcnR5KSkge1xuXHRcdFx0aWYoc291cmNlW3Byb3BlcnR5XSBpbnN0YW5jZW9mIEFycmF5KSB7XG5cdFx0XHRcdHRhcmdldFtwcm9wZXJ0eV0gPSBzb3VyY2VbcHJvcGVydHldLmNvbmNhdCh0YXJnZXRbcHJvcGVydHldIGluc3RhbmNlb2YgQXJyYXkgPyB0YXJnZXRbcHJvcGVydHldIDogW10pO1xuXHRcdFx0fSBlbHNlIGlmKFxuXHRcdFx0XHRzb3VyY2VbcHJvcGVydHldICE9PSBudWxsICYmXG5cdFx0XHRcdHR5cGVvZiBzb3VyY2VbcHJvcGVydHldID09PSBcIm9iamVjdFwiICYmXG5cdFx0XHRcdHNvdXJjZVtwcm9wZXJ0eV0uY29uc3RydWN0b3IgPT09IE9iamVjdFxuXHRcdFx0KSB7XG5cdFx0XHRcdHRhcmdldFtwcm9wZXJ0eV0gPSBfbWVyZ2VQcm9wZXJ0aWVzKHRhcmdldFtwcm9wZXJ0eV0gfHwge30sIHNvdXJjZVtwcm9wZXJ0eV0pO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGFyZ2V0W3Byb3BlcnR5XSA9IHNvdXJjZVtwcm9wZXJ0eV07XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIHRhcmdldDtcbn1cblxuLy8gTWVyZ2UgYW4gYXJiaXRyYXJ5IG51bWJlciBvZiBvYmplY3RzIGludG8gb25lLlxuZnVuY3Rpb24gZXh0ZW5kKHRhcmdldCkge1xuXHRmb3IodmFyIGkgPSAxOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG5cdFx0dGFyZ2V0ID0gX21lcmdlUHJvcGVydGllcyh0YXJnZXQsIGFyZ3VtZW50c1tpXSk7XG5cdH1cblxuXHRyZXR1cm4gdGFyZ2V0O1xufVxuXG4vKiBUaGUgcmlnaHQgd29yZCBjb3VudCBpbiByZXNwZWN0IGZvciBDSksuICovXG5mdW5jdGlvbiB3b3JkQ291bnQoZGF0YSkge1xuXHR2YXIgcGF0dGVybiA9IC9bYS16QS1aMC05X1xcdTAzOTItXFx1MDNjOV0rfFtcXHU0RTAwLVxcdTlGRkZcXHUzNDAwLVxcdTRkYmZcXHVmOTAwLVxcdWZhZmZcXHUzMDQwLVxcdTMwOWZcXHVhYzAwLVxcdWQ3YWZdKy9nO1xuXHR2YXIgbSA9IGRhdGEubWF0Y2gocGF0dGVybik7XG5cdHZhciBjb3VudCA9IDA7XG5cdGlmKG0gPT09IG51bGwpIHJldHVybiBjb3VudDtcblx0Zm9yKHZhciBpID0gMDsgaSA8IG0ubGVuZ3RoOyBpKyspIHtcblx0XHRpZihtW2ldLmNoYXJDb2RlQXQoMCkgPj0gMHg0RTAwKSB7XG5cdFx0XHRjb3VudCArPSBtW2ldLmxlbmd0aDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Y291bnQgKz0gMTtcblx0XHR9XG5cdH1cblx0cmV0dXJuIGNvdW50O1xufVxuXG5cbnZhciB0b29sYmFyQnVpbHRJbkJ1dHRvbnMgPSB7XG5cdFwiYm9sZFwiOiB7XG5cdFx0bmFtZTogXCJib2xkXCIsXG5cdFx0YWN0aW9uOiB0b2dnbGVCb2xkLFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1ib2xkXCIsXG5cdFx0dGl0bGU6IFwiQm9sZCAoQ3RybCtCKVwiXG5cdH0sXG5cdFwiaXRhbGljXCI6IHtcblx0XHRuYW1lOiBcIml0YWxpY1wiLFxuXHRcdGFjdGlvbjogdG9nZ2xlSXRhbGljLFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1pdGFsaWNcIixcblx0XHR0aXRsZTogXCJJdGFsaWMgKEN0cmwrSSlcIlxuXHR9LFxuXHRcInN0cmlrZXRocm91Z2hcIjoge1xuXHRcdG5hbWU6IFwic3RyaWtldGhyb3VnaFwiLFxuXHRcdGFjdGlvbjogdG9nZ2xlU3RyaWtldGhyb3VnaCxcblx0XHRjbGFzc05hbWU6IFwiZmEgZmEtc3RyaWtldGhyb3VnaFwiLFxuXHRcdHRpdGxlOiBcIlN0cmlrZXRocm91Z2hcIlxuXHR9LFxuXHRcImhlYWRpbmdcIjoge1xuXHRcdG5hbWU6IFwiaGVhZGluZ1wiLFxuXHRcdGFjdGlvbjogdG9nZ2xlSGVhZGluZ1NtYWxsZXIsXG5cdFx0Y2xhc3NOYW1lOiBcImZhIGZhLWhlYWRlclwiLFxuXHRcdHRpdGxlOiBcIkhlYWRpbmcgKEN0cmwrSClcIlxuXHR9LFxuXHRcImhlYWRpbmctc21hbGxlclwiOiB7XG5cdFx0bmFtZTogXCJoZWFkaW5nLXNtYWxsZXJcIixcblx0XHRhY3Rpb246IHRvZ2dsZUhlYWRpbmdTbWFsbGVyLFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1oZWFkZXIgZmEtaGVhZGVyLXggZmEtaGVhZGVyLXNtYWxsZXJcIixcblx0XHR0aXRsZTogXCJTbWFsbGVyIEhlYWRpbmcgKEN0cmwrSClcIlxuXHR9LFxuXHRcImhlYWRpbmctYmlnZ2VyXCI6IHtcblx0XHRuYW1lOiBcImhlYWRpbmctYmlnZ2VyXCIsXG5cdFx0YWN0aW9uOiB0b2dnbGVIZWFkaW5nQmlnZ2VyLFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1oZWFkZXIgZmEtaGVhZGVyLXggZmEtaGVhZGVyLWJpZ2dlclwiLFxuXHRcdHRpdGxlOiBcIkJpZ2dlciBIZWFkaW5nIChTaGlmdCtDdHJsK0gpXCJcblx0fSxcblx0XCJoZWFkaW5nLTFcIjoge1xuXHRcdG5hbWU6IFwiaGVhZGluZy0xXCIsXG5cdFx0YWN0aW9uOiB0b2dnbGVIZWFkaW5nMSxcblx0XHRjbGFzc05hbWU6IFwiZmEgZmEtaGVhZGVyIGZhLWhlYWRlci14IGZhLWhlYWRlci0xXCIsXG5cdFx0dGl0bGU6IFwiQmlnIEhlYWRpbmdcIlxuXHR9LFxuXHRcImhlYWRpbmctMlwiOiB7XG5cdFx0bmFtZTogXCJoZWFkaW5nLTJcIixcblx0XHRhY3Rpb246IHRvZ2dsZUhlYWRpbmcyLFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1oZWFkZXIgZmEtaGVhZGVyLXggZmEtaGVhZGVyLTJcIixcblx0XHR0aXRsZTogXCJNZWRpdW0gSGVhZGluZ1wiXG5cdH0sXG5cdFwiaGVhZGluZy0zXCI6IHtcblx0XHRuYW1lOiBcImhlYWRpbmctM1wiLFxuXHRcdGFjdGlvbjogdG9nZ2xlSGVhZGluZzMsXG5cdFx0Y2xhc3NOYW1lOiBcImZhIGZhLWhlYWRlciBmYS1oZWFkZXIteCBmYS1oZWFkZXItM1wiLFxuXHRcdHRpdGxlOiBcIlNtYWxsIEhlYWRpbmdcIlxuXHR9LFxuXHRcImNvZGVcIjoge1xuXHRcdG5hbWU6IFwiY29kZVwiLFxuXHRcdGFjdGlvbjogdG9nZ2xlQ29kZUJsb2NrLFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1jb2RlXCIsXG5cdFx0dGl0bGU6IFwiQ29kZSAoQ3RybCtBbHQrQylcIlxuXHR9LFxuXHRcInF1b3RlXCI6IHtcblx0XHRuYW1lOiBcInF1b3RlXCIsXG5cdFx0YWN0aW9uOiB0b2dnbGVCbG9ja3F1b3RlLFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1xdW90ZS1sZWZ0XCIsXG5cdFx0dGl0bGU6IFwiUXVvdGUgKEN0cmwrJylcIlxuXHR9LFxuXHRcInVub3JkZXJlZC1saXN0XCI6IHtcblx0XHRuYW1lOiBcInVub3JkZXJlZC1saXN0XCIsXG5cdFx0YWN0aW9uOiB0b2dnbGVVbm9yZGVyZWRMaXN0LFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1saXN0LXVsXCIsXG5cdFx0dGl0bGU6IFwiR2VuZXJpYyBMaXN0IChDdHJsK0wpXCJcblx0fSxcblx0XCJvcmRlcmVkLWxpc3RcIjoge1xuXHRcdG5hbWU6IFwib3JkZXJlZC1saXN0XCIsXG5cdFx0YWN0aW9uOiB0b2dnbGVPcmRlcmVkTGlzdCxcblx0XHRjbGFzc05hbWU6IFwiZmEgZmEtbGlzdC1vbFwiLFxuXHRcdHRpdGxlOiBcIk51bWJlcmVkIExpc3QgKEN0cmwrQWx0K0wpXCJcblx0fSxcblx0XCJsaW5rXCI6IHtcblx0XHRuYW1lOiBcImxpbmtcIixcblx0XHRhY3Rpb246IGRyYXdMaW5rLFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1saW5rXCIsXG5cdFx0dGl0bGU6IFwiQ3JlYXRlIExpbmsgKEN0cmwrSylcIlxuXHR9LFxuXHRcImltYWdlXCI6IHtcblx0XHRuYW1lOiBcImltYWdlXCIsXG5cdFx0YWN0aW9uOiBkcmF3SW1hZ2UsXG5cdFx0Y2xhc3NOYW1lOiBcImZhIGZhLXBpY3R1cmUtb1wiLFxuXHRcdHRpdGxlOiBcIkluc2VydCBJbWFnZSAoQ3RybCtBbHQrSSlcIlxuXHR9LFxuXHRcInRhYmxlXCI6IHtcblx0XHRuYW1lOiBcInRhYmxlXCIsXG5cdFx0YWN0aW9uOiBkcmF3VGFibGUsXG5cdFx0Y2xhc3NOYW1lOiBcImZhIGZhLXRhYmxlXCIsXG5cdFx0dGl0bGU6IFwiSW5zZXJ0IFRhYmxlXCJcblx0fSxcblx0XCJob3Jpem9udGFsLXJ1bGVcIjoge1xuXHRcdG5hbWU6IFwiaG9yaXpvbnRhbC1ydWxlXCIsXG5cdFx0YWN0aW9uOiBkcmF3SG9yaXpvbnRhbFJ1bGUsXG5cdFx0Y2xhc3NOYW1lOiBcImZhIGZhLW1pbnVzXCIsXG5cdFx0dGl0bGU6IFwiSW5zZXJ0IEhvcml6b250YWwgTGluZVwiXG5cdH0sXG5cdFwicHJldmlld1wiOiB7XG5cdFx0bmFtZTogXCJwcmV2aWV3XCIsXG5cdFx0YWN0aW9uOiB0b2dnbGVQcmV2aWV3LFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1leWUgbm8tZGlzYWJsZVwiLFxuXHRcdHRpdGxlOiBcIlRvZ2dsZSBQcmV2aWV3IChDdHJsK1ApXCJcblx0fSxcblx0XCJzaWRlLWJ5LXNpZGVcIjoge1xuXHRcdG5hbWU6IFwic2lkZS1ieS1zaWRlXCIsXG5cdFx0YWN0aW9uOiB0b2dnbGVTaWRlQnlTaWRlLFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1jb2x1bW5zIG5vLWRpc2FibGUgbm8tbW9iaWxlXCIsXG5cdFx0dGl0bGU6IFwiVG9nZ2xlIFNpZGUgYnkgU2lkZSAoRjkpXCJcblx0fSxcblx0XCJmdWxsc2NyZWVuXCI6IHtcblx0XHRuYW1lOiBcImZ1bGxzY3JlZW5cIixcblx0XHRhY3Rpb246IHRvZ2dsZUZ1bGxTY3JlZW4sXG5cdFx0Y2xhc3NOYW1lOiBcImZhIGZhLWFycm93cy1hbHQgbm8tZGlzYWJsZSBuby1tb2JpbGVcIixcblx0XHR0aXRsZTogXCJUb2dnbGUgRnVsbHNjcmVlbiAoRjExKVwiXG5cdH0sXG5cdFwiZ3VpZGVcIjoge1xuXHRcdG5hbWU6IFwiZ3VpZGVcIixcblx0XHRhY3Rpb246IFwiaHR0cDovL25leHRzdGVwd2Vicy5naXRodWIuaW8vc2ltcGxlbWRlLW1hcmtkb3duLWVkaXRvci9tYXJrZG93bi1ndWlkZVwiLFxuXHRcdGNsYXNzTmFtZTogXCJmYSBmYS1xdWVzdGlvbi1jaXJjbGVcIixcblx0XHR0aXRsZTogXCJNYXJrZG93biBHdWlkZVwiXG5cdH1cbn07XG5cbnZhciBpbnNlcnRUZXh0cyA9IHtcblx0bGluazogW1wiW1wiLCBcIl0oaHR0cDovLylcIl0sXG5cdGltYWdlOiBbXCIhW10oaHR0cDovL1wiLCBcIilcIl0sXG5cdHRhYmxlOiBbXCJcIiwgXCJcXG5cXG58IENvbHVtbiAxIHwgQ29sdW1uIDIgfCBDb2x1bW4gMyB8XFxufCAtLS0tLS0tLSB8IC0tLS0tLS0tIHwgLS0tLS0tLS0gfFxcbnwgVGV4dCAgICAgfCBUZXh0ICAgICAgfCBUZXh0ICAgICB8XFxuXFxuXCJdLFxuXHRob3Jpem9udGFsUnVsZTogW1wiXCIsIFwiXFxuXFxuLS0tLS1cXG5cXG5cIl1cbn07XG5cbnZhciBibG9ja1N0eWxlcyA9IHtcblx0XCJib2xkXCI6IFwiKipcIixcblx0XCJpdGFsaWNcIjogXCIqXCJcbn07XG5cbi8qKlxuICogSW50ZXJmYWNlIG9mIFNpbXBsZU1ERS5cbiAqL1xuZnVuY3Rpb24gU2ltcGxlTURFKG9wdGlvbnMpIHtcblx0Ly8gSGFuZGxlIG9wdGlvbnMgcGFyYW1ldGVyXG5cdG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG5cblx0Ly8gVXNlZCBsYXRlciB0byByZWZlciB0byBpdFwicyBwYXJlbnRcblx0b3B0aW9ucy5wYXJlbnQgPSB0aGlzO1xuXG5cblx0Ly8gQ2hlY2sgaWYgRm9udCBBd2Vzb21lIG5lZWRzIHRvIGJlIGF1dG8gZG93bmxvYWRlZFxuXHR2YXIgYXV0b0Rvd25sb2FkRkEgPSB0cnVlO1xuXG5cdGlmKG9wdGlvbnMuYXV0b0Rvd25sb2FkRm9udEF3ZXNvbWUgPT09IGZhbHNlKSB7XG5cdFx0YXV0b0Rvd25sb2FkRkEgPSBmYWxzZTtcblx0fVxuXG5cdGlmKG9wdGlvbnMuYXV0b0Rvd25sb2FkRm9udEF3ZXNvbWUgIT09IHRydWUpIHtcblx0XHR2YXIgc3R5bGVTaGVldHMgPSBkb2N1bWVudC5zdHlsZVNoZWV0cztcblx0XHRmb3IodmFyIGkgPSAwOyBpIDwgc3R5bGVTaGVldHMubGVuZ3RoOyBpKyspIHtcblx0XHRcdGlmKCFzdHlsZVNoZWV0c1tpXS5ocmVmKVxuXHRcdFx0XHRjb250aW51ZTtcblxuXHRcdFx0aWYoc3R5bGVTaGVldHNbaV0uaHJlZi5pbmRleE9mKFwiLy9tYXhjZG4uYm9vdHN0cmFwY2RuLmNvbS9mb250LWF3ZXNvbWUvXCIpID4gLTEpIHtcblx0XHRcdFx0YXV0b0Rvd25sb2FkRkEgPSBmYWxzZTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRpZihhdXRvRG93bmxvYWRGQSkge1xuXHRcdHZhciBsaW5rID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImxpbmtcIik7XG5cdFx0bGluay5yZWwgPSBcInN0eWxlc2hlZXRcIjtcblx0XHRsaW5rLmhyZWYgPSBcImh0dHBzOi8vbWF4Y2RuLmJvb3RzdHJhcGNkbi5jb20vZm9udC1hd2Vzb21lL2xhdGVzdC9jc3MvZm9udC1hd2Vzb21lLm1pbi5jc3NcIjtcblx0XHRkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZShcImhlYWRcIilbMF0uYXBwZW5kQ2hpbGQobGluayk7XG5cdH1cblxuXG5cdC8vIEZpbmQgdGhlIHRleHRhcmVhIHRvIHVzZVxuXHRpZihvcHRpb25zLmVsZW1lbnQpIHtcblx0XHR0aGlzLmVsZW1lbnQgPSBvcHRpb25zLmVsZW1lbnQ7XG5cdH0gZWxzZSBpZihvcHRpb25zLmVsZW1lbnQgPT09IG51bGwpIHtcblx0XHQvLyBUaGlzIG1lYW5zIHRoYXQgdGhlIGVsZW1lbnQgb3B0aW9uIHdhcyBzcGVjaWZpZWQsIGJ1dCBubyBlbGVtZW50IHdhcyBmb3VuZFxuXHRcdGNvbnNvbGUubG9nKFwiU2ltcGxlTURFOiBFcnJvci4gTm8gZWxlbWVudCB3YXMgZm91bmQuXCIpO1xuXHRcdHJldHVybjtcblx0fVxuXG5cblx0Ly8gSGFuZGxlIHRvb2xiYXIgYW5kIHN0YXR1cyBiYXJcblx0aWYob3B0aW9ucy50b29sYmFyICE9PSBmYWxzZSlcblx0XHRvcHRpb25zLnRvb2xiYXIgPSBvcHRpb25zLnRvb2xiYXIgfHwgU2ltcGxlTURFLnRvb2xiYXI7XG5cblx0aWYoIW9wdGlvbnMuaGFzT3duUHJvcGVydHkoXCJzdGF0dXNcIikpIHtcblx0XHRvcHRpb25zLnN0YXR1cyA9IFtcImF1dG9zYXZlXCIsIFwibGluZXNcIiwgXCJ3b3Jkc1wiLCBcImN1cnNvclwiXTtcblx0fVxuXG5cblx0Ly8gQWRkIGRlZmF1bHQgcHJldmlldyByZW5kZXJpbmcgZnVuY3Rpb25cblx0aWYoIW9wdGlvbnMucHJldmlld1JlbmRlcikge1xuXHRcdG9wdGlvbnMucHJldmlld1JlbmRlciA9IGZ1bmN0aW9uKHBsYWluVGV4dCkge1xuXHRcdFx0Ly8gTm90ZTogXCJ0aGlzXCIgcmVmZXJzIHRvIHRoZSBvcHRpb25zIG9iamVjdFxuXHRcdFx0cmV0dXJuIHRoaXMucGFyZW50Lm1hcmtkb3duKHBsYWluVGV4dCk7XG5cdFx0fTtcblx0fVxuXG5cblx0Ly8gU2V0IGRlZmF1bHQgb3B0aW9ucyBmb3IgcGFyc2luZyBjb25maWdcblx0b3B0aW9ucy5wYXJzaW5nQ29uZmlnID0gb3B0aW9ucy5wYXJzaW5nQ29uZmlnIHx8IHt9O1xuXG5cblx0Ly8gTWVyZ2luZyB0aGUgaW5zZXJ0VGV4dHMsIHdpdGggdGhlIGdpdmVuIG9wdGlvbnNcblx0b3B0aW9ucy5pbnNlcnRUZXh0cyA9IGV4dGVuZCh7fSwgaW5zZXJ0VGV4dHMsIG9wdGlvbnMuaW5zZXJ0VGV4dHMgfHwge30pO1xuXG5cblx0Ly8gTWVyZ2luZyB0aGUgYmxvY2tTdHlsZXMsIHdpdGggdGhlIGdpdmVuIG9wdGlvbnNcblx0b3B0aW9ucy5ibG9ja1N0eWxlcyA9IGV4dGVuZCh7fSwgYmxvY2tTdHlsZXMsIG9wdGlvbnMuYmxvY2tTdHlsZXMgfHwge30pO1xuXG5cblx0Ly8gQ2hhbmdlIHVuaXF1ZV9pZCB0byB1bmlxdWVJZCBmb3IgYmFja3dhcmRzIGNvbXBhdGliaWxpdHlcblx0aWYob3B0aW9ucy5hdXRvc2F2ZSAhPSB1bmRlZmluZWQgJiYgb3B0aW9ucy5hdXRvc2F2ZS51bmlxdWVfaWQgIT0gdW5kZWZpbmVkICYmIG9wdGlvbnMuYXV0b3NhdmUudW5pcXVlX2lkICE9IFwiXCIpXG5cdFx0b3B0aW9ucy5hdXRvc2F2ZS51bmlxdWVJZCA9IG9wdGlvbnMuYXV0b3NhdmUudW5pcXVlX2lkO1xuXG5cblx0Ly8gVXBkYXRlIHRoaXMgb3B0aW9uc1xuXHR0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuXG5cblx0Ly8gQXV0byByZW5kZXJcblx0dGhpcy5yZW5kZXIoKTtcblxuXG5cdC8vIFRoZSBjb2RlbWlycm9yIGNvbXBvbmVudCBpcyBvbmx5IGF2YWlsYWJsZSBhZnRlciByZW5kZXJpbmdcblx0Ly8gc28sIHRoZSBzZXR0ZXIgZm9yIHRoZSBpbml0aWFsVmFsdWUgY2FuIG9ubHkgcnVuIGFmdGVyXG5cdC8vIHRoZSBlbGVtZW50IGhhcyBiZWVuIHJlbmRlcmVkXG5cdGlmKG9wdGlvbnMuaW5pdGlhbFZhbHVlKSB7XG5cdFx0dGhpcy52YWx1ZShvcHRpb25zLmluaXRpYWxWYWx1ZSk7XG5cdH1cbn1cblxuLyoqXG4gKiBEZWZhdWx0IHRvb2xiYXIgZWxlbWVudHMuXG4gKi9cblNpbXBsZU1ERS50b29sYmFyID0gW1wiYm9sZFwiLCBcIml0YWxpY1wiLCBcImhlYWRpbmdcIiwgXCJ8XCIsIFwicXVvdGVcIiwgXCJ1bm9yZGVyZWQtbGlzdFwiLCBcIm9yZGVyZWQtbGlzdFwiLCBcInxcIiwgXCJsaW5rXCIsIFwiaW1hZ2VcIiwgXCJ8XCIsIFwicHJldmlld1wiLCBcInNpZGUtYnktc2lkZVwiLCBcImZ1bGxzY3JlZW5cIiwgXCJndWlkZVwiXTtcblxuLyoqXG4gKiBEZWZhdWx0IG1hcmtkb3duIHJlbmRlci5cbiAqL1xuU2ltcGxlTURFLnByb3RvdHlwZS5tYXJrZG93biA9IGZ1bmN0aW9uKHRleHQpIHtcblx0aWYobWFya2VkKSB7XG5cdFx0Ly8gSW5pdGlhbGl6ZVxuXHRcdHZhciBtYXJrZWRPcHRpb25zID0ge307XG5cblxuXHRcdC8vIFVwZGF0ZSBvcHRpb25zXG5cdFx0aWYodGhpcy5vcHRpb25zICYmIHRoaXMub3B0aW9ucy5yZW5kZXJpbmdDb25maWcgJiYgdGhpcy5vcHRpb25zLnJlbmRlcmluZ0NvbmZpZy5zaW5nbGVMaW5lQnJlYWtzICE9PSBmYWxzZSkge1xuXHRcdFx0bWFya2VkT3B0aW9ucy5icmVha3MgPSB0cnVlO1xuXHRcdH1cblxuXHRcdGlmKHRoaXMub3B0aW9ucyAmJiB0aGlzLm9wdGlvbnMucmVuZGVyaW5nQ29uZmlnICYmIHRoaXMub3B0aW9ucy5yZW5kZXJpbmdDb25maWcuY29kZVN5bnRheEhpZ2hsaWdodGluZyA9PT0gdHJ1ZSAmJiB3aW5kb3cuaGxqcykge1xuXHRcdFx0bWFya2VkT3B0aW9ucy5oaWdobGlnaHQgPSBmdW5jdGlvbihjb2RlKSB7XG5cdFx0XHRcdHJldHVybiB3aW5kb3cuaGxqcy5oaWdobGlnaHRBdXRvKGNvZGUpLnZhbHVlO1xuXHRcdFx0fTtcblx0XHR9XG5cblxuXHRcdC8vIFNldCBvcHRpb25zXG5cdFx0bWFya2VkLnNldE9wdGlvbnMobWFya2VkT3B0aW9ucyk7XG5cblxuXHRcdC8vIFJldHVyblxuXHRcdHJldHVybiBtYXJrZWQodGV4dCk7XG5cdH1cbn07XG5cbi8qKlxuICogUmVuZGVyIGVkaXRvciB0byB0aGUgZ2l2ZW4gZWxlbWVudC5cbiAqL1xuU2ltcGxlTURFLnByb3RvdHlwZS5yZW5kZXIgPSBmdW5jdGlvbihlbCkge1xuXHRpZighZWwpIHtcblx0XHRlbCA9IHRoaXMuZWxlbWVudCB8fCBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZShcInRleHRhcmVhXCIpWzBdO1xuXHR9XG5cblx0aWYodGhpcy5fcmVuZGVyZWQgJiYgdGhpcy5fcmVuZGVyZWQgPT09IGVsKSB7XG5cdFx0Ly8gQWxyZWFkeSByZW5kZXJlZC5cblx0XHRyZXR1cm47XG5cdH1cblxuXHR0aGlzLmVsZW1lbnQgPSBlbDtcblx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0dmFyIHNlbGYgPSB0aGlzO1xuXHR2YXIga2V5TWFwcyA9IHt9O1xuXG5cdGZvcih2YXIga2V5IGluIHNob3J0Y3V0cykge1xuXHRcdChmdW5jdGlvbihrZXkpIHtcblx0XHRcdGtleU1hcHNbZml4U2hvcnRjdXQoa2V5KV0gPSBmdW5jdGlvbigpIHtcblx0XHRcdFx0c2hvcnRjdXRzW2tleV0oc2VsZik7XG5cdFx0XHR9O1xuXHRcdH0pKGtleSk7XG5cdH1cblxuXHRrZXlNYXBzW1wiRW50ZXJcIl0gPSBcIm5ld2xpbmVBbmRJbmRlbnRDb250aW51ZU1hcmtkb3duTGlzdFwiO1xuXHRrZXlNYXBzW1wiVGFiXCJdID0gXCJ0YWJBbmRJbmRlbnRNYXJrZG93bkxpc3RcIjtcblx0a2V5TWFwc1tcIlNoaWZ0LVRhYlwiXSA9IFwic2hpZnRUYWJBbmRVbmluZGVudE1hcmtkb3duTGlzdFwiO1xuXHRrZXlNYXBzW1wiRjExXCJdID0gZnVuY3Rpb24oKSB7XG5cdFx0dG9nZ2xlRnVsbFNjcmVlbihzZWxmKTtcblx0fTtcblx0a2V5TWFwc1tcIkY5XCJdID0gZnVuY3Rpb24oKSB7XG5cdFx0dG9nZ2xlU2lkZUJ5U2lkZShzZWxmKTtcblx0fTtcblx0a2V5TWFwc1tcIkVzY1wiXSA9IGZ1bmN0aW9uKGNtKSB7XG5cdFx0aWYoY20uZ2V0T3B0aW9uKFwiZnVsbFNjcmVlblwiKSkgdG9nZ2xlRnVsbFNjcmVlbihzZWxmKTtcblx0fTtcblxuXHR2YXIgbW9kZSwgYmFja2Ryb3A7XG5cdGlmKG9wdGlvbnMuc3BlbGxDaGVja2VyICE9PSBmYWxzZSkge1xuXHRcdG1vZGUgPSBcInNwZWxsLWNoZWNrZXJcIjtcblx0XHRiYWNrZHJvcCA9IG9wdGlvbnMucGFyc2luZ0NvbmZpZztcblx0XHRiYWNrZHJvcC5uYW1lID0gXCJnZm1cIjtcblx0XHRiYWNrZHJvcC5naXRIdWJTcGljZSA9IGZhbHNlO1xuXHR9IGVsc2Uge1xuXHRcdG1vZGUgPSBvcHRpb25zLnBhcnNpbmdDb25maWc7XG5cdFx0bW9kZS5uYW1lID0gXCJnZm1cIjtcblx0XHRtb2RlLmdpdEh1YlNwaWNlID0gZmFsc2U7XG5cdH1cblxuXHR0aGlzLmNvZGVtaXJyb3IgPSBDb2RlTWlycm9yLmZyb21UZXh0QXJlYShlbCwge1xuXHRcdG1vZGU6IG1vZGUsXG5cdFx0YmFja2Ryb3A6IGJhY2tkcm9wLFxuXHRcdHRoZW1lOiBcInBhcGVyXCIsXG5cdFx0dGFiU2l6ZTogKG9wdGlvbnMudGFiU2l6ZSAhPSB1bmRlZmluZWQpID8gb3B0aW9ucy50YWJTaXplIDogMixcblx0XHRpbmRlbnRVbml0OiAob3B0aW9ucy50YWJTaXplICE9IHVuZGVmaW5lZCkgPyBvcHRpb25zLnRhYlNpemUgOiAyLFxuXHRcdGluZGVudFdpdGhUYWJzOiAob3B0aW9ucy5pbmRlbnRXaXRoVGFicyA9PT0gZmFsc2UpID8gZmFsc2UgOiB0cnVlLFxuXHRcdGxpbmVOdW1iZXJzOiBmYWxzZSxcblx0XHRhdXRvZm9jdXM6IChvcHRpb25zLmF1dG9mb2N1cyA9PT0gdHJ1ZSkgPyB0cnVlIDogZmFsc2UsXG5cdFx0ZXh0cmFLZXlzOiBrZXlNYXBzLFxuXHRcdGxpbmVXcmFwcGluZzogKG9wdGlvbnMubGluZVdyYXBwaW5nID09PSBmYWxzZSkgPyBmYWxzZSA6IHRydWUsXG5cdFx0YWxsb3dEcm9wRmlsZVR5cGVzOiBbXCJ0ZXh0L3BsYWluXCJdXG5cdH0pO1xuXG5cdGlmKG9wdGlvbnMudG9vbGJhciAhPT0gZmFsc2UpIHtcblx0XHR0aGlzLmNyZWF0ZVRvb2xiYXIoKTtcblx0fVxuXHRpZihvcHRpb25zLnN0YXR1cyAhPT0gZmFsc2UpIHtcblx0XHR0aGlzLmNyZWF0ZVN0YXR1c2JhcigpO1xuXHR9XG5cdGlmKG9wdGlvbnMuYXV0b3NhdmUgIT0gdW5kZWZpbmVkICYmIG9wdGlvbnMuYXV0b3NhdmUuZW5hYmxlZCA9PT0gdHJ1ZSkge1xuXHRcdHRoaXMuYXV0b3NhdmUoKTtcblx0fVxuXG5cdHRoaXMuY3JlYXRlU2lkZUJ5U2lkZSgpO1xuXG5cdHRoaXMuX3JlbmRlcmVkID0gdGhpcy5lbGVtZW50O1xufTtcblxuU2ltcGxlTURFLnByb3RvdHlwZS5hdXRvc2F2ZSA9IGZ1bmN0aW9uKCkge1xuXHRpZihsb2NhbFN0b3JhZ2UpIHtcblx0XHR2YXIgc2ltcGxlbWRlID0gdGhpcztcblxuXHRcdGlmKHRoaXMub3B0aW9ucy5hdXRvc2F2ZS51bmlxdWVJZCA9PSB1bmRlZmluZWQgfHwgdGhpcy5vcHRpb25zLmF1dG9zYXZlLnVuaXF1ZUlkID09IFwiXCIpIHtcblx0XHRcdGNvbnNvbGUubG9nKFwiU2ltcGxlTURFOiBZb3UgbXVzdCBzZXQgYSB1bmlxdWVJZCB0byB1c2UgdGhlIGF1dG9zYXZlIGZlYXR1cmVcIik7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYoc2ltcGxlbWRlLmVsZW1lbnQuZm9ybSAhPSBudWxsICYmIHNpbXBsZW1kZS5lbGVtZW50LmZvcm0gIT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRzaW1wbGVtZGUuZWxlbWVudC5mb3JtLmFkZEV2ZW50TGlzdGVuZXIoXCJzdWJtaXRcIiwgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGxvY2FsU3RvcmFnZS5yZW1vdmVJdGVtKFwic21kZV9cIiArIHNpbXBsZW1kZS5vcHRpb25zLmF1dG9zYXZlLnVuaXF1ZUlkKTtcblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdGlmKHRoaXMub3B0aW9ucy5hdXRvc2F2ZS5sb2FkZWQgIT09IHRydWUpIHtcblx0XHRcdGlmKHR5cGVvZiBsb2NhbFN0b3JhZ2UuZ2V0SXRlbShcInNtZGVfXCIgKyB0aGlzLm9wdGlvbnMuYXV0b3NhdmUudW5pcXVlSWQpID09IFwic3RyaW5nXCIgJiYgbG9jYWxTdG9yYWdlLmdldEl0ZW0oXCJzbWRlX1wiICsgdGhpcy5vcHRpb25zLmF1dG9zYXZlLnVuaXF1ZUlkKSAhPSBcIlwiKVxuXHRcdFx0XHR0aGlzLmNvZGVtaXJyb3Iuc2V0VmFsdWUobG9jYWxTdG9yYWdlLmdldEl0ZW0oXCJzbWRlX1wiICsgdGhpcy5vcHRpb25zLmF1dG9zYXZlLnVuaXF1ZUlkKSk7XG5cblx0XHRcdHRoaXMub3B0aW9ucy5hdXRvc2F2ZS5sb2FkZWQgPSB0cnVlO1xuXHRcdH1cblxuXHRcdGxvY2FsU3RvcmFnZS5zZXRJdGVtKFwic21kZV9cIiArIHRoaXMub3B0aW9ucy5hdXRvc2F2ZS51bmlxdWVJZCwgc2ltcGxlbWRlLnZhbHVlKCkpO1xuXG5cdFx0dmFyIGVsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJhdXRvc2F2ZWRcIik7XG5cdFx0aWYoZWwgIT0gbnVsbCAmJiBlbCAhPSB1bmRlZmluZWQgJiYgZWwgIT0gXCJcIikge1xuXHRcdFx0dmFyIGQgPSBuZXcgRGF0ZSgpO1xuXHRcdFx0dmFyIGhoID0gZC5nZXRIb3VycygpO1xuXHRcdFx0dmFyIG0gPSBkLmdldE1pbnV0ZXMoKTtcblx0XHRcdHZhciBkZCA9IFwiYW1cIjtcblx0XHRcdHZhciBoID0gaGg7XG5cdFx0XHRpZihoID49IDEyKSB7XG5cdFx0XHRcdGggPSBoaCAtIDEyO1xuXHRcdFx0XHRkZCA9IFwicG1cIjtcblx0XHRcdH1cblx0XHRcdGlmKGggPT0gMCkge1xuXHRcdFx0XHRoID0gMTI7XG5cdFx0XHR9XG5cdFx0XHRtID0gbSA8IDEwID8gXCIwXCIgKyBtIDogbTtcblxuXHRcdFx0ZWwuaW5uZXJIVE1MID0gXCJBdXRvc2F2ZWQ6IFwiICsgaCArIFwiOlwiICsgbSArIFwiIFwiICsgZGQ7XG5cdFx0fVxuXG5cdFx0c2V0VGltZW91dChmdW5jdGlvbigpIHtcblx0XHRcdHNpbXBsZW1kZS5hdXRvc2F2ZSgpO1xuXHRcdH0sIHRoaXMub3B0aW9ucy5hdXRvc2F2ZS5kZWxheSB8fCAxMDAwMCk7XG5cdH0gZWxzZSB7XG5cdFx0Y29uc29sZS5sb2coXCJTaW1wbGVNREU6IGxvY2FsU3RvcmFnZSBub3QgYXZhaWxhYmxlLCBjYW5ub3QgYXV0b3NhdmVcIik7XG5cdH1cbn07XG5cblNpbXBsZU1ERS5wcm90b3R5cGUuY2xlYXJBdXRvc2F2ZWRWYWx1ZSA9IGZ1bmN0aW9uKCkge1xuXHRpZihsb2NhbFN0b3JhZ2UpIHtcblx0XHRpZih0aGlzLm9wdGlvbnMuYXV0b3NhdmUudW5pcXVlSWQgPT0gdW5kZWZpbmVkIHx8IHRoaXMub3B0aW9ucy5hdXRvc2F2ZS51bmlxdWVJZCA9PSBcIlwiKSB7XG5cdFx0XHRjb25zb2xlLmxvZyhcIlNpbXBsZU1ERTogWW91IG11c3Qgc2V0IGEgdW5pcXVlSWQgdG8gdXNlIHRoZSBhdXRvc2F2ZSBmZWF0dXJlXCIpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGxvY2FsU3RvcmFnZS5yZW1vdmVJdGVtKFwic21kZV9cIiArIHRoaXMub3B0aW9ucy5hdXRvc2F2ZS51bmlxdWVJZCk7XG5cdH0gZWxzZSB7XG5cdFx0Y29uc29sZS5sb2coXCJTaW1wbGVNREU6IGxvY2FsU3RvcmFnZSBub3QgYXZhaWxhYmxlLCBjYW5ub3QgYXV0b3NhdmVcIik7XG5cdH1cbn07XG5cblNpbXBsZU1ERS5wcm90b3R5cGUuY3JlYXRlU2lkZUJ5U2lkZSA9IGZ1bmN0aW9uKCkge1xuXHR2YXIgY20gPSB0aGlzLmNvZGVtaXJyb3I7XG5cdHZhciB3cmFwcGVyID0gY20uZ2V0V3JhcHBlckVsZW1lbnQoKTtcblx0dmFyIHByZXZpZXcgPSB3cmFwcGVyLm5leHRTaWJsaW5nO1xuXG5cdGlmKCFwcmV2aWV3IHx8ICEvZWRpdG9yLXByZXZpZXctc2lkZS8udGVzdChwcmV2aWV3LmNsYXNzTmFtZSkpIHtcblx0XHRwcmV2aWV3ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcblx0XHRwcmV2aWV3LmNsYXNzTmFtZSA9IFwiZWRpdG9yLXByZXZpZXctc2lkZVwiO1xuXHRcdHdyYXBwZXIucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUocHJldmlldywgd3JhcHBlci5uZXh0U2libGluZyk7XG5cdH1cblxuXHQvLyBTeW5jcyBzY3JvbGwgIGVkaXRvciAtPiBwcmV2aWV3XG5cdHZhciBjU2Nyb2xsID0gZmFsc2U7XG5cdHZhciBwU2Nyb2xsID0gZmFsc2U7XG5cdGNtLm9uKFwic2Nyb2xsXCIsIGZ1bmN0aW9uKHYpIHtcblx0XHRpZihjU2Nyb2xsKSB7XG5cdFx0XHRjU2Nyb2xsID0gZmFsc2U7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHBTY3JvbGwgPSB0cnVlO1xuXHRcdHZhciBoZWlnaHQgPSB2LmdldFNjcm9sbEluZm8oKS5oZWlnaHQgLSB2LmdldFNjcm9sbEluZm8oKS5jbGllbnRIZWlnaHQ7XG5cdFx0dmFyIHJhdGlvID0gcGFyc2VGbG9hdCh2LmdldFNjcm9sbEluZm8oKS50b3ApIC8gaGVpZ2h0O1xuXHRcdHZhciBtb3ZlID0gKHByZXZpZXcuc2Nyb2xsSGVpZ2h0IC0gcHJldmlldy5jbGllbnRIZWlnaHQpICogcmF0aW87XG5cdFx0cHJldmlldy5zY3JvbGxUb3AgPSBtb3ZlO1xuXHR9KTtcblxuXHQvLyBTeW5jcyBzY3JvbGwgIHByZXZpZXcgLT4gZWRpdG9yXG5cdHByZXZpZXcub25zY3JvbGwgPSBmdW5jdGlvbigpIHtcblx0XHRpZihwU2Nyb2xsKSB7XG5cdFx0XHRwU2Nyb2xsID0gZmFsc2U7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGNTY3JvbGwgPSB0cnVlO1xuXHRcdHZhciBoZWlnaHQgPSBwcmV2aWV3LnNjcm9sbEhlaWdodCAtIHByZXZpZXcuY2xpZW50SGVpZ2h0O1xuXHRcdHZhciByYXRpbyA9IHBhcnNlRmxvYXQocHJldmlldy5zY3JvbGxUb3ApIC8gaGVpZ2h0O1xuXHRcdHZhciBtb3ZlID0gKGNtLmdldFNjcm9sbEluZm8oKS5oZWlnaHQgLSBjbS5nZXRTY3JvbGxJbmZvKCkuY2xpZW50SGVpZ2h0KSAqIHJhdGlvO1xuXHRcdGNtLnNjcm9sbFRvKDAsIG1vdmUpO1xuXHR9O1xuXHRyZXR1cm4gdHJ1ZTtcbn07XG5cblNpbXBsZU1ERS5wcm90b3R5cGUuY3JlYXRlVG9vbGJhciA9IGZ1bmN0aW9uKGl0ZW1zKSB7XG5cdGl0ZW1zID0gaXRlbXMgfHwgdGhpcy5vcHRpb25zLnRvb2xiYXI7XG5cblx0aWYoIWl0ZW1zIHx8IGl0ZW1zLmxlbmd0aCA9PT0gMCkge1xuXHRcdHJldHVybjtcblx0fVxuXHR2YXIgaTtcblx0Zm9yKGkgPSAwOyBpIDwgaXRlbXMubGVuZ3RoOyBpKyspIHtcblx0XHRpZih0b29sYmFyQnVpbHRJbkJ1dHRvbnNbaXRlbXNbaV1dICE9IHVuZGVmaW5lZCkge1xuXHRcdFx0aXRlbXNbaV0gPSB0b29sYmFyQnVpbHRJbkJ1dHRvbnNbaXRlbXNbaV1dO1xuXHRcdH1cblx0fVxuXG5cdHZhciBiYXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xuXHRiYXIuY2xhc3NOYW1lID0gXCJlZGl0b3ItdG9vbGJhclwiO1xuXG5cdHZhciBzZWxmID0gdGhpcztcblxuXHR2YXIgdG9vbGJhcl9kYXRhID0ge307XG5cdHNlbGYudG9vbGJhciA9IGl0ZW1zO1xuXG5cdGZvcihpID0gMDsgaSA8IGl0ZW1zLmxlbmd0aDsgaSsrKSB7XG5cdFx0aWYoaXRlbXNbaV0ubmFtZSA9PSBcImd1aWRlXCIgJiYgc2VsZi5vcHRpb25zLnRvb2xiYXJHdWlkZUljb24gPT09IGZhbHNlKVxuXHRcdFx0Y29udGludWU7XG5cblx0XHRpZihzZWxmLm9wdGlvbnMuaGlkZUljb25zICYmIHNlbGYub3B0aW9ucy5oaWRlSWNvbnMuaW5kZXhPZihpdGVtc1tpXS5uYW1lKSAhPSAtMSlcblx0XHRcdGNvbnRpbnVlO1xuXG5cdFx0Ly8gRnVsbHNjcmVlbiBkb2VzIG5vdCB3b3JrIHdlbGwgb24gbW9iaWxlIGRldmljZXMgKGV2ZW4gdGFibGV0cylcblx0XHQvLyBJbiB0aGUgZnV0dXJlLCBob3BlZnVsbHkgdGhpcyBjYW4gYmUgcmVzb2x2ZWRcblx0XHRpZigoaXRlbXNbaV0ubmFtZSA9PSBcImZ1bGxzY3JlZW5cIiB8fCBpdGVtc1tpXS5uYW1lID09IFwic2lkZS1ieS1zaWRlXCIpICYmIGlzTW9iaWxlKCkpXG5cdFx0XHRjb250aW51ZTtcblxuXHRcdChmdW5jdGlvbihpdGVtKSB7XG5cdFx0XHR2YXIgZWw7XG5cdFx0XHRpZihpdGVtID09PSBcInxcIikge1xuXHRcdFx0XHRlbCA9IGNyZWF0ZVNlcCgpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0ZWwgPSBjcmVhdGVJY29uKGl0ZW0sIHNlbGYub3B0aW9ucy50b29sYmFyVGlwcyk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIGJpbmQgZXZlbnRzLCBzcGVjaWFsIGZvciBpbmZvXG5cdFx0XHRpZihpdGVtLmFjdGlvbikge1xuXHRcdFx0XHRpZih0eXBlb2YgaXRlbS5hY3Rpb24gPT09IFwiZnVuY3Rpb25cIikge1xuXHRcdFx0XHRcdGVsLm9uY2xpY2sgPSBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdGl0ZW0uYWN0aW9uKHNlbGYpO1xuXHRcdFx0XHRcdH07XG5cdFx0XHRcdH0gZWxzZSBpZih0eXBlb2YgaXRlbS5hY3Rpb24gPT09IFwic3RyaW5nXCIpIHtcblx0XHRcdFx0XHRlbC5ocmVmID0gaXRlbS5hY3Rpb247XG5cdFx0XHRcdFx0ZWwudGFyZ2V0ID0gXCJfYmxhbmtcIjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0dG9vbGJhcl9kYXRhW2l0ZW0ubmFtZSB8fCBpdGVtXSA9IGVsO1xuXHRcdFx0YmFyLmFwcGVuZENoaWxkKGVsKTtcblx0XHR9KShpdGVtc1tpXSk7XG5cdH1cblxuXHRzZWxmLnRvb2xiYXJFbGVtZW50cyA9IHRvb2xiYXJfZGF0YTtcblxuXHR2YXIgY20gPSB0aGlzLmNvZGVtaXJyb3I7XG5cdGNtLm9uKFwiY3Vyc29yQWN0aXZpdHlcIiwgZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHN0YXQgPSBnZXRTdGF0ZShjbSk7XG5cblx0XHRmb3IodmFyIGtleSBpbiB0b29sYmFyX2RhdGEpIHtcblx0XHRcdChmdW5jdGlvbihrZXkpIHtcblx0XHRcdFx0dmFyIGVsID0gdG9vbGJhcl9kYXRhW2tleV07XG5cdFx0XHRcdGlmKHN0YXRba2V5XSkge1xuXHRcdFx0XHRcdGVsLmNsYXNzTmFtZSArPSBcIiBhY3RpdmVcIjtcblx0XHRcdFx0fSBlbHNlIGlmKGtleSAhPSBcImZ1bGxzY3JlZW5cIiAmJiBrZXkgIT0gXCJzaWRlLWJ5LXNpZGVcIikge1xuXHRcdFx0XHRcdGVsLmNsYXNzTmFtZSA9IGVsLmNsYXNzTmFtZS5yZXBsYWNlKC9cXHMqYWN0aXZlXFxzKi9nLCBcIlwiKTtcblx0XHRcdFx0fVxuXHRcdFx0fSkoa2V5KTtcblx0XHR9XG5cdH0pO1xuXG5cdHZhciBjbVdyYXBwZXIgPSBjbS5nZXRXcmFwcGVyRWxlbWVudCgpO1xuXHRjbVdyYXBwZXIucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoYmFyLCBjbVdyYXBwZXIpO1xuXHRyZXR1cm4gYmFyO1xufTtcblxuU2ltcGxlTURFLnByb3RvdHlwZS5jcmVhdGVTdGF0dXNiYXIgPSBmdW5jdGlvbihzdGF0dXMpIHtcblx0c3RhdHVzID0gc3RhdHVzIHx8IHRoaXMub3B0aW9ucy5zdGF0dXM7XG5cdHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuXG5cdGlmKCFzdGF0dXMgfHwgc3RhdHVzLmxlbmd0aCA9PT0gMCkgcmV0dXJuO1xuXG5cdHZhciBiYXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiZGl2XCIpO1xuXHRiYXIuY2xhc3NOYW1lID0gXCJlZGl0b3Itc3RhdHVzYmFyXCI7XG5cblx0dmFyIHBvcywgY20gPSB0aGlzLmNvZGVtaXJyb3I7XG5cdGZvcih2YXIgaSA9IDA7IGkgPCBzdGF0dXMubGVuZ3RoOyBpKyspIHtcblx0XHQoZnVuY3Rpb24obmFtZSkge1xuXHRcdFx0dmFyIGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInNwYW5cIik7XG5cdFx0XHRlbC5jbGFzc05hbWUgPSBuYW1lO1xuXHRcdFx0aWYobmFtZSA9PT0gXCJ3b3Jkc1wiKSB7XG5cdFx0XHRcdGVsLmlubmVySFRNTCA9IFwiMFwiO1xuXHRcdFx0XHRjbS5vbihcInVwZGF0ZVwiLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRlbC5pbm5lckhUTUwgPSB3b3JkQ291bnQoY20uZ2V0VmFsdWUoKSk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSBlbHNlIGlmKG5hbWUgPT09IFwibGluZXNcIikge1xuXHRcdFx0XHRlbC5pbm5lckhUTUwgPSBcIjBcIjtcblx0XHRcdFx0Y20ub24oXCJ1cGRhdGVcIiwgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0ZWwuaW5uZXJIVE1MID0gY20ubGluZUNvdW50KCk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSBlbHNlIGlmKG5hbWUgPT09IFwiY3Vyc29yXCIpIHtcblx0XHRcdFx0ZWwuaW5uZXJIVE1MID0gXCIwOjBcIjtcblx0XHRcdFx0Y20ub24oXCJjdXJzb3JBY3Rpdml0eVwiLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRwb3MgPSBjbS5nZXRDdXJzb3IoKTtcblx0XHRcdFx0XHRlbC5pbm5lckhUTUwgPSBwb3MubGluZSArIFwiOlwiICsgcG9zLmNoO1xuXHRcdFx0XHR9KTtcblx0XHRcdH0gZWxzZSBpZihuYW1lID09PSBcImF1dG9zYXZlXCIpIHtcblx0XHRcdFx0aWYob3B0aW9ucy5hdXRvc2F2ZSAhPSB1bmRlZmluZWQgJiYgb3B0aW9ucy5hdXRvc2F2ZS5lbmFibGVkID09PSB0cnVlKSB7XG5cdFx0XHRcdFx0ZWwuc2V0QXR0cmlidXRlKFwiaWRcIiwgXCJhdXRvc2F2ZWRcIik7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGJhci5hcHBlbmRDaGlsZChlbCk7XG5cdFx0fSkoc3RhdHVzW2ldKTtcblx0fVxuXG5cdHZhciBjbVdyYXBwZXIgPSB0aGlzLmNvZGVtaXJyb3IuZ2V0V3JhcHBlckVsZW1lbnQoKTtcblx0Y21XcmFwcGVyLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGJhciwgY21XcmFwcGVyLm5leHRTaWJsaW5nKTtcblx0cmV0dXJuIGJhcjtcbn07XG5cbi8qKlxuICogR2V0IG9yIHNldCB0aGUgdGV4dCBjb250ZW50LlxuICovXG5TaW1wbGVNREUucHJvdG90eXBlLnZhbHVlID0gZnVuY3Rpb24odmFsKSB7XG5cdGlmKHZhbCA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0cmV0dXJuIHRoaXMuY29kZW1pcnJvci5nZXRWYWx1ZSgpO1xuXHR9IGVsc2Uge1xuXHRcdHRoaXMuY29kZW1pcnJvci5nZXREb2MoKS5zZXRWYWx1ZSh2YWwpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG59O1xuXG5cbi8qKlxuICogQmluZCBzdGF0aWMgbWV0aG9kcyBmb3IgZXhwb3J0cy5cbiAqL1xuU2ltcGxlTURFLnRvZ2dsZUJvbGQgPSB0b2dnbGVCb2xkO1xuU2ltcGxlTURFLnRvZ2dsZUl0YWxpYyA9IHRvZ2dsZUl0YWxpYztcblNpbXBsZU1ERS50b2dnbGVTdHJpa2V0aHJvdWdoID0gdG9nZ2xlU3RyaWtldGhyb3VnaDtcblNpbXBsZU1ERS50b2dnbGVCbG9ja3F1b3RlID0gdG9nZ2xlQmxvY2txdW90ZTtcblNpbXBsZU1ERS50b2dnbGVIZWFkaW5nU21hbGxlciA9IHRvZ2dsZUhlYWRpbmdTbWFsbGVyO1xuU2ltcGxlTURFLnRvZ2dsZUhlYWRpbmdCaWdnZXIgPSB0b2dnbGVIZWFkaW5nQmlnZ2VyO1xuU2ltcGxlTURFLnRvZ2dsZUhlYWRpbmcxID0gdG9nZ2xlSGVhZGluZzE7XG5TaW1wbGVNREUudG9nZ2xlSGVhZGluZzIgPSB0b2dnbGVIZWFkaW5nMjtcblNpbXBsZU1ERS50b2dnbGVIZWFkaW5nMyA9IHRvZ2dsZUhlYWRpbmczO1xuU2ltcGxlTURFLnRvZ2dsZUNvZGVCbG9jayA9IHRvZ2dsZUNvZGVCbG9jaztcblNpbXBsZU1ERS50b2dnbGVVbm9yZGVyZWRMaXN0ID0gdG9nZ2xlVW5vcmRlcmVkTGlzdDtcblNpbXBsZU1ERS50b2dnbGVPcmRlcmVkTGlzdCA9IHRvZ2dsZU9yZGVyZWRMaXN0O1xuU2ltcGxlTURFLmRyYXdMaW5rID0gZHJhd0xpbms7XG5TaW1wbGVNREUuZHJhd0ltYWdlID0gZHJhd0ltYWdlO1xuU2ltcGxlTURFLmRyYXdUYWJsZSA9IGRyYXdUYWJsZTtcblNpbXBsZU1ERS5kcmF3SG9yaXpvbnRhbFJ1bGUgPSBkcmF3SG9yaXpvbnRhbFJ1bGU7XG5TaW1wbGVNREUudW5kbyA9IHVuZG87XG5TaW1wbGVNREUucmVkbyA9IHJlZG87XG5TaW1wbGVNREUudG9nZ2xlUHJldmlldyA9IHRvZ2dsZVByZXZpZXc7XG5TaW1wbGVNREUudG9nZ2xlU2lkZUJ5U2lkZSA9IHRvZ2dsZVNpZGVCeVNpZGU7XG5TaW1wbGVNREUudG9nZ2xlRnVsbFNjcmVlbiA9IHRvZ2dsZUZ1bGxTY3JlZW47XG5cbi8qKlxuICogQmluZCBpbnN0YW5jZSBtZXRob2RzIGZvciBleHBvcnRzLlxuICovXG5TaW1wbGVNREUucHJvdG90eXBlLnRvZ2dsZUJvbGQgPSBmdW5jdGlvbigpIHtcblx0dG9nZ2xlQm9sZCh0aGlzKTtcbn07XG5TaW1wbGVNREUucHJvdG90eXBlLnRvZ2dsZUl0YWxpYyA9IGZ1bmN0aW9uKCkge1xuXHR0b2dnbGVJdGFsaWModGhpcyk7XG59O1xuU2ltcGxlTURFLnByb3RvdHlwZS50b2dnbGVTdHJpa2V0aHJvdWdoID0gZnVuY3Rpb24oKSB7XG5cdHRvZ2dsZVN0cmlrZXRocm91Z2godGhpcyk7XG59O1xuU2ltcGxlTURFLnByb3RvdHlwZS50b2dnbGVCbG9ja3F1b3RlID0gZnVuY3Rpb24oKSB7XG5cdHRvZ2dsZUJsb2NrcXVvdGUodGhpcyk7XG59O1xuU2ltcGxlTURFLnByb3RvdHlwZS50b2dnbGVIZWFkaW5nU21hbGxlciA9IGZ1bmN0aW9uKCkge1xuXHR0b2dnbGVIZWFkaW5nU21hbGxlcih0aGlzKTtcbn07XG5TaW1wbGVNREUucHJvdG90eXBlLnRvZ2dsZUhlYWRpbmdCaWdnZXIgPSBmdW5jdGlvbigpIHtcblx0dG9nZ2xlSGVhZGluZ0JpZ2dlcih0aGlzKTtcbn07XG5TaW1wbGVNREUucHJvdG90eXBlLnRvZ2dsZUhlYWRpbmcxID0gZnVuY3Rpb24oKSB7XG5cdHRvZ2dsZUhlYWRpbmcxKHRoaXMpO1xufTtcblNpbXBsZU1ERS5wcm90b3R5cGUudG9nZ2xlSGVhZGluZzIgPSBmdW5jdGlvbigpIHtcblx0dG9nZ2xlSGVhZGluZzIodGhpcyk7XG59O1xuU2ltcGxlTURFLnByb3RvdHlwZS50b2dnbGVIZWFkaW5nMyA9IGZ1bmN0aW9uKCkge1xuXHR0b2dnbGVIZWFkaW5nMyh0aGlzKTtcbn07XG5TaW1wbGVNREUucHJvdG90eXBlLnRvZ2dsZUNvZGVCbG9jayA9IGZ1bmN0aW9uKCkge1xuXHR0b2dnbGVDb2RlQmxvY2sodGhpcyk7XG59O1xuU2ltcGxlTURFLnByb3RvdHlwZS50b2dnbGVVbm9yZGVyZWRMaXN0ID0gZnVuY3Rpb24oKSB7XG5cdHRvZ2dsZVVub3JkZXJlZExpc3QodGhpcyk7XG59O1xuU2ltcGxlTURFLnByb3RvdHlwZS50b2dnbGVPcmRlcmVkTGlzdCA9IGZ1bmN0aW9uKCkge1xuXHR0b2dnbGVPcmRlcmVkTGlzdCh0aGlzKTtcbn07XG5TaW1wbGVNREUucHJvdG90eXBlLmRyYXdMaW5rID0gZnVuY3Rpb24oKSB7XG5cdGRyYXdMaW5rKHRoaXMpO1xufTtcblNpbXBsZU1ERS5wcm90b3R5cGUuZHJhd0ltYWdlID0gZnVuY3Rpb24oKSB7XG5cdGRyYXdJbWFnZSh0aGlzKTtcbn07XG5TaW1wbGVNREUucHJvdG90eXBlLmRyYXdUYWJsZSA9IGZ1bmN0aW9uKCkge1xuXHRkcmF3VGFibGUodGhpcyk7XG59O1xuU2ltcGxlTURFLnByb3RvdHlwZS5kcmF3SG9yaXpvbnRhbFJ1bGUgPSBmdW5jdGlvbigpIHtcblx0ZHJhd0hvcml6b250YWxSdWxlKHRoaXMpO1xufTtcblNpbXBsZU1ERS5wcm90b3R5cGUudW5kbyA9IGZ1bmN0aW9uKCkge1xuXHR1bmRvKHRoaXMpO1xufTtcblNpbXBsZU1ERS5wcm90b3R5cGUucmVkbyA9IGZ1bmN0aW9uKCkge1xuXHRyZWRvKHRoaXMpO1xufTtcblNpbXBsZU1ERS5wcm90b3R5cGUudG9nZ2xlUHJldmlldyA9IGZ1bmN0aW9uKCkge1xuXHR0b2dnbGVQcmV2aWV3KHRoaXMpO1xufTtcblNpbXBsZU1ERS5wcm90b3R5cGUudG9nZ2xlU2lkZUJ5U2lkZSA9IGZ1bmN0aW9uKCkge1xuXHR0b2dnbGVTaWRlQnlTaWRlKHRoaXMpO1xufTtcblNpbXBsZU1ERS5wcm90b3R5cGUudG9nZ2xlRnVsbFNjcmVlbiA9IGZ1bmN0aW9uKCkge1xuXHR0b2dnbGVGdWxsU2NyZWVuKHRoaXMpO1xufTtcblxuU2ltcGxlTURFLnByb3RvdHlwZS5pc1ByZXZpZXdBY3RpdmUgPSBmdW5jdGlvbigpIHtcblx0dmFyIGNtID0gdGhpcy5jb2RlbWlycm9yO1xuXHR2YXIgd3JhcHBlciA9IGNtLmdldFdyYXBwZXJFbGVtZW50KCk7XG5cdHZhciBwcmV2aWV3ID0gd3JhcHBlci5sYXN0Q2hpbGQ7XG5cblx0cmV0dXJuIC9lZGl0b3ItcHJldmlldy1hY3RpdmUvLnRlc3QocHJldmlldy5jbGFzc05hbWUpO1xufTtcblxuU2ltcGxlTURFLnByb3RvdHlwZS5pc1NpZGVCeVNpZGVBY3RpdmUgPSBmdW5jdGlvbigpIHtcblx0dmFyIGNtID0gdGhpcy5jb2RlbWlycm9yO1xuXHR2YXIgd3JhcHBlciA9IGNtLmdldFdyYXBwZXJFbGVtZW50KCk7XG5cdHZhciBwcmV2aWV3ID0gd3JhcHBlci5uZXh0U2libGluZztcblxuXHRyZXR1cm4gL2VkaXRvci1wcmV2aWV3LWFjdGl2ZS1zaWRlLy50ZXN0KHByZXZpZXcuY2xhc3NOYW1lKTtcbn07XG5cblNpbXBsZU1ERS5wcm90b3R5cGUuaXNGdWxsc2NyZWVuQWN0aXZlID0gZnVuY3Rpb24oKSB7XG5cdHZhciBjbSA9IHRoaXMuY29kZW1pcnJvcjtcblxuXHRyZXR1cm4gY20uZ2V0T3B0aW9uKFwiZnVsbFNjcmVlblwiKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU2ltcGxlTURFO1xuIl19