silika-website/wwwroot/assets/vendor/libs/jstree/jstree.js

134 lines
883 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* ATTENTION: An "eval-source-map" devtool has been used.
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory(require("jQuery"));
else if(typeof define === 'function' && define.amd)
define(["jQuery"], factory);
else {
var a = typeof exports === 'object' ? factory(require("jQuery")) : factory(root["jQuery"]);
for(var i in a) (typeof exports === 'object' ? exports : root)[i] = a[i];
}
})(self, function(__WEBPACK_EXTERNAL_MODULE_jquery__) {
return /******/ (function() { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./libs/jstree/jstree.js":
/*!*******************************!*\
!*** ./libs/jstree/jstree.js ***!
\*******************************/
/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {
"use strict";
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var jstree_dist_jstree__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! jstree/dist/jstree */ "./node_modules/jstree/dist/jstree.js");
/* harmony import */ var jstree_dist_jstree__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(jstree_dist_jstree__WEBPACK_IMPORTED_MODULE_0__);
/***/ }),
/***/ "./node_modules/jstree/dist/jstree.js":
/*!********************************************!*\
!*** ./node_modules/jstree/dist/jstree.js ***!
\********************************************/
/***/ (function(module, exports, __webpack_require__) {
eval("var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*globals jQuery, define, module, exports, require, window, document, postMessage */\n(function (factory) {\n\t\"use strict\";\n\tif (true) {\n\t\t!(__WEBPACK_AMD_DEFINE_ARRAY__ = [__webpack_require__(/*! jquery */ \"jquery\")], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),\n\t\t__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?\n\t\t(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),\n\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n\t}\n\telse {}\n}(function ($, undefined) {\n\t\"use strict\";\n/*!\n * jsTree 3.3.12\n * http://jstree.com/\n *\n * Copyright (c) 2014 Ivan Bozhanov (http://vakata.com)\n *\n * Licensed same as jquery - under the terms of the MIT License\n * http://www.opensource.org/licenses/mit-license.php\n */\n/*!\n * if using jslint please allow for the jQuery global and use following options:\n * jslint: loopfunc: true, browser: true, ass: true, bitwise: true, continue: true, nomen: true, plusplus: true, regexp: true, unparam: true, todo: true, white: true\n */\n/*jshint -W083 */\n\n\t// prevent another load? maybe there is a better way?\n\tif($.jstree) {\n\t\treturn;\n\t}\n\n\t/**\n\t * ### jsTree core functionality\n\t */\n\n\t// internal variables\n\tvar instance_counter = 0,\n\t\tccp_node = false,\n\t\tccp_mode = false,\n\t\tccp_inst = false,\n\t\tthemes_loaded = [],\n\t\tsrc = $('script:last').attr('src'),\n\t\tdocument = window.document; // local variable is always faster to access then a global\n\n\tvar setImmediate = window.setImmediate;\n\tvar Promise = window.Promise;\n\tif (!setImmediate && Promise) {\n\t\t// Good enough approximation of setImmediate\n\t\tsetImmediate = function (cb, arg) {\n\t\t\tPromise.resolve(arg).then(cb);\n\t\t};\n\t}\n\n\t/**\n\t * holds all jstree related functions and variables, including the actual class and methods to create, access and manipulate instances.\n\t * @name $.jstree\n\t */\n\t$.jstree = {\n\t\t/**\n\t\t * specifies the jstree version in use\n\t\t * @name $.jstree.version\n\t\t */\n\t\tversion : '3.3.12',\n\t\t/**\n\t\t * holds all the default options used when creating new instances\n\t\t * @name $.jstree.defaults\n\t\t */\n\t\tdefaults : {\n\t\t\t/**\n\t\t\t * configure which plugins will be active on an instance. Should be an array of strings, where each element is a plugin name. The default is `[]`\n\t\t\t * @name $.jstree.defaults.plugins\n\t\t\t */\n\t\t\tplugins : []\n\t\t},\n\t\t/**\n\t\t * stores all loaded jstree plugins (used internally)\n\t\t * @name $.jstree.plugins\n\t\t */\n\t\tplugins : {},\n\t\tpath : src && src.indexOf('/') !== -1 ? src.replace(/\\/[^\\/]+$/,'') : '',\n\t\tidregex : /[\\\\:&!^|()\\[\\]<>@*'+~#\";.,=\\- \\/${}%?`]/g,\n\t\troot : '#'\n\t};\n\t\n\t/**\n\t * creates a jstree instance\n\t * @name $.jstree.create(el [, options])\n\t * @param {DOMElement|jQuery|String} el the element to create the instance on, can be jQuery extended or a selector\n\t * @param {Object} options options for this instance (extends `$.jstree.defaults`)\n\t * @return {jsTree} the new instance\n\t */\n\t$.jstree.create = function (el, options) {\n\t\tvar tmp = new $.jstree.core(++instance_counter),\n\t\t\topt = options;\n\t\toptions = $.extend(true, {}, $.jstree.defaults, options);\n\t\tif(opt && opt.plugins) {\n\t\t\toptions.plugins = opt.plugins;\n\t\t}\n\t\t$.each(options.plugins, function (i, k) {\n\t\t\tif(i !== 'core') {\n\t\t\t\ttmp = tmp.plugin(k, options[k]);\n\t\t\t}\n\t\t});\n\t\t$(el).data('jstree', tmp);\n\t\ttmp.init(el, options);\n\t\treturn tmp;\n\t};\n\t/**\n\t * remove all traces of jstree from the DOM and destroy all instances\n\t * @name $.jstree.destroy()\n\t */\n\t$.jstree.destroy = function () {\n\t\t$('.jstree:jstree').jstree('destroy');\n\t\t$(document).off('.jstree');\n\t};\n\t/**\n\t * the jstree class constructor, used only internally\n\t * @private\n\t * @name $.jstree.core(id)\n\t * @param {Number} id this instance's index\n\t */\n\t$.jstree.core = function (id) {\n\t\tthis._id = id;\n\t\tthis._cnt = 0;\n\t\tthis._wrk = null;\n\t\tthis._data = {\n\t\t\tcore : {\n\t\t\t\tthemes : {\n\t\t\t\t\tname : false,\n\t\t\t\t\tdots : false,\n\t\t\t\t\ticons : false,\n\t\t\t\t\tellipsis : false\n\t\t\t\t},\n\t\t\t\tselected : [],\n\t\t\t\tlast_error : {},\n\t\t\t\tworking : false,\n\t\t\t\tworker_queue : [],\n\t\t\t\tfocused : null\n\t\t\t}\n\t\t};\n\t};\n\t/**\n\t * get a reference to an existing instance\n\t *\n\t * __Examples__\n\t *\n\t *\t// provided a container with an ID of \"tree\", and a nested node with an ID of \"branch\"\n\t *\t// all of there will return the same instance\n\t *\t$.jstree.reference('tree');\n\t *\t$.jstree.reference('#tree');\n\t *\t$.jstree.reference($('#tree'));\n\t *\t$.jstree.reference(document.getElementByID('tree'));\n\t *\t$.jstree.reference('branch');\n\t *\t$.jstree.reference('#branch');\n\t *\t$.jstree.reference($('#branch'));\n\t *\t$.jstree.reference(document.getElementByID('branch'));\n\t *\n\t * @name $.jstree.reference(needle)\n\t * @param {DOMElement|jQuery|String} needle\n\t * @return {jsTree|null} the instance or `null` if not found\n\t */\n\t$.jstree.reference = function (needle) {\n\t\tvar tmp = null,\n\t\t\tobj = null;\n\t\tif(needle && needle.id && (!needle.tagName || !needle.nodeType)) { needle = needle.id; }\n\n\t\tif(!obj || !obj.length) {\n\t\t\ttry { obj = $(needle); } catch (ignore) { }\n\t\t}\n\t\tif(!obj || !obj.length) {\n\t\t\ttry { obj = $('#' + needle.replace($.jstree.idregex,'\\\\$&')); } catch (ignore) { }\n\t\t}\n\t\tif(obj && obj.length && (obj = obj.closest('.jstree')).length && (obj = obj.data('jstree'))) {\n\t\t\ttmp = obj;\n\t\t}\n\t\telse {\n\t\t\t$('.jstree').each(function () {\n\t\t\t\tvar inst = $(this).data('jstree');\n\t\t\t\tif(inst && inst._model.data[needle]) {\n\t\t\t\t\ttmp = inst;\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn tmp;\n\t};\n\t/**\n\t * Create an instance, get an instance or invoke a command on a instance.\n\t *\n\t * If there is no instance associated with the current node a new one is created and `arg` is used to extend `$.jstree.defaults` for this new instance. There would be no return value (chaining is not broken).\n\t *\n\t * If there is an existing instance and `arg` is a string the command specified by `arg` is executed on the instance, with any additional arguments passed to the function. If the function returns a value it will be returned (chaining could break depending on function).\n\t *\n\t * If there is an existing instance and `arg` is not a string the instance itself is returned (similar to `$.jstree.reference`).\n\t *\n\t * In any other case - nothing is returned and chaining is not broken.\n\t *\n\t * __Examples__\n\t *\n\t *\t$('#tree1').jstree(); // creates an instance\n\t *\t$('#tree2').jstree({ plugins : [] }); // create an instance with some options\n\t *\t$('#tree1').jstree('open_node', '#branch_1'); // call a method on an existing instance, passing additional arguments\n\t *\t$('#tree2').jstree(); // get an existing instance (or create an instance)\n\t *\t$('#tree2').jstree(true); // get an existing instance (will not create new instance)\n\t *\t$('#branch_1').jstree().select_node('#branch_1'); // get an instance (using a nested element and call a method)\n\t *\n\t * @name $().jstree([arg])\n\t * @param {String|Object} arg\n\t * @return {Mixed}\n\t */\n\t$.fn.jstree = function (arg) {\n\t\t// check for string argument\n\t\tvar is_method\t= (typeof arg === 'string'),\n\t\t\targs\t\t= Array.prototype.slice.call(arguments, 1),\n\t\t\tresult\t\t= null;\n\t\tif(arg === true && !this.length) { return false; }\n\t\tthis.each(function () {\n\t\t\t// get the instance (if there is one) and method (if it exists)\n\t\t\tvar instance = $.jstree.reference(this),\n\t\t\t\tmethod = is_method && instance ? instance[arg] : null;\n\t\t\t// if calling a method, and method is available - execute on the instance\n\t\t\tresult = is_method && method ?\n\t\t\t\tmethod.apply(instance, args) :\n\t\t\t\tnull;\n\t\t\t// if there is no instance and no method is being called - create one\n\t\t\tif(!instance && !is_method && (arg === undefined || $.isPlainObject(arg))) {\n\t\t\t\t$.jstree.create(this, arg);\n\t\t\t}\n\t\t\t// if there is an instance and no method is called - return the instance\n\t\t\tif( (instance && !is_method) || arg === true ) {\n\t\t\t\tresult = instance || false;\n\t\t\t}\n\t\t\t// if there was a method call which returned a result - break and return the value\n\t\t\tif(result !== null && result !== undefined) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t});\n\t\t// if there was a method call with a valid return value - return that, otherwise continue the chain\n\t\treturn result !== null && result !== undefined ?\n\t\t\tresult : this;\n\t};\n\t/**\n\t * used to find elements containing an instance\n\t *\n\t * __Examples__\n\t *\n\t *\t$('div:jstree').each(function () {\n\t *\t\t$(this).jstree('destroy');\n\t *\t});\n\t *\n\t * @name $(':jstree')\n\t * @return {jQuery}\n\t */\n\t$.expr.pseudos.jstree = $.expr.createPseudo(function(search) {\n\t\treturn function(a) {\n\t\t\treturn $(a).hasClass('jstree') &&\n\t\t\t\t$(a).data('jstree') !== undefined;\n\t\t};\n\t});\n\n\t/**\n\t * stores all defaults for the core\n\t * @name $.jstree.defaults.core\n\t */\n\t$.jstree.defaults.core = {\n\t\t/**\n\t\t * data configuration\n\t\t *\n\t\t * If left as `false` the HTML inside the jstree container element is used to populate the tree (that should be an unordered list with list items).\n\t\t *\n\t\t * You can also pass in a HTML string or a JSON array here.\n\t\t *\n\t\t * It is possible to pass in a standard jQuery-like AJAX config and jstree will automatically determine if the response is JSON or HTML and use that to populate the tree.\n\t\t * In addition to the standard jQuery ajax options here you can supply functions for `data` and `url`, the functions will be run in the current instance's scope and a param will be passed indicating which node is being loaded, the return value of those functions will be used.\n\t\t *\n\t\t * The last option is to specify a function, that function will receive the node being loaded as argument and a second param which is a function which should be called with the result.\n\t\t *\n\t\t * __Examples__\n\t\t *\n\t\t *\t// AJAX\n\t\t *\t$('#tree').jstree({\n\t\t *\t\t'core' : {\n\t\t *\t\t\t'data' : {\n\t\t *\t\t\t\t'url' : '/get/children/',\n\t\t *\t\t\t\t'data' : function (node) {\n\t\t *\t\t\t\t\treturn { 'id' : node.id };\n\t\t *\t\t\t\t}\n\t\t *\t\t\t}\n\t\t *\t\t});\n\t\t *\n\t\t *\t// direct data\n\t\t *\t$('#tree').jstree({\n\t\t *\t\t'core' : {\n\t\t *\t\t\t'data' : [\n\t\t *\t\t\t\t'Simple root node',\n\t\t *\t\t\t\t{\n\t\t *\t\t\t\t\t'id' : 'node_2',\n\t\t *\t\t\t\t\t'text' : 'Root node with options',\n\t\t *\t\t\t\t\t'state' : { 'opened' : true, 'selected' : true },\n\t\t *\t\t\t\t\t'children' : [ { 'text' : 'Child 1' }, 'Child 2']\n\t\t *\t\t\t\t}\n\t\t *\t\t\t]\n\t\t *\t\t}\n\t\t *\t});\n\t\t *\n\t\t *\t// function\n\t\t *\t$('#tree').jstree({\n\t\t *\t\t'core' : {\n\t\t *\t\t\t'data' : function (obj, callback) {\n\t\t *\t\t\t\tcallback.call(this, ['Root 1', 'Root 2']);\n\t\t *\t\t\t}\n\t\t *\t\t});\n\t\t *\n\t\t * @name $.jstree.defaults.core.data\n\t\t */\n\t\tdata\t\t\t: false,\n\t\t/**\n\t\t * configure the various strings used throughout the tree\n\t\t *\n\t\t * You can use an object where the key is the string you need to replace and the value is your replacement.\n\t\t * Another option is to specify a function which will be called with an argument of the needed string and should return the replacement.\n\t\t * If left as `false` no replacement is made.\n\t\t *\n\t\t * __Examples__\n\t\t *\n\t\t *\t$('#tree').jstree({\n\t\t *\t\t'core' : {\n\t\t *\t\t\t'strings' : {\n\t\t *\t\t\t\t'Loading ...' : 'Please wait ...'\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\t});\n\t\t *\n\t\t * @name $.jstree.defaults.core.strings\n\t\t */\n\t\tstrings\t\t\t: false,\n\t\t/**\n\t\t * determines what happens when a user tries to modify the structure of the tree\n\t\t * If left as `false` all operations like create, rename, delete, move or copy are prevented.\n\t\t * You can set this to `true` to allow all interactions or use a function to have better control.\n\t\t *\n\t\t * __Examples__\n\t\t *\n\t\t *\t$('#tree').jstree({\n\t\t *\t\t'core' : {\n\t\t *\t\t\t'check_callback' : function (operation, node, node_parent, node_position, more) {\n\t\t *\t\t\t\t// operation can be 'create_node', 'rename_node', 'delete_node', 'move_node', 'copy_node' or 'edit'\n\t\t *\t\t\t\t// in case of 'rename_node' node_position is filled with the new node name\n\t\t *\t\t\t\treturn operation === 'rename_node' ? true : false;\n\t\t *\t\t\t}\n\t\t *\t\t}\n\t\t *\t});\n\t\t *\n\t\t * @name $.jstree.defaults.core.check_callback\n\t\t */\n\t\tcheck_callback\t: false,\n\t\t/**\n\t\t * a callback called with a single object parameter in the instance's scope when something goes wrong (operation prevented, ajax failed, etc)\n\t\t * @name $.jstree.defaults.core.error\n\t\t */\n\t\terror\t\t\t: $.noop,\n\t\t/**\n\t\t * the open / close animation duration in milliseconds - set this to `false` to disable the animation (default is `200`)\n\t\t * @name $.jstree.defaults.core.animation\n\t\t */\n\t\tanimation\t\t: 200,\n\t\t/**\n\t\t * a boolean indicating if multiple nodes can be selected\n\t\t * @name $.jstree.defaults.core.multiple\n\t\t */\n\t\tmultiple\t\t: true,\n\t\t/**\n\t\t * theme configuration object\n\t\t * @name $.jstree.defaults.core.themes\n\t\t */\n\t\tthemes\t\t\t: {\n\t\t\t/**\n\t\t\t * the name of the theme to use (if left as `false` the default theme is used)\n\t\t\t * @name $.jstree.defaults.core.themes.name\n\t\t\t */\n\t\t\tname\t\t\t: false,\n\t\t\t/**\n\t\t\t * the URL of the theme's CSS file, leave this as `false` if you have manually included the theme CSS (recommended). You can set this to `true` too which will try to autoload the theme.\n\t\t\t * @name $.jstree.defaults.core.themes.url\n\t\t\t */\n\t\t\turl\t\t\t\t: false,\n\t\t\t/**\n\t\t\t * the location of all jstree themes - only used if `url` is set to `true`\n\t\t\t * @name $.jstree.defaults.core.themes.dir\n\t\t\t */\n\t\t\tdir\t\t\t\t: false,\n\t\t\t/**\n\t\t\t * a boolean indicating if connecting dots are shown\n\t\t\t * @name $.jstree.defaults.core.themes.dots\n\t\t\t */\n\t\t\tdots\t\t\t: true,\n\t\t\t/**\n\t\t\t * a boolean indicating if node icons are shown\n\t\t\t * @name $.jstree.defaults.core.themes.icons\n\t\t\t */\n\t\t\ticons\t\t\t: true,\n\t\t\t/**\n\t\t\t * a boolean indicating if node ellipsis should be shown - this only works with a fixed with on the container\n\t\t\t * @name $.jstree.defaults.core.themes.ellipsis\n\t\t\t */\n\t\t\tellipsis\t\t: false,\n\t\t\t/**\n\t\t\t * a boolean indicating if the tree background is striped\n\t\t\t * @name $.jstree.defaults.core.themes.stripes\n\t\t\t */\n\t\t\tstripes\t\t\t: false,\n\t\t\t/**\n\t\t\t * a string (or boolean `false`) specifying the theme variant to use (if the theme supports variants)\n\t\t\t * @name $.jstree.defaults.core.themes.variant\n\t\t\t */\n\t\t\tvariant\t\t\t: false,\n\t\t\t/**\n\t\t\t * a boolean specifying if a reponsive version of the theme should kick in on smaller screens (if the theme supports it). Defaults to `false`.\n\t\t\t * @name $.jstree.defaults.core.themes.responsive\n\t\t\t */\n\t\t\tresponsive\t\t: false\n\t\t},\n\t\t/**\n\t\t * if left as `true` all parents of all selected nodes will be opened once the tree loads (so that all selected nodes are visible to the user)\n\t\t * @name $.jstree.defaults.core.expand_selected_onload\n\t\t */\n\t\texpand_selected_onload : true,\n\t\t/**\n\t\t * if left as `true` web workers will be used to parse incoming JSON data where possible, so that the UI will not be blocked by large requests. Workers are however about 30% slower. Defaults to `true`\n\t\t * @name $.jstree.defaults.core.worker\n\t\t */\n\t\tworker : true,\n\t\t/**\n\t\t * Force node text to plain text (and escape HTML). Defaults to `false`\n\t\t * @name $.jstree.defaults.core.force_text\n\t\t */\n\t\tforce_text : false,\n\t\t/**\n\t\t * Should the node be toggled if the text is double clicked. Defaults to `true`\n\t\t * @name $.jstree.defaults.core.dblclick_toggle\n\t\t */\n\t\tdblclick_toggle : true,\n\t\t/**\n\t\t * Should the loaded nodes be part of the state. Defaults to `false`\n\t\t * @name $.jstree.defaults.core.loaded_state\n\t\t */\n\t\tloaded_state : false,\n\t\t/**\n\t\t * Should the last active node be focused when the tree container is blurred and the focused again. This helps working with screen readers. Defaults to `true`\n\t\t * @name $.jstree.defaults.core.restore_focus\n\t\t */\n\t\trestore_focus : true,\n\t\t/**\n\t\t * Force to compute and set \"aria-setsize\" and \"aria-posinset\" explicitly for each treeitem. \n\t\t * Some browsers may compute incorrect elements position and produce wrong announcements for screen readers. Defaults to `false`\n\t\t * @name $.jstree.defaults.core.compute_elements_positions\n\t\t */\n\t\tcompute_elements_positions : false,\n\t\t/**\n\t\t * Default keyboard shortcuts (an object where each key is the button name or combo - like 'enter', 'ctrl-space', 'p', etc and the value is the function to execute in the instance's scope)\n\t\t * @name $.jstree.defaults.core.keyboard\n\t\t */\n\t\tkeyboard : {\n\t\t\t'ctrl-space': function (e) {\n\t\t\t\t// aria defines space only with Ctrl\n\t\t\t\te.type = \"click\";\n\t\t\t\t$(e.currentTarget).trigger(e);\n\t\t\t},\n\t\t\t'enter': function (e) {\n\t\t\t\t// enter\n\t\t\t\te.type = \"click\";\n\t\t\t\t$(e.currentTarget).trigger(e);\n\t\t\t},\n\t\t\t'left': function (e) {\n\t\t\t\t// left\n\t\t\t\te.preventDefault();\n\t\t\t\tif(this.is_open(e.currentTarget)) {\n\t\t\t\t\tthis.close_node(e.currentTarget);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tvar o = this.get_parent(e.currentTarget);\n\t\t\t\t\tif(o && o.id !== $.jstree.root) { this.get_node(o, true).children('.jstree-anchor').trigger('focus'); }\n\t\t\t\t}\n\t\t\t},\n\t\t\t'up': function (e) {\n\t\t\t\t// up\n\t\t\t\te.preventDefault();\n\t\t\t\tvar o = this.get_prev_dom(e.currentTarget);\n\t\t\t\tif(o && o.length) { o.children('.jstree-anchor').trigger('focus'); }\n\t\t\t},\n\t\t\t'right': function (e) {\n\t\t\t\t// right\n\t\t\t\te.preventDefault();\n\t\t\t\tif(this.is_closed(e.currentTarget)) {\n\t\t\t\t\tthis.open_node(e.currentTarget, function (o) { this.get_node(o, true).children('.jstree-anchor').trigger('focus'); });\n\t\t\t\t}\n\t\t\t\telse if (this.is_open(e.currentTarget)) {\n\t\t\t\t\tvar o = this.get_node(e.currentTarget, true).children('.jstree-children')[0];\n\t\t\t\t\tif(o) { $(this._firstChild(o)).children('.jstree-anchor').trigger('focus'); }\n\t\t\t\t}\n\t\t\t},\n\t\t\t'down': function (e) {\n\t\t\t\t// down\n\t\t\t\te.preventDefault();\n\t\t\t\tvar o = this.get_next_dom(e.currentTarget);\n\t\t\t\tif(o && o.length) { o.children('.jstree-anchor').trigger('focus'); }\n\t\t\t},\n\t\t\t'*': function (e) {\n\t\t\t\t// aria defines * on numpad as open_all - not very common\n\t\t\t\tthis.open_all();\n\t\t\t},\n\t\t\t'home': function (e) {\n\t\t\t\t// home\n\t\t\t\te.preventDefault();\n\t\t\t\tvar o = this._firstChild(this.get_container_ul()[0]);\n\t\t\t\tif(o) { $(o).children('.jstree-anchor').filter(':visible').trigger('focus'); }\n\t\t\t},\n\t\t\t'end': function (e) {\n\t\t\t\t// end\n\t\t\t\te.preventDefault();\n\t\t\t\tthis.element.find('.jstree-anchor').filter(':visible').last().trigger('focus');\n\t\t\t},\n\t\t\t'f2': function (e) {\n\t\t\t\t// f2 - safe to include - if check_callback is false it will fail\n\t\t\t\te.preventDefault();\n\t\t\t\tthis.edit(e.currentTarget);\n\t\t\t}\n\t\t}\n\t};\n\t$.jstree.core.prototype = {\n\t\t/**\n\t\t * used to decorate an instance with a plugin. Used internally.\n\t\t * @private\n\t\t * @name plugin(deco [, opts])\n\t\t * @param {String} deco the plugin to decorate with\n\t\t * @param {Object} opts options for the plugin\n\t\t * @return {jsTree}\n\t\t */\n\t\tplugin : function (deco, opts) {\n\t\t\tvar Child = $.jstree.plugins[deco];\n\t\t\tif(Child) {\n\t\t\t\tthis._data[deco] = {};\n\t\t\t\tChild.prototype = this;\n\t\t\t\treturn new Child(opts, this);\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\t\t/**\n\t\t * initialize the instance. Used internally.\n\t\t * @private\n\t\t * @name init(el, optons)\n\t\t * @param {DOMElement|jQuery|String} el the element we are transforming\n\t\t * @param {Object} options options for this instance\n\t\t * @trigger init.jstree, loading.jstree, loaded.jstree, ready.jstree, changed.jstree\n\t\t */\n\t\tinit : function (el, options) {\n\t\t\tthis._model = {\n\t\t\t\tdata : {},\n\t\t\t\tchanged : [],\n\t\t\t\tforce_full_redraw : false,\n\t\t\t\tredraw_timeout : false,\n\t\t\t\tdefault_state : {\n\t\t\t\t\tloaded : true,\n\t\t\t\t\topened : false,\n\t\t\t\t\tselected : false,\n\t\t\t\t\tdisabled : false\n\t\t\t\t}\n\t\t\t};\n\t\t\tthis._model.data[$.jstree.root] = {\n\t\t\t\tid : $.jstree.root,\n\t\t\t\tparent : null,\n\t\t\t\tparents : [],\n\t\t\t\tchildren : [],\n\t\t\t\tchildren_d : [],\n\t\t\t\tstate : { loaded : false }\n\t\t\t};\n\n\t\t\tthis.element = $(el).addClass('jstree jstree-' + this._id);\n\t\t\tthis.settings = options;\n\n\t\t\tthis._data.core.ready = false;\n\t\t\tthis._data.core.loaded = false;\n\t\t\tthis._data.core.rtl = (this.element.css(\"direction\") === \"rtl\");\n\t\t\tthis.element[this._data.core.rtl ? 'addClass' : 'removeClass'](\"jstree-rtl\");\n\t\t\tthis.element.attr('role','tree');\n\t\t\tif(this.settings.core.multiple) {\n\t\t\t\tthis.element.attr('aria-multiselectable', true);\n\t\t\t}\n\t\t\tif(!this.element.attr('tabindex')) {\n\t\t\t\tthis.element.attr('tabindex','0');\n\t\t\t}\n\n\t\t\tthis.bind();\n\t\t\t/**\n\t\t\t * triggered after all events are bound\n\t\t\t * @event\n\t\t\t * @name init.jstree\n\t\t\t */\n\t\t\tthis.trigger(\"init\");\n\n\t\t\tthis._data.core.original_container_html = this.element.find(\" > ul > li\").clone(true);\n\t\t\tthis._data.core.original_container_html\n\t\t\t\t.find(\"li\").addBack()\n\t\t\t\t.contents().filter(function() {\n\t\t\t\t\treturn this.nodeType === 3 && (!this.nodeValue || /^\\s+$/.test(this.nodeValue));\n\t\t\t\t})\n\t\t\t\t.remove();\n\t\t\tthis.element.html(\"<\"+\"ul class='jstree-container-ul jstree-children' role='group'><\"+\"li id='j\"+this._id+\"_loading' class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='none'><i class='jstree-icon jstree-ocl'></i><\"+\"a class='jstree-anchor' role='treeitem' href='#'><i class='jstree-icon jstree-themeicon-hidden'></i>\" + this.get_string(\"Loading ...\") + \"</a></li></ul>\");\n\t\t\tthis.element.attr('aria-activedescendant','j' + this._id + '_loading');\n\t\t\tthis._data.core.li_height = this.get_container_ul().children(\"li\").first().outerHeight() || 24;\n\t\t\tthis._data.core.node = this._create_prototype_node();\n\t\t\t/**\n\t\t\t * triggered after the loading text is shown and before loading starts\n\t\t\t * @event\n\t\t\t * @name loading.jstree\n\t\t\t */\n\t\t\tthis.trigger(\"loading\");\n\t\t\tthis.load_node($.jstree.root);\n\t\t},\n\t\t/**\n\t\t * destroy an instance\n\t\t * @name destroy()\n\t\t * @param {Boolean} keep_html if not set to `true` the container will be emptied, otherwise the current DOM elements will be kept intact\n\t\t */\n\t\tdestroy : function (keep_html) {\n\t\t\t/**\n\t\t\t * triggered before the tree is destroyed\n\t\t\t * @event\n\t\t\t * @name destroy.jstree\n\t\t\t */\n\t\t\tthis.trigger(\"destroy\");\n\t\t\tif(this._wrk) {\n\t\t\t\ttry {\n\t\t\t\t\twindow.URL.revokeObjectURL(this._wrk);\n\t\t\t\t\tthis._wrk = null;\n\t\t\t\t}\n\t\t\t\tcatch (ignore) { }\n\t\t\t}\n\t\t\tif(!keep_html) { this.element.empty(); }\n\t\t\tthis.teardown();\n\t\t},\n\t\t/**\n\t\t * Create a prototype node\n\t\t * @name _create_prototype_node()\n\t\t * @return {DOMElement}\n\t\t */\n\t\t_create_prototype_node : function () {\n\t\t\tvar _node = document.createElement('LI'), _temp1, _temp2;\n\t\t\t_node.setAttribute('role', 'none');\n\t\t\t_temp1 = document.createElement('I');\n\t\t\t_temp1.className = 'jstree-icon jstree-ocl';\n\t\t\t_temp1.setAttribute('role', 'presentation');\n\t\t\t_node.appendChild(_temp1);\n\t\t\t_temp1 = document.createElement('A');\n\t\t\t_temp1.className = 'jstree-anchor';\n\t\t\t_temp1.setAttribute('href','#');\n\t\t\t_temp1.setAttribute('tabindex','-1');\n\t\t\t_temp1.setAttribute('role', 'treeitem');\n\t\t\t_temp2 = document.createElement('I');\n\t\t\t_temp2.className = 'jstree-icon jstree-themeicon';\n\t\t\t_temp2.setAttribute('role', 'presentation');\n\t\t\t_temp1.appendChild(_temp2);\n\t\t\t_node.appendChild(_temp1);\n\t\t\t_temp1 = _temp2 = null;\n\n\t\t\treturn _node;\n\t\t},\n\t\t_kbevent_to_func : function (e) {\n\t\t\tvar keys = {\n\t\t\t\t8: \"Backspace\", 9: \"Tab\", 13: \"Enter\", 19: \"Pause\", 27: \"Esc\",\n\t\t\t\t32: \"Space\", 33: \"PageUp\", 34: \"PageDown\", 35: \"End\", 36: \"Home\",\n\t\t\t\t37: \"Left\", 38: \"Up\", 39: \"Right\", 40: \"Down\", 44: \"Print\", 45: \"Insert\",\n\t\t\t\t46: \"Delete\", 96: \"Numpad0\", 97: \"Numpad1\", 98: \"Numpad2\", 99 : \"Numpad3\",\n\t\t\t\t100: \"Numpad4\", 101: \"Numpad5\", 102: \"Numpad6\", 103: \"Numpad7\",\n\t\t\t\t104: \"Numpad8\", 105: \"Numpad9\", '-13': \"NumpadEnter\", 112: \"F1\",\n\t\t\t\t113: \"F2\", 114: \"F3\", 115: \"F4\", 116: \"F5\", 117: \"F6\", 118: \"F7\",\n\t\t\t\t119: \"F8\", 120: \"F9\", 121: \"F10\", 122: \"F11\", 123: \"F12\", 144: \"Numlock\",\n\t\t\t\t145: \"Scrolllock\", 16: 'Shift', 17: 'Ctrl', 18: 'Alt',\n\t\t\t\t48: '0', 49: '1', 50: '2', 51: '3', 52: '4', 53: '5',\n\t\t\t\t54: '6', 55: '7', 56: '8', 57: '9', 59: ';', 61: '=', 65: 'a',\n\t\t\t\t66: 'b', 67: 'c', 68: 'd', 69: 'e', 70: 'f', 71: 'g', 72: 'h',\n\t\t\t\t73: 'i', 74: 'j', 75: 'k', 76: 'l', 77: 'm', 78: 'n', 79: 'o',\n\t\t\t\t80: 'p', 81: 'q', 82: 'r', 83: 's', 84: 't', 85: 'u', 86: 'v',\n\t\t\t\t87: 'w', 88: 'x', 89: 'y', 90: 'z', 107: '+', 109: '-', 110: '.',\n\t\t\t\t186: ';', 187: '=', 188: ',', 189: '-', 190: '.', 191: '/', 192: '`',\n\t\t\t\t219: '[', 220: '\\\\',221: ']', 222: \"'\", 111: '/', 106: '*', 173: '-'\n\t\t\t};\n\t\t\tvar parts = [];\n\t\t\tif (e.ctrlKey) { parts.push('ctrl'); }\n\t\t\tif (e.altKey) { parts.push('alt'); }\n if (e.shiftKey) { parts.push('shift'); }\n\t\t\tparts.push(keys[e.which] || e.which);\n parts = parts.sort().join('-').toLowerCase();\n if (parts === 'shift-shift' || parts === 'ctrl-ctrl' || parts === 'alt-alt') {\n return null;\n }\n\n\t\t\tvar kb = this.settings.core.keyboard, i, tmp;\n\t\t\tfor (i in kb) {\n\t\t\t\tif (kb.hasOwnProperty(i)) {\n\t\t\t\t\ttmp = i;\n\t\t\t\t\tif (tmp !== '-' && tmp !== '+') {\n\t\t\t\t\t\ttmp = tmp.replace('--', '-MINUS').replace('+-', '-MINUS').replace('++', '-PLUS').replace('-+', '-PLUS');\n\t\t\t\t\t\ttmp = tmp.split(/-|\\+/).sort().join('-').replace('MINUS', '-').replace('PLUS', '+').toLowerCase();\n\t\t\t\t\t}\n\t\t\t\t\tif (tmp === parts) {\n\t\t\t\t\t\treturn kb[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\t/**\n\t\t * part of the destroying of an instance. Used internally.\n\t\t * @private\n\t\t * @name teardown()\n\t\t */\n\t\tteardown : function () {\n\t\t\tthis.unbind();\n\t\t\tthis.element\n\t\t\t\t.removeClass('jstree')\n\t\t\t\t.removeData('jstree')\n\t\t\t\t.find(\"[class^='jstree']\")\n\t\t\t\t\t.addBack()\n\t\t\t\t\t.attr(\"class\", function () { return this.className.replace(/jstree[^ ]*|$/ig,''); });\n\t\t\tthis.element = null;\n\t\t},\n\t\t/**\n\t\t * bind all events. Used internally.\n\t\t * @private\n\t\t * @name bind()\n\t\t */\n\t\tbind : function () {\n\t\t\tvar word = '',\n\t\t\t\ttout = null,\n\t\t\t\twas_click = 0;\n\t\t\tthis.element\n\t\t\t\t.on(\"dblclick.jstree\", function (e) {\n\t\t\t\t\t\tif(e.target.tagName && e.target.tagName.toLowerCase() === \"input\") { return true; }\n\t\t\t\t\t\tif(document.selection && document.selection.empty) {\n\t\t\t\t\t\t\tdocument.selection.empty();\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tif(window.getSelection) {\n\t\t\t\t\t\t\t\tvar sel = window.getSelection();\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tsel.removeAllRanges();\n\t\t\t\t\t\t\t\t\tsel.collapse();\n\t\t\t\t\t\t\t\t} catch (ignore) { }\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t.on(\"mousedown.jstree\", function (e) {\n\t\t\t\t\t\tif(e.target === this.element[0]) {\n\t\t\t\t\t\t\te.preventDefault(); // prevent losing focus when clicking scroll arrows (FF, Chrome)\n\t\t\t\t\t\t\twas_click = +(new Date()); // ie does not allow to prevent losing focus\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"mousedown.jstree\", \".jstree-ocl\", function (e) {\n\t\t\t\t\t\te.preventDefault(); // prevent any node inside from losing focus when clicking the open/close icon\n\t\t\t\t\t})\n\t\t\t\t.on(\"click.jstree\", \".jstree-ocl\", function (e) {\n\t\t\t\t\t\tthis.toggle_node(e.target);\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"dblclick.jstree\", \".jstree-anchor\", function (e) {\n\t\t\t\t\t\tif(e.target.tagName && e.target.tagName.toLowerCase() === \"input\") { return true; }\n\t\t\t\t\t\tif(this.settings.core.dblclick_toggle) {\n\t\t\t\t\t\t\tthis.toggle_node(e.target);\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"click.jstree\", \".jstree-anchor\", function (e) {\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tif(e.currentTarget !== document.activeElement) { $(e.currentTarget).trigger('focus'); }\n\t\t\t\t\t\tthis.activate_node(e.currentTarget, e);\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on('keydown.jstree', '.jstree-anchor', function (e) {\n\t\t\t\t\t\tif(e.target.tagName && e.target.tagName.toLowerCase() === \"input\") { return true; }\n\t\t\t\t\t\tif(this._data.core.rtl) {\n\t\t\t\t\t\t\tif(e.which === 37) { e.which = 39; }\n\t\t\t\t\t\t\telse if(e.which === 39) { e.which = 37; }\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvar f = this._kbevent_to_func(e);\n\t\t\t\t\t\tif (f) {\n\t\t\t\t\t\t\tvar r = f.call(this, e);\n\t\t\t\t\t\t\tif (r === false || r === true) {\n\t\t\t\t\t\t\t\treturn r;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"load_node.jstree\", function (e, data) {\n\t\t\t\t\t\tif(data.status) {\n\t\t\t\t\t\t\tif(data.node.id === $.jstree.root && !this._data.core.loaded) {\n\t\t\t\t\t\t\t\tthis._data.core.loaded = true;\n\t\t\t\t\t\t\t\tif(this._firstChild(this.get_container_ul()[0])) {\n\t\t\t\t\t\t\t\t\tthis.element.attr('aria-activedescendant',this._firstChild(this.get_container_ul()[0]).id);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t\t * triggered after the root node is loaded for the first time\n\t\t\t\t\t\t\t\t * @event\n\t\t\t\t\t\t\t\t * @name loaded.jstree\n\t\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\t\tthis.trigger(\"loaded\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(!this._data.core.ready) {\n\t\t\t\t\t\t\t\tsetTimeout(function() {\n\t\t\t\t\t\t\t\t\tif(this.element && !this.get_container_ul().find('.jstree-loading').length) {\n\t\t\t\t\t\t\t\t\t\tthis._data.core.ready = true;\n\t\t\t\t\t\t\t\t\t\tif(this._data.core.selected.length) {\n\t\t\t\t\t\t\t\t\t\t\tif(this.settings.core.expand_selected_onload) {\n\t\t\t\t\t\t\t\t\t\t\t\tvar tmp = [], i, j;\n\t\t\t\t\t\t\t\t\t\t\t\tfor(i = 0, j = this._data.core.selected.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\t\t\t\t\ttmp = tmp.concat(this._model.data[this._data.core.selected[i]].parents);\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\ttmp = $.vakata.array_unique(tmp);\n\t\t\t\t\t\t\t\t\t\t\t\tfor(i = 0, j = tmp.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\t\t\t\t\tthis.open_node(tmp[i], false, 0);\n\t\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tthis.trigger('changed', { 'action' : 'ready', 'selected' : this._data.core.selected });\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t/**\n\t\t\t\t\t\t\t\t\t\t * triggered after all nodes are finished loading\n\t\t\t\t\t\t\t\t\t\t * @event\n\t\t\t\t\t\t\t\t\t\t * @name ready.jstree\n\t\t\t\t\t\t\t\t\t\t */\n\t\t\t\t\t\t\t\t\t\tthis.trigger(\"ready\");\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}.bind(this), 0);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this))\n\t\t\t\t// quick searching when the tree is focused\n\t\t\t\t.on('keypress.jstree', function (e) {\n\t\t\t\t\t\tif(e.target.tagName && e.target.tagName.toLowerCase() === \"input\") { return true; }\n\t\t\t\t\t\tif(tout) { clearTimeout(tout); }\n\t\t\t\t\t\ttout = setTimeout(function () {\n\t\t\t\t\t\t\tword = '';\n\t\t\t\t\t\t}, 500);\n\n\t\t\t\t\t\tvar chr = String.fromCharCode(e.which).toLowerCase(),\n\t\t\t\t\t\t\tcol = this.element.find('.jstree-anchor').filter(':visible'),\n\t\t\t\t\t\t\tind = col.index(document.activeElement) || 0,\n\t\t\t\t\t\t\tend = false;\n\t\t\t\t\t\tword += chr;\n\n\t\t\t\t\t\t// match for whole word from current node down (including the current node)\n\t\t\t\t\t\tif(word.length > 1) {\n\t\t\t\t\t\t\tcol.slice(ind).each(function (i, v) {\n\t\t\t\t\t\t\t\tif($(v).text().toLowerCase().indexOf(word) === 0) {\n\t\t\t\t\t\t\t\t\t$(v).trigger('focus');\n\t\t\t\t\t\t\t\t\tend = true;\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}.bind(this));\n\t\t\t\t\t\t\tif(end) { return; }\n\n\t\t\t\t\t\t\t// match for whole word from the beginning of the tree\n\t\t\t\t\t\t\tcol.slice(0, ind).each(function (i, v) {\n\t\t\t\t\t\t\t\tif($(v).text().toLowerCase().indexOf(word) === 0) {\n\t\t\t\t\t\t\t\t\t$(v).trigger('focus');\n\t\t\t\t\t\t\t\t\tend = true;\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}.bind(this));\n\t\t\t\t\t\t\tif(end) { return; }\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// list nodes that start with that letter (only if word consists of a single char)\n\t\t\t\t\t\tif(new RegExp('^' + chr.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&') + '+$').test(word)) {\n\t\t\t\t\t\t\t// search for the next node starting with that letter\n\t\t\t\t\t\t\tcol.slice(ind + 1).each(function (i, v) {\n\t\t\t\t\t\t\t\tif($(v).text().toLowerCase().charAt(0) === chr) {\n\t\t\t\t\t\t\t\t\t$(v).trigger('focus');\n\t\t\t\t\t\t\t\t\tend = true;\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}.bind(this));\n\t\t\t\t\t\t\tif(end) { return; }\n\n\t\t\t\t\t\t\t// search from the beginning\n\t\t\t\t\t\t\tcol.slice(0, ind + 1).each(function (i, v) {\n\t\t\t\t\t\t\t\tif($(v).text().toLowerCase().charAt(0) === chr) {\n\t\t\t\t\t\t\t\t\t$(v).trigger('focus');\n\t\t\t\t\t\t\t\t\tend = true;\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}.bind(this));\n\t\t\t\t\t\t\tif(end) { return; }\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this))\n\t\t\t\t// THEME RELATED\n\t\t\t\t.on(\"init.jstree\", function () {\n\t\t\t\t\t\tvar s = this.settings.core.themes;\n\t\t\t\t\t\tthis._data.core.themes.dots\t\t\t= s.dots;\n\t\t\t\t\t\tthis._data.core.themes.stripes\t\t= s.stripes;\n\t\t\t\t\t\tthis._data.core.themes.icons\t\t= s.icons;\n\t\t\t\t\t\tthis._data.core.themes.ellipsis\t\t= s.ellipsis;\n\t\t\t\t\t\tthis.set_theme(s.name || \"default\", s.url);\n\t\t\t\t\t\tthis.set_theme_variant(s.variant);\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"loading.jstree\", function () {\n\t\t\t\t\t\tthis[ this._data.core.themes.dots ? \"show_dots\" : \"hide_dots\" ]();\n\t\t\t\t\t\tthis[ this._data.core.themes.icons ? \"show_icons\" : \"hide_icons\" ]();\n\t\t\t\t\t\tthis[ this._data.core.themes.stripes ? \"show_stripes\" : \"hide_stripes\" ]();\n\t\t\t\t\t\tthis[ this._data.core.themes.ellipsis ? \"show_ellipsis\" : \"hide_ellipsis\" ]();\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on('blur.jstree', '.jstree-anchor', function (e) {\n\t\t\t\t\t\tthis._data.core.focused = null;\n\t\t\t\t\t\t$(e.currentTarget).filter('.jstree-hovered').trigger('mouseleave');\n\t\t\t\t\t\tthis.element.attr('tabindex', '0');\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on('focus.jstree', '.jstree-anchor', function (e) {\n\t\t\t\t\t\tvar tmp = this.get_node(e.currentTarget);\n\t\t\t\t\t\tif(tmp && tmp.id) {\n\t\t\t\t\t\t\tthis._data.core.focused = tmp.id;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.element.find('.jstree-hovered').not(e.currentTarget).trigger('mouseleave');\n\t\t\t\t\t\t$(e.currentTarget).trigger('mouseenter');\n\t\t\t\t\t\tthis.element.attr('tabindex', '-1');\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on('focus.jstree', function () {\n\t\t\t\t\t\tif(+(new Date()) - was_click > 500 && !this._data.core.focused && this.settings.core.restore_focus) {\n\t\t\t\t\t\t\twas_click = 0;\n\t\t\t\t\t\t\tvar act = this.get_node(this.element.attr('aria-activedescendant'), true);\n\t\t\t\t\t\t\tif(act) {\n\t\t\t\t\t\t\t\tact.find('> .jstree-anchor').trigger('focus');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on('mouseenter.jstree', '.jstree-anchor', function (e) {\n\t\t\t\t\t\tthis.hover_node(e.currentTarget);\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on('mouseleave.jstree', '.jstree-anchor', function (e) {\n\t\t\t\t\t\tthis.dehover_node(e.currentTarget);\n\t\t\t\t\t}.bind(this));\n\t\t},\n\t\t/**\n\t\t * part of the destroying of an instance. Used internally.\n\t\t * @private\n\t\t * @name unbind()\n\t\t */\n\t\tunbind : function () {\n\t\t\tthis.element.off('.jstree');\n\t\t\t$(document).off('.jstree-' + this._id);\n\t\t},\n\t\t/**\n\t\t * trigger an event. Used internally.\n\t\t * @private\n\t\t * @name trigger(ev [, data])\n\t\t * @param {String} ev the name of the event to trigger\n\t\t * @param {Object} data additional data to pass with the event\n\t\t */\n\t\ttrigger : function (ev, data) {\n\t\t\tif(!data) {\n\t\t\t\tdata = {};\n\t\t\t}\n\t\t\tdata.instance = this;\n\t\t\tthis.element.triggerHandler(ev.replace('.jstree','') + '.jstree', data);\n\t\t},\n\t\t/**\n\t\t * returns the jQuery extended instance container\n\t\t * @name get_container()\n\t\t * @return {jQuery}\n\t\t */\n\t\tget_container : function () {\n\t\t\treturn this.element;\n\t\t},\n\t\t/**\n\t\t * returns the jQuery extended main UL node inside the instance container. Used internally.\n\t\t * @private\n\t\t * @name get_container_ul()\n\t\t * @return {jQuery}\n\t\t */\n\t\tget_container_ul : function () {\n\t\t\treturn this.element.children(\".jstree-children\").first();\n\t\t},\n\t\t/**\n\t\t * gets string replacements (localization). Used internally.\n\t\t * @private\n\t\t * @name get_string(key)\n\t\t * @param {String} key\n\t\t * @return {String}\n\t\t */\n\t\tget_string : function (key) {\n\t\t\tvar a = this.settings.core.strings;\n\t\t\tif($.vakata.is_function(a)) { return a.call(this, key); }\n\t\t\tif(a && a[key]) { return a[key]; }\n\t\t\treturn key;\n\t\t},\n\t\t/**\n\t\t * gets the first child of a DOM node. Used internally.\n\t\t * @private\n\t\t * @name _firstChild(dom)\n\t\t * @param {DOMElement} dom\n\t\t * @return {DOMElement}\n\t\t */\n\t\t_firstChild : function (dom) {\n\t\t\tdom = dom ? dom.firstChild : null;\n\t\t\twhile(dom !== null && dom.nodeType !== 1) {\n\t\t\t\tdom = dom.nextSibling;\n\t\t\t}\n\t\t\treturn dom;\n\t\t},\n\t\t/**\n\t\t * gets the next sibling of a DOM node. Used internally.\n\t\t * @private\n\t\t * @name _nextSibling(dom)\n\t\t * @param {DOMElement} dom\n\t\t * @return {DOMElement}\n\t\t */\n\t\t_nextSibling : function (dom) {\n\t\t\tdom = dom ? dom.nextSibling : null;\n\t\t\twhile(dom !== null && dom.nodeType !== 1) {\n\t\t\t\tdom = dom.nextSibling;\n\t\t\t}\n\t\t\treturn dom;\n\t\t},\n\t\t/**\n\t\t * gets the previous sibling of a DOM node. Used internally.\n\t\t * @private\n\t\t * @name _previousSibling(dom)\n\t\t * @param {DOMElement} dom\n\t\t * @return {DOMElement}\n\t\t */\n\t\t_previousSibling : function (dom) {\n\t\t\tdom = dom ? dom.previousSibling : null;\n\t\t\twhile(dom !== null && dom.nodeType !== 1) {\n\t\t\t\tdom = dom.previousSibling;\n\t\t\t}\n\t\t\treturn dom;\n\t\t},\n\t\t/**\n\t\t * get the JSON representation of a node (or the actual jQuery extended DOM node) by using any input (child DOM element, ID string, selector, etc)\n\t\t * @name get_node(obj [, as_dom])\n\t\t * @param {mixed} obj\n\t\t * @param {Boolean} as_dom\n\t\t * @return {Object|jQuery}\n\t\t */\n\t\tget_node : function (obj, as_dom) {\n\t\t\tif(obj && obj.id) {\n\t\t\t\tobj = obj.id;\n\t\t\t}\n\t\t\tif (obj instanceof $ && obj.length && obj[0].id) {\n\t\t\t\tobj = obj[0].id;\n\t\t\t}\n\t\t\tvar dom;\n\t\t\ttry {\n\t\t\t\tif(this._model.data[obj]) {\n\t\t\t\t\tobj = this._model.data[obj];\n\t\t\t\t}\n\t\t\t\telse if(typeof obj === \"string\" && this._model.data[obj.replace(/^#/, '')]) {\n\t\t\t\t\tobj = this._model.data[obj.replace(/^#/, '')];\n\t\t\t\t}\n\t\t\t\telse if(typeof obj === \"string\" && (dom = $('#' + obj.replace($.jstree.idregex,'\\\\$&'), this.element)).length && this._model.data[dom.closest('.jstree-node').attr('id')]) {\n\t\t\t\t\tobj = this._model.data[dom.closest('.jstree-node').attr('id')];\n\t\t\t\t}\n\t\t\t\telse if((dom = this.element.find(obj)).length && this._model.data[dom.closest('.jstree-node').attr('id')]) {\n\t\t\t\t\tobj = this._model.data[dom.closest('.jstree-node').attr('id')];\n\t\t\t\t}\n\t\t\t\telse if((dom = this.element.find(obj)).length && dom.hasClass('jstree')) {\n\t\t\t\t\tobj = this._model.data[$.jstree.root];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\tif(as_dom) {\n\t\t\t\t\tobj = obj.id === $.jstree.root ? this.element : $('#' + obj.id.replace($.jstree.idregex,'\\\\$&'), this.element);\n\t\t\t\t}\n\t\t\t\treturn obj;\n\t\t\t} catch (ex) { return false; }\n\t\t},\n\t\t/**\n\t\t * get the path to a node, either consisting of node texts, or of node IDs, optionally glued together (otherwise an array)\n\t\t * @name get_path(obj [, glue, ids])\n\t\t * @param {mixed} obj the node\n\t\t * @param {String} glue if you want the path as a string - pass the glue here (for example '/'), if a falsy value is supplied here, an array is returned\n\t\t * @param {Boolean} ids if set to true build the path using ID, otherwise node text is used\n\t\t * @return {mixed}\n\t\t */\n\t\tget_path : function (obj, glue, ids) {\n\t\t\tobj = obj.parents ? obj : this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root || !obj.parents) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar i, j, p = [];\n\t\t\tp.push(ids ? obj.id : obj.text);\n\t\t\tfor(i = 0, j = obj.parents.length; i < j; i++) {\n\t\t\t\tp.push(ids ? obj.parents[i] : this.get_text(obj.parents[i]));\n\t\t\t}\n\t\t\tp = p.reverse().slice(1);\n\t\t\treturn glue ? p.join(glue) : p;\n\t\t},\n\t\t/**\n\t\t * get the next visible node that is below the `obj` node. If `strict` is set to `true` only sibling nodes are returned.\n\t\t * @name get_next_dom(obj [, strict])\n\t\t * @param {mixed} obj\n\t\t * @param {Boolean} strict\n\t\t * @return {jQuery}\n\t\t */\n\t\tget_next_dom : function (obj, strict) {\n\t\t\tvar tmp;\n\t\t\tobj = this.get_node(obj, true);\n\t\t\tif(obj[0] === this.element[0]) {\n\t\t\t\ttmp = this._firstChild(this.get_container_ul()[0]);\n\t\t\t\twhile (tmp && tmp.offsetHeight === 0) {\n\t\t\t\t\ttmp = this._nextSibling(tmp);\n\t\t\t\t}\n\t\t\t\treturn tmp ? $(tmp) : false;\n\t\t\t}\n\t\t\tif(!obj || !obj.length) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(strict) {\n\t\t\t\ttmp = obj[0];\n\t\t\t\tdo {\n\t\t\t\t\ttmp = this._nextSibling(tmp);\n\t\t\t\t} while (tmp && tmp.offsetHeight === 0);\n\t\t\t\treturn tmp ? $(tmp) : false;\n\t\t\t}\n\t\t\tif(obj.hasClass(\"jstree-open\")) {\n\t\t\t\ttmp = this._firstChild(obj.children('.jstree-children')[0]);\n\t\t\t\twhile (tmp && tmp.offsetHeight === 0) {\n\t\t\t\t\ttmp = this._nextSibling(tmp);\n\t\t\t\t}\n\t\t\t\tif(tmp !== null) {\n\t\t\t\t\treturn $(tmp);\n\t\t\t\t}\n\t\t\t}\n\t\t\ttmp = obj[0];\n\t\t\tdo {\n\t\t\t\ttmp = this._nextSibling(tmp);\n\t\t\t} while (tmp && tmp.offsetHeight === 0);\n\t\t\tif(tmp !== null) {\n\t\t\t\treturn $(tmp);\n\t\t\t}\n\t\t\treturn obj.parentsUntil(\".jstree\",\".jstree-node\").nextAll(\".jstree-node:visible\").first();\n\t\t},\n\t\t/**\n\t\t * get the previous visible node that is above the `obj` node. If `strict` is set to `true` only sibling nodes are returned.\n\t\t * @name get_prev_dom(obj [, strict])\n\t\t * @param {mixed} obj\n\t\t * @param {Boolean} strict\n\t\t * @return {jQuery}\n\t\t */\n\t\tget_prev_dom : function (obj, strict) {\n\t\t\tvar tmp;\n\t\t\tobj = this.get_node(obj, true);\n\t\t\tif(obj[0] === this.element[0]) {\n\t\t\t\ttmp = this.get_container_ul()[0].lastChild;\n\t\t\t\twhile (tmp && tmp.offsetHeight === 0) {\n\t\t\t\t\ttmp = this._previousSibling(tmp);\n\t\t\t\t}\n\t\t\t\treturn tmp ? $(tmp) : false;\n\t\t\t}\n\t\t\tif(!obj || !obj.length) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(strict) {\n\t\t\t\ttmp = obj[0];\n\t\t\t\tdo {\n\t\t\t\t\ttmp = this._previousSibling(tmp);\n\t\t\t\t} while (tmp && tmp.offsetHeight === 0);\n\t\t\t\treturn tmp ? $(tmp) : false;\n\t\t\t}\n\t\t\ttmp = obj[0];\n\t\t\tdo {\n\t\t\t\ttmp = this._previousSibling(tmp);\n\t\t\t} while (tmp && tmp.offsetHeight === 0);\n\t\t\tif(tmp !== null) {\n\t\t\t\tobj = $(tmp);\n\t\t\t\twhile(obj.hasClass(\"jstree-open\")) {\n\t\t\t\t\tobj = obj.children(\".jstree-children\").first().children(\".jstree-node:visible:last\");\n\t\t\t\t}\n\t\t\t\treturn obj;\n\t\t\t}\n\t\t\ttmp = obj[0].parentNode.parentNode;\n\t\t\treturn tmp && tmp.className && tmp.className.indexOf('jstree-node') !== -1 ? $(tmp) : false;\n\t\t},\n\t\t/**\n\t\t * get the parent ID of a node\n\t\t * @name get_parent(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {String}\n\t\t */\n\t\tget_parent : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn obj.parent;\n\t\t},\n\t\t/**\n\t\t * get a jQuery collection of all the children of a node (node must be rendered), returns false on error\n\t\t * @name get_children_dom(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {jQuery}\n\t\t */\n\t\tget_children_dom : function (obj) {\n\t\t\tobj = this.get_node(obj, true);\n\t\t\tif(obj[0] === this.element[0]) {\n\t\t\t\treturn this.get_container_ul().children(\".jstree-node\");\n\t\t\t}\n\t\t\tif(!obj || !obj.length) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn obj.children(\".jstree-children\").children(\".jstree-node\");\n\t\t},\n\t\t/**\n\t\t * checks if a node has children\n\t\t * @name is_parent(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {Boolean}\n\t\t */\n\t\tis_parent : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\treturn obj && (obj.state.loaded === false || obj.children.length > 0);\n\t\t},\n\t\t/**\n\t\t * checks if a node is loaded (its children are available)\n\t\t * @name is_loaded(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {Boolean}\n\t\t */\n\t\tis_loaded : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\treturn obj && obj.state.loaded;\n\t\t},\n\t\t/**\n\t\t * check if a node is currently loading (fetching children)\n\t\t * @name is_loading(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {Boolean}\n\t\t */\n\t\tis_loading : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\treturn obj && obj.state && obj.state.loading;\n\t\t},\n\t\t/**\n\t\t * check if a node is opened\n\t\t * @name is_open(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {Boolean}\n\t\t */\n\t\tis_open : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\treturn obj && obj.state.opened;\n\t\t},\n\t\t/**\n\t\t * check if a node is in a closed state\n\t\t * @name is_closed(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {Boolean}\n\t\t */\n\t\tis_closed : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\treturn obj && this.is_parent(obj) && !obj.state.opened;\n\t\t},\n\t\t/**\n\t\t * check if a node has no children\n\t\t * @name is_leaf(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {Boolean}\n\t\t */\n\t\tis_leaf : function (obj) {\n\t\t\treturn !this.is_parent(obj);\n\t\t},\n\t\t/**\n\t\t * loads a node (fetches its children using the `core.data` setting). Multiple nodes can be passed to by using an array.\n\t\t * @name load_node(obj [, callback])\n\t\t * @param {mixed} obj\n\t\t * @param {function} callback a function to be executed once loading is complete, the function is executed in the instance's scope and receives two arguments - the node and a boolean status\n\t\t * @return {Boolean}\n\t\t * @trigger load_node.jstree\n\t\t */\n\t\tload_node : function (obj, callback) {\n\t\t\tvar k, l, i, j, c;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tthis._load_nodes(obj.slice(), callback);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj) {\n\t\t\t\tif(callback) { callback.call(this, obj, false); }\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t// if(obj.state.loading) { } // the node is already loading - just wait for it to load and invoke callback? but if called implicitly it should be loaded again?\n\t\t\tif(obj.state.loaded) {\n\t\t\t\tobj.state.loaded = false;\n\t\t\t\tfor(i = 0, j = obj.parents.length; i < j; i++) {\n\t\t\t\t\tthis._model.data[obj.parents[i]].children_d = $.vakata.array_filter(this._model.data[obj.parents[i]].children_d, function (v) {\n\t\t\t\t\t\treturn $.inArray(v, obj.children_d) === -1;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tfor(k = 0, l = obj.children_d.length; k < l; k++) {\n\t\t\t\t\tif(this._model.data[obj.children_d[k]].state.selected) {\n\t\t\t\t\t\tc = true;\n\t\t\t\t\t}\n\t\t\t\t\tdelete this._model.data[obj.children_d[k]];\n\t\t\t\t}\n\t\t\t\tif (c) {\n\t\t\t\t\tthis._data.core.selected = $.vakata.array_filter(this._data.core.selected, function (v) {\n\t\t\t\t\t\treturn $.inArray(v, obj.children_d) === -1;\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tobj.children = [];\n\t\t\t\tobj.children_d = [];\n\t\t\t\tif(c) {\n\t\t\t\t\tthis.trigger('changed', { 'action' : 'load_node', 'node' : obj, 'selected' : this._data.core.selected });\n\t\t\t\t}\n\t\t\t}\n\t\t\tobj.state.failed = false;\n\t\t\tobj.state.loading = true;\n\t\t\tthis.get_node(obj, true).addClass(\"jstree-loading\").attr('aria-busy',true);\n\t\t\tthis._load_node(obj, function (status) {\n\t\t\t\tobj = this._model.data[obj.id];\n\t\t\t\tobj.state.loading = false;\n\t\t\t\tobj.state.loaded = status;\n\t\t\t\tobj.state.failed = !obj.state.loaded;\n\t\t\t\tvar dom = this.get_node(obj, true), i = 0, j = 0, m = this._model.data, has_children = false;\n\t\t\t\tfor(i = 0, j = obj.children.length; i < j; i++) {\n\t\t\t\t\tif(m[obj.children[i]] && !m[obj.children[i]].state.hidden) {\n\t\t\t\t\t\thas_children = true;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(obj.state.loaded && dom && dom.length) {\n\t\t\t\t\tdom.removeClass('jstree-closed jstree-open jstree-leaf');\n\t\t\t\t\tif (!has_children) {\n\t\t\t\t\t\tdom.addClass('jstree-leaf');\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tif (obj.id !== '#') {\n\t\t\t\t\t\t\tdom.addClass(obj.state.opened ? 'jstree-open' : 'jstree-closed');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tdom.removeClass(\"jstree-loading\").attr('aria-busy',false);\n\t\t\t\t/**\n\t\t\t\t * triggered after a node is loaded\n\t\t\t\t * @event\n\t\t\t\t * @name load_node.jstree\n\t\t\t\t * @param {Object} node the node that was loading\n\t\t\t\t * @param {Boolean} status was the node loaded successfully\n\t\t\t\t */\n\t\t\t\tthis.trigger('load_node', { \"node\" : obj, \"status\" : status });\n\t\t\t\tif(callback) {\n\t\t\t\t\tcallback.call(this, obj, status);\n\t\t\t\t}\n\t\t\t}.bind(this));\n\t\t\treturn true;\n\t\t},\n\t\t/**\n\t\t * load an array of nodes (will also load unavailable nodes as soon as they appear in the structure). Used internally.\n\t\t * @private\n\t\t * @name _load_nodes(nodes [, callback])\n\t\t * @param {array} nodes\n\t\t * @param {function} callback a function to be executed once loading is complete, the function is executed in the instance's scope and receives one argument - the array passed to _load_nodes\n\t\t */\n\t\t_load_nodes : function (nodes, callback, is_callback, force_reload) {\n\t\t\tvar r = true,\n\t\t\t\tc = function () { this._load_nodes(nodes, callback, true); },\n\t\t\t\tm = this._model.data, i, j, tmp = [];\n\t\t\tfor(i = 0, j = nodes.length; i < j; i++) {\n\t\t\t\tif(m[nodes[i]] && ( (!m[nodes[i]].state.loaded && !m[nodes[i]].state.failed) || (!is_callback && force_reload) )) {\n\t\t\t\t\tif(!this.is_loading(nodes[i])) {\n\t\t\t\t\t\tthis.load_node(nodes[i], c);\n\t\t\t\t\t}\n\t\t\t\t\tr = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(r) {\n\t\t\t\tfor(i = 0, j = nodes.length; i < j; i++) {\n\t\t\t\t\tif(m[nodes[i]] && m[nodes[i]].state.loaded) {\n\t\t\t\t\t\ttmp.push(nodes[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(callback && !callback.done) {\n\t\t\t\t\tcallback.call(this, tmp);\n\t\t\t\t\tcallback.done = true;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * loads all unloaded nodes\n\t\t * @name load_all([obj, callback])\n\t\t * @param {mixed} obj the node to load recursively, omit to load all nodes in the tree\n\t\t * @param {function} callback a function to be executed once loading all the nodes is complete,\n\t\t * @trigger load_all.jstree\n\t\t */\n\t\tload_all : function (obj, callback) {\n\t\t\tif(!obj) { obj = $.jstree.root; }\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj) { return false; }\n\t\t\tvar to_load = [],\n\t\t\t\tm = this._model.data,\n\t\t\t\tc = m[obj.id].children_d,\n\t\t\t\ti, j;\n\t\t\tif(obj.state && !obj.state.loaded) {\n\t\t\t\tto_load.push(obj.id);\n\t\t\t}\n\t\t\tfor(i = 0, j = c.length; i < j; i++) {\n\t\t\t\tif(m[c[i]] && m[c[i]].state && !m[c[i]].state.loaded) {\n\t\t\t\t\tto_load.push(c[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(to_load.length) {\n\t\t\t\tthis._load_nodes(to_load, function () {\n\t\t\t\t\tthis.load_all(obj, callback);\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\t/**\n\t\t\t\t * triggered after a load_all call completes\n\t\t\t\t * @event\n\t\t\t\t * @name load_all.jstree\n\t\t\t\t * @param {Object} node the recursively loaded node\n\t\t\t\t */\n\t\t\t\tif(callback) { callback.call(this, obj); }\n\t\t\t\tthis.trigger('load_all', { \"node\" : obj });\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * handles the actual loading of a node. Used only internally.\n\t\t * @private\n\t\t * @name _load_node(obj [, callback])\n\t\t * @param {mixed} obj\n\t\t * @param {function} callback a function to be executed once loading is complete, the function is executed in the instance's scope and receives one argument - a boolean status\n\t\t * @return {Boolean}\n\t\t */\n\t\t_load_node : function (obj, callback) {\n\t\t\tvar s = this.settings.core.data, t;\n\t\t\tvar notTextOrCommentNode = function notTextOrCommentNode () {\n\t\t\t\treturn this.nodeType !== 3 && this.nodeType !== 8;\n\t\t\t};\n\t\t\t// use original HTML\n\t\t\tif(!s) {\n\t\t\t\tif(obj.id === $.jstree.root) {\n\t\t\t\t\treturn this._append_html_data(obj, this._data.core.original_container_html.clone(true), function (status) {\n\t\t\t\t\t\tcallback.call(this, status);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\treturn callback.call(this, false);\n\t\t\t\t}\n\t\t\t\t// return callback.call(this, obj.id === $.jstree.root ? this._append_html_data(obj, this._data.core.original_container_html.clone(true)) : false);\n\t\t\t}\n\t\t\tif($.vakata.is_function(s)) {\n\t\t\t\treturn s.call(this, obj, function (d) {\n\t\t\t\t\tif(d === false) {\n\t\t\t\t\t\tcallback.call(this, false);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis[typeof d === 'string' ? '_append_html_data' : '_append_json_data'](obj, typeof d === 'string' ? $($.parseHTML(d)).filter(notTextOrCommentNode) : d, function (status) {\n\t\t\t\t\t\t\tcallback.call(this, status);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\t// return d === false ? callback.call(this, false) : callback.call(this, this[typeof d === 'string' ? '_append_html_data' : '_append_json_data'](obj, typeof d === 'string' ? $(d) : d));\n\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t\tif(typeof s === 'object') {\n\t\t\t\tif(s.url) {\n\t\t\t\t\ts = $.extend(true, {}, s);\n\t\t\t\t\tif($.vakata.is_function(s.url)) {\n\t\t\t\t\t\ts.url = s.url.call(this, obj);\n\t\t\t\t\t}\n\t\t\t\t\tif($.vakata.is_function(s.data)) {\n\t\t\t\t\t\ts.data = s.data.call(this, obj);\n\t\t\t\t\t}\n\t\t\t\t\treturn $.ajax(s)\n\t\t\t\t\t\t.done(function (d,t,x) {\n\t\t\t\t\t\t\t\tvar type = x.getResponseHeader('Content-Type');\n\t\t\t\t\t\t\t\tif((type && type.indexOf('json') !== -1) || typeof d === \"object\") {\n\t\t\t\t\t\t\t\t\treturn this._append_json_data(obj, d, function (status) { callback.call(this, status); });\n\t\t\t\t\t\t\t\t\t//return callback.call(this, this._append_json_data(obj, d));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif((type && type.indexOf('html') !== -1) || typeof d === \"string\") {\n\t\t\t\t\t\t\t\t\treturn this._append_html_data(obj, $($.parseHTML(d)).filter(notTextOrCommentNode), function (status) { callback.call(this, status); });\n\t\t\t\t\t\t\t\t\t// return callback.call(this, this._append_html_data(obj, $(d)));\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tthis._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'core', 'id' : 'core_04', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id, 'xhr' : x }) };\n\t\t\t\t\t\t\t\tthis.settings.core.error.call(this, this._data.core.last_error);\n\t\t\t\t\t\t\t\treturn callback.call(this, false);\n\t\t\t\t\t\t\t}.bind(this))\n\t\t\t\t\t\t.fail(function (f) {\n\t\t\t\t\t\t\t\tthis._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'core', 'id' : 'core_04', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id, 'xhr' : f }) };\n\t\t\t\t\t\t\t\tcallback.call(this, false);\n\t\t\t\t\t\t\t\tthis.settings.core.error.call(this, this._data.core.last_error);\n\t\t\t\t\t\t\t}.bind(this));\n\t\t\t\t}\n\t\t\t\tif ($.vakata.is_array(s)) {\n\t\t\t\t\tt = $.extend(true, [], s);\n\t\t\t\t} else if ($.isPlainObject(s)) {\n\t\t\t\t\tt = $.extend(true, {}, s);\n\t\t\t\t} else {\n\t\t\t\t\tt = s;\n\t\t\t\t}\n\t\t\t\tif(obj.id === $.jstree.root) {\n\t\t\t\t\treturn this._append_json_data(obj, t, function (status) {\n\t\t\t\t\t\tcallback.call(this, status);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis._data.core.last_error = { 'error' : 'nodata', 'plugin' : 'core', 'id' : 'core_05', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id }) };\n\t\t\t\t\tthis.settings.core.error.call(this, this._data.core.last_error);\n\t\t\t\t\treturn callback.call(this, false);\n\t\t\t\t}\n\t\t\t\t//return callback.call(this, (obj.id === $.jstree.root ? this._append_json_data(obj, t) : false) );\n\t\t\t}\n\t\t\tif(typeof s === 'string') {\n\t\t\t\tif(obj.id === $.jstree.root) {\n\t\t\t\t\treturn this._append_html_data(obj, $($.parseHTML(s)).filter(notTextOrCommentNode), function (status) {\n\t\t\t\t\t\tcallback.call(this, status);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis._data.core.last_error = { 'error' : 'nodata', 'plugin' : 'core', 'id' : 'core_06', 'reason' : 'Could not load node', 'data' : JSON.stringify({ 'id' : obj.id }) };\n\t\t\t\t\tthis.settings.core.error.call(this, this._data.core.last_error);\n\t\t\t\t\treturn callback.call(this, false);\n\t\t\t\t}\n\t\t\t\t//return callback.call(this, (obj.id === $.jstree.root ? this._append_html_data(obj, $(s)) : false) );\n\t\t\t}\n\t\t\treturn callback.call(this, false);\n\t\t},\n\t\t/**\n\t\t * adds a node to the list of nodes to redraw. Used only internally.\n\t\t * @private\n\t\t * @name _node_changed(obj [, callback])\n\t\t * @param {mixed} obj\n\t\t */\n\t\t_node_changed : function (obj) {\n\t\t\tobj = this.get_node(obj);\n if (obj && $.inArray(obj.id, this._model.changed) === -1) {\n\t\t\t\tthis._model.changed.push(obj.id);\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * appends HTML content to the tree. Used internally.\n\t\t * @private\n\t\t * @name _append_html_data(obj, data)\n\t\t * @param {mixed} obj the node to append to\n\t\t * @param {String} data the HTML string to parse and append\n\t\t * @trigger model.jstree, changed.jstree\n\t\t */\n\t\t_append_html_data : function (dom, data, cb) {\n\t\t\tdom = this.get_node(dom);\n\t\t\tdom.children = [];\n\t\t\tdom.children_d = [];\n\t\t\tvar dat = data.is('ul') ? data.children() : data,\n\t\t\t\tpar = dom.id,\n\t\t\t\tchd = [],\n\t\t\t\tdpc = [],\n\t\t\t\tm = this._model.data,\n\t\t\t\tp = m[par],\n\t\t\t\ts = this._data.core.selected.length,\n\t\t\t\ttmp, i, j;\n\t\t\tdat.each(function (i, v) {\n\t\t\t\ttmp = this._parse_model_from_html($(v), par, p.parents.concat());\n\t\t\t\tif(tmp) {\n\t\t\t\t\tchd.push(tmp);\n\t\t\t\t\tdpc.push(tmp);\n\t\t\t\t\tif(m[tmp].children_d.length) {\n\t\t\t\t\t\tdpc = dpc.concat(m[tmp].children_d);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}.bind(this));\n\t\t\tp.children = chd;\n\t\t\tp.children_d = dpc;\n\t\t\tfor(i = 0, j = p.parents.length; i < j; i++) {\n\t\t\t\tm[p.parents[i]].children_d = m[p.parents[i]].children_d.concat(dpc);\n\t\t\t}\n\t\t\t/**\n\t\t\t * triggered when new data is inserted to the tree model\n\t\t\t * @event\n\t\t\t * @name model.jstree\n\t\t\t * @param {Array} nodes an array of node IDs\n\t\t\t * @param {String} parent the parent ID of the nodes\n\t\t\t */\n\t\t\tthis.trigger('model', { \"nodes\" : dpc, 'parent' : par });\n\t\t\tif(par !== $.jstree.root) {\n\t\t\t\tthis._node_changed(par);\n\t\t\t\tthis.redraw();\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.get_container_ul().children('.jstree-initial-node').remove();\n\t\t\t\tthis.redraw(true);\n\t\t\t}\n\t\t\tif(this._data.core.selected.length !== s) {\n\t\t\t\tthis.trigger('changed', { 'action' : 'model', 'selected' : this._data.core.selected });\n\t\t\t}\n\t\t\tcb.call(this, true);\n\t\t},\n\t\t/**\n\t\t * appends JSON content to the tree. Used internally.\n\t\t * @private\n\t\t * @name _append_json_data(obj, data)\n\t\t * @param {mixed} obj the node to append to\n\t\t * @param {String} data the JSON object to parse and append\n\t\t * @param {Boolean} force_processing internal param - do not set\n\t\t * @trigger model.jstree, changed.jstree\n\t\t */\n\t\t_append_json_data : function (dom, data, cb, force_processing) {\n\t\t\tif(this.element === null) { return; }\n\t\t\tdom = this.get_node(dom);\n\t\t\tdom.children = [];\n\t\t\tdom.children_d = [];\n\t\t\t// *%$@!!!\n\t\t\tif(data.d) {\n\t\t\t\tdata = data.d;\n\t\t\t\tif(typeof data === \"string\") {\n\t\t\t\t\tdata = JSON.parse(data);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!$.vakata.is_array(data)) { data = [data]; }\n\t\t\tvar w = null,\n\t\t\t\targs = {\n\t\t\t\t\t'df'\t: this._model.default_state,\n\t\t\t\t\t'dat'\t: data,\n\t\t\t\t\t'par'\t: dom.id,\n\t\t\t\t\t'm'\t\t: this._model.data,\n\t\t\t\t\t't_id'\t: this._id,\n\t\t\t\t\t't_cnt'\t: this._cnt,\n\t\t\t\t\t'sel'\t: this._data.core.selected\n\t\t\t\t},\n\t\t\t\tinst = this,\n\t\t\t\tfunc = function (data, undefined) {\n\t\t\t\t\tif(data.data) { data = data.data; }\n\t\t\t\t\tvar dat = data.dat,\n\t\t\t\t\t\tpar = data.par,\n\t\t\t\t\t\tchd = [],\n\t\t\t\t\t\tdpc = [],\n\t\t\t\t\t\tadd = [],\n\t\t\t\t\t\tdf = data.df,\n\t\t\t\t\t\tt_id = data.t_id,\n\t\t\t\t\t\tt_cnt = data.t_cnt,\n\t\t\t\t\t\tm = data.m,\n\t\t\t\t\t\tp = m[par],\n\t\t\t\t\t\tsel = data.sel,\n\t\t\t\t\t\ttmp, i, j, rslt,\n\t\t\t\t\t\tparse_flat = function (d, p, ps) {\n\t\t\t\t\t\t\tif(!ps) { ps = []; }\n\t\t\t\t\t\t\telse { ps = ps.concat(); }\n\t\t\t\t\t\t\tif(p) { ps.unshift(p); }\n\t\t\t\t\t\t\tvar tid = d.id.toString(),\n\t\t\t\t\t\t\t\ti, j, c, e,\n\t\t\t\t\t\t\t\ttmp = {\n\t\t\t\t\t\t\t\t\tid\t\t\t: tid,\n\t\t\t\t\t\t\t\t\ttext\t\t: d.text || '',\n\t\t\t\t\t\t\t\t\ticon\t\t: d.icon !== undefined ? d.icon : true,\n\t\t\t\t\t\t\t\t\tparent\t\t: p,\n\t\t\t\t\t\t\t\t\tparents\t\t: ps,\n\t\t\t\t\t\t\t\t\tchildren\t: d.children || [],\n\t\t\t\t\t\t\t\t\tchildren_d\t: d.children_d || [],\n\t\t\t\t\t\t\t\t\tdata\t\t: d.data,\n\t\t\t\t\t\t\t\t\tstate\t\t: { },\n\t\t\t\t\t\t\t\t\tli_attr\t\t: { id : false },\n\t\t\t\t\t\t\t\t\ta_attr\t\t: { href : '#' },\n\t\t\t\t\t\t\t\t\toriginal\t: false\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tfor(i in df) {\n\t\t\t\t\t\t\t\tif(df.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\ttmp.state[i] = df[i];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && d.data && d.data.jstree && d.data.jstree.icon) {\n\t\t\t\t\t\t\t\ttmp.icon = d.data.jstree.icon;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(tmp.icon === undefined || tmp.icon === null || tmp.icon === \"\") {\n\t\t\t\t\t\t\t\ttmp.icon = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && d.data) {\n\t\t\t\t\t\t\t\ttmp.data = d.data;\n\t\t\t\t\t\t\t\tif(d.data.jstree) {\n\t\t\t\t\t\t\t\t\tfor(i in d.data.jstree) {\n\t\t\t\t\t\t\t\t\t\tif(d.data.jstree.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\t\t\ttmp.state[i] = d.data.jstree[i];\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && typeof d.state === 'object') {\n\t\t\t\t\t\t\t\tfor (i in d.state) {\n\t\t\t\t\t\t\t\t\tif(d.state.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\t\ttmp.state[i] = d.state[i];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && typeof d.li_attr === 'object') {\n\t\t\t\t\t\t\t\tfor (i in d.li_attr) {\n\t\t\t\t\t\t\t\t\tif(d.li_attr.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\t\ttmp.li_attr[i] = d.li_attr[i];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(!tmp.li_attr.id) {\n\t\t\t\t\t\t\t\ttmp.li_attr.id = tid;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && typeof d.a_attr === 'object') {\n\t\t\t\t\t\t\t\tfor (i in d.a_attr) {\n\t\t\t\t\t\t\t\t\tif(d.a_attr.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\t\ttmp.a_attr[i] = d.a_attr[i];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && d.children && d.children === true) {\n\t\t\t\t\t\t\t\ttmp.state.loaded = false;\n\t\t\t\t\t\t\t\ttmp.children = [];\n\t\t\t\t\t\t\t\ttmp.children_d = [];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tm[tmp.id] = tmp;\n\t\t\t\t\t\t\tfor(i = 0, j = tmp.children.length; i < j; i++) {\n\t\t\t\t\t\t\t\tc = parse_flat(m[tmp.children[i]], tmp.id, ps);\n\t\t\t\t\t\t\t\te = m[c];\n\t\t\t\t\t\t\t\ttmp.children_d.push(c);\n\t\t\t\t\t\t\t\tif(e.children_d.length) {\n\t\t\t\t\t\t\t\t\ttmp.children_d = tmp.children_d.concat(e.children_d);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdelete d.data;\n\t\t\t\t\t\t\tdelete d.children;\n\t\t\t\t\t\t\tm[tmp.id].original = d;\n\t\t\t\t\t\t\tif(tmp.state.selected) {\n\t\t\t\t\t\t\t\tadd.push(tmp.id);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn tmp.id;\n\t\t\t\t\t\t},\n\t\t\t\t\t\tparse_nest = function (d, p, ps) {\n\t\t\t\t\t\t\tif(!ps) { ps = []; }\n\t\t\t\t\t\t\telse { ps = ps.concat(); }\n\t\t\t\t\t\t\tif(p) { ps.unshift(p); }\n\t\t\t\t\t\t\tvar tid = false, i, j, c, e, tmp;\n\t\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\t\ttid = 'j' + t_id + '_' + (++t_cnt);\n\t\t\t\t\t\t\t} while(m[tid]);\n\n\t\t\t\t\t\t\ttmp = {\n\t\t\t\t\t\t\t\tid\t\t\t: false,\n\t\t\t\t\t\t\t\ttext\t\t: typeof d === 'string' ? d : '',\n\t\t\t\t\t\t\t\ticon\t\t: typeof d === 'object' && d.icon !== undefined ? d.icon : true,\n\t\t\t\t\t\t\t\tparent\t\t: p,\n\t\t\t\t\t\t\t\tparents\t\t: ps,\n\t\t\t\t\t\t\t\tchildren\t: [],\n\t\t\t\t\t\t\t\tchildren_d\t: [],\n\t\t\t\t\t\t\t\tdata\t\t: null,\n\t\t\t\t\t\t\t\tstate\t\t: { },\n\t\t\t\t\t\t\t\tli_attr\t\t: { id : false },\n\t\t\t\t\t\t\t\ta_attr\t\t: { href : '#' },\n\t\t\t\t\t\t\t\toriginal\t: false\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\tfor(i in df) {\n\t\t\t\t\t\t\t\tif(df.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\ttmp.state[i] = df[i];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && d.id) { tmp.id = d.id.toString(); }\n\t\t\t\t\t\t\tif(d && d.text) { tmp.text = d.text; }\n\t\t\t\t\t\t\tif(d && d.data && d.data.jstree && d.data.jstree.icon) {\n\t\t\t\t\t\t\t\ttmp.icon = d.data.jstree.icon;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(tmp.icon === undefined || tmp.icon === null || tmp.icon === \"\") {\n\t\t\t\t\t\t\t\ttmp.icon = true;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && d.data) {\n\t\t\t\t\t\t\t\ttmp.data = d.data;\n\t\t\t\t\t\t\t\tif(d.data.jstree) {\n\t\t\t\t\t\t\t\t\tfor(i in d.data.jstree) {\n\t\t\t\t\t\t\t\t\t\tif(d.data.jstree.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\t\t\ttmp.state[i] = d.data.jstree[i];\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && typeof d.state === 'object') {\n\t\t\t\t\t\t\t\tfor (i in d.state) {\n\t\t\t\t\t\t\t\t\tif(d.state.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\t\ttmp.state[i] = d.state[i];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && typeof d.li_attr === 'object') {\n\t\t\t\t\t\t\t\tfor (i in d.li_attr) {\n\t\t\t\t\t\t\t\t\tif(d.li_attr.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\t\ttmp.li_attr[i] = d.li_attr[i];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(tmp.li_attr.id && !tmp.id) {\n\t\t\t\t\t\t\t\ttmp.id = tmp.li_attr.id.toString();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(!tmp.id) {\n\t\t\t\t\t\t\t\ttmp.id = tid;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(!tmp.li_attr.id) {\n\t\t\t\t\t\t\t\ttmp.li_attr.id = tmp.id;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && typeof d.a_attr === 'object') {\n\t\t\t\t\t\t\t\tfor (i in d.a_attr) {\n\t\t\t\t\t\t\t\t\tif(d.a_attr.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\t\ttmp.a_attr[i] = d.a_attr[i];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && d.children && d.children.length) {\n\t\t\t\t\t\t\t\tfor(i = 0, j = d.children.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\tc = parse_nest(d.children[i], tmp.id, ps);\n\t\t\t\t\t\t\t\t\te = m[c];\n\t\t\t\t\t\t\t\t\ttmp.children.push(c);\n\t\t\t\t\t\t\t\t\tif(e.children_d.length) {\n\t\t\t\t\t\t\t\t\t\ttmp.children_d = tmp.children_d.concat(e.children_d);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\ttmp.children_d = tmp.children_d.concat(tmp.children);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(d && d.children && d.children === true) {\n\t\t\t\t\t\t\t\ttmp.state.loaded = false;\n\t\t\t\t\t\t\t\ttmp.children = [];\n\t\t\t\t\t\t\t\ttmp.children_d = [];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tdelete d.data;\n\t\t\t\t\t\t\tdelete d.children;\n\t\t\t\t\t\t\ttmp.original = d;\n\t\t\t\t\t\t\tm[tmp.id] = tmp;\n\t\t\t\t\t\t\tif(tmp.state.selected) {\n\t\t\t\t\t\t\t\tadd.push(tmp.id);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn tmp.id;\n\t\t\t\t\t\t};\n\n\t\t\t\t\tif(dat.length && dat[0].id !== undefined && dat[0].parent !== undefined) {\n\t\t\t\t\t\t// Flat JSON support (for easy import from DB):\n\t\t\t\t\t\t// 1) convert to object (foreach)\n\t\t\t\t\t\tfor(i = 0, j = dat.length; i < j; i++) {\n\t\t\t\t\t\t\tif(!dat[i].children) {\n\t\t\t\t\t\t\t\tdat[i].children = [];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(!dat[i].state) {\n\t\t\t\t\t\t\t\tdat[i].state = {};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tm[dat[i].id.toString()] = dat[i];\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// 2) populate children (foreach)\n\t\t\t\t\t\tfor(i = 0, j = dat.length; i < j; i++) {\n\t\t\t\t\t\t\tif (!m[dat[i].parent.toString()]) {\n\t\t\t\t\t\t\t\tif (typeof inst !== \"undefined\") {\n\t\t\t\t\t\t\t\t\tinst._data.core.last_error = { 'error' : 'parse', 'plugin' : 'core', 'id' : 'core_07', 'reason' : 'Node with invalid parent', 'data' : JSON.stringify({ 'id' : dat[i].id.toString(), 'parent' : dat[i].parent.toString() }) };\n\t\t\t\t\t\t\t\t\tinst.settings.core.error.call(inst, inst._data.core.last_error);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tm[dat[i].parent.toString()].children.push(dat[i].id.toString());\n\t\t\t\t\t\t\t// populate parent.children_d\n\t\t\t\t\t\t\tp.children_d.push(dat[i].id.toString());\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// 3) normalize && populate parents and children_d with recursion\n\t\t\t\t\t\tfor(i = 0, j = p.children.length; i < j; i++) {\n\t\t\t\t\t\t\ttmp = parse_flat(m[p.children[i]], par, p.parents.concat());\n\t\t\t\t\t\t\tdpc.push(tmp);\n\t\t\t\t\t\t\tif(m[tmp].children_d.length) {\n\t\t\t\t\t\t\t\tdpc = dpc.concat(m[tmp].children_d);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tfor(i = 0, j = p.parents.length; i < j; i++) {\n\t\t\t\t\t\t\tm[p.parents[i]].children_d = m[p.parents[i]].children_d.concat(dpc);\n\t\t\t\t\t\t}\n\t\t\t\t\t\t// ?) three_state selection - p.state.selected && t - (if three_state foreach(dat => ch) -> foreach(parents) if(parent.selected) child.selected = true;\n\t\t\t\t\t\trslt = {\n\t\t\t\t\t\t\t'cnt' : t_cnt,\n\t\t\t\t\t\t\t'mod' : m,\n\t\t\t\t\t\t\t'sel' : sel,\n\t\t\t\t\t\t\t'par' : par,\n\t\t\t\t\t\t\t'dpc' : dpc,\n\t\t\t\t\t\t\t'add' : add\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfor(i = 0, j = dat.length; i < j; i++) {\n\t\t\t\t\t\t\ttmp = parse_nest(dat[i], par, p.parents.concat());\n\t\t\t\t\t\t\tif(tmp) {\n\t\t\t\t\t\t\t\tchd.push(tmp);\n\t\t\t\t\t\t\t\tdpc.push(tmp);\n\t\t\t\t\t\t\t\tif(m[tmp].children_d.length) {\n\t\t\t\t\t\t\t\t\tdpc = dpc.concat(m[tmp].children_d);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tp.children = chd;\n\t\t\t\t\t\tp.children_d = dpc;\n\t\t\t\t\t\tfor(i = 0, j = p.parents.length; i < j; i++) {\n\t\t\t\t\t\t\tm[p.parents[i]].children_d = m[p.parents[i]].children_d.concat(dpc);\n\t\t\t\t\t\t}\n\t\t\t\t\t\trslt = {\n\t\t\t\t\t\t\t'cnt' : t_cnt,\n\t\t\t\t\t\t\t'mod' : m,\n\t\t\t\t\t\t\t'sel' : sel,\n\t\t\t\t\t\t\t'par' : par,\n\t\t\t\t\t\t\t'dpc' : dpc,\n\t\t\t\t\t\t\t'add' : add\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tif(typeof window === 'undefined' || typeof window.document === 'undefined') {\n\t\t\t\t\t\tpostMessage(rslt);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\treturn rslt;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\trslt = function (rslt, worker) {\n\t\t\t\t\tif(this.element === null) { return; }\n\t\t\t\t\tthis._cnt = rslt.cnt;\n\t\t\t\t\tvar i, m = this._model.data;\n\t\t\t\t\tfor (i in m) {\n\t\t\t\t\t\tif (m.hasOwnProperty(i) && m[i].state && m[i].state.loading && rslt.mod[i]) {\n\t\t\t\t\t\t\trslt.mod[i].state.loading = true;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis._model.data = rslt.mod; // breaks the reference in load_node - careful\n\n\t\t\t\t\tif(worker) {\n\t\t\t\t\t\tvar j, a = rslt.add, r = rslt.sel, s = this._data.core.selected.slice();\n\t\t\t\t\t\tm = this._model.data;\n\t\t\t\t\t\t// if selection was changed while calculating in worker\n\t\t\t\t\t\tif(r.length !== s.length || $.vakata.array_unique(r.concat(s)).length !== r.length) {\n\t\t\t\t\t\t\t// deselect nodes that are no longer selected\n\t\t\t\t\t\t\tfor(i = 0, j = r.length; i < j; i++) {\n\t\t\t\t\t\t\t\tif($.inArray(r[i], a) === -1 && $.inArray(r[i], s) === -1) {\n\t\t\t\t\t\t\t\t\tm[r[i]].state.selected = false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t// select nodes that were selected in the mean time\n\t\t\t\t\t\t\tfor(i = 0, j = s.length; i < j; i++) {\n\t\t\t\t\t\t\t\tif($.inArray(s[i], r) === -1) {\n\t\t\t\t\t\t\t\t\tm[s[i]].state.selected = true;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(rslt.add.length) {\n\t\t\t\t\t\tthis._data.core.selected = this._data.core.selected.concat(rslt.add);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.trigger('model', { \"nodes\" : rslt.dpc, 'parent' : rslt.par });\n\n\t\t\t\t\tif(rslt.par !== $.jstree.root) {\n\t\t\t\t\t\tthis._node_changed(rslt.par);\n\t\t\t\t\t\tthis.redraw();\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// this.get_container_ul().children('.jstree-initial-node').remove();\n\t\t\t\t\t\tthis.redraw(true);\n\t\t\t\t\t}\n\t\t\t\t\tif(rslt.add.length) {\n\t\t\t\t\t\tthis.trigger('changed', { 'action' : 'model', 'selected' : this._data.core.selected });\n\t\t\t\t\t}\n\n\t\t\t\t\t// If no worker, try to mimic worker behavioour, by invoking cb asynchronously\n\t\t\t\t\tif (!worker && setImmediate) {\n\t\t\t\t\t\tsetImmediate(function(){\n\t\t\t\t\t\t\tcb.call(inst, true);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tcb.call(inst, true);\n\t\t\t\t\t}\n\t\t\t\t};\n\t\t\tif(this.settings.core.worker && window.Blob && window.URL && window.Worker) {\n\t\t\t\ttry {\n\t\t\t\t\tif(this._wrk === null) {\n\t\t\t\t\t\tthis._wrk = window.URL.createObjectURL(\n\t\t\t\t\t\t\tnew window.Blob(\n\t\t\t\t\t\t\t\t['self.onmessage = ' + func.toString()],\n\t\t\t\t\t\t\t\t{type:\"text/javascript\"}\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif(!this._data.core.working || force_processing) {\n\t\t\t\t\t\tthis._data.core.working = true;\n\t\t\t\t\t\tw = new window.Worker(this._wrk);\n\t\t\t\t\t\tw.onmessage = function (e) {\n\t\t\t\t\t\t\trslt.call(this, e.data, true);\n\t\t\t\t\t\t\ttry { w.terminate(); w = null; } catch(ignore) { }\n\t\t\t\t\t\t\tif(this._data.core.worker_queue.length) {\n\t\t\t\t\t\t\t\tthis._append_json_data.apply(this, this._data.core.worker_queue.shift());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tthis._data.core.working = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}.bind(this);\n\t\t\t\t\t\tif(!args.par) {\n\t\t\t\t\t\t\tif(this._data.core.worker_queue.length) {\n\t\t\t\t\t\t\t\tthis._append_json_data.apply(this, this._data.core.worker_queue.shift());\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tthis._data.core.working = false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tw.postMessage(args);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis._data.core.worker_queue.push([dom, data, cb, true]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tcatch(e) {\n\t\t\t\t\trslt.call(this, func(args), false);\n\t\t\t\t\tif(this._data.core.worker_queue.length) {\n\t\t\t\t\t\tthis._append_json_data.apply(this, this._data.core.worker_queue.shift());\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis._data.core.working = false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\trslt.call(this, func(args), false);\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * parses a node from a jQuery object and appends them to the in memory tree model. Used internally.\n\t\t * @private\n\t\t * @name _parse_model_from_html(d [, p, ps])\n\t\t * @param {jQuery} d the jQuery object to parse\n\t\t * @param {String} p the parent ID\n\t\t * @param {Array} ps list of all parents\n\t\t * @return {String} the ID of the object added to the model\n\t\t */\n\t\t_parse_model_from_html : function (d, p, ps) {\n\t\t\tif(!ps) { ps = []; }\n\t\t\telse { ps = [].concat(ps); }\n\t\t\tif(p) { ps.unshift(p); }\n\t\t\tvar c, e, m = this._model.data,\n\t\t\t\tdata = {\n\t\t\t\t\tid\t\t\t: false,\n\t\t\t\t\ttext\t\t: false,\n\t\t\t\t\ticon\t\t: true,\n\t\t\t\t\tparent\t\t: p,\n\t\t\t\t\tparents\t\t: ps,\n\t\t\t\t\tchildren\t: [],\n\t\t\t\t\tchildren_d\t: [],\n\t\t\t\t\tdata\t\t: null,\n\t\t\t\t\tstate\t\t: { },\n\t\t\t\t\tli_attr\t\t: { id : false },\n\t\t\t\t\ta_attr\t\t: { href : '#' },\n\t\t\t\t\toriginal\t: false\n\t\t\t\t}, i, tmp, tid;\n\t\t\tfor(i in this._model.default_state) {\n\t\t\t\tif(this._model.default_state.hasOwnProperty(i)) {\n\t\t\t\t\tdata.state[i] = this._model.default_state[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\ttmp = $.vakata.attributes(d, true);\n\t\t\t$.each(tmp, function (i, v) {\n\t\t\t\tv = $.vakata.trim(v);\n\t\t\t\tif(!v.length) { return true; }\n\t\t\t\tdata.li_attr[i] = v;\n\t\t\t\tif(i === 'id') {\n\t\t\t\t\tdata.id = v.toString();\n\t\t\t\t}\n\t\t\t});\n\t\t\ttmp = d.children('a').first();\n\t\t\tif(tmp.length) {\n\t\t\t\ttmp = $.vakata.attributes(tmp, true);\n\t\t\t\t$.each(tmp, function (i, v) {\n\t\t\t\t\tv = $.vakata.trim(v);\n\t\t\t\t\tif(v.length) {\n\t\t\t\t\t\tdata.a_attr[i] = v;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t}\n\t\t\ttmp = d.children(\"a\").first().length ? d.children(\"a\").first().clone() : d.clone();\n\t\t\ttmp.children(\"ins, i, ul\").remove();\n\t\t\ttmp = tmp.html();\n\t\t\ttmp = $('<div></div>').html(tmp);\n\t\t\tdata.text = this.settings.core.force_text ? tmp.text() : tmp.html();\n\t\t\ttmp = d.data();\n\t\t\tdata.data = tmp ? $.extend(true, {}, tmp) : null;\n\t\t\tdata.state.opened = d.hasClass('jstree-open');\n\t\t\tdata.state.selected = d.children('a').hasClass('jstree-clicked');\n\t\t\tdata.state.disabled = d.children('a').hasClass('jstree-disabled');\n\t\t\tif(data.data && data.data.jstree) {\n\t\t\t\tfor(i in data.data.jstree) {\n\t\t\t\t\tif(data.data.jstree.hasOwnProperty(i)) {\n\t\t\t\t\t\tdata.state[i] = data.data.jstree[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\ttmp = d.children(\"a\").children(\".jstree-themeicon\");\n\t\t\tif(tmp.length) {\n\t\t\t\tdata.icon = tmp.hasClass('jstree-themeicon-hidden') ? false : tmp.attr('rel');\n\t\t\t}\n\t\t\tif(data.state.icon !== undefined) {\n\t\t\t\tdata.icon = data.state.icon;\n\t\t\t}\n\t\t\tif(data.icon === undefined || data.icon === null || data.icon === \"\") {\n\t\t\t\tdata.icon = true;\n\t\t\t}\n\t\t\ttmp = d.children(\"ul\").children(\"li\");\n\t\t\tdo {\n\t\t\t\ttid = 'j' + this._id + '_' + (++this._cnt);\n\t\t\t} while(m[tid]);\n\t\t\tdata.id = data.li_attr.id ? data.li_attr.id.toString() : tid;\n\t\t\tif(tmp.length) {\n\t\t\t\ttmp.each(function (i, v) {\n\t\t\t\t\tc = this._parse_model_from_html($(v), data.id, ps);\n\t\t\t\t\te = this._model.data[c];\n\t\t\t\t\tdata.children.push(c);\n\t\t\t\t\tif(e.children_d.length) {\n\t\t\t\t\t\tdata.children_d = data.children_d.concat(e.children_d);\n\t\t\t\t\t}\n\t\t\t\t}.bind(this));\n\t\t\t\tdata.children_d = data.children_d.concat(data.children);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif(d.hasClass('jstree-closed')) {\n\t\t\t\t\tdata.state.loaded = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(data.li_attr['class']) {\n\t\t\t\tdata.li_attr['class'] = data.li_attr['class'].replace('jstree-closed','').replace('jstree-open','');\n\t\t\t}\n\t\t\tif(data.a_attr['class']) {\n\t\t\t\tdata.a_attr['class'] = data.a_attr['class'].replace('jstree-clicked','').replace('jstree-disabled','');\n\t\t\t}\n\t\t\tm[data.id] = data;\n\t\t\tif(data.state.selected) {\n\t\t\t\tthis._data.core.selected.push(data.id);\n\t\t\t}\n\t\t\treturn data.id;\n\t\t},\n\t\t/**\n\t\t * parses a node from a JSON object (used when dealing with flat data, which has no nesting of children, but has id and parent properties) and appends it to the in memory tree model. Used internally.\n\t\t * @private\n\t\t * @name _parse_model_from_flat_json(d [, p, ps])\n\t\t * @param {Object} d the JSON object to parse\n\t\t * @param {String} p the parent ID\n\t\t * @param {Array} ps list of all parents\n\t\t * @return {String} the ID of the object added to the model\n\t\t */\n\t\t_parse_model_from_flat_json : function (d, p, ps) {\n\t\t\tif(!ps) { ps = []; }\n\t\t\telse { ps = ps.concat(); }\n\t\t\tif(p) { ps.unshift(p); }\n\t\t\tvar tid = d.id.toString(),\n\t\t\t\tm = this._model.data,\n\t\t\t\tdf = this._model.default_state,\n\t\t\t\ti, j, c, e,\n\t\t\t\ttmp = {\n\t\t\t\t\tid\t\t\t: tid,\n\t\t\t\t\ttext\t\t: d.text || '',\n\t\t\t\t\ticon\t\t: d.icon !== undefined ? d.icon : true,\n\t\t\t\t\tparent\t\t: p,\n\t\t\t\t\tparents\t\t: ps,\n\t\t\t\t\tchildren\t: d.children || [],\n\t\t\t\t\tchildren_d\t: d.children_d || [],\n\t\t\t\t\tdata\t\t: d.data,\n\t\t\t\t\tstate\t\t: { },\n\t\t\t\t\tli_attr\t\t: { id : false },\n\t\t\t\t\ta_attr\t\t: { href : '#' },\n\t\t\t\t\toriginal\t: false\n\t\t\t\t};\n\t\t\tfor(i in df) {\n\t\t\t\tif(df.hasOwnProperty(i)) {\n\t\t\t\t\ttmp.state[i] = df[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(d && d.data && d.data.jstree && d.data.jstree.icon) {\n\t\t\t\ttmp.icon = d.data.jstree.icon;\n\t\t\t}\n\t\t\tif(tmp.icon === undefined || tmp.icon === null || tmp.icon === \"\") {\n\t\t\t\ttmp.icon = true;\n\t\t\t}\n\t\t\tif(d && d.data) {\n\t\t\t\ttmp.data = d.data;\n\t\t\t\tif(d.data.jstree) {\n\t\t\t\t\tfor(i in d.data.jstree) {\n\t\t\t\t\t\tif(d.data.jstree.hasOwnProperty(i)) {\n\t\t\t\t\t\t\ttmp.state[i] = d.data.jstree[i];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(d && typeof d.state === 'object') {\n\t\t\t\tfor (i in d.state) {\n\t\t\t\t\tif(d.state.hasOwnProperty(i)) {\n\t\t\t\t\t\ttmp.state[i] = d.state[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(d && typeof d.li_attr === 'object') {\n\t\t\t\tfor (i in d.li_attr) {\n\t\t\t\t\tif(d.li_attr.hasOwnProperty(i)) {\n\t\t\t\t\t\ttmp.li_attr[i] = d.li_attr[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!tmp.li_attr.id) {\n\t\t\t\ttmp.li_attr.id = tid;\n\t\t\t}\n\t\t\tif(d && typeof d.a_attr === 'object') {\n\t\t\t\tfor (i in d.a_attr) {\n\t\t\t\t\tif(d.a_attr.hasOwnProperty(i)) {\n\t\t\t\t\t\ttmp.a_attr[i] = d.a_attr[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(d && d.children && d.children === true) {\n\t\t\t\ttmp.state.loaded = false;\n\t\t\t\ttmp.children = [];\n\t\t\t\ttmp.children_d = [];\n\t\t\t}\n\t\t\tm[tmp.id] = tmp;\n\t\t\tfor(i = 0, j = tmp.children.length; i < j; i++) {\n\t\t\t\tc = this._parse_model_from_flat_json(m[tmp.children[i]], tmp.id, ps);\n\t\t\t\te = m[c];\n\t\t\t\ttmp.children_d.push(c);\n\t\t\t\tif(e.children_d.length) {\n\t\t\t\t\ttmp.children_d = tmp.children_d.concat(e.children_d);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdelete d.data;\n\t\t\tdelete d.children;\n\t\t\tm[tmp.id].original = d;\n\t\t\tif(tmp.state.selected) {\n\t\t\t\tthis._data.core.selected.push(tmp.id);\n\t\t\t}\n\t\t\treturn tmp.id;\n\t\t},\n\t\t/**\n\t\t * parses a node from a JSON object and appends it to the in memory tree model. Used internally.\n\t\t * @private\n\t\t * @name _parse_model_from_json(d [, p, ps])\n\t\t * @param {Object} d the JSON object to parse\n\t\t * @param {String} p the parent ID\n\t\t * @param {Array} ps list of all parents\n\t\t * @return {String} the ID of the object added to the model\n\t\t */\n\t\t_parse_model_from_json : function (d, p, ps) {\n\t\t\tif(!ps) { ps = []; }\n\t\t\telse { ps = ps.concat(); }\n\t\t\tif(p) { ps.unshift(p); }\n\t\t\tvar tid = false, i, j, c, e, m = this._model.data, df = this._model.default_state, tmp;\n\t\t\tdo {\n\t\t\t\ttid = 'j' + this._id + '_' + (++this._cnt);\n\t\t\t} while(m[tid]);\n\n\t\t\ttmp = {\n\t\t\t\tid\t\t\t: false,\n\t\t\t\ttext\t\t: typeof d === 'string' ? d : '',\n\t\t\t\ticon\t\t: typeof d === 'object' && d.icon !== undefined ? d.icon : true,\n\t\t\t\tparent\t\t: p,\n\t\t\t\tparents\t\t: ps,\n\t\t\t\tchildren\t: [],\n\t\t\t\tchildren_d\t: [],\n\t\t\t\tdata\t\t: null,\n\t\t\t\tstate\t\t: { },\n\t\t\t\tli_attr\t\t: { id : false },\n\t\t\t\ta_attr\t\t: { href : '#' },\n\t\t\t\toriginal\t: false\n\t\t\t};\n\t\t\tfor(i in df) {\n\t\t\t\tif(df.hasOwnProperty(i)) {\n\t\t\t\t\ttmp.state[i] = df[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(d && d.id) { tmp.id = d.id.toString(); }\n\t\t\tif(d && d.text) { tmp.text = d.text; }\n\t\t\tif(d && d.data && d.data.jstree && d.data.jstree.icon) {\n\t\t\t\ttmp.icon = d.data.jstree.icon;\n\t\t\t}\n\t\t\tif(tmp.icon === undefined || tmp.icon === null || tmp.icon === \"\") {\n\t\t\t\ttmp.icon = true;\n\t\t\t}\n\t\t\tif(d && d.data) {\n\t\t\t\ttmp.data = d.data;\n\t\t\t\tif(d.data.jstree) {\n\t\t\t\t\tfor(i in d.data.jstree) {\n\t\t\t\t\t\tif(d.data.jstree.hasOwnProperty(i)) {\n\t\t\t\t\t\t\ttmp.state[i] = d.data.jstree[i];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(d && typeof d.state === 'object') {\n\t\t\t\tfor (i in d.state) {\n\t\t\t\t\tif(d.state.hasOwnProperty(i)) {\n\t\t\t\t\t\ttmp.state[i] = d.state[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(d && typeof d.li_attr === 'object') {\n\t\t\t\tfor (i in d.li_attr) {\n\t\t\t\t\tif(d.li_attr.hasOwnProperty(i)) {\n\t\t\t\t\t\ttmp.li_attr[i] = d.li_attr[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(tmp.li_attr.id && !tmp.id) {\n\t\t\t\ttmp.id = tmp.li_attr.id.toString();\n\t\t\t}\n\t\t\tif(!tmp.id) {\n\t\t\t\ttmp.id = tid;\n\t\t\t}\n\t\t\tif(!tmp.li_attr.id) {\n\t\t\t\ttmp.li_attr.id = tmp.id;\n\t\t\t}\n\t\t\tif(d && typeof d.a_attr === 'object') {\n\t\t\t\tfor (i in d.a_attr) {\n\t\t\t\t\tif(d.a_attr.hasOwnProperty(i)) {\n\t\t\t\t\t\ttmp.a_attr[i] = d.a_attr[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(d && d.children && d.children.length) {\n\t\t\t\tfor(i = 0, j = d.children.length; i < j; i++) {\n\t\t\t\t\tc = this._parse_model_from_json(d.children[i], tmp.id, ps);\n\t\t\t\t\te = m[c];\n\t\t\t\t\ttmp.children.push(c);\n\t\t\t\t\tif(e.children_d.length) {\n\t\t\t\t\t\ttmp.children_d = tmp.children_d.concat(e.children_d);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ttmp.children_d = tmp.children.concat(tmp.children_d);\n\t\t\t}\n\t\t\tif(d && d.children && d.children === true) {\n\t\t\t\ttmp.state.loaded = false;\n\t\t\t\ttmp.children = [];\n\t\t\t\ttmp.children_d = [];\n\t\t\t}\n\t\t\tdelete d.data;\n\t\t\tdelete d.children;\n\t\t\ttmp.original = d;\n\t\t\tm[tmp.id] = tmp;\n\t\t\tif(tmp.state.selected) {\n\t\t\t\tthis._data.core.selected.push(tmp.id);\n\t\t\t}\n\t\t\treturn tmp.id;\n\t\t},\n\t\t/**\n\t\t * redraws all nodes that need to be redrawn. Used internally.\n\t\t * @private\n\t\t * @name _redraw()\n\t\t * @trigger redraw.jstree\n\t\t */\n\t\t_redraw : function () {\n\t\t\tvar nodes = this._model.force_full_redraw ? this._model.data[$.jstree.root].children.concat([]) : this._model.changed.concat([]),\n\t\t\t\tf = document.createElement('UL'), tmp, i, j, fe = this._data.core.focused;\n\t\t\tfor(i = 0, j = nodes.length; i < j; i++) {\n\t\t\t\ttmp = this.redraw_node(nodes[i], true, this._model.force_full_redraw);\n\t\t\t\tif(tmp && this._model.force_full_redraw) {\n\t\t\t\t\tf.appendChild(tmp);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(this._model.force_full_redraw) {\n\t\t\t\tf.className = this.get_container_ul()[0].className;\n\t\t\t\tf.setAttribute('role','group');\n\t\t\t\tthis.element.empty().append(f);\n\t\t\t\t//this.get_container_ul()[0].appendChild(f);\n\t\t\t}\n\t\t\tif(fe !== null && this.settings.core.restore_focus) {\n\t\t\t\ttmp = this.get_node(fe, true);\n\t\t\t\tif(tmp && tmp.length && tmp.children('.jstree-anchor')[0] !== document.activeElement) {\n\t\t\t\t\ttmp.children('.jstree-anchor').trigger('focus');\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis._data.core.focused = null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._model.force_full_redraw = false;\n\t\t\tthis._model.changed = [];\n\t\t\t/**\n\t\t\t * triggered after nodes are redrawn\n\t\t\t * @event\n\t\t\t * @name redraw.jstree\n\t\t\t * @param {array} nodes the redrawn nodes\n\t\t\t */\n\t\t\tthis.trigger('redraw', { \"nodes\" : nodes });\n\t\t},\n\t\t/**\n\t\t * redraws all nodes that need to be redrawn or optionally - the whole tree\n\t\t * @name redraw([full])\n\t\t * @param {Boolean} full if set to `true` all nodes are redrawn.\n\t\t */\n\t\tredraw : function (full) {\n\t\t\tif(full) {\n\t\t\t\tthis._model.force_full_redraw = true;\n\t\t\t}\n\t\t\t//if(this._model.redraw_timeout) {\n\t\t\t//\tclearTimeout(this._model.redraw_timeout);\n\t\t\t//}\n\t\t\t//this._model.redraw_timeout = setTimeout($.proxy(this._redraw, this),0);\n\t\t\tthis._redraw();\n\t\t},\n\t\t/**\n\t\t * redraws a single node's children. Used internally.\n\t\t * @private\n\t\t * @name draw_children(node)\n\t\t * @param {mixed} node the node whose children will be redrawn\n\t\t */\n\t\tdraw_children : function (node) {\n\t\t\tvar obj = this.get_node(node),\n\t\t\t\ti = false,\n\t\t\t\tj = false,\n\t\t\t\tk = false,\n\t\t\t\td = document;\n\t\t\tif(!obj) { return false; }\n\t\t\tif(obj.id === $.jstree.root) { return this.redraw(true); }\n\t\t\tnode = this.get_node(node, true);\n\t\t\tif(!node || !node.length) { return false; } // TODO: quick toggle\n\n\t\t\tnode.children('.jstree-children').remove();\n\t\t\tnode = node[0];\n\t\t\tif(obj.children.length && obj.state.loaded) {\n\t\t\t\tk = d.createElement('UL');\n\t\t\t\tk.setAttribute('role', 'group');\n\t\t\t\tk.className = 'jstree-children';\n\t\t\t\tfor(i = 0, j = obj.children.length; i < j; i++) {\n\t\t\t\t\tk.appendChild(this.redraw_node(obj.children[i], true, true));\n\t\t\t\t}\n\t\t\t\tnode.appendChild(k);\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * redraws a single node. Used internally.\n\t\t * @private\n\t\t * @name redraw_node(node, deep, is_callback, force_render)\n\t\t * @param {mixed} node the node to redraw\n\t\t * @param {Boolean} deep should child nodes be redrawn too\n\t\t * @param {Boolean} is_callback is this a recursion call\n\t\t * @param {Boolean} force_render should children of closed parents be drawn anyway\n\t\t */\n\t\tredraw_node : function (node, deep, is_callback, force_render) {\n\t\t\tvar obj = this.get_node(node),\n\t\t\t\tpar = false,\n\t\t\t\tind = false,\n\t\t\t\told = false,\n\t\t\t\ti = false,\n\t\t\t\tj = false,\n\t\t\t\tk = false,\n\t\t\t\tc = '',\n\t\t\t\td = document,\n\t\t\t\tm = this._model.data,\n\t\t\t\tf = false,\n\t\t\t\ts = false,\n\t\t\t\ttmp = null,\n\t\t\t\tt = 0,\n\t\t\t\tl = 0,\n\t\t\t\thas_children = false,\n\t\t\t\tlast_sibling = false;\n\t\t\tif(!obj) { return false; }\n\t\t\tif(obj.id === $.jstree.root) { return this.redraw(true); }\n\t\t\tdeep = deep || obj.children.length === 0;\n\t\t\tnode = !document.querySelector ? document.getElementById(obj.id) : this.element[0].querySelector('#' + (\"0123456789\".indexOf(obj.id[0]) !== -1 ? '\\\\3' + obj.id[0] + ' ' + obj.id.substr(1).replace($.jstree.idregex,'\\\\$&') : obj.id.replace($.jstree.idregex,'\\\\$&')) ); //, this.element);\n\t\t\tif(!node) {\n\t\t\t\tdeep = true;\n\t\t\t\t//node = d.createElement('LI');\n\t\t\t\tif(!is_callback) {\n\t\t\t\t\tpar = obj.parent !== $.jstree.root ? $('#' + obj.parent.replace($.jstree.idregex,'\\\\$&'), this.element)[0] : null;\n\t\t\t\t\tif(par !== null && (!par || !m[obj.parent].state.opened)) {\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tind = $.inArray(obj.id, par === null ? m[$.jstree.root].children : m[obj.parent].children);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnode = $(node);\n\t\t\t\tif(!is_callback) {\n\t\t\t\t\tpar = node.parent().parent()[0];\n\t\t\t\t\tif(par === this.element[0]) {\n\t\t\t\t\t\tpar = null;\n\t\t\t\t\t}\n\t\t\t\t\tind = node.index();\n\t\t\t\t}\n\t\t\t\t// m[obj.id].data = node.data(); // use only node's data, no need to touch jquery storage\n\t\t\t\tif(!deep && obj.children.length && !node.children('.jstree-children').length) {\n\t\t\t\t\tdeep = true;\n\t\t\t\t}\n\t\t\t\tif(!deep) {\n\t\t\t\t\told = node.children('.jstree-children')[0];\n\t\t\t\t}\n\t\t\t\tf = node.children('.jstree-anchor')[0] === document.activeElement;\n\t\t\t\tnode.remove();\n\t\t\t\t//node = d.createElement('LI');\n\t\t\t\t//node = node[0];\n\t\t\t}\n\t\t\tnode = this._data.core.node.cloneNode(true);\n\t\t\t// node is DOM, deep is boolean\n\n\t\t\tc = 'jstree-node ';\n\t\t\tfor(i in obj.li_attr) {\n\t\t\t\tif(obj.li_attr.hasOwnProperty(i)) {\n\t\t\t\t\tif(i === 'id') { continue; }\n\t\t\t\t\tif(i !== 'class') {\n\t\t\t\t\t\tnode.setAttribute(i, obj.li_attr[i]);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tc += obj.li_attr[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!obj.a_attr.id) {\n\t\t\t\tobj.a_attr.id = obj.id + '_anchor';\n\t\t\t}\n\t\t\tnode.childNodes[1].setAttribute('aria-selected', !!obj.state.selected);\n\t\t\tnode.childNodes[1].setAttribute('aria-level', obj.parents.length);\n\t\t\tif(this.settings.core.compute_elements_positions) {\n\t\t\t\tnode.childNodes[1].setAttribute('aria-setsize', m[obj.parent].children.length);\n\t\t\t\tnode.childNodes[1].setAttribute('aria-posinset', m[obj.parent].children.indexOf(obj.id) + 1);\n\t\t\t}\n\t\t\tif(obj.state.disabled) {\n\t\t\t\tnode.childNodes[1].setAttribute('aria-disabled', true);\n\t\t\t}\n\n\t\t\tfor(i = 0, j = obj.children.length; i < j; i++) {\n\t\t\t\tif(!m[obj.children[i]].state.hidden) {\n\t\t\t\t\thas_children = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(obj.parent !== null && m[obj.parent] && !obj.state.hidden) {\n\t\t\t\ti = $.inArray(obj.id, m[obj.parent].children);\n\t\t\t\tlast_sibling = obj.id;\n\t\t\t\tif(i !== -1) {\n\t\t\t\t\ti++;\n\t\t\t\t\tfor(j = m[obj.parent].children.length; i < j; i++) {\n\t\t\t\t\t\tif(!m[m[obj.parent].children[i]].state.hidden) {\n\t\t\t\t\t\t\tlast_sibling = m[obj.parent].children[i];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(last_sibling !== obj.id) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(obj.state.hidden) {\n\t\t\t\tc += ' jstree-hidden';\n\t\t\t}\n\t\t\tif (obj.state.loading) {\n\t\t\t\tc += ' jstree-loading';\n\t\t\t}\n\t\t\tif(obj.state.loaded && !has_children) {\n\t\t\t\tc += ' jstree-leaf';\n\t\t\t}\n\t\t\telse {\n\t\t\t\tc += obj.state.opened && obj.state.loaded ? ' jstree-open' : ' jstree-closed';\n\t\t\t\tnode.childNodes[1].setAttribute('aria-expanded', (obj.state.opened && obj.state.loaded) );\n\t\t\t}\n\t\t\tif(last_sibling === obj.id) {\n\t\t\t\tc += ' jstree-last';\n\t\t\t}\n\t\t\tnode.id = obj.id;\n\t\t\tnode.className = c;\n\t\t\tc = ( obj.state.selected ? ' jstree-clicked' : '') + ( obj.state.disabled ? ' jstree-disabled' : '');\n\t\t\tfor(j in obj.a_attr) {\n\t\t\t\tif(obj.a_attr.hasOwnProperty(j)) {\n\t\t\t\t\tif(j === 'href' && obj.a_attr[j] === '#') { continue; }\n\t\t\t\t\tif(j !== 'class') {\n\t\t\t\t\t\tnode.childNodes[1].setAttribute(j, obj.a_attr[j]);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tc += ' ' + obj.a_attr[j];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(c.length) {\n\t\t\t\tnode.childNodes[1].className = 'jstree-anchor ' + c;\n\t\t\t}\n\t\t\tif((obj.icon && obj.icon !== true) || obj.icon === false) {\n\t\t\t\tif(obj.icon === false) {\n\t\t\t\t\tnode.childNodes[1].childNodes[0].className += ' jstree-themeicon-hidden';\n\t\t\t\t}\n\t\t\t\telse if(obj.icon.indexOf('/') === -1 && obj.icon.indexOf('.') === -1) {\n\t\t\t\t\tnode.childNodes[1].childNodes[0].className += ' ' + obj.icon + ' jstree-themeicon-custom';\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnode.childNodes[1].childNodes[0].style.backgroundImage = 'url(\"'+obj.icon+'\")';\n\t\t\t\t\tnode.childNodes[1].childNodes[0].style.backgroundPosition = 'center center';\n\t\t\t\t\tnode.childNodes[1].childNodes[0].style.backgroundSize = 'auto';\n\t\t\t\t\tnode.childNodes[1].childNodes[0].className += ' jstree-themeicon-custom';\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif(this.settings.core.force_text) {\n\t\t\t\tnode.childNodes[1].appendChild(d.createTextNode(obj.text));\n\t\t\t}\n\t\t\telse {\n\t\t\t\tnode.childNodes[1].innerHTML += obj.text;\n\t\t\t}\n\n\n\t\t\tif(deep && obj.children.length && (obj.state.opened || force_render) && obj.state.loaded) {\n\t\t\t\tk = d.createElement('UL');\n\t\t\t\tk.setAttribute('role', 'group');\n\t\t\t\tk.className = 'jstree-children';\n\t\t\t\tfor(i = 0, j = obj.children.length; i < j; i++) {\n\t\t\t\t\tk.appendChild(this.redraw_node(obj.children[i], deep, true));\n\t\t\t\t}\n\t\t\t\tnode.appendChild(k);\n\t\t\t}\n\t\t\tif(old) {\n\t\t\t\tnode.appendChild(old);\n\t\t\t}\n\t\t\tif(!is_callback) {\n\t\t\t\t// append back using par / ind\n\t\t\t\tif(!par) {\n\t\t\t\t\tpar = this.element[0];\n\t\t\t\t}\n\t\t\t\tfor(i = 0, j = par.childNodes.length; i < j; i++) {\n\t\t\t\t\tif(par.childNodes[i] && par.childNodes[i].className && par.childNodes[i].className.indexOf('jstree-children') !== -1) {\n\t\t\t\t\t\ttmp = par.childNodes[i];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(!tmp) {\n\t\t\t\t\ttmp = d.createElement('UL');\n\t\t\t\t\ttmp.setAttribute('role', 'group');\n\t\t\t\t\ttmp.className = 'jstree-children';\n\t\t\t\t\tpar.appendChild(tmp);\n\t\t\t\t}\n\t\t\t\tpar = tmp;\n\n\t\t\t\tif(ind < par.childNodes.length) {\n\t\t\t\t\tpar.insertBefore(node, par.childNodes[ind]);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tpar.appendChild(node);\n\t\t\t\t}\n\t\t\t\tif(f) {\n\t\t\t\t\tt = this.element[0].scrollTop;\n\t\t\t\t\tl = this.element[0].scrollLeft;\n\t\t\t\t\tnode.childNodes[1].focus();\n\t\t\t\t\tthis.element[0].scrollTop = t;\n\t\t\t\t\tthis.element[0].scrollLeft = l;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(obj.state.opened && !obj.state.loaded) {\n\t\t\t\tobj.state.opened = false;\n\t\t\t\tsetTimeout(function () {\n\t\t\t\t\tthis.open_node(obj.id, false, 0);\n\t\t\t\t}.bind(this), 0);\n\t\t\t}\n\t\t\treturn node;\n\t\t},\n\t\t/**\n\t\t * opens a node, revealing its children. If the node is not loaded it will be loaded and opened once ready.\n\t\t * @name open_node(obj [, callback, animation])\n\t\t * @param {mixed} obj the node to open\n\t\t * @param {Function} callback a function to execute once the node is opened\n\t\t * @param {Number} animation the animation duration in milliseconds when opening the node (overrides the `core.animation` setting). Use `false` for no animation.\n\t\t * @trigger open_node.jstree, after_open.jstree, before_open.jstree\n\t\t */\n\t\topen_node : function (obj, callback, animation) {\n\t\t\tvar t1, t2, d, t;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.open_node(obj[t1], callback, animation);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tanimation = animation === undefined ? this.settings.core.animation : animation;\n\t\t\tif(!this.is_closed(obj)) {\n\t\t\t\tif(callback) {\n\t\t\t\t\tcallback.call(this, obj, false);\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(!this.is_loaded(obj)) {\n\t\t\t\tif(this.is_loading(obj)) {\n\t\t\t\t\treturn setTimeout(function () {\n\t\t\t\t\t\tthis.open_node(obj, callback, animation);\n\t\t\t\t\t}.bind(this), 500);\n\t\t\t\t}\n\t\t\t\tthis.load_node(obj, function (o, ok) {\n\t\t\t\t\treturn ok ? this.open_node(o, callback, animation) : (callback ? callback.call(this, o, false) : false);\n\t\t\t\t});\n\t\t\t}\n\t\t\telse {\n\t\t\t\td = this.get_node(obj, true);\n\t\t\t\tt = this;\n\t\t\t\tif(d.length) {\n\t\t\t\t\tif(animation && d.children(\".jstree-children\").length) {\n\t\t\t\t\t\td.children(\".jstree-children\").stop(true, true);\n\t\t\t\t\t}\n\t\t\t\t\tif(obj.children.length && !this._firstChild(d.children('.jstree-children')[0])) {\n\t\t\t\t\t\tthis.draw_children(obj);\n\t\t\t\t\t\t//d = this.get_node(obj, true);\n\t\t\t\t\t}\n\t\t\t\t\tif(!animation) {\n\t\t\t\t\t\tthis.trigger('before_open', { \"node\" : obj });\n\t\t\t\t\t\td[0].className = d[0].className.replace('jstree-closed', 'jstree-open');\n\t\t\t\t\t\td[0].childNodes[1].setAttribute(\"aria-expanded\", true);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis.trigger('before_open', { \"node\" : obj });\n\t\t\t\t\t\td\n\t\t\t\t\t\t\t.children(\".jstree-children\").css(\"display\",\"none\").end()\n\t\t\t\t\t\t\t.removeClass(\"jstree-closed\").addClass(\"jstree-open\")\n\t\t\t\t\t\t\t\t.children('.jstree-anchor').attr(\"aria-expanded\", true).end()\n\t\t\t\t\t\t\t.children(\".jstree-children\").stop(true, true)\n\t\t\t\t\t\t\t\t.slideDown(animation, function () {\n\t\t\t\t\t\t\t\t\tthis.style.display = \"\";\n\t\t\t\t\t\t\t\t\tif (t.element) {\n\t\t\t\t\t\t\t\t\t\tt.trigger(\"after_open\", { \"node\" : obj });\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tobj.state.opened = true;\n\t\t\t\tif(callback) {\n\t\t\t\t\tcallback.call(this, obj, true);\n\t\t\t\t}\n\t\t\t\tif(!d.length) {\n\t\t\t\t\t/**\n\t\t\t\t\t * triggered when a node is about to be opened (if the node is supposed to be in the DOM, it will be, but it won't be visible yet)\n\t\t\t\t\t * @event\n\t\t\t\t\t * @name before_open.jstree\n\t\t\t\t\t * @param {Object} node the opened node\n\t\t\t\t\t */\n\t\t\t\t\tthis.trigger('before_open', { \"node\" : obj });\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * triggered when a node is opened (if there is an animation it will not be completed yet)\n\t\t\t\t * @event\n\t\t\t\t * @name open_node.jstree\n\t\t\t\t * @param {Object} node the opened node\n\t\t\t\t */\n\t\t\t\tthis.trigger('open_node', { \"node\" : obj });\n\t\t\t\tif(!animation || !d.length) {\n\t\t\t\t\t/**\n\t\t\t\t\t * triggered when a node is opened and the animation is complete\n\t\t\t\t\t * @event\n\t\t\t\t\t * @name after_open.jstree\n\t\t\t\t\t * @param {Object} node the opened node\n\t\t\t\t\t */\n\t\t\t\t\tthis.trigger(\"after_open\", { \"node\" : obj });\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * opens every parent of a node (node should be loaded)\n\t\t * @name _open_to(obj)\n\t\t * @param {mixed} obj the node to reveal\n\t\t * @private\n\t\t */\n\t\t_open_to : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar i, j, p = obj.parents;\n\t\t\tfor(i = 0, j = p.length; i < j; i+=1) {\n\t\t\t\tif(i !== $.jstree.root) {\n\t\t\t\t\tthis.open_node(p[i], false, 0);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn $('#' + obj.id.replace($.jstree.idregex,'\\\\$&'), this.element);\n\t\t},\n\t\t/**\n\t\t * closes a node, hiding its children\n\t\t * @name close_node(obj [, animation])\n\t\t * @param {mixed} obj the node to close\n\t\t * @param {Number} animation the animation duration in milliseconds when closing the node (overrides the `core.animation` setting). Use `false` for no animation.\n\t\t * @trigger close_node.jstree, after_close.jstree\n\t\t */\n\t\tclose_node : function (obj, animation) {\n\t\t\tvar t1, t2, t, d;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.close_node(obj[t1], animation);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(this.is_closed(obj)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tanimation = animation === undefined ? this.settings.core.animation : animation;\n\t\t\tt = this;\n\t\t\td = this.get_node(obj, true);\n\n\t\t\tobj.state.opened = false;\n\t\t\t/**\n\t\t\t * triggered when a node is closed (if there is an animation it will not be complete yet)\n\t\t\t * @event\n\t\t\t * @name close_node.jstree\n\t\t\t * @param {Object} node the closed node\n\t\t\t */\n\t\t\tthis.trigger('close_node',{ \"node\" : obj });\n\t\t\tif(!d.length) {\n\t\t\t\t/**\n\t\t\t\t * triggered when a node is closed and the animation is complete\n\t\t\t\t * @event\n\t\t\t\t * @name after_close.jstree\n\t\t\t\t * @param {Object} node the closed node\n\t\t\t\t */\n\t\t\t\tthis.trigger(\"after_close\", { \"node\" : obj });\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif(!animation) {\n\t\t\t\t\td[0].className = d[0].className.replace('jstree-open', 'jstree-closed');\n\t\t\t\t\td.children('.jstree-anchor').attr(\"aria-expanded\", false);\n\t\t\t\t\td.children('.jstree-children').remove();\n\t\t\t\t\tthis.trigger(\"after_close\", { \"node\" : obj });\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\td\n\t\t\t\t\t\t.children(\".jstree-children\").attr(\"style\",\"display:block !important\").end()\n\t\t\t\t\t\t.removeClass(\"jstree-open\").addClass(\"jstree-closed\")\n\t\t\t\t\t\t\t.children('.jstree-anchor').attr(\"aria-expanded\", false).end()\n\t\t\t\t\t\t.children(\".jstree-children\").stop(true, true).slideUp(animation, function () {\n\t\t\t\t\t\t\tthis.style.display = \"\";\n\t\t\t\t\t\t\td.children('.jstree-children').remove();\n\t\t\t\t\t\t\tif (t.element) {\n\t\t\t\t\t\t\t\tt.trigger(\"after_close\", { \"node\" : obj });\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * toggles a node - closing it if it is open, opening it if it is closed\n\t\t * @name toggle_node(obj)\n\t\t * @param {mixed} obj the node to toggle\n\t\t */\n\t\ttoggle_node : function (obj) {\n\t\t\tvar t1, t2;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.toggle_node(obj[t1]);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tif(this.is_closed(obj)) {\n\t\t\t\treturn this.open_node(obj);\n\t\t\t}\n\t\t\tif(this.is_open(obj)) {\n\t\t\t\treturn this.close_node(obj);\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * opens all nodes within a node (or the tree), revealing their children. If the node is not loaded it will be loaded and opened once ready.\n\t\t * @name open_all([obj, animation, original_obj])\n\t\t * @param {mixed} obj the node to open recursively, omit to open all nodes in the tree\n\t\t * @param {Number} animation the animation duration in milliseconds when opening the nodes, the default is no animation\n\t\t * @param {jQuery} reference to the node that started the process (internal use)\n\t\t * @trigger open_all.jstree\n\t\t */\n\t\topen_all : function (obj, animation, original_obj) {\n\t\t\tif(!obj) { obj = $.jstree.root; }\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj) { return false; }\n\t\t\tvar dom = obj.id === $.jstree.root ? this.get_container_ul() : this.get_node(obj, true), i, j, _this;\n\t\t\tif(!dom.length) {\n\t\t\t\tfor(i = 0, j = obj.children_d.length; i < j; i++) {\n\t\t\t\t\tif(this.is_closed(this._model.data[obj.children_d[i]])) {\n\t\t\t\t\t\tthis._model.data[obj.children_d[i]].state.opened = true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn this.trigger('open_all', { \"node\" : obj });\n\t\t\t}\n\t\t\toriginal_obj = original_obj || dom;\n\t\t\t_this = this;\n\t\t\tdom = this.is_closed(obj) ? dom.find('.jstree-closed').addBack() : dom.find('.jstree-closed');\n\t\t\tdom.each(function () {\n\t\t\t\t_this.open_node(\n\t\t\t\t\tthis,\n\t\t\t\t\tfunction(node, status) { if(status && this.is_parent(node)) { this.open_all(node, animation, original_obj); } },\n\t\t\t\t\tanimation || 0\n\t\t\t\t);\n\t\t\t});\n\t\t\tif(original_obj.find('.jstree-closed').length === 0) {\n\t\t\t\t/**\n\t\t\t\t * triggered when an `open_all` call completes\n\t\t\t\t * @event\n\t\t\t\t * @name open_all.jstree\n\t\t\t\t * @param {Object} node the opened node\n\t\t\t\t */\n\t\t\t\tthis.trigger('open_all', { \"node\" : this.get_node(original_obj) });\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * closes all nodes within a node (or the tree), revealing their children\n\t\t * @name close_all([obj, animation])\n\t\t * @param {mixed} obj the node to close recursively, omit to close all nodes in the tree\n\t\t * @param {Number} animation the animation duration in milliseconds when closing the nodes, the default is no animation\n\t\t * @trigger close_all.jstree\n\t\t */\n\t\tclose_all : function (obj, animation) {\n\t\t\tif(!obj) { obj = $.jstree.root; }\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj) { return false; }\n\t\t\tvar dom = obj.id === $.jstree.root ? this.get_container_ul() : this.get_node(obj, true),\n\t\t\t\t_this = this, i, j;\n\t\t\tif(dom.length) {\n\t\t\t\tdom = this.is_open(obj) ? dom.find('.jstree-open').addBack() : dom.find('.jstree-open');\n\t\t\t\t$(dom.get().reverse()).each(function () { _this.close_node(this, animation || 0); });\n\t\t\t}\n\t\t\tfor(i = 0, j = obj.children_d.length; i < j; i++) {\n\t\t\t\tthis._model.data[obj.children_d[i]].state.opened = false;\n\t\t\t}\n\t\t\t/**\n\t\t\t * triggered when an `close_all` call completes\n\t\t\t * @event\n\t\t\t * @name close_all.jstree\n\t\t\t * @param {Object} node the closed node\n\t\t\t */\n\t\t\tthis.trigger('close_all', { \"node\" : obj });\n\t\t},\n\t\t/**\n\t\t * checks if a node is disabled (not selectable)\n\t\t * @name is_disabled(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {Boolean}\n\t\t */\n\t\tis_disabled : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\treturn obj && obj.state && obj.state.disabled;\n\t\t},\n\t\t/**\n\t\t * enables a node - so that it can be selected\n\t\t * @name enable_node(obj)\n\t\t * @param {mixed} obj the node to enable\n\t\t * @trigger enable_node.jstree\n\t\t */\n\t\tenable_node : function (obj) {\n\t\t\tvar t1, t2;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.enable_node(obj[t1]);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tobj.state.disabled = false;\n\t\t\tthis.get_node(obj,true).children('.jstree-anchor').removeClass('jstree-disabled').attr('aria-disabled', false);\n\t\t\t/**\n\t\t\t * triggered when an node is enabled\n\t\t\t * @event\n\t\t\t * @name enable_node.jstree\n\t\t\t * @param {Object} node the enabled node\n\t\t\t */\n\t\t\tthis.trigger('enable_node', { 'node' : obj });\n\t\t},\n\t\t/**\n\t\t * disables a node - so that it can not be selected\n\t\t * @name disable_node(obj)\n\t\t * @param {mixed} obj the node to disable\n\t\t * @trigger disable_node.jstree\n\t\t */\n\t\tdisable_node : function (obj) {\n\t\t\tvar t1, t2;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.disable_node(obj[t1]);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tobj.state.disabled = true;\n\t\t\tthis.get_node(obj,true).children('.jstree-anchor').addClass('jstree-disabled').attr('aria-disabled', true);\n\t\t\t/**\n\t\t\t * triggered when an node is disabled\n\t\t\t * @event\n\t\t\t * @name disable_node.jstree\n\t\t\t * @param {Object} node the disabled node\n\t\t\t */\n\t\t\tthis.trigger('disable_node', { 'node' : obj });\n\t\t},\n\t\t/**\n\t\t * determines if a node is hidden\n\t\t * @name is_hidden(obj)\n\t\t * @param {mixed} obj the node\n\t\t */\n\t\tis_hidden : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\treturn obj.state.hidden === true;\n\t\t},\n\t\t/**\n\t\t * hides a node - it is still in the structure but will not be visible\n\t\t * @name hide_node(obj)\n\t\t * @param {mixed} obj the node to hide\n\t\t * @param {Boolean} skip_redraw internal parameter controlling if redraw is called\n\t\t * @trigger hide_node.jstree\n\t\t */\n\t\thide_node : function (obj, skip_redraw) {\n\t\t\tvar t1, t2;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.hide_node(obj[t1], true);\n\t\t\t\t}\n\t\t\t\tif (!skip_redraw) {\n\t\t\t\t\tthis.redraw();\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(!obj.state.hidden) {\n\t\t\t\tobj.state.hidden = true;\n\t\t\t\tthis._node_changed(obj.parent);\n\t\t\t\tif(!skip_redraw) {\n\t\t\t\t\tthis.redraw();\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * triggered when an node is hidden\n\t\t\t\t * @event\n\t\t\t\t * @name hide_node.jstree\n\t\t\t\t * @param {Object} node the hidden node\n\t\t\t\t */\n\t\t\t\tthis.trigger('hide_node', { 'node' : obj });\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * shows a node\n\t\t * @name show_node(obj)\n\t\t * @param {mixed} obj the node to show\n\t\t * @param {Boolean} skip_redraw internal parameter controlling if redraw is called\n\t\t * @trigger show_node.jstree\n\t\t */\n\t\tshow_node : function (obj, skip_redraw) {\n\t\t\tvar t1, t2;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.show_node(obj[t1], true);\n\t\t\t\t}\n\t\t\t\tif (!skip_redraw) {\n\t\t\t\t\tthis.redraw();\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(obj.state.hidden) {\n\t\t\t\tobj.state.hidden = false;\n\t\t\t\tthis._node_changed(obj.parent);\n\t\t\t\tif(!skip_redraw) {\n\t\t\t\t\tthis.redraw();\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * triggered when an node is shown\n\t\t\t\t * @event\n\t\t\t\t * @name show_node.jstree\n\t\t\t\t * @param {Object} node the shown node\n\t\t\t\t */\n\t\t\t\tthis.trigger('show_node', { 'node' : obj });\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * hides all nodes\n\t\t * @name hide_all()\n\t\t * @trigger hide_all.jstree\n\t\t */\n\t\thide_all : function (skip_redraw) {\n\t\t\tvar i, m = this._model.data, ids = [];\n\t\t\tfor(i in m) {\n\t\t\t\tif(m.hasOwnProperty(i) && i !== $.jstree.root && !m[i].state.hidden) {\n\t\t\t\t\tm[i].state.hidden = true;\n\t\t\t\t\tids.push(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._model.force_full_redraw = true;\n\t\t\tif(!skip_redraw) {\n\t\t\t\tthis.redraw();\n\t\t\t}\n\t\t\t/**\n\t\t\t * triggered when all nodes are hidden\n\t\t\t * @event\n\t\t\t * @name hide_all.jstree\n\t\t\t * @param {Array} nodes the IDs of all hidden nodes\n\t\t\t */\n\t\t\tthis.trigger('hide_all', { 'nodes' : ids });\n\t\t\treturn ids;\n\t\t},\n\t\t/**\n\t\t * shows all nodes\n\t\t * @name show_all()\n\t\t * @trigger show_all.jstree\n\t\t */\n\t\tshow_all : function (skip_redraw) {\n\t\t\tvar i, m = this._model.data, ids = [];\n\t\t\tfor(i in m) {\n\t\t\t\tif(m.hasOwnProperty(i) && i !== $.jstree.root && m[i].state.hidden) {\n\t\t\t\t\tm[i].state.hidden = false;\n\t\t\t\t\tids.push(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._model.force_full_redraw = true;\n\t\t\tif(!skip_redraw) {\n\t\t\t\tthis.redraw();\n\t\t\t}\n\t\t\t/**\n\t\t\t * triggered when all nodes are shown\n\t\t\t * @event\n\t\t\t * @name show_all.jstree\n\t\t\t * @param {Array} nodes the IDs of all shown nodes\n\t\t\t */\n\t\t\tthis.trigger('show_all', { 'nodes' : ids });\n\t\t\treturn ids;\n\t\t},\n\t\t/**\n\t\t * called when a node is selected by the user. Used internally.\n\t\t * @private\n\t\t * @name activate_node(obj, e)\n\t\t * @param {mixed} obj the node\n\t\t * @param {Object} e the related event\n\t\t * @trigger activate_node.jstree, changed.jstree\n\t\t */\n\t\tactivate_node : function (obj, e) {\n\t\t\tif(this.is_disabled(obj)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(!e || typeof e !== 'object') {\n\t\t\t\te = {};\n\t\t\t}\n\n\t\t\t// ensure last_clicked is still in the DOM, make it fresh (maybe it was moved?) and make sure it is still selected, if not - make last_clicked the last selected node\n\t\t\tthis._data.core.last_clicked = this._data.core.last_clicked && this._data.core.last_clicked.id !== undefined ? this.get_node(this._data.core.last_clicked.id) : null;\n\t\t\tif(this._data.core.last_clicked && !this._data.core.last_clicked.state.selected) { this._data.core.last_clicked = null; }\n\t\t\tif(!this._data.core.last_clicked && this._data.core.selected.length) { this._data.core.last_clicked = this.get_node(this._data.core.selected[this._data.core.selected.length - 1]); }\n\n\t\t\tif(!this.settings.core.multiple || (!e.metaKey && !e.ctrlKey && !e.shiftKey) || (e.shiftKey && (!this._data.core.last_clicked || !this.get_parent(obj) || this.get_parent(obj) !== this._data.core.last_clicked.parent ) )) {\n\t\t\t\tif(!this.settings.core.multiple && (e.metaKey || e.ctrlKey || e.shiftKey) && this.is_selected(obj)) {\n\t\t\t\t\tthis.deselect_node(obj, false, e);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis.deselect_all(true);\n\t\t\t\t\tthis.select_node(obj, false, false, e);\n\t\t\t\t\tthis._data.core.last_clicked = this.get_node(obj);\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif(e.shiftKey) {\n\t\t\t\t\tvar o = this.get_node(obj).id,\n\t\t\t\t\t\tl = this._data.core.last_clicked.id,\n\t\t\t\t\t\tp = this.get_node(this._data.core.last_clicked.parent).children,\n\t\t\t\t\t\tc = false,\n\t\t\t\t\t\ti, j;\n\t\t\t\t\tfor(i = 0, j = p.length; i < j; i += 1) {\n\t\t\t\t\t\t// separate IFs work whem o and l are the same\n\t\t\t\t\t\tif(p[i] === o) {\n\t\t\t\t\t\t\tc = !c;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(p[i] === l) {\n\t\t\t\t\t\t\tc = !c;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(!this.is_disabled(p[i]) && (c || p[i] === o || p[i] === l)) {\n\t\t\t\t\t\t\tif (!this.is_hidden(p[i])) {\n\t\t\t\t\t\t\t\tthis.select_node(p[i], true, false, e);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tthis.deselect_node(p[i], true, e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis.trigger('changed', { 'action' : 'select_node', 'node' : this.get_node(obj), 'selected' : this._data.core.selected, 'event' : e });\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif(!this.is_selected(obj)) {\n\t\t\t\t\t\tthis.select_node(obj, false, false, e);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tthis.deselect_node(obj, false, e);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t/**\n\t\t\t * triggered when an node is clicked or intercated with by the user\n\t\t\t * @event\n\t\t\t * @name activate_node.jstree\n\t\t\t * @param {Object} node\n\t\t\t * @param {Object} event the ooriginal event (if any) which triggered the call (may be an empty object)\n\t\t\t */\n\t\t\tthis.trigger('activate_node', { 'node' : this.get_node(obj), 'event' : e });\n\t\t},\n\t\t/**\n\t\t * applies the hover state on a node, called when a node is hovered by the user. Used internally.\n\t\t * @private\n\t\t * @name hover_node(obj)\n\t\t * @param {mixed} obj\n\t\t * @trigger hover_node.jstree\n\t\t */\n\t\thover_node : function (obj) {\n\t\t\tobj = this.get_node(obj, true);\n\t\t\tif(!obj || !obj.length || obj.children('.jstree-hovered').length) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar o = this.element.find('.jstree-hovered'), t = this.element;\n\t\t\tif(o && o.length) { this.dehover_node(o); }\n\n\t\t\tobj.children('.jstree-anchor').addClass('jstree-hovered');\n\t\t\t/**\n\t\t\t * triggered when an node is hovered\n\t\t\t * @event\n\t\t\t * @name hover_node.jstree\n\t\t\t * @param {Object} node\n\t\t\t */\n\t\t\tthis.trigger('hover_node', { 'node' : this.get_node(obj) });\n\t\t\tsetTimeout(function () { t.attr('aria-activedescendant', obj[0].id); }, 0);\n\t\t},\n\t\t/**\n\t\t * removes the hover state from a nodecalled when a node is no longer hovered by the user. Used internally.\n\t\t * @private\n\t\t * @name dehover_node(obj)\n\t\t * @param {mixed} obj\n\t\t * @trigger dehover_node.jstree\n\t\t */\n\t\tdehover_node : function (obj) {\n\t\t\tobj = this.get_node(obj, true);\n\t\t\tif(!obj || !obj.length || !obj.children('.jstree-hovered').length) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tobj.children('.jstree-anchor').removeClass('jstree-hovered');\n\t\t\t/**\n\t\t\t * triggered when an node is no longer hovered\n\t\t\t * @event\n\t\t\t * @name dehover_node.jstree\n\t\t\t * @param {Object} node\n\t\t\t */\n\t\t\tthis.trigger('dehover_node', { 'node' : this.get_node(obj) });\n\t\t},\n\t\t/**\n\t\t * select a node\n\t\t * @name select_node(obj [, supress_event, prevent_open])\n\t\t * @param {mixed} obj an array can be used to select multiple nodes\n\t\t * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered\n\t\t * @param {Boolean} prevent_open if set to `true` parents of the selected node won't be opened\n\t\t * @trigger select_node.jstree, changed.jstree\n\t\t */\n\t\tselect_node : function (obj, supress_event, prevent_open, e) {\n\t\t\tvar dom, t1, t2, th;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.select_node(obj[t1], supress_event, prevent_open, e);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdom = this.get_node(obj, true);\n\t\t\tif(!obj.state.selected) {\n\t\t\t\tobj.state.selected = true;\n\t\t\t\tthis._data.core.selected.push(obj.id);\n\t\t\t\tif(!prevent_open) {\n\t\t\t\t\tdom = this._open_to(obj);\n\t\t\t\t}\n\t\t\t\tif(dom && dom.length) {\n\t\t\t\t\tdom.children('.jstree-anchor').addClass('jstree-clicked').attr('aria-selected', true);\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * triggered when an node is selected\n\t\t\t\t * @event\n\t\t\t\t * @name select_node.jstree\n\t\t\t\t * @param {Object} node\n\t\t\t\t * @param {Array} selected the current selection\n\t\t\t\t * @param {Object} event the event (if any) that triggered this select_node\n\t\t\t\t */\n\t\t\t\tthis.trigger('select_node', { 'node' : obj, 'selected' : this._data.core.selected, 'event' : e });\n\t\t\t\tif(!supress_event) {\n\t\t\t\t\t/**\n\t\t\t\t\t * triggered when selection changes\n\t\t\t\t\t * @event\n\t\t\t\t\t * @name changed.jstree\n\t\t\t\t\t * @param {Object} node\n\t\t\t\t\t * @param {Object} action the action that caused the selection to change\n\t\t\t\t\t * @param {Array} selected the current selection\n\t\t\t\t\t * @param {Object} event the event (if any) that triggered this changed event\n\t\t\t\t\t */\n\t\t\t\t\tthis.trigger('changed', { 'action' : 'select_node', 'node' : obj, 'selected' : this._data.core.selected, 'event' : e });\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * deselect a node\n\t\t * @name deselect_node(obj [, supress_event])\n\t\t * @param {mixed} obj an array can be used to deselect multiple nodes\n\t\t * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered\n\t\t * @trigger deselect_node.jstree, changed.jstree\n\t\t */\n\t\tdeselect_node : function (obj, supress_event, e) {\n\t\t\tvar t1, t2, dom;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.deselect_node(obj[t1], supress_event, e);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdom = this.get_node(obj, true);\n\t\t\tif(obj.state.selected) {\n\t\t\t\tobj.state.selected = false;\n\t\t\t\tthis._data.core.selected = $.vakata.array_remove_item(this._data.core.selected, obj.id);\n\t\t\t\tif(dom.length) {\n\t\t\t\t\tdom.children('.jstree-anchor').removeClass('jstree-clicked').attr('aria-selected', false);\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * triggered when an node is deselected\n\t\t\t\t * @event\n\t\t\t\t * @name deselect_node.jstree\n\t\t\t\t * @param {Object} node\n\t\t\t\t * @param {Array} selected the current selection\n\t\t\t\t * @param {Object} event the event (if any) that triggered this deselect_node\n\t\t\t\t */\n\t\t\t\tthis.trigger('deselect_node', { 'node' : obj, 'selected' : this._data.core.selected, 'event' : e });\n\t\t\t\tif(!supress_event) {\n\t\t\t\t\tthis.trigger('changed', { 'action' : 'deselect_node', 'node' : obj, 'selected' : this._data.core.selected, 'event' : e });\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * select all nodes in the tree\n\t\t * @name select_all([supress_event])\n\t\t * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered\n\t\t * @trigger select_all.jstree, changed.jstree\n\t\t */\n\t\tselect_all : function (supress_event) {\n\t\t\tvar tmp = this._data.core.selected.concat([]), i, j;\n\t\t\tthis._data.core.selected = this._model.data[$.jstree.root].children_d.concat();\n\t\t\tfor(i = 0, j = this._data.core.selected.length; i < j; i++) {\n\t\t\t\tif(this._model.data[this._data.core.selected[i]]) {\n\t\t\t\t\tthis._model.data[this._data.core.selected[i]].state.selected = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.redraw(true);\n\t\t\t/**\n\t\t\t * triggered when all nodes are selected\n\t\t\t * @event\n\t\t\t * @name select_all.jstree\n\t\t\t * @param {Array} selected the current selection\n\t\t\t */\n\t\t\tthis.trigger('select_all', { 'selected' : this._data.core.selected });\n\t\t\tif(!supress_event) {\n\t\t\t\tthis.trigger('changed', { 'action' : 'select_all', 'selected' : this._data.core.selected, 'old_selection' : tmp });\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * deselect all selected nodes\n\t\t * @name deselect_all([supress_event])\n\t\t * @param {Boolean} supress_event if set to `true` the `changed.jstree` event won't be triggered\n\t\t * @trigger deselect_all.jstree, changed.jstree\n\t\t */\n\t\tdeselect_all : function (supress_event) {\n\t\t\tvar tmp = this._data.core.selected.concat([]), i, j;\n\t\t\tfor(i = 0, j = this._data.core.selected.length; i < j; i++) {\n\t\t\t\tif(this._model.data[this._data.core.selected[i]]) {\n\t\t\t\t\tthis._model.data[this._data.core.selected[i]].state.selected = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._data.core.selected = [];\n\t\t\tthis.element.find('.jstree-clicked').removeClass('jstree-clicked').attr('aria-selected', false);\n\t\t\t/**\n\t\t\t * triggered when all nodes are deselected\n\t\t\t * @event\n\t\t\t * @name deselect_all.jstree\n\t\t\t * @param {Object} node the previous selection\n\t\t\t * @param {Array} selected the current selection\n\t\t\t */\n\t\t\tthis.trigger('deselect_all', { 'selected' : this._data.core.selected, 'node' : tmp });\n\t\t\tif(!supress_event) {\n\t\t\t\tthis.trigger('changed', { 'action' : 'deselect_all', 'selected' : this._data.core.selected, 'old_selection' : tmp });\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * checks if a node is selected\n\t\t * @name is_selected(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {Boolean}\n\t\t */\n\t\tis_selected : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn obj.state.selected;\n\t\t},\n\t\t/**\n\t\t * get an array of all selected nodes\n\t\t * @name get_selected([full])\n\t\t * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned\n\t\t * @return {Array}\n\t\t */\n\t\tget_selected : function (full) {\n\t\t\treturn full ? $.map(this._data.core.selected, function (i) { return this.get_node(i); }.bind(this)) : this._data.core.selected.slice();\n\t\t},\n\t\t/**\n\t\t * get an array of all top level selected nodes (ignoring children of selected nodes)\n\t\t * @name get_top_selected([full])\n\t\t * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned\n\t\t * @return {Array}\n\t\t */\n\t\tget_top_selected : function (full) {\n\t\t\tvar tmp = this.get_selected(true),\n\t\t\t\tobj = {}, i, j, k, l;\n\t\t\tfor(i = 0, j = tmp.length; i < j; i++) {\n\t\t\t\tobj[tmp[i].id] = tmp[i];\n\t\t\t}\n\t\t\tfor(i = 0, j = tmp.length; i < j; i++) {\n\t\t\t\tfor(k = 0, l = tmp[i].children_d.length; k < l; k++) {\n\t\t\t\t\tif(obj[tmp[i].children_d[k]]) {\n\t\t\t\t\t\tdelete obj[tmp[i].children_d[k]];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\ttmp = [];\n\t\t\tfor(i in obj) {\n\t\t\t\tif(obj.hasOwnProperty(i)) {\n\t\t\t\t\ttmp.push(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn full ? $.map(tmp, function (i) { return this.get_node(i); }.bind(this)) : tmp;\n\t\t},\n\t\t/**\n\t\t * get an array of all bottom level selected nodes (ignoring selected parents)\n\t\t * @name get_bottom_selected([full])\n\t\t * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned\n\t\t * @return {Array}\n\t\t */\n\t\tget_bottom_selected : function (full) {\n\t\t\tvar tmp = this.get_selected(true),\n\t\t\t\tobj = [], i, j;\n\t\t\tfor(i = 0, j = tmp.length; i < j; i++) {\n\t\t\t\tif(!tmp[i].children.length) {\n\t\t\t\t\tobj.push(tmp[i].id);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn full ? $.map(obj, function (i) { return this.get_node(i); }.bind(this)) : obj;\n\t\t},\n\t\t/**\n\t\t * gets the current state of the tree so that it can be restored later with `set_state(state)`. Used internally.\n\t\t * @name get_state()\n\t\t * @private\n\t\t * @return {Object}\n\t\t */\n\t\tget_state : function () {\n\t\t\tvar state\t= {\n\t\t\t\t'core' : {\n\t\t\t\t\t'open' : [],\n\t\t\t\t\t'loaded' : [],\n\t\t\t\t\t'scroll' : {\n\t\t\t\t\t\t'left' : this.element.scrollLeft(),\n\t\t\t\t\t\t'top' : this.element.scrollTop()\n\t\t\t\t\t},\n\t\t\t\t\t/*!\n\t\t\t\t\t'themes' : {\n\t\t\t\t\t\t'name' : this.get_theme(),\n\t\t\t\t\t\t'icons' : this._data.core.themes.icons,\n\t\t\t\t\t\t'dots' : this._data.core.themes.dots\n\t\t\t\t\t},\n\t\t\t\t\t*/\n\t\t\t\t\t'selected' : []\n\t\t\t\t}\n\t\t\t}, i;\n\t\t\tfor(i in this._model.data) {\n\t\t\t\tif(this._model.data.hasOwnProperty(i)) {\n\t\t\t\t\tif(i !== $.jstree.root) {\n\t\t\t\t\t\tif(this._model.data[i].state.loaded && this.settings.core.loaded_state) {\n\t\t\t\t\t\t\tstate.core.loaded.push(i);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(this._model.data[i].state.opened) {\n\t\t\t\t\t\t\tstate.core.open.push(i);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(this._model.data[i].state.selected) {\n\t\t\t\t\t\t\tstate.core.selected.push(i);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn state;\n\t\t},\n\t\t/**\n\t\t * sets the state of the tree. Used internally.\n\t\t * @name set_state(state [, callback])\n\t\t * @private\n\t\t * @param {Object} state the state to restore. Keep in mind this object is passed by reference and jstree will modify it.\n\t\t * @param {Function} callback an optional function to execute once the state is restored.\n\t\t * @trigger set_state.jstree\n\t\t */\n\t\tset_state : function (state, callback) {\n\t\t\tif(state) {\n\t\t\t\tif(state.core && state.core.selected && state.core.initial_selection === undefined) {\n\t\t\t\t\tstate.core.initial_selection = this._data.core.selected.concat([]).sort().join(',');\n\t\t\t\t}\n\t\t\t\tif(state.core) {\n\t\t\t\t\tvar res, n, t, _this, i;\n\t\t\t\t\tif(state.core.loaded) {\n\t\t\t\t\t\tif(!this.settings.core.loaded_state || !$.vakata.is_array(state.core.loaded) || !state.core.loaded.length) {\n\t\t\t\t\t\t\tdelete state.core.loaded;\n\t\t\t\t\t\t\tthis.set_state(state, callback);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tthis._load_nodes(state.core.loaded, function (nodes) {\n\t\t\t\t\t\t\t\tdelete state.core.loaded;\n\t\t\t\t\t\t\t\tthis.set_state(state, callback);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif(state.core.open) {\n\t\t\t\t\t\tif(!$.vakata.is_array(state.core.open) || !state.core.open.length) {\n\t\t\t\t\t\t\tdelete state.core.open;\n\t\t\t\t\t\t\tthis.set_state(state, callback);\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tthis._load_nodes(state.core.open, function (nodes) {\n\t\t\t\t\t\t\t\tthis.open_node(nodes, false, 0);\n\t\t\t\t\t\t\t\tdelete state.core.open;\n\t\t\t\t\t\t\t\tthis.set_state(state, callback);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif(state.core.scroll) {\n\t\t\t\t\t\tif(state.core.scroll && state.core.scroll.left !== undefined) {\n\t\t\t\t\t\t\tthis.element.scrollLeft(state.core.scroll.left);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(state.core.scroll && state.core.scroll.top !== undefined) {\n\t\t\t\t\t\t\tthis.element.scrollTop(state.core.scroll.top);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdelete state.core.scroll;\n\t\t\t\t\t\tthis.set_state(state, callback);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tif(state.core.selected) {\n\t\t\t\t\t\t_this = this;\n\t\t\t\t\t\tif (state.core.initial_selection === undefined ||\n\t\t\t\t\t\t\tstate.core.initial_selection === this._data.core.selected.concat([]).sort().join(',')\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tthis.deselect_all();\n\t\t\t\t\t\t\t$.each(state.core.selected, function (i, v) {\n\t\t\t\t\t\t\t\t_this.select_node(v, false, true);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}\n\t\t\t\t\t\tdelete state.core.initial_selection;\n\t\t\t\t\t\tdelete state.core.selected;\n\t\t\t\t\t\tthis.set_state(state, callback);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\tfor(i in state) {\n\t\t\t\t\t\tif(state.hasOwnProperty(i) && i !== \"core\" && $.inArray(i, this.settings.plugins) === -1) {\n\t\t\t\t\t\t\tdelete state[i];\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif($.isEmptyObject(state.core)) {\n\t\t\t\t\t\tdelete state.core;\n\t\t\t\t\t\tthis.set_state(state, callback);\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif($.isEmptyObject(state)) {\n\t\t\t\t\tstate = null;\n\t\t\t\t\tif(callback) { callback.call(this); }\n\t\t\t\t\t/**\n\t\t\t\t\t * triggered when a `set_state` call completes\n\t\t\t\t\t * @event\n\t\t\t\t\t * @name set_state.jstree\n\t\t\t\t\t */\n\t\t\t\t\tthis.trigger('set_state');\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t},\n\t\t/**\n\t\t * refreshes the tree - all nodes are reloaded with calls to `load_node`.\n\t\t * @name refresh()\n\t\t * @param {Boolean} skip_loading an option to skip showing the loading indicator\n\t\t * @param {Mixed} forget_state if set to `true` state will not be reapplied, if set to a function (receiving the current state as argument) the result of that function will be used as state\n\t\t * @trigger refresh.jstree\n\t\t */\n\t\trefresh : function (skip_loading, forget_state) {\n\t\t\tthis._data.core.state = forget_state === true ? {} : this.get_state();\n\t\t\tif(forget_state && $.vakata.is_function(forget_state)) { this._data.core.state = forget_state.call(this, this._data.core.state); }\n\t\t\tthis._cnt = 0;\n\t\t\tthis._model.data = {};\n\t\t\tthis._model.data[$.jstree.root] = {\n\t\t\t\tid : $.jstree.root,\n\t\t\t\tparent : null,\n\t\t\t\tparents : [],\n\t\t\t\tchildren : [],\n\t\t\t\tchildren_d : [],\n\t\t\t\tstate : { loaded : false }\n\t\t\t};\n\t\t\tthis._data.core.selected = [];\n\t\t\tthis._data.core.last_clicked = null;\n\t\t\tthis._data.core.focused = null;\n\n\t\t\tvar c = this.get_container_ul()[0].className;\n\t\t\tif(!skip_loading) {\n\t\t\t\tthis.element.html(\"<\"+\"ul class='\"+c+\"' role='group'><\"+\"li class='jstree-initial-node jstree-loading jstree-leaf jstree-last' role='none' id='j\"+this._id+\"_loading'><i class='jstree-icon jstree-ocl'></i><\"+\"a class='jstree-anchor' role='treeitem' href='#'><i class='jstree-icon jstree-themeicon-hidden'></i>\" + this.get_string(\"Loading ...\") + \"</a></li></ul>\");\n\t\t\t\tthis.element.attr('aria-activedescendant','j'+this._id+'_loading');\n\t\t\t}\n\t\t\tthis.load_node($.jstree.root, function (o, s) {\n\t\t\t\tif(s) {\n\t\t\t\t\tthis.get_container_ul()[0].className = c;\n\t\t\t\t\tif(this._firstChild(this.get_container_ul()[0])) {\n\t\t\t\t\t\tthis.element.attr('aria-activedescendant',this._firstChild(this.get_container_ul()[0]).id);\n\t\t\t\t\t}\n\t\t\t\t\tthis.set_state($.extend(true, {}, this._data.core.state), function () {\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * triggered when a `refresh` call completes\n\t\t\t\t\t\t * @event\n\t\t\t\t\t\t * @name refresh.jstree\n\t\t\t\t\t\t */\n\t\t\t\t\t\tthis.trigger('refresh');\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tthis._data.core.state = null;\n\t\t\t});\n\t\t},\n\t\t/**\n\t\t * refreshes a node in the tree (reload its children) all opened nodes inside that node are reloaded with calls to `load_node`.\n\t\t * @name refresh_node(obj)\n\t\t * @param {mixed} obj the node\n\t\t * @trigger refresh_node.jstree\n\t\t */\n\t\trefresh_node : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) { return false; }\n\t\t\tvar opened = [], to_load = [], s = this._data.core.selected.concat([]);\n\t\t\tto_load.push(obj.id);\n\t\t\tif(obj.state.opened === true) { opened.push(obj.id); }\n\t\t\tthis.get_node(obj, true).find('.jstree-open').each(function() { to_load.push(this.id); opened.push(this.id); });\n\t\t\tthis._load_nodes(to_load, function (nodes) {\n\t\t\t\tthis.open_node(opened, false, 0);\n\t\t\t\tthis.select_node(s);\n\t\t\t\t/**\n\t\t\t\t * triggered when a node is refreshed\n\t\t\t\t * @event\n\t\t\t\t * @name refresh_node.jstree\n\t\t\t\t * @param {Object} node - the refreshed node\n\t\t\t\t * @param {Array} nodes - an array of the IDs of the nodes that were reloaded\n\t\t\t\t */\n\t\t\t\tthis.trigger('refresh_node', { 'node' : obj, 'nodes' : nodes });\n\t\t\t}.bind(this), false, true);\n\t\t},\n\t\t/**\n\t\t * set (change) the ID of a node\n\t\t * @name set_id(obj, id)\n\t\t * @param {mixed} obj the node\n\t\t * @param {String} id the new ID\n\t\t * @return {Boolean}\n\t\t * @trigger set_id.jstree\n\t\t */\n\t\tset_id : function (obj, id) {\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) { return false; }\n\t\t\tvar i, j, m = this._model.data, old = obj.id;\n\t\t\tid = id.toString();\n\t\t\t// update parents (replace current ID with new one in children and children_d)\n\t\t\tm[obj.parent].children[$.inArray(obj.id, m[obj.parent].children)] = id;\n\t\t\tfor(i = 0, j = obj.parents.length; i < j; i++) {\n\t\t\t\tm[obj.parents[i]].children_d[$.inArray(obj.id, m[obj.parents[i]].children_d)] = id;\n\t\t\t}\n\t\t\t// update children (replace current ID with new one in parent and parents)\n\t\t\tfor(i = 0, j = obj.children.length; i < j; i++) {\n\t\t\t\tm[obj.children[i]].parent = id;\n\t\t\t}\n\t\t\tfor(i = 0, j = obj.children_d.length; i < j; i++) {\n\t\t\t\tm[obj.children_d[i]].parents[$.inArray(obj.id, m[obj.children_d[i]].parents)] = id;\n\t\t\t}\n\t\t\ti = $.inArray(obj.id, this._data.core.selected);\n\t\t\tif(i !== -1) { this._data.core.selected[i] = id; }\n\t\t\t// update model and obj itself (obj.id, this._model.data[KEY])\n\t\t\ti = this.get_node(obj.id, true);\n\t\t\tif(i) {\n\t\t\t\ti.attr('id', id); //.children('.jstree-anchor').attr('id', id + '_anchor').end().attr('aria-labelledby', id + '_anchor');\n\t\t\t\tif(this.element.attr('aria-activedescendant') === obj.id) {\n\t\t\t\t\tthis.element.attr('aria-activedescendant', id);\n\t\t\t\t}\n\t\t\t}\n\t\t\tdelete m[obj.id];\n\t\t\tobj.id = id;\n\t\t\tobj.li_attr.id = id;\n\t\t\tm[id] = obj;\n\t\t\t/**\n\t\t\t * triggered when a node id value is changed\n\t\t\t * @event\n\t\t\t * @name set_id.jstree\n\t\t\t * @param {Object} node\n\t\t\t * @param {String} old the old id\n\t\t\t */\n\t\t\tthis.trigger('set_id',{ \"node\" : obj, \"new\" : obj.id, \"old\" : old });\n\t\t\treturn true;\n\t\t},\n\t\t/**\n\t\t * get the text value of a node\n\t\t * @name get_text(obj)\n\t\t * @param {mixed} obj the node\n\t\t * @return {String}\n\t\t */\n\t\tget_text : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\treturn (!obj || obj.id === $.jstree.root) ? false : obj.text;\n\t\t},\n\t\t/**\n\t\t * set the text value of a node. Used internally, please use `rename_node(obj, val)`.\n\t\t * @private\n\t\t * @name set_text(obj, val)\n\t\t * @param {mixed} obj the node, you can pass an array to set the text on multiple nodes\n\t\t * @param {String} val the new text value\n\t\t * @return {Boolean}\n\t\t * @trigger set_text.jstree\n\t\t */\n\t\tset_text : function (obj, val) {\n\t\t\tvar t1, t2;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.set_text(obj[t1], val);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) { return false; }\n\t\t\tobj.text = val;\n\t\t\tif(this.get_node(obj, true).length) {\n\t\t\t\tthis.redraw_node(obj.id);\n\t\t\t}\n\t\t\t/**\n\t\t\t * triggered when a node text value is changed\n\t\t\t * @event\n\t\t\t * @name set_text.jstree\n\t\t\t * @param {Object} obj\n\t\t\t * @param {String} text the new value\n\t\t\t */\n\t\t\tthis.trigger('set_text',{ \"obj\" : obj, \"text\" : val });\n\t\t\treturn true;\n\t\t},\n\t\t/**\n\t\t * gets a JSON representation of a node (or the whole tree)\n\t\t * @name get_json([obj, options])\n\t\t * @param {mixed} obj\n\t\t * @param {Object} options\n\t\t * @param {Boolean} options.no_state do not return state information\n\t\t * @param {Boolean} options.no_id do not return ID\n\t\t * @param {Boolean} options.no_children do not include children\n\t\t * @param {Boolean} options.no_data do not include node data\n\t\t * @param {Boolean} options.no_li_attr do not include LI attributes\n\t\t * @param {Boolean} options.no_a_attr do not include A attributes\n\t\t * @param {Boolean} options.flat return flat JSON instead of nested\n\t\t * @return {Object}\n\t\t */\n\t\tget_json : function (obj, options, flat) {\n\t\t\tobj = this.get_node(obj || $.jstree.root);\n\t\t\tif(!obj) { return false; }\n\t\t\tif(options && options.flat && !flat) { flat = []; }\n\t\t\tvar tmp = {\n\t\t\t\t'id' : obj.id,\n\t\t\t\t'text' : obj.text,\n\t\t\t\t'icon' : this.get_icon(obj),\n\t\t\t\t'li_attr' : $.extend(true, {}, obj.li_attr),\n\t\t\t\t'a_attr' : $.extend(true, {}, obj.a_attr),\n\t\t\t\t'state' : {},\n\t\t\t\t'data' : options && options.no_data ? false : $.extend(true, $.vakata.is_array(obj.data)?[]:{}, obj.data)\n\t\t\t\t//( this.get_node(obj, true).length ? this.get_node(obj, true).data() : obj.data ),\n\t\t\t}, i, j;\n\t\t\tif(options && options.flat) {\n\t\t\t\ttmp.parent = obj.parent;\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttmp.children = [];\n\t\t\t}\n\t\t\tif(!options || !options.no_state) {\n\t\t\t\tfor(i in obj.state) {\n\t\t\t\t\tif(obj.state.hasOwnProperty(i)) {\n\t\t\t\t\t\ttmp.state[i] = obj.state[i];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdelete tmp.state;\n\t\t\t}\n\t\t\tif(options && options.no_li_attr) {\n\t\t\t\tdelete tmp.li_attr;\n\t\t\t}\n\t\t\tif(options && options.no_a_attr) {\n\t\t\t\tdelete tmp.a_attr;\n\t\t\t}\n\t\t\tif(options && options.no_id) {\n\t\t\t\tdelete tmp.id;\n\t\t\t\tif(tmp.li_attr && tmp.li_attr.id) {\n\t\t\t\t\tdelete tmp.li_attr.id;\n\t\t\t\t}\n\t\t\t\tif(tmp.a_attr && tmp.a_attr.id) {\n\t\t\t\t\tdelete tmp.a_attr.id;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(options && options.flat && obj.id !== $.jstree.root) {\n\t\t\t\tflat.push(tmp);\n\t\t\t}\n\t\t\tif(!options || !options.no_children) {\n\t\t\t\tfor(i = 0, j = obj.children.length; i < j; i++) {\n\t\t\t\t\tif(options && options.flat) {\n\t\t\t\t\t\tthis.get_json(obj.children[i], options, flat);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\ttmp.children.push(this.get_json(obj.children[i], options));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn options && options.flat ? flat : (obj.id === $.jstree.root ? tmp.children : tmp);\n\t\t},\n\t\t/**\n\t\t * create a new node (do not confuse with load_node)\n\t\t * @name create_node([par, node, pos, callback, is_loaded])\n\t\t * @param {mixed} par the parent node (to create a root node use either \"#\" (string) or `null`)\n\t\t * @param {mixed} node the data for the new node (a valid JSON object, or a simple string with the name)\n\t\t * @param {mixed} pos the index at which to insert the node, \"first\" and \"last\" are also supported, default is \"last\"\n\t\t * @param {Function} callback a function to be called once the node is created\n\t\t * @param {Boolean} is_loaded internal argument indicating if the parent node was succesfully loaded\n\t\t * @return {String} the ID of the newly create node\n\t\t * @trigger model.jstree, create_node.jstree\n\t\t */\n\t\tcreate_node : function (par, node, pos, callback, is_loaded) {\n\t\t\tif(par === null) { par = $.jstree.root; }\n\t\t\tpar = this.get_node(par);\n\t\t\tif(!par) { return false; }\n\t\t\tpos = pos === undefined ? \"last\" : pos;\n\t\t\tif(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {\n\t\t\t\treturn this.load_node(par, function () { this.create_node(par, node, pos, callback, true); });\n\t\t\t}\n\t\t\tif(!node) { node = { \"text\" : this.get_string('New node') }; }\n\t\t\tif(typeof node === \"string\") {\n\t\t\t\tnode = { \"text\" : node };\n\t\t\t} else {\n\t\t\t\tnode = $.extend(true, {}, node);\n\t\t\t}\n\t\t\tif(node.text === undefined) { node.text = this.get_string('New node'); }\n\t\t\tvar tmp, dpc, i, j;\n\n\t\t\tif(par.id === $.jstree.root) {\n\t\t\t\tif(pos === \"before\") { pos = \"first\"; }\n\t\t\t\tif(pos === \"after\") { pos = \"last\"; }\n\t\t\t}\n\t\t\tswitch(pos) {\n\t\t\t\tcase \"before\":\n\t\t\t\t\ttmp = this.get_node(par.parent);\n\t\t\t\t\tpos = $.inArray(par.id, tmp.children);\n\t\t\t\t\tpar = tmp;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"after\" :\n\t\t\t\t\ttmp = this.get_node(par.parent);\n\t\t\t\t\tpos = $.inArray(par.id, tmp.children) + 1;\n\t\t\t\t\tpar = tmp;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"inside\":\n\t\t\t\tcase \"first\":\n\t\t\t\t\tpos = 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"last\":\n\t\t\t\t\tpos = par.children.length;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tif(!pos) { pos = 0; }\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(pos > par.children.length) { pos = par.children.length; }\n\t\t\tif(!node.id) { node.id = true; }\n\t\t\tif(!this.check(\"create_node\", node, par, pos)) {\n\t\t\t\tthis.settings.core.error.call(this, this._data.core.last_error);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(node.id === true) { delete node.id; }\n\t\t\tnode = this._parse_model_from_json(node, par.id, par.parents.concat());\n\t\t\tif(!node) { return false; }\n\t\t\ttmp = this.get_node(node);\n\t\t\tdpc = [];\n\t\t\tdpc.push(node);\n\t\t\tdpc = dpc.concat(tmp.children_d);\n\t\t\tthis.trigger('model', { \"nodes\" : dpc, \"parent\" : par.id });\n\n\t\t\tpar.children_d = par.children_d.concat(dpc);\n\t\t\tfor(i = 0, j = par.parents.length; i < j; i++) {\n\t\t\t\tthis._model.data[par.parents[i]].children_d = this._model.data[par.parents[i]].children_d.concat(dpc);\n\t\t\t}\n\t\t\tnode = tmp;\n\t\t\ttmp = [];\n\t\t\tfor(i = 0, j = par.children.length; i < j; i++) {\n\t\t\t\ttmp[i >= pos ? i+1 : i] = par.children[i];\n\t\t\t}\n\t\t\ttmp[pos] = node.id;\n\t\t\tpar.children = tmp;\n\n\t\t\tthis.redraw_node(par, true);\n\t\t\t/**\n\t\t\t * triggered when a node is created\n\t\t\t * @event\n\t\t\t * @name create_node.jstree\n\t\t\t * @param {Object} node\n\t\t\t * @param {String} parent the parent's ID\n\t\t\t * @param {Number} position the position of the new node among the parent's children\n\t\t\t */\n\t\t\tthis.trigger('create_node', { \"node\" : this.get_node(node), \"parent\" : par.id, \"position\" : pos });\n\t\t\tif(callback) { callback.call(this, this.get_node(node)); }\n\t\t\treturn node.id;\n\t\t},\n\t\t/**\n\t\t * set the text value of a node\n\t\t * @name rename_node(obj, val)\n\t\t * @param {mixed} obj the node, you can pass an array to rename multiple nodes to the same name\n\t\t * @param {String} val the new text value\n\t\t * @return {Boolean}\n\t\t * @trigger rename_node.jstree\n\t\t */\n\t\trename_node : function (obj, val) {\n\t\t\tvar t1, t2, old;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.rename_node(obj[t1], val);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) { return false; }\n\t\t\told = obj.text;\n\t\t\tif(!this.check(\"rename_node\", obj, this.get_parent(obj), val)) {\n\t\t\t\tthis.settings.core.error.call(this, this._data.core.last_error);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tthis.set_text(obj, val); // .apply(this, Array.prototype.slice.call(arguments))\n\t\t\t/**\n\t\t\t * triggered when a node is renamed\n\t\t\t * @event\n\t\t\t * @name rename_node.jstree\n\t\t\t * @param {Object} node\n\t\t\t * @param {String} text the new value\n\t\t\t * @param {String} old the old value\n\t\t\t */\n\t\t\tthis.trigger('rename_node', { \"node\" : obj, \"text\" : val, \"old\" : old });\n\t\t\treturn true;\n\t\t},\n\t\t/**\n\t\t * remove a node\n\t\t * @name delete_node(obj)\n\t\t * @param {mixed} obj the node, you can pass an array to delete multiple nodes\n\t\t * @return {Boolean}\n\t\t * @trigger delete_node.jstree, changed.jstree\n\t\t */\n\t\tdelete_node : function (obj) {\n\t\t\tvar t1, t2, par, pos, tmp, i, j, k, l, c, top, lft;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.delete_node(obj[t1]);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) { return false; }\n\t\t\tpar = this.get_node(obj.parent);\n\t\t\tpos = $.inArray(obj.id, par.children);\n\t\t\tc = false;\n\t\t\tif(!this.check(\"delete_node\", obj, par, pos)) {\n\t\t\t\tthis.settings.core.error.call(this, this._data.core.last_error);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(pos !== -1) {\n\t\t\t\tpar.children = $.vakata.array_remove(par.children, pos);\n\t\t\t}\n\t\t\ttmp = obj.children_d.concat([]);\n\t\t\ttmp.push(obj.id);\n\t\t\tfor(i = 0, j = obj.parents.length; i < j; i++) {\n\t\t\t\tthis._model.data[obj.parents[i]].children_d = $.vakata.array_filter(this._model.data[obj.parents[i]].children_d, function (v) {\n\t\t\t\t\treturn $.inArray(v, tmp) === -1;\n\t\t\t\t});\n\t\t\t}\n\t\t\tfor(k = 0, l = tmp.length; k < l; k++) {\n\t\t\t\tif(this._model.data[tmp[k]].state.selected) {\n\t\t\t\t\tc = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (c) {\n\t\t\t\tthis._data.core.selected = $.vakata.array_filter(this._data.core.selected, function (v) {\n\t\t\t\t\treturn $.inArray(v, tmp) === -1;\n\t\t\t\t});\n\t\t\t}\n\t\t\t/**\n\t\t\t * triggered when a node is deleted\n\t\t\t * @event\n\t\t\t * @name delete_node.jstree\n\t\t\t * @param {Object} node\n\t\t\t * @param {String} parent the parent's ID\n\t\t\t */\n\t\t\tthis.trigger('delete_node', { \"node\" : obj, \"parent\" : par.id });\n\t\t\tif(c) {\n\t\t\t\tthis.trigger('changed', { 'action' : 'delete_node', 'node' : obj, 'selected' : this._data.core.selected, 'parent' : par.id });\n\t\t\t}\n\t\t\tfor(k = 0, l = tmp.length; k < l; k++) {\n\t\t\t\tdelete this._model.data[tmp[k]];\n\t\t\t}\n\t\t\tif($.inArray(this._data.core.focused, tmp) !== -1) {\n\t\t\t\tthis._data.core.focused = null;\n\t\t\t\ttop = this.element[0].scrollTop;\n\t\t\t\tlft = this.element[0].scrollLeft;\n\t\t\t\tif(par.id === $.jstree.root) {\n\t\t\t\t\tif (this._model.data[$.jstree.root].children[0]) {\n\t\t\t\t\t\tthis.get_node(this._model.data[$.jstree.root].children[0], true).children('.jstree-anchor').triger('focus');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis.get_node(par, true).children('.jstree-anchor').trigger('focus');\n\t\t\t\t}\n\t\t\t\tthis.element[0].scrollTop = top;\n\t\t\t\tthis.element[0].scrollLeft = lft;\n\t\t\t}\n\t\t\tthis.redraw_node(par, true);\n\t\t\treturn true;\n\t\t},\n\t\t/**\n\t\t * check if an operation is premitted on the tree. Used internally.\n\t\t * @private\n\t\t * @name check(chk, obj, par, pos)\n\t\t * @param {String} chk the operation to check, can be \"create_node\", \"rename_node\", \"delete_node\", \"copy_node\" or \"move_node\"\n\t\t * @param {mixed} obj the node\n\t\t * @param {mixed} par the parent\n\t\t * @param {mixed} pos the position to insert at, or if \"rename_node\" - the new name\n\t\t * @param {mixed} more some various additional information, for example if a \"move_node\" operations is triggered by DND this will be the hovered node\n\t\t * @return {Boolean}\n\t\t */\n\t\tcheck : function (chk, obj, par, pos, more) {\n\t\t\tobj = obj && obj.id ? obj : this.get_node(obj);\n\t\t\tpar = par && par.id ? par : this.get_node(par);\n\t\t\tvar tmp = chk.match(/^move_node|copy_node|create_node$/i) ? par : obj,\n\t\t\t\tchc = this.settings.core.check_callback;\n\t\t\tif(chk === \"move_node\" || chk === \"copy_node\") {\n\t\t\t\tif((!more || !more.is_multi) && (chk === \"move_node\" && $.inArray(obj.id, par.children) === pos)) {\n\t\t\t\t\tthis._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_08', 'reason' : 'Moving node to its current position', 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif((!more || !more.is_multi) && (obj.id === par.id || (chk === \"move_node\" && $.inArray(obj.id, par.children) === pos) || $.inArray(par.id, obj.children_d) !== -1)) {\n\t\t\t\t\tthis._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_01', 'reason' : 'Moving parent inside child', 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(tmp && tmp.data) { tmp = tmp.data; }\n\t\t\tif(tmp && tmp.functions && (tmp.functions[chk] === false || tmp.functions[chk] === true)) {\n\t\t\t\tif(tmp.functions[chk] === false) {\n\t\t\t\t\tthis._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_02', 'reason' : 'Node data prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };\n\t\t\t\t}\n\t\t\t\treturn tmp.functions[chk];\n\t\t\t}\n\t\t\tif(chc === false || ($.vakata.is_function(chc) && chc.call(this, chk, obj, par, pos, more) === false) || (chc && chc[chk] === false)) {\n\t\t\t\tthis._data.core.last_error = { 'error' : 'check', 'plugin' : 'core', 'id' : 'core_03', 'reason' : 'User config for core.check_callback prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\t/**\n\t\t * get the last error\n\t\t * @name last_error()\n\t\t * @return {Object}\n\t\t */\n\t\tlast_error : function () {\n\t\t\treturn this._data.core.last_error;\n\t\t},\n\t\t/**\n\t\t * move a node to a new parent\n\t\t * @name move_node(obj, par [, pos, callback, is_loaded])\n\t\t * @param {mixed} obj the node to move, pass an array to move multiple nodes\n\t\t * @param {mixed} par the new parent\n\t\t * @param {mixed} pos the position to insert at (besides integer values, \"first\" and \"last\" are supported, as well as \"before\" and \"after\"), defaults to integer `0`\n\t\t * @param {function} callback a function to call once the move is completed, receives 3 arguments - the node, the new parent and the position\n\t\t * @param {Boolean} is_loaded internal parameter indicating if the parent node has been loaded\n\t\t * @param {Boolean} skip_redraw internal parameter indicating if the tree should be redrawn\n\t\t * @param {Boolean} instance internal parameter indicating if the node comes from another instance\n\t\t * @trigger move_node.jstree\n\t\t */\n\t\tmove_node : function (obj, par, pos, callback, is_loaded, skip_redraw, origin) {\n\t\t\tvar t1, t2, old_par, old_pos, new_par, old_ins, is_multi, dpc, tmp, i, j, k, l, p;\n\n\t\t\tpar = this.get_node(par);\n\t\t\tpos = pos === undefined ? 0 : pos;\n\t\t\tif(!par) { return false; }\n\t\t\tif(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {\n\t\t\t\treturn this.load_node(par, function () { this.move_node(obj, par, pos, callback, true, false, origin); });\n\t\t\t}\n\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tif(obj.length === 1) {\n\t\t\t\t\tobj = obj[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t//obj = obj.slice();\n\t\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\t\tif((tmp = this.move_node(obj[t1], par, pos, callback, is_loaded, false, origin))) {\n\t\t\t\t\t\t\tpar = tmp;\n\t\t\t\t\t\t\tpos = \"after\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis.redraw();\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tobj = obj && obj.id ? obj : this.get_node(obj);\n\n\t\t\tif(!obj || obj.id === $.jstree.root) { return false; }\n\n\t\t\told_par = (obj.parent || $.jstree.root).toString();\n\t\t\tnew_par = (!pos.toString().match(/^(before|after)$/) || par.id === $.jstree.root) ? par : this.get_node(par.parent);\n\t\t\told_ins = origin ? origin : (this._model.data[obj.id] ? this : $.jstree.reference(obj.id));\n\t\t\tis_multi = !old_ins || !old_ins._id || (this._id !== old_ins._id);\n\t\t\told_pos = old_ins && old_ins._id && old_par && old_ins._model.data[old_par] && old_ins._model.data[old_par].children ? $.inArray(obj.id, old_ins._model.data[old_par].children) : -1;\n\t\t\tif(old_ins && old_ins._id) {\n\t\t\t\tobj = old_ins._model.data[obj.id];\n\t\t\t}\n\n\t\t\tif(is_multi) {\n\t\t\t\tif((tmp = this.copy_node(obj, par, pos, callback, is_loaded, false, origin))) {\n\t\t\t\t\tif(old_ins) { old_ins.delete_node(obj); }\n\t\t\t\t\treturn tmp;\n\t\t\t\t}\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\t//var m = this._model.data;\n\t\t\tif(par.id === $.jstree.root) {\n\t\t\t\tif(pos === \"before\") { pos = \"first\"; }\n\t\t\t\tif(pos === \"after\") { pos = \"last\"; }\n\t\t\t}\n\t\t\tswitch(pos) {\n\t\t\t\tcase \"before\":\n\t\t\t\t\tpos = $.inArray(par.id, new_par.children);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"after\" :\n\t\t\t\t\tpos = $.inArray(par.id, new_par.children) + 1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"inside\":\n\t\t\t\tcase \"first\":\n\t\t\t\t\tpos = 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"last\":\n\t\t\t\t\tpos = new_par.children.length;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tif(!pos) { pos = 0; }\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(pos > new_par.children.length) { pos = new_par.children.length; }\n\t\t\tif(!this.check(\"move_node\", obj, new_par, pos, { 'core' : true, 'origin' : origin, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id) })) {\n\t\t\t\tthis.settings.core.error.call(this, this._data.core.last_error);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(obj.parent === new_par.id) {\n\t\t\t\tdpc = new_par.children.concat();\n\t\t\t\ttmp = $.inArray(obj.id, dpc);\n\t\t\t\tif(tmp !== -1) {\n\t\t\t\t\tdpc = $.vakata.array_remove(dpc, tmp);\n\t\t\t\t\tif(pos > tmp) { pos--; }\n\t\t\t\t}\n\t\t\t\ttmp = [];\n\t\t\t\tfor(i = 0, j = dpc.length; i < j; i++) {\n\t\t\t\t\ttmp[i >= pos ? i+1 : i] = dpc[i];\n\t\t\t\t}\n\t\t\t\ttmp[pos] = obj.id;\n\t\t\t\tnew_par.children = tmp;\n\t\t\t\tthis._node_changed(new_par.id);\n\t\t\t\tthis.redraw(new_par.id === $.jstree.root);\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// clean old parent and up\n\t\t\t\ttmp = obj.children_d.concat();\n\t\t\t\ttmp.push(obj.id);\n\t\t\t\tfor(i = 0, j = obj.parents.length; i < j; i++) {\n\t\t\t\t\tdpc = [];\n\t\t\t\t\tp = old_ins._model.data[obj.parents[i]].children_d;\n\t\t\t\t\tfor(k = 0, l = p.length; k < l; k++) {\n\t\t\t\t\t\tif($.inArray(p[k], tmp) === -1) {\n\t\t\t\t\t\t\tdpc.push(p[k]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\told_ins._model.data[obj.parents[i]].children_d = dpc;\n\t\t\t\t}\n\t\t\t\told_ins._model.data[old_par].children = $.vakata.array_remove_item(old_ins._model.data[old_par].children, obj.id);\n\n\t\t\t\t// insert into new parent and up\n\t\t\t\tfor(i = 0, j = new_par.parents.length; i < j; i++) {\n\t\t\t\t\tthis._model.data[new_par.parents[i]].children_d = this._model.data[new_par.parents[i]].children_d.concat(tmp);\n\t\t\t\t}\n\t\t\t\tdpc = [];\n\t\t\t\tfor(i = 0, j = new_par.children.length; i < j; i++) {\n\t\t\t\t\tdpc[i >= pos ? i+1 : i] = new_par.children[i];\n\t\t\t\t}\n\t\t\t\tdpc[pos] = obj.id;\n\t\t\t\tnew_par.children = dpc;\n\t\t\t\tnew_par.children_d.push(obj.id);\n\t\t\t\tnew_par.children_d = new_par.children_d.concat(obj.children_d);\n\n\t\t\t\t// update object\n\t\t\t\tobj.parent = new_par.id;\n\t\t\t\ttmp = new_par.parents.concat();\n\t\t\t\ttmp.unshift(new_par.id);\n\t\t\t\tp = obj.parents.length;\n\t\t\t\tobj.parents = tmp;\n\n\t\t\t\t// update object children\n\t\t\t\ttmp = tmp.concat();\n\t\t\t\tfor(i = 0, j = obj.children_d.length; i < j; i++) {\n\t\t\t\t\tthis._model.data[obj.children_d[i]].parents = this._model.data[obj.children_d[i]].parents.slice(0,p*-1);\n\t\t\t\t\tArray.prototype.push.apply(this._model.data[obj.children_d[i]].parents, tmp);\n\t\t\t\t}\n\n\t\t\t\tif(old_par === $.jstree.root || new_par.id === $.jstree.root) {\n\t\t\t\t\tthis._model.force_full_redraw = true;\n\t\t\t\t}\n\t\t\t\tif(!this._model.force_full_redraw) {\n\t\t\t\t\tthis._node_changed(old_par);\n\t\t\t\t\tthis._node_changed(new_par.id);\n\t\t\t\t}\n\t\t\t\tif(!skip_redraw) {\n\t\t\t\t\tthis.redraw();\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(callback) { callback.call(this, obj, new_par, pos); }\n\t\t\t/**\n\t\t\t * triggered when a node is moved\n\t\t\t * @event\n\t\t\t * @name move_node.jstree\n\t\t\t * @param {Object} node\n\t\t\t * @param {String} parent the parent's ID\n\t\t\t * @param {Number} position the position of the node among the parent's children\n\t\t\t * @param {String} old_parent the old parent of the node\n\t\t\t * @param {Number} old_position the old position of the node\n\t\t\t * @param {Boolean} is_multi do the node and new parent belong to different instances\n\t\t\t * @param {jsTree} old_instance the instance the node came from\n\t\t\t * @param {jsTree} new_instance the instance of the new parent\n\t\t\t */\n\t\t\tthis.trigger('move_node', { \"node\" : obj, \"parent\" : new_par.id, \"position\" : pos, \"old_parent\" : old_par, \"old_position\" : old_pos, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id), 'old_instance' : old_ins, 'new_instance' : this });\n\t\t\treturn obj.id;\n\t\t},\n\t\t/**\n\t\t * copy a node to a new parent\n\t\t * @name copy_node(obj, par [, pos, callback, is_loaded])\n\t\t * @param {mixed} obj the node to copy, pass an array to copy multiple nodes\n\t\t * @param {mixed} par the new parent\n\t\t * @param {mixed} pos the position to insert at (besides integer values, \"first\" and \"last\" are supported, as well as \"before\" and \"after\"), defaults to integer `0`\n\t\t * @param {function} callback a function to call once the move is completed, receives 3 arguments - the node, the new parent and the position\n\t\t * @param {Boolean} is_loaded internal parameter indicating if the parent node has been loaded\n\t\t * @param {Boolean} skip_redraw internal parameter indicating if the tree should be redrawn\n\t\t * @param {Boolean} instance internal parameter indicating if the node comes from another instance\n\t\t * @trigger model.jstree copy_node.jstree\n\t\t */\n\t\tcopy_node : function (obj, par, pos, callback, is_loaded, skip_redraw, origin) {\n\t\t\tvar t1, t2, dpc, tmp, i, j, node, old_par, new_par, old_ins, is_multi;\n\n\t\t\tpar = this.get_node(par);\n\t\t\tpos = pos === undefined ? 0 : pos;\n\t\t\tif(!par) { return false; }\n\t\t\tif(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {\n\t\t\t\treturn this.load_node(par, function () { this.copy_node(obj, par, pos, callback, true, false, origin); });\n\t\t\t}\n\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tif(obj.length === 1) {\n\t\t\t\t\tobj = obj[0];\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\t//obj = obj.slice();\n\t\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\t\tif((tmp = this.copy_node(obj[t1], par, pos, callback, is_loaded, true, origin))) {\n\t\t\t\t\t\t\tpar = tmp;\n\t\t\t\t\t\t\tpos = \"after\";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tthis.redraw();\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tobj = obj && obj.id ? obj : this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) { return false; }\n\n\t\t\told_par = (obj.parent || $.jstree.root).toString();\n\t\t\tnew_par = (!pos.toString().match(/^(before|after)$/) || par.id === $.jstree.root) ? par : this.get_node(par.parent);\n\t\t\told_ins = origin ? origin : (this._model.data[obj.id] ? this : $.jstree.reference(obj.id));\n\t\t\tis_multi = !old_ins || !old_ins._id || (this._id !== old_ins._id);\n\n\t\t\tif(old_ins && old_ins._id) {\n\t\t\t\tobj = old_ins._model.data[obj.id];\n\t\t\t}\n\n\t\t\tif(par.id === $.jstree.root) {\n\t\t\t\tif(pos === \"before\") { pos = \"first\"; }\n\t\t\t\tif(pos === \"after\") { pos = \"last\"; }\n\t\t\t}\n\t\t\tswitch(pos) {\n\t\t\t\tcase \"before\":\n\t\t\t\t\tpos = $.inArray(par.id, new_par.children);\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"after\" :\n\t\t\t\t\tpos = $.inArray(par.id, new_par.children) + 1;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"inside\":\n\t\t\t\tcase \"first\":\n\t\t\t\t\tpos = 0;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"last\":\n\t\t\t\t\tpos = new_par.children.length;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tif(!pos) { pos = 0; }\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif(pos > new_par.children.length) { pos = new_par.children.length; }\n\t\t\tif(!this.check(\"copy_node\", obj, new_par, pos, { 'core' : true, 'origin' : origin, 'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id) })) {\n\t\t\t\tthis.settings.core.error.call(this, this._data.core.last_error);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tnode = old_ins ? old_ins.get_json(obj, { no_id : true, no_data : true, no_state : true }) : obj;\n\t\t\tif(!node) { return false; }\n\t\t\tif(node.id === true) { delete node.id; }\n\t\t\tnode = this._parse_model_from_json(node, new_par.id, new_par.parents.concat());\n\t\t\tif(!node) { return false; }\n\t\t\ttmp = this.get_node(node);\n\t\t\tif(obj && obj.state && obj.state.loaded === false) { tmp.state.loaded = false; }\n\t\t\tdpc = [];\n\t\t\tdpc.push(node);\n\t\t\tdpc = dpc.concat(tmp.children_d);\n\t\t\tthis.trigger('model', { \"nodes\" : dpc, \"parent\" : new_par.id });\n\n\t\t\t// insert into new parent and up\n\t\t\tfor(i = 0, j = new_par.parents.length; i < j; i++) {\n\t\t\t\tthis._model.data[new_par.parents[i]].children_d = this._model.data[new_par.parents[i]].children_d.concat(dpc);\n\t\t\t}\n\t\t\tdpc = [];\n\t\t\tfor(i = 0, j = new_par.children.length; i < j; i++) {\n\t\t\t\tdpc[i >= pos ? i+1 : i] = new_par.children[i];\n\t\t\t}\n\t\t\tdpc[pos] = tmp.id;\n\t\t\tnew_par.children = dpc;\n\t\t\tnew_par.children_d.push(tmp.id);\n\t\t\tnew_par.children_d = new_par.children_d.concat(tmp.children_d);\n\n\t\t\tif(new_par.id === $.jstree.root) {\n\t\t\t\tthis._model.force_full_redraw = true;\n\t\t\t}\n\t\t\tif(!this._model.force_full_redraw) {\n\t\t\t\tthis._node_changed(new_par.id);\n\t\t\t}\n\t\t\tif(!skip_redraw) {\n\t\t\t\tthis.redraw(new_par.id === $.jstree.root);\n\t\t\t}\n\t\t\tif(callback) { callback.call(this, tmp, new_par, pos); }\n\t\t\t/**\n\t\t\t * triggered when a node is copied\n\t\t\t * @event\n\t\t\t * @name copy_node.jstree\n\t\t\t * @param {Object} node the copied node\n\t\t\t * @param {Object} original the original node\n\t\t\t * @param {String} parent the parent's ID\n\t\t\t * @param {Number} position the position of the node among the parent's children\n\t\t\t * @param {String} old_parent the old parent of the node\n\t\t\t * @param {Number} old_position the position of the original node\n\t\t\t * @param {Boolean} is_multi do the node and new parent belong to different instances\n\t\t\t * @param {jsTree} old_instance the instance the node came from\n\t\t\t * @param {jsTree} new_instance the instance of the new parent\n\t\t\t */\n\t\t\tthis.trigger('copy_node', { \"node\" : tmp, \"original\" : obj, \"parent\" : new_par.id, \"position\" : pos, \"old_parent\" : old_par, \"old_position\" : old_ins && old_ins._id && old_par && old_ins._model.data[old_par] && old_ins._model.data[old_par].children ? $.inArray(obj.id, old_ins._model.data[old_par].children) : -1,'is_multi' : (old_ins && old_ins._id && old_ins._id !== this._id), 'is_foreign' : (!old_ins || !old_ins._id), 'old_instance' : old_ins, 'new_instance' : this });\n\t\t\treturn tmp.id;\n\t\t},\n\t\t/**\n\t\t * cut a node (a later call to `paste(obj)` would move the node)\n\t\t * @name cut(obj)\n\t\t * @param {mixed} obj multiple objects can be passed using an array\n\t\t * @trigger cut.jstree\n\t\t */\n\t\tcut : function (obj) {\n\t\t\tif(!obj) { obj = this._data.core.selected.concat(); }\n\t\t\tif(!$.vakata.is_array(obj)) { obj = [obj]; }\n\t\t\tif(!obj.length) { return false; }\n\t\t\tvar tmp = [], o, t1, t2;\n\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\to = this.get_node(obj[t1]);\n\t\t\t\tif(o && o.id && o.id !== $.jstree.root) { tmp.push(o); }\n\t\t\t}\n\t\t\tif(!tmp.length) { return false; }\n\t\t\tccp_node = tmp;\n\t\t\tccp_inst = this;\n\t\t\tccp_mode = 'move_node';\n\t\t\t/**\n\t\t\t * triggered when nodes are added to the buffer for moving\n\t\t\t * @event\n\t\t\t * @name cut.jstree\n\t\t\t * @param {Array} node\n\t\t\t */\n\t\t\tthis.trigger('cut', { \"node\" : obj });\n\t\t},\n\t\t/**\n\t\t * copy a node (a later call to `paste(obj)` would copy the node)\n\t\t * @name copy(obj)\n\t\t * @param {mixed} obj multiple objects can be passed using an array\n\t\t * @trigger copy.jstree\n\t\t */\n\t\tcopy : function (obj) {\n\t\t\tif(!obj) { obj = this._data.core.selected.concat(); }\n\t\t\tif(!$.vakata.is_array(obj)) { obj = [obj]; }\n\t\t\tif(!obj.length) { return false; }\n\t\t\tvar tmp = [], o, t1, t2;\n\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\to = this.get_node(obj[t1]);\n\t\t\t\tif(o && o.id && o.id !== $.jstree.root) { tmp.push(o); }\n\t\t\t}\n\t\t\tif(!tmp.length) { return false; }\n\t\t\tccp_node = tmp;\n\t\t\tccp_inst = this;\n\t\t\tccp_mode = 'copy_node';\n\t\t\t/**\n\t\t\t * triggered when nodes are added to the buffer for copying\n\t\t\t * @event\n\t\t\t * @name copy.jstree\n\t\t\t * @param {Array} node\n\t\t\t */\n\t\t\tthis.trigger('copy', { \"node\" : obj });\n\t\t},\n\t\t/**\n\t\t * get the current buffer (any nodes that are waiting for a paste operation)\n\t\t * @name get_buffer()\n\t\t * @return {Object} an object consisting of `mode` (\"copy_node\" or \"move_node\"), `node` (an array of objects) and `inst` (the instance)\n\t\t */\n\t\tget_buffer : function () {\n\t\t\treturn { 'mode' : ccp_mode, 'node' : ccp_node, 'inst' : ccp_inst };\n\t\t},\n\t\t/**\n\t\t * check if there is something in the buffer to paste\n\t\t * @name can_paste()\n\t\t * @return {Boolean}\n\t\t */\n\t\tcan_paste : function () {\n\t\t\treturn ccp_mode !== false && ccp_node !== false; // && ccp_inst._model.data[ccp_node];\n\t\t},\n\t\t/**\n\t\t * copy or move the previously cut or copied nodes to a new parent\n\t\t * @name paste(obj [, pos])\n\t\t * @param {mixed} obj the new parent\n\t\t * @param {mixed} pos the position to insert at (besides integer, \"first\" and \"last\" are supported), defaults to integer `0`\n\t\t * @trigger paste.jstree\n\t\t */\n\t\tpaste : function (obj, pos) {\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || !ccp_mode || !ccp_mode.match(/^(copy_node|move_node)$/) || !ccp_node) { return false; }\n\t\t\tif(this[ccp_mode](ccp_node, obj, pos, false, false, false, ccp_inst)) {\n\t\t\t\t/**\n\t\t\t\t * triggered when paste is invoked\n\t\t\t\t * @event\n\t\t\t\t * @name paste.jstree\n\t\t\t\t * @param {String} parent the ID of the receiving node\n\t\t\t\t * @param {Array} node the nodes in the buffer\n\t\t\t\t * @param {String} mode the performed operation - \"copy_node\" or \"move_node\"\n\t\t\t\t */\n\t\t\t\tthis.trigger('paste', { \"parent\" : obj.id, \"node\" : ccp_node, \"mode\" : ccp_mode });\n\t\t\t}\n\t\t\tccp_node = false;\n\t\t\tccp_mode = false;\n\t\t\tccp_inst = false;\n\t\t},\n\t\t/**\n\t\t * clear the buffer of previously copied or cut nodes\n\t\t * @name clear_buffer()\n\t\t * @trigger clear_buffer.jstree\n\t\t */\n\t\tclear_buffer : function () {\n\t\t\tccp_node = false;\n\t\t\tccp_mode = false;\n\t\t\tccp_inst = false;\n\t\t\t/**\n\t\t\t * triggered when the copy / cut buffer is cleared\n\t\t\t * @event\n\t\t\t * @name clear_buffer.jstree\n\t\t\t */\n\t\t\tthis.trigger('clear_buffer');\n\t\t},\n\t\t/**\n\t\t * put a node in edit mode (input field to rename the node)\n\t\t * @name edit(obj [, default_text, callback])\n\t\t * @param {mixed} obj\n\t\t * @param {String} default_text the text to populate the input with (if omitted or set to a non-string value the node's text value is used)\n\t\t * @param {Function} callback a function to be called once the text box is blurred, it is called in the instance's scope and receives the node, a status parameter (true if the rename is successful, false otherwise), a boolean indicating if the user cancelled the edit and the original unescaped value provided by the user. You can also access the node's title using .text\n\t\t */\n\t\tedit : function (obj, default_text, callback) {\n\t\t\tvar rtl, w, a, s, t, h1, h2, fn, tmp, cancel = false;\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj) { return false; }\n\t\t\tif(!this.check(\"edit\", obj, this.get_parent(obj))) {\n\t\t\t\tthis.settings.core.error.call(this, this._data.core.last_error);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\ttmp = obj;\n\t\t\tdefault_text = typeof default_text === 'string' ? default_text : obj.text;\n\t\t\tthis.set_text(obj, \"\");\n\t\t\tobj = this._open_to(obj);\n\t\t\ttmp.text = default_text;\n\n\t\t\trtl = this._data.core.rtl;\n\t\t\tw = this.element.width();\n\t\t\tthis._data.core.focused = tmp.id;\n\t\t\ta = obj.children('.jstree-anchor').trigger('focus');\n\t\t\ts = $('<span></span>');\n\t\t\t/*!\n\t\t\toi = obj.children(\"i:visible\"),\n\t\t\tai = a.children(\"i:visible\"),\n\t\t\tw1 = oi.width() * oi.length,\n\t\t\tw2 = ai.width() * ai.length,\n\t\t\t*/\n\t\t\tt = default_text;\n\t\t\th1 = $(\"<\"+\"div></div>\", { css : { \"position\" : \"absolute\", \"top\" : \"-200px\", \"left\" : (rtl ? \"0px\" : \"-1000px\"), \"visibility\" : \"hidden\" } }).appendTo(document.body);\n\t\t\th2 = $(\"<\"+\"input />\", {\n\t\t\t\t\t\t\"value\" : t,\n\t\t\t\t\t\t\"class\" : \"jstree-rename-input\",\n\t\t\t\t\t\t// \"size\" : t.length,\n\t\t\t\t\t\t\"css\" : {\n\t\t\t\t\t\t\t\"padding\" : \"0\",\n\t\t\t\t\t\t\t\"border\" : \"1px solid silver\",\n\t\t\t\t\t\t\t\"box-sizing\" : \"border-box\",\n\t\t\t\t\t\t\t\"display\" : \"inline-block\",\n\t\t\t\t\t\t\t\"height\" : (this._data.core.li_height) + \"px\",\n\t\t\t\t\t\t\t\"lineHeight\" : (this._data.core.li_height) + \"px\",\n\t\t\t\t\t\t\t\"width\" : \"150px\" // will be set a bit further down\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"blur\" : function (e) {\n\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\tvar i = s.children(\".jstree-rename-input\"),\n\t\t\t\t\t\t\t\tv = i.val(),\n\t\t\t\t\t\t\t\tf = this.settings.core.force_text,\n\t\t\t\t\t\t\t\tnv;\n\t\t\t\t\t\t\tif(v === \"\") { v = t; }\n\t\t\t\t\t\t\th1.remove();\n\t\t\t\t\t\t\ts.replaceWith(a);\n\t\t\t\t\t\t\ts.remove();\n\t\t\t\t\t\t\tt = f ? t : $('<div></div>').append($.parseHTML(t)).html();\n\t\t\t\t\t\t\tobj = this.get_node(obj);\n\t\t\t\t\t\t\tthis.set_text(obj, t);\n\t\t\t\t\t\t\tnv = !!this.rename_node(obj, f ? $('<div></div>').text(v).text() : $('<div></div>').append($.parseHTML(v)).html());\n\t\t\t\t\t\t\tif(!nv) {\n\t\t\t\t\t\t\t\tthis.set_text(obj, t); // move this up? and fix #483\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis._data.core.focused = tmp.id;\n\t\t\t\t\t\t\tsetTimeout(function () {\n\t\t\t\t\t\t\t\tvar node = this.get_node(tmp.id, true);\n\t\t\t\t\t\t\t\tif(node.length) {\n\t\t\t\t\t\t\t\t\tthis._data.core.focused = tmp.id;\n\t\t\t\t\t\t\t\t\tnode.children('.jstree-anchor').trigger('focus');\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}.bind(this), 0);\n\t\t\t\t\t\t\tif(callback) {\n\t\t\t\t\t\t\t\tcallback.call(this, tmp, nv, cancel, v);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\th2 = null;\n\t\t\t\t\t\t}.bind(this),\n\t\t\t\t\t\t\"keydown\" : function (e) {\n\t\t\t\t\t\t\tvar key = e.which;\n\t\t\t\t\t\t\tif(key === 27) {\n\t\t\t\t\t\t\t\tcancel = true;\n\t\t\t\t\t\t\t\tthis.value = t;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(key === 27 || key === 13 || key === 37 || key === 38 || key === 39 || key === 40 || key === 32) {\n\t\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(key === 27 || key === 13) {\n\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\tthis.blur();\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"click\" : function (e) { e.stopImmediatePropagation(); },\n\t\t\t\t\t\t\"mousedown\" : function (e) { e.stopImmediatePropagation(); },\n\t\t\t\t\t\t\"keyup\" : function (e) {\n\t\t\t\t\t\t\th2.width(Math.min(h1.text(\"pW\" + this.value).width(),w));\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"keypress\" : function(e) {\n\t\t\t\t\t\t\tif(e.which === 13) { return false; }\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\tfn = {\n\t\t\t\t\t\tfontFamily\t\t: a.css('fontFamily')\t\t|| '',\n\t\t\t\t\t\tfontSize\t\t: a.css('fontSize')\t\t\t|| '',\n\t\t\t\t\t\tfontWeight\t\t: a.css('fontWeight')\t\t|| '',\n\t\t\t\t\t\tfontStyle\t\t: a.css('fontStyle')\t\t|| '',\n\t\t\t\t\t\tfontStretch\t\t: a.css('fontStretch')\t\t|| '',\n\t\t\t\t\t\tfontVariant\t\t: a.css('fontVariant')\t\t|| '',\n\t\t\t\t\t\tletterSpacing\t: a.css('letterSpacing')\t|| '',\n\t\t\t\t\t\twordSpacing\t\t: a.css('wordSpacing')\t\t|| ''\n\t\t\t\t};\n\t\t\ts.attr('class', a.attr('class')).append(a.contents().clone()).append(h2);\n\t\t\ta.replaceWith(s);\n\t\t\th1.css(fn);\n\t\t\th2.css(fn).width(Math.min(h1.text(\"pW\" + h2[0].value).width(),w))[0].select();\n\t\t\t$(document).one('mousedown.jstree touchstart.jstree dnd_start.vakata', function (e) {\n\t\t\t\tif (h2 && e.target !== h2) {\n\t\t\t\t\t$(h2).trigger('blur');\n\t\t\t\t}\n\t\t\t});\n\t\t},\n\n\n\t\t/**\n\t\t * changes the theme\n\t\t * @name set_theme(theme_name [, theme_url])\n\t\t * @param {String} theme_name the name of the new theme to apply\n\t\t * @param {mixed} theme_url the location of the CSS file for this theme. Omit or set to `false` if you manually included the file. Set to `true` to autoload from the `core.themes.dir` directory.\n\t\t * @trigger set_theme.jstree\n\t\t */\n\t\tset_theme : function (theme_name, theme_url) {\n\t\t\tif(!theme_name) { return false; }\n\t\t\tif(theme_url === true) {\n\t\t\t\tvar dir = this.settings.core.themes.dir;\n\t\t\t\tif(!dir) { dir = $.jstree.path + '/themes'; }\n\t\t\t\ttheme_url = dir + '/' + theme_name + '/style.css';\n\t\t\t}\n\t\t\tif(theme_url && $.inArray(theme_url, themes_loaded) === -1) {\n\t\t\t\t$('head').append('<'+'link rel=\"stylesheet\" href=\"' + theme_url + '\" type=\"text/css\" />');\n\t\t\t\tthemes_loaded.push(theme_url);\n\t\t\t}\n\t\t\tif(this._data.core.themes.name) {\n\t\t\t\tthis.element.removeClass('jstree-' + this._data.core.themes.name);\n\t\t\t}\n\t\t\tthis._data.core.themes.name = theme_name;\n\t\t\tthis.element.addClass('jstree-' + theme_name);\n\t\t\tthis.element[this.settings.core.themes.responsive ? 'addClass' : 'removeClass' ]('jstree-' + theme_name + '-responsive');\n\t\t\t/**\n\t\t\t * triggered when a theme is set\n\t\t\t * @event\n\t\t\t * @name set_theme.jstree\n\t\t\t * @param {String} theme the new theme\n\t\t\t */\n\t\t\tthis.trigger('set_theme', { 'theme' : theme_name });\n\t\t},\n\t\t/**\n\t\t * gets the name of the currently applied theme name\n\t\t * @name get_theme()\n\t\t * @return {String}\n\t\t */\n\t\tget_theme : function () { return this._data.core.themes.name; },\n\t\t/**\n\t\t * changes the theme variant (if the theme has variants)\n\t\t * @name set_theme_variant(variant_name)\n\t\t * @param {String|Boolean} variant_name the variant to apply (if `false` is used the current variant is removed)\n\t\t */\n\t\tset_theme_variant : function (variant_name) {\n\t\t\tif(this._data.core.themes.variant) {\n\t\t\t\tthis.element.removeClass('jstree-' + this._data.core.themes.name + '-' + this._data.core.themes.variant);\n\t\t\t}\n\t\t\tthis._data.core.themes.variant = variant_name;\n\t\t\tif(variant_name) {\n\t\t\t\tthis.element.addClass('jstree-' + this._data.core.themes.name + '-' + this._data.core.themes.variant);\n\t\t\t}\n\t\t},\n\t\t/**\n\t\t * gets the name of the currently applied theme variant\n\t\t * @name get_theme()\n\t\t * @return {String}\n\t\t */\n\t\tget_theme_variant : function () { return this._data.core.themes.variant; },\n\t\t/**\n\t\t * shows a striped background on the container (if the theme supports it)\n\t\t * @name show_stripes()\n\t\t */\n\t\tshow_stripes : function () {\n\t\t\tthis._data.core.themes.stripes = true;\n\t\t\tthis.get_container_ul().addClass(\"jstree-striped\");\n\t\t\t/**\n\t\t\t * triggered when stripes are shown\n\t\t\t * @event\n\t\t\t * @name show_stripes.jstree\n\t\t\t */\n\t\t\tthis.trigger('show_stripes');\n\t\t},\n\t\t/**\n\t\t * hides the striped background on the container\n\t\t * @name hide_stripes()\n\t\t */\n\t\thide_stripes : function () {\n\t\t\tthis._data.core.themes.stripes = false;\n\t\t\tthis.get_container_ul().removeClass(\"jstree-striped\");\n\t\t\t/**\n\t\t\t * triggered when stripes are hidden\n\t\t\t * @event\n\t\t\t * @name hide_stripes.jstree\n\t\t\t */\n\t\t\tthis.trigger('hide_stripes');\n\t\t},\n\t\t/**\n\t\t * toggles the striped background on the container\n\t\t * @name toggle_stripes()\n\t\t */\n\t\ttoggle_stripes : function () { if(this._data.core.themes.stripes) { this.hide_stripes(); } else { this.show_stripes(); } },\n\t\t/**\n\t\t * shows the connecting dots (if the theme supports it)\n\t\t * @name show_dots()\n\t\t */\n\t\tshow_dots : function () {\n\t\t\tthis._data.core.themes.dots = true;\n\t\t\tthis.get_container_ul().removeClass(\"jstree-no-dots\");\n\t\t\t/**\n\t\t\t * triggered when dots are shown\n\t\t\t * @event\n\t\t\t * @name show_dots.jstree\n\t\t\t */\n\t\t\tthis.trigger('show_dots');\n\t\t},\n\t\t/**\n\t\t * hides the connecting dots\n\t\t * @name hide_dots()\n\t\t */\n\t\thide_dots : function () {\n\t\t\tthis._data.core.themes.dots = false;\n\t\t\tthis.get_container_ul().addClass(\"jstree-no-dots\");\n\t\t\t/**\n\t\t\t * triggered when dots are hidden\n\t\t\t * @event\n\t\t\t * @name hide_dots.jstree\n\t\t\t */\n\t\t\tthis.trigger('hide_dots');\n\t\t},\n\t\t/**\n\t\t * toggles the connecting dots\n\t\t * @name toggle_dots()\n\t\t */\n\t\ttoggle_dots : function () { if(this._data.core.themes.dots) { this.hide_dots(); } else { this.show_dots(); } },\n\t\t/**\n\t\t * show the node icons\n\t\t * @name show_icons()\n\t\t */\n\t\tshow_icons : function () {\n\t\t\tthis._data.core.themes.icons = true;\n\t\t\tthis.get_container_ul().removeClass(\"jstree-no-icons\");\n\t\t\t/**\n\t\t\t * triggered when icons are shown\n\t\t\t * @event\n\t\t\t * @name show_icons.jstree\n\t\t\t */\n\t\t\tthis.trigger('show_icons');\n\t\t},\n\t\t/**\n\t\t * hide the node icons\n\t\t * @name hide_icons()\n\t\t */\n\t\thide_icons : function () {\n\t\t\tthis._data.core.themes.icons = false;\n\t\t\tthis.get_container_ul().addClass(\"jstree-no-icons\");\n\t\t\t/**\n\t\t\t * triggered when icons are hidden\n\t\t\t * @event\n\t\t\t * @name hide_icons.jstree\n\t\t\t */\n\t\t\tthis.trigger('hide_icons');\n\t\t},\n\t\t/**\n\t\t * toggle the node icons\n\t\t * @name toggle_icons()\n\t\t */\n\t\ttoggle_icons : function () { if(this._data.core.themes.icons) { this.hide_icons(); } else { this.show_icons(); } },\n\t\t/**\n\t\t * show the node ellipsis\n\t\t * @name show_icons()\n\t\t */\n\t\tshow_ellipsis : function () {\n\t\t\tthis._data.core.themes.ellipsis = true;\n\t\t\tthis.get_container_ul().addClass(\"jstree-ellipsis\");\n\t\t\t/**\n\t\t\t * triggered when ellisis is shown\n\t\t\t * @event\n\t\t\t * @name show_ellipsis.jstree\n\t\t\t */\n\t\t\tthis.trigger('show_ellipsis');\n\t\t},\n\t\t/**\n\t\t * hide the node ellipsis\n\t\t * @name hide_ellipsis()\n\t\t */\n\t\thide_ellipsis : function () {\n\t\t\tthis._data.core.themes.ellipsis = false;\n\t\t\tthis.get_container_ul().removeClass(\"jstree-ellipsis\");\n\t\t\t/**\n\t\t\t * triggered when ellisis is hidden\n\t\t\t * @event\n\t\t\t * @name hide_ellipsis.jstree\n\t\t\t */\n\t\t\tthis.trigger('hide_ellipsis');\n\t\t},\n\t\t/**\n\t\t * toggle the node ellipsis\n\t\t * @name toggle_icons()\n\t\t */\n\t\ttoggle_ellipsis : function () { if(this._data.core.themes.ellipsis) { this.hide_ellipsis(); } else { this.show_ellipsis(); } },\n\t\t/**\n\t\t * set the node icon for a node\n\t\t * @name set_icon(obj, icon)\n\t\t * @param {mixed} obj\n\t\t * @param {String} icon the new icon - can be a path to an icon or a className, if using an image that is in the current directory use a `./` prefix, otherwise it will be detected as a class\n\t\t */\n\t\tset_icon : function (obj, icon) {\n\t\t\tvar t1, t2, dom, old;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.set_icon(obj[t1], icon);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) { return false; }\n\t\t\told = obj.icon;\n\t\t\tobj.icon = icon === true || icon === null || icon === undefined || icon === '' ? true : icon;\n\t\t\tdom = this.get_node(obj, true).children(\".jstree-anchor\").children(\".jstree-themeicon\");\n\t\t\tif(icon === false) {\n\t\t\t\tdom.removeClass('jstree-themeicon-custom ' + old).css(\"background\",\"\").removeAttr(\"rel\");\n\t\t\t\tthis.hide_icon(obj);\n\t\t\t}\n\t\t\telse if(icon === true || icon === null || icon === undefined || icon === '') {\n\t\t\t\tdom.removeClass('jstree-themeicon-custom ' + old).css(\"background\",\"\").removeAttr(\"rel\");\n\t\t\t\tif(old === false) { this.show_icon(obj); }\n\t\t\t}\n\t\t\telse if(icon.indexOf(\"/\") === -1 && icon.indexOf(\".\") === -1) {\n\t\t\t\tdom.removeClass(old).css(\"background\",\"\");\n\t\t\t\tdom.addClass(icon + ' jstree-themeicon-custom').attr(\"rel\",icon);\n\t\t\t\tif(old === false) { this.show_icon(obj); }\n\t\t\t}\n\t\t\telse {\n\t\t\t\tdom.removeClass(old).css(\"background\",\"\");\n\t\t\t\tdom.addClass('jstree-themeicon-custom').css(\"background\", \"url('\" + icon + \"') center center no-repeat\").attr(\"rel\",icon);\n\t\t\t\tif(old === false) { this.show_icon(obj); }\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\t/**\n\t\t * get the node icon for a node\n\t\t * @name get_icon(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {String}\n\t\t */\n\t\tget_icon : function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\treturn (!obj || obj.id === $.jstree.root) ? false : obj.icon;\n\t\t},\n\t\t/**\n\t\t * hide the icon on an individual node\n\t\t * @name hide_icon(obj)\n\t\t * @param {mixed} obj\n\t\t */\n\t\thide_icon : function (obj) {\n\t\t\tvar t1, t2;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.hide_icon(obj[t1]);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj === $.jstree.root) { return false; }\n\t\t\tobj.icon = false;\n\t\t\tthis.get_node(obj, true).children(\".jstree-anchor\").children(\".jstree-themeicon\").addClass('jstree-themeicon-hidden');\n\t\t\treturn true;\n\t\t},\n\t\t/**\n\t\t * show the icon on an individual node\n\t\t * @name show_icon(obj)\n\t\t * @param {mixed} obj\n\t\t */\n\t\tshow_icon : function (obj) {\n\t\t\tvar t1, t2, dom;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.show_icon(obj[t1]);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj === $.jstree.root) { return false; }\n\t\t\tdom = this.get_node(obj, true);\n\t\t\tobj.icon = dom.length ? dom.children(\".jstree-anchor\").children(\".jstree-themeicon\").attr('rel') : true;\n\t\t\tif(!obj.icon) { obj.icon = true; }\n\t\t\tdom.children(\".jstree-anchor\").children(\".jstree-themeicon\").removeClass('jstree-themeicon-hidden');\n\t\t\treturn true;\n\t\t}\n\t};\n\n\t// helpers\n\t$.vakata = {};\n\t// collect attributes\n\t$.vakata.attributes = function(node, with_values) {\n\t\tnode = $(node)[0];\n\t\tvar attr = with_values ? {} : [];\n\t\tif(node && node.attributes) {\n\t\t\t$.each(node.attributes, function (i, v) {\n\t\t\t\tif($.inArray(v.name.toLowerCase(),['style','contenteditable','hasfocus','tabindex']) !== -1) { return; }\n\t\t\t\tif(v.value !== null && $.vakata.trim(v.value) !== '') {\n\t\t\t\t\tif(with_values) { attr[v.name] = v.value; }\n\t\t\t\t\telse { attr.push(v.name); }\n\t\t\t\t}\n\t\t\t});\n\t\t}\n\t\treturn attr;\n\t};\n\t$.vakata.array_unique = function(array) {\n\t\tvar a = [], i, j, l, o = {};\n\t\tfor(i = 0, l = array.length; i < l; i++) {\n\t\t\tif(o[array[i]] === undefined) {\n\t\t\t\ta.push(array[i]);\n\t\t\t\to[array[i]] = true;\n\t\t\t}\n\t\t}\n\t\treturn a;\n\t};\n\t// remove item from array\n\t$.vakata.array_remove = function(array, from) {\n\t\tarray.splice(from, 1);\n\t\treturn array;\n\t\t//var rest = array.slice((to || from) + 1 || array.length);\n\t\t//array.length = from < 0 ? array.length + from : from;\n\t\t//array.push.apply(array, rest);\n\t\t//return array;\n\t};\n\t// remove item from array\n\t$.vakata.array_remove_item = function(array, item) {\n\t\tvar tmp = $.inArray(item, array);\n\t\treturn tmp !== -1 ? $.vakata.array_remove(array, tmp) : array;\n\t};\n\t$.vakata.array_filter = function(c,a,b,d,e) {\n\t\tif (c.filter) {\n\t\t\treturn c.filter(a, b);\n\t\t}\n\t\td=[];\n\t\tfor (e in c) {\n\t\t\tif (~~e+''===e+'' && e>=0 && a.call(b,c[e],+e,c)) {\n\t\t\t\td.push(c[e]);\n\t\t\t}\n\t\t}\n\t\treturn d;\n\t};\n\t$.vakata.trim = function (text) {\n\t\treturn String.prototype.trim ? \n\t\t\tString.prototype.trim.call(text.toString()) :\n\t\t\ttext.toString().replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n\t};\n\t$.vakata.is_function = function(obj) {\n\t\treturn typeof obj === \"function\" && typeof obj.nodeType !== \"number\";\n\t};\n\t$.vakata.is_array = Array.isArray || function (obj) {\n\t\treturn Object.prototype.toString.call(obj) === \"[object Array]\";\n\t};\n\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind#polyfill\n\tif (!Function.prototype.bind) {\n\t\tFunction.prototype.bind = function () {\n\t\t\tvar thatFunc = this, thatArg = arguments[0];\n\t\t\tvar args = Array.prototype.slice.call(arguments, 1);\n\t\t\tif (typeof thatFunc !== 'function') {\n\t\t\t\t// closest thing possible to the ECMAScript 5\n\t\t\t\t// internal IsCallable function\n\t\t\t\tthrow new TypeError('Function.prototype.bind - what is trying to be bound is not callable');\n\t\t\t}\n\t\t\treturn function(){\n\t\t\t\tvar funcArgs = args.concat(Array.prototype.slice.call(arguments));\n\t\t\t\treturn thatFunc.apply(thatArg, funcArgs);\n\t\t\t};\n\t\t};\n\t}\n\n\n/**\n * ### Changed plugin\n *\n * This plugin adds more information to the `changed.jstree` event. The new data is contained in the `changed` event data property, and contains a lists of `selected` and `deselected` nodes.\n */\n\n\t$.jstree.plugins.changed = function (options, parent) {\n\t\tvar last = [];\n\t\tthis.trigger = function (ev, data) {\n\t\t\tvar i, j;\n\t\t\tif(!data) {\n\t\t\t\tdata = {};\n\t\t\t}\n\t\t\tif(ev.replace('.jstree','') === 'changed') {\n\t\t\t\tdata.changed = { selected : [], deselected : [] };\n\t\t\t\tvar tmp = {};\n\t\t\t\tfor(i = 0, j = last.length; i < j; i++) {\n\t\t\t\t\ttmp[last[i]] = 1;\n\t\t\t\t}\n\t\t\t\tfor(i = 0, j = data.selected.length; i < j; i++) {\n\t\t\t\t\tif(!tmp[data.selected[i]]) {\n\t\t\t\t\t\tdata.changed.selected.push(data.selected[i]);\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\ttmp[data.selected[i]] = 2;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor(i = 0, j = last.length; i < j; i++) {\n\t\t\t\t\tif(tmp[last[i]] === 1) {\n\t\t\t\t\t\tdata.changed.deselected.push(last[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlast = data.selected.slice();\n\t\t\t}\n\t\t\t/**\n\t\t\t * triggered when selection changes (the \"changed\" plugin enhances the original event with more data)\n\t\t\t * @event\n\t\t\t * @name changed.jstree\n\t\t\t * @param {Object} node\n\t\t\t * @param {Object} action the action that caused the selection to change\n\t\t\t * @param {Array} selected the current selection\n\t\t\t * @param {Object} changed an object containing two properties `selected` and `deselected` - both arrays of node IDs, which were selected or deselected since the last changed event\n\t\t\t * @param {Object} event the event (if any) that triggered this changed event\n\t\t\t * @plugin changed\n\t\t\t */\n\t\t\tparent.trigger.call(this, ev, data);\n\t\t};\n\t\tthis.refresh = function (skip_loading, forget_state) {\n\t\t\tlast = [];\n\t\t\treturn parent.refresh.apply(this, arguments);\n\t\t};\n\t};\n\n/**\n * ### Checkbox plugin\n *\n * This plugin renders checkbox icons in front of each node, making multiple selection much easier.\n * It also supports tri-state behavior, meaning that if a node has a few of its children checked it will be rendered as undetermined, and state will be propagated up.\n */\n\n\tvar _i = document.createElement('I');\n\t_i.className = 'jstree-icon jstree-checkbox';\n\t_i.setAttribute('role', 'presentation');\n\t/**\n\t * stores all defaults for the checkbox plugin\n\t * @name $.jstree.defaults.checkbox\n\t * @plugin checkbox\n\t */\n\t$.jstree.defaults.checkbox = {\n\t\t/**\n\t\t * a boolean indicating if checkboxes should be visible (can be changed at a later time using `show_checkboxes()` and `hide_checkboxes`). Defaults to `true`.\n\t\t * @name $.jstree.defaults.checkbox.visible\n\t\t * @plugin checkbox\n\t\t */\n\t\tvisible\t\t\t\t: true,\n\t\t/**\n\t\t * a boolean indicating if checkboxes should cascade down and have an undetermined state. Defaults to `true`.\n\t\t * @name $.jstree.defaults.checkbox.three_state\n\t\t * @plugin checkbox\n\t\t */\n\t\tthree_state\t\t\t: true,\n\t\t/**\n\t\t * a boolean indicating if clicking anywhere on the node should act as clicking on the checkbox. Defaults to `true`.\n\t\t * @name $.jstree.defaults.checkbox.whole_node\n\t\t * @plugin checkbox\n\t\t */\n\t\twhole_node\t\t\t: true,\n\t\t/**\n\t\t * a boolean indicating if the selected style of a node should be kept, or removed. Defaults to `true`.\n\t\t * @name $.jstree.defaults.checkbox.keep_selected_style\n\t\t * @plugin checkbox\n\t\t */\n\t\tkeep_selected_style\t: true,\n\t\t/**\n\t\t * This setting controls how cascading and undetermined nodes are applied.\n\t\t * If 'up' is in the string - cascading up is enabled, if 'down' is in the string - cascading down is enabled, if 'undetermined' is in the string - undetermined nodes will be used.\n\t\t * If `three_state` is set to `true` this setting is automatically set to 'up+down+undetermined'. Defaults to ''.\n\t\t * @name $.jstree.defaults.checkbox.cascade\n\t\t * @plugin checkbox\n\t\t */\n\t\tcascade\t\t\t\t: '',\n\t\t/**\n\t\t * This setting controls if checkbox are bound to the general tree selection or to an internal array maintained by the checkbox plugin. Defaults to `true`, only set to `false` if you know exactly what you are doing.\n\t\t * @name $.jstree.defaults.checkbox.tie_selection\n\t\t * @plugin checkbox\n\t\t */\n\t\ttie_selection\t\t: true,\n\n\t\t/**\n\t\t * This setting controls if cascading down affects disabled checkboxes\n\t\t * @name $.jstree.defaults.checkbox.cascade_to_disabled\n\t\t * @plugin checkbox\n\t\t */\n\t\tcascade_to_disabled : true,\n\n\t\t/**\n\t\t * This setting controls if cascading down affects hidden checkboxes\n\t\t * @name $.jstree.defaults.checkbox.cascade_to_hidden\n\t\t * @plugin checkbox\n\t\t */\n\t\tcascade_to_hidden : true\n\t};\n\t$.jstree.plugins.checkbox = function (options, parent) {\n\t\tthis.bind = function () {\n\t\t\tparent.bind.call(this);\n\t\t\tthis._data.checkbox.uto = false;\n\t\t\tthis._data.checkbox.selected = [];\n\t\t\tif(this.settings.checkbox.three_state) {\n\t\t\t\tthis.settings.checkbox.cascade = 'up+down+undetermined';\n\t\t\t}\n\t\t\tthis.element\n\t\t\t\t.on(\"init.jstree\", function () {\n\t\t\t\t\t\tthis._data.checkbox.visible = this.settings.checkbox.visible;\n\t\t\t\t\t\tif(!this.settings.checkbox.keep_selected_style) {\n\t\t\t\t\t\t\tthis.element.addClass('jstree-checkbox-no-clicked');\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(this.settings.checkbox.tie_selection) {\n\t\t\t\t\t\t\tthis.element.addClass('jstree-checkbox-selection');\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"loading.jstree\", function () {\n\t\t\t\t\t\tthis[ this._data.checkbox.visible ? 'show_checkboxes' : 'hide_checkboxes' ]();\n\t\t\t\t\t}.bind(this));\n\t\t\tif(this.settings.checkbox.cascade.indexOf('undetermined') !== -1) {\n\t\t\t\tthis.element\n\t\t\t\t\t.on('changed.jstree uncheck_node.jstree check_node.jstree uncheck_all.jstree check_all.jstree move_node.jstree copy_node.jstree redraw.jstree open_node.jstree', function () {\n\t\t\t\t\t\t\t// only if undetermined is in setting\n\t\t\t\t\t\t\tif(this._data.checkbox.uto) { clearTimeout(this._data.checkbox.uto); }\n\t\t\t\t\t\t\tthis._data.checkbox.uto = setTimeout(this._undetermined.bind(this), 50);\n\t\t\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t\tif(!this.settings.checkbox.tie_selection) {\n\t\t\t\tthis.element\n\t\t\t\t\t.on('model.jstree', function (e, data) {\n\t\t\t\t\t\tvar m = this._model.data,\n\t\t\t\t\t\t\tp = m[data.parent],\n\t\t\t\t\t\t\tdpc = data.nodes,\n\t\t\t\t\t\t\ti, j;\n\t\t\t\t\t\tfor(i = 0, j = dpc.length; i < j; i++) {\n\t\t\t\t\t\t\tm[dpc[i]].state.checked = m[dpc[i]].state.checked || (m[dpc[i]].original && m[dpc[i]].original.state && m[dpc[i]].original.state.checked);\n\t\t\t\t\t\t\tif(m[dpc[i]].state.checked) {\n\t\t\t\t\t\t\t\tthis._data.checkbox.selected.push(dpc[i]);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t\tif(this.settings.checkbox.cascade.indexOf('up') !== -1 || this.settings.checkbox.cascade.indexOf('down') !== -1) {\n\t\t\t\tthis.element\n\t\t\t\t\t.on('model.jstree', function (e, data) {\n\t\t\t\t\t\t\tvar m = this._model.data,\n\t\t\t\t\t\t\t\tp = m[data.parent],\n\t\t\t\t\t\t\t\tdpc = data.nodes,\n\t\t\t\t\t\t\t\tchd = [],\n\t\t\t\t\t\t\t\tc, i, j, k, l, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection;\n\n\t\t\t\t\t\t\tif(s.indexOf('down') !== -1) {\n\t\t\t\t\t\t\t\t// apply down\n\t\t\t\t\t\t\t\tif(p.state[ t ? 'selected' : 'checked' ]) {\n\t\t\t\t\t\t\t\t\tfor(i = 0, j = dpc.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\t\tm[dpc[i]].state[ t ? 'selected' : 'checked' ] = true;\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tthis._data[ t ? 'core' : 'checkbox' ].selected = this._data[ t ? 'core' : 'checkbox' ].selected.concat(dpc);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tfor(i = 0, j = dpc.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\t\tif(m[dpc[i]].state[ t ? 'selected' : 'checked' ]) {\n\t\t\t\t\t\t\t\t\t\t\tfor(k = 0, l = m[dpc[i]].children_d.length; k < l; k++) {\n\t\t\t\t\t\t\t\t\t\t\t\tm[m[dpc[i]].children_d[k]].state[ t ? 'selected' : 'checked' ] = true;\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\tthis._data[ t ? 'core' : 'checkbox' ].selected = this._data[ t ? 'core' : 'checkbox' ].selected.concat(m[dpc[i]].children_d);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif(s.indexOf('up') !== -1) {\n\t\t\t\t\t\t\t\t// apply up\n\t\t\t\t\t\t\t\tfor(i = 0, j = p.children_d.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\tif(!m[p.children_d[i]].children.length) {\n\t\t\t\t\t\t\t\t\t\tchd.push(m[p.children_d[i]].parent);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tchd = $.vakata.array_unique(chd);\n\t\t\t\t\t\t\t\tfor(k = 0, l = chd.length; k < l; k++) {\n\t\t\t\t\t\t\t\t\tp = m[chd[k]];\n\t\t\t\t\t\t\t\t\twhile(p && p.id !== $.jstree.root) {\n\t\t\t\t\t\t\t\t\t\tc = 0;\n\t\t\t\t\t\t\t\t\t\tfor(i = 0, j = p.children.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\t\t\tc += m[p.children[i]].state[ t ? 'selected' : 'checked' ];\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tif(c === j) {\n\t\t\t\t\t\t\t\t\t\t\tp.state[ t ? 'selected' : 'checked' ] = true;\n\t\t\t\t\t\t\t\t\t\t\tthis._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);\n\t\t\t\t\t\t\t\t\t\t\ttmp = this.get_node(p, true);\n\t\t\t\t\t\t\t\t\t\t\tif(tmp && tmp.length) {\n\t\t\t\t\t\t\t\t\t\t\t\ttmp.attr('aria-selected', true).children('.jstree-anchor').addClass( t ? 'jstree-clicked' : 'jstree-checked');\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tp = this.get_node(p.parent);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tthis._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(this._data[ t ? 'core' : 'checkbox' ].selected);\n\t\t\t\t\t\t}.bind(this))\n\t\t\t\t\t.on(this.settings.checkbox.tie_selection ? 'select_node.jstree' : 'check_node.jstree', function (e, data) {\n\t\t\t\t\t\t\tvar self = this,\n\t\t\t\t\t\t\t\tobj = data.node,\n\t\t\t\t\t\t\t\tm = this._model.data,\n\t\t\t\t\t\t\t\tpar = this.get_node(obj.parent),\n\t\t\t\t\t\t\t\ti, j, c, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection,\n\t\t\t\t\t\t\t\tsel = {}, cur = this._data[ t ? 'core' : 'checkbox' ].selected;\n\n\t\t\t\t\t\t\tfor (i = 0, j = cur.length; i < j; i++) {\n\t\t\t\t\t\t\t\tsel[cur[i]] = true;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// apply down\n\t\t\t\t\t\t\tif(s.indexOf('down') !== -1) {\n\t\t\t\t\t\t\t\t//this._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_unique(this._data[ t ? 'core' : 'checkbox' ].selected.concat(obj.children_d));\n\t\t\t\t\t\t\t\tvar selectedIds = this._cascade_new_checked_state(obj.id, true);\n\t\t\t\t\t\t\t\tvar temp = obj.children_d.concat(obj.id);\n\t\t\t\t\t\t\t\tfor (i = 0, j = temp.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\tif (selectedIds.indexOf(temp[i]) > -1) {\n\t\t\t\t\t\t\t\t\t\tsel[temp[i]] = true;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tdelete sel[temp[i]];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// apply up\n\t\t\t\t\t\t\tif(s.indexOf('up') !== -1) {\n\t\t\t\t\t\t\t\twhile(par && par.id !== $.jstree.root) {\n\t\t\t\t\t\t\t\t\tc = 0;\n\t\t\t\t\t\t\t\t\tfor(i = 0, j = par.children.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\t\tc += m[par.children[i]].state[ t ? 'selected' : 'checked' ];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif(c === j) {\n\t\t\t\t\t\t\t\t\t\tpar.state[ t ? 'selected' : 'checked' ] = true;\n\t\t\t\t\t\t\t\t\t\tsel[par.id] = true;\n\t\t\t\t\t\t\t\t\t\t//this._data[ t ? 'core' : 'checkbox' ].selected.push(par.id);\n\t\t\t\t\t\t\t\t\t\ttmp = this.get_node(par, true);\n\t\t\t\t\t\t\t\t\t\tif(tmp && tmp.length) {\n\t\t\t\t\t\t\t\t\t\t\ttmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tpar = this.get_node(par.parent);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tcur = [];\n\t\t\t\t\t\t\tfor (i in sel) {\n\t\t\t\t\t\t\t\tif (sel.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\tcur.push(i);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tthis._data[ t ? 'core' : 'checkbox' ].selected = cur;\n\t\t\t\t\t\t}.bind(this))\n\t\t\t\t\t.on(this.settings.checkbox.tie_selection ? 'deselect_all.jstree' : 'uncheck_all.jstree', function (e, data) {\n\t\t\t\t\t\t\tvar obj = this.get_node($.jstree.root),\n\t\t\t\t\t\t\t\tm = this._model.data,\n\t\t\t\t\t\t\t\ti, j, tmp;\n\t\t\t\t\t\t\tfor(i = 0, j = obj.children_d.length; i < j; i++) {\n\t\t\t\t\t\t\t\ttmp = m[obj.children_d[i]];\n\t\t\t\t\t\t\t\tif(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) {\n\t\t\t\t\t\t\t\t\ttmp.original.state.undetermined = false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}.bind(this))\n\t\t\t\t\t.on(this.settings.checkbox.tie_selection ? 'deselect_node.jstree' : 'uncheck_node.jstree', function (e, data) {\n\t\t\t\t\t\t\tvar self = this,\n\t\t\t\t\t\t\t\tobj = data.node,\n\t\t\t\t\t\t\t\tdom = this.get_node(obj, true),\n\t\t\t\t\t\t\t\ti, j, tmp, s = this.settings.checkbox.cascade, t = this.settings.checkbox.tie_selection,\n\t\t\t\t\t\t\t\tcur = this._data[ t ? 'core' : 'checkbox' ].selected, sel = {},\n\t\t\t\t\t\t\t\tstillSelectedIds = [],\n\t\t\t\t\t\t\t\tallIds = obj.children_d.concat(obj.id);\n\n\t\t\t\t\t\t\t// apply down\n\t\t\t\t\t\t\tif(s.indexOf('down') !== -1) {\n\t\t\t\t\t\t\t\tvar selectedIds = this._cascade_new_checked_state(obj.id, false);\n\n\t\t\t\t\t\t\t\tcur = $.vakata.array_filter(cur, function(id) {\n\t\t\t\t\t\t\t\t\treturn allIds.indexOf(id) === -1 || selectedIds.indexOf(id) > -1;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// only apply up if cascade up is enabled and if this node is not selected\n\t\t\t\t\t\t\t// (if all child nodes are disabled and cascade_to_disabled === false then this node will till be selected).\n\t\t\t\t\t\t\tif(s.indexOf('up') !== -1 && cur.indexOf(obj.id) === -1) {\n\t\t\t\t\t\t\t\tfor(i = 0, j = obj.parents.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\ttmp = this._model.data[obj.parents[i]];\n\t\t\t\t\t\t\t\t\ttmp.state[ t ? 'selected' : 'checked' ] = false;\n\t\t\t\t\t\t\t\t\tif(tmp && tmp.original && tmp.original.state && tmp.original.state.undetermined) {\n\t\t\t\t\t\t\t\t\t\ttmp.original.state.undetermined = false;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\ttmp = this.get_node(obj.parents[i], true);\n\t\t\t\t\t\t\t\t\tif(tmp && tmp.length) {\n\t\t\t\t\t\t\t\t\t\ttmp.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tcur = $.vakata.array_filter(cur, function(id) {\n\t\t\t\t\t\t\t\t\treturn obj.parents.indexOf(id) === -1;\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tthis._data[ t ? 'core' : 'checkbox' ].selected = cur;\n\t\t\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t\tif(this.settings.checkbox.cascade.indexOf('up') !== -1) {\n\t\t\t\tthis.element\n\t\t\t\t\t.on('delete_node.jstree', function (e, data) {\n\t\t\t\t\t\t\t// apply up (whole handler)\n\t\t\t\t\t\t\tvar p = this.get_node(data.parent),\n\t\t\t\t\t\t\t\tm = this._model.data,\n\t\t\t\t\t\t\t\ti, j, c, tmp, t = this.settings.checkbox.tie_selection;\n\t\t\t\t\t\t\twhile(p && p.id !== $.jstree.root && !p.state[ t ? 'selected' : 'checked' ]) {\n\t\t\t\t\t\t\t\tc = 0;\n\t\t\t\t\t\t\t\tfor(i = 0, j = p.children.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\tc += m[p.children[i]].state[ t ? 'selected' : 'checked' ];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif(j > 0 && c === j) {\n\t\t\t\t\t\t\t\t\tp.state[ t ? 'selected' : 'checked' ] = true;\n\t\t\t\t\t\t\t\t\tthis._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);\n\t\t\t\t\t\t\t\t\ttmp = this.get_node(p, true);\n\t\t\t\t\t\t\t\t\tif(tmp && tmp.length) {\n\t\t\t\t\t\t\t\t\t\ttmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tp = this.get_node(p.parent);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}.bind(this))\n\t\t\t\t\t.on('move_node.jstree', function (e, data) {\n\t\t\t\t\t\t\t// apply up (whole handler)\n\t\t\t\t\t\t\tvar is_multi = data.is_multi,\n\t\t\t\t\t\t\t\told_par = data.old_parent,\n\t\t\t\t\t\t\t\tnew_par = this.get_node(data.parent),\n\t\t\t\t\t\t\t\tm = this._model.data,\n\t\t\t\t\t\t\t\tp, c, i, j, tmp, t = this.settings.checkbox.tie_selection;\n\t\t\t\t\t\t\tif(!is_multi) {\n\t\t\t\t\t\t\t\tp = this.get_node(old_par);\n\t\t\t\t\t\t\t\twhile(p && p.id !== $.jstree.root && !p.state[ t ? 'selected' : 'checked' ]) {\n\t\t\t\t\t\t\t\t\tc = 0;\n\t\t\t\t\t\t\t\t\tfor(i = 0, j = p.children.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\t\tc += m[p.children[i]].state[ t ? 'selected' : 'checked' ];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif(j > 0 && c === j) {\n\t\t\t\t\t\t\t\t\t\tp.state[ t ? 'selected' : 'checked' ] = true;\n\t\t\t\t\t\t\t\t\t\tthis._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);\n\t\t\t\t\t\t\t\t\t\ttmp = this.get_node(p, true);\n\t\t\t\t\t\t\t\t\t\tif(tmp && tmp.length) {\n\t\t\t\t\t\t\t\t\t\t\ttmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tp = this.get_node(p.parent);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tp = new_par;\n\t\t\t\t\t\t\twhile(p && p.id !== $.jstree.root) {\n\t\t\t\t\t\t\t\tc = 0;\n\t\t\t\t\t\t\t\tfor(i = 0, j = p.children.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\tc += m[p.children[i]].state[ t ? 'selected' : 'checked' ];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif(c === j) {\n\t\t\t\t\t\t\t\t\tif(!p.state[ t ? 'selected' : 'checked' ]) {\n\t\t\t\t\t\t\t\t\t\tp.state[ t ? 'selected' : 'checked' ] = true;\n\t\t\t\t\t\t\t\t\t\tthis._data[ t ? 'core' : 'checkbox' ].selected.push(p.id);\n\t\t\t\t\t\t\t\t\t\ttmp = this.get_node(p, true);\n\t\t\t\t\t\t\t\t\t\tif(tmp && tmp.length) {\n\t\t\t\t\t\t\t\t\t\t\ttmp.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tif(p.state[ t ? 'selected' : 'checked' ]) {\n\t\t\t\t\t\t\t\t\t\tp.state[ t ? 'selected' : 'checked' ] = false;\n\t\t\t\t\t\t\t\t\t\tthis._data[ t ? 'core' : 'checkbox' ].selected = $.vakata.array_remove_item(this._data[ t ? 'core' : 'checkbox' ].selected, p.id);\n\t\t\t\t\t\t\t\t\t\ttmp = this.get_node(p, true);\n\t\t\t\t\t\t\t\t\t\tif(tmp && tmp.length) {\n\t\t\t\t\t\t\t\t\t\t\ttmp.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tp = this.get_node(p.parent);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t};\n\t\t/**\n\t\t * get an array of all nodes whose state is \"undetermined\"\n\t\t * @name get_undetermined([full])\n\t\t * @param {boolean} full: if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned\n\t\t * @return {Array}\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.get_undetermined = function (full) {\n\t\t\tif (this.settings.checkbox.cascade.indexOf('undetermined') === -1) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tvar i, j, k, l, o = {}, m = this._model.data, t = this.settings.checkbox.tie_selection, s = this._data[ t ? 'core' : 'checkbox' ].selected, p = [], tt = this, r = [];\n\t\t\tfor(i = 0, j = s.length; i < j; i++) {\n\t\t\t\tif(m[s[i]] && m[s[i]].parents) {\n\t\t\t\t\tfor(k = 0, l = m[s[i]].parents.length; k < l; k++) {\n\t\t\t\t\t\tif(o[m[s[i]].parents[k]] !== undefined) {\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(m[s[i]].parents[k] !== $.jstree.root) {\n\t\t\t\t\t\t\to[m[s[i]].parents[k]] = true;\n\t\t\t\t\t\t\tp.push(m[s[i]].parents[k]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t// attempt for server side undetermined state\n\t\t\tthis.element.find('.jstree-closed').not(':has(.jstree-children)')\n\t\t\t\t.each(function () {\n\t\t\t\t\tvar tmp = tt.get_node(this), tmp2;\n\t\t\t\t\t\n\t\t\t\t\tif(!tmp) { return; }\n\t\t\t\t\t\n\t\t\t\t\tif(!tmp.state.loaded) {\n\t\t\t\t\t\tif(tmp.original && tmp.original.state && tmp.original.state.undetermined && tmp.original.state.undetermined === true) {\n\t\t\t\t\t\t\tif(o[tmp.id] === undefined && tmp.id !== $.jstree.root) {\n\t\t\t\t\t\t\t\to[tmp.id] = true;\n\t\t\t\t\t\t\t\tp.push(tmp.id);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfor(k = 0, l = tmp.parents.length; k < l; k++) {\n\t\t\t\t\t\t\t\tif(o[tmp.parents[k]] === undefined && tmp.parents[k] !== $.jstree.root) {\n\t\t\t\t\t\t\t\t\to[tmp.parents[k]] = true;\n\t\t\t\t\t\t\t\t\tp.push(tmp.parents[k]);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\tfor(i = 0, j = tmp.children_d.length; i < j; i++) {\n\t\t\t\t\t\t\ttmp2 = m[tmp.children_d[i]];\n\t\t\t\t\t\t\tif(!tmp2.state.loaded && tmp2.original && tmp2.original.state && tmp2.original.state.undetermined && tmp2.original.state.undetermined === true) {\n\t\t\t\t\t\t\t\tif(o[tmp2.id] === undefined && tmp2.id !== $.jstree.root) {\n\t\t\t\t\t\t\t\t\to[tmp2.id] = true;\n\t\t\t\t\t\t\t\t\tp.push(tmp2.id);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tfor(k = 0, l = tmp2.parents.length; k < l; k++) {\n\t\t\t\t\t\t\t\t\tif(o[tmp2.parents[k]] === undefined && tmp2.parents[k] !== $.jstree.root) {\n\t\t\t\t\t\t\t\t\t\to[tmp2.parents[k]] = true;\n\t\t\t\t\t\t\t\t\t\tp.push(tmp2.parents[k]);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\tfor (i = 0, j = p.length; i < j; i++) {\n\t\t\t\tif(!m[p[i]].state[ t ? 'selected' : 'checked' ]) {\n\t\t\t\t\tr.push(full ? m[p[i]] : p[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn r;\n\t\t};\n\t\t/**\n\t\t * set the undetermined state where and if necessary. Used internally.\n\t\t * @private\n\t\t * @name _undetermined()\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis._undetermined = function () {\n\t\t\tif(this.element === null) { return; }\n\t\t\tvar p = this.get_undetermined(false), i, j, s;\n\n\t\t\tthis.element.find('.jstree-undetermined').removeClass('jstree-undetermined');\n\t\t\tfor (i = 0, j = p.length; i < j; i++) {\n\t\t\t\ts = this.get_node(p[i], true);\n\t\t\t\tif(s && s.length) {\n\t\t\t\t\ts.children('.jstree-anchor').children('.jstree-checkbox').addClass('jstree-undetermined');\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\tthis.redraw_node = function(obj, deep, is_callback, force_render) {\n\t\t\tobj = parent.redraw_node.apply(this, arguments);\n\t\t\tif(obj) {\n\t\t\t\tvar i, j, tmp = null, icon = null;\n\t\t\t\tfor(i = 0, j = obj.childNodes.length; i < j; i++) {\n\t\t\t\t\tif(obj.childNodes[i] && obj.childNodes[i].className && obj.childNodes[i].className.indexOf(\"jstree-anchor\") !== -1) {\n\t\t\t\t\t\ttmp = obj.childNodes[i];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(tmp) {\n\t\t\t\t\tif(!this.settings.checkbox.tie_selection && this._model.data[obj.id].state.checked) { tmp.className += ' jstree-checked'; }\n\t\t\t\t\ticon = _i.cloneNode(false);\n\t\t\t\t\tif(this._model.data[obj.id].state.checkbox_disabled) { icon.className += ' jstree-checkbox-disabled'; }\n\t\t\t\t\ttmp.insertBefore(icon, tmp.childNodes[0]);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!is_callback && this.settings.checkbox.cascade.indexOf('undetermined') !== -1) {\n\t\t\t\tif(this._data.checkbox.uto) { clearTimeout(this._data.checkbox.uto); }\n\t\t\t\tthis._data.checkbox.uto = setTimeout(this._undetermined.bind(this), 50);\n\t\t\t}\n\t\t\treturn obj;\n\t\t};\n\t\t/**\n\t\t * show the node checkbox icons\n\t\t * @name show_checkboxes()\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.show_checkboxes = function () { this._data.core.themes.checkboxes = true; this.get_container_ul().removeClass(\"jstree-no-checkboxes\"); };\n\t\t/**\n\t\t * hide the node checkbox icons\n\t\t * @name hide_checkboxes()\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.hide_checkboxes = function () { this._data.core.themes.checkboxes = false; this.get_container_ul().addClass(\"jstree-no-checkboxes\"); };\n\t\t/**\n\t\t * toggle the node icons\n\t\t * @name toggle_checkboxes()\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.toggle_checkboxes = function () { if(this._data.core.themes.checkboxes) { this.hide_checkboxes(); } else { this.show_checkboxes(); } };\n\t\t/**\n\t\t * checks if a node is in an undetermined state\n\t\t * @name is_undetermined(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {Boolean}\n\t\t */\n\t\tthis.is_undetermined = function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\tvar s = this.settings.checkbox.cascade, i, j, t = this.settings.checkbox.tie_selection, d = this._data[ t ? 'core' : 'checkbox' ].selected, m = this._model.data;\n\t\t\tif(!obj || obj.state[ t ? 'selected' : 'checked' ] === true || s.indexOf('undetermined') === -1 || (s.indexOf('down') === -1 && s.indexOf('up') === -1)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(!obj.state.loaded && obj.original.state.undetermined === true) {\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tfor(i = 0, j = obj.children_d.length; i < j; i++) {\n\t\t\t\tif($.inArray(obj.children_d[i], d) !== -1 || (!m[obj.children_d[i]].state.loaded && m[obj.children_d[i]].original.state.undetermined)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\t\t/**\n\t\t * disable a node's checkbox\n\t\t * @name disable_checkbox(obj)\n\t\t * @param {mixed} obj an array can be used too\n\t\t * @trigger disable_checkbox.jstree\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.disable_checkbox = function (obj) {\n\t\t\tvar t1, t2, dom;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.disable_checkbox(obj[t1]);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdom = this.get_node(obj, true);\n\t\t\tif(!obj.state.checkbox_disabled) {\n\t\t\t\tobj.state.checkbox_disabled = true;\n\t\t\t\tif(dom && dom.length) {\n\t\t\t\t\tdom.children('.jstree-anchor').children('.jstree-checkbox').addClass('jstree-checkbox-disabled');\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * triggered when an node's checkbox is disabled\n\t\t\t\t * @event\n\t\t\t\t * @name disable_checkbox.jstree\n\t\t\t\t * @param {Object} node\n\t\t\t\t * @plugin checkbox\n\t\t\t\t */\n\t\t\t\tthis.trigger('disable_checkbox', { 'node' : obj });\n\t\t\t}\n\t\t};\n\t\t/**\n\t\t * enable a node's checkbox\n\t\t * @name enable_checkbox(obj)\n\t\t * @param {mixed} obj an array can be used too\n\t\t * @trigger enable_checkbox.jstree\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.enable_checkbox = function (obj) {\n\t\t\tvar t1, t2, dom;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.enable_checkbox(obj[t1]);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdom = this.get_node(obj, true);\n\t\t\tif(obj.state.checkbox_disabled) {\n\t\t\t\tobj.state.checkbox_disabled = false;\n\t\t\t\tif(dom && dom.length) {\n\t\t\t\t\tdom.children('.jstree-anchor').children('.jstree-checkbox').removeClass('jstree-checkbox-disabled');\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * triggered when an node's checkbox is enabled\n\t\t\t\t * @event\n\t\t\t\t * @name enable_checkbox.jstree\n\t\t\t\t * @param {Object} node\n\t\t\t\t * @plugin checkbox\n\t\t\t\t */\n\t\t\t\tthis.trigger('enable_checkbox', { 'node' : obj });\n\t\t\t}\n\t\t};\n\n\t\tthis.activate_node = function (obj, e) {\n\t\t\tif($(e.target).hasClass('jstree-checkbox-disabled')) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(this.settings.checkbox.tie_selection && (this.settings.checkbox.whole_node || $(e.target).hasClass('jstree-checkbox'))) {\n\t\t\t\te.ctrlKey = true;\n\t\t\t}\n\t\t\tif(this.settings.checkbox.tie_selection || (!this.settings.checkbox.whole_node && !$(e.target).hasClass('jstree-checkbox'))) {\n\t\t\t\treturn parent.activate_node.call(this, obj, e);\n\t\t\t}\n\t\t\tif(this.is_disabled(obj)) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif(this.is_checked(obj)) {\n\t\t\t\tthis.uncheck_node(obj, e);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.check_node(obj, e);\n\t\t\t}\n\t\t\tthis.trigger('activate_node', { 'node' : this.get_node(obj) });\n\t\t};\n\n\t\t/**\n\t\t * Cascades checked state to a node and all its descendants. This function does NOT affect hidden and disabled nodes (or their descendants).\n\t\t * However if these unaffected nodes are already selected their ids will be included in the returned array.\n\t\t * @private\n\t\t * @name _cascade_new_checked_state(id, checkedState)\n\t\t * @param {string} id the node ID\n\t\t * @param {bool} checkedState should the nodes be checked or not\n\t\t * @returns {Array} Array of all node id's (in this tree branch) that are checked.\n\t\t */\n\t\tthis._cascade_new_checked_state = function (id, checkedState) {\n\t\t\tvar self = this;\n\t\t\tvar t = this.settings.checkbox.tie_selection;\n\t\t\tvar node = this._model.data[id];\n\t\t\tvar selectedNodeIds = [];\n\t\t\tvar selectedChildrenIds = [], i, j, selectedChildIds;\n\n\t\t\tif (\n\t\t\t\t(this.settings.checkbox.cascade_to_disabled || !node.state.disabled) &&\n\t\t\t\t(this.settings.checkbox.cascade_to_hidden || !node.state.hidden)\n\t\t\t) {\n\t\t\t\t//First try and check/uncheck the children\n\t\t\t\tif (node.children) {\n\t\t\t\t\tfor (i = 0, j = node.children.length; i < j; i++) {\n\t\t\t\t\t\tvar childId = node.children[i];\n\t\t\t\t\t\tselectedChildIds = self._cascade_new_checked_state(childId, checkedState);\n\t\t\t\t\t\tselectedNodeIds = selectedNodeIds.concat(selectedChildIds);\n\t\t\t\t\t\tif (selectedChildIds.indexOf(childId) > -1) {\n\t\t\t\t\t\t\tselectedChildrenIds.push(childId);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tvar dom = self.get_node(node, true);\n\n\t\t\t\t//A node's state is undetermined if some but not all of it's children are checked/selected .\n\t\t\t\tvar undetermined = selectedChildrenIds.length > 0 && selectedChildrenIds.length < node.children.length;\n\n\t\t\t\tif(node.original && node.original.state && node.original.state.undetermined) {\n\t\t\t\t\tnode.original.state.undetermined = undetermined;\n\t\t\t\t}\n\n\t\t\t\t//If a node is undetermined then remove selected class\n\t\t\t\tif (undetermined) {\n\t\t\t\t\tnode.state[ t ? 'selected' : 'checked' ] = false;\n\t\t\t\t\tdom.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');\n\t\t\t\t}\n\t\t\t\t//Otherwise, if the checkedState === true (i.e. the node is being checked now) and all of the node's children are checked (if it has any children),\n\t\t\t\t//check the node and style it correctly.\n\t\t\t\telse if (checkedState && selectedChildrenIds.length === node.children.length) {\n\t\t\t\t\tnode.state[ t ? 'selected' : 'checked' ] = checkedState;\n\t\t\t\t\tselectedNodeIds.push(node.id);\n\n\t\t\t\t\tdom.attr('aria-selected', true).children('.jstree-anchor').addClass(t ? 'jstree-clicked' : 'jstree-checked');\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tnode.state[ t ? 'selected' : 'checked' ] = false;\n\t\t\t\t\tdom.attr('aria-selected', false).children('.jstree-anchor').removeClass(t ? 'jstree-clicked' : 'jstree-checked');\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tselectedChildIds = this.get_checked_descendants(id);\n\n\t\t\t\tif (node.state[ t ? 'selected' : 'checked' ]) {\n\t\t\t\t\tselectedChildIds.push(node.id);\n\t\t\t\t}\n\n\t\t\t\tselectedNodeIds = selectedNodeIds.concat(selectedChildIds);\n\t\t\t}\n\n\t\t\treturn selectedNodeIds;\n\t\t};\n\n\t\t/**\n\t\t * Gets ids of nodes selected in branch (of tree) specified by id (does not include the node specified by id)\n\t\t * @name get_checked_descendants(obj)\n\t\t * @param {string} id the node ID\n\t\t * @return {Array} array of IDs\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.get_checked_descendants = function (id) {\n\t\t\tvar self = this;\n\t\t\tvar t = self.settings.checkbox.tie_selection;\n\t\t\tvar node = self._model.data[id];\n\n\t\t\treturn $.vakata.array_filter(node.children_d, function(_id) {\n\t\t\t\treturn self._model.data[_id].state[ t ? 'selected' : 'checked' ];\n\t\t\t});\n\t\t};\n\n\t\t/**\n\t\t * check a node (only if tie_selection in checkbox settings is false, otherwise select_node will be called internally)\n\t\t * @name check_node(obj)\n\t\t * @param {mixed} obj an array can be used to check multiple nodes\n\t\t * @trigger check_node.jstree\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.check_node = function (obj, e) {\n\t\t\tif(this.settings.checkbox.tie_selection) { return this.select_node(obj, false, true, e); }\n\t\t\tvar dom, t1, t2, th;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.check_node(obj[t1], e);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdom = this.get_node(obj, true);\n\t\t\tif(!obj.state.checked) {\n\t\t\t\tobj.state.checked = true;\n\t\t\t\tthis._data.checkbox.selected.push(obj.id);\n\t\t\t\tif(dom && dom.length) {\n\t\t\t\t\tdom.children('.jstree-anchor').addClass('jstree-checked');\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * triggered when an node is checked (only if tie_selection in checkbox settings is false)\n\t\t\t\t * @event\n\t\t\t\t * @name check_node.jstree\n\t\t\t\t * @param {Object} node\n\t\t\t\t * @param {Array} selected the current selection\n\t\t\t\t * @param {Object} event the event (if any) that triggered this check_node\n\t\t\t\t * @plugin checkbox\n\t\t\t\t */\n\t\t\t\tthis.trigger('check_node', { 'node' : obj, 'selected' : this._data.checkbox.selected, 'event' : e });\n\t\t\t}\n\t\t};\n\t\t/**\n\t\t * uncheck a node (only if tie_selection in checkbox settings is false, otherwise deselect_node will be called internally)\n\t\t * @name uncheck_node(obj)\n\t\t * @param {mixed} obj an array can be used to uncheck multiple nodes\n\t\t * @trigger uncheck_node.jstree\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.uncheck_node = function (obj, e) {\n\t\t\tif(this.settings.checkbox.tie_selection) { return this.deselect_node(obj, false, e); }\n\t\t\tvar t1, t2, dom;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.uncheck_node(obj[t1], e);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tdom = this.get_node(obj, true);\n\t\t\tif(obj.state.checked) {\n\t\t\t\tobj.state.checked = false;\n\t\t\t\tthis._data.checkbox.selected = $.vakata.array_remove_item(this._data.checkbox.selected, obj.id);\n\t\t\t\tif(dom.length) {\n\t\t\t\t\tdom.children('.jstree-anchor').removeClass('jstree-checked');\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * triggered when an node is unchecked (only if tie_selection in checkbox settings is false)\n\t\t\t\t * @event\n\t\t\t\t * @name uncheck_node.jstree\n\t\t\t\t * @param {Object} node\n\t\t\t\t * @param {Array} selected the current selection\n\t\t\t\t * @param {Object} event the event (if any) that triggered this uncheck_node\n\t\t\t\t * @plugin checkbox\n\t\t\t\t */\n\t\t\t\tthis.trigger('uncheck_node', { 'node' : obj, 'selected' : this._data.checkbox.selected, 'event' : e });\n\t\t\t}\n\t\t};\n\t\t\n\t\t/**\n\t\t * checks all nodes in the tree (only if tie_selection in checkbox settings is false, otherwise select_all will be called internally)\n\t\t * @name check_all()\n\t\t * @trigger check_all.jstree, changed.jstree\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.check_all = function () {\n\t\t\tif(this.settings.checkbox.tie_selection) { return this.select_all(); }\n\t\t\tvar tmp = this._data.checkbox.selected.concat([]), i, j;\n\t\t\tthis._data.checkbox.selected = this._model.data[$.jstree.root].children_d.concat();\n\t\t\tfor(i = 0, j = this._data.checkbox.selected.length; i < j; i++) {\n\t\t\t\tif(this._model.data[this._data.checkbox.selected[i]]) {\n\t\t\t\t\tthis._model.data[this._data.checkbox.selected[i]].state.checked = true;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.redraw(true);\n\t\t\t/**\n\t\t\t * triggered when all nodes are checked (only if tie_selection in checkbox settings is false)\n\t\t\t * @event\n\t\t\t * @name check_all.jstree\n\t\t\t * @param {Array} selected the current selection\n\t\t\t * @plugin checkbox\n\t\t\t */\n\t\t\tthis.trigger('check_all', { 'selected' : this._data.checkbox.selected });\n\t\t};\n\t\t/**\n\t\t * uncheck all checked nodes (only if tie_selection in checkbox settings is false, otherwise deselect_all will be called internally)\n\t\t * @name uncheck_all()\n\t\t * @trigger uncheck_all.jstree\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.uncheck_all = function () {\n\t\t\tif(this.settings.checkbox.tie_selection) { return this.deselect_all(); }\n\t\t\tvar tmp = this._data.checkbox.selected.concat([]), i, j;\n\t\t\tfor(i = 0, j = this._data.checkbox.selected.length; i < j; i++) {\n\t\t\t\tif(this._model.data[this._data.checkbox.selected[i]]) {\n\t\t\t\t\tthis._model.data[this._data.checkbox.selected[i]].state.checked = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._data.checkbox.selected = [];\n\t\t\tthis.element.find('.jstree-checked').removeClass('jstree-checked');\n\t\t\t/**\n\t\t\t * triggered when all nodes are unchecked (only if tie_selection in checkbox settings is false)\n\t\t\t * @event\n\t\t\t * @name uncheck_all.jstree\n\t\t\t * @param {Object} node the previous selection\n\t\t\t * @param {Array} selected the current selection\n\t\t\t * @plugin checkbox\n\t\t\t */\n\t\t\tthis.trigger('uncheck_all', { 'selected' : this._data.checkbox.selected, 'node' : tmp });\n\t\t};\n\t\t/**\n\t\t * checks if a node is checked (if tie_selection is on in the settings this function will return the same as is_selected)\n\t\t * @name is_checked(obj)\n\t\t * @param {mixed} obj\n\t\t * @return {Boolean}\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.is_checked = function (obj) {\n\t\t\tif(this.settings.checkbox.tie_selection) { return this.is_selected(obj); }\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) { return false; }\n\t\t\treturn obj.state.checked;\n\t\t};\n\t\t/**\n\t\t * get an array of all checked nodes (if tie_selection is on in the settings this function will return the same as get_selected)\n\t\t * @name get_checked([full])\n\t\t * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned\n\t\t * @return {Array}\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.get_checked = function (full) {\n\t\t\tif(this.settings.checkbox.tie_selection) { return this.get_selected(full); }\n\t\t\treturn full ? $.map(this._data.checkbox.selected, function (i) { return this.get_node(i); }.bind(this)) : this._data.checkbox.selected.slice();\n\t\t};\n\t\t/**\n\t\t * get an array of all top level checked nodes (ignoring children of checked nodes) (if tie_selection is on in the settings this function will return the same as get_top_selected)\n\t\t * @name get_top_checked([full])\n\t\t * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned\n\t\t * @return {Array}\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.get_top_checked = function (full) {\n\t\t\tif(this.settings.checkbox.tie_selection) { return this.get_top_selected(full); }\n\t\t\tvar tmp = this.get_checked(true),\n\t\t\t\tobj = {}, i, j, k, l;\n\t\t\tfor(i = 0, j = tmp.length; i < j; i++) {\n\t\t\t\tobj[tmp[i].id] = tmp[i];\n\t\t\t}\n\t\t\tfor(i = 0, j = tmp.length; i < j; i++) {\n\t\t\t\tfor(k = 0, l = tmp[i].children_d.length; k < l; k++) {\n\t\t\t\t\tif(obj[tmp[i].children_d[k]]) {\n\t\t\t\t\t\tdelete obj[tmp[i].children_d[k]];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\ttmp = [];\n\t\t\tfor(i in obj) {\n\t\t\t\tif(obj.hasOwnProperty(i)) {\n\t\t\t\t\ttmp.push(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn full ? $.map(tmp, function (i) { return this.get_node(i); }.bind(this)) : tmp;\n\t\t};\n\t\t/**\n\t\t * get an array of all bottom level checked nodes (ignoring selected parents) (if tie_selection is on in the settings this function will return the same as get_bottom_selected)\n\t\t * @name get_bottom_checked([full])\n\t\t * @param {mixed} full if set to `true` the returned array will consist of the full node objects, otherwise - only IDs will be returned\n\t\t * @return {Array}\n\t\t * @plugin checkbox\n\t\t */\n\t\tthis.get_bottom_checked = function (full) {\n\t\t\tif(this.settings.checkbox.tie_selection) { return this.get_bottom_selected(full); }\n\t\t\tvar tmp = this.get_checked(true),\n\t\t\t\tobj = [], i, j;\n\t\t\tfor(i = 0, j = tmp.length; i < j; i++) {\n\t\t\t\tif(!tmp[i].children.length) {\n\t\t\t\t\tobj.push(tmp[i].id);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn full ? $.map(obj, function (i) { return this.get_node(i); }.bind(this)) : obj;\n\t\t};\n\t\tthis.load_node = function (obj, callback) {\n\t\t\tvar k, l, i, j, c, tmp;\n\t\t\tif(!$.vakata.is_array(obj) && !this.settings.checkbox.tie_selection) {\n\t\t\t\ttmp = this.get_node(obj);\n\t\t\t\tif(tmp && tmp.state.loaded) {\n\t\t\t\t\tfor(k = 0, l = tmp.children_d.length; k < l; k++) {\n\t\t\t\t\t\tif(this._model.data[tmp.children_d[k]].state.checked) {\n\t\t\t\t\t\t\tc = true;\n\t\t\t\t\t\t\tthis._data.checkbox.selected = $.vakata.array_remove_item(this._data.checkbox.selected, tmp.children_d[k]);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn parent.load_node.apply(this, arguments);\n\t\t};\n\t\tthis.get_state = function () {\n\t\t\tvar state = parent.get_state.apply(this, arguments);\n\t\t\tif(this.settings.checkbox.tie_selection) { return state; }\n\t\t\tstate.checkbox = this._data.checkbox.selected.slice();\n\t\t\treturn state;\n\t\t};\n\t\tthis.set_state = function (state, callback) {\n\t\t\tvar res = parent.set_state.apply(this, arguments);\n\t\t\tif(res && state.checkbox) {\n\t\t\t\tif(!this.settings.checkbox.tie_selection) {\n\t\t\t\t\tthis.uncheck_all();\n\t\t\t\t\tvar _this = this;\n\t\t\t\t\t$.each(state.checkbox, function (i, v) {\n\t\t\t\t\t\t_this.check_node(v);\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tdelete state.checkbox;\n\t\t\t\tthis.set_state(state, callback);\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\treturn res;\n\t\t};\n\t\tthis.refresh = function (skip_loading, forget_state) {\n\t\t\tif(this.settings.checkbox.tie_selection) {\n\t\t\t\tthis._data.checkbox.selected = [];\n\t\t\t}\n\t\t\treturn parent.refresh.apply(this, arguments);\n\t\t};\n\t};\n\n\t// include the checkbox plugin by default\n\t// $.jstree.defaults.plugins.push(\"checkbox\");\n\n\n/**\n * ### Conditionalselect plugin\n *\n * This plugin allows defining a callback to allow or deny node selection by user input (activate node method).\n */\n\n\t/**\n\t * a callback (function) which is invoked in the instance's scope and receives two arguments - the node and the event that triggered the `activate_node` call. Returning false prevents working with the node, returning true allows invoking activate_node. Defaults to returning `true`.\n\t * @name $.jstree.defaults.checkbox.visible\n\t * @plugin checkbox\n\t */\n\t$.jstree.defaults.conditionalselect = function () { return true; };\n\t$.jstree.plugins.conditionalselect = function (options, parent) {\n\t\t// own function\n\t\tthis.activate_node = function (obj, e) {\n\t\t\tif(this.settings.conditionalselect.call(this, this.get_node(obj), e)) {\n\t\t\t\treturn parent.activate_node.call(this, obj, e);\n\t\t\t}\n\t\t};\n\t};\n\n\n/**\n * ### Contextmenu plugin\n *\n * Shows a context menu when a node is right-clicked.\n */\n\n\t/**\n\t * stores all defaults for the contextmenu plugin\n\t * @name $.jstree.defaults.contextmenu\n\t * @plugin contextmenu\n\t */\n\t$.jstree.defaults.contextmenu = {\n\t\t/**\n\t\t * a boolean indicating if the node should be selected when the context menu is invoked on it. Defaults to `true`.\n\t\t * @name $.jstree.defaults.contextmenu.select_node\n\t\t * @plugin contextmenu\n\t\t */\n\t\tselect_node : true,\n\t\t/**\n\t\t * a boolean indicating if the menu should be shown aligned with the node. Defaults to `true`, otherwise the mouse coordinates are used.\n\t\t * @name $.jstree.defaults.contextmenu.show_at_node\n\t\t * @plugin contextmenu\n\t\t */\n\t\tshow_at_node : true,\n\t\t/**\n\t\t * an object of actions, or a function that accepts a node and a callback function and calls the callback function with an object of actions available for that node (you can also return the items too).\n\t\t *\n\t\t * Each action consists of a key (a unique name) and a value which is an object with the following properties (only label and action are required). Once a menu item is activated the `action` function will be invoked with an object containing the following keys: item - the contextmenu item definition as seen below, reference - the DOM node that was used (the tree node), element - the contextmenu DOM element, position - an object with x/y properties indicating the position of the menu.\n\t\t *\n\t\t * * `separator_before` - a boolean indicating if there should be a separator before this item\n\t\t * * `separator_after` - a boolean indicating if there should be a separator after this item\n\t\t * * `_disabled` - a boolean indicating if this action should be disabled\n\t\t * * `label` - a string - the name of the action (could be a function returning a string)\n\t\t * * `title` - a string - an optional tooltip for the item\n\t\t * * `action` - a function to be executed if this item is chosen, the function will receive \n\t\t * * `icon` - a string, can be a path to an icon or a className, if using an image that is in the current directory use a `./` prefix, otherwise it will be detected as a class\n\t\t * * `shortcut` - keyCode which will trigger the action if the menu is open (for example `113` for rename, which equals F2)\n\t\t * * `shortcut_label` - shortcut label (like for example `F2` for rename)\n\t\t * * `submenu` - an object with the same structure as $.jstree.defaults.contextmenu.items which can be used to create a submenu - each key will be rendered as a separate option in a submenu that will appear once the current item is hovered\n\t\t *\n\t\t * @name $.jstree.defaults.contextmenu.items\n\t\t * @plugin contextmenu\n\t\t */\n\t\titems : function (o, cb) { // Could be an object directly\n\t\t\treturn {\n\t\t\t\t\"create\" : {\n\t\t\t\t\t\"separator_before\"\t: false,\n\t\t\t\t\t\"separator_after\"\t: true,\n\t\t\t\t\t\"_disabled\"\t\t\t: false, //(this.check(\"create_node\", data.reference, {}, \"last\")),\n\t\t\t\t\t\"label\"\t\t\t\t: \"Create\",\n\t\t\t\t\t\"action\"\t\t\t: function (data) {\n\t\t\t\t\t\tvar inst = $.jstree.reference(data.reference),\n\t\t\t\t\t\t\tobj = inst.get_node(data.reference);\n\t\t\t\t\t\tinst.create_node(obj, {}, \"last\", function (new_node) {\n\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\tinst.edit(new_node);\n\t\t\t\t\t\t\t} catch (ex) {\n\t\t\t\t\t\t\t\tsetTimeout(function () { inst.edit(new_node); },0);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"rename\" : {\n\t\t\t\t\t\"separator_before\"\t: false,\n\t\t\t\t\t\"separator_after\"\t: false,\n\t\t\t\t\t\"_disabled\"\t\t\t: false, //(this.check(\"rename_node\", data.reference, this.get_parent(data.reference), \"\")),\n\t\t\t\t\t\"label\"\t\t\t\t: \"Rename\",\n\t\t\t\t\t/*!\n\t\t\t\t\t\"shortcut\"\t\t\t: 113,\n\t\t\t\t\t\"shortcut_label\"\t: 'F2',\n\t\t\t\t\t\"icon\"\t\t\t\t: \"glyphicon glyphicon-leaf\",\n\t\t\t\t\t*/\n\t\t\t\t\t\"action\"\t\t\t: function (data) {\n\t\t\t\t\t\tvar inst = $.jstree.reference(data.reference),\n\t\t\t\t\t\t\tobj = inst.get_node(data.reference);\n\t\t\t\t\t\tinst.edit(obj);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"remove\" : {\n\t\t\t\t\t\"separator_before\"\t: false,\n\t\t\t\t\t\"icon\"\t\t\t\t: false,\n\t\t\t\t\t\"separator_after\"\t: false,\n\t\t\t\t\t\"_disabled\"\t\t\t: false, //(this.check(\"delete_node\", data.reference, this.get_parent(data.reference), \"\")),\n\t\t\t\t\t\"label\"\t\t\t\t: \"Delete\",\n\t\t\t\t\t\"action\"\t\t\t: function (data) {\n\t\t\t\t\t\tvar inst = $.jstree.reference(data.reference),\n\t\t\t\t\t\t\tobj = inst.get_node(data.reference);\n\t\t\t\t\t\tif(inst.is_selected(obj)) {\n\t\t\t\t\t\t\tinst.delete_node(inst.get_selected());\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse {\n\t\t\t\t\t\t\tinst.delete_node(obj);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t\"ccp\" : {\n\t\t\t\t\t\"separator_before\"\t: true,\n\t\t\t\t\t\"icon\"\t\t\t\t: false,\n\t\t\t\t\t\"separator_after\"\t: false,\n\t\t\t\t\t\"label\"\t\t\t\t: \"Edit\",\n\t\t\t\t\t\"action\"\t\t\t: false,\n\t\t\t\t\t\"submenu\" : {\n\t\t\t\t\t\t\"cut\" : {\n\t\t\t\t\t\t\t\"separator_before\"\t: false,\n\t\t\t\t\t\t\t\"separator_after\"\t: false,\n\t\t\t\t\t\t\t\"label\"\t\t\t\t: \"Cut\",\n\t\t\t\t\t\t\t\"action\"\t\t\t: function (data) {\n\t\t\t\t\t\t\t\tvar inst = $.jstree.reference(data.reference),\n\t\t\t\t\t\t\t\t\tobj = inst.get_node(data.reference);\n\t\t\t\t\t\t\t\tif(inst.is_selected(obj)) {\n\t\t\t\t\t\t\t\t\tinst.cut(inst.get_top_selected());\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tinst.cut(obj);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"copy\" : {\n\t\t\t\t\t\t\t\"separator_before\"\t: false,\n\t\t\t\t\t\t\t\"icon\"\t\t\t\t: false,\n\t\t\t\t\t\t\t\"separator_after\"\t: false,\n\t\t\t\t\t\t\t\"label\"\t\t\t\t: \"Copy\",\n\t\t\t\t\t\t\t\"action\"\t\t\t: function (data) {\n\t\t\t\t\t\t\t\tvar inst = $.jstree.reference(data.reference),\n\t\t\t\t\t\t\t\t\tobj = inst.get_node(data.reference);\n\t\t\t\t\t\t\t\tif(inst.is_selected(obj)) {\n\t\t\t\t\t\t\t\t\tinst.copy(inst.get_top_selected());\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\tinst.copy(obj);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t},\n\t\t\t\t\t\t\"paste\" : {\n\t\t\t\t\t\t\t\"separator_before\"\t: false,\n\t\t\t\t\t\t\t\"icon\"\t\t\t\t: false,\n\t\t\t\t\t\t\t\"_disabled\"\t\t\t: function (data) {\n\t\t\t\t\t\t\t\treturn !$.jstree.reference(data.reference).can_paste();\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\"separator_after\"\t: false,\n\t\t\t\t\t\t\t\"label\"\t\t\t\t: \"Paste\",\n\t\t\t\t\t\t\t\"action\"\t\t\t: function (data) {\n\t\t\t\t\t\t\t\tvar inst = $.jstree.reference(data.reference),\n\t\t\t\t\t\t\t\t\tobj = inst.get_node(data.reference);\n\t\t\t\t\t\t\t\tinst.paste(obj);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t};\n\n\t$.jstree.plugins.contextmenu = function (options, parent) {\n\t\tthis.bind = function () {\n\t\t\tparent.bind.call(this);\n\n\t\t\tvar last_ts = 0, cto = null, ex, ey;\n\t\t\tthis.element\n\t\t\t\t.on(\"init.jstree loading.jstree ready.jstree\", function () {\n\t\t\t\t\t\tthis.get_container_ul().addClass('jstree-contextmenu');\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"contextmenu.jstree\", \".jstree-anchor\", function (e, data) {\n\t\t\t\t\t\tif (e.target.tagName.toLowerCase() === 'input') {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\tlast_ts = e.ctrlKey ? +new Date() : 0;\n\t\t\t\t\t\tif(data || cto) {\n\t\t\t\t\t\t\tlast_ts = (+new Date()) + 10000;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(cto) {\n\t\t\t\t\t\t\tclearTimeout(cto);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(!this.is_loading(e.currentTarget)) {\n\t\t\t\t\t\t\tthis.show_contextmenu(e.currentTarget, e.pageX, e.pageY, e);\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"click.jstree\", \".jstree-anchor\", function (e) {\n\t\t\t\t\t\tif(this._data.contextmenu.visible && (!last_ts || (+new Date()) - last_ts > 250)) { // work around safari & macOS ctrl+click\n\t\t\t\t\t\t\t$.vakata.context.hide();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tlast_ts = 0;\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"touchstart.jstree\", \".jstree-anchor\", function (e) {\n\t\t\t\t\t\tif(!e.originalEvent || !e.originalEvent.changedTouches || !e.originalEvent.changedTouches[0]) {\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tex = e.originalEvent.changedTouches[0].clientX;\n\t\t\t\t\t\tey = e.originalEvent.changedTouches[0].clientY;\n\t\t\t\t\t\tcto = setTimeout(function () {\n\t\t\t\t\t\t\t$(e.currentTarget).trigger('contextmenu', true);\n\t\t\t\t\t\t}, 750);\n\t\t\t\t\t})\n\t\t\t\t.on('touchmove.vakata.jstree', function (e) {\n\t\t\t\t\t\tif(cto && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0] && (Math.abs(ex - e.originalEvent.changedTouches[0].clientX) > 10 || Math.abs(ey - e.originalEvent.changedTouches[0].clientY) > 10)) {\n\t\t\t\t\t\t\tclearTimeout(cto);\n\t\t\t\t\t\t\t$.vakata.context.hide();\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t.on('touchend.vakata.jstree', function (e) {\n\t\t\t\t\t\tif(cto) {\n\t\t\t\t\t\t\tclearTimeout(cto);\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t/*!\n\t\t\tif(!('oncontextmenu' in document.body) && ('ontouchstart' in document.body)) {\n\t\t\t\tvar el = null, tm = null;\n\t\t\t\tthis.element\n\t\t\t\t\t.on(\"touchstart\", \".jstree-anchor\", function (e) {\n\t\t\t\t\t\tel = e.currentTarget;\n\t\t\t\t\t\ttm = +new Date();\n\t\t\t\t\t\t$(document).one(\"touchend\", function (e) {\n\t\t\t\t\t\t\te.target = document.elementFromPoint(e.originalEvent.targetTouches[0].pageX - window.pageXOffset, e.originalEvent.targetTouches[0].pageY - window.pageYOffset);\n\t\t\t\t\t\t\te.currentTarget = e.target;\n\t\t\t\t\t\t\ttm = ((+(new Date())) - tm);\n\t\t\t\t\t\t\tif(e.target === el && tm > 600 && tm < 1000) {\n\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t$(el).trigger('contextmenu', e);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tel = null;\n\t\t\t\t\t\t\ttm = null;\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t}\n\t\t\t*/\n\t\t\t$(document).on(\"context_hide.vakata.jstree\", function (e, data) {\n\t\t\t\tthis._data.contextmenu.visible = false;\n\t\t\t\t$(data.reference).removeClass('jstree-context');\n\t\t\t}.bind(this));\n\t\t};\n\t\tthis.teardown = function () {\n\t\t\tif(this._data.contextmenu.visible) {\n\t\t\t\t$.vakata.context.hide();\n\t\t\t}\n\t\t\t$(document).off(\"context_hide.vakata.jstree\");\n\t\t\tparent.teardown.call(this);\n\t\t};\n\n\t\t/**\n\t\t * prepare and show the context menu for a node\n\t\t * @name show_contextmenu(obj [, x, y])\n\t\t * @param {mixed} obj the node\n\t\t * @param {Number} x the x-coordinate relative to the document to show the menu at\n\t\t * @param {Number} y the y-coordinate relative to the document to show the menu at\n\t\t * @param {Object} e the event if available that triggered the contextmenu\n\t\t * @plugin contextmenu\n\t\t * @trigger show_contextmenu.jstree\n\t\t */\n\t\tthis.show_contextmenu = function (obj, x, y, e) {\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj || obj.id === $.jstree.root) { return false; }\n\t\t\tvar s = this.settings.contextmenu,\n\t\t\t\td = this.get_node(obj, true),\n\t\t\t\ta = d.children(\".jstree-anchor\"),\n\t\t\t\to = false,\n\t\t\t\ti = false;\n\t\t\tif(s.show_at_node || x === undefined || y === undefined) {\n\t\t\t\to = a.offset();\n\t\t\t\tx = o.left;\n\t\t\t\ty = o.top + this._data.core.li_height;\n\t\t\t}\n\t\t\tif(this.settings.contextmenu.select_node && !this.is_selected(obj)) {\n\t\t\t\tthis.activate_node(obj, e);\n\t\t\t}\n\n\t\t\ti = s.items;\n\t\t\tif($.vakata.is_function(i)) {\n\t\t\t\ti = i.call(this, obj, function (i) {\n\t\t\t\t\tthis._show_contextmenu(obj, x, y, i);\n\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t\tif($.isPlainObject(i)) {\n\t\t\t\tthis._show_contextmenu(obj, x, y, i);\n\t\t\t}\n\t\t};\n\t\t/**\n\t\t * show the prepared context menu for a node\n\t\t * @name _show_contextmenu(obj, x, y, i)\n\t\t * @param {mixed} obj the node\n\t\t * @param {Number} x the x-coordinate relative to the document to show the menu at\n\t\t * @param {Number} y the y-coordinate relative to the document to show the menu at\n\t\t * @param {Number} i the object of items to show\n\t\t * @plugin contextmenu\n\t\t * @trigger show_contextmenu.jstree\n\t\t * @private\n\t\t */\n\t\tthis._show_contextmenu = function (obj, x, y, i) {\n\t\t\tvar d = this.get_node(obj, true),\n\t\t\t\ta = d.children(\".jstree-anchor\");\n\t\t\t$(document).one(\"context_show.vakata.jstree\", function (e, data) {\n\t\t\t\tvar cls = 'jstree-contextmenu jstree-' + this.get_theme() + '-contextmenu';\n\t\t\t\t$(data.element).addClass(cls);\n\t\t\t\ta.addClass('jstree-context');\n\t\t\t}.bind(this));\n\t\t\tthis._data.contextmenu.visible = true;\n\t\t\t$.vakata.context.show(a, { 'x' : x, 'y' : y }, i);\n\t\t\t/**\n\t\t\t * triggered when the contextmenu is shown for a node\n\t\t\t * @event\n\t\t\t * @name show_contextmenu.jstree\n\t\t\t * @param {Object} node the node\n\t\t\t * @param {Number} x the x-coordinate of the menu relative to the document\n\t\t\t * @param {Number} y the y-coordinate of the menu relative to the document\n\t\t\t * @plugin contextmenu\n\t\t\t */\n\t\t\tthis.trigger('show_contextmenu', { \"node\" : obj, \"x\" : x, \"y\" : y });\n\t\t};\n\t};\n\n\t// contextmenu helper\n\t(function ($) {\n\t\tvar right_to_left = false,\n\t\t\tvakata_context = {\n\t\t\t\telement\t\t: false,\n\t\t\t\treference\t: false,\n\t\t\t\tposition_x\t: 0,\n\t\t\t\tposition_y\t: 0,\n\t\t\t\titems\t\t: [],\n\t\t\t\thtml\t\t: \"\",\n\t\t\t\tis_visible\t: false\n\t\t\t};\n\n\t\t$.vakata.context = {\n\t\t\tsettings : {\n\t\t\t\thide_onmouseleave\t: 0,\n\t\t\t\ticons\t\t\t\t: true\n\t\t\t},\n\t\t\t_trigger : function (event_name) {\n\t\t\t\t$(document).triggerHandler(\"context_\" + event_name + \".vakata\", {\n\t\t\t\t\t\"reference\"\t: vakata_context.reference,\n\t\t\t\t\t\"element\"\t: vakata_context.element,\n\t\t\t\t\t\"position\"\t: {\n\t\t\t\t\t\t\"x\" : vakata_context.position_x,\n\t\t\t\t\t\t\"y\" : vakata_context.position_y\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t},\n\t\t\t_execute : function (i) {\n\t\t\t\ti = vakata_context.items[i];\n\t\t\t\treturn i && (!i._disabled || ($.vakata.is_function(i._disabled) && !i._disabled({ \"item\" : i, \"reference\" : vakata_context.reference, \"element\" : vakata_context.element }))) && i.action ? i.action.call(null, {\n\t\t\t\t\t\t\t\"item\"\t\t: i,\n\t\t\t\t\t\t\t\"reference\"\t: vakata_context.reference,\n\t\t\t\t\t\t\t\"element\"\t: vakata_context.element,\n\t\t\t\t\t\t\t\"position\"\t: {\n\t\t\t\t\t\t\t\t\"x\" : vakata_context.position_x,\n\t\t\t\t\t\t\t\t\"y\" : vakata_context.position_y\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}) : false;\n\t\t\t},\n\t\t\t_parse : function (o, is_callback) {\n\t\t\t\tif(!o) { return false; }\n\t\t\t\tif(!is_callback) {\n\t\t\t\t\tvakata_context.html\t\t= \"\";\n\t\t\t\t\tvakata_context.items\t= [];\n\t\t\t\t}\n\t\t\t\tvar str = \"\",\n\t\t\t\t\tsep = false,\n\t\t\t\t\ttmp;\n\n\t\t\t\tif(is_callback) { str += \"<\"+\"ul>\"; }\n\t\t\t\t$.each(o, function (i, val) {\n\t\t\t\t\tif(!val) { return true; }\n\t\t\t\t\tvakata_context.items.push(val);\n\t\t\t\t\tif(!sep && val.separator_before) {\n\t\t\t\t\t\tstr += \"<\"+\"li class='vakata-context-separator'><\"+\"a href='#' \" + ($.vakata.context.settings.icons ? '' : 'class=\"vakata-context-no-icons\"') + \">&#160;<\"+\"/a><\"+\"/li>\";\n\t\t\t\t\t}\n\t\t\t\t\tsep = false;\n\t\t\t\t\tstr += \"<\"+\"li class='\" + (val._class || \"\") + (val._disabled === true || ($.vakata.is_function(val._disabled) && val._disabled({ \"item\" : val, \"reference\" : vakata_context.reference, \"element\" : vakata_context.element })) ? \" vakata-contextmenu-disabled \" : \"\") + \"' \"+(val.shortcut?\" data-shortcut='\"+val.shortcut+\"' \":'')+\">\";\n\t\t\t\t\tstr += \"<\"+\"a href='#' rel='\" + (vakata_context.items.length - 1) + \"' \" + (val.title ? \"title='\" + val.title + \"'\" : \"\") + \">\";\n\t\t\t\t\tif($.vakata.context.settings.icons) {\n\t\t\t\t\t\tstr += \"<\"+\"i \";\n\t\t\t\t\t\tif(val.icon) {\n\t\t\t\t\t\t\tif(val.icon.indexOf(\"/\") !== -1 || val.icon.indexOf(\".\") !== -1) { str += \" style='background:url(\\\"\" + val.icon + \"\\\") center center no-repeat' \"; }\n\t\t\t\t\t\t\telse { str += \" class='\" + val.icon + \"' \"; }\n\t\t\t\t\t\t}\n\t\t\t\t\t\tstr += \"><\"+\"/i><\"+\"span class='vakata-contextmenu-sep'>&#160;<\"+\"/span>\";\n\t\t\t\t\t}\n\t\t\t\t\tstr += ($.vakata.is_function(val.label) ? val.label({ \"item\" : i, \"reference\" : vakata_context.reference, \"element\" : vakata_context.element }) : val.label) + (val.shortcut?' <span class=\"vakata-contextmenu-shortcut vakata-contextmenu-shortcut-'+val.shortcut+'\">'+ (val.shortcut_label || '') +'</span>':'') + \"<\"+\"/a>\";\n\t\t\t\t\tif(val.submenu) {\n\t\t\t\t\t\ttmp = $.vakata.context._parse(val.submenu, true);\n\t\t\t\t\t\tif(tmp) { str += tmp; }\n\t\t\t\t\t}\n\t\t\t\t\tstr += \"<\"+\"/li>\";\n\t\t\t\t\tif(val.separator_after) {\n\t\t\t\t\t\tstr += \"<\"+\"li class='vakata-context-separator'><\"+\"a href='#' \" + ($.vakata.context.settings.icons ? '' : 'class=\"vakata-context-no-icons\"') + \">&#160;<\"+\"/a><\"+\"/li>\";\n\t\t\t\t\t\tsep = true;\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\tstr = str.replace(/<li class\\='vakata-context-separator'\\><\\/li\\>$/,\"\");\n\t\t\t\tif(is_callback) { str += \"</ul>\"; }\n\t\t\t\t/**\n\t\t\t\t * triggered on the document when the contextmenu is parsed (HTML is built)\n\t\t\t\t * @event\n\t\t\t\t * @plugin contextmenu\n\t\t\t\t * @name context_parse.vakata\n\t\t\t\t * @param {jQuery} reference the element that was right clicked\n\t\t\t\t * @param {jQuery} element the DOM element of the menu itself\n\t\t\t\t * @param {Object} position the x & y coordinates of the menu\n\t\t\t\t */\n\t\t\t\tif(!is_callback) { vakata_context.html = str; $.vakata.context._trigger(\"parse\"); }\n\t\t\t\treturn str.length > 10 ? str : false;\n\t\t\t},\n\t\t\t_show_submenu : function (o) {\n\t\t\t\to = $(o);\n\t\t\t\tif(!o.length || !o.children(\"ul\").length) { return; }\n\t\t\t\tvar e = o.children(\"ul\"),\n\t\t\t\t\txl = o.offset().left,\n\t\t\t\t\tx = xl + o.outerWidth(),\n\t\t\t\t\ty = o.offset().top,\n\t\t\t\t\tw = e.width(),\n\t\t\t\t\th = e.height(),\n\t\t\t\t\tdw = $(window).width() + $(window).scrollLeft(),\n\t\t\t\t\tdh = $(window).height() + $(window).scrollTop();\n\t\t\t\t// може да се спести е една проверка - дали няма някой от класовете вече нагоре\n\t\t\t\tif(right_to_left) {\n\t\t\t\t\to[x - (w + 10 + o.outerWidth()) < 0 ? \"addClass\" : \"removeClass\"](\"vakata-context-left\");\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\to[x + w > dw && xl > dw - x ? \"addClass\" : \"removeClass\"](\"vakata-context-right\");\n\t\t\t\t}\n\t\t\t\tif(y + h + 10 > dh) {\n\t\t\t\t\te.css(\"bottom\",\"-1px\");\n\t\t\t\t}\n\n\t\t\t\t//if does not fit - stick it to the side\n\t\t\t\tif (o.hasClass('vakata-context-right')) {\n\t\t\t\t\tif (xl < w) {\n\t\t\t\t\t\te.css(\"margin-right\", xl - w);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (dw - x < w) {\n\t\t\t\t\t\te.css(\"margin-left\", dw - x - w);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\te.show();\n\t\t\t},\n\t\t\tshow : function (reference, position, data) {\n\t\t\t\tvar o, e, x, y, w, h, dw, dh, cond = true;\n\t\t\t\tif(vakata_context.element && vakata_context.element.length) {\n\t\t\t\t\tvakata_context.element.width('');\n\t\t\t\t}\n\t\t\t\tswitch(cond) {\n\t\t\t\t\tcase (!position && !reference):\n\t\t\t\t\t\treturn false;\n\t\t\t\t\tcase (!!position && !!reference):\n\t\t\t\t\t\tvakata_context.reference\t= reference;\n\t\t\t\t\t\tvakata_context.position_x\t= position.x;\n\t\t\t\t\t\tvakata_context.position_y\t= position.y;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase (!position && !!reference):\n\t\t\t\t\t\tvakata_context.reference\t= reference;\n\t\t\t\t\t\to = reference.offset();\n\t\t\t\t\t\tvakata_context.position_x\t= o.left + reference.outerHeight();\n\t\t\t\t\t\tvakata_context.position_y\t= o.top;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase (!!position && !reference):\n\t\t\t\t\t\tvakata_context.position_x\t= position.x;\n\t\t\t\t\t\tvakata_context.position_y\t= position.y;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif(!!reference && !data && $(reference).data('vakata_contextmenu')) {\n\t\t\t\t\tdata = $(reference).data('vakata_contextmenu');\n\t\t\t\t}\n\t\t\t\tif($.vakata.context._parse(data)) {\n\t\t\t\t\tvakata_context.element.html(vakata_context.html);\n\t\t\t\t}\n\t\t\t\tif(vakata_context.items.length) {\n\t\t\t\t\tvakata_context.element.appendTo(document.body);\n\t\t\t\t\te = vakata_context.element;\n\t\t\t\t\tx = vakata_context.position_x;\n\t\t\t\t\ty = vakata_context.position_y;\n\t\t\t\t\tw = e.width();\n\t\t\t\t\th = e.height();\n\t\t\t\t\tdw = $(window).width() + $(window).scrollLeft();\n\t\t\t\t\tdh = $(window).height() + $(window).scrollTop();\n\t\t\t\t\tif(right_to_left) {\n\t\t\t\t\t\tx -= (e.outerWidth() - $(reference).outerWidth());\n\t\t\t\t\t\tif(x < $(window).scrollLeft() + 20) {\n\t\t\t\t\t\t\tx = $(window).scrollLeft() + 20;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(x + w + 20 > dw) {\n\t\t\t\t\t\tx = dw - (w + 20);\n\t\t\t\t\t}\n\t\t\t\t\tif(y + h + 20 > dh) {\n\t\t\t\t\t\ty = dh - (h + 20);\n\t\t\t\t\t}\n\n\t\t\t\t\tvakata_context.element\n\t\t\t\t\t\t.css({ \"left\" : x, \"top\" : y })\n\t\t\t\t\t\t.show()\n\t\t\t\t\t\t.find('a').first().trigger('focus').parent().addClass(\"vakata-context-hover\");\n\t\t\t\t\tvakata_context.is_visible = true;\n\t\t\t\t\t/**\n\t\t\t\t\t * triggered on the document when the contextmenu is shown\n\t\t\t\t\t * @event\n\t\t\t\t\t * @plugin contextmenu\n\t\t\t\t\t * @name context_show.vakata\n\t\t\t\t\t * @param {jQuery} reference the element that was right clicked\n\t\t\t\t\t * @param {jQuery} element the DOM element of the menu itself\n\t\t\t\t\t * @param {Object} position the x & y coordinates of the menu\n\t\t\t\t\t */\n\t\t\t\t\t$.vakata.context._trigger(\"show\");\n\t\t\t\t}\n\t\t\t},\n\t\t\thide : function () {\n\t\t\t\tif(vakata_context.is_visible) {\n\t\t\t\t\tvakata_context.element.hide().find(\"ul\").hide().end().find(':focus').trigger('blur').end().detach();\n\t\t\t\t\tvakata_context.is_visible = false;\n\t\t\t\t\t/**\n\t\t\t\t\t * triggered on the document when the contextmenu is hidden\n\t\t\t\t\t * @event\n\t\t\t\t\t * @plugin contextmenu\n\t\t\t\t\t * @name context_hide.vakata\n\t\t\t\t\t * @param {jQuery} reference the element that was right clicked\n\t\t\t\t\t * @param {jQuery} element the DOM element of the menu itself\n\t\t\t\t\t * @param {Object} position the x & y coordinates of the menu\n\t\t\t\t\t */\n\t\t\t\t\t$.vakata.context._trigger(\"hide\");\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t\t$(function () {\n\t\t\tright_to_left = $(document.body).css(\"direction\") === \"rtl\";\n\t\t\tvar to = false;\n\n\t\t\tvakata_context.element = $(\"<ul class='vakata-context'></ul>\");\n\t\t\tvakata_context.element\n\t\t\t\t.on(\"mouseenter\", \"li\", function (e) {\n\t\t\t\t\te.stopImmediatePropagation();\n\n\t\t\t\t\tif($.contains(this, e.relatedTarget)) {\n\t\t\t\t\t\t// премахнато заради delegate mouseleave по-долу\n\t\t\t\t\t\t// $(this).find(\".vakata-context-hover\").removeClass(\"vakata-context-hover\");\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif(to) { clearTimeout(to); }\n\t\t\t\t\tvakata_context.element.find(\".vakata-context-hover\").removeClass(\"vakata-context-hover\").end();\n\n\t\t\t\t\t$(this)\n\t\t\t\t\t\t.siblings().find(\"ul\").hide().end().end()\n\t\t\t\t\t\t.parentsUntil(\".vakata-context\", \"li\").addBack().addClass(\"vakata-context-hover\");\n\t\t\t\t\t$.vakata.context._show_submenu(this);\n\t\t\t\t})\n\t\t\t\t// тестово - дали не натоварва?\n\t\t\t\t.on(\"mouseleave\", \"li\", function (e) {\n\t\t\t\t\tif($.contains(this, e.relatedTarget)) { return; }\n\t\t\t\t\t$(this).find(\".vakata-context-hover\").addBack().removeClass(\"vakata-context-hover\");\n\t\t\t\t})\n\t\t\t\t.on(\"mouseleave\", function (e) {\n\t\t\t\t\t$(this).find(\".vakata-context-hover\").removeClass(\"vakata-context-hover\");\n\t\t\t\t\tif($.vakata.context.settings.hide_onmouseleave) {\n\t\t\t\t\t\tto = setTimeout(\n\t\t\t\t\t\t\t(function (t) {\n\t\t\t\t\t\t\t\treturn function () { $.vakata.context.hide(); };\n\t\t\t\t\t\t\t}(this)), $.vakata.context.settings.hide_onmouseleave);\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.on(\"click\", \"a\", function (e) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t//})\n\t\t\t\t//.on(\"mouseup\", \"a\", function (e) {\n\t\t\t\t\tif(!$(this).trigger('blur').parent().hasClass(\"vakata-context-disabled\") && $.vakata.context._execute($(this).attr(\"rel\")) !== false) {\n\t\t\t\t\t\t$.vakata.context.hide();\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.on('keydown', 'a', function (e) {\n\t\t\t\t\t\tvar o = null;\n\t\t\t\t\t\tswitch(e.which) {\n\t\t\t\t\t\t\tcase 13:\n\t\t\t\t\t\t\tcase 32:\n\t\t\t\t\t\t\t\te.type = \"click\";\n\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t$(e.currentTarget).trigger(e);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 37:\n\t\t\t\t\t\t\t\tif(vakata_context.is_visible) {\n\t\t\t\t\t\t\t\t\tvakata_context.element.find(\".vakata-context-hover\").last().closest(\"li\").first().find(\"ul\").hide().find(\".vakata-context-hover\").removeClass(\"vakata-context-hover\").end().end().children('a').trigger('focus');\n\t\t\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 38:\n\t\t\t\t\t\t\t\tif(vakata_context.is_visible) {\n\t\t\t\t\t\t\t\t\to = vakata_context.element.find(\"ul:visible\").addBack().last().children(\".vakata-context-hover\").removeClass(\"vakata-context-hover\").prevAll(\"li:not(.vakata-context-separator)\").first();\n\t\t\t\t\t\t\t\t\tif(!o.length) { o = vakata_context.element.find(\"ul:visible\").addBack().last().children(\"li:not(.vakata-context-separator)\").last(); }\n\t\t\t\t\t\t\t\t\to.addClass(\"vakata-context-hover\").children('a').trigger('focus');\n\t\t\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 39:\n\t\t\t\t\t\t\t\tif(vakata_context.is_visible) {\n\t\t\t\t\t\t\t\t\tvakata_context.element.find(\".vakata-context-hover\").last().children(\"ul\").show().children(\"li:not(.vakata-context-separator)\").removeClass(\"vakata-context-hover\").first().addClass(\"vakata-context-hover\").children('a').trigger('focus');\n\t\t\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 40:\n\t\t\t\t\t\t\t\tif(vakata_context.is_visible) {\n\t\t\t\t\t\t\t\t\to = vakata_context.element.find(\"ul:visible\").addBack().last().children(\".vakata-context-hover\").removeClass(\"vakata-context-hover\").nextAll(\"li:not(.vakata-context-separator)\").first();\n\t\t\t\t\t\t\t\t\tif(!o.length) { o = vakata_context.element.find(\"ul:visible\").addBack().last().children(\"li:not(.vakata-context-separator)\").first(); }\n\t\t\t\t\t\t\t\t\to.addClass(\"vakata-context-hover\").children('a').trigger('focus');\n\t\t\t\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 27:\n\t\t\t\t\t\t\t\t$.vakata.context.hide();\n\t\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\t//console.log(e.which);\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t.on('keydown', function (e) {\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tvar a = vakata_context.element.find('.vakata-contextmenu-shortcut-' + e.which).parent();\n\t\t\t\t\tif(a.parent().not('.vakata-context-disabled')) {\n\t\t\t\t\t\ta.trigger('click');\n\t\t\t\t\t}\n\t\t\t\t});\n\n\t\t\t$(document)\n\t\t\t\t.on(\"mousedown.vakata.jstree\", function (e) {\n\t\t\t\t\tif(vakata_context.is_visible && vakata_context.element[0] !== e.target && !$.contains(vakata_context.element[0], e.target)) {\n\t\t\t\t\t\t$.vakata.context.hide();\n\t\t\t\t\t}\n\t\t\t\t})\n\t\t\t\t.on(\"context_show.vakata.jstree\", function (e, data) {\n\t\t\t\t\tvakata_context.element.find(\"li:has(ul)\").children(\"a\").addClass(\"vakata-context-parent\");\n\t\t\t\t\tif(right_to_left) {\n\t\t\t\t\t\tvakata_context.element.addClass(\"vakata-context-rtl\").css(\"direction\", \"rtl\");\n\t\t\t\t\t}\n\t\t\t\t\t// also apply a RTL class?\n\t\t\t\t\tvakata_context.element.find(\"ul\").hide().end();\n\t\t\t\t});\n\t\t});\n\t}($));\n\t// $.jstree.defaults.plugins.push(\"contextmenu\");\n\n\n/**\n * ### Drag'n'drop plugin\n *\n * Enables dragging and dropping of nodes in the tree, resulting in a move or copy operations.\n */\n\n\t/**\n\t * stores all defaults for the drag'n'drop plugin\n\t * @name $.jstree.defaults.dnd\n\t * @plugin dnd\n\t */\n\t$.jstree.defaults.dnd = {\n\t\t/**\n\t\t * a boolean indicating if a copy should be possible while dragging (by pressint the meta key or Ctrl). Defaults to `true`.\n\t\t * @name $.jstree.defaults.dnd.copy\n\t\t * @plugin dnd\n\t\t */\n\t\tcopy : true,\n\t\t/**\n\t\t * a number indicating how long a node should remain hovered while dragging to be opened. Defaults to `500`.\n\t\t * @name $.jstree.defaults.dnd.open_timeout\n\t\t * @plugin dnd\n\t\t */\n\t\topen_timeout : 500,\n\t\t/**\n\t\t * a function invoked each time a node is about to be dragged, invoked in the tree's scope and receives the nodes about to be dragged as an argument (array) and the event that started the drag - return `false` to prevent dragging\n\t\t * @name $.jstree.defaults.dnd.is_draggable\n\t\t * @plugin dnd\n\t\t */\n\t\tis_draggable : true,\n\t\t/**\n\t\t * a boolean indicating if checks should constantly be made while the user is dragging the node (as opposed to checking only on drop), default is `true`\n\t\t * @name $.jstree.defaults.dnd.check_while_dragging\n\t\t * @plugin dnd\n\t\t */\n\t\tcheck_while_dragging : true,\n\t\t/**\n\t\t * a boolean indicating if nodes from this tree should only be copied with dnd (as opposed to moved), default is `false`\n\t\t * @name $.jstree.defaults.dnd.always_copy\n\t\t * @plugin dnd\n\t\t */\n\t\talways_copy : false,\n\t\t/**\n\t\t * when dropping a node \"inside\", this setting indicates the position the node should go to - it can be an integer or a string: \"first\" (same as 0) or \"last\", default is `0`\n\t\t * @name $.jstree.defaults.dnd.inside_pos\n\t\t * @plugin dnd\n\t\t */\n\t\tinside_pos : 0,\n\t\t/**\n\t\t * when starting the drag on a node that is selected this setting controls if all selected nodes are dragged or only the single node, default is `true`, which means all selected nodes are dragged when the drag is started on a selected node\n\t\t * @name $.jstree.defaults.dnd.drag_selection\n\t\t * @plugin dnd\n\t\t */\n\t\tdrag_selection : true,\n\t\t/**\n\t\t * controls whether dnd works on touch devices. If left as boolean true dnd will work the same as in desktop browsers, which in some cases may impair scrolling. If set to boolean false dnd will not work on touch devices. There is a special third option - string \"selected\" which means only selected nodes can be dragged on touch devices.\n\t\t * @name $.jstree.defaults.dnd.touch\n\t\t * @plugin dnd\n\t\t */\n\t\ttouch : true,\n\t\t/**\n\t\t * controls whether items can be dropped anywhere on the node, not just on the anchor, by default only the node anchor is a valid drop target. Works best with the wholerow plugin. If enabled on mobile depending on the interface it might be hard for the user to cancel the drop, since the whole tree container will be a valid drop target.\n\t\t * @name $.jstree.defaults.dnd.large_drop_target\n\t\t * @plugin dnd\n\t\t */\n\t\tlarge_drop_target : false,\n\t\t/**\n\t\t * controls whether a drag can be initiated from any part of the node and not just the text/icon part, works best with the wholerow plugin. Keep in mind it can cause problems with tree scrolling on mobile depending on the interface - in that case set the touch option to \"selected\".\n\t\t * @name $.jstree.defaults.dnd.large_drag_target\n\t\t * @plugin dnd\n\t\t */\n\t\tlarge_drag_target : false,\n\t\t/**\n\t\t * controls whether use HTML5 dnd api instead of classical. That will allow better integration of dnd events with other HTML5 controls.\n\t\t * @reference http://caniuse.com/#feat=dragndrop\n\t\t * @name $.jstree.defaults.dnd.use_html5\n\t\t * @plugin dnd\n\t\t */\n\t\tuse_html5: false\n\t};\n\tvar drg, elm;\n\t// TODO: now check works by checking for each node individually, how about max_children, unique, etc?\n\t$.jstree.plugins.dnd = function (options, parent) {\n\t\tthis.init = function (el, options) {\n\t\t\tparent.init.call(this, el, options);\n\t\t\tthis.settings.dnd.use_html5 = this.settings.dnd.use_html5 && ('draggable' in document.createElement('span'));\n\t\t};\n\t\tthis.bind = function () {\n\t\t\tparent.bind.call(this);\n\n\t\t\tthis.element\n\t\t\t\t.on(this.settings.dnd.use_html5 ? 'dragstart.jstree' : 'mousedown.jstree touchstart.jstree', this.settings.dnd.large_drag_target ? '.jstree-node' : '.jstree-anchor', function (e) {\n\t\t\t\t\t\tif(this.settings.dnd.large_drag_target && $(e.target).closest('.jstree-node')[0] !== e.currentTarget) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(e.type === \"touchstart\" && (!this.settings.dnd.touch || (this.settings.dnd.touch === 'selected' && !$(e.currentTarget).closest('.jstree-node').children('.jstree-anchor').hasClass('jstree-clicked')))) {\n\t\t\t\t\t\t\treturn true;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvar obj = this.get_node(e.target),\n\t\t\t\t\t\t\tmlt = this.is_selected(obj) && this.settings.dnd.drag_selection ? this.get_top_selected().length : 1,\n\t\t\t\t\t\t\ttxt = (mlt > 1 ? mlt + ' ' + this.get_string('nodes') : this.get_text(e.currentTarget));\n\t\t\t\t\t\tif(this.settings.core.force_text) {\n\t\t\t\t\t\t\ttxt = $.vakata.html.escape(txt);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(obj && obj.id && obj.id !== $.jstree.root && (e.which === 1 || e.type === \"touchstart\" || e.type === \"dragstart\") &&\n\t\t\t\t\t\t\t(this.settings.dnd.is_draggable === true || ($.vakata.is_function(this.settings.dnd.is_draggable) && this.settings.dnd.is_draggable.call(this, (mlt > 1 ? this.get_top_selected(true) : [obj]), e)))\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\tdrg = { 'jstree' : true, 'origin' : this, 'obj' : this.get_node(obj,true), 'nodes' : mlt > 1 ? this.get_top_selected() : [obj.id] };\n\t\t\t\t\t\t\telm = e.currentTarget;\n\t\t\t\t\t\t\tif (this.settings.dnd.use_html5) {\n\t\t\t\t\t\t\t\t$.vakata.dnd._trigger('start', e, { 'helper': $(), 'element': elm, 'data': drg });\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tthis.element.trigger('mousedown.jstree');\n\t\t\t\t\t\t\t\treturn $.vakata.dnd.start(e, drg, '<div id=\"jstree-dnd\" class=\"jstree-' + this.get_theme() + ' jstree-' + this.get_theme() + '-' + this.get_theme_variant() + ' ' + ( this.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' ) + '\"><i class=\"jstree-icon jstree-er\"></i>' + txt + '<ins class=\"jstree-copy\">+</ins></div>');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this));\n\t\t\tif (this.settings.dnd.use_html5) {\n\t\t\t\tthis.element\n\t\t\t\t\t.on('dragover.jstree', function (e) {\n\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t$.vakata.dnd._trigger('move', e, { 'helper': $(), 'element': elm, 'data': drg });\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t})\n\t\t\t\t\t//.on('dragenter.jstree', this.settings.dnd.large_drop_target ? '.jstree-node' : '.jstree-anchor', $.proxy(function (e) {\n\t\t\t\t\t//\t\te.preventDefault();\n\t\t\t\t\t//\t\t$.vakata.dnd._trigger('move', e, { 'helper': $(), 'element': elm, 'data': drg });\n\t\t\t\t\t//\t\treturn false;\n\t\t\t\t\t//\t}, this))\n\t\t\t\t\t.on('drop.jstree', function (e) {\n\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\t$.vakata.dnd._trigger('stop', e, { 'helper': $(), 'element': elm, 'data': drg });\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}.bind(this));\n\t\t\t}\n\t\t};\n\t\tthis.redraw_node = function(obj, deep, callback, force_render) {\n\t\t\tobj = parent.redraw_node.apply(this, arguments);\n\t\t\tif (obj && this.settings.dnd.use_html5) {\n\t\t\t\tif (this.settings.dnd.large_drag_target) {\n\t\t\t\t\tobj.setAttribute('draggable', true);\n\t\t\t\t} else {\n\t\t\t\t\tvar i, j, tmp = null;\n\t\t\t\t\tfor(i = 0, j = obj.childNodes.length; i < j; i++) {\n\t\t\t\t\t\tif(obj.childNodes[i] && obj.childNodes[i].className && obj.childNodes[i].className.indexOf(\"jstree-anchor\") !== -1) {\n\t\t\t\t\t\t\ttmp = obj.childNodes[i];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(tmp) {\n\t\t\t\t\t\ttmp.setAttribute('draggable', true);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn obj;\n\t\t};\n\t};\n\n\t$(function() {\n\t\t// bind only once for all instances\n\t\tvar lastmv = false,\n\t\t\tlaster = false,\n\t\t\tlastev = false,\n\t\t\topento = false,\n\t\t\tmarker = $('<div id=\"jstree-marker\">&#160;</div>').hide(); //.appendTo('body');\n\n\t\t$(document)\n\t\t\t.on('dragover.vakata.jstree', function (e) {\n\t\t\t\tif (elm) {\n\t\t\t\t\t$.vakata.dnd._trigger('move', e, { 'helper': $(), 'element': elm, 'data': drg });\n\t\t\t\t}\n\t\t\t})\n\t\t\t.on('drop.vakata.jstree', function (e) {\n\t\t\t\tif (elm) {\n\t\t\t\t\t$.vakata.dnd._trigger('stop', e, { 'helper': $(), 'element': elm, 'data': drg });\n\t\t\t\t\telm = null;\n\t\t\t\t\tdrg = null;\n\t\t\t\t}\n\t\t\t})\n\t\t\t.on('dnd_start.vakata.jstree', function (e, data) {\n\t\t\t\tlastmv = false;\n\t\t\t\tlastev = false;\n\t\t\t\tif(!data || !data.data || !data.data.jstree) { return; }\n\t\t\t\tmarker.appendTo(document.body); //.show();\n\t\t\t})\n\t\t\t.on('dnd_move.vakata.jstree', function (e, data) {\n\t\t\t\tvar isDifferentNode = data.event.target !== lastev.target;\n\t\t\t\tif(opento) {\n\t\t\t\t\tif (!data.event || data.event.type !== 'dragover' || isDifferentNode) {\n\t\t\t\t\t\tclearTimeout(opento);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(!data || !data.data || !data.data.jstree) { return; }\n\n\t\t\t\t// if we are hovering the marker image do nothing (can happen on \"inside\" drags)\n\t\t\t\tif(data.event.target.id && data.event.target.id === 'jstree-marker') {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlastev = data.event;\n\n\t\t\t\tvar ins = $.jstree.reference(data.event.target),\n\t\t\t\t\tref = false,\n\t\t\t\t\toff = false,\n\t\t\t\t\trel = false,\n\t\t\t\t\ttmp, l, t, h, p, i, o, ok, t1, t2, op, ps, pr, ip, tm, is_copy, pn, c;\n\t\t\t\t// if we are over an instance\n\t\t\t\tif(ins && ins._data && ins._data.dnd) {\n\t\t\t\t\tmarker.attr('class', 'jstree-' + ins.get_theme() + ( ins.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' ));\n\t\t\t\t\tis_copy = data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey)));\n\t\t\t\t\tdata.helper\n\t\t\t\t\t\t.children().attr('class', 'jstree-' + ins.get_theme() + ' jstree-' + ins.get_theme() + '-' + ins.get_theme_variant() + ' ' + ( ins.settings.core.themes.responsive ? ' jstree-dnd-responsive' : '' ))\n\t\t\t\t\t\t.find('.jstree-copy').first()[ is_copy ? 'show' : 'hide' ]();\n\n\t\t\t\t\t// if are hovering the container itself add a new root node\n\t\t\t\t\t//console.log(data.event);\n\t\t\t\t\tif( (data.event.target === ins.element[0] || data.event.target === ins.get_container_ul()[0]) && ins.get_container_ul().children().length === 0) {\n\t\t\t\t\t\tok = true;\n\t\t\t\t\t\tfor(t1 = 0, t2 = data.data.nodes.length; t1 < t2; t1++) {\n\t\t\t\t\t\t\tok = ok && ins.check( (data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey)) ) ? \"copy_node\" : \"move_node\"), (data.data.origin && data.data.origin !== ins ? data.data.origin.get_node(data.data.nodes[t1]) : data.data.nodes[t1]), $.jstree.root, 'last', { 'dnd' : true, 'ref' : ins.get_node($.jstree.root), 'pos' : 'i', 'origin' : data.data.origin, 'is_multi' : (data.data.origin && data.data.origin !== ins), 'is_foreign' : (!data.data.origin) });\n\t\t\t\t\t\t\tif(!ok) { break; }\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(ok) {\n\t\t\t\t\t\t\tlastmv = { 'ins' : ins, 'par' : $.jstree.root, 'pos' : 'last' };\n\t\t\t\t\t\t\tmarker.hide();\n\t\t\t\t\t\t\tdata.helper.find('.jstree-icon').first().removeClass('jstree-er').addClass('jstree-ok');\n\t\t\t\t\t\t\tif (data.event.originalEvent && data.event.originalEvent.dataTransfer) {\n\t\t\t\t\t\t\t\tdata.event.originalEvent.dataTransfer.dropEffect = is_copy ? 'copy' : 'move';\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\telse {\n\t\t\t\t\t\t// if we are hovering a tree node\n\t\t\t\t\t\tref = ins.settings.dnd.large_drop_target ? $(data.event.target).closest('.jstree-node').children('.jstree-anchor') : $(data.event.target).closest('.jstree-anchor');\n\t\t\t\t\t\tif(ref && ref.length && ref.parent().is('.jstree-closed, .jstree-open, .jstree-leaf')) {\n\t\t\t\t\t\t\toff = ref.offset();\n\t\t\t\t\t\t\trel = (data.event.pageY !== undefined ? data.event.pageY : data.event.originalEvent.pageY) - off.top;\n\t\t\t\t\t\t\th = ref.outerHeight();\n\t\t\t\t\t\t\tif(rel < h / 3) {\n\t\t\t\t\t\t\t\to = ['b', 'i', 'a'];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse if(rel > h - h / 3) {\n\t\t\t\t\t\t\t\to = ['a', 'i', 'b'];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\to = rel > h / 2 ? ['i', 'a', 'b'] : ['i', 'b', 'a'];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t$.each(o, function (j, v) {\n\t\t\t\t\t\t\t\tswitch(v) {\n\t\t\t\t\t\t\t\t\tcase 'b':\n\t\t\t\t\t\t\t\t\t\tl = off.left - 6;\n\t\t\t\t\t\t\t\t\t\tt = off.top;\n\t\t\t\t\t\t\t\t\t\tp = ins.get_parent(ref);\n\t\t\t\t\t\t\t\t\t\ti = ref.parent().index();\n\t\t\t\t\t\t\t\t\t\tc = 'jstree-below';\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase 'i':\n\t\t\t\t\t\t\t\t\t\tip = ins.settings.dnd.inside_pos;\n\t\t\t\t\t\t\t\t\t\ttm = ins.get_node(ref.parent());\n\t\t\t\t\t\t\t\t\t\tl = off.left - 2;\n\t\t\t\t\t\t\t\t\t\tt = off.top + h / 2 + 1;\n\t\t\t\t\t\t\t\t\t\tp = tm.id;\n\t\t\t\t\t\t\t\t\t\ti = ip === 'first' ? 0 : (ip === 'last' ? tm.children.length : Math.min(ip, tm.children.length));\n\t\t\t\t\t\t\t\t\t\tc = 'jstree-inside';\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\tcase 'a':\n\t\t\t\t\t\t\t\t\t\tl = off.left - 6;\n\t\t\t\t\t\t\t\t\t\tt = off.top + h;\n\t\t\t\t\t\t\t\t\t\tp = ins.get_parent(ref);\n\t\t\t\t\t\t\t\t\t\ti = ref.parent().index() + 1;\n\t\t\t\t\t\t\t\t\t\tc = 'jstree-above';\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tok = true;\n\t\t\t\t\t\t\t\tfor(t1 = 0, t2 = data.data.nodes.length; t1 < t2; t1++) {\n\t\t\t\t\t\t\t\t\top = data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))) ? \"copy_node\" : \"move_node\";\n\t\t\t\t\t\t\t\t\tps = i;\n\t\t\t\t\t\t\t\t\tif(op === \"move_node\" && v === 'a' && (data.data.origin && data.data.origin === ins) && p === ins.get_parent(data.data.nodes[t1])) {\n\t\t\t\t\t\t\t\t\t\tpr = ins.get_node(p);\n\t\t\t\t\t\t\t\t\t\tif(ps > $.inArray(data.data.nodes[t1], pr.children)) {\n\t\t\t\t\t\t\t\t\t\t\tps -= 1;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tok = ok && ( (ins && ins.settings && ins.settings.dnd && ins.settings.dnd.check_while_dragging === false) || ins.check(op, (data.data.origin && data.data.origin !== ins ? data.data.origin.get_node(data.data.nodes[t1]) : data.data.nodes[t1]), p, ps, { 'dnd' : true, 'ref' : ins.get_node(ref.parent()), 'pos' : v, 'origin' : data.data.origin, 'is_multi' : (data.data.origin && data.data.origin !== ins), 'is_foreign' : (!data.data.origin) }) );\n\t\t\t\t\t\t\t\t\tif(!ok) {\n\t\t\t\t\t\t\t\t\t\tif(ins && ins.last_error) { laster = ins.last_error(); }\n\t\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif(v === 'i' && ref.parent().is('.jstree-closed') && ins.settings.dnd.open_timeout) {\n\t\t\t\t\t\t\t\t\tif (!data.event || data.event.type !== 'dragover' || isDifferentNode) {\n\t\t\t\t\t\t\t\t\t\tif (opento) { clearTimeout(opento); }\n\t\t\t\t\t\t\t\t\t\topento = setTimeout((function (x, z) { return function () { x.open_node(z); }; }(ins, ref)), ins.settings.dnd.open_timeout);\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif(ok) {\n\t\t\t\t\t\t\t\t\tpn = ins.get_node(p, true);\n\t\t\t\t\t\t\t\t\tif (!pn.hasClass('.jstree-dnd-parent')) {\n\t\t\t\t\t\t\t\t\t\t$('.jstree-dnd-parent').removeClass('jstree-dnd-parent');\n\t\t\t\t\t\t\t\t\t\tpn.addClass('jstree-dnd-parent');\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tlastmv = { 'ins' : ins, 'par' : p, 'pos' : v === 'i' && ip === 'last' && i === 0 && !ins.is_loaded(tm) ? 'last' : i };\n\t\t\t\t\t\t\t\t\tmarker.css({ 'left' : l + 'px', 'top' : t + 'px' }).show();\n\t\t\t\t\t\t\t\t\tmarker.removeClass('jstree-above jstree-inside jstree-below').addClass(c);\n\t\t\t\t\t\t\t\t\tdata.helper.find('.jstree-icon').first().removeClass('jstree-er').addClass('jstree-ok');\n\t\t\t\t\t\t\t\t\tif (data.event.originalEvent && data.event.originalEvent.dataTransfer) {\n\t\t\t\t\t\t\t\t\t\tdata.event.originalEvent.dataTransfer.dropEffect = is_copy ? 'copy' : 'move';\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tlaster = {};\n\t\t\t\t\t\t\t\t\to = true;\n\t\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif(o === true) { return; }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t$('.jstree-dnd-parent').removeClass('jstree-dnd-parent');\n\t\t\t\tlastmv = false;\n\t\t\t\tdata.helper.find('.jstree-icon').removeClass('jstree-ok').addClass('jstree-er');\n\t\t\t\tif (data.event.originalEvent && data.event.originalEvent.dataTransfer) {\n\t\t\t\t\t//data.event.originalEvent.dataTransfer.dropEffect = 'none';\n\t\t\t\t}\n\t\t\t\tmarker.hide();\n\t\t\t})\n\t\t\t.on('dnd_scroll.vakata.jstree', function (e, data) {\n\t\t\t\tif(!data || !data.data || !data.data.jstree) { return; }\n\t\t\t\tmarker.hide();\n\t\t\t\tlastmv = false;\n\t\t\t\tlastev = false;\n\t\t\t\tdata.helper.find('.jstree-icon').first().removeClass('jstree-ok').addClass('jstree-er');\n\t\t\t})\n\t\t\t.on('dnd_stop.vakata.jstree', function (e, data) {\n\t\t\t\t$('.jstree-dnd-parent').removeClass('jstree-dnd-parent');\n\t\t\t\tif(opento) { clearTimeout(opento); }\n\t\t\t\tif(!data || !data.data || !data.data.jstree) { return; }\n\t\t\t\tmarker.hide().detach();\n\t\t\t\tvar i, j, nodes = [];\n\t\t\t\tif(lastmv) {\n\t\t\t\t\tfor(i = 0, j = data.data.nodes.length; i < j; i++) {\n\t\t\t\t\t\tnodes[i] = data.data.origin ? data.data.origin.get_node(data.data.nodes[i]) : data.data.nodes[i];\n\t\t\t\t\t}\n\t\t\t\t\tlastmv.ins[ data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (data.event.metaKey || data.event.ctrlKey))) ? 'copy_node' : 'move_node' ](nodes, lastmv.par, lastmv.pos, false, false, false, data.data.origin);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ti = $(data.event.target).closest('.jstree');\n\t\t\t\t\tif(i.length && laster && laster.error && laster.error === 'check') {\n\t\t\t\t\t\ti = i.jstree(true);\n\t\t\t\t\t\tif(i) {\n\t\t\t\t\t\t\ti.settings.core.error.call(this, laster);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tlastev = false;\n\t\t\t\tlastmv = false;\n\t\t\t})\n\t\t\t.on('keyup.jstree keydown.jstree', function (e, data) {\n\t\t\t\tdata = $.vakata.dnd._get();\n\t\t\t\tif(data && data.data && data.data.jstree) {\n\t\t\t\t\tif (e.type === \"keyup\" && e.which === 27) {\n\t\t\t\t\t\tif (opento) { clearTimeout(opento); }\n\t\t\t\t\t\tlastmv = false;\n\t\t\t\t\t\tlaster = false;\n\t\t\t\t\t\tlastev = false;\n\t\t\t\t\t\topento = false;\n\t\t\t\t\t\tmarker.hide().detach();\n\t\t\t\t\t\t$.vakata.dnd._clean();\n\t\t\t\t\t} else {\n\t\t\t\t\t\tdata.helper.find('.jstree-copy').first()[ data.data.origin && (data.data.origin.settings.dnd.always_copy || (data.data.origin.settings.dnd.copy && (e.metaKey || e.ctrlKey))) ? 'show' : 'hide' ]();\n\t\t\t\t\t\tif(lastev) {\n\t\t\t\t\t\t\tlastev.metaKey = e.metaKey;\n\t\t\t\t\t\t\tlastev.ctrlKey = e.ctrlKey;\n\t\t\t\t\t\t\t$.vakata.dnd._trigger('move', lastev);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t});\n\t});\n\n\t// helpers\n\t(function ($) {\n\t\t$.vakata.html = {\n\t\t\tdiv : $('<div></div>'),\n\t\t\tescape : function (str) {\n\t\t\t\treturn $.vakata.html.div.text(str).html();\n\t\t\t},\n\t\t\tstrip : function (str) {\n\t\t\t\treturn $.vakata.html.div.empty().append($.parseHTML(str)).text();\n\t\t\t}\n\t\t};\n\t\t// private variable\n\t\tvar vakata_dnd = {\n\t\t\telement\t: false,\n\t\t\ttarget\t: false,\n\t\t\tis_down\t: false,\n\t\t\tis_drag\t: false,\n\t\t\thelper\t: false,\n\t\t\thelper_w: 0,\n\t\t\tdata\t: false,\n\t\t\tinit_x\t: 0,\n\t\t\tinit_y\t: 0,\n\t\t\tscroll_l: 0,\n\t\t\tscroll_t: 0,\n\t\t\tscroll_e: false,\n\t\t\tscroll_i: false,\n\t\t\tis_touch: false\n\t\t};\n\t\t$.vakata.dnd = {\n\t\t\tsettings : {\n\t\t\t\tscroll_speed\t\t: 10,\n\t\t\t\tscroll_proximity\t: 20,\n\t\t\t\thelper_left\t\t\t: 5,\n\t\t\t\thelper_top\t\t\t: 10,\n\t\t\t\tthreshold\t\t\t: 5,\n\t\t\t\tthreshold_touch\t\t: 10\n\t\t\t},\n\t\t\t_trigger : function (event_name, e, data) {\n\t\t\t\tif (data === undefined) {\n\t\t\t\t\tdata = $.vakata.dnd._get();\n\t\t\t\t}\n\t\t\t\tdata.event = e;\n\t\t\t\t$(document).triggerHandler(\"dnd_\" + event_name + \".vakata\", data);\n\t\t\t},\n\t\t\t_get : function () {\n\t\t\t\treturn {\n\t\t\t\t\t\"data\"\t\t: vakata_dnd.data,\n\t\t\t\t\t\"element\"\t: vakata_dnd.element,\n\t\t\t\t\t\"helper\"\t: vakata_dnd.helper\n\t\t\t\t};\n\t\t\t},\n\t\t\t_clean : function () {\n\t\t\t\tif(vakata_dnd.helper) { vakata_dnd.helper.remove(); }\n\t\t\t\tif(vakata_dnd.scroll_i) { clearInterval(vakata_dnd.scroll_i); vakata_dnd.scroll_i = false; }\n\t\t\t\tvakata_dnd = {\n\t\t\t\t\telement\t: false,\n\t\t\t\t\ttarget\t: false,\n\t\t\t\t\tis_down\t: false,\n\t\t\t\t\tis_drag\t: false,\n\t\t\t\t\thelper\t: false,\n\t\t\t\t\thelper_w: 0,\n\t\t\t\t\tdata\t: false,\n\t\t\t\t\tinit_x\t: 0,\n\t\t\t\t\tinit_y\t: 0,\n\t\t\t\t\tscroll_l: 0,\n\t\t\t\t\tscroll_t: 0,\n\t\t\t\t\tscroll_e: false,\n\t\t\t\t\tscroll_i: false,\n\t\t\t\t\tis_touch: false\n\t\t\t\t};\n\t\t\t\telm = null;\n\t\t\t\t$(document).off(\"mousemove.vakata.jstree touchmove.vakata.jstree\", $.vakata.dnd.drag);\n\t\t\t\t$(document).off(\"mouseup.vakata.jstree touchend.vakata.jstree\", $.vakata.dnd.stop);\n\t\t\t},\n\t\t\t_scroll : function (init_only) {\n\t\t\t\tif(!vakata_dnd.scroll_e || (!vakata_dnd.scroll_l && !vakata_dnd.scroll_t)) {\n\t\t\t\t\tif(vakata_dnd.scroll_i) { clearInterval(vakata_dnd.scroll_i); vakata_dnd.scroll_i = false; }\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif(!vakata_dnd.scroll_i) {\n\t\t\t\t\tvakata_dnd.scroll_i = setInterval($.vakata.dnd._scroll, 100);\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif(init_only === true) { return false; }\n\n\t\t\t\tvar i = vakata_dnd.scroll_e.scrollTop(),\n\t\t\t\t\tj = vakata_dnd.scroll_e.scrollLeft();\n\t\t\t\tvakata_dnd.scroll_e.scrollTop(i + vakata_dnd.scroll_t * $.vakata.dnd.settings.scroll_speed);\n\t\t\t\tvakata_dnd.scroll_e.scrollLeft(j + vakata_dnd.scroll_l * $.vakata.dnd.settings.scroll_speed);\n\t\t\t\tif(i !== vakata_dnd.scroll_e.scrollTop() || j !== vakata_dnd.scroll_e.scrollLeft()) {\n\t\t\t\t\t/**\n\t\t\t\t\t * triggered on the document when a drag causes an element to scroll\n\t\t\t\t\t * @event\n\t\t\t\t\t * @plugin dnd\n\t\t\t\t\t * @name dnd_scroll.vakata\n\t\t\t\t\t * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start\n\t\t\t\t\t * @param {DOM} element the DOM element being dragged\n\t\t\t\t\t * @param {jQuery} helper the helper shown next to the mouse\n\t\t\t\t\t * @param {jQuery} event the element that is scrolling\n\t\t\t\t\t */\n\t\t\t\t\t$.vakata.dnd._trigger(\"scroll\", vakata_dnd.scroll_e);\n\t\t\t\t}\n\t\t\t},\n\t\t\tstart : function (e, data, html) {\n\t\t\t\tif(e.type === \"touchstart\" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) {\n\t\t\t\t\te.pageX = e.originalEvent.changedTouches[0].pageX;\n\t\t\t\t\te.pageY = e.originalEvent.changedTouches[0].pageY;\n\t\t\t\t\te.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset);\n\t\t\t\t}\n\t\t\t\tif(vakata_dnd.is_drag) { $.vakata.dnd.stop({}); }\n\t\t\t\ttry {\n\t\t\t\t\te.currentTarget.unselectable = \"on\";\n\t\t\t\t\te.currentTarget.onselectstart = function() { return false; };\n\t\t\t\t\tif(e.currentTarget.style) {\n\t\t\t\t\t\te.currentTarget.style.touchAction = \"none\";\n\t\t\t\t\t\te.currentTarget.style.msTouchAction = \"none\";\n\t\t\t\t\t\te.currentTarget.style.MozUserSelect = \"none\";\n\t\t\t\t\t}\n\t\t\t\t} catch(ignore) { }\n\t\t\t\tvakata_dnd.init_x\t= e.pageX;\n\t\t\t\tvakata_dnd.init_y\t= e.pageY;\n\t\t\t\tvakata_dnd.data\t\t= data;\n\t\t\t\tvakata_dnd.is_down\t= true;\n\t\t\t\tvakata_dnd.element\t= e.currentTarget;\n\t\t\t\tvakata_dnd.target\t= e.target;\n\t\t\t\tvakata_dnd.is_touch\t= e.type === \"touchstart\";\n\t\t\t\tif(html !== false) {\n\t\t\t\t\tvakata_dnd.helper = $(\"<div id='vakata-dnd'></div>\").html(html).css({\n\t\t\t\t\t\t\"display\"\t\t: \"block\",\n\t\t\t\t\t\t\"margin\"\t\t: \"0\",\n\t\t\t\t\t\t\"padding\"\t\t: \"0\",\n\t\t\t\t\t\t\"position\"\t\t: \"absolute\",\n\t\t\t\t\t\t\"top\"\t\t\t: \"-2000px\",\n\t\t\t\t\t\t\"lineHeight\"\t: \"16px\",\n\t\t\t\t\t\t\"zIndex\"\t\t: \"10000\"\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t$(document).on(\"mousemove.vakata.jstree touchmove.vakata.jstree\", $.vakata.dnd.drag);\n\t\t\t\t$(document).on(\"mouseup.vakata.jstree touchend.vakata.jstree\", $.vakata.dnd.stop);\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tdrag : function (e) {\n\t\t\t\tif(e.type === \"touchmove\" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) {\n\t\t\t\t\te.pageX = e.originalEvent.changedTouches[0].pageX;\n\t\t\t\t\te.pageY = e.originalEvent.changedTouches[0].pageY;\n\t\t\t\t\te.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset);\n\t\t\t\t}\n\t\t\t\tif(!vakata_dnd.is_down) { return; }\n\t\t\t\tif(!vakata_dnd.is_drag) {\n\t\t\t\t\tif(\n\t\t\t\t\t\tMath.abs(e.pageX - vakata_dnd.init_x) > (vakata_dnd.is_touch ? $.vakata.dnd.settings.threshold_touch : $.vakata.dnd.settings.threshold) ||\n\t\t\t\t\t\tMath.abs(e.pageY - vakata_dnd.init_y) > (vakata_dnd.is_touch ? $.vakata.dnd.settings.threshold_touch : $.vakata.dnd.settings.threshold)\n\t\t\t\t\t) {\n\t\t\t\t\t\tif(vakata_dnd.helper) {\n\t\t\t\t\t\t\tvakata_dnd.helper.appendTo(document.body);\n\t\t\t\t\t\t\tvakata_dnd.helper_w = vakata_dnd.helper.outerWidth();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tvakata_dnd.is_drag = true;\n\t\t\t\t\t\t$(vakata_dnd.target).one('click.vakata', false);\n\t\t\t\t\t\t/**\n\t\t\t\t\t\t * triggered on the document when a drag starts\n\t\t\t\t\t\t * @event\n\t\t\t\t\t\t * @plugin dnd\n\t\t\t\t\t\t * @name dnd_start.vakata\n\t\t\t\t\t\t * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start\n\t\t\t\t\t\t * @param {DOM} element the DOM element being dragged\n\t\t\t\t\t\t * @param {jQuery} helper the helper shown next to the mouse\n\t\t\t\t\t\t * @param {Object} event the event that caused the start (probably mousemove)\n\t\t\t\t\t\t */\n\t\t\t\t\t\t$.vakata.dnd._trigger(\"start\", e);\n\t\t\t\t\t}\n\t\t\t\t\telse { return; }\n\t\t\t\t}\n\n\t\t\t\tvar d = false, w = false,\n\t\t\t\t\tdh = false, wh = false,\n\t\t\t\t\tdw = false, ww = false,\n\t\t\t\t\tdt = false, dl = false,\n\t\t\t\t\tht = false, hl = false;\n\n\t\t\t\tvakata_dnd.scroll_t = 0;\n\t\t\t\tvakata_dnd.scroll_l = 0;\n\t\t\t\tvakata_dnd.scroll_e = false;\n\t\t\t\t$($(e.target).parentsUntil(\"body\").addBack().get().reverse())\n\t\t\t\t\t.filter(function () {\n\t\t\t\t\t\treturn\t(/^auto|scroll$/).test($(this).css(\"overflow\")) &&\n\t\t\t\t\t\t\t\t(this.scrollHeight > this.offsetHeight || this.scrollWidth > this.offsetWidth);\n\t\t\t\t\t})\n\t\t\t\t\t.each(function () {\n\t\t\t\t\t\tvar t = $(this), o = t.offset();\n\t\t\t\t\t\tif(this.scrollHeight > this.offsetHeight) {\n\t\t\t\t\t\t\tif(o.top + t.height() - e.pageY < $.vakata.dnd.settings.scroll_proximity)\t{ vakata_dnd.scroll_t = 1; }\n\t\t\t\t\t\t\tif(e.pageY - o.top < $.vakata.dnd.settings.scroll_proximity)\t\t\t\t{ vakata_dnd.scroll_t = -1; }\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(this.scrollWidth > this.offsetWidth) {\n\t\t\t\t\t\t\tif(o.left + t.width() - e.pageX < $.vakata.dnd.settings.scroll_proximity)\t{ vakata_dnd.scroll_l = 1; }\n\t\t\t\t\t\t\tif(e.pageX - o.left < $.vakata.dnd.settings.scroll_proximity)\t\t\t\t{ vakata_dnd.scroll_l = -1; }\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(vakata_dnd.scroll_t || vakata_dnd.scroll_l) {\n\t\t\t\t\t\t\tvakata_dnd.scroll_e = $(this);\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t});\n\n\t\t\t\tif(!vakata_dnd.scroll_e) {\n\t\t\t\t\td = $(document); w = $(window);\n\t\t\t\t\tdh = d.height(); wh = w.height();\n\t\t\t\t\tdw = d.width(); ww = w.width();\n\t\t\t\t\tdt = d.scrollTop(); dl = d.scrollLeft();\n\t\t\t\t\tif(dh > wh && e.pageY - dt < $.vakata.dnd.settings.scroll_proximity)\t\t{ vakata_dnd.scroll_t = -1; }\n\t\t\t\t\tif(dh > wh && wh - (e.pageY - dt) < $.vakata.dnd.settings.scroll_proximity)\t{ vakata_dnd.scroll_t = 1; }\n\t\t\t\t\tif(dw > ww && e.pageX - dl < $.vakata.dnd.settings.scroll_proximity)\t\t{ vakata_dnd.scroll_l = -1; }\n\t\t\t\t\tif(dw > ww && ww - (e.pageX - dl) < $.vakata.dnd.settings.scroll_proximity)\t{ vakata_dnd.scroll_l = 1; }\n\t\t\t\t\tif(vakata_dnd.scroll_t || vakata_dnd.scroll_l) {\n\t\t\t\t\t\tvakata_dnd.scroll_e = d;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(vakata_dnd.scroll_e) { $.vakata.dnd._scroll(true); }\n\n\t\t\t\tif(vakata_dnd.helper) {\n\t\t\t\t\tht = parseInt(e.pageY + $.vakata.dnd.settings.helper_top, 10);\n\t\t\t\t\thl = parseInt(e.pageX + $.vakata.dnd.settings.helper_left, 10);\n\t\t\t\t\tif(dh && ht + 25 > dh) { ht = dh - 50; }\n\t\t\t\t\tif(dw && hl + vakata_dnd.helper_w > dw) { hl = dw - (vakata_dnd.helper_w + 2); }\n\t\t\t\t\tvakata_dnd.helper.css({\n\t\t\t\t\t\tleft\t: hl + \"px\",\n\t\t\t\t\t\ttop\t\t: ht + \"px\"\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\t/**\n\t\t\t\t * triggered on the document when a drag is in progress\n\t\t\t\t * @event\n\t\t\t\t * @plugin dnd\n\t\t\t\t * @name dnd_move.vakata\n\t\t\t\t * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start\n\t\t\t\t * @param {DOM} element the DOM element being dragged\n\t\t\t\t * @param {jQuery} helper the helper shown next to the mouse\n\t\t\t\t * @param {Object} event the event that caused this to trigger (most likely mousemove)\n\t\t\t\t */\n\t\t\t\t$.vakata.dnd._trigger(\"move\", e);\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\tstop : function (e) {\n\t\t\t\tif(e.type === \"touchend\" && e.originalEvent && e.originalEvent.changedTouches && e.originalEvent.changedTouches[0]) {\n\t\t\t\t\te.pageX = e.originalEvent.changedTouches[0].pageX;\n\t\t\t\t\te.pageY = e.originalEvent.changedTouches[0].pageY;\n\t\t\t\t\te.target = document.elementFromPoint(e.originalEvent.changedTouches[0].pageX - window.pageXOffset, e.originalEvent.changedTouches[0].pageY - window.pageYOffset);\n\t\t\t\t}\n\t\t\t\tif(vakata_dnd.is_drag) {\n\t\t\t\t\t/**\n\t\t\t\t\t * triggered on the document when a drag stops (the dragged element is dropped)\n\t\t\t\t\t * @event\n\t\t\t\t\t * @plugin dnd\n\t\t\t\t\t * @name dnd_stop.vakata\n\t\t\t\t\t * @param {Mixed} data any data supplied with the call to $.vakata.dnd.start\n\t\t\t\t\t * @param {DOM} element the DOM element being dragged\n\t\t\t\t\t * @param {jQuery} helper the helper shown next to the mouse\n\t\t\t\t\t * @param {Object} event the event that caused the stop\n\t\t\t\t\t */\n\t\t\t\t\tif (e.target !== vakata_dnd.target) {\n\t\t\t\t\t\t$(vakata_dnd.target).off('click.vakata');\n\t\t\t\t\t}\n\t\t\t\t\t$.vakata.dnd._trigger(\"stop\", e);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tif(e.type === \"touchend\" && e.target === vakata_dnd.target) {\n\t\t\t\t\t\tvar to = setTimeout(function () { $(e.target).trigger('click'); }, 100);\n\t\t\t\t\t\t$(e.target).one('click', function() { if(to) { clearTimeout(to); } });\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t$.vakata.dnd._clean();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t};\n\t}($));\n\n\t// include the dnd plugin by default\n\t// $.jstree.defaults.plugins.push(\"dnd\");\n\n\n/**\n * ### Massload plugin\n *\n * Adds massload functionality to jsTree, so that multiple nodes can be loaded in a single request (only useful with lazy loading).\n */\n\n\t/**\n\t * massload configuration\n\t *\n\t * It is possible to set this to a standard jQuery-like AJAX config.\n\t * In addition to the standard jQuery ajax options here you can supply functions for `data` and `url`, the functions will be run in the current instance's scope and a param will be passed indicating which node IDs need to be loaded, the return value of those functions will be used.\n\t *\n\t * You can also set this to a function, that function will receive the node IDs being loaded as argument and a second param which is a function (callback) which should be called with the result.\n\t *\n\t * Both the AJAX and the function approach rely on the same return value - an object where the keys are the node IDs, and the value is the children of that node as an array.\n\t *\n\t *\t{\n\t *\t\t\"id1\" : [{ \"text\" : \"Child of ID1\", \"id\" : \"c1\" }, { \"text\" : \"Another child of ID1\", \"id\" : \"c2\" }],\n\t *\t\t\"id2\" : [{ \"text\" : \"Child of ID2\", \"id\" : \"c3\" }]\n\t *\t}\n\t * \n\t * @name $.jstree.defaults.massload\n\t * @plugin massload\n\t */\n\t$.jstree.defaults.massload = null;\n\t$.jstree.plugins.massload = function (options, parent) {\n\t\tthis.init = function (el, options) {\n\t\t\tthis._data.massload = {};\n\t\t\tparent.init.call(this, el, options);\n\t\t};\n\t\tthis._load_nodes = function (nodes, callback, is_callback, force_reload) {\n\t\t\tvar s = this.settings.massload,\t\t\t\t\n\t\t\t\ttoLoad = [],\n\t\t\t\tm = this._model.data,\n\t\t\t\ti, j, dom;\n\t\t\tif (!is_callback) {\n\t\t\t\tfor(i = 0, j = nodes.length; i < j; i++) {\n\t\t\t\t\tif(!m[nodes[i]] || ( (!m[nodes[i]].state.loaded && !m[nodes[i]].state.failed) || force_reload) ) {\n\t\t\t\t\t\ttoLoad.push(nodes[i]);\n\t\t\t\t\t\tdom = this.get_node(nodes[i], true);\n\t\t\t\t\t\tif (dom && dom.length) {\n\t\t\t\t\t\t\tdom.addClass(\"jstree-loading\").attr('aria-busy',true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tthis._data.massload = {};\n\t\t\t\tif (toLoad.length) {\n\t\t\t\t\tif($.vakata.is_function(s)) {\n\t\t\t\t\t\treturn s.call(this, toLoad, function (data) {\n\t\t\t\t\t\t\tvar i, j;\n\t\t\t\t\t\t\tif(data) {\n\t\t\t\t\t\t\t\tfor(i in data) {\n\t\t\t\t\t\t\t\t\tif(data.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\t\tthis._data.massload[i] = data[i];\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfor(i = 0, j = nodes.length; i < j; i++) {\n\t\t\t\t\t\t\t\tdom = this.get_node(nodes[i], true);\n\t\t\t\t\t\t\t\tif (dom && dom.length) {\n\t\t\t\t\t\t\t\t\tdom.removeClass(\"jstree-loading\").attr('aria-busy',false);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tparent._load_nodes.call(this, nodes, callback, is_callback, force_reload);\n\t\t\t\t\t\t}.bind(this));\n\t\t\t\t\t}\n\t\t\t\t\tif(typeof s === 'object' && s && s.url) {\n\t\t\t\t\t\ts = $.extend(true, {}, s);\n\t\t\t\t\t\tif($.vakata.is_function(s.url)) {\n\t\t\t\t\t\t\ts.url = s.url.call(this, toLoad);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif($.vakata.is_function(s.data)) {\n\t\t\t\t\t\t\ts.data = s.data.call(this, toLoad);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn $.ajax(s)\n\t\t\t\t\t\t\t.done(function (data,t,x) {\n\t\t\t\t\t\t\t\t\tvar i, j;\n\t\t\t\t\t\t\t\t\tif(data) {\n\t\t\t\t\t\t\t\t\t\tfor(i in data) {\n\t\t\t\t\t\t\t\t\t\t\tif(data.hasOwnProperty(i)) {\n\t\t\t\t\t\t\t\t\t\t\t\tthis._data.massload[i] = data[i];\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tfor(i = 0, j = nodes.length; i < j; i++) {\n\t\t\t\t\t\t\t\t\t\tdom = this.get_node(nodes[i], true);\n\t\t\t\t\t\t\t\t\t\tif (dom && dom.length) {\n\t\t\t\t\t\t\t\t\t\t\tdom.removeClass(\"jstree-loading\").attr('aria-busy',false);\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tparent._load_nodes.call(this, nodes, callback, is_callback, force_reload);\n\t\t\t\t\t\t\t\t}.bind(this))\n\t\t\t\t\t\t\t.fail(function (f) {\n\t\t\t\t\t\t\t\t\tparent._load_nodes.call(this, nodes, callback, is_callback, force_reload);\n\t\t\t\t\t\t\t\t}.bind(this));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn parent._load_nodes.call(this, nodes, callback, is_callback, force_reload);\n\t\t};\n\t\tthis._load_node = function (obj, callback) {\n\t\t\tvar data = this._data.massload[obj.id],\n\t\t\t\trslt = null, dom;\n\t\t\tif(data) {\n\t\t\t\trslt = this[typeof data === 'string' ? '_append_html_data' : '_append_json_data'](\n\t\t\t\t\tobj,\n\t\t\t\t\ttypeof data === 'string' ? $($.parseHTML(data)).filter(function () { return this.nodeType !== 3; }) : data,\n\t\t\t\t\tfunction (status) { callback.call(this, status); }\n\t\t\t\t);\n\t\t\t\tdom = this.get_node(obj.id, true);\n\t\t\t\tif (dom && dom.length) {\n\t\t\t\t\tdom.removeClass(\"jstree-loading\").attr('aria-busy',false);\n\t\t\t\t}\n\t\t\t\tdelete this._data.massload[obj.id];\n\t\t\t\treturn rslt;\n\t\t\t}\n\t\t\treturn parent._load_node.call(this, obj, callback);\n\t\t};\n\t};\n\n\n/**\n * ### Search plugin\n *\n * Adds search functionality to jsTree.\n */\n\n\t/**\n\t * stores all defaults for the search plugin\n\t * @name $.jstree.defaults.search\n\t * @plugin search\n\t */\n\t$.jstree.defaults.search = {\n\t\t/**\n\t\t * a jQuery-like AJAX config, which jstree uses if a server should be queried for results.\n\t\t *\n\t\t * A `str` (which is the search string) parameter will be added with the request, an optional `inside` parameter will be added if the search is limited to a node id. The expected result is a JSON array with nodes that need to be opened so that matching nodes will be revealed.\n\t\t * Leave this setting as `false` to not query the server. You can also set this to a function, which will be invoked in the instance's scope and receive 3 parameters - the search string, the callback to call with the array of nodes to load, and the optional node ID to limit the search to\n\t\t * @name $.jstree.defaults.search.ajax\n\t\t * @plugin search\n\t\t */\n\t\tajax : false,\n\t\t/**\n\t\t * Indicates if the search should be fuzzy or not (should `chnd3` match `child node 3`). Default is `false`.\n\t\t * @name $.jstree.defaults.search.fuzzy\n\t\t * @plugin search\n\t\t */\n\t\tfuzzy : false,\n\t\t/**\n\t\t * Indicates if the search should be case sensitive. Default is `false`.\n\t\t * @name $.jstree.defaults.search.case_sensitive\n\t\t * @plugin search\n\t\t */\n\t\tcase_sensitive : false,\n\t\t/**\n\t\t * Indicates if the tree should be filtered (by default) to show only matching nodes (keep in mind this can be a heavy on large trees in old browsers).\n\t\t * This setting can be changed at runtime when calling the search method. Default is `false`.\n\t\t * @name $.jstree.defaults.search.show_only_matches\n\t\t * @plugin search\n\t\t */\n\t\tshow_only_matches : false,\n\t\t/**\n\t\t * Indicates if the children of matched element are shown (when show_only_matches is true)\n\t\t * This setting can be changed at runtime when calling the search method. Default is `false`.\n\t\t * @name $.jstree.defaults.search.show_only_matches_children\n\t\t * @plugin search\n\t\t */\n\t\tshow_only_matches_children : false,\n\t\t/**\n\t\t * Indicates if all nodes opened to reveal the search result, should be closed when the search is cleared or a new search is performed. Default is `true`.\n\t\t * @name $.jstree.defaults.search.close_opened_onclear\n\t\t * @plugin search\n\t\t */\n\t\tclose_opened_onclear : true,\n\t\t/**\n\t\t * Indicates if only leaf nodes should be included in search results. Default is `false`.\n\t\t * @name $.jstree.defaults.search.search_leaves_only\n\t\t * @plugin search\n\t\t */\n\t\tsearch_leaves_only : false,\n\t\t/**\n\t\t * If set to a function it wil be called in the instance's scope with two arguments - search string and node (where node will be every node in the structure, so use with caution).\n\t\t * If the function returns a truthy value the node will be considered a match (it might not be displayed if search_only_leaves is set to true and the node is not a leaf). Default is `false`.\n\t\t * @name $.jstree.defaults.search.search_callback\n\t\t * @plugin search\n\t\t */\n\t\tsearch_callback : false\n\t};\n\n\t$.jstree.plugins.search = function (options, parent) {\n\t\tthis.bind = function () {\n\t\t\tparent.bind.call(this);\n\n\t\t\tthis._data.search.str = \"\";\n\t\t\tthis._data.search.dom = $();\n\t\t\tthis._data.search.res = [];\n\t\t\tthis._data.search.opn = [];\n\t\t\tthis._data.search.som = false;\n\t\t\tthis._data.search.smc = false;\n\t\t\tthis._data.search.hdn = [];\n\n\t\t\tthis.element\n\t\t\t\t.on(\"search.jstree\", function (e, data) {\n\t\t\t\t\t\tif(this._data.search.som && data.res.length) {\n\t\t\t\t\t\t\tvar m = this._model.data, i, j, p = [], k, l;\n\t\t\t\t\t\t\tfor(i = 0, j = data.res.length; i < j; i++) {\n\t\t\t\t\t\t\t\tif(m[data.res[i]] && !m[data.res[i]].state.hidden) {\n\t\t\t\t\t\t\t\t\tp.push(data.res[i]);\n\t\t\t\t\t\t\t\t\tp = p.concat(m[data.res[i]].parents);\n\t\t\t\t\t\t\t\t\tif(this._data.search.smc) {\n\t\t\t\t\t\t\t\t\t\tfor (k = 0, l = m[data.res[i]].children_d.length; k < l; k++) {\n\t\t\t\t\t\t\t\t\t\t\tif (m[m[data.res[i]].children_d[k]] && !m[m[data.res[i]].children_d[k]].state.hidden) {\n\t\t\t\t\t\t\t\t\t\t\t\tp.push(m[data.res[i]].children_d[k]);\n\t\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tp = $.vakata.array_remove_item($.vakata.array_unique(p), $.jstree.root);\n\t\t\t\t\t\t\tthis._data.search.hdn = this.hide_all(true);\n\t\t\t\t\t\t\tthis.show_node(p, true);\n\t\t\t\t\t\t\tthis.redraw(true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"clear_search.jstree\", function (e, data) {\n\t\t\t\t\t\tif(this._data.search.som && data.res.length) {\n\t\t\t\t\t\t\tthis.show_node(this._data.search.hdn, true);\n\t\t\t\t\t\t\tthis.redraw(true);\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this));\n\t\t};\n\t\t/**\n\t\t * used to search the tree nodes for a given string\n\t\t * @name search(str [, skip_async])\n\t\t * @param {String} str the search string\n\t\t * @param {Boolean} skip_async if set to true server will not be queried even if configured\n\t\t * @param {Boolean} show_only_matches if set to true only matching nodes will be shown (keep in mind this can be very slow on large trees or old browsers)\n\t\t * @param {mixed} inside an optional node to whose children to limit the search\n\t\t * @param {Boolean} append if set to true the results of this search are appended to the previous search\n\t\t * @plugin search\n\t\t * @trigger search.jstree\n\t\t */\n\t\tthis.search = function (str, skip_async, show_only_matches, inside, append, show_only_matches_children) {\n\t\t\tif(str === false || $.vakata.trim(str.toString()) === \"\") {\n\t\t\t\treturn this.clear_search();\n\t\t\t}\n\t\t\tinside = this.get_node(inside);\n\t\t\tinside = inside && inside.id ? inside.id : null;\n\t\t\tstr = str.toString();\n\t\t\tvar s = this.settings.search,\n\t\t\t\ta = s.ajax ? s.ajax : false,\n\t\t\t\tm = this._model.data,\n\t\t\t\tf = null,\n\t\t\t\tr = [],\n\t\t\t\tp = [], i, j;\n\t\t\tif(this._data.search.res.length && !append) {\n\t\t\t\tthis.clear_search();\n\t\t\t}\n\t\t\tif(show_only_matches === undefined) {\n\t\t\t\tshow_only_matches = s.show_only_matches;\n\t\t\t}\n\t\t\tif(show_only_matches_children === undefined) {\n\t\t\t\tshow_only_matches_children = s.show_only_matches_children;\n\t\t\t}\n\t\t\tif(!skip_async && a !== false) {\n\t\t\t\tif($.vakata.is_function(a)) {\n\t\t\t\t\treturn a.call(this, str, function (d) {\n\t\t\t\t\t\t\tif(d && d.d) { d = d.d; }\n\t\t\t\t\t\t\tthis._load_nodes(!$.vakata.is_array(d) ? [] : $.vakata.array_unique(d), function () {\n\t\t\t\t\t\t\t\tthis.search(str, true, show_only_matches, inside, append, show_only_matches_children);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}.bind(this), inside);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\ta = $.extend({}, a);\n\t\t\t\t\tif(!a.data) { a.data = {}; }\n\t\t\t\t\ta.data.str = str;\n\t\t\t\t\tif(inside) {\n\t\t\t\t\t\ta.data.inside = inside;\n\t\t\t\t\t}\n\t\t\t\t\tif (this._data.search.lastRequest) {\n\t\t\t\t\t\tthis._data.search.lastRequest.abort();\n\t\t\t\t\t}\n\t\t\t\t\tthis._data.search.lastRequest = $.ajax(a)\n\t\t\t\t\t\t.fail(function () {\n\t\t\t\t\t\t\tthis._data.core.last_error = { 'error' : 'ajax', 'plugin' : 'search', 'id' : 'search_01', 'reason' : 'Could not load search parents', 'data' : JSON.stringify(a) };\n\t\t\t\t\t\t\tthis.settings.core.error.call(this, this._data.core.last_error);\n\t\t\t\t\t\t}.bind(this))\n\t\t\t\t\t\t.done(function (d) {\n\t\t\t\t\t\t\tif(d && d.d) { d = d.d; }\n\t\t\t\t\t\t\tthis._load_nodes(!$.vakata.is_array(d) ? [] : $.vakata.array_unique(d), function () {\n\t\t\t\t\t\t\t\tthis.search(str, true, show_only_matches, inside, append, show_only_matches_children);\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t}.bind(this));\n\t\t\t\t\treturn this._data.search.lastRequest;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(!append) {\n\t\t\t\tthis._data.search.str = str;\n\t\t\t\tthis._data.search.dom = $();\n\t\t\t\tthis._data.search.res = [];\n\t\t\t\tthis._data.search.opn = [];\n\t\t\t\tthis._data.search.som = show_only_matches;\n\t\t\t\tthis._data.search.smc = show_only_matches_children;\n\t\t\t}\n\n\t\t\tf = new $.vakata.search(str, true, { caseSensitive : s.case_sensitive, fuzzy : s.fuzzy });\n\t\t\t$.each(m[inside ? inside : $.jstree.root].children_d, function (ii, i) {\n\t\t\t\tvar v = m[i];\n\t\t\t\tif(v.text && !v.state.hidden && (!s.search_leaves_only || (v.state.loaded && v.children.length === 0)) && ( (s.search_callback && s.search_callback.call(this, str, v)) || (!s.search_callback && f.search(v.text).isMatch) ) ) {\n\t\t\t\t\tr.push(i);\n\t\t\t\t\tp = p.concat(v.parents);\n\t\t\t\t}\n\t\t\t});\n\t\t\tif(r.length) {\n\t\t\t\tp = $.vakata.array_unique(p);\n\t\t\t\tfor(i = 0, j = p.length; i < j; i++) {\n\t\t\t\t\tif(p[i] !== $.jstree.root && m[p[i]] && this.open_node(p[i], null, 0) === true) {\n\t\t\t\t\t\tthis._data.search.opn.push(p[i]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif(!append) {\n\t\t\t\t\tthis._data.search.dom = $(this.element[0].querySelectorAll('#' + $.map(r, function (v) { return \"0123456789\".indexOf(v[0]) !== -1 ? '\\\\3' + v[0] + ' ' + v.substr(1).replace($.jstree.idregex,'\\\\$&') : v.replace($.jstree.idregex,'\\\\$&'); }).join(', #')));\n\t\t\t\t\tthis._data.search.res = r;\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tthis._data.search.dom = this._data.search.dom.add($(this.element[0].querySelectorAll('#' + $.map(r, function (v) { return \"0123456789\".indexOf(v[0]) !== -1 ? '\\\\3' + v[0] + ' ' + v.substr(1).replace($.jstree.idregex,'\\\\$&') : v.replace($.jstree.idregex,'\\\\$&'); }).join(', #'))));\n\t\t\t\t\tthis._data.search.res = $.vakata.array_unique(this._data.search.res.concat(r));\n\t\t\t\t}\n\t\t\t\tthis._data.search.dom.children(\".jstree-anchor\").addClass('jstree-search');\n\t\t\t}\n\t\t\t/**\n\t\t\t * triggered after search is complete\n\t\t\t * @event\n\t\t\t * @name search.jstree\n\t\t\t * @param {jQuery} nodes a jQuery collection of matching nodes\n\t\t\t * @param {String} str the search string\n\t\t\t * @param {Array} res a collection of objects represeing the matching nodes\n\t\t\t * @plugin search\n\t\t\t */\n\t\t\tthis.trigger('search', { nodes : this._data.search.dom, str : str, res : this._data.search.res, show_only_matches : show_only_matches });\n\t\t};\n\t\t/**\n\t\t * used to clear the last search (removes classes and shows all nodes if filtering is on)\n\t\t * @name clear_search()\n\t\t * @plugin search\n\t\t * @trigger clear_search.jstree\n\t\t */\n\t\tthis.clear_search = function () {\n\t\t\tif(this.settings.search.close_opened_onclear) {\n\t\t\t\tthis.close_node(this._data.search.opn, 0);\n\t\t\t}\n\t\t\t/**\n\t\t\t * triggered after search is complete\n\t\t\t * @event\n\t\t\t * @name clear_search.jstree\n\t\t\t * @param {jQuery} nodes a jQuery collection of matching nodes (the result from the last search)\n\t\t\t * @param {String} str the search string (the last search string)\n\t\t\t * @param {Array} res a collection of objects represeing the matching nodes (the result from the last search)\n\t\t\t * @plugin search\n\t\t\t */\n\t\t\tthis.trigger('clear_search', { 'nodes' : this._data.search.dom, str : this._data.search.str, res : this._data.search.res });\n\t\t\tif(this._data.search.res.length) {\n\t\t\t\tthis._data.search.dom = $(this.element[0].querySelectorAll('#' + $.map(this._data.search.res, function (v) {\n\t\t\t\t\treturn \"0123456789\".indexOf(v[0]) !== -1 ? '\\\\3' + v[0] + ' ' + v.substr(1).replace($.jstree.idregex,'\\\\$&') : v.replace($.jstree.idregex,'\\\\$&');\n\t\t\t\t}).join(', #')));\n\t\t\t\tthis._data.search.dom.children(\".jstree-anchor\").removeClass(\"jstree-search\");\n\t\t\t}\n\t\t\tthis._data.search.str = \"\";\n\t\t\tthis._data.search.res = [];\n\t\t\tthis._data.search.opn = [];\n\t\t\tthis._data.search.dom = $();\n\t\t};\n\n\t\tthis.redraw_node = function(obj, deep, callback, force_render) {\n\t\t\tobj = parent.redraw_node.apply(this, arguments);\n\t\t\tif(obj) {\n\t\t\t\tif($.inArray(obj.id, this._data.search.res) !== -1) {\n\t\t\t\t\tvar i, j, tmp = null;\n\t\t\t\t\tfor(i = 0, j = obj.childNodes.length; i < j; i++) {\n\t\t\t\t\t\tif(obj.childNodes[i] && obj.childNodes[i].className && obj.childNodes[i].className.indexOf(\"jstree-anchor\") !== -1) {\n\t\t\t\t\t\t\ttmp = obj.childNodes[i];\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif(tmp) {\n\t\t\t\t\t\ttmp.className += ' jstree-search';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn obj;\n\t\t};\n\t};\n\n\t// helpers\n\t(function ($) {\n\t\t// from http://kiro.me/projects/fuse.html\n\t\t$.vakata.search = function(pattern, txt, options) {\n\t\t\toptions = options || {};\n\t\t\toptions = $.extend({}, $.vakata.search.defaults, options);\n\t\t\tif(options.fuzzy !== false) {\n\t\t\t\toptions.fuzzy = true;\n\t\t\t}\n\t\t\tpattern = options.caseSensitive ? pattern : pattern.toLowerCase();\n\t\t\tvar MATCH_LOCATION\t= options.location,\n\t\t\t\tMATCH_DISTANCE\t= options.distance,\n\t\t\t\tMATCH_THRESHOLD\t= options.threshold,\n\t\t\t\tpatternLen = pattern.length,\n\t\t\t\tmatchmask, pattern_alphabet, match_bitapScore, search;\n\t\t\tif(patternLen > 32) {\n\t\t\t\toptions.fuzzy = false;\n\t\t\t}\n\t\t\tif(options.fuzzy) {\n\t\t\t\tmatchmask = 1 << (patternLen - 1);\n\t\t\t\tpattern_alphabet = (function () {\n\t\t\t\t\tvar mask = {},\n\t\t\t\t\t\ti = 0;\n\t\t\t\t\tfor (i = 0; i < patternLen; i++) {\n\t\t\t\t\t\tmask[pattern.charAt(i)] = 0;\n\t\t\t\t\t}\n\t\t\t\t\tfor (i = 0; i < patternLen; i++) {\n\t\t\t\t\t\tmask[pattern.charAt(i)] |= 1 << (patternLen - i - 1);\n\t\t\t\t\t}\n\t\t\t\t\treturn mask;\n\t\t\t\t}());\n\t\t\t\tmatch_bitapScore = function (e, x) {\n\t\t\t\t\tvar accuracy = e / patternLen,\n\t\t\t\t\t\tproximity = Math.abs(MATCH_LOCATION - x);\n\t\t\t\t\tif(!MATCH_DISTANCE) {\n\t\t\t\t\t\treturn proximity ? 1.0 : accuracy;\n\t\t\t\t\t}\n\t\t\t\t\treturn accuracy + (proximity / MATCH_DISTANCE);\n\t\t\t\t};\n\t\t\t}\n\t\t\tsearch = function (text) {\n\t\t\t\ttext = options.caseSensitive ? text : text.toLowerCase();\n\t\t\t\tif(pattern === text || text.indexOf(pattern) !== -1) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tisMatch: true,\n\t\t\t\t\t\tscore: 0\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif(!options.fuzzy) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tisMatch: false,\n\t\t\t\t\t\tscore: 1\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tvar i, j,\n\t\t\t\t\ttextLen = text.length,\n\t\t\t\t\tscoreThreshold = MATCH_THRESHOLD,\n\t\t\t\t\tbestLoc = text.indexOf(pattern, MATCH_LOCATION),\n\t\t\t\t\tbinMin, binMid,\n\t\t\t\t\tbinMax = patternLen + textLen,\n\t\t\t\t\tlastRd, start, finish, rd, charMatch,\n\t\t\t\t\tscore = 1,\n\t\t\t\t\tlocations = [];\n\t\t\t\tif (bestLoc !== -1) {\n\t\t\t\t\tscoreThreshold = Math.min(match_bitapScore(0, bestLoc), scoreThreshold);\n\t\t\t\t\tbestLoc = text.lastIndexOf(pattern, MATCH_LOCATION + patternLen);\n\t\t\t\t\tif (bestLoc !== -1) {\n\t\t\t\t\t\tscoreThreshold = Math.min(match_bitapScore(0, bestLoc), scoreThreshold);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbestLoc = -1;\n\t\t\t\tfor (i = 0; i < patternLen; i++) {\n\t\t\t\t\tbinMin = 0;\n\t\t\t\t\tbinMid = binMax;\n\t\t\t\t\twhile (binMin < binMid) {\n\t\t\t\t\t\tif (match_bitapScore(i, MATCH_LOCATION + binMid) <= scoreThreshold) {\n\t\t\t\t\t\t\tbinMin = binMid;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tbinMax = binMid;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbinMid = Math.floor((binMax - binMin) / 2 + binMin);\n\t\t\t\t\t}\n\t\t\t\t\tbinMax = binMid;\n\t\t\t\t\tstart = Math.max(1, MATCH_LOCATION - binMid + 1);\n\t\t\t\t\tfinish = Math.min(MATCH_LOCATION + binMid, textLen) + patternLen;\n\t\t\t\t\trd = new Array(finish + 2);\n\t\t\t\t\trd[finish + 1] = (1 << i) - 1;\n\t\t\t\t\tfor (j = finish; j >= start; j--) {\n\t\t\t\t\t\tcharMatch = pattern_alphabet[text.charAt(j - 1)];\n\t\t\t\t\t\tif (i === 0) {\n\t\t\t\t\t\t\trd[j] = ((rd[j + 1] << 1) | 1) & charMatch;\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\trd[j] = ((rd[j + 1] << 1) | 1) & charMatch | (((lastRd[j + 1] | lastRd[j]) << 1) | 1) | lastRd[j + 1];\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (rd[j] & matchmask) {\n\t\t\t\t\t\t\tscore = match_bitapScore(i, j - 1);\n\t\t\t\t\t\t\tif (score <= scoreThreshold) {\n\t\t\t\t\t\t\t\tscoreThreshold = score;\n\t\t\t\t\t\t\t\tbestLoc = j - 1;\n\t\t\t\t\t\t\t\tlocations.push(bestLoc);\n\t\t\t\t\t\t\t\tif (bestLoc > MATCH_LOCATION) {\n\t\t\t\t\t\t\t\t\tstart = Math.max(1, 2 * MATCH_LOCATION - bestLoc);\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif (match_bitapScore(i + 1, MATCH_LOCATION) > scoreThreshold) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tlastRd = rd;\n\t\t\t\t}\n\t\t\t\treturn {\n\t\t\t\t\tisMatch: bestLoc >= 0,\n\t\t\t\t\tscore: score\n\t\t\t\t};\n\t\t\t};\n\t\t\treturn txt === true ? { 'search' : search } : search(txt);\n\t\t};\n\t\t$.vakata.search.defaults = {\n\t\t\tlocation : 0,\n\t\t\tdistance : 100,\n\t\t\tthreshold : 0.6,\n\t\t\tfuzzy : false,\n\t\t\tcaseSensitive : false\n\t\t};\n\t}($));\n\n\t// include the search plugin by default\n\t// $.jstree.defaults.plugins.push(\"search\");\n\n\n/**\n * ### Sort plugin\n *\n * Automatically sorts all siblings in the tree according to a sorting function.\n */\n\n\t/**\n\t * the settings function used to sort the nodes.\n\t * It is executed in the tree's context, accepts two nodes as arguments and should return `1` or `-1`.\n\t * @name $.jstree.defaults.sort\n\t * @plugin sort\n\t */\n\t$.jstree.defaults.sort = function (a, b) {\n\t\t//return this.get_type(a) === this.get_type(b) ? (this.get_text(a) > this.get_text(b) ? 1 : -1) : this.get_type(a) >= this.get_type(b);\n\t\treturn this.get_text(a) > this.get_text(b) ? 1 : -1;\n\t};\n\t$.jstree.plugins.sort = function (options, parent) {\n\t\tthis.bind = function () {\n\t\t\tparent.bind.call(this);\n\t\t\tthis.element\n\t\t\t\t.on(\"model.jstree\", function (e, data) {\n\t\t\t\t\t\tthis.sort(data.parent, true);\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"rename_node.jstree create_node.jstree\", function (e, data) {\n\t\t\t\t\t\tthis.sort(data.parent || data.node.parent, false);\n\t\t\t\t\t\tthis.redraw_node(data.parent || data.node.parent, true);\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"move_node.jstree copy_node.jstree\", function (e, data) {\n\t\t\t\t\t\tthis.sort(data.parent, false);\n\t\t\t\t\t\tthis.redraw_node(data.parent, true);\n\t\t\t\t\t}.bind(this));\n\t\t};\n\t\t/**\n\t\t * used to sort a node's children\n\t\t * @private\n\t\t * @name sort(obj [, deep])\n\t\t * @param {mixed} obj the node\n\t\t * @param {Boolean} deep if set to `true` nodes are sorted recursively.\n\t\t * @plugin sort\n\t\t * @trigger search.jstree\n\t\t */\n\t\tthis.sort = function (obj, deep) {\n\t\t\tvar i, j;\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(obj && obj.children && obj.children.length) {\n\t\t\t\tobj.children.sort(this.settings.sort.bind(this));\n\t\t\t\tif(deep) {\n\t\t\t\t\tfor(i = 0, j = obj.children_d.length; i < j; i++) {\n\t\t\t\t\t\tthis.sort(obj.children_d[i], false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t};\n\n\t// include the sort plugin by default\n\t// $.jstree.defaults.plugins.push(\"sort\");\n\n/**\n * ### State plugin\n *\n * Saves the state of the tree (selected nodes, opened nodes) on the user's computer using available options (localStorage, cookies, etc)\n */\n\n\tvar to = false;\n\t/**\n\t * stores all defaults for the state plugin\n\t * @name $.jstree.defaults.state\n\t * @plugin state\n\t */\n\t$.jstree.defaults.state = {\n\t\t/**\n\t\t * A string for the key to use when saving the current tree (change if using multiple trees in your project). Defaults to `jstree`.\n\t\t * @name $.jstree.defaults.state.key\n\t\t * @plugin state\n\t\t */\n\t\tkey\t\t: 'jstree',\n\t\t/**\n\t\t * A space separated list of events that trigger a state save. Defaults to `changed.jstree open_node.jstree close_node.jstree`.\n\t\t * @name $.jstree.defaults.state.events\n\t\t * @plugin state\n\t\t */\n\t\tevents\t: 'changed.jstree open_node.jstree close_node.jstree check_node.jstree uncheck_node.jstree',\n\t\t/**\n\t\t * Time in milliseconds after which the state will expire. Defaults to 'false' meaning - no expire.\n\t\t * @name $.jstree.defaults.state.ttl\n\t\t * @plugin state\n\t\t */\n\t\tttl\t\t: false,\n\t\t/**\n\t\t * A function that will be executed prior to restoring state with one argument - the state object. Can be used to clear unwanted parts of the state.\n\t\t * @name $.jstree.defaults.state.filter\n\t\t * @plugin state\n\t\t */\n\t\tfilter\t: false,\n\t\t/**\n\t\t * Should loaded nodes be restored (setting this to true means that it is possible that the whole tree will be loaded for some users - use with caution). Defaults to `false`\n\t\t * @name $.jstree.defaults.state.preserve_loaded\n\t\t * @plugin state\n\t\t */\n\t\tpreserve_loaded : false\n\t};\n\t$.jstree.plugins.state = function (options, parent) {\n\t\tthis.bind = function () {\n\t\t\tparent.bind.call(this);\n\t\t\tvar bind = function () {\n\t\t\t\tthis.element.on(this.settings.state.events, function () {\n\t\t\t\t\tif(to) { clearTimeout(to); }\n\t\t\t\t\tto = setTimeout(function () { this.save_state(); }.bind(this), 100);\n\t\t\t\t}.bind(this));\n\t\t\t\t/**\n\t\t\t\t * triggered when the state plugin is finished restoring the state (and immediately after ready if there is no state to restore).\n\t\t\t\t * @event\n\t\t\t\t * @name state_ready.jstree\n\t\t\t\t * @plugin state\n\t\t\t\t */\n\t\t\t\tthis.trigger('state_ready');\n\t\t\t}.bind(this);\n\t\t\tthis.element\n\t\t\t\t.on(\"ready.jstree\", function (e, data) {\n\t\t\t\t\t\tthis.element.one(\"restore_state.jstree\", bind);\n\t\t\t\t\t\tif(!this.restore_state()) { bind(); }\n\t\t\t\t\t}.bind(this));\n\t\t};\n\t\t/**\n\t\t * save the state\n\t\t * @name save_state()\n\t\t * @plugin state\n\t\t */\n\t\tthis.save_state = function () {\n\t\t\tvar tm = this.get_state();\n\t\t\tif (!this.settings.state.preserve_loaded) {\n\t\t\t\tdelete tm.core.loaded;\n\t\t\t}\n\t\t\tvar st = { 'state' : tm, 'ttl' : this.settings.state.ttl, 'sec' : +(new Date()) };\n\t\t\t$.vakata.storage.set(this.settings.state.key, JSON.stringify(st));\n\t\t};\n\t\t/**\n\t\t * restore the state from the user's computer\n\t\t * @name restore_state()\n\t\t * @plugin state\n\t\t */\n\t\tthis.restore_state = function () {\n\t\t\tvar k = $.vakata.storage.get(this.settings.state.key);\n\t\t\tif(!!k) { try { k = JSON.parse(k); } catch(ex) { return false; } }\n\t\t\tif(!!k && k.ttl && k.sec && +(new Date()) - k.sec > k.ttl) { return false; }\n\t\t\tif(!!k && k.state) { k = k.state; }\n\t\t\tif(!!k && $.vakata.is_function(this.settings.state.filter)) { k = this.settings.state.filter.call(this, k); }\n\t\t\tif(!!k) {\n\t\t\t\tif (!this.settings.state.preserve_loaded) {\n\t\t\t\t\tdelete k.core.loaded;\n\t\t\t\t}\n\t\t\t\tthis.element.one(\"set_state.jstree\", function (e, data) { data.instance.trigger('restore_state', { 'state' : $.extend(true, {}, k) }); });\n\t\t\t\tthis.set_state(k);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\treturn false;\n\t\t};\n\t\t/**\n\t\t * clear the state on the user's computer\n\t\t * @name clear_state()\n\t\t * @plugin state\n\t\t */\n\t\tthis.clear_state = function () {\n\t\t\treturn $.vakata.storage.del(this.settings.state.key);\n\t\t};\n\t};\n\n\t(function ($, undefined) {\n\t\t$.vakata.storage = {\n\t\t\t// simply specifying the functions in FF throws an error\n\t\t\tset : function (key, val) { return window.localStorage.setItem(key, val); },\n\t\t\tget : function (key) { return window.localStorage.getItem(key); },\n\t\t\tdel : function (key) { return window.localStorage.removeItem(key); }\n\t\t};\n\t}($));\n\n\t// include the state plugin by default\n\t// $.jstree.defaults.plugins.push(\"state\");\n\n/**\n * ### Types plugin\n *\n * Makes it possible to add predefined types for groups of nodes, which make it possible to easily control nesting rules and icon for each group.\n */\n\n\t/**\n\t * An object storing all types as key value pairs, where the key is the type name and the value is an object that could contain following keys (all optional).\n\t *\n\t * * `max_children` the maximum number of immediate children this node type can have. Do not specify or set to `-1` for unlimited.\n\t * * `max_depth` the maximum number of nesting this node type can have. A value of `1` would mean that the node can have children, but no grandchildren. Do not specify or set to `-1` for unlimited.\n\t * * `valid_children` an array of node type strings, that nodes of this type can have as children. Do not specify or set to `-1` for no limits.\n\t * * `icon` a string - can be a path to an icon or a className, if using an image that is in the current directory use a `./` prefix, otherwise it will be detected as a class. Omit to use the default icon from your theme.\n\t * * `li_attr` an object of values which will be used to add HTML attributes on the resulting LI DOM node (merged with the node's own data)\n\t * * `a_attr` an object of values which will be used to add HTML attributes on the resulting A DOM node (merged with the node's own data)\n\t *\n\t * There are two predefined types:\n\t *\n\t * * `#` represents the root of the tree, for example `max_children` would control the maximum number of root nodes.\n\t * * `default` represents the default node - any settings here will be applied to all nodes that do not have a type specified.\n\t *\n\t * @name $.jstree.defaults.types\n\t * @plugin types\n\t */\n\t$.jstree.defaults.types = {\n\t\t'default' : {}\n\t};\n\t$.jstree.defaults.types[$.jstree.root] = {};\n\n\t$.jstree.plugins.types = function (options, parent) {\n\t\tthis.init = function (el, options) {\n\t\t\tvar i, j;\n\t\t\tif(options && options.types && options.types['default']) {\n\t\t\t\tfor(i in options.types) {\n\t\t\t\t\tif(i !== \"default\" && i !== $.jstree.root && options.types.hasOwnProperty(i)) {\n\t\t\t\t\t\tfor(j in options.types['default']) {\n\t\t\t\t\t\t\tif(options.types['default'].hasOwnProperty(j) && options.types[i][j] === undefined) {\n\t\t\t\t\t\t\t\toptions.types[i][j] = options.types['default'][j];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tparent.init.call(this, el, options);\n\t\t\tthis._model.data[$.jstree.root].type = $.jstree.root;\n\t\t};\n\t\tthis.refresh = function (skip_loading, forget_state) {\n\t\t\tparent.refresh.call(this, skip_loading, forget_state);\n\t\t\tthis._model.data[$.jstree.root].type = $.jstree.root;\n\t\t};\n\t\tthis.bind = function () {\n\t\t\tthis.element\n\t\t\t\t.on('model.jstree', function (e, data) {\n\t\t\t\t\t\tvar m = this._model.data,\n\t\t\t\t\t\t\tdpc = data.nodes,\n\t\t\t\t\t\t\tt = this.settings.types,\n\t\t\t\t\t\t\ti, j, c = 'default', k;\n\t\t\t\t\t\tfor(i = 0, j = dpc.length; i < j; i++) {\n\t\t\t\t\t\t\tc = 'default';\n\t\t\t\t\t\t\tif(m[dpc[i]].original && m[dpc[i]].original.type && t[m[dpc[i]].original.type]) {\n\t\t\t\t\t\t\t\tc = m[dpc[i]].original.type;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(m[dpc[i]].data && m[dpc[i]].data.jstree && m[dpc[i]].data.jstree.type && t[m[dpc[i]].data.jstree.type]) {\n\t\t\t\t\t\t\t\tc = m[dpc[i]].data.jstree.type;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tm[dpc[i]].type = c;\n\t\t\t\t\t\t\tif(m[dpc[i]].icon === true && t[c].icon !== undefined) {\n\t\t\t\t\t\t\t\tm[dpc[i]].icon = t[c].icon;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(t[c].li_attr !== undefined && typeof t[c].li_attr === 'object') {\n\t\t\t\t\t\t\t\tfor (k in t[c].li_attr) {\n\t\t\t\t\t\t\t\t\tif (t[c].li_attr.hasOwnProperty(k)) {\n\t\t\t\t\t\t\t\t\t\tif (k === 'id') {\n\t\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse if (m[dpc[i]].li_attr[k] === undefined) {\n\t\t\t\t\t\t\t\t\t\t\tm[dpc[i]].li_attr[k] = t[c].li_attr[k];\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse if (k === 'class') {\n\t\t\t\t\t\t\t\t\t\t\tm[dpc[i]].li_attr['class'] = t[c].li_attr['class'] + ' ' + m[dpc[i]].li_attr['class'];\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif(t[c].a_attr !== undefined && typeof t[c].a_attr === 'object') {\n\t\t\t\t\t\t\t\tfor (k in t[c].a_attr) {\n\t\t\t\t\t\t\t\t\tif (t[c].a_attr.hasOwnProperty(k)) {\n\t\t\t\t\t\t\t\t\t\tif (k === 'id') {\n\t\t\t\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse if (m[dpc[i]].a_attr[k] === undefined) {\n\t\t\t\t\t\t\t\t\t\t\tm[dpc[i]].a_attr[k] = t[c].a_attr[k];\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse if (k === 'href' && m[dpc[i]].a_attr[k] === '#') {\n\t\t\t\t\t\t\t\t\t\t\tm[dpc[i]].a_attr['href'] = t[c].a_attr['href'];\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\telse if (k === 'class') {\n\t\t\t\t\t\t\t\t\t\t\tm[dpc[i]].a_attr['class'] = t[c].a_attr['class'] + ' ' + m[dpc[i]].a_attr['class'];\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tm[$.jstree.root].type = $.jstree.root;\n\t\t\t\t\t}.bind(this));\n\t\t\tparent.bind.call(this);\n\t\t};\n\t\tthis.get_json = function (obj, options, flat) {\n\t\t\tvar i, j,\n\t\t\t\tm = this._model.data,\n\t\t\t\topt = options ? $.extend(true, {}, options, {no_id:false}) : {},\n\t\t\t\ttmp = parent.get_json.call(this, obj, opt, flat);\n\t\t\tif(tmp === false) { return false; }\n\t\t\tif($.vakata.is_array(tmp)) {\n\t\t\t\tfor(i = 0, j = tmp.length; i < j; i++) {\n\t\t\t\t\ttmp[i].type = tmp[i].id && m[tmp[i].id] && m[tmp[i].id].type ? m[tmp[i].id].type : \"default\";\n\t\t\t\t\tif(options && options.no_id) {\n\t\t\t\t\t\tdelete tmp[i].id;\n\t\t\t\t\t\tif(tmp[i].li_attr && tmp[i].li_attr.id) {\n\t\t\t\t\t\t\tdelete tmp[i].li_attr.id;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(tmp[i].a_attr && tmp[i].a_attr.id) {\n\t\t\t\t\t\t\tdelete tmp[i].a_attr.id;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\ttmp.type = tmp.id && m[tmp.id] && m[tmp.id].type ? m[tmp.id].type : \"default\";\n\t\t\t\tif(options && options.no_id) {\n\t\t\t\t\ttmp = this._delete_ids(tmp);\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn tmp;\n\t\t};\n\t\tthis._delete_ids = function (tmp) {\n\t\t\tif($.vakata.is_array(tmp)) {\n\t\t\t\tfor(var i = 0, j = tmp.length; i < j; i++) {\n\t\t\t\t\ttmp[i] = this._delete_ids(tmp[i]);\n\t\t\t\t}\n\t\t\t\treturn tmp;\n\t\t\t}\n\t\t\tdelete tmp.id;\n\t\t\tif(tmp.li_attr && tmp.li_attr.id) {\n\t\t\t\tdelete tmp.li_attr.id;\n\t\t\t}\n\t\t\tif(tmp.a_attr && tmp.a_attr.id) {\n\t\t\t\tdelete tmp.a_attr.id;\n\t\t\t}\n\t\t\tif(tmp.children && $.vakata.is_array(tmp.children)) {\n\t\t\t\ttmp.children = this._delete_ids(tmp.children);\n\t\t\t}\n\t\t\treturn tmp;\n\t\t};\n\t\tthis.check = function (chk, obj, par, pos, more) {\n\t\t\tif(parent.check.call(this, chk, obj, par, pos, more) === false) { return false; }\n\t\t\tobj = obj && obj.id ? obj : this.get_node(obj);\n\t\t\tpar = par && par.id ? par : this.get_node(par);\n\t\t\tvar m = obj && obj.id ? (more && more.origin ? more.origin : $.jstree.reference(obj.id)) : null, tmp, d, i, j;\n\t\t\tm = m && m._model && m._model.data ? m._model.data : null;\n\t\t\tswitch(chk) {\n\t\t\t\tcase \"create_node\":\n\t\t\t\tcase \"move_node\":\n\t\t\t\tcase \"copy_node\":\n\t\t\t\t\tif(chk !== 'move_node' || $.inArray(obj.id, par.children) === -1) {\n\t\t\t\t\t\ttmp = this.get_rules(par);\n\t\t\t\t\t\tif(tmp.max_children !== undefined && tmp.max_children !== -1 && tmp.max_children === par.children.length) {\n\t\t\t\t\t\t\tthis._data.core.last_error = { 'error' : 'check', 'plugin' : 'types', 'id' : 'types_01', 'reason' : 'max_children prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(tmp.valid_children !== undefined && tmp.valid_children !== -1 && $.inArray((obj.type || 'default'), tmp.valid_children) === -1) {\n\t\t\t\t\t\t\tthis._data.core.last_error = { 'error' : 'check', 'plugin' : 'types', 'id' : 'types_02', 'reason' : 'valid_children prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };\n\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(m && obj.children_d && obj.parents) {\n\t\t\t\t\t\t\td = 0;\n\t\t\t\t\t\t\tfor(i = 0, j = obj.children_d.length; i < j; i++) {\n\t\t\t\t\t\t\t\td = Math.max(d, m[obj.children_d[i]].parents.length);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\td = d - obj.parents.length + 1;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif(d <= 0 || d === undefined) { d = 1; }\n\t\t\t\t\t\tdo {\n\t\t\t\t\t\t\tif(tmp.max_depth !== undefined && tmp.max_depth !== -1 && tmp.max_depth < d) {\n\t\t\t\t\t\t\t\tthis._data.core.last_error = { 'error' : 'check', 'plugin' : 'types', 'id' : 'types_03', 'reason' : 'max_depth prevents function: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };\n\t\t\t\t\t\t\t\treturn false;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tpar = this.get_node(par.parent);\n\t\t\t\t\t\t\ttmp = this.get_rules(par);\n\t\t\t\t\t\t\td++;\n\t\t\t\t\t\t} while(par);\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn true;\n\t\t};\n\t\t/**\n\t\t * used to retrieve the type settings object for a node\n\t\t * @name get_rules(obj)\n\t\t * @param {mixed} obj the node to find the rules for\n\t\t * @return {Object}\n\t\t * @plugin types\n\t\t */\n\t\tthis.get_rules = function (obj) {\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!obj) { return false; }\n\t\t\tvar tmp = this.get_type(obj, true);\n\t\t\tif(tmp.max_depth === undefined) { tmp.max_depth = -1; }\n\t\t\tif(tmp.max_children === undefined) { tmp.max_children = -1; }\n\t\t\tif(tmp.valid_children === undefined) { tmp.valid_children = -1; }\n\t\t\treturn tmp;\n\t\t};\n\t\t/**\n\t\t * used to retrieve the type string or settings object for a node\n\t\t * @name get_type(obj [, rules])\n\t\t * @param {mixed} obj the node to find the rules for\n\t\t * @param {Boolean} rules if set to `true` instead of a string the settings object will be returned\n\t\t * @return {String|Object}\n\t\t * @plugin types\n\t\t */\n\t\tthis.get_type = function (obj, rules) {\n\t\t\tobj = this.get_node(obj);\n\t\t\treturn (!obj) ? false : ( rules ? $.extend({ 'type' : obj.type }, this.settings.types[obj.type]) : obj.type);\n\t\t};\n\t\t/**\n\t\t * used to change a node's type\n\t\t * @name set_type(obj, type)\n\t\t * @param {mixed} obj the node to change\n\t\t * @param {String} type the new type\n\t\t * @plugin types\n\t\t */\n\t\tthis.set_type = function (obj, type) {\n\t\t\tvar m = this._model.data, t, t1, t2, old_type, old_icon, k, d, a;\n\t\t\tif($.vakata.is_array(obj)) {\n\t\t\t\tobj = obj.slice();\n\t\t\t\tfor(t1 = 0, t2 = obj.length; t1 < t2; t1++) {\n\t\t\t\t\tthis.set_type(obj[t1], type);\n\t\t\t\t}\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tt = this.settings.types;\n\t\t\tobj = this.get_node(obj);\n\t\t\tif(!t[type] || !obj) { return false; }\n\t\t\td = this.get_node(obj, true);\n\t\t\tif (d && d.length) {\n\t\t\t\ta = d.children('.jstree-anchor');\n\t\t\t}\n\t\t\told_type = obj.type;\n\t\t\told_icon = this.get_icon(obj);\n\t\t\tobj.type = type;\n\t\t\tif(old_icon === true || !t[old_type] || (t[old_type].icon !== undefined && old_icon === t[old_type].icon)) {\n\t\t\t\tthis.set_icon(obj, t[type].icon !== undefined ? t[type].icon : true);\n\t\t\t}\n\n\t\t\t// remove old type props\n\t\t\tif(t[old_type] && t[old_type].li_attr !== undefined && typeof t[old_type].li_attr === 'object') {\n\t\t\t\tfor (k in t[old_type].li_attr) {\n\t\t\t\t\tif (t[old_type].li_attr.hasOwnProperty(k)) {\n\t\t\t\t\t\tif (k === 'id') {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (k === 'class') {\n\t\t\t\t\t\t\tm[obj.id].li_attr['class'] = (m[obj.id].li_attr['class'] || '').replace(t[old_type].li_attr[k], '');\n\t\t\t\t\t\t\tif (d) { d.removeClass(t[old_type].li_attr[k]); }\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (m[obj.id].li_attr[k] === t[old_type].li_attr[k]) {\n\t\t\t\t\t\t\tm[obj.id].li_attr[k] = null;\n\t\t\t\t\t\t\tif (d) { d.removeAttr(k); }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(t[old_type] && t[old_type].a_attr !== undefined && typeof t[old_type].a_attr === 'object') {\n\t\t\t\tfor (k in t[old_type].a_attr) {\n\t\t\t\t\tif (t[old_type].a_attr.hasOwnProperty(k)) {\n\t\t\t\t\t\tif (k === 'id') {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (k === 'class') {\n\t\t\t\t\t\t\tm[obj.id].a_attr['class'] = (m[obj.id].a_attr['class'] || '').replace(t[old_type].a_attr[k], '');\n\t\t\t\t\t\t\tif (a) { a.removeClass(t[old_type].a_attr[k]); }\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (m[obj.id].a_attr[k] === t[old_type].a_attr[k]) {\n\t\t\t\t\t\t\tif (k === 'href') {\n\t\t\t\t\t\t\t\tm[obj.id].a_attr[k] = '#';\n\t\t\t\t\t\t\t\tif (a) { a.attr('href', '#'); }\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\tdelete m[obj.id].a_attr[k];\n\t\t\t\t\t\t\t\tif (a) { a.removeAttr(k); }\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// add new props\n\t\t\tif(t[type].li_attr !== undefined && typeof t[type].li_attr === 'object') {\n\t\t\t\tfor (k in t[type].li_attr) {\n\t\t\t\t\tif (t[type].li_attr.hasOwnProperty(k)) {\n\t\t\t\t\t\tif (k === 'id') {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (m[obj.id].li_attr[k] === undefined) {\n\t\t\t\t\t\t\tm[obj.id].li_attr[k] = t[type].li_attr[k];\n\t\t\t\t\t\t\tif (d) {\n\t\t\t\t\t\t\t\tif (k === 'class') {\n\t\t\t\t\t\t\t\t\td.addClass(t[type].li_attr[k]);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\td.attr(k, t[type].li_attr[k]);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (k === 'class') {\n\t\t\t\t\t\t\tm[obj.id].li_attr['class'] = t[type].li_attr[k] + ' ' + m[obj.id].li_attr['class'];\n\t\t\t\t\t\t\tif (d) { d.addClass(t[type].li_attr[k]); }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif(t[type].a_attr !== undefined && typeof t[type].a_attr === 'object') {\n\t\t\t\tfor (k in t[type].a_attr) {\n\t\t\t\t\tif (t[type].a_attr.hasOwnProperty(k)) {\n\t\t\t\t\t\tif (k === 'id') {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (m[obj.id].a_attr[k] === undefined) {\n\t\t\t\t\t\t\tm[obj.id].a_attr[k] = t[type].a_attr[k];\n\t\t\t\t\t\t\tif (a) {\n\t\t\t\t\t\t\t\tif (k === 'class') {\n\t\t\t\t\t\t\t\t\ta.addClass(t[type].a_attr[k]);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\telse {\n\t\t\t\t\t\t\t\t\ta.attr(k, t[type].a_attr[k]);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (k === 'href' && m[obj.id].a_attr[k] === '#') {\n\t\t\t\t\t\t\tm[obj.id].a_attr['href'] = t[type].a_attr['href'];\n\t\t\t\t\t\t\tif (a) { a.attr('href', t[type].a_attr['href']); }\n\t\t\t\t\t\t}\n\t\t\t\t\t\telse if (k === 'class') {\n\t\t\t\t\t\t\tm[obj.id].a_attr['class'] = t[type].a_attr['class'] + ' ' + m[obj.id].a_attr['class'];\n\t\t\t\t\t\t\tif (a) { a.addClass(t[type].a_attr[k]); }\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn true;\n\t\t};\n\t};\n\t// include the types plugin by default\n\t// $.jstree.defaults.plugins.push(\"types\");\n\n\n/**\n * ### Unique plugin\n *\n * Enforces that no nodes with the same name can coexist as siblings.\n */\n\n\t/**\n\t * stores all defaults for the unique plugin\n\t * @name $.jstree.defaults.unique\n\t * @plugin unique\n\t */\n\t$.jstree.defaults.unique = {\n\t\t/**\n\t\t * Indicates if the comparison should be case sensitive. Default is `false`.\n\t\t * @name $.jstree.defaults.unique.case_sensitive\n\t\t * @plugin unique\n\t\t */\n\t\tcase_sensitive : false,\n\t\t/**\n\t\t * Indicates if white space should be trimmed before the comparison. Default is `false`.\n\t\t * @name $.jstree.defaults.unique.trim_whitespace\n\t\t * @plugin unique\n\t\t */\n\t\ttrim_whitespace : false,\n\t\t/**\n\t\t * A callback executed in the instance's scope when a new node is created and the name is already taken, the two arguments are the conflicting name and the counter. The default will produce results like `New node (2)`.\n\t\t * @name $.jstree.defaults.unique.duplicate\n\t\t * @plugin unique\n\t\t */\n\t\tduplicate : function (name, counter) {\n\t\t\treturn name + ' (' + counter + ')';\n\t\t}\n\t};\n\n\t$.jstree.plugins.unique = function (options, parent) {\n\t\tthis.check = function (chk, obj, par, pos, more) {\n\t\t\tif(parent.check.call(this, chk, obj, par, pos, more) === false) { return false; }\n\t\t\tobj = obj && obj.id ? obj : this.get_node(obj);\n\t\t\tpar = par && par.id ? par : this.get_node(par);\n\t\t\tif(!par || !par.children) { return true; }\n\t\t\tvar n = chk === \"rename_node\" ? pos : obj.text,\n\t\t\t\tc = [],\n\t\t\t\ts = this.settings.unique.case_sensitive,\n\t\t\t\tw = this.settings.unique.trim_whitespace,\n\t\t\t\tm = this._model.data, i, j, t;\n\t\t\tfor(i = 0, j = par.children.length; i < j; i++) {\n\t\t\t\tt = m[par.children[i]].text;\n\t\t\t\tif (!s) {\n\t\t\t\t\tt = t.toLowerCase();\n\t\t\t\t}\n\t\t\t\tif (w) {\n\t\t\t\t\tt = t.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n\t\t\t\t}\n\t\t\t\tc.push(t);\n\t\t\t}\n\t\t\tif(!s) { n = n.toLowerCase(); }\n\t\t\tif (w) { n = n.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, ''); }\n\t\t\tswitch(chk) {\n\t\t\t\tcase \"delete_node\":\n\t\t\t\t\treturn true;\n\t\t\t\tcase \"rename_node\":\n\t\t\t\t\tt = obj.text || '';\n\t\t\t\t\tif (!s) {\n\t\t\t\t\t\tt = t.toLowerCase();\n\t\t\t\t\t}\n\t\t\t\t\tif (w) {\n\t\t\t\t\t\tt = t.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n\t\t\t\t\t}\n\t\t\t\t\ti = ($.inArray(n, c) === -1 || (obj.text && t === n));\n\t\t\t\t\tif(!i) {\n\t\t\t\t\t\tthis._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_01', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };\n\t\t\t\t\t}\n\t\t\t\t\treturn i;\n\t\t\t\tcase \"create_node\":\n\t\t\t\t\ti = ($.inArray(n, c) === -1);\n\t\t\t\t\tif(!i) {\n\t\t\t\t\t\tthis._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_04', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };\n\t\t\t\t\t}\n\t\t\t\t\treturn i;\n\t\t\t\tcase \"copy_node\":\n\t\t\t\t\ti = ($.inArray(n, c) === -1);\n\t\t\t\t\tif(!i) {\n\t\t\t\t\t\tthis._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_02', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };\n\t\t\t\t\t}\n\t\t\t\t\treturn i;\n\t\t\t\tcase \"move_node\":\n\t\t\t\t\ti = ( (obj.parent === par.id && (!more || !more.is_multi)) || $.inArray(n, c) === -1);\n\t\t\t\t\tif(!i) {\n\t\t\t\t\t\tthis._data.core.last_error = { 'error' : 'check', 'plugin' : 'unique', 'id' : 'unique_03', 'reason' : 'Child with name ' + n + ' already exists. Preventing: ' + chk, 'data' : JSON.stringify({ 'chk' : chk, 'pos' : pos, 'obj' : obj && obj.id ? obj.id : false, 'par' : par && par.id ? par.id : false }) };\n\t\t\t\t\t}\n\t\t\t\t\treturn i;\n\t\t\t}\n\t\t\treturn true;\n\t\t};\n\t\tthis.create_node = function (par, node, pos, callback, is_loaded) {\n\t\t\tif(!node || node.text === undefined) {\n\t\t\t\tif(par === null) {\n\t\t\t\t\tpar = $.jstree.root;\n\t\t\t\t}\n\t\t\t\tpar = this.get_node(par);\n\t\t\t\tif(!par) {\n\t\t\t\t\treturn parent.create_node.call(this, par, node, pos, callback, is_loaded);\n\t\t\t\t}\n\t\t\t\tpos = pos === undefined ? \"last\" : pos;\n\t\t\t\tif(!pos.toString().match(/^(before|after)$/) && !is_loaded && !this.is_loaded(par)) {\n\t\t\t\t\treturn parent.create_node.call(this, par, node, pos, callback, is_loaded);\n\t\t\t\t}\n\t\t\t\tif(!node) { node = {}; }\n\t\t\t\tvar tmp, n, dpc, i, j, m = this._model.data, s = this.settings.unique.case_sensitive, w = this.settings.unique.trim_whitespace, cb = this.settings.unique.duplicate, t;\n\t\t\t\tn = tmp = this.get_string('New node');\n\t\t\t\tdpc = [];\n\t\t\t\tfor(i = 0, j = par.children.length; i < j; i++) {\n\t\t\t\t\tt = m[par.children[i]].text;\n\t\t\t\t\tif (!s) {\n\t\t\t\t\t\tt = t.toLowerCase();\n\t\t\t\t\t}\n\t\t\t\t\tif (w) {\n\t\t\t\t\t\tt = t.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n\t\t\t\t\t}\n\t\t\t\t\tdpc.push(t);\n\t\t\t\t}\n\t\t\t\ti = 1;\n\t\t\t\tt = n;\n\t\t\t\tif (!s) {\n\t\t\t\t\tt = t.toLowerCase();\n\t\t\t\t}\n\t\t\t\tif (w) {\n\t\t\t\t\tt = t.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n\t\t\t\t}\n\t\t\t\twhile($.inArray(t, dpc) !== -1) {\n\t\t\t\t\tn = cb.call(this, tmp, (++i)).toString();\n\t\t\t\t\tt = n;\n\t\t\t\t\tif (!s) {\n\t\t\t\t\t\tt = t.toLowerCase();\n\t\t\t\t\t}\n\t\t\t\t\tif (w) {\n\t\t\t\t\t\tt = t.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, '');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tnode.text = n;\n\t\t\t}\n\t\t\treturn parent.create_node.call(this, par, node, pos, callback, is_loaded);\n\t\t};\n\t};\n\n\t// include the unique plugin by default\n\t// $.jstree.defaults.plugins.push(\"unique\");\n\n\n/**\n * ### Wholerow plugin\n *\n * Makes each node appear block level. Making selection easier. May cause slow down for large trees in old browsers.\n */\n\n\tvar div = document.createElement('DIV');\n\tdiv.setAttribute('unselectable','on');\n\tdiv.setAttribute('role','presentation');\n\tdiv.className = 'jstree-wholerow';\n\tdiv.innerHTML = '&#160;';\n\t$.jstree.plugins.wholerow = function (options, parent) {\n\t\tthis.bind = function () {\n\t\t\tparent.bind.call(this);\n\n\t\t\tthis.element\n\t\t\t\t.on('ready.jstree set_state.jstree', function () {\n\t\t\t\t\t\tthis.hide_dots();\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"init.jstree loading.jstree ready.jstree\", function () {\n\t\t\t\t\t\t//div.style.height = this._data.core.li_height + 'px';\n\t\t\t\t\t\tthis.get_container_ul().addClass('jstree-wholerow-ul');\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"deselect_all.jstree\", function (e, data) {\n\t\t\t\t\t\tthis.element.find('.jstree-wholerow-clicked').removeClass('jstree-wholerow-clicked');\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"changed.jstree\", function (e, data) {\n\t\t\t\t\t\tthis.element.find('.jstree-wholerow-clicked').removeClass('jstree-wholerow-clicked');\n\t\t\t\t\t\tvar tmp = false, i, j;\n\t\t\t\t\t\tfor(i = 0, j = data.selected.length; i < j; i++) {\n\t\t\t\t\t\t\ttmp = this.get_node(data.selected[i], true);\n\t\t\t\t\t\t\tif(tmp && tmp.length) {\n\t\t\t\t\t\t\t\ttmp.children('.jstree-wholerow').addClass('jstree-wholerow-clicked');\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"open_node.jstree\", function (e, data) {\n\t\t\t\t\t\tthis.get_node(data.node, true).find('.jstree-clicked').parent().children('.jstree-wholerow').addClass('jstree-wholerow-clicked');\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"hover_node.jstree dehover_node.jstree\", function (e, data) {\n\t\t\t\t\t\tif(e.type === \"hover_node\" && this.is_disabled(data.node)) { return; }\n\t\t\t\t\t\tthis.get_node(data.node, true).children('.jstree-wholerow')[e.type === \"hover_node\"?\"addClass\":\"removeClass\"]('jstree-wholerow-hovered');\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"contextmenu.jstree\", \".jstree-wholerow\", function (e) {\n\t\t\t\t\t\tif (this._data.contextmenu) {\n\t\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\t\tvar tmp = $.Event('contextmenu', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey, pageX : e.pageX, pageY : e.pageY });\n\t\t\t\t\t\t\t$(e.currentTarget).closest(\".jstree-node\").children(\".jstree-anchor\").first().trigger(tmp);\n\t\t\t\t\t\t}\n\t\t\t\t\t}.bind(this))\n\t\t\t\t/*!\n\t\t\t\t.on(\"mousedown.jstree touchstart.jstree\", \".jstree-wholerow\", function (e) {\n\t\t\t\t\t\tif(e.target === e.currentTarget) {\n\t\t\t\t\t\t\tvar a = $(e.currentTarget).closest(\".jstree-node\").children(\".jstree-anchor\");\n\t\t\t\t\t\t\te.target = a[0];\n\t\t\t\t\t\t\ta.trigger(e);\n\t\t\t\t\t\t}\n\t\t\t\t\t})\n\t\t\t\t*/\n\t\t\t\t.on(\"click.jstree\", \".jstree-wholerow\", function (e) {\n\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\tvar tmp = $.Event('click', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey });\n\t\t\t\t\t\t$(e.currentTarget).closest(\".jstree-node\").children(\".jstree-anchor\").first().trigger(tmp).trigger('focus');\n\t\t\t\t\t})\n\t\t\t\t.on(\"dblclick.jstree\", \".jstree-wholerow\", function (e) {\n\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\tvar tmp = $.Event('dblclick', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey });\n\t\t\t\t\t\t$(e.currentTarget).closest(\".jstree-node\").children(\".jstree-anchor\").first().trigger(tmp).trigger('focus');\n\t\t\t\t\t})\n\t\t\t\t.on(\"click.jstree\", \".jstree-leaf > .jstree-ocl\", function (e) {\n\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\tvar tmp = $.Event('click', { metaKey : e.metaKey, ctrlKey : e.ctrlKey, altKey : e.altKey, shiftKey : e.shiftKey });\n\t\t\t\t\t\t$(e.currentTarget).closest(\".jstree-node\").children(\".jstree-anchor\").first().trigger(tmp).trigger('focus');\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"mouseover.jstree\", \".jstree-wholerow, .jstree-icon\", function (e) {\n\t\t\t\t\t\te.stopImmediatePropagation();\n\t\t\t\t\t\tif(!this.is_disabled(e.currentTarget)) {\n\t\t\t\t\t\t\tthis.hover_node(e.currentTarget);\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}.bind(this))\n\t\t\t\t.on(\"mouseleave.jstree\", \".jstree-node\", function (e) {\n\t\t\t\t\t\tthis.dehover_node(e.currentTarget);\n\t\t\t\t\t}.bind(this));\n\t\t};\n\t\tthis.teardown = function () {\n\t\t\tif(this.settings.wholerow) {\n\t\t\t\tthis.element.find(\".jstree-wholerow\").remove();\n\t\t\t}\n\t\t\tparent.teardown.call(this);\n\t\t};\n\t\tthis.redraw_node = function(obj, deep, callback, force_render) {\n\t\t\tobj = parent.redraw_node.apply(this, arguments);\n\t\t\tif(obj) {\n\t\t\t\tvar tmp = div.cloneNode(true);\n\t\t\t\t//tmp.style.height = this._data.core.li_height + 'px';\n\t\t\t\tif($.inArray(obj.id, this._data.core.selected) !== -1) { tmp.className += ' jstree-wholerow-clicked'; }\n\t\t\t\tif(this._data.core.focused && this._data.core.focused === obj.id) { tmp.className += ' jstree-wholerow-hovered'; }\n\t\t\t\tobj.insertBefore(tmp, obj.childNodes[0]);\n\t\t\t}\n\t\t\treturn obj;\n\t\t};\n\t};\n\t// include the wholerow plugin by default\n\t// $.jstree.defaults.plugins.push(\"wholerow\");\n\tif(window.customElements && Object && Object.create) {\n\t\tvar proto = Object.create(HTMLElement.prototype);\n\t\tproto.createdCallback = function () {\n\t\t\tvar c = { core : {}, plugins : [] }, i;\n\t\t\tfor(i in $.jstree.plugins) {\n\t\t\t\tif($.jstree.plugins.hasOwnProperty(i) && this.attributes[i]) {\n\t\t\t\t\tc.plugins.push(i);\n\t\t\t\t\tif(this.getAttribute(i) && JSON.parse(this.getAttribute(i))) {\n\t\t\t\t\t\tc[i] = JSON.parse(this.getAttribute(i));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor(i in $.jstree.defaults.core) {\n\t\t\t\tif($.jstree.defaults.core.hasOwnProperty(i) && this.attributes[i]) {\n\t\t\t\t\tc.core[i] = JSON.parse(this.getAttribute(i)) || this.getAttribute(i);\n\t\t\t\t}\n\t\t\t}\n\t\t\t$(this).jstree(c);\n\t\t};\n\t\t// proto.attributeChangedCallback = function (name, previous, value) { };\n\t\ttry {\n\t\t\twindow.customElements.define(\"vakata-jstree\", function() {}, { prototype: proto });\n\t\t} catch (ignore) { }\n\t}\n\n}));//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9ub2RlX21vZHVsZXMvanN0cmVlL2Rpc3QvanN0cmVlLmpzLmpzIiwibWFwcGluZ3MiOiJBQUFBO0FBQ0E7QUFDQTtBQUNBLEtBQUssSUFBMEM7QUFDL0MsRUFBRSxpQ0FBTyxDQUFDLDJDQUFRLENBQUMsb0NBQUUsT0FBTztBQUFBO0FBQUE7QUFBQSxrR0FBQztBQUM3QjtBQUNBLE1BQU0sRUFLSjtBQUNGLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOEJBQThCOztBQUU5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQSxxQ0FBcUMsV0FBVztBQUNoRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLDBCQUEwQjtBQUN0QyxZQUFZLFFBQVE7QUFDcEIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCO0FBQzdCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNB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LE9BQU87QUFDckIsY0FBYyxTQUFTO0FBQ3ZCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUssYUFBYTtBQUNsQixHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsY0FBYyxPQUFPO0FBQ3JCLGNBQWMsUUFBUTtBQUN0QixjQUFjLFNBQVM7QUFDdkIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0MsT0FBTztBQUM3QztBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxjQUFjLE9BQU87QUFDckIsY0FBYyxTQUFTO0FBQ3ZCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxjQUFjLE9BQU87QUFDckIsY0FBYyxTQUFTO0FBQ3ZCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7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QUFDQSxxQ0FBcUMsT0FBTztBQUM1QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkNBQTZDLE9BQU87QUFDcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZDQUE2QyxPQUFPO0FBQ3BEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNFQUFzRTtBQUN0RTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQyxPQUFPO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7O0FBRUE7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEMsT0FBTztBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQyxPQUFPO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMENBQTBDLE9BQU87QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5QjtBQUN6Qiw0QkFBNEIsT0FBTztBQUNuQztBQUNBLDRDQUE0QyxPQUFPO0FBQ25EO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBDQUEwQyxPQUFPO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0Q0FBNEMsT0FBTztBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0Q0FBNEMsT0FBTztBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLDZCQUE2QixPQUFPO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0JBQStCO0FBQy9COztBQUVBO0FBQ0EsNkJBQTZCLE9BQU87QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEMsT0FBTztBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyRkFBMkY7QUFDM0Y7QUFDQSw0REFBNEQ7QUFDNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrQ0FBa0M7QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUNBQXVDLDBDQUEwQztBQUNqRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUNBQXVDLDJDQUEyQztBQUNsRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUNBQXlDLHdDQUF3QywwQkFBMEIsT0FBTztBQUNsSDtBQUNBO0FBQ0E7QUFDQSxjQUFjLE9BQU87QUFDckIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUNBQXlDLE9BQU87QUFDaEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUNBQWlDLFNBQVM7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSxRQUFRO0FBQ3ZCO0FBQ0E7QUFDQSx1Q0FBdUMsY0FBYztBQUNyRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUNBQWlDLFNBQVM7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSxRQUFRO0FBQ3ZCO0FBQ0E7QUFDQSxzQ0FBc0MsY0FBYztBQUNwRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLDZCQUE2QjtBQUNoRTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsTUFBTTtBQUNuQixlQUFlLE9BQU87QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkNBQTJDLE9BQU87QUFDbEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLFFBQVE7QUFDckIsY0FBYyxPQUFPO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsT0FBTztBQUNwQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QztBQUM5QztBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsU0FBUztBQUMxQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsUUFBUTtBQUN2QixlQUFlLE9BQU87QUFDdEIsZUFBZSxRQUFRO0FBQ3ZCO0FBQ0E7QUFDQSxpQ0FBaUMsc0VBQXNFO0FBQ3ZHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLE9BQU87QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEM7QUFDOUM7QUFDQTtBQUNBO0FBQ0EsaUNBQWlDLFNBQVM7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLFFBQVE7QUFDdkIsZUFBZSxPQUFPO0FBQ3RCLGVBQWUsUUFBUTtBQUN2QjtBQUNBO0FBQ0EsbUNBQW1DLHNFQUFzRTtBQUN6RztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QztBQUM5QztBQUNBO0FBQ0EsdURBQXVELE9BQU87QUFDOUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxPQUFPO0FBQ3JCO0FBQ0E7QUFDQSwrQkFBK0IsMkNBQTJDO0FBQzFFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEM7QUFDOUM7QUFDQSx1REFBdUQsT0FBTztBQUM5RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjLE9BQU87QUFDckI7QUFDQTtBQUNBLGlDQUFpQyx5REFBeUQ7QUFDMUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFFBQVE7QUFDdEIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QztBQUM5QztBQUNBLDBDQUEwQztBQUMxQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEM7QUFDOUMsb0VBQW9FLDBCQUEwQjtBQUM5RjtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0EsOENBQThDO0FBQzlDO0FBQ0EsWUFBWTtBQUNaLDhCQUE4QixPQUFPO0FBQ3JDO0FBQ0E7QUFDQSw4QkFBOEIsT0FBTztBQUNyQyw2Q0FBNkMsT0FBTztBQUNwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkNBQTJDLDBCQUEwQjtBQUNyRTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsUUFBUTtBQUN0QixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0EsOENBQThDO0FBQzlDO0FBQ0E7QUFDQSw4QkFBOEIsT0FBTztBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQywwQkFBMEI7QUFDckU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkNBQTJDLE9BQU87QUFDbEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhDQUE4QztBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscURBQXFEO0FBQ3JEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2QkFBNkI7QUFDN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyRUFBMkU7QUFDM0U7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4QkFBOEI7QUFDOUI7QUFDQTtBQUNBLFNBQVM7QUFDVCxpQ0FBaUMsc0JBQXNCO0FBQ3ZEO0FBQ0EsT0FBTztBQUNQO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBLDBGQUEwRjtBQUMxRjtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUCxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07O0FBRU47QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUCxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsT0FBTztBQUNwQixhQUFhLFFBQVE7QUFDckIsYUFBYSxR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Q3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxjQUFjO0FBQ2Q7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLDZDQUE2QztBQUM3QztBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCO0FBQzdCLFFBQVE7QUFDUjtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlCQUF5QjtBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsR0FBRztBQUNILEVBQUU7QUFDRjs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtB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QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMEVBQTBFLDZCQUE2QjtBQUN2Ryx5QkFBeUI7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsT0FBTztBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBLDREQUE0RCxPQUFPO0FBQ25FO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCLGFBQWEsU0FBUztBQUN0QixhQUFhLFNBQVM7QUFDdEIsYUFBYSxPQUFPO0FBQ3BCLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQjtBQUN0QjtBQUNBO0FBQ0EsUUFBUTtBQUNSLE9BQU87QUFDUDtBQUNBO0FBQ0Esb0JBQW9CO0FBQ3BCLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0M7QUFDdEM7QUFDQSxPQUFPO0FBQ1A7QUFDQSxzQkFBc0I7QUFDdEI7QUFDQTtBQUNBLFFBQVE7QUFDUixPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx3Q0FBd0MsbURBQW1EO0FBQzNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsNkJBQTZCLE9BQU87QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhGQUE4RixvSkFBb0o7QUFDbFA7QUFDQTtBQUNBO0FBQ0Esd0hBQXdILG9KQUFvSjtBQUM1UTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QixjQUFjLE9BQU87QUFDckI7QUFDQTtBQUNBLDRCQUE0Qiw4R0FBOEc7QUFDMUk7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxRQUFRO0FBQ3RCLGNBQWMsUUFBUTtBQUN0QixjQUFjLE9BQU87QUFDckI7QUFDQTtBQUNBLGtDQUFrQywyRkFBMkY7QUFDN0g7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyQ0FBMkMsT0FBTztBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQjtBQUNsQjtBQUNBLGlCQUFpQixnQkFBZ0I7QUFDakM7QUFDQTtBQUNBLGlCQUFpQixnQkFBZ0I7QUFDakM7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLGdCQUFnQjtBQUNoQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQixZQUFZO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyQkFBMkIsb0JBQW9CO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxPQUFPO0FBQ3JCLGFBQWEsU0FBUztBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyQ0FBMkMsT0FBTztBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkLG1DQUFtQyxvQkFBb0I7QUFDdkQsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQztBQUNsQyxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLE1BQU0scUJBQXFCLFlBQVk7QUFDcEQsZ0VBQWdFO0FBQ2hFLHdCQUF3QjtBQUN4QixpRUFBaUU7QUFDakU7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4REFBOEQseUNBQXlDLDJCQUEyQixNQUFNLElBQUk7QUFDNUk7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSwrQkFBK0IsK0NBQStDO0FBQzlFLDBCQUEwQiwwQ0FBMEM7QUFDcEUsMEJBQTBCO0FBQzFCO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsT0FBTztBQUN4QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLFlBQVksWUFBWSxNQUFNO0FBQ25FO0FBQ0EsdUJBQXVCO0FBQ3ZCO0FBQ0EsK0JBQStCLE9BQU87QUFDdEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUMsT0FBTztBQUMxQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUVBQXFFO0FBQ3JFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0MseUlBQXlJLDBHQUEwRztBQUN6UjtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0MsMklBQTJJLDBHQUEwRztBQUMzUjtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZDQUE2QyxPQUFPO0FBQ3BEO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0NBQXNDO0FBQ3RDO0FBQ0E7QUFDQSx1Q0FBdUMsc0lBQXNJLDBHQUEwRztBQUN2UjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLE9BQU87QUFDcEIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0EscUNBQXFDO0FBQ3JDLHdDQUF3QztBQUN4QywwQ0FBMEM7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsT0FBTztBQUNwQixhQUFhLFNBQVM7QUFDdEIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0RBQWdELG1CQUFtQjtBQUNuRTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsT0FBTztBQUNwQixhQUFhLFFBQVE7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUNBQWlDLFNBQVM7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMEJBQTBCO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHFFQUFxRTtBQUNyRTtBQUNBO0FBQ0EsK0JBQStCO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsT0FBTztBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1osWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLGlLQUFpSywwR0FBMEc7QUFDaFQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQyxpS0FBaUssMEdBQTBHO0FBQ2hUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQ0FBcUMsaUtBQWlLLDBHQUEwRztBQUNoVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLGlLQUFpSywwR0FBMEc7QUFDaFQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCO0FBQ0E7QUFDQTtBQUNBLHdDQUF3QyxPQUFPO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QjtBQUN4QjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQyxPQUFPO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBLG1FQUFtRTtBQUNuRTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEMsc0hBQXNIO0FBQ2hLO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLG9GQUFvRjtBQUN2SDtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0Esc0NBQXNDLG9GQUFvRjtBQUMxSDtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsbUNBQW1DLG9GQUFvRjtBQUN2SDtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2REFBNkQ7QUFDN0Qsd0VBQXdFO0FBQ3hFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxTQUFTLGdCQUFnQjtBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOERBQThELElBQUksa0JBQWtCO0FBQ3BGLElBQUk7QUFDSjs7QUFFQSxDQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vVnVleHkvLi9ub2RlX21vZHVsZXMvanN0cmVlL2Rpc3QvanN0cmVlLmpzPzVmNjMiXSwic291cmNlc0NvbnRlbnQiOlsiLypnbG9iYWxzIGpRdWVyeSwgZGVmaW5lLCBtb2R1bGUsIGV4cG9ydHMsIHJlcXVpcmUsIHdpbmRvdywgZG9jdW1lbnQsIHBvc3RNZXNzYWdlICovXG4oZnVuY3Rpb24gKGZhY3RvcnkpIHtcblx0XCJ1c2Ugc3RyaWN0XCI7XG5cdGlmICh0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQpIHtcblx0XHRkZWZpbmUoWydqcXVlcnknXSwgZmFjdG9yeSk7XG5cdH1cblx0ZWxzZSBpZih0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJyAmJiBtb2R1bGUuZXhwb3J0cykge1xuXHRcdG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeShyZXF1aXJlKCdqcXVlcnknKSk7XG5cdH1cblx0ZWxzZSB7XG5cdFx0ZmFjdG9yeShqUXVlcnkpO1xuXHR9XG59KGZ1bmN0aW9uICgkLCB1bmRlZmluZWQpIHtcblx0XCJ1c2Ugc3RyaWN0XCI7XG4vKiFcbiAqIGpzVHJlZSAzLjMuMTJcbiAqIGh0dHA6Ly9qc3RyZWUuY29tL1xuICpcbiAqIENvcHlyaWdodCAoYykgMjAxNCBJdmFuIEJvemhhbm92IChodHRwOi8vdmFrYXRhLmNvbSlcbiAqXG4gKiBMaWNlbnNlZCBzYW1lIGFzIGpxdWVyeSAtIHVuZGVyIHRoZSB0ZXJtcyBvZiB0aGUgTUlUIExpY2Vuc2VcbiAqICAgaHR0cDovL3d3dy5vcGVuc291cmNlLm9yZy9saWNlbnNlcy9taXQtbGljZW5zZS5waHBcbiAqL1xuLyohXG4gKiBpZiB1c2luZyBqc2xpbnQgcGxlYXNlIGFsbG93IGZvciB0aGUgalF1ZXJ5IGdsb2JhbCBhbmQgdXNlIGZvbGxvd2luZyBvcHRpb25zOlxuICoganNsaW50OiBsb29wZnVuYzogdHJ1ZSwgYnJvd3NlcjogdHJ1ZSwgYXNzOiB0cnVlLCBiaXR3aXNlOiB0cnVlLCBjb250aW51ZTogdHJ1ZSwgbm9tZW46IHRydWUsIHBsdXNwbHVzOiB0cnVlLCByZWdleHA6IHRydWUsIHVucGFyYW06IHRydWUsIHRvZG86IHRydWUsIHdoaXRlOiB0cnVlXG4gKi9cbi8qanNoaW50IC1XMDgzICovXG5cblx0Ly8gcHJldmVudCBhbm90aGVyIGxvYWQ/IG1heWJlIHRoZXJlIGlzIGEgYmV0dGVyIHdheT9cblx0aWYoJC5qc3RyZWUpIHtcblx0XHRyZXR1cm47XG5cdH1cblxuXHQvKipcblx0ICogIyMjIGpzVHJlZSBjb3JlIGZ1bmN0aW9uYWxpdHlcblx0ICovXG5cblx0Ly8gaW50ZXJuYWwgdmFyaWFibGVzXG5cdHZhciBpbnN0YW5jZV9jb3VudGVyID0gMCxcblx0XHRjY3Bfbm9kZSA9IGZhbHNlLFxuXHRcdGNjcF9tb2RlID0gZmFsc2UsXG5cdFx0Y2NwX2luc3QgPSBmYWxzZSxcblx0XHR0aGVtZXNfbG9hZGVkID0gW10sXG5cdFx0c3JjID0gJCgnc2NyaXB0Omxhc3QnKS5hdHRyKCdzcmMnKSxcblx0XHRkb2N1bWVudCA9IHdpbmRvdy5kb2N1bWVudDsgLy8gbG9jYWwgdmFyaWFibGUgaXMgYWx3YXlzIGZhc3RlciB0byBhY2Nlc3MgdGhlbiBhIGdsb2JhbFxuXG5cdHZhciBzZXRJbW1lZGlhdGUgPSB3aW5kb3cuc2V0SW1tZWRpYXRlO1xuXHR2YXIgUHJvbWlzZSA9IHdpbmRvdy5Qcm9taXNlO1xuXHRpZiAoIXNldEltbWVkaWF0ZSAmJiBQcm9taXNlKSB7XG5cdFx0Ly8gR29vZCBlbm91Z2ggYXBwcm94aW1hdGlvbiBvZiBzZXRJbW1lZGlhdGVcblx0XHRzZXRJbW1lZGlhdGUgPSBmdW5jdGlvbiAoY2IsIGFyZykge1xuXHRcdFx0UHJvbWlzZS5yZXNvbHZlKGFyZykudGhlbihjYik7XG5cdFx0fTtcblx0fVxuXG5cdC8qKlxuXHQgKiBob2xkcyBhbGwganN0cmVlIHJlbGF0ZWQgZnVuY3Rpb25zIGFuZCB2YXJpYWJsZXMsIGluY2x1ZGluZyB0aGUgYWN0dWFsIGNsYXNzIGFuZCBtZXRob2RzIHRvIGNyZWF0ZSwgYWNjZXNzIGFuZCBtYW5pcHVsYXRlIGluc3RhbmNlcy5cblx0ICogQG5hbWUgJC5qc3RyZWVcblx0ICovXG5cdCQuanN0cmVlID0ge1xuXHRcdC8qKlxuXHRcdCAqIHNwZWNpZmllcyB0aGUganN0cmVlIHZlcnNpb24gaW4gdXNlXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUudmVyc2lvblxuXHRcdCAqL1xuXHRcdHZlcnNpb24gOiAnMy4zLjEyJyxcblx0XHQvKipcblx0XHQgKiBob2xkcyBhbGwgdGhlIGRlZmF1bHQgb3B0aW9ucyB1c2VkIHdoZW4gY3JlYXRpbmcgbmV3IGluc3RhbmNlc1xuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzXG5cdFx0ICovXG5cdFx0ZGVmYXVsdHMgOiB7XG5cdFx0XHQvKipcblx0XHRcdCAqIGNvbmZpZ3VyZSB3aGljaCBwbHVnaW5zIHdpbGwgYmUgYWN0aXZlIG9uIGFuIGluc3RhbmNlLiBTaG91bGQgYmUgYW4gYXJyYXkgb2Ygc3RyaW5ncywgd2hlcmUgZWFjaCBlbGVtZW50IGlzIGEgcGx1Z2luIG5hbWUuIFRoZSBkZWZhdWx0IGlzIGBbXWBcblx0XHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLnBsdWdpbnNcblx0XHRcdCAqL1xuXHRcdFx0cGx1Z2lucyA6IFtdXG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBzdG9yZXMgYWxsIGxvYWRlZCBqc3RyZWUgcGx1Z2lucyAodXNlZCBpbnRlcm5hbGx5KVxuXHRcdCAqIEBuYW1lICQuanN0cmVlLnBsdWdpbnNcblx0XHQgKi9cblx0XHRwbHVnaW5zIDoge30sXG5cdFx0cGF0aCA6IHNyYyAmJiBzcmMuaW5kZXhPZignLycpICE9PSAtMSA/IHNyYy5yZXBsYWNlKC9cXC9bXlxcL10rJC8sJycpIDogJycsXG5cdFx0aWRyZWdleCA6IC9bXFxcXDomIV58KClcXFtcXF08PkAqJyt+I1wiOy4sPVxcLSBcXC8ke30lP2BdL2csXG5cdFx0cm9vdCA6ICcjJ1xuXHR9O1xuXHRcblx0LyoqXG5cdCAqIGNyZWF0ZXMgYSBqc3RyZWUgaW5zdGFuY2Vcblx0ICogQG5hbWUgJC5qc3RyZWUuY3JlYXRlKGVsIFssIG9wdGlvbnNdKVxuXHQgKiBAcGFyYW0ge0RPTUVsZW1lbnR8alF1ZXJ5fFN0cmluZ30gZWwgdGhlIGVsZW1lbnQgdG8gY3JlYXRlIHRoZSBpbnN0YW5jZSBvbiwgY2FuIGJlIGpRdWVyeSBleHRlbmRlZCBvciBhIHNlbGVjdG9yXG5cdCAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIG9wdGlvbnMgZm9yIHRoaXMgaW5zdGFuY2UgKGV4dGVuZHMgYCQuanN0cmVlLmRlZmF1bHRzYClcblx0ICogQHJldHVybiB7anNUcmVlfSB0aGUgbmV3IGluc3RhbmNlXG5cdCAqL1xuXHQkLmpzdHJlZS5jcmVhdGUgPSBmdW5jdGlvbiAoZWwsIG9wdGlvbnMpIHtcblx0XHR2YXIgdG1wID0gbmV3ICQuanN0cmVlLmNvcmUoKytpbnN0YW5jZV9jb3VudGVyKSxcblx0XHRcdG9wdCA9IG9wdGlvbnM7XG5cdFx0b3B0aW9ucyA9ICQuZXh0ZW5kKHRydWUsIHt9LCAkLmpzdHJlZS5kZWZhdWx0cywgb3B0aW9ucyk7XG5cdFx0aWYob3B0ICYmIG9wdC5wbHVnaW5zKSB7XG5cdFx0XHRvcHRpb25zLnBsdWdpbnMgPSBvcHQucGx1Z2lucztcblx0XHR9XG5cdFx0JC5lYWNoKG9wdGlvbnMucGx1Z2lucywgZnVuY3Rpb24gKGksIGspIHtcblx0XHRcdGlmKGkgIT09ICdjb3JlJykge1xuXHRcdFx0XHR0bXAgPSB0bXAucGx1Z2luKGssIG9wdGlvbnNba10pO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHRcdCQoZWwpLmRhdGEoJ2pzdHJlZScsIHRtcCk7XG5cdFx0dG1wLmluaXQoZWwsIG9wdGlvbnMpO1xuXHRcdHJldHVybiB0bXA7XG5cdH07XG5cdC8qKlxuXHQgKiByZW1vdmUgYWxsIHRyYWNlcyBvZiBqc3RyZWUgZnJvbSB0aGUgRE9NIGFuZCBkZXN0cm95IGFsbCBpbnN0YW5jZXNcblx0ICogQG5hbWUgJC5qc3RyZWUuZGVzdHJveSgpXG5cdCAqL1xuXHQkLmpzdHJlZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuXHRcdCQoJy5qc3RyZWU6anN0cmVlJykuanN0cmVlKCdkZXN0cm95Jyk7XG5cdFx0JChkb2N1bWVudCkub2ZmKCcuanN0cmVlJyk7XG5cdH07XG5cdC8qKlxuXHQgKiB0aGUganN0cmVlIGNsYXNzIGNvbnN0cnVjdG9yLCB1c2VkIG9ubHkgaW50ZXJuYWxseVxuXHQgKiBAcHJpdmF0ZVxuXHQgKiBAbmFtZSAkLmpzdHJlZS5jb3JlKGlkKVxuXHQgKiBAcGFyYW0ge051bWJlcn0gaWQgdGhpcyBpbnN0YW5jZSdzIGluZGV4XG5cdCAqL1xuXHQkLmpzdHJlZS5jb3JlID0gZnVuY3Rpb24gKGlkKSB7XG5cdFx0dGhpcy5faWQgPSBpZDtcblx0XHR0aGlzLl9jbnQgPSAwO1xuXHRcdHRoaXMuX3dyayA9IG51bGw7XG5cdFx0dGhpcy5fZGF0YSA9IHtcblx0XHRcdGNvcmUgOiB7XG5cdFx0XHRcdHRoZW1lcyA6IHtcblx0XHRcdFx0XHRuYW1lIDogZmFsc2UsXG5cdFx0XHRcdFx0ZG90cyA6IGZhbHNlLFxuXHRcdFx0XHRcdGljb25zIDogZmFsc2UsXG5cdFx0XHRcdFx0ZWxsaXBzaXMgOiBmYWxzZVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRzZWxlY3RlZCA6IFtdLFxuXHRcdFx0XHRsYXN0X2Vycm9yIDoge30sXG5cdFx0XHRcdHdvcmtpbmcgOiBmYWxzZSxcblx0XHRcdFx0d29ya2VyX3F1ZXVlIDogW10sXG5cdFx0XHRcdGZvY3VzZWQgOiBudWxsXG5cdFx0XHR9XG5cdFx0fTtcblx0fTtcblx0LyoqXG5cdCAqIGdldCBhIHJlZmVyZW5jZSB0byBhbiBleGlzdGluZyBpbnN0YW5jZVxuXHQgKlxuXHQgKiBfX0V4YW1wbGVzX19cblx0ICpcblx0ICpcdC8vIHByb3ZpZGVkIGEgY29udGFpbmVyIHdpdGggYW4gSUQgb2YgXCJ0cmVlXCIsIGFuZCBhIG5lc3RlZCBub2RlIHdpdGggYW4gSUQgb2YgXCJicmFuY2hcIlxuXHQgKlx0Ly8gYWxsIG9mIHRoZXJlIHdpbGwgcmV0dXJuIHRoZSBzYW1lIGluc3RhbmNlXG5cdCAqXHQkLmpzdHJlZS5yZWZlcmVuY2UoJ3RyZWUnKTtcblx0ICpcdCQuanN0cmVlLnJlZmVyZW5jZSgnI3RyZWUnKTtcblx0ICpcdCQuanN0cmVlLnJlZmVyZW5jZSgkKCcjdHJlZScpKTtcblx0ICpcdCQuanN0cmVlLnJlZmVyZW5jZShkb2N1bWVudC5nZXRFbGVtZW50QnlJRCgndHJlZScpKTtcblx0ICpcdCQuanN0cmVlLnJlZmVyZW5jZSgnYnJhbmNoJyk7XG5cdCAqXHQkLmpzdHJlZS5yZWZlcmVuY2UoJyNicmFuY2gnKTtcblx0ICpcdCQuanN0cmVlLnJlZmVyZW5jZSgkKCcjYnJhbmNoJykpO1xuXHQgKlx0JC5qc3RyZWUucmVmZXJlbmNlKGRvY3VtZW50LmdldEVsZW1lbnRCeUlEKCdicmFuY2gnKSk7XG5cdCAqXG5cdCAqIEBuYW1lICQuanN0cmVlLnJlZmVyZW5jZShuZWVkbGUpXG5cdCAqIEBwYXJhbSB7RE9NRWxlbWVudHxqUXVlcnl8U3RyaW5nfSBuZWVkbGVcblx0ICogQHJldHVybiB7anNUcmVlfG51bGx9IHRoZSBpbnN0YW5jZSBvciBgbnVsbGAgaWYgbm90IGZvdW5kXG5cdCAqL1xuXHQkLmpzdHJlZS5yZWZlcmVuY2UgPSBmdW5jdGlvbiAobmVlZGxlKSB7XG5cdFx0dmFyIHRtcCA9IG51bGwsXG5cdFx0XHRvYmogPSBudWxsO1xuXHRcdGlmKG5lZWRsZSAmJiBuZWVkbGUuaWQgJiYgKCFuZWVkbGUudGFnTmFtZSB8fCAhbmVlZGxlLm5vZGVUeXBlKSkgeyBuZWVkbGUgPSBuZWVkbGUuaWQ7IH1cblxuXHRcdGlmKCFvYmogfHwgIW9iai5sZW5ndGgpIHtcblx0XHRcdHRyeSB7IG9iaiA9ICQobmVlZGxlKTsgfSBjYXRjaCAoaWdub3JlKSB7IH1cblx0XHR9XG5cdFx0aWYoIW9iaiB8fCAhb2JqLmxlbmd0aCkge1xuXHRcdFx0dHJ5IHsgb2JqID0gJCgnIycgKyBuZWVkbGUucmVwbGFjZSgkLmpzdHJlZS5pZHJlZ2V4LCdcXFxcJCYnKSk7IH0gY2F0Y2ggKGlnbm9yZSkgeyB9XG5cdFx0fVxuXHRcdGlmKG9iaiAmJiBvYmoubGVuZ3RoICYmIChvYmogPSBvYmouY2xvc2VzdCgnLmpzdHJlZScpKS5sZW5ndGggJiYgKG9iaiA9IG9iai5kYXRhKCdqc3RyZWUnKSkpIHtcblx0XHRcdHRtcCA9IG9iajtcblx0XHR9XG5cdFx0ZWxzZSB7XG5cdFx0XHQkKCcuanN0cmVlJykuZWFjaChmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdHZhciBpbnN0ID0gJCh0aGlzKS5kYXRhKCdqc3RyZWUnKTtcblx0XHRcdFx0aWYoaW5zdCAmJiBpbnN0Ll9tb2RlbC5kYXRhW25lZWRsZV0pIHtcblx0XHRcdFx0XHR0bXAgPSBpbnN0O1xuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fVxuXHRcdHJldHVybiB0bXA7XG5cdH07XG5cdC8qKlxuXHQgKiBDcmVhdGUgYW4gaW5zdGFuY2UsIGdldCBhbiBpbnN0YW5jZSBvciBpbnZva2UgYSBjb21tYW5kIG9uIGEgaW5zdGFuY2UuXG5cdCAqXG5cdCAqIElmIHRoZXJlIGlzIG5vIGluc3RhbmNlIGFzc29jaWF0ZWQgd2l0aCB0aGUgY3VycmVudCBub2RlIGEgbmV3IG9uZSBpcyBjcmVhdGVkIGFuZCBgYXJnYCBpcyB1c2VkIHRvIGV4dGVuZCBgJC5qc3RyZWUuZGVmYXVsdHNgIGZvciB0aGlzIG5ldyBpbnN0YW5jZS4gVGhlcmUgd291bGQgYmUgbm8gcmV0dXJuIHZhbHVlIChjaGFpbmluZyBpcyBub3QgYnJva2VuKS5cblx0ICpcblx0ICogSWYgdGhlcmUgaXMgYW4gZXhpc3RpbmcgaW5zdGFuY2UgYW5kIGBhcmdgIGlzIGEgc3RyaW5nIHRoZSBjb21tYW5kIHNwZWNpZmllZCBieSBgYXJnYCBpcyBleGVjdXRlZCBvbiB0aGUgaW5zdGFuY2UsIHdpdGggYW55IGFkZGl0aW9uYWwgYXJndW1lbnRzIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uIElmIHRoZSBmdW5jdGlvbiByZXR1cm5zIGEgdmFsdWUgaXQgd2lsbCBiZSByZXR1cm5lZCAoY2hhaW5pbmcgY291bGQgYnJlYWsgZGVwZW5kaW5nIG9uIGZ1bmN0aW9uKS5cblx0ICpcblx0ICogSWYgdGhlcmUgaXMgYW4gZXhpc3RpbmcgaW5zdGFuY2UgYW5kIGBhcmdgIGlzIG5vdCBhIHN0cmluZyB0aGUgaW5zdGFuY2UgaXRzZWxmIGlzIHJldHVybmVkIChzaW1pbGFyIHRvIGAkLmpzdHJlZS5yZWZlcmVuY2VgKS5cblx0ICpcblx0ICogSW4gYW55IG90aGVyIGNhc2UgLSBub3RoaW5nIGlzIHJldHVybmVkIGFuZCBjaGFpbmluZyBpcyBub3QgYnJva2VuLlxuXHQgKlxuXHQgKiBfX0V4YW1wbGVzX19cblx0ICpcblx0ICpcdCQoJyN0cmVlMScpLmpzdHJlZSgpOyAvLyBjcmVhdGVzIGFuIGluc3RhbmNlXG5cdCAqXHQkKCcjdHJlZTInKS5qc3RyZWUoeyBwbHVnaW5zIDogW10gfSk7IC8vIGNyZWF0ZSBhbiBpbnN0YW5jZSB3aXRoIHNvbWUgb3B0aW9uc1xuXHQgKlx0JCgnI3RyZWUxJykuanN0cmVlKCdvcGVuX25vZGUnLCAnI2JyYW5jaF8xJyk7IC8vIGNhbGwgYSBtZXRob2Qgb24gYW4gZXhpc3RpbmcgaW5zdGFuY2UsIHBhc3NpbmcgYWRkaXRpb25hbCBhcmd1bWVudHNcblx0ICpcdCQoJyN0cmVlMicpLmpzdHJlZSgpOyAvLyBnZXQgYW4gZXhpc3RpbmcgaW5zdGFuY2UgKG9yIGNyZWF0ZSBhbiBpbnN0YW5jZSlcblx0ICpcdCQoJyN0cmVlMicpLmpzdHJlZSh0cnVlKTsgLy8gZ2V0IGFuIGV4aXN0aW5nIGluc3RhbmNlICh3aWxsIG5vdCBjcmVhdGUgbmV3IGluc3RhbmNlKVxuXHQgKlx0JCgnI2JyYW5jaF8xJykuanN0cmVlKCkuc2VsZWN0X25vZGUoJyNicmFuY2hfMScpOyAvLyBnZXQgYW4gaW5zdGFuY2UgKHVzaW5nIGEgbmVzdGVkIGVsZW1lbnQgYW5kIGNhbGwgYSBtZXRob2QpXG5cdCAqXG5cdCAqIEBuYW1lICQoKS5qc3RyZWUoW2FyZ10pXG5cdCAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gYXJnXG5cdCAqIEByZXR1cm4ge01peGVkfVxuXHQgKi9cblx0JC5mbi5qc3RyZWUgPSBmdW5jdGlvbiAoYXJnKSB7XG5cdFx0Ly8gY2hlY2sgZm9yIHN0cmluZyBhcmd1bWVudFxuXHRcdHZhciBpc19tZXRob2RcdD0gKHR5cGVvZiBhcmcgPT09ICdzdHJpbmcnKSxcblx0XHRcdGFyZ3NcdFx0PSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpLFxuXHRcdFx0cmVzdWx0XHRcdD0gbnVsbDtcblx0XHRpZihhcmcgPT09IHRydWUgJiYgIXRoaXMubGVuZ3RoKSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7XG5cdFx0XHQvLyBnZXQgdGhlIGluc3RhbmNlIChpZiB0aGVyZSBpcyBvbmUpIGFuZCBtZXRob2QgKGlmIGl0IGV4aXN0cylcblx0XHRcdHZhciBpbnN0YW5jZSA9ICQuanN0cmVlLnJlZmVyZW5jZSh0aGlzKSxcblx0XHRcdFx0bWV0aG9kID0gaXNfbWV0aG9kICYmIGluc3RhbmNlID8gaW5zdGFuY2VbYXJnXSA6IG51bGw7XG5cdFx0XHQvLyBpZiBjYWxsaW5nIGEgbWV0aG9kLCBhbmQgbWV0aG9kIGlzIGF2YWlsYWJsZSAtIGV4ZWN1dGUgb24gdGhlIGluc3RhbmNlXG5cdFx0XHRyZXN1bHQgPSBpc19tZXRob2QgJiYgbWV0aG9kID9cblx0XHRcdFx0bWV0aG9kLmFwcGx5KGluc3RhbmNlLCBhcmdzKSA6XG5cdFx0XHRcdG51bGw7XG5cdFx0XHQvLyBpZiB0aGVyZSBpcyBubyBpbnN0YW5jZSBhbmQgbm8gbWV0aG9kIGlzIGJlaW5nIGNhbGxlZCAtIGNyZWF0ZSBvbmVcblx0XHRcdGlmKCFpbnN0YW5jZSAmJiAhaXNfbWV0aG9kICYmIChhcmcgPT09IHVuZGVmaW5lZCB8fCAkLmlzUGxhaW5PYmplY3QoYXJnKSkpIHtcblx0XHRcdFx0JC5qc3RyZWUuY3JlYXRlKHRoaXMsIGFyZyk7XG5cdFx0XHR9XG5cdFx0XHQvLyBpZiB0aGVyZSBpcyBhbiBpbnN0YW5jZSBhbmQgbm8gbWV0aG9kIGlzIGNhbGxlZCAtIHJldHVybiB0aGUgaW5zdGFuY2Vcblx0XHRcdGlmKCAoaW5zdGFuY2UgJiYgIWlzX21ldGhvZCkgfHwgYXJnID09PSB0cnVlICkge1xuXHRcdFx0XHRyZXN1bHQgPSBpbnN0YW5jZSB8fCBmYWxzZTtcblx0XHRcdH1cblx0XHRcdC8vIGlmIHRoZXJlIHdhcyBhIG1ldGhvZCBjYWxsIHdoaWNoIHJldHVybmVkIGEgcmVzdWx0IC0gYnJlYWsgYW5kIHJldHVybiB0aGUgdmFsdWVcblx0XHRcdGlmKHJlc3VsdCAhPT0gbnVsbCAmJiByZXN1bHQgIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fSk7XG5cdFx0Ly8gaWYgdGhlcmUgd2FzIGEgbWV0aG9kIGNhbGwgd2l0aCBhIHZhbGlkIHJldHVybiB2YWx1ZSAtIHJldHVybiB0aGF0LCBvdGhlcndpc2UgY29udGludWUgdGhlIGNoYWluXG5cdFx0cmV0dXJuIHJlc3VsdCAhPT0gbnVsbCAmJiByZXN1bHQgIT09IHVuZGVmaW5lZCA/XG5cdFx0XHRyZXN1bHQgOiB0aGlzO1xuXHR9O1xuXHQvKipcblx0ICogdXNlZCB0byBmaW5kIGVsZW1lbnRzIGNvbnRhaW5pbmcgYW4gaW5zdGFuY2Vcblx0ICpcblx0ICogX19FeGFtcGxlc19fXG5cdCAqXG5cdCAqXHQkKCdkaXY6anN0cmVlJykuZWFjaChmdW5jdGlvbiAoKSB7XG5cdCAqXHRcdCQodGhpcykuanN0cmVlKCdkZXN0cm95Jyk7XG5cdCAqXHR9KTtcblx0ICpcblx0ICogQG5hbWUgJCgnOmpzdHJlZScpXG5cdCAqIEByZXR1cm4ge2pRdWVyeX1cblx0ICovXG5cdCQuZXhwci5wc2V1ZG9zLmpzdHJlZSA9ICQuZXhwci5jcmVhdGVQc2V1ZG8oZnVuY3Rpb24oc2VhcmNoKSB7XG5cdFx0cmV0dXJuIGZ1bmN0aW9uKGEpIHtcblx0XHRcdHJldHVybiAkKGEpLmhhc0NsYXNzKCdqc3RyZWUnKSAmJlxuXHRcdFx0XHQkKGEpLmRhdGEoJ2pzdHJlZScpICE9PSB1bmRlZmluZWQ7XG5cdFx0fTtcblx0fSk7XG5cblx0LyoqXG5cdCAqIHN0b3JlcyBhbGwgZGVmYXVsdHMgZm9yIHRoZSBjb3JlXG5cdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNvcmVcblx0ICovXG5cdCQuanN0cmVlLmRlZmF1bHRzLmNvcmUgPSB7XG5cdFx0LyoqXG5cdFx0ICogZGF0YSBjb25maWd1cmF0aW9uXG5cdFx0ICpcblx0XHQgKiBJZiBsZWZ0IGFzIGBmYWxzZWAgdGhlIEhUTUwgaW5zaWRlIHRoZSBqc3RyZWUgY29udGFpbmVyIGVsZW1lbnQgaXMgdXNlZCB0byBwb3B1bGF0ZSB0aGUgdHJlZSAodGhhdCBzaG91bGQgYmUgYW4gdW5vcmRlcmVkIGxpc3Qgd2l0aCBsaXN0IGl0ZW1zKS5cblx0XHQgKlxuXHRcdCAqIFlvdSBjYW4gYWxzbyBwYXNzIGluIGEgSFRNTCBzdHJpbmcgb3IgYSBKU09OIGFycmF5IGhlcmUuXG5cdFx0ICpcblx0XHQgKiBJdCBpcyBwb3NzaWJsZSB0byBwYXNzIGluIGEgc3RhbmRhcmQgalF1ZXJ5LWxpa2UgQUpBWCBjb25maWcgYW5kIGpzdHJlZSB3aWxsIGF1dG9tYXRpY2FsbHkgZGV0ZXJtaW5lIGlmIHRoZSByZXNwb25zZSBpcyBKU09OIG9yIEhUTUwgYW5kIHVzZSB0aGF0IHRvIHBvcHVsYXRlIHRoZSB0cmVlLlxuXHRcdCAqIEluIGFkZGl0aW9uIHRvIHRoZSBzdGFuZGFyZCBqUXVlcnkgYWpheCBvcHRpb25zIGhlcmUgeW91IGNhbiBzdXBwbHkgZnVuY3Rpb25zIGZvciBgZGF0YWAgYW5kIGB1cmxgLCB0aGUgZnVuY3Rpb25zIHdpbGwgYmUgcnVuIGluIHRoZSBjdXJyZW50IGluc3RhbmNlJ3Mgc2NvcGUgYW5kIGEgcGFyYW0gd2lsbCBiZSBwYXNzZWQgaW5kaWNhdGluZyB3aGljaCBub2RlIGlzIGJlaW5nIGxvYWRlZCwgdGhlIHJldHVybiB2YWx1ZSBvZiB0aG9zZSBmdW5jdGlvbnMgd2lsbCBiZSB1c2VkLlxuXHRcdCAqXG5cdFx0ICogVGhlIGxhc3Qgb3B0aW9uIGlzIHRvIHNwZWNpZnkgYSBmdW5jdGlvbiwgdGhhdCBmdW5jdGlvbiB3aWxsIHJlY2VpdmUgdGhlIG5vZGUgYmVpbmcgbG9hZGVkIGFzIGFyZ3VtZW50IGFuZCBhIHNlY29uZCBwYXJhbSB3aGljaCBpcyBhIGZ1bmN0aW9uIHdoaWNoIHNob3VsZCBiZSBjYWxsZWQgd2l0aCB0aGUgcmVzdWx0LlxuXHRcdCAqXG5cdFx0ICogX19FeGFtcGxlc19fXG5cdFx0ICpcblx0XHQgKlx0Ly8gQUpBWFxuXHRcdCAqXHQkKCcjdHJlZScpLmpzdHJlZSh7XG5cdFx0ICpcdFx0J2NvcmUnIDoge1xuXHRcdCAqXHRcdFx0J2RhdGEnIDoge1xuXHRcdCAqXHRcdFx0XHQndXJsJyA6ICcvZ2V0L2NoaWxkcmVuLycsXG5cdFx0ICpcdFx0XHRcdCdkYXRhJyA6IGZ1bmN0aW9uIChub2RlKSB7XG5cdFx0ICpcdFx0XHRcdFx0cmV0dXJuIHsgJ2lkJyA6IG5vZGUuaWQgfTtcblx0XHQgKlx0XHRcdFx0fVxuXHRcdCAqXHRcdFx0fVxuXHRcdCAqXHRcdH0pO1xuXHRcdCAqXG5cdFx0ICpcdC8vIGRpcmVjdCBkYXRhXG5cdFx0ICpcdCQoJyN0cmVlJykuanN0cmVlKHtcblx0XHQgKlx0XHQnY29yZScgOiB7XG5cdFx0ICpcdFx0XHQnZGF0YScgOiBbXG5cdFx0ICpcdFx0XHRcdCdTaW1wbGUgcm9vdCBub2RlJyxcblx0XHQgKlx0XHRcdFx0e1xuXHRcdCAqXHRcdFx0XHRcdCdpZCcgOiAnbm9kZV8yJyxcblx0XHQgKlx0XHRcdFx0XHQndGV4dCcgOiAnUm9vdCBub2RlIHdpdGggb3B0aW9ucycsXG5cdFx0ICpcdFx0XHRcdFx0J3N0YXRlJyA6IHsgJ29wZW5lZCcgOiB0cnVlLCAnc2VsZWN0ZWQnIDogdHJ1ZSB9LFxuXHRcdCAqXHRcdFx0XHRcdCdjaGlsZHJlbicgOiBbIHsgJ3RleHQnIDogJ0NoaWxkIDEnIH0sICdDaGlsZCAyJ11cblx0XHQgKlx0XHRcdFx0fVxuXHRcdCAqXHRcdFx0XVxuXHRcdCAqXHRcdH1cblx0XHQgKlx0fSk7XG5cdFx0ICpcblx0XHQgKlx0Ly8gZnVuY3Rpb25cblx0XHQgKlx0JCgnI3RyZWUnKS5qc3RyZWUoe1xuXHRcdCAqXHRcdCdjb3JlJyA6IHtcblx0XHQgKlx0XHRcdCdkYXRhJyA6IGZ1bmN0aW9uIChvYmosIGNhbGxiYWNrKSB7XG5cdFx0ICpcdFx0XHRcdGNhbGxiYWNrLmNhbGwodGhpcywgWydSb290IDEnLCAnUm9vdCAyJ10pO1xuXHRcdCAqXHRcdFx0fVxuXHRcdCAqXHRcdH0pO1xuXHRcdCAqXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuY29yZS5kYXRhXG5cdFx0ICovXG5cdFx0ZGF0YVx0XHRcdDogZmFsc2UsXG5cdFx0LyoqXG5cdFx0ICogY29uZmlndXJlIHRoZSB2YXJpb3VzIHN0cmluZ3MgdXNlZCB0aHJvdWdob3V0IHRoZSB0cmVlXG5cdFx0ICpcblx0XHQgKiBZb3UgY2FuIHVzZSBhbiBvYmplY3Qgd2hlcmUgdGhlIGtleSBpcyB0aGUgc3RyaW5nIHlvdSBuZWVkIHRvIHJlcGxhY2UgYW5kIHRoZSB2YWx1ZSBpcyB5b3VyIHJlcGxhY2VtZW50LlxuXHRcdCAqIEFub3RoZXIgb3B0aW9uIGlzIHRvIHNwZWNpZnkgYSBmdW5jdGlvbiB3aGljaCB3aWxsIGJlIGNhbGxlZCB3aXRoIGFuIGFyZ3VtZW50IG9mIHRoZSBuZWVkZWQgc3RyaW5nIGFuZCBzaG91bGQgcmV0dXJuIHRoZSByZXBsYWNlbWVudC5cblx0XHQgKiBJZiBsZWZ0IGFzIGBmYWxzZWAgbm8gcmVwbGFjZW1lbnQgaXMgbWFkZS5cblx0XHQgKlxuXHRcdCAqIF9fRXhhbXBsZXNfX1xuXHRcdCAqXG5cdFx0ICpcdCQoJyN0cmVlJykuanN0cmVlKHtcblx0XHQgKlx0XHQnY29yZScgOiB7XG5cdFx0ICpcdFx0XHQnc3RyaW5ncycgOiB7XG5cdFx0ICpcdFx0XHRcdCdMb2FkaW5nIC4uLicgOiAnUGxlYXNlIHdhaXQgLi4uJ1xuXHRcdCAqXHRcdFx0fVxuXHRcdCAqXHRcdH1cblx0XHQgKlx0fSk7XG5cdFx0ICpcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlLnN0cmluZ3Ncblx0XHQgKi9cblx0XHRzdHJpbmdzXHRcdFx0OiBmYWxzZSxcblx0XHQvKipcblx0XHQgKiBkZXRlcm1pbmVzIHdoYXQgaGFwcGVucyB3aGVuIGEgdXNlciB0cmllcyB0byBtb2RpZnkgdGhlIHN0cnVjdHVyZSBvZiB0aGUgdHJlZVxuXHRcdCAqIElmIGxlZnQgYXMgYGZhbHNlYCBhbGwgb3BlcmF0aW9ucyBsaWtlIGNyZWF0ZSwgcmVuYW1lLCBkZWxldGUsIG1vdmUgb3IgY29weSBhcmUgcHJldmVudGVkLlxuXHRcdCAqIFlvdSBjYW4gc2V0IHRoaXMgdG8gYHRydWVgIHRvIGFsbG93IGFsbCBpbnRlcmFjdGlvbnMgb3IgdXNlIGEgZnVuY3Rpb24gdG8gaGF2ZSBiZXR0ZXIgY29udHJvbC5cblx0XHQgKlxuXHRcdCAqIF9fRXhhbXBsZXNfX1xuXHRcdCAqXG5cdFx0ICpcdCQoJyN0cmVlJykuanN0cmVlKHtcblx0XHQgKlx0XHQnY29yZScgOiB7XG5cdFx0ICpcdFx0XHQnY2hlY2tfY2FsbGJhY2snIDogZnVuY3Rpb24gKG9wZXJhdGlvbiwgbm9kZSwgbm9kZV9wYXJlbnQsIG5vZGVfcG9zaXRpb24sIG1vcmUpIHtcblx0XHQgKlx0XHRcdFx0Ly8gb3BlcmF0aW9uIGNhbiBiZSAnY3JlYXRlX25vZGUnLCAncmVuYW1lX25vZGUnLCAnZGVsZXRlX25vZGUnLCAnbW92ZV9ub2RlJywgJ2NvcHlfbm9kZScgb3IgJ2VkaXQnXG5cdFx0ICpcdFx0XHRcdC8vIGluIGNhc2Ugb2YgJ3JlbmFtZV9ub2RlJyBub2RlX3Bvc2l0aW9uIGlzIGZpbGxlZCB3aXRoIHRoZSBuZXcgbm9kZSBuYW1lXG5cdFx0ICpcdFx0XHRcdHJldHVybiBvcGVyYXRpb24gPT09ICdyZW5hbWVfbm9kZScgPyB0cnVlIDogZmFsc2U7XG5cdFx0ICpcdFx0XHR9XG5cdFx0ICpcdFx0fVxuXHRcdCAqXHR9KTtcblx0XHQgKlxuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNvcmUuY2hlY2tfY2FsbGJhY2tcblx0XHQgKi9cblx0XHRjaGVja19jYWxsYmFja1x0OiBmYWxzZSxcblx0XHQvKipcblx0XHQgKiBhIGNhbGxiYWNrIGNhbGxlZCB3aXRoIGEgc2luZ2xlIG9iamVjdCBwYXJhbWV0ZXIgaW4gdGhlIGluc3RhbmNlJ3Mgc2NvcGUgd2hlbiBzb21ldGhpbmcgZ29lcyB3cm9uZyAob3BlcmF0aW9uIHByZXZlbnRlZCwgYWpheCBmYWlsZWQsIGV0Yylcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlLmVycm9yXG5cdFx0ICovXG5cdFx0ZXJyb3JcdFx0XHQ6ICQubm9vcCxcblx0XHQvKipcblx0XHQgKiB0aGUgb3BlbiAvIGNsb3NlIGFuaW1hdGlvbiBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgLSBzZXQgdGhpcyB0byBgZmFsc2VgIHRvIGRpc2FibGUgdGhlIGFuaW1hdGlvbiAoZGVmYXVsdCBpcyBgMjAwYClcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlLmFuaW1hdGlvblxuXHRcdCAqL1xuXHRcdGFuaW1hdGlvblx0XHQ6IDIwMCxcblx0XHQvKipcblx0XHQgKiBhIGJvb2xlYW4gaW5kaWNhdGluZyBpZiBtdWx0aXBsZSBub2RlcyBjYW4gYmUgc2VsZWN0ZWRcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlLm11bHRpcGxlXG5cdFx0ICovXG5cdFx0bXVsdGlwbGVcdFx0OiB0cnVlLFxuXHRcdC8qKlxuXHRcdCAqIHRoZW1lIGNvbmZpZ3VyYXRpb24gb2JqZWN0XG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuY29yZS50aGVtZXNcblx0XHQgKi9cblx0XHR0aGVtZXNcdFx0XHQ6IHtcblx0XHRcdC8qKlxuXHRcdFx0ICogdGhlIG5hbWUgb2YgdGhlIHRoZW1lIHRvIHVzZSAoaWYgbGVmdCBhcyBgZmFsc2VgIHRoZSBkZWZhdWx0IHRoZW1lIGlzIHVzZWQpXG5cdFx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlLnRoZW1lcy5uYW1lXG5cdFx0XHQgKi9cblx0XHRcdG5hbWVcdFx0XHQ6IGZhbHNlLFxuXHRcdFx0LyoqXG5cdFx0XHQgKiB0aGUgVVJMIG9mIHRoZSB0aGVtZSdzIENTUyBmaWxlLCBsZWF2ZSB0aGlzIGFzIGBmYWxzZWAgaWYgeW91IGhhdmUgbWFudWFsbHkgaW5jbHVkZWQgdGhlIHRoZW1lIENTUyAocmVjb21tZW5kZWQpLiBZb3UgY2FuIHNldCB0aGlzIHRvIGB0cnVlYCB0b28gd2hpY2ggd2lsbCB0cnkgdG8gYXV0b2xvYWQgdGhlIHRoZW1lLlxuXHRcdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuY29yZS50aGVtZXMudXJsXG5cdFx0XHQgKi9cblx0XHRcdHVybFx0XHRcdFx0OiBmYWxzZSxcblx0XHRcdC8qKlxuXHRcdFx0ICogdGhlIGxvY2F0aW9uIG9mIGFsbCBqc3RyZWUgdGhlbWVzIC0gb25seSB1c2VkIGlmIGB1cmxgIGlzIHNldCB0byBgdHJ1ZWBcblx0XHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNvcmUudGhlbWVzLmRpclxuXHRcdFx0ICovXG5cdFx0XHRkaXJcdFx0XHRcdDogZmFsc2UsXG5cdFx0XHQvKipcblx0XHRcdCAqIGEgYm9vbGVhbiBpbmRpY2F0aW5nIGlmIGNvbm5lY3RpbmcgZG90cyBhcmUgc2hvd25cblx0XHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNvcmUudGhlbWVzLmRvdHNcblx0XHRcdCAqL1xuXHRcdFx0ZG90c1x0XHRcdDogdHJ1ZSxcblx0XHRcdC8qKlxuXHRcdFx0ICogYSBib29sZWFuIGluZGljYXRpbmcgaWYgbm9kZSBpY29ucyBhcmUgc2hvd25cblx0XHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNvcmUudGhlbWVzLmljb25zXG5cdFx0XHQgKi9cblx0XHRcdGljb25zXHRcdFx0OiB0cnVlLFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBhIGJvb2xlYW4gaW5kaWNhdGluZyBpZiBub2RlIGVsbGlwc2lzIHNob3VsZCBiZSBzaG93biAtIHRoaXMgb25seSB3b3JrcyB3aXRoIGEgZml4ZWQgd2l0aCBvbiB0aGUgY29udGFpbmVyXG5cdFx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlLnRoZW1lcy5lbGxpcHNpc1xuXHRcdFx0ICovXG5cdFx0XHRlbGxpcHNpc1x0XHQ6IGZhbHNlLFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBhIGJvb2xlYW4gaW5kaWNhdGluZyBpZiB0aGUgdHJlZSBiYWNrZ3JvdW5kIGlzIHN0cmlwZWRcblx0XHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNvcmUudGhlbWVzLnN0cmlwZXNcblx0XHRcdCAqL1xuXHRcdFx0c3RyaXBlc1x0XHRcdDogZmFsc2UsXG5cdFx0XHQvKipcblx0XHRcdCAqIGEgc3RyaW5nIChvciBib29sZWFuIGBmYWxzZWApIHNwZWNpZnlpbmcgdGhlIHRoZW1lIHZhcmlhbnQgdG8gdXNlIChpZiB0aGUgdGhlbWUgc3VwcG9ydHMgdmFyaWFudHMpXG5cdFx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlLnRoZW1lcy52YXJpYW50XG5cdFx0XHQgKi9cblx0XHRcdHZhcmlhbnRcdFx0XHQ6IGZhbHNlLFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBhIGJvb2xlYW4gc3BlY2lmeWluZyBpZiBhIHJlcG9uc2l2ZSB2ZXJzaW9uIG9mIHRoZSB0aGVtZSBzaG91bGQga2ljayBpbiBvbiBzbWFsbGVyIHNjcmVlbnMgKGlmIHRoZSB0aGVtZSBzdXBwb3J0cyBpdCkuIERlZmF1bHRzIHRvIGBmYWxzZWAuXG5cdFx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlLnRoZW1lcy5yZXNwb25zaXZlXG5cdFx0XHQgKi9cblx0XHRcdHJlc3BvbnNpdmVcdFx0OiBmYWxzZVxuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogaWYgbGVmdCBhcyBgdHJ1ZWAgYWxsIHBhcmVudHMgb2YgYWxsIHNlbGVjdGVkIG5vZGVzIHdpbGwgYmUgb3BlbmVkIG9uY2UgdGhlIHRyZWUgbG9hZHMgKHNvIHRoYXQgYWxsIHNlbGVjdGVkIG5vZGVzIGFyZSB2aXNpYmxlIHRvIHRoZSB1c2VyKVxuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNvcmUuZXhwYW5kX3NlbGVjdGVkX29ubG9hZFxuXHRcdCAqL1xuXHRcdGV4cGFuZF9zZWxlY3RlZF9vbmxvYWQgOiB0cnVlLFxuXHRcdC8qKlxuXHRcdCAqIGlmIGxlZnQgYXMgYHRydWVgIHdlYiB3b3JrZXJzIHdpbGwgYmUgdXNlZCB0byBwYXJzZSBpbmNvbWluZyBKU09OIGRhdGEgd2hlcmUgcG9zc2libGUsIHNvIHRoYXQgdGhlIFVJIHdpbGwgbm90IGJlIGJsb2NrZWQgYnkgbGFyZ2UgcmVxdWVzdHMuIFdvcmtlcnMgYXJlIGhvd2V2ZXIgYWJvdXQgMzAlIHNsb3dlci4gRGVmYXVsdHMgdG8gYHRydWVgXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuY29yZS53b3JrZXJcblx0XHQgKi9cblx0XHR3b3JrZXIgOiB0cnVlLFxuXHRcdC8qKlxuXHRcdCAqIEZvcmNlIG5vZGUgdGV4dCB0byBwbGFpbiB0ZXh0IChhbmQgZXNjYXBlIEhUTUwpLiBEZWZhdWx0cyB0byBgZmFsc2VgXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuY29yZS5mb3JjZV90ZXh0XG5cdFx0ICovXG5cdFx0Zm9yY2VfdGV4dCA6IGZhbHNlLFxuXHRcdC8qKlxuXHRcdCAqIFNob3VsZCB0aGUgbm9kZSBiZSB0b2dnbGVkIGlmIHRoZSB0ZXh0IGlzIGRvdWJsZSBjbGlja2VkLiBEZWZhdWx0cyB0byBgdHJ1ZWBcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlLmRibGNsaWNrX3RvZ2dsZVxuXHRcdCAqL1xuXHRcdGRibGNsaWNrX3RvZ2dsZSA6IHRydWUsXG5cdFx0LyoqXG5cdFx0ICogU2hvdWxkIHRoZSBsb2FkZWQgbm9kZXMgYmUgcGFydCBvZiB0aGUgc3RhdGUuIERlZmF1bHRzIHRvIGBmYWxzZWBcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlLmxvYWRlZF9zdGF0ZVxuXHRcdCAqL1xuXHRcdGxvYWRlZF9zdGF0ZSA6IGZhbHNlLFxuXHRcdC8qKlxuXHRcdCAqIFNob3VsZCB0aGUgbGFzdCBhY3RpdmUgbm9kZSBiZSBmb2N1c2VkIHdoZW4gdGhlIHRyZWUgY29udGFpbmVyIGlzIGJsdXJyZWQgYW5kIHRoZSBmb2N1c2VkIGFnYWluLiBUaGlzIGhlbHBzIHdvcmtpbmcgd2l0aCBzY3JlZW4gcmVhZGVycy4gRGVmYXVsdHMgdG8gYHRydWVgXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuY29yZS5yZXN0b3JlX2ZvY3VzXG5cdFx0ICovXG5cdFx0cmVzdG9yZV9mb2N1cyA6IHRydWUsXG5cdFx0LyoqXG5cdFx0ICogRm9yY2UgdG8gY29tcHV0ZSBhbmQgc2V0IFwiYXJpYS1zZXRzaXplXCIgYW5kIFwiYXJpYS1wb3NpbnNldFwiIGV4cGxpY2l0bHkgZm9yIGVhY2ggdHJlZWl0ZW0uIFxuXHRcdCAqIFNvbWUgYnJvd3NlcnMgbWF5IGNvbXB1dGUgaW5jb3JyZWN0IGVsZW1lbnRzIHBvc2l0aW9uIGFuZCBwcm9kdWNlIHdyb25nIGFubm91bmNlbWVudHMgZm9yIHNjcmVlbiByZWFkZXJzLiBEZWZhdWx0cyB0byBgZmFsc2VgXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuY29yZS5jb21wdXRlX2VsZW1lbnRzX3Bvc2l0aW9uc1xuXHRcdCAqL1xuXHRcdGNvbXB1dGVfZWxlbWVudHNfcG9zaXRpb25zIDogZmFsc2UsXG5cdFx0LyoqXG5cdFx0ICogRGVmYXVsdCBrZXlib2FyZCBzaG9ydGN1dHMgKGFuIG9iamVjdCB3aGVyZSBlYWNoIGtleSBpcyB0aGUgYnV0dG9uIG5hbWUgb3IgY29tYm8gLSBsaWtlICdlbnRlcicsICdjdHJsLXNwYWNlJywgJ3AnLCBldGMgYW5kIHRoZSB2YWx1ZSBpcyB0aGUgZnVuY3Rpb24gdG8gZXhlY3V0ZSBpbiB0aGUgaW5zdGFuY2UncyBzY29wZSlcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlLmtleWJvYXJkXG5cdFx0ICovXG5cdFx0a2V5Ym9hcmQgOiB7XG5cdFx0XHQnY3RybC1zcGFjZSc6IGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdC8vIGFyaWEgZGVmaW5lcyBzcGFjZSBvbmx5IHdpdGggQ3RybFxuXHRcdFx0XHRlLnR5cGUgPSBcImNsaWNrXCI7XG5cdFx0XHRcdCQoZS5jdXJyZW50VGFyZ2V0KS50cmlnZ2VyKGUpO1xuXHRcdFx0fSxcblx0XHRcdCdlbnRlcic6IGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdC8vIGVudGVyXG5cdFx0XHRcdGUudHlwZSA9IFwiY2xpY2tcIjtcblx0XHRcdFx0JChlLmN1cnJlbnRUYXJnZXQpLnRyaWdnZXIoZSk7XG5cdFx0XHR9LFxuXHRcdFx0J2xlZnQnOiBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHQvLyBsZWZ0XG5cdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0aWYodGhpcy5pc19vcGVuKGUuY3VycmVudFRhcmdldCkpIHtcblx0XHRcdFx0XHR0aGlzLmNsb3NlX25vZGUoZS5jdXJyZW50VGFyZ2V0KTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHR2YXIgbyA9IHRoaXMuZ2V0X3BhcmVudChlLmN1cnJlbnRUYXJnZXQpO1xuXHRcdFx0XHRcdGlmKG8gJiYgby5pZCAhPT0gJC5qc3RyZWUucm9vdCkgeyB0aGlzLmdldF9ub2RlKG8sIHRydWUpLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLnRyaWdnZXIoJ2ZvY3VzJyk7IH1cblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdCd1cCc6IGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdC8vIHVwXG5cdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0dmFyIG8gPSB0aGlzLmdldF9wcmV2X2RvbShlLmN1cnJlbnRUYXJnZXQpO1xuXHRcdFx0XHRpZihvICYmIG8ubGVuZ3RoKSB7IG8uY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykudHJpZ2dlcignZm9jdXMnKTsgfVxuXHRcdFx0fSxcblx0XHRcdCdyaWdodCc6IGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdC8vIHJpZ2h0XG5cdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0aWYodGhpcy5pc19jbG9zZWQoZS5jdXJyZW50VGFyZ2V0KSkge1xuXHRcdFx0XHRcdHRoaXMub3Blbl9ub2RlKGUuY3VycmVudFRhcmdldCwgZnVuY3Rpb24gKG8pIHsgdGhpcy5nZXRfbm9kZShvLCB0cnVlKS5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS50cmlnZ2VyKCdmb2N1cycpOyB9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIGlmICh0aGlzLmlzX29wZW4oZS5jdXJyZW50VGFyZ2V0KSkge1xuXHRcdFx0XHRcdHZhciBvID0gdGhpcy5nZXRfbm9kZShlLmN1cnJlbnRUYXJnZXQsIHRydWUpLmNoaWxkcmVuKCcuanN0cmVlLWNoaWxkcmVuJylbMF07XG5cdFx0XHRcdFx0aWYobykgeyAkKHRoaXMuX2ZpcnN0Q2hpbGQobykpLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLnRyaWdnZXIoJ2ZvY3VzJyk7IH1cblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdCdkb3duJzogZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0Ly8gZG93blxuXHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdHZhciBvID0gdGhpcy5nZXRfbmV4dF9kb20oZS5jdXJyZW50VGFyZ2V0KTtcblx0XHRcdFx0aWYobyAmJiBvLmxlbmd0aCkgeyBvLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLnRyaWdnZXIoJ2ZvY3VzJyk7IH1cblx0XHRcdH0sXG5cdFx0XHQnKic6IGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdC8vIGFyaWEgZGVmaW5lcyAqIG9uIG51bXBhZCBhcyBvcGVuX2FsbCAtIG5vdCB2ZXJ5IGNvbW1vblxuXHRcdFx0XHR0aGlzLm9wZW5fYWxsKCk7XG5cdFx0XHR9LFxuXHRcdFx0J2hvbWUnOiBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHQvLyBob21lXG5cdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0dmFyIG8gPSB0aGlzLl9maXJzdENoaWxkKHRoaXMuZ2V0X2NvbnRhaW5lcl91bCgpWzBdKTtcblx0XHRcdFx0aWYobykgeyAkKG8pLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLmZpbHRlcignOnZpc2libGUnKS50cmlnZ2VyKCdmb2N1cycpOyB9XG5cdFx0XHR9LFxuXHRcdFx0J2VuZCc6IGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdC8vIGVuZFxuXHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5maW5kKCcuanN0cmVlLWFuY2hvcicpLmZpbHRlcignOnZpc2libGUnKS5sYXN0KCkudHJpZ2dlcignZm9jdXMnKTtcblx0XHRcdH0sXG5cdFx0XHQnZjInOiBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHQvLyBmMiAtIHNhZmUgdG8gaW5jbHVkZSAtIGlmIGNoZWNrX2NhbGxiYWNrIGlzIGZhbHNlIGl0IHdpbGwgZmFpbFxuXHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdHRoaXMuZWRpdChlLmN1cnJlbnRUYXJnZXQpO1xuXHRcdFx0fVxuXHRcdH1cblx0fTtcblx0JC5qc3RyZWUuY29yZS5wcm90b3R5cGUgPSB7XG5cdFx0LyoqXG5cdFx0ICogdXNlZCB0byBkZWNvcmF0ZSBhbiBpbnN0YW5jZSB3aXRoIGEgcGx1Z2luLiBVc2VkIGludGVybmFsbHkuXG5cdFx0ICogQHByaXZhdGVcblx0XHQgKiBAbmFtZSBwbHVnaW4oZGVjbyBbLCBvcHRzXSlcblx0XHQgKiBAcGFyYW0gIHtTdHJpbmd9IGRlY28gdGhlIHBsdWdpbiB0byBkZWNvcmF0ZSB3aXRoXG5cdFx0ICogQHBhcmFtICB7T2JqZWN0fSBvcHRzIG9wdGlvbnMgZm9yIHRoZSBwbHVnaW5cblx0XHQgKiBAcmV0dXJuIHtqc1RyZWV9XG5cdFx0ICovXG5cdFx0cGx1Z2luIDogZnVuY3Rpb24gKGRlY28sIG9wdHMpIHtcblx0XHRcdHZhciBDaGlsZCA9ICQuanN0cmVlLnBsdWdpbnNbZGVjb107XG5cdFx0XHRpZihDaGlsZCkge1xuXHRcdFx0XHR0aGlzLl9kYXRhW2RlY29dID0ge307XG5cdFx0XHRcdENoaWxkLnByb3RvdHlwZSA9IHRoaXM7XG5cdFx0XHRcdHJldHVybiBuZXcgQ2hpbGQob3B0cywgdGhpcyk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdGhpcztcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGluaXRpYWxpemUgdGhlIGluc3RhbmNlLiBVc2VkIGludGVybmFsbHkuXG5cdFx0ICogQHByaXZhdGVcblx0XHQgKiBAbmFtZSBpbml0KGVsLCBvcHRvbnMpXG5cdFx0ICogQHBhcmFtIHtET01FbGVtZW50fGpRdWVyeXxTdHJpbmd9IGVsIHRoZSBlbGVtZW50IHdlIGFyZSB0cmFuc2Zvcm1pbmdcblx0XHQgKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyBvcHRpb25zIGZvciB0aGlzIGluc3RhbmNlXG5cdFx0ICogQHRyaWdnZXIgaW5pdC5qc3RyZWUsIGxvYWRpbmcuanN0cmVlLCBsb2FkZWQuanN0cmVlLCByZWFkeS5qc3RyZWUsIGNoYW5nZWQuanN0cmVlXG5cdFx0ICovXG5cdFx0aW5pdCA6IGZ1bmN0aW9uIChlbCwgb3B0aW9ucykge1xuXHRcdFx0dGhpcy5fbW9kZWwgPSB7XG5cdFx0XHRcdGRhdGEgOiB7fSxcblx0XHRcdFx0Y2hhbmdlZCA6IFtdLFxuXHRcdFx0XHRmb3JjZV9mdWxsX3JlZHJhdyA6IGZhbHNlLFxuXHRcdFx0XHRyZWRyYXdfdGltZW91dCA6IGZhbHNlLFxuXHRcdFx0XHRkZWZhdWx0X3N0YXRlIDoge1xuXHRcdFx0XHRcdGxvYWRlZCA6IHRydWUsXG5cdFx0XHRcdFx0b3BlbmVkIDogZmFsc2UsXG5cdFx0XHRcdFx0c2VsZWN0ZWQgOiBmYWxzZSxcblx0XHRcdFx0XHRkaXNhYmxlZCA6IGZhbHNlXG5cdFx0XHRcdH1cblx0XHRcdH07XG5cdFx0XHR0aGlzLl9tb2RlbC5kYXRhWyQuanN0cmVlLnJvb3RdID0ge1xuXHRcdFx0XHRpZCA6ICQuanN0cmVlLnJvb3QsXG5cdFx0XHRcdHBhcmVudCA6IG51bGwsXG5cdFx0XHRcdHBhcmVudHMgOiBbXSxcblx0XHRcdFx0Y2hpbGRyZW4gOiBbXSxcblx0XHRcdFx0Y2hpbGRyZW5fZCA6IFtdLFxuXHRcdFx0XHRzdGF0ZSA6IHsgbG9hZGVkIDogZmFsc2UgfVxuXHRcdFx0fTtcblxuXHRcdFx0dGhpcy5lbGVtZW50ID0gJChlbCkuYWRkQ2xhc3MoJ2pzdHJlZSBqc3RyZWUtJyArIHRoaXMuX2lkKTtcblx0XHRcdHRoaXMuc2V0dGluZ3MgPSBvcHRpb25zO1xuXG5cdFx0XHR0aGlzLl9kYXRhLmNvcmUucmVhZHkgPSBmYWxzZTtcblx0XHRcdHRoaXMuX2RhdGEuY29yZS5sb2FkZWQgPSBmYWxzZTtcblx0XHRcdHRoaXMuX2RhdGEuY29yZS5ydGwgPSAodGhpcy5lbGVtZW50LmNzcyhcImRpcmVjdGlvblwiKSA9PT0gXCJydGxcIik7XG5cdFx0XHR0aGlzLmVsZW1lbnRbdGhpcy5fZGF0YS5jb3JlLnJ0bCA/ICdhZGRDbGFzcycgOiAncmVtb3ZlQ2xhc3MnXShcImpzdHJlZS1ydGxcIik7XG5cdFx0XHR0aGlzLmVsZW1lbnQuYXR0cigncm9sZScsJ3RyZWUnKTtcblx0XHRcdGlmKHRoaXMuc2V0dGluZ3MuY29yZS5tdWx0aXBsZSkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQuYXR0cignYXJpYS1tdWx0aXNlbGVjdGFibGUnLCB0cnVlKTtcblx0XHRcdH1cblx0XHRcdGlmKCF0aGlzLmVsZW1lbnQuYXR0cigndGFiaW5kZXgnKSkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQuYXR0cigndGFiaW5kZXgnLCcwJyk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuYmluZCgpO1xuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgYWZ0ZXIgYWxsIGV2ZW50cyBhcmUgYm91bmRcblx0XHRcdCAqIEBldmVudFxuXHRcdFx0ICogQG5hbWUgaW5pdC5qc3RyZWVcblx0XHRcdCAqL1xuXHRcdFx0dGhpcy50cmlnZ2VyKFwiaW5pdFwiKTtcblxuXHRcdFx0dGhpcy5fZGF0YS5jb3JlLm9yaWdpbmFsX2NvbnRhaW5lcl9odG1sID0gdGhpcy5lbGVtZW50LmZpbmQoXCIgPiB1bCA+IGxpXCIpLmNsb25lKHRydWUpO1xuXHRcdFx0dGhpcy5fZGF0YS5jb3JlLm9yaWdpbmFsX2NvbnRhaW5lcl9odG1sXG5cdFx0XHRcdC5maW5kKFwibGlcIikuYWRkQmFjaygpXG5cdFx0XHRcdC5jb250ZW50cygpLmZpbHRlcihmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcy5ub2RlVHlwZSA9PT0gMyAmJiAoIXRoaXMubm9kZVZhbHVlIHx8IC9eXFxzKyQvLnRlc3QodGhpcy5ub2RlVmFsdWUpKTtcblx0XHRcdFx0fSlcblx0XHRcdFx0LnJlbW92ZSgpO1xuXHRcdFx0dGhpcy5lbGVtZW50Lmh0bWwoXCI8XCIrXCJ1bCBjbGFzcz0nanN0cmVlLWNvbnRhaW5lci11bCBqc3RyZWUtY2hpbGRyZW4nIHJvbGU9J2dyb3VwJz48XCIrXCJsaSBpZD0nalwiK3RoaXMuX2lkK1wiX2xvYWRpbmcnIGNsYXNzPSdqc3RyZWUtaW5pdGlhbC1ub2RlIGpzdHJlZS1sb2FkaW5nIGpzdHJlZS1sZWFmIGpzdHJlZS1sYXN0JyByb2xlPSdub25lJz48aSBjbGFzcz0nanN0cmVlLWljb24ganN0cmVlLW9jbCc+PC9pPjxcIitcImEgY2xhc3M9J2pzdHJlZS1hbmNob3InIHJvbGU9J3RyZWVpdGVtJyBocmVmPScjJz48aSBjbGFzcz0nanN0cmVlLWljb24ganN0cmVlLXRoZW1laWNvbi1oaWRkZW4nPjwvaT5cIiArIHRoaXMuZ2V0X3N0cmluZyhcIkxvYWRpbmcgLi4uXCIpICsgXCI8L2E+PC9saT48L3VsPlwiKTtcblx0XHRcdHRoaXMuZWxlbWVudC5hdHRyKCdhcmlhLWFjdGl2ZWRlc2NlbmRhbnQnLCdqJyArIHRoaXMuX2lkICsgJ19sb2FkaW5nJyk7XG5cdFx0XHR0aGlzLl9kYXRhLmNvcmUubGlfaGVpZ2h0ID0gdGhpcy5nZXRfY29udGFpbmVyX3VsKCkuY2hpbGRyZW4oXCJsaVwiKS5maXJzdCgpLm91dGVySGVpZ2h0KCkgfHwgMjQ7XG5cdFx0XHR0aGlzLl9kYXRhLmNvcmUubm9kZSA9IHRoaXMuX2NyZWF0ZV9wcm90b3R5cGVfbm9kZSgpO1xuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgYWZ0ZXIgdGhlIGxvYWRpbmcgdGV4dCBpcyBzaG93biBhbmQgYmVmb3JlIGxvYWRpbmcgc3RhcnRzXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGxvYWRpbmcuanN0cmVlXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcihcImxvYWRpbmdcIik7XG5cdFx0XHR0aGlzLmxvYWRfbm9kZSgkLmpzdHJlZS5yb290KTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGRlc3Ryb3kgYW4gaW5zdGFuY2Vcblx0XHQgKiBAbmFtZSBkZXN0cm95KClcblx0XHQgKiBAcGFyYW0gIHtCb29sZWFufSBrZWVwX2h0bWwgaWYgbm90IHNldCB0byBgdHJ1ZWAgdGhlIGNvbnRhaW5lciB3aWxsIGJlIGVtcHRpZWQsIG90aGVyd2lzZSB0aGUgY3VycmVudCBET00gZWxlbWVudHMgd2lsbCBiZSBrZXB0IGludGFjdFxuXHRcdCAqL1xuXHRcdGRlc3Ryb3kgOiBmdW5jdGlvbiAoa2VlcF9odG1sKSB7XG5cdFx0XHQvKipcblx0XHRcdCAqIHRyaWdnZXJlZCBiZWZvcmUgdGhlIHRyZWUgaXMgZGVzdHJveWVkXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGRlc3Ryb3kuanN0cmVlXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcihcImRlc3Ryb3lcIik7XG5cdFx0XHRpZih0aGlzLl93cmspIHtcblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHR3aW5kb3cuVVJMLnJldm9rZU9iamVjdFVSTCh0aGlzLl93cmspO1xuXHRcdFx0XHRcdHRoaXMuX3dyayA9IG51bGw7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y2F0Y2ggKGlnbm9yZSkgeyB9XG5cdFx0XHR9XG5cdFx0XHRpZigha2VlcF9odG1sKSB7IHRoaXMuZWxlbWVudC5lbXB0eSgpOyB9XG5cdFx0XHR0aGlzLnRlYXJkb3duKCk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBDcmVhdGUgYSBwcm90b3R5cGUgbm9kZVxuXHRcdCAqIEBuYW1lIF9jcmVhdGVfcHJvdG90eXBlX25vZGUoKVxuXHRcdCAqIEByZXR1cm4ge0RPTUVsZW1lbnR9XG5cdFx0ICovXG5cdFx0X2NyZWF0ZV9wcm90b3R5cGVfbm9kZSA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHZhciBfbm9kZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ0xJJyksIF90ZW1wMSwgX3RlbXAyO1xuXHRcdFx0X25vZGUuc2V0QXR0cmlidXRlKCdyb2xlJywgJ25vbmUnKTtcblx0XHRcdF90ZW1wMSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ0knKTtcblx0XHRcdF90ZW1wMS5jbGFzc05hbWUgPSAnanN0cmVlLWljb24ganN0cmVlLW9jbCc7XG5cdFx0XHRfdGVtcDEuc2V0QXR0cmlidXRlKCdyb2xlJywgJ3ByZXNlbnRhdGlvbicpO1xuXHRcdFx0X25vZGUuYXBwZW5kQ2hpbGQoX3RlbXAxKTtcblx0XHRcdF90ZW1wMSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ0EnKTtcblx0XHRcdF90ZW1wMS5jbGFzc05hbWUgPSAnanN0cmVlLWFuY2hvcic7XG5cdFx0XHRfdGVtcDEuc2V0QXR0cmlidXRlKCdocmVmJywnIycpO1xuXHRcdFx0X3RlbXAxLnNldEF0dHJpYnV0ZSgndGFiaW5kZXgnLCctMScpO1xuXHRcdFx0X3RlbXAxLnNldEF0dHJpYnV0ZSgncm9sZScsICd0cmVlaXRlbScpO1xuXHRcdFx0X3RlbXAyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnSScpO1xuXHRcdFx0X3RlbXAyLmNsYXNzTmFtZSA9ICdqc3RyZWUtaWNvbiBqc3RyZWUtdGhlbWVpY29uJztcblx0XHRcdF90ZW1wMi5zZXRBdHRyaWJ1dGUoJ3JvbGUnLCAncHJlc2VudGF0aW9uJyk7XG5cdFx0XHRfdGVtcDEuYXBwZW5kQ2hpbGQoX3RlbXAyKTtcblx0XHRcdF9ub2RlLmFwcGVuZENoaWxkKF90ZW1wMSk7XG5cdFx0XHRfdGVtcDEgPSBfdGVtcDIgPSBudWxsO1xuXG5cdFx0XHRyZXR1cm4gX25vZGU7XG5cdFx0fSxcblx0XHRfa2JldmVudF90b19mdW5jIDogZnVuY3Rpb24gKGUpIHtcblx0XHRcdHZhciBrZXlzID0ge1xuXHRcdFx0XHQ4OiBcIkJhY2tzcGFjZVwiLCA5OiBcIlRhYlwiLCAxMzogXCJFbnRlclwiLCAxOTogXCJQYXVzZVwiLCAyNzogXCJFc2NcIixcblx0XHRcdFx0MzI6IFwiU3BhY2VcIiwgMzM6IFwiUGFnZVVwXCIsIDM0OiBcIlBhZ2VEb3duXCIsIDM1OiBcIkVuZFwiLCAzNjogXCJIb21lXCIsXG5cdFx0XHRcdDM3OiBcIkxlZnRcIiwgMzg6IFwiVXBcIiwgMzk6IFwiUmlnaHRcIiwgNDA6IFwiRG93blwiLCA0NDogXCJQcmludFwiLCA0NTogXCJJbnNlcnRcIixcblx0XHRcdFx0NDY6IFwiRGVsZXRlXCIsIDk2OiBcIk51bXBhZDBcIiwgOTc6IFwiTnVtcGFkMVwiLCA5ODogXCJOdW1wYWQyXCIsIDk5IDogXCJOdW1wYWQzXCIsXG5cdFx0XHRcdDEwMDogXCJOdW1wYWQ0XCIsIDEwMTogXCJOdW1wYWQ1XCIsIDEwMjogXCJOdW1wYWQ2XCIsIDEwMzogXCJOdW1wYWQ3XCIsXG5cdFx0XHRcdDEwNDogXCJOdW1wYWQ4XCIsIDEwNTogXCJOdW1wYWQ5XCIsICctMTMnOiBcIk51bXBhZEVudGVyXCIsIDExMjogXCJGMVwiLFxuXHRcdFx0XHQxMTM6IFwiRjJcIiwgMTE0OiBcIkYzXCIsIDExNTogXCJGNFwiLCAxMTY6IFwiRjVcIiwgMTE3OiBcIkY2XCIsIDExODogXCJGN1wiLFxuXHRcdFx0XHQxMTk6IFwiRjhcIiwgMTIwOiBcIkY5XCIsIDEyMTogXCJGMTBcIiwgMTIyOiBcIkYxMVwiLCAxMjM6IFwiRjEyXCIsIDE0NDogXCJOdW1sb2NrXCIsXG5cdFx0XHRcdDE0NTogXCJTY3JvbGxsb2NrXCIsIDE2OiAnU2hpZnQnLCAxNzogJ0N0cmwnLCAxODogJ0FsdCcsXG5cdFx0XHRcdDQ4OiAnMCcsICA0OTogJzEnLCAgNTA6ICcyJywgIDUxOiAnMycsICA1MjogJzQnLCA1MzogICc1Jyxcblx0XHRcdFx0NTQ6ICc2JywgIDU1OiAnNycsICA1NjogJzgnLCAgNTc6ICc5JywgIDU5OiAnOycsICA2MTogJz0nLCA2NTogICdhJyxcblx0XHRcdFx0NjY6ICdiJywgIDY3OiAnYycsICA2ODogJ2QnLCAgNjk6ICdlJywgIDcwOiAnZicsICA3MTogJ2cnLCA3MjogICdoJyxcblx0XHRcdFx0NzM6ICdpJywgIDc0OiAnaicsICA3NTogJ2snLCAgNzY6ICdsJywgIDc3OiAnbScsICA3ODogJ24nLCA3OTogICdvJyxcblx0XHRcdFx0ODA6ICdwJywgIDgxOiAncScsICA4MjogJ3InLCAgODM6ICdzJywgIDg0OiAndCcsICA4NTogJ3UnLCA4NjogICd2Jyxcblx0XHRcdFx0ODc6ICd3JywgIDg4OiAneCcsICA4OTogJ3knLCAgOTA6ICd6JywgMTA3OiAnKycsIDEwOTogJy0nLCAxMTA6ICcuJyxcblx0XHRcdFx0MTg2OiAnOycsIDE4NzogJz0nLCAxODg6ICcsJywgMTg5OiAnLScsIDE5MDogJy4nLCAxOTE6ICcvJywgMTkyOiAnYCcsXG5cdFx0XHRcdDIxOTogJ1snLCAyMjA6ICdcXFxcJywyMjE6ICddJywgMjIyOiBcIidcIiwgMTExOiAnLycsIDEwNjogJyonLCAxNzM6ICctJ1xuXHRcdFx0fTtcblx0XHRcdHZhciBwYXJ0cyA9IFtdO1xuXHRcdFx0aWYgKGUuY3RybEtleSkgeyBwYXJ0cy5wdXNoKCdjdHJsJyk7IH1cblx0XHRcdGlmIChlLmFsdEtleSkgeyBwYXJ0cy5wdXNoKCdhbHQnKTsgfVxuICAgICAgICAgICAgaWYgKGUuc2hpZnRLZXkpIHsgcGFydHMucHVzaCgnc2hpZnQnKTsgfVxuXHRcdFx0cGFydHMucHVzaChrZXlzW2Uud2hpY2hdIHx8IGUud2hpY2gpO1xuICAgICAgICAgICAgcGFydHMgPSBwYXJ0cy5zb3J0KCkuam9pbignLScpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgICAgICBpZiAocGFydHMgPT09ICdzaGlmdC1zaGlmdCcgfHwgcGFydHMgPT09ICdjdHJsLWN0cmwnIHx8IHBhcnRzID09PSAnYWx0LWFsdCcpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIH1cblxuXHRcdFx0dmFyIGtiID0gdGhpcy5zZXR0aW5ncy5jb3JlLmtleWJvYXJkLCBpLCB0bXA7XG5cdFx0XHRmb3IgKGkgaW4ga2IpIHtcblx0XHRcdFx0aWYgKGtiLmhhc093blByb3BlcnR5KGkpKSB7XG5cdFx0XHRcdFx0dG1wID0gaTtcblx0XHRcdFx0XHRpZiAodG1wICE9PSAnLScgJiYgdG1wICE9PSAnKycpIHtcblx0XHRcdFx0XHRcdHRtcCA9IHRtcC5yZXBsYWNlKCctLScsICctTUlOVVMnKS5yZXBsYWNlKCcrLScsICctTUlOVVMnKS5yZXBsYWNlKCcrKycsICctUExVUycpLnJlcGxhY2UoJy0rJywgJy1QTFVTJyk7XG5cdFx0XHRcdFx0XHR0bXAgPSB0bXAuc3BsaXQoLy18XFwrLykuc29ydCgpLmpvaW4oJy0nKS5yZXBsYWNlKCdNSU5VUycsICctJykucmVwbGFjZSgnUExVUycsICcrJykudG9Mb3dlckNhc2UoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKHRtcCA9PT0gcGFydHMpIHtcblx0XHRcdFx0XHRcdHJldHVybiBrYltpXTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogcGFydCBvZiB0aGUgZGVzdHJveWluZyBvZiBhbiBpbnN0YW5jZS4gVXNlZCBpbnRlcm5hbGx5LlxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICogQG5hbWUgdGVhcmRvd24oKVxuXHRcdCAqL1xuXHRcdHRlYXJkb3duIDogZnVuY3Rpb24gKCkge1xuXHRcdFx0dGhpcy51bmJpbmQoKTtcblx0XHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0XHQucmVtb3ZlQ2xhc3MoJ2pzdHJlZScpXG5cdFx0XHRcdC5yZW1vdmVEYXRhKCdqc3RyZWUnKVxuXHRcdFx0XHQuZmluZChcIltjbGFzc149J2pzdHJlZSddXCIpXG5cdFx0XHRcdFx0LmFkZEJhY2soKVxuXHRcdFx0XHRcdC5hdHRyKFwiY2xhc3NcIiwgZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5jbGFzc05hbWUucmVwbGFjZSgvanN0cmVlW14gXSp8JC9pZywnJyk7IH0pO1xuXHRcdFx0dGhpcy5lbGVtZW50ID0gbnVsbDtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGJpbmQgYWxsIGV2ZW50cy4gVXNlZCBpbnRlcm5hbGx5LlxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICogQG5hbWUgYmluZCgpXG5cdFx0ICovXG5cdFx0YmluZCA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHZhciB3b3JkID0gJycsXG5cdFx0XHRcdHRvdXQgPSBudWxsLFxuXHRcdFx0XHR3YXNfY2xpY2sgPSAwO1xuXHRcdFx0dGhpcy5lbGVtZW50XG5cdFx0XHRcdC5vbihcImRibGNsaWNrLmpzdHJlZVwiLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0aWYoZS50YXJnZXQudGFnTmFtZSAmJiBlLnRhcmdldC50YWdOYW1lLnRvTG93ZXJDYXNlKCkgPT09IFwiaW5wdXRcIikgeyByZXR1cm4gdHJ1ZTsgfVxuXHRcdFx0XHRcdFx0aWYoZG9jdW1lbnQuc2VsZWN0aW9uICYmIGRvY3VtZW50LnNlbGVjdGlvbi5lbXB0eSkge1xuXHRcdFx0XHRcdFx0XHRkb2N1bWVudC5zZWxlY3Rpb24uZW1wdHkoKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRpZih3aW5kb3cuZ2V0U2VsZWN0aW9uKSB7XG5cdFx0XHRcdFx0XHRcdFx0dmFyIHNlbCA9IHdpbmRvdy5nZXRTZWxlY3Rpb24oKTtcblx0XHRcdFx0XHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdFx0XHRcdFx0c2VsLnJlbW92ZUFsbFJhbmdlcygpO1xuXHRcdFx0XHRcdFx0XHRcdFx0c2VsLmNvbGxhcHNlKCk7XG5cdFx0XHRcdFx0XHRcdFx0fSBjYXRjaCAoaWdub3JlKSB7IH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0pXG5cdFx0XHRcdC5vbihcIm1vdXNlZG93bi5qc3RyZWVcIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdGlmKGUudGFyZ2V0ID09PSB0aGlzLmVsZW1lbnRbMF0pIHtcblx0XHRcdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpOyAvLyBwcmV2ZW50IGxvc2luZyBmb2N1cyB3aGVuIGNsaWNraW5nIHNjcm9sbCBhcnJvd3MgKEZGLCBDaHJvbWUpXG5cdFx0XHRcdFx0XHRcdHdhc19jbGljayA9ICsobmV3IERhdGUoKSk7IC8vIGllIGRvZXMgbm90IGFsbG93IHRvIHByZXZlbnQgbG9zaW5nIGZvY3VzXG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fS5iaW5kKHRoaXMpKVxuXHRcdFx0XHQub24oXCJtb3VzZWRvd24uanN0cmVlXCIsIFwiLmpzdHJlZS1vY2xcIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTsgLy8gcHJldmVudCBhbnkgbm9kZSBpbnNpZGUgZnJvbSBsb3NpbmcgZm9jdXMgd2hlbiBjbGlja2luZyB0aGUgb3Blbi9jbG9zZSBpY29uXG5cdFx0XHRcdFx0fSlcblx0XHRcdFx0Lm9uKFwiY2xpY2suanN0cmVlXCIsIFwiLmpzdHJlZS1vY2xcIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdHRoaXMudG9nZ2xlX25vZGUoZS50YXJnZXQpO1xuXHRcdFx0XHRcdH0uYmluZCh0aGlzKSlcblx0XHRcdFx0Lm9uKFwiZGJsY2xpY2suanN0cmVlXCIsIFwiLmpzdHJlZS1hbmNob3JcIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdGlmKGUudGFyZ2V0LnRhZ05hbWUgJiYgZS50YXJnZXQudGFnTmFtZS50b0xvd2VyQ2FzZSgpID09PSBcImlucHV0XCIpIHsgcmV0dXJuIHRydWU7IH1cblx0XHRcdFx0XHRcdGlmKHRoaXMuc2V0dGluZ3MuY29yZS5kYmxjbGlja190b2dnbGUpIHtcblx0XHRcdFx0XHRcdFx0dGhpcy50b2dnbGVfbm9kZShlLnRhcmdldCk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fS5iaW5kKHRoaXMpKVxuXHRcdFx0XHQub24oXCJjbGljay5qc3RyZWVcIiwgXCIuanN0cmVlLWFuY2hvclwiLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0aWYoZS5jdXJyZW50VGFyZ2V0ICE9PSBkb2N1bWVudC5hY3RpdmVFbGVtZW50KSB7ICQoZS5jdXJyZW50VGFyZ2V0KS50cmlnZ2VyKCdmb2N1cycpOyB9XG5cdFx0XHRcdFx0XHR0aGlzLmFjdGl2YXRlX25vZGUoZS5jdXJyZW50VGFyZ2V0LCBlKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbigna2V5ZG93bi5qc3RyZWUnLCAnLmpzdHJlZS1hbmNob3InLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0aWYoZS50YXJnZXQudGFnTmFtZSAmJiBlLnRhcmdldC50YWdOYW1lLnRvTG93ZXJDYXNlKCkgPT09IFwiaW5wdXRcIikgeyByZXR1cm4gdHJ1ZTsgfVxuXHRcdFx0XHRcdFx0aWYodGhpcy5fZGF0YS5jb3JlLnJ0bCkge1xuXHRcdFx0XHRcdFx0XHRpZihlLndoaWNoID09PSAzNykgeyBlLndoaWNoID0gMzk7IH1cblx0XHRcdFx0XHRcdFx0ZWxzZSBpZihlLndoaWNoID09PSAzOSkgeyBlLndoaWNoID0gMzc7IH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdHZhciBmID0gdGhpcy5fa2JldmVudF90b19mdW5jKGUpO1xuXHRcdFx0XHRcdFx0aWYgKGYpIHtcblx0XHRcdFx0XHRcdFx0dmFyIHIgPSBmLmNhbGwodGhpcywgZSk7XG5cdFx0XHRcdFx0XHRcdGlmIChyID09PSBmYWxzZSB8fCByID09PSB0cnVlKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHI7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbihcImxvYWRfbm9kZS5qc3RyZWVcIiwgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0XHRcdGlmKGRhdGEuc3RhdHVzKSB7XG5cdFx0XHRcdFx0XHRcdGlmKGRhdGEubm9kZS5pZCA9PT0gJC5qc3RyZWUucm9vdCAmJiAhdGhpcy5fZGF0YS5jb3JlLmxvYWRlZCkge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5sb2FkZWQgPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRcdGlmKHRoaXMuX2ZpcnN0Q2hpbGQodGhpcy5nZXRfY29udGFpbmVyX3VsKClbMF0pKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHR0aGlzLmVsZW1lbnQuYXR0cignYXJpYS1hY3RpdmVkZXNjZW5kYW50Jyx0aGlzLl9maXJzdENoaWxkKHRoaXMuZ2V0X2NvbnRhaW5lcl91bCgpWzBdKS5pZCk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdC8qKlxuXHRcdFx0XHRcdFx0XHRcdCAqIHRyaWdnZXJlZCBhZnRlciB0aGUgcm9vdCBub2RlIGlzIGxvYWRlZCBmb3IgdGhlIGZpcnN0IHRpbWVcblx0XHRcdFx0XHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0XHRcdFx0XHQgKiBAbmFtZSBsb2FkZWQuanN0cmVlXG5cdFx0XHRcdFx0XHRcdFx0ICovXG5cdFx0XHRcdFx0XHRcdFx0dGhpcy50cmlnZ2VyKFwibG9hZGVkXCIpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGlmKCF0aGlzLl9kYXRhLmNvcmUucmVhZHkpIHtcblx0XHRcdFx0XHRcdFx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYodGhpcy5lbGVtZW50ICYmICF0aGlzLmdldF9jb250YWluZXJfdWwoKS5maW5kKCcuanN0cmVlLWxvYWRpbmcnKS5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLnJlYWR5ID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYodGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdGlmKHRoaXMuc2V0dGluZ3MuY29yZS5leHBhbmRfc2VsZWN0ZWRfb25sb2FkKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR2YXIgdG1wID0gW10sIGksIGo7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSB0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRtcCA9IHRtcC5jb25jYXQodGhpcy5fbW9kZWwuZGF0YVt0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWRbaV1dLnBhcmVudHMpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0dG1wID0gJC52YWthdGEuYXJyYXlfdW5pcXVlKHRtcCk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSB0bXAubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRoaXMub3Blbl9ub2RlKHRtcFtpXSwgZmFsc2UsIDApO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHR0aGlzLnRyaWdnZXIoJ2NoYW5nZWQnLCB7ICdhY3Rpb24nIDogJ3JlYWR5JywgJ3NlbGVjdGVkJyA6IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZCB9KTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0XHQvKipcblx0XHRcdFx0XHRcdFx0XHRcdFx0ICogdHJpZ2dlcmVkIGFmdGVyIGFsbCBub2RlcyBhcmUgZmluaXNoZWQgbG9hZGluZ1xuXHRcdFx0XHRcdFx0XHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0XHRcdFx0XHRcdFx0ICogQG5hbWUgcmVhZHkuanN0cmVlXG5cdFx0XHRcdFx0XHRcdFx0XHRcdCAqL1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0aGlzLnRyaWdnZXIoXCJyZWFkeVwiKTtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9LmJpbmQodGhpcyksIDApO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fS5iaW5kKHRoaXMpKVxuXHRcdFx0XHQvLyBxdWljayBzZWFyY2hpbmcgd2hlbiB0aGUgdHJlZSBpcyBmb2N1c2VkXG5cdFx0XHRcdC5vbigna2V5cHJlc3MuanN0cmVlJywgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdGlmKGUudGFyZ2V0LnRhZ05hbWUgJiYgZS50YXJnZXQudGFnTmFtZS50b0xvd2VyQ2FzZSgpID09PSBcImlucHV0XCIpIHsgcmV0dXJuIHRydWU7IH1cblx0XHRcdFx0XHRcdGlmKHRvdXQpIHsgY2xlYXJUaW1lb3V0KHRvdXQpOyB9XG5cdFx0XHRcdFx0XHR0b3V0ID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0XHRcdHdvcmQgPSAnJztcblx0XHRcdFx0XHRcdH0sIDUwMCk7XG5cblx0XHRcdFx0XHRcdHZhciBjaHIgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGUud2hpY2gpLnRvTG93ZXJDYXNlKCksXG5cdFx0XHRcdFx0XHRcdGNvbCA9IHRoaXMuZWxlbWVudC5maW5kKCcuanN0cmVlLWFuY2hvcicpLmZpbHRlcignOnZpc2libGUnKSxcblx0XHRcdFx0XHRcdFx0aW5kID0gY29sLmluZGV4KGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpIHx8IDAsXG5cdFx0XHRcdFx0XHRcdGVuZCA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0d29yZCArPSBjaHI7XG5cblx0XHRcdFx0XHRcdC8vIG1hdGNoIGZvciB3aG9sZSB3b3JkIGZyb20gY3VycmVudCBub2RlIGRvd24gKGluY2x1ZGluZyB0aGUgY3VycmVudCBub2RlKVxuXHRcdFx0XHRcdFx0aWYod29yZC5sZW5ndGggPiAxKSB7XG5cdFx0XHRcdFx0XHRcdGNvbC5zbGljZShpbmQpLmVhY2goZnVuY3Rpb24gKGksIHYpIHtcblx0XHRcdFx0XHRcdFx0XHRpZigkKHYpLnRleHQoKS50b0xvd2VyQ2FzZSgpLmluZGV4T2Yod29yZCkgPT09IDApIHtcblx0XHRcdFx0XHRcdFx0XHRcdCQodikudHJpZ2dlcignZm9jdXMnKTtcblx0XHRcdFx0XHRcdFx0XHRcdGVuZCA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9LmJpbmQodGhpcykpO1xuXHRcdFx0XHRcdFx0XHRpZihlbmQpIHsgcmV0dXJuOyB9XG5cblx0XHRcdFx0XHRcdFx0Ly8gbWF0Y2ggZm9yIHdob2xlIHdvcmQgZnJvbSB0aGUgYmVnaW5uaW5nIG9mIHRoZSB0cmVlXG5cdFx0XHRcdFx0XHRcdGNvbC5zbGljZSgwLCBpbmQpLmVhY2goZnVuY3Rpb24gKGksIHYpIHtcblx0XHRcdFx0XHRcdFx0XHRpZigkKHYpLnRleHQoKS50b0xvd2VyQ2FzZSgpLmluZGV4T2Yod29yZCkgPT09IDApIHtcblx0XHRcdFx0XHRcdFx0XHRcdCQodikudHJpZ2dlcignZm9jdXMnKTtcblx0XHRcdFx0XHRcdFx0XHRcdGVuZCA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9LmJpbmQodGhpcykpO1xuXHRcdFx0XHRcdFx0XHRpZihlbmQpIHsgcmV0dXJuOyB9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHQvLyBsaXN0IG5vZGVzIHRoYXQgc3RhcnQgd2l0aCB0aGF0IGxldHRlciAob25seSBpZiB3b3JkIGNvbnNpc3RzIG9mIGEgc2luZ2xlIGNoYXIpXG5cdFx0XHRcdFx0XHRpZihuZXcgUmVnRXhwKCdeJyArIGNoci5yZXBsYWNlKC9bLVxcL1xcXFxeJCorPy4oKXxbXFxde31dL2csICdcXFxcJCYnKSArICcrJCcpLnRlc3Qod29yZCkpIHtcblx0XHRcdFx0XHRcdFx0Ly8gc2VhcmNoIGZvciB0aGUgbmV4dCBub2RlIHN0YXJ0aW5nIHdpdGggdGhhdCBsZXR0ZXJcblx0XHRcdFx0XHRcdFx0Y29sLnNsaWNlKGluZCArIDEpLmVhY2goZnVuY3Rpb24gKGksIHYpIHtcblx0XHRcdFx0XHRcdFx0XHRpZigkKHYpLnRleHQoKS50b0xvd2VyQ2FzZSgpLmNoYXJBdCgwKSA9PT0gY2hyKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHQkKHYpLnRyaWdnZXIoJ2ZvY3VzJyk7XG5cdFx0XHRcdFx0XHRcdFx0XHRlbmQgPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHRcdFx0XHRcdFx0aWYoZW5kKSB7IHJldHVybjsgfVxuXG5cdFx0XHRcdFx0XHRcdC8vIHNlYXJjaCBmcm9tIHRoZSBiZWdpbm5pbmdcblx0XHRcdFx0XHRcdFx0Y29sLnNsaWNlKDAsIGluZCArIDEpLmVhY2goZnVuY3Rpb24gKGksIHYpIHtcblx0XHRcdFx0XHRcdFx0XHRpZigkKHYpLnRleHQoKS50b0xvd2VyQ2FzZSgpLmNoYXJBdCgwKSA9PT0gY2hyKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHQkKHYpLnRyaWdnZXIoJ2ZvY3VzJyk7XG5cdFx0XHRcdFx0XHRcdFx0XHRlbmQgPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHRcdFx0XHRcdFx0aWYoZW5kKSB7IHJldHVybjsgfVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0uYmluZCh0aGlzKSlcblx0XHRcdFx0Ly8gVEhFTUUgUkVMQVRFRFxuXHRcdFx0XHQub24oXCJpbml0LmpzdHJlZVwiLCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0XHR2YXIgcyA9IHRoaXMuc2V0dGluZ3MuY29yZS50aGVtZXM7XG5cdFx0XHRcdFx0XHR0aGlzLl9kYXRhLmNvcmUudGhlbWVzLmRvdHNcdFx0XHQ9IHMuZG90cztcblx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS50aGVtZXMuc3RyaXBlc1x0XHQ9IHMuc3RyaXBlcztcblx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS50aGVtZXMuaWNvbnNcdFx0PSBzLmljb25zO1xuXHRcdFx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLnRoZW1lcy5lbGxpcHNpc1x0XHQ9IHMuZWxsaXBzaXM7XG5cdFx0XHRcdFx0XHR0aGlzLnNldF90aGVtZShzLm5hbWUgfHwgXCJkZWZhdWx0XCIsIHMudXJsKTtcblx0XHRcdFx0XHRcdHRoaXMuc2V0X3RoZW1lX3ZhcmlhbnQocy52YXJpYW50KTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbihcImxvYWRpbmcuanN0cmVlXCIsIGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRcdHRoaXNbIHRoaXMuX2RhdGEuY29yZS50aGVtZXMuZG90cyA/IFwic2hvd19kb3RzXCIgOiBcImhpZGVfZG90c1wiIF0oKTtcblx0XHRcdFx0XHRcdHRoaXNbIHRoaXMuX2RhdGEuY29yZS50aGVtZXMuaWNvbnMgPyBcInNob3dfaWNvbnNcIiA6IFwiaGlkZV9pY29uc1wiIF0oKTtcblx0XHRcdFx0XHRcdHRoaXNbIHRoaXMuX2RhdGEuY29yZS50aGVtZXMuc3RyaXBlcyA/IFwic2hvd19zdHJpcGVzXCIgOiBcImhpZGVfc3RyaXBlc1wiIF0oKTtcblx0XHRcdFx0XHRcdHRoaXNbIHRoaXMuX2RhdGEuY29yZS50aGVtZXMuZWxsaXBzaXMgPyBcInNob3dfZWxsaXBzaXNcIiA6IFwiaGlkZV9lbGxpcHNpc1wiIF0oKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbignYmx1ci5qc3RyZWUnLCAnLmpzdHJlZS1hbmNob3InLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLmZvY3VzZWQgPSBudWxsO1xuXHRcdFx0XHRcdFx0JChlLmN1cnJlbnRUYXJnZXQpLmZpbHRlcignLmpzdHJlZS1ob3ZlcmVkJykudHJpZ2dlcignbW91c2VsZWF2ZScpO1xuXHRcdFx0XHRcdFx0dGhpcy5lbGVtZW50LmF0dHIoJ3RhYmluZGV4JywgJzAnKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbignZm9jdXMuanN0cmVlJywgJy5qc3RyZWUtYW5jaG9yJywgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdHZhciB0bXAgPSB0aGlzLmdldF9ub2RlKGUuY3VycmVudFRhcmdldCk7XG5cdFx0XHRcdFx0XHRpZih0bXAgJiYgdG1wLmlkKSB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5mb2N1c2VkID0gdG1wLmlkO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0dGhpcy5lbGVtZW50LmZpbmQoJy5qc3RyZWUtaG92ZXJlZCcpLm5vdChlLmN1cnJlbnRUYXJnZXQpLnRyaWdnZXIoJ21vdXNlbGVhdmUnKTtcblx0XHRcdFx0XHRcdCQoZS5jdXJyZW50VGFyZ2V0KS50cmlnZ2VyKCdtb3VzZWVudGVyJyk7XG5cdFx0XHRcdFx0XHR0aGlzLmVsZW1lbnQuYXR0cigndGFiaW5kZXgnLCAnLTEnKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbignZm9jdXMuanN0cmVlJywgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0aWYoKyhuZXcgRGF0ZSgpKSAtIHdhc19jbGljayA+IDUwMCAmJiAhdGhpcy5fZGF0YS5jb3JlLmZvY3VzZWQgJiYgdGhpcy5zZXR0aW5ncy5jb3JlLnJlc3RvcmVfZm9jdXMpIHtcblx0XHRcdFx0XHRcdFx0d2FzX2NsaWNrID0gMDtcblx0XHRcdFx0XHRcdFx0dmFyIGFjdCA9IHRoaXMuZ2V0X25vZGUodGhpcy5lbGVtZW50LmF0dHIoJ2FyaWEtYWN0aXZlZGVzY2VuZGFudCcpLCB0cnVlKTtcblx0XHRcdFx0XHRcdFx0aWYoYWN0KSB7XG5cdFx0XHRcdFx0XHRcdFx0YWN0LmZpbmQoJz4gLmpzdHJlZS1hbmNob3InKS50cmlnZ2VyKCdmb2N1cycpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fS5iaW5kKHRoaXMpKVxuXHRcdFx0XHQub24oJ21vdXNlZW50ZXIuanN0cmVlJywgJy5qc3RyZWUtYW5jaG9yJywgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdHRoaXMuaG92ZXJfbm9kZShlLmN1cnJlbnRUYXJnZXQpO1xuXHRcdFx0XHRcdH0uYmluZCh0aGlzKSlcblx0XHRcdFx0Lm9uKCdtb3VzZWxlYXZlLmpzdHJlZScsICcuanN0cmVlLWFuY2hvcicsIGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdFx0XHR0aGlzLmRlaG92ZXJfbm9kZShlLmN1cnJlbnRUYXJnZXQpO1xuXHRcdFx0XHRcdH0uYmluZCh0aGlzKSk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBwYXJ0IG9mIHRoZSBkZXN0cm95aW5nIG9mIGFuIGluc3RhbmNlLiBVc2VkIGludGVybmFsbHkuXG5cdFx0ICogQHByaXZhdGVcblx0XHQgKiBAbmFtZSB1bmJpbmQoKVxuXHRcdCAqL1xuXHRcdHVuYmluZCA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHRoaXMuZWxlbWVudC5vZmYoJy5qc3RyZWUnKTtcblx0XHRcdCQoZG9jdW1lbnQpLm9mZignLmpzdHJlZS0nICsgdGhpcy5faWQpO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogdHJpZ2dlciBhbiBldmVudC4gVXNlZCBpbnRlcm5hbGx5LlxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICogQG5hbWUgdHJpZ2dlcihldiBbLCBkYXRhXSlcblx0XHQgKiBAcGFyYW0gIHtTdHJpbmd9IGV2IHRoZSBuYW1lIG9mIHRoZSBldmVudCB0byB0cmlnZ2VyXG5cdFx0ICogQHBhcmFtICB7T2JqZWN0fSBkYXRhIGFkZGl0aW9uYWwgZGF0YSB0byBwYXNzIHdpdGggdGhlIGV2ZW50XG5cdFx0ICovXG5cdFx0dHJpZ2dlciA6IGZ1bmN0aW9uIChldiwgZGF0YSkge1xuXHRcdFx0aWYoIWRhdGEpIHtcblx0XHRcdFx0ZGF0YSA9IHt9O1xuXHRcdFx0fVxuXHRcdFx0ZGF0YS5pbnN0YW5jZSA9IHRoaXM7XG5cdFx0XHR0aGlzLmVsZW1lbnQudHJpZ2dlckhhbmRsZXIoZXYucmVwbGFjZSgnLmpzdHJlZScsJycpICsgJy5qc3RyZWUnLCBkYXRhKTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIHJldHVybnMgdGhlIGpRdWVyeSBleHRlbmRlZCBpbnN0YW5jZSBjb250YWluZXJcblx0XHQgKiBAbmFtZSBnZXRfY29udGFpbmVyKClcblx0XHQgKiBAcmV0dXJuIHtqUXVlcnl9XG5cdFx0ICovXG5cdFx0Z2V0X2NvbnRhaW5lciA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHJldHVybiB0aGlzLmVsZW1lbnQ7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiByZXR1cm5zIHRoZSBqUXVlcnkgZXh0ZW5kZWQgbWFpbiBVTCBub2RlIGluc2lkZSB0aGUgaW5zdGFuY2UgY29udGFpbmVyLiBVc2VkIGludGVybmFsbHkuXG5cdFx0ICogQHByaXZhdGVcblx0XHQgKiBAbmFtZSBnZXRfY29udGFpbmVyX3VsKClcblx0XHQgKiBAcmV0dXJuIHtqUXVlcnl9XG5cdFx0ICovXG5cdFx0Z2V0X2NvbnRhaW5lcl91bCA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHJldHVybiB0aGlzLmVsZW1lbnQuY2hpbGRyZW4oXCIuanN0cmVlLWNoaWxkcmVuXCIpLmZpcnN0KCk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBnZXRzIHN0cmluZyByZXBsYWNlbWVudHMgKGxvY2FsaXphdGlvbikuIFVzZWQgaW50ZXJuYWxseS5cblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEBuYW1lIGdldF9zdHJpbmcoa2V5KVxuXHRcdCAqIEBwYXJhbSAge1N0cmluZ30ga2V5XG5cdFx0ICogQHJldHVybiB7U3RyaW5nfVxuXHRcdCAqL1xuXHRcdGdldF9zdHJpbmcgOiBmdW5jdGlvbiAoa2V5KSB7XG5cdFx0XHR2YXIgYSA9IHRoaXMuc2V0dGluZ3MuY29yZS5zdHJpbmdzO1xuXHRcdFx0aWYoJC52YWthdGEuaXNfZnVuY3Rpb24oYSkpIHsgcmV0dXJuIGEuY2FsbCh0aGlzLCBrZXkpOyB9XG5cdFx0XHRpZihhICYmIGFba2V5XSkgeyByZXR1cm4gYVtrZXldOyB9XG5cdFx0XHRyZXR1cm4ga2V5O1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogZ2V0cyB0aGUgZmlyc3QgY2hpbGQgb2YgYSBET00gbm9kZS4gVXNlZCBpbnRlcm5hbGx5LlxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICogQG5hbWUgX2ZpcnN0Q2hpbGQoZG9tKVxuXHRcdCAqIEBwYXJhbSAge0RPTUVsZW1lbnR9IGRvbVxuXHRcdCAqIEByZXR1cm4ge0RPTUVsZW1lbnR9XG5cdFx0ICovXG5cdFx0X2ZpcnN0Q2hpbGQgOiBmdW5jdGlvbiAoZG9tKSB7XG5cdFx0XHRkb20gPSBkb20gPyBkb20uZmlyc3RDaGlsZCA6IG51bGw7XG5cdFx0XHR3aGlsZShkb20gIT09IG51bGwgJiYgZG9tLm5vZGVUeXBlICE9PSAxKSB7XG5cdFx0XHRcdGRvbSA9IGRvbS5uZXh0U2libGluZztcblx0XHRcdH1cblx0XHRcdHJldHVybiBkb207XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBnZXRzIHRoZSBuZXh0IHNpYmxpbmcgb2YgYSBET00gbm9kZS4gVXNlZCBpbnRlcm5hbGx5LlxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICogQG5hbWUgX25leHRTaWJsaW5nKGRvbSlcblx0XHQgKiBAcGFyYW0gIHtET01FbGVtZW50fSBkb21cblx0XHQgKiBAcmV0dXJuIHtET01FbGVtZW50fVxuXHRcdCAqL1xuXHRcdF9uZXh0U2libGluZyA6IGZ1bmN0aW9uIChkb20pIHtcblx0XHRcdGRvbSA9IGRvbSA/IGRvbS5uZXh0U2libGluZyA6IG51bGw7XG5cdFx0XHR3aGlsZShkb20gIT09IG51bGwgJiYgZG9tLm5vZGVUeXBlICE9PSAxKSB7XG5cdFx0XHRcdGRvbSA9IGRvbS5uZXh0U2libGluZztcblx0XHRcdH1cblx0XHRcdHJldHVybiBkb207XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBnZXRzIHRoZSBwcmV2aW91cyBzaWJsaW5nIG9mIGEgRE9NIG5vZGUuIFVzZWQgaW50ZXJuYWxseS5cblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEBuYW1lIF9wcmV2aW91c1NpYmxpbmcoZG9tKVxuXHRcdCAqIEBwYXJhbSAge0RPTUVsZW1lbnR9IGRvbVxuXHRcdCAqIEByZXR1cm4ge0RPTUVsZW1lbnR9XG5cdFx0ICovXG5cdFx0X3ByZXZpb3VzU2libGluZyA6IGZ1bmN0aW9uIChkb20pIHtcblx0XHRcdGRvbSA9IGRvbSA/IGRvbS5wcmV2aW91c1NpYmxpbmcgOiBudWxsO1xuXHRcdFx0d2hpbGUoZG9tICE9PSBudWxsICYmIGRvbS5ub2RlVHlwZSAhPT0gMSkge1xuXHRcdFx0XHRkb20gPSBkb20ucHJldmlvdXNTaWJsaW5nO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGRvbTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGdldCB0aGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiBhIG5vZGUgKG9yIHRoZSBhY3R1YWwgalF1ZXJ5IGV4dGVuZGVkIERPTSBub2RlKSBieSB1c2luZyBhbnkgaW5wdXQgKGNoaWxkIERPTSBlbGVtZW50LCBJRCBzdHJpbmcsIHNlbGVjdG9yLCBldGMpXG5cdFx0ICogQG5hbWUgZ2V0X25vZGUob2JqIFssIGFzX2RvbV0pXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9ialxuXHRcdCAqIEBwYXJhbSAge0Jvb2xlYW59IGFzX2RvbVxuXHRcdCAqIEByZXR1cm4ge09iamVjdHxqUXVlcnl9XG5cdFx0ICovXG5cdFx0Z2V0X25vZGUgOiBmdW5jdGlvbiAob2JqLCBhc19kb20pIHtcblx0XHRcdGlmKG9iaiAmJiBvYmouaWQpIHtcblx0XHRcdFx0b2JqID0gb2JqLmlkO1xuXHRcdFx0fVxuXHRcdFx0aWYgKG9iaiBpbnN0YW5jZW9mICQgJiYgb2JqLmxlbmd0aCAmJiBvYmpbMF0uaWQpIHtcblx0XHRcdFx0b2JqID0gb2JqWzBdLmlkO1xuXHRcdFx0fVxuXHRcdFx0dmFyIGRvbTtcblx0XHRcdHRyeSB7XG5cdFx0XHRcdGlmKHRoaXMuX21vZGVsLmRhdGFbb2JqXSkge1xuXHRcdFx0XHRcdG9iaiA9IHRoaXMuX21vZGVsLmRhdGFbb2JqXTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIGlmKHR5cGVvZiBvYmogPT09IFwic3RyaW5nXCIgJiYgdGhpcy5fbW9kZWwuZGF0YVtvYmoucmVwbGFjZSgvXiMvLCAnJyldKSB7XG5cdFx0XHRcdFx0b2JqID0gdGhpcy5fbW9kZWwuZGF0YVtvYmoucmVwbGFjZSgvXiMvLCAnJyldO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGVsc2UgaWYodHlwZW9mIG9iaiA9PT0gXCJzdHJpbmdcIiAmJiAoZG9tID0gJCgnIycgKyBvYmoucmVwbGFjZSgkLmpzdHJlZS5pZHJlZ2V4LCdcXFxcJCYnKSwgdGhpcy5lbGVtZW50KSkubGVuZ3RoICYmIHRoaXMuX21vZGVsLmRhdGFbZG9tLmNsb3Nlc3QoJy5qc3RyZWUtbm9kZScpLmF0dHIoJ2lkJyldKSB7XG5cdFx0XHRcdFx0b2JqID0gdGhpcy5fbW9kZWwuZGF0YVtkb20uY2xvc2VzdCgnLmpzdHJlZS1ub2RlJykuYXR0cignaWQnKV07XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSBpZigoZG9tID0gdGhpcy5lbGVtZW50LmZpbmQob2JqKSkubGVuZ3RoICYmIHRoaXMuX21vZGVsLmRhdGFbZG9tLmNsb3Nlc3QoJy5qc3RyZWUtbm9kZScpLmF0dHIoJ2lkJyldKSB7XG5cdFx0XHRcdFx0b2JqID0gdGhpcy5fbW9kZWwuZGF0YVtkb20uY2xvc2VzdCgnLmpzdHJlZS1ub2RlJykuYXR0cignaWQnKV07XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSBpZigoZG9tID0gdGhpcy5lbGVtZW50LmZpbmQob2JqKSkubGVuZ3RoICYmIGRvbS5oYXNDbGFzcygnanN0cmVlJykpIHtcblx0XHRcdFx0XHRvYmogPSB0aGlzLl9tb2RlbC5kYXRhWyQuanN0cmVlLnJvb3RdO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmKGFzX2RvbSkge1xuXHRcdFx0XHRcdG9iaiA9IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCA/IHRoaXMuZWxlbWVudCA6ICQoJyMnICsgb2JqLmlkLnJlcGxhY2UoJC5qc3RyZWUuaWRyZWdleCwnXFxcXCQmJyksIHRoaXMuZWxlbWVudCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIG9iajtcblx0XHRcdH0gY2F0Y2ggKGV4KSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogZ2V0IHRoZSBwYXRoIHRvIGEgbm9kZSwgZWl0aGVyIGNvbnNpc3Rpbmcgb2Ygbm9kZSB0ZXh0cywgb3Igb2Ygbm9kZSBJRHMsIG9wdGlvbmFsbHkgZ2x1ZWQgdG9nZXRoZXIgKG90aGVyd2lzZSBhbiBhcnJheSlcblx0XHQgKiBAbmFtZSBnZXRfcGF0aChvYmogWywgZ2x1ZSwgaWRzXSlcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqIHRoZSBub2RlXG5cdFx0ICogQHBhcmFtICB7U3RyaW5nfSBnbHVlIGlmIHlvdSB3YW50IHRoZSBwYXRoIGFzIGEgc3RyaW5nIC0gcGFzcyB0aGUgZ2x1ZSBoZXJlIChmb3IgZXhhbXBsZSAnLycpLCBpZiBhIGZhbHN5IHZhbHVlIGlzIHN1cHBsaWVkIGhlcmUsIGFuIGFycmF5IGlzIHJldHVybmVkXG5cdFx0ICogQHBhcmFtICB7Qm9vbGVhbn0gaWRzIGlmIHNldCB0byB0cnVlIGJ1aWxkIHRoZSBwYXRoIHVzaW5nIElELCBvdGhlcndpc2Ugbm9kZSB0ZXh0IGlzIHVzZWRcblx0XHQgKiBAcmV0dXJuIHttaXhlZH1cblx0XHQgKi9cblx0XHRnZXRfcGF0aCA6IGZ1bmN0aW9uIChvYmosIGdsdWUsIGlkcykge1xuXHRcdFx0b2JqID0gb2JqLnBhcmVudHMgPyBvYmogOiB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqIHx8IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCB8fCAhb2JqLnBhcmVudHMpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0dmFyIGksIGosIHAgPSBbXTtcblx0XHRcdHAucHVzaChpZHMgPyBvYmouaWQgOiBvYmoudGV4dCk7XG5cdFx0XHRmb3IoaSA9IDAsIGogPSBvYmoucGFyZW50cy5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0cC5wdXNoKGlkcyA/IG9iai5wYXJlbnRzW2ldIDogdGhpcy5nZXRfdGV4dChvYmoucGFyZW50c1tpXSkpO1xuXHRcdFx0fVxuXHRcdFx0cCA9IHAucmV2ZXJzZSgpLnNsaWNlKDEpO1xuXHRcdFx0cmV0dXJuIGdsdWUgPyBwLmpvaW4oZ2x1ZSkgOiBwO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogZ2V0IHRoZSBuZXh0IHZpc2libGUgbm9kZSB0aGF0IGlzIGJlbG93IHRoZSBgb2JqYCBub2RlLiBJZiBgc3RyaWN0YCBpcyBzZXQgdG8gYHRydWVgIG9ubHkgc2libGluZyBub2RlcyBhcmUgcmV0dXJuZWQuXG5cdFx0ICogQG5hbWUgZ2V0X25leHRfZG9tKG9iaiBbLCBzdHJpY3RdKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBvYmpcblx0XHQgKiBAcGFyYW0gIHtCb29sZWFufSBzdHJpY3Rcblx0XHQgKiBAcmV0dXJuIHtqUXVlcnl9XG5cdFx0ICovXG5cdFx0Z2V0X25leHRfZG9tIDogZnVuY3Rpb24gKG9iaiwgc3RyaWN0KSB7XG5cdFx0XHR2YXIgdG1wO1xuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmosIHRydWUpO1xuXHRcdFx0aWYob2JqWzBdID09PSB0aGlzLmVsZW1lbnRbMF0pIHtcblx0XHRcdFx0dG1wID0gdGhpcy5fZmlyc3RDaGlsZCh0aGlzLmdldF9jb250YWluZXJfdWwoKVswXSk7XG5cdFx0XHRcdHdoaWxlICh0bXAgJiYgdG1wLm9mZnNldEhlaWdodCA9PT0gMCkge1xuXHRcdFx0XHRcdHRtcCA9IHRoaXMuX25leHRTaWJsaW5nKHRtcCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRtcCA/ICQodG1wKSA6IGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0aWYoIW9iaiB8fCAhb2JqLmxlbmd0aCkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRpZihzdHJpY3QpIHtcblx0XHRcdFx0dG1wID0gb2JqWzBdO1xuXHRcdFx0XHRkbyB7XG5cdFx0XHRcdFx0dG1wID0gdGhpcy5fbmV4dFNpYmxpbmcodG1wKTtcblx0XHRcdFx0fSB3aGlsZSAodG1wICYmIHRtcC5vZmZzZXRIZWlnaHQgPT09IDApO1xuXHRcdFx0XHRyZXR1cm4gdG1wID8gJCh0bXApIDogZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRpZihvYmouaGFzQ2xhc3MoXCJqc3RyZWUtb3BlblwiKSkge1xuXHRcdFx0XHR0bXAgPSB0aGlzLl9maXJzdENoaWxkKG9iai5jaGlsZHJlbignLmpzdHJlZS1jaGlsZHJlbicpWzBdKTtcblx0XHRcdFx0d2hpbGUgKHRtcCAmJiB0bXAub2Zmc2V0SGVpZ2h0ID09PSAwKSB7XG5cdFx0XHRcdFx0dG1wID0gdGhpcy5fbmV4dFNpYmxpbmcodG1wKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZih0bXAgIT09IG51bGwpIHtcblx0XHRcdFx0XHRyZXR1cm4gJCh0bXApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHR0bXAgPSBvYmpbMF07XG5cdFx0XHRkbyB7XG5cdFx0XHRcdHRtcCA9IHRoaXMuX25leHRTaWJsaW5nKHRtcCk7XG5cdFx0XHR9IHdoaWxlICh0bXAgJiYgdG1wLm9mZnNldEhlaWdodCA9PT0gMCk7XG5cdFx0XHRpZih0bXAgIT09IG51bGwpIHtcblx0XHRcdFx0cmV0dXJuICQodG1wKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBvYmoucGFyZW50c1VudGlsKFwiLmpzdHJlZVwiLFwiLmpzdHJlZS1ub2RlXCIpLm5leHRBbGwoXCIuanN0cmVlLW5vZGU6dmlzaWJsZVwiKS5maXJzdCgpO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogZ2V0IHRoZSBwcmV2aW91cyB2aXNpYmxlIG5vZGUgdGhhdCBpcyBhYm92ZSB0aGUgYG9iamAgbm9kZS4gSWYgYHN0cmljdGAgaXMgc2V0IHRvIGB0cnVlYCBvbmx5IHNpYmxpbmcgbm9kZXMgYXJlIHJldHVybmVkLlxuXHRcdCAqIEBuYW1lIGdldF9wcmV2X2RvbShvYmogWywgc3RyaWN0XSlcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqXG5cdFx0ICogQHBhcmFtICB7Qm9vbGVhbn0gc3RyaWN0XG5cdFx0ICogQHJldHVybiB7alF1ZXJ5fVxuXHRcdCAqL1xuXHRcdGdldF9wcmV2X2RvbSA6IGZ1bmN0aW9uIChvYmosIHN0cmljdCkge1xuXHRcdFx0dmFyIHRtcDtcblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqLCB0cnVlKTtcblx0XHRcdGlmKG9ialswXSA9PT0gdGhpcy5lbGVtZW50WzBdKSB7XG5cdFx0XHRcdHRtcCA9IHRoaXMuZ2V0X2NvbnRhaW5lcl91bCgpWzBdLmxhc3RDaGlsZDtcblx0XHRcdFx0d2hpbGUgKHRtcCAmJiB0bXAub2Zmc2V0SGVpZ2h0ID09PSAwKSB7XG5cdFx0XHRcdFx0dG1wID0gdGhpcy5fcHJldmlvdXNTaWJsaW5nKHRtcCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRtcCA/ICQodG1wKSA6IGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0aWYoIW9iaiB8fCAhb2JqLmxlbmd0aCkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRpZihzdHJpY3QpIHtcblx0XHRcdFx0dG1wID0gb2JqWzBdO1xuXHRcdFx0XHRkbyB7XG5cdFx0XHRcdFx0dG1wID0gdGhpcy5fcHJldmlvdXNTaWJsaW5nKHRtcCk7XG5cdFx0XHRcdH0gd2hpbGUgKHRtcCAmJiB0bXAub2Zmc2V0SGVpZ2h0ID09PSAwKTtcblx0XHRcdFx0cmV0dXJuIHRtcCA/ICQodG1wKSA6IGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0dG1wID0gb2JqWzBdO1xuXHRcdFx0ZG8ge1xuXHRcdFx0XHR0bXAgPSB0aGlzLl9wcmV2aW91c1NpYmxpbmcodG1wKTtcblx0XHRcdH0gd2hpbGUgKHRtcCAmJiB0bXAub2Zmc2V0SGVpZ2h0ID09PSAwKTtcblx0XHRcdGlmKHRtcCAhPT0gbnVsbCkge1xuXHRcdFx0XHRvYmogPSAkKHRtcCk7XG5cdFx0XHRcdHdoaWxlKG9iai5oYXNDbGFzcyhcImpzdHJlZS1vcGVuXCIpKSB7XG5cdFx0XHRcdFx0b2JqID0gb2JqLmNoaWxkcmVuKFwiLmpzdHJlZS1jaGlsZHJlblwiKS5maXJzdCgpLmNoaWxkcmVuKFwiLmpzdHJlZS1ub2RlOnZpc2libGU6bGFzdFwiKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gb2JqO1xuXHRcdFx0fVxuXHRcdFx0dG1wID0gb2JqWzBdLnBhcmVudE5vZGUucGFyZW50Tm9kZTtcblx0XHRcdHJldHVybiB0bXAgJiYgdG1wLmNsYXNzTmFtZSAmJiB0bXAuY2xhc3NOYW1lLmluZGV4T2YoJ2pzdHJlZS1ub2RlJykgIT09IC0xID8gJCh0bXApIDogZmFsc2U7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBnZXQgdGhlIHBhcmVudCBJRCBvZiBhIG5vZGVcblx0XHQgKiBAbmFtZSBnZXRfcGFyZW50KG9iailcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqXG5cdFx0ICogQHJldHVybiB7U3RyaW5nfVxuXHRcdCAqL1xuXHRcdGdldF9wYXJlbnQgOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqIHx8IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gb2JqLnBhcmVudDtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGdldCBhIGpRdWVyeSBjb2xsZWN0aW9uIG9mIGFsbCB0aGUgY2hpbGRyZW4gb2YgYSBub2RlIChub2RlIG11c3QgYmUgcmVuZGVyZWQpLCByZXR1cm5zIGZhbHNlIG9uIGVycm9yXG5cdFx0ICogQG5hbWUgZ2V0X2NoaWxkcmVuX2RvbShvYmopXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9ialxuXHRcdCAqIEByZXR1cm4ge2pRdWVyeX1cblx0XHQgKi9cblx0XHRnZXRfY2hpbGRyZW5fZG9tIDogZnVuY3Rpb24gKG9iaikge1xuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmosIHRydWUpO1xuXHRcdFx0aWYob2JqWzBdID09PSB0aGlzLmVsZW1lbnRbMF0pIHtcblx0XHRcdFx0cmV0dXJuIHRoaXMuZ2V0X2NvbnRhaW5lcl91bCgpLmNoaWxkcmVuKFwiLmpzdHJlZS1ub2RlXCIpO1xuXHRcdFx0fVxuXHRcdFx0aWYoIW9iaiB8fCAhb2JqLmxlbmd0aCkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gb2JqLmNoaWxkcmVuKFwiLmpzdHJlZS1jaGlsZHJlblwiKS5jaGlsZHJlbihcIi5qc3RyZWUtbm9kZVwiKTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGNoZWNrcyBpZiBhIG5vZGUgaGFzIGNoaWxkcmVuXG5cdFx0ICogQG5hbWUgaXNfcGFyZW50KG9iailcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqXG5cdFx0ICogQHJldHVybiB7Qm9vbGVhbn1cblx0XHQgKi9cblx0XHRpc19wYXJlbnQgOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRyZXR1cm4gb2JqICYmIChvYmouc3RhdGUubG9hZGVkID09PSBmYWxzZSB8fCBvYmouY2hpbGRyZW4ubGVuZ3RoID4gMCk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBjaGVja3MgaWYgYSBub2RlIGlzIGxvYWRlZCAoaXRzIGNoaWxkcmVuIGFyZSBhdmFpbGFibGUpXG5cdFx0ICogQG5hbWUgaXNfbG9hZGVkKG9iailcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqXG5cdFx0ICogQHJldHVybiB7Qm9vbGVhbn1cblx0XHQgKi9cblx0XHRpc19sb2FkZWQgOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRyZXR1cm4gb2JqICYmIG9iai5zdGF0ZS5sb2FkZWQ7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBjaGVjayBpZiBhIG5vZGUgaXMgY3VycmVudGx5IGxvYWRpbmcgKGZldGNoaW5nIGNoaWxkcmVuKVxuXHRcdCAqIEBuYW1lIGlzX2xvYWRpbmcob2JqKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBvYmpcblx0XHQgKiBAcmV0dXJuIHtCb29sZWFufVxuXHRcdCAqL1xuXHRcdGlzX2xvYWRpbmcgOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRyZXR1cm4gb2JqICYmIG9iai5zdGF0ZSAmJiBvYmouc3RhdGUubG9hZGluZztcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGNoZWNrIGlmIGEgbm9kZSBpcyBvcGVuZWRcblx0XHQgKiBAbmFtZSBpc19vcGVuKG9iailcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqXG5cdFx0ICogQHJldHVybiB7Qm9vbGVhbn1cblx0XHQgKi9cblx0XHRpc19vcGVuIDogZnVuY3Rpb24gKG9iaikge1xuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0cmV0dXJuIG9iaiAmJiBvYmouc3RhdGUub3BlbmVkO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogY2hlY2sgaWYgYSBub2RlIGlzIGluIGEgY2xvc2VkIHN0YXRlXG5cdFx0ICogQG5hbWUgaXNfY2xvc2VkKG9iailcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqXG5cdFx0ICogQHJldHVybiB7Qm9vbGVhbn1cblx0XHQgKi9cblx0XHRpc19jbG9zZWQgOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRyZXR1cm4gb2JqICYmIHRoaXMuaXNfcGFyZW50KG9iaikgJiYgIW9iai5zdGF0ZS5vcGVuZWQ7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBjaGVjayBpZiBhIG5vZGUgaGFzIG5vIGNoaWxkcmVuXG5cdFx0ICogQG5hbWUgaXNfbGVhZihvYmopXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9ialxuXHRcdCAqIEByZXR1cm4ge0Jvb2xlYW59XG5cdFx0ICovXG5cdFx0aXNfbGVhZiA6IGZ1bmN0aW9uIChvYmopIHtcblx0XHRcdHJldHVybiAhdGhpcy5pc19wYXJlbnQob2JqKTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGxvYWRzIGEgbm9kZSAoZmV0Y2hlcyBpdHMgY2hpbGRyZW4gdXNpbmcgdGhlIGBjb3JlLmRhdGFgIHNldHRpbmcpLiBNdWx0aXBsZSBub2RlcyBjYW4gYmUgcGFzc2VkIHRvIGJ5IHVzaW5nIGFuIGFycmF5LlxuXHRcdCAqIEBuYW1lIGxvYWRfbm9kZShvYmogWywgY2FsbGJhY2tdKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBvYmpcblx0XHQgKiBAcGFyYW0gIHtmdW5jdGlvbn0gY2FsbGJhY2sgYSBmdW5jdGlvbiB0byBiZSBleGVjdXRlZCBvbmNlIGxvYWRpbmcgaXMgY29tcGxldGUsIHRoZSBmdW5jdGlvbiBpcyBleGVjdXRlZCBpbiB0aGUgaW5zdGFuY2UncyBzY29wZSBhbmQgcmVjZWl2ZXMgdHdvIGFyZ3VtZW50cyAtIHRoZSBub2RlIGFuZCBhIGJvb2xlYW4gc3RhdHVzXG5cdFx0ICogQHJldHVybiB7Qm9vbGVhbn1cblx0XHQgKiBAdHJpZ2dlciBsb2FkX25vZGUuanN0cmVlXG5cdFx0ICovXG5cdFx0bG9hZF9ub2RlIDogZnVuY3Rpb24gKG9iaiwgY2FsbGJhY2spIHtcblx0XHRcdHZhciBrLCBsLCBpLCBqLCBjO1xuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkob2JqKSkge1xuXHRcdFx0XHR0aGlzLl9sb2FkX25vZGVzKG9iai5zbGljZSgpLCBjYWxsYmFjayk7XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaikge1xuXHRcdFx0XHRpZihjYWxsYmFjaykgeyBjYWxsYmFjay5jYWxsKHRoaXMsIG9iaiwgZmFsc2UpOyB9XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdC8vIGlmKG9iai5zdGF0ZS5sb2FkaW5nKSB7IH0gLy8gdGhlIG5vZGUgaXMgYWxyZWFkeSBsb2FkaW5nIC0ganVzdCB3YWl0IGZvciBpdCB0byBsb2FkIGFuZCBpbnZva2UgY2FsbGJhY2s/IGJ1dCBpZiBjYWxsZWQgaW1wbGljaXRseSBpdCBzaG91bGQgYmUgbG9hZGVkIGFnYWluP1xuXHRcdFx0aWYob2JqLnN0YXRlLmxvYWRlZCkge1xuXHRcdFx0XHRvYmouc3RhdGUubG9hZGVkID0gZmFsc2U7XG5cdFx0XHRcdGZvcihpID0gMCwgaiA9IG9iai5wYXJlbnRzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdHRoaXMuX21vZGVsLmRhdGFbb2JqLnBhcmVudHNbaV1dLmNoaWxkcmVuX2QgPSAkLnZha2F0YS5hcnJheV9maWx0ZXIodGhpcy5fbW9kZWwuZGF0YVtvYmoucGFyZW50c1tpXV0uY2hpbGRyZW5fZCwgZnVuY3Rpb24gKHYpIHtcblx0XHRcdFx0XHRcdHJldHVybiAkLmluQXJyYXkodiwgb2JqLmNoaWxkcmVuX2QpID09PSAtMTtcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHRmb3IoayA9IDAsIGwgPSBvYmouY2hpbGRyZW5fZC5sZW5ndGg7IGsgPCBsOyBrKyspIHtcblx0XHRcdFx0XHRpZih0aGlzLl9tb2RlbC5kYXRhW29iai5jaGlsZHJlbl9kW2tdXS5zdGF0ZS5zZWxlY3RlZCkge1xuXHRcdFx0XHRcdFx0YyA9IHRydWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGRlbGV0ZSB0aGlzLl9tb2RlbC5kYXRhW29iai5jaGlsZHJlbl9kW2tdXTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoYykge1xuXHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZCA9ICQudmFrYXRhLmFycmF5X2ZpbHRlcih0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQsIGZ1bmN0aW9uICh2KSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gJC5pbkFycmF5KHYsIG9iai5jaGlsZHJlbl9kKSA9PT0gLTE7XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0b2JqLmNoaWxkcmVuID0gW107XG5cdFx0XHRcdG9iai5jaGlsZHJlbl9kID0gW107XG5cdFx0XHRcdGlmKGMpIHtcblx0XHRcdFx0XHR0aGlzLnRyaWdnZXIoJ2NoYW5nZWQnLCB7ICdhY3Rpb24nIDogJ2xvYWRfbm9kZScsICdub2RlJyA6IG9iaiwgJ3NlbGVjdGVkJyA6IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZCB9KTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0b2JqLnN0YXRlLmZhaWxlZCA9IGZhbHNlO1xuXHRcdFx0b2JqLnN0YXRlLmxvYWRpbmcgPSB0cnVlO1xuXHRcdFx0dGhpcy5nZXRfbm9kZShvYmosIHRydWUpLmFkZENsYXNzKFwianN0cmVlLWxvYWRpbmdcIikuYXR0cignYXJpYS1idXN5Jyx0cnVlKTtcblx0XHRcdHRoaXMuX2xvYWRfbm9kZShvYmosIGZ1bmN0aW9uIChzdGF0dXMpIHtcblx0XHRcdFx0b2JqID0gdGhpcy5fbW9kZWwuZGF0YVtvYmouaWRdO1xuXHRcdFx0XHRvYmouc3RhdGUubG9hZGluZyA9IGZhbHNlO1xuXHRcdFx0XHRvYmouc3RhdGUubG9hZGVkID0gc3RhdHVzO1xuXHRcdFx0XHRvYmouc3RhdGUuZmFpbGVkID0gIW9iai5zdGF0ZS5sb2FkZWQ7XG5cdFx0XHRcdHZhciBkb20gPSB0aGlzLmdldF9ub2RlKG9iaiwgdHJ1ZSksIGkgPSAwLCBqID0gMCwgbSA9IHRoaXMuX21vZGVsLmRhdGEsIGhhc19jaGlsZHJlbiA9IGZhbHNlO1xuXHRcdFx0XHRmb3IoaSA9IDAsIGogPSBvYmouY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0aWYobVtvYmouY2hpbGRyZW5baV1dICYmICFtW29iai5jaGlsZHJlbltpXV0uc3RhdGUuaGlkZGVuKSB7XG5cdFx0XHRcdFx0XHRoYXNfY2hpbGRyZW4gPSB0cnVlO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKG9iai5zdGF0ZS5sb2FkZWQgJiYgZG9tICYmIGRvbS5sZW5ndGgpIHtcblx0XHRcdFx0XHRkb20ucmVtb3ZlQ2xhc3MoJ2pzdHJlZS1jbG9zZWQganN0cmVlLW9wZW4ganN0cmVlLWxlYWYnKTtcblx0XHRcdFx0XHRpZiAoIWhhc19jaGlsZHJlbikge1xuXHRcdFx0XHRcdFx0ZG9tLmFkZENsYXNzKCdqc3RyZWUtbGVhZicpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdGlmIChvYmouaWQgIT09ICcjJykge1xuXHRcdFx0XHRcdFx0XHRkb20uYWRkQ2xhc3Mob2JqLnN0YXRlLm9wZW5lZCA/ICdqc3RyZWUtb3BlbicgOiAnanN0cmVlLWNsb3NlZCcpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRkb20ucmVtb3ZlQ2xhc3MoXCJqc3RyZWUtbG9hZGluZ1wiKS5hdHRyKCdhcmlhLWJ1c3knLGZhbHNlKTtcblx0XHRcdFx0LyoqXG5cdFx0XHRcdCAqIHRyaWdnZXJlZCBhZnRlciBhIG5vZGUgaXMgbG9hZGVkXG5cdFx0XHRcdCAqIEBldmVudFxuXHRcdFx0XHQgKiBAbmFtZSBsb2FkX25vZGUuanN0cmVlXG5cdFx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlIHRoZSBub2RlIHRoYXQgd2FzIGxvYWRpbmdcblx0XHRcdFx0ICogQHBhcmFtIHtCb29sZWFufSBzdGF0dXMgd2FzIHRoZSBub2RlIGxvYWRlZCBzdWNjZXNzZnVsbHlcblx0XHRcdFx0ICovXG5cdFx0XHRcdHRoaXMudHJpZ2dlcignbG9hZF9ub2RlJywgeyBcIm5vZGVcIiA6IG9iaiwgXCJzdGF0dXNcIiA6IHN0YXR1cyB9KTtcblx0XHRcdFx0aWYoY2FsbGJhY2spIHtcblx0XHRcdFx0XHRjYWxsYmFjay5jYWxsKHRoaXMsIG9iaiwgc3RhdHVzKTtcblx0XHRcdFx0fVxuXHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogbG9hZCBhbiBhcnJheSBvZiBub2RlcyAod2lsbCBhbHNvIGxvYWQgdW5hdmFpbGFibGUgbm9kZXMgYXMgc29vbiBhcyB0aGV5IGFwcGVhciBpbiB0aGUgc3RydWN0dXJlKS4gVXNlZCBpbnRlcm5hbGx5LlxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICogQG5hbWUgX2xvYWRfbm9kZXMobm9kZXMgWywgY2FsbGJhY2tdKVxuXHRcdCAqIEBwYXJhbSAge2FycmF5fSBub2Rlc1xuXHRcdCAqIEBwYXJhbSAge2Z1bmN0aW9ufSBjYWxsYmFjayBhIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIG9uY2UgbG9hZGluZyBpcyBjb21wbGV0ZSwgdGhlIGZ1bmN0aW9uIGlzIGV4ZWN1dGVkIGluIHRoZSBpbnN0YW5jZSdzIHNjb3BlIGFuZCByZWNlaXZlcyBvbmUgYXJndW1lbnQgLSB0aGUgYXJyYXkgcGFzc2VkIHRvIF9sb2FkX25vZGVzXG5cdFx0ICovXG5cdFx0X2xvYWRfbm9kZXMgOiBmdW5jdGlvbiAobm9kZXMsIGNhbGxiYWNrLCBpc19jYWxsYmFjaywgZm9yY2VfcmVsb2FkKSB7XG5cdFx0XHR2YXIgciA9IHRydWUsXG5cdFx0XHRcdGMgPSBmdW5jdGlvbiAoKSB7IHRoaXMuX2xvYWRfbm9kZXMobm9kZXMsIGNhbGxiYWNrLCB0cnVlKTsgfSxcblx0XHRcdFx0bSA9IHRoaXMuX21vZGVsLmRhdGEsIGksIGosIHRtcCA9IFtdO1xuXHRcdFx0Zm9yKGkgPSAwLCBqID0gbm9kZXMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdGlmKG1bbm9kZXNbaV1dICYmICggKCFtW25vZGVzW2ldXS5zdGF0ZS5sb2FkZWQgJiYgIW1bbm9kZXNbaV1dLnN0YXRlLmZhaWxlZCkgfHwgKCFpc19jYWxsYmFjayAmJiBmb3JjZV9yZWxvYWQpICkpIHtcblx0XHRcdFx0XHRpZighdGhpcy5pc19sb2FkaW5nKG5vZGVzW2ldKSkge1xuXHRcdFx0XHRcdFx0dGhpcy5sb2FkX25vZGUobm9kZXNbaV0sIGMpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRyID0gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmKHIpIHtcblx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gbm9kZXMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0aWYobVtub2Rlc1tpXV0gJiYgbVtub2Rlc1tpXV0uc3RhdGUubG9hZGVkKSB7XG5cdFx0XHRcdFx0XHR0bXAucHVzaChub2Rlc1tpXSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKGNhbGxiYWNrICYmICFjYWxsYmFjay5kb25lKSB7XG5cdFx0XHRcdFx0Y2FsbGJhY2suY2FsbCh0aGlzLCB0bXApO1xuXHRcdFx0XHRcdGNhbGxiYWNrLmRvbmUgPSB0cnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBsb2FkcyBhbGwgdW5sb2FkZWQgbm9kZXNcblx0XHQgKiBAbmFtZSBsb2FkX2FsbChbb2JqLCBjYWxsYmFja10pXG5cdFx0ICogQHBhcmFtIHttaXhlZH0gb2JqIHRoZSBub2RlIHRvIGxvYWQgcmVjdXJzaXZlbHksIG9taXQgdG8gbG9hZCBhbGwgbm9kZXMgaW4gdGhlIHRyZWVcblx0XHQgKiBAcGFyYW0ge2Z1bmN0aW9ufSBjYWxsYmFjayBhIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIG9uY2UgbG9hZGluZyBhbGwgdGhlIG5vZGVzIGlzIGNvbXBsZXRlLFxuXHRcdCAqIEB0cmlnZ2VyIGxvYWRfYWxsLmpzdHJlZVxuXHRcdCAqL1xuXHRcdGxvYWRfYWxsIDogZnVuY3Rpb24gKG9iaiwgY2FsbGJhY2spIHtcblx0XHRcdGlmKCFvYmopIHsgb2JqID0gJC5qc3RyZWUucm9vdDsgfVxuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaikgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdHZhciB0b19sb2FkID0gW10sXG5cdFx0XHRcdG0gPSB0aGlzLl9tb2RlbC5kYXRhLFxuXHRcdFx0XHRjID0gbVtvYmouaWRdLmNoaWxkcmVuX2QsXG5cdFx0XHRcdGksIGo7XG5cdFx0XHRpZihvYmouc3RhdGUgJiYgIW9iai5zdGF0ZS5sb2FkZWQpIHtcblx0XHRcdFx0dG9fbG9hZC5wdXNoKG9iai5pZCk7XG5cdFx0XHR9XG5cdFx0XHRmb3IoaSA9IDAsIGogPSBjLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRpZihtW2NbaV1dICYmIG1bY1tpXV0uc3RhdGUgJiYgIW1bY1tpXV0uc3RhdGUubG9hZGVkKSB7XG5cdFx0XHRcdFx0dG9fbG9hZC5wdXNoKGNbaV0pO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRpZih0b19sb2FkLmxlbmd0aCkge1xuXHRcdFx0XHR0aGlzLl9sb2FkX25vZGVzKHRvX2xvYWQsIGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHR0aGlzLmxvYWRfYWxsKG9iaiwgY2FsbGJhY2spO1xuXHRcdFx0XHR9KTtcblx0XHRcdH1cblx0XHRcdGVsc2Uge1xuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIGFmdGVyIGEgbG9hZF9hbGwgY2FsbCBjb21wbGV0ZXNcblx0XHRcdFx0ICogQGV2ZW50XG5cdFx0XHRcdCAqIEBuYW1lIGxvYWRfYWxsLmpzdHJlZVxuXHRcdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZSB0aGUgcmVjdXJzaXZlbHkgbG9hZGVkIG5vZGVcblx0XHRcdFx0ICovXG5cdFx0XHRcdGlmKGNhbGxiYWNrKSB7IGNhbGxiYWNrLmNhbGwodGhpcywgb2JqKTsgfVxuXHRcdFx0XHR0aGlzLnRyaWdnZXIoJ2xvYWRfYWxsJywgeyBcIm5vZGVcIiA6IG9iaiB9KTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGhhbmRsZXMgdGhlIGFjdHVhbCBsb2FkaW5nIG9mIGEgbm9kZS4gVXNlZCBvbmx5IGludGVybmFsbHkuXG5cdFx0ICogQHByaXZhdGVcblx0XHQgKiBAbmFtZSBfbG9hZF9ub2RlKG9iaiBbLCBjYWxsYmFja10pXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9ialxuXHRcdCAqIEBwYXJhbSAge2Z1bmN0aW9ufSBjYWxsYmFjayBhIGZ1bmN0aW9uIHRvIGJlIGV4ZWN1dGVkIG9uY2UgbG9hZGluZyBpcyBjb21wbGV0ZSwgdGhlIGZ1bmN0aW9uIGlzIGV4ZWN1dGVkIGluIHRoZSBpbnN0YW5jZSdzIHNjb3BlIGFuZCByZWNlaXZlcyBvbmUgYXJndW1lbnQgLSBhIGJvb2xlYW4gc3RhdHVzXG5cdFx0ICogQHJldHVybiB7Qm9vbGVhbn1cblx0XHQgKi9cblx0XHRfbG9hZF9ub2RlIDogZnVuY3Rpb24gKG9iaiwgY2FsbGJhY2spIHtcblx0XHRcdHZhciBzID0gdGhpcy5zZXR0aW5ncy5jb3JlLmRhdGEsIHQ7XG5cdFx0XHR2YXIgbm90VGV4dE9yQ29tbWVudE5vZGUgPSBmdW5jdGlvbiBub3RUZXh0T3JDb21tZW50Tm9kZSAoKSB7XG5cdFx0XHRcdHJldHVybiB0aGlzLm5vZGVUeXBlICE9PSAzICYmIHRoaXMubm9kZVR5cGUgIT09IDg7XG5cdFx0XHR9O1xuXHRcdFx0Ly8gdXNlIG9yaWdpbmFsIEhUTUxcblx0XHRcdGlmKCFzKSB7XG5cdFx0XHRcdGlmKG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkge1xuXHRcdFx0XHRcdHJldHVybiB0aGlzLl9hcHBlbmRfaHRtbF9kYXRhKG9iaiwgdGhpcy5fZGF0YS5jb3JlLm9yaWdpbmFsX2NvbnRhaW5lcl9odG1sLmNsb25lKHRydWUpLCBmdW5jdGlvbiAoc3RhdHVzKSB7XG5cdFx0XHRcdFx0XHRjYWxsYmFjay5jYWxsKHRoaXMsIHN0YXR1cyk7XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0cmV0dXJuIGNhbGxiYWNrLmNhbGwodGhpcywgZmFsc2UpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdC8vIHJldHVybiBjYWxsYmFjay5jYWxsKHRoaXMsIG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCA/IHRoaXMuX2FwcGVuZF9odG1sX2RhdGEob2JqLCB0aGlzLl9kYXRhLmNvcmUub3JpZ2luYWxfY29udGFpbmVyX2h0bWwuY2xvbmUodHJ1ZSkpIDogZmFsc2UpO1xuXHRcdFx0fVxuXHRcdFx0aWYoJC52YWthdGEuaXNfZnVuY3Rpb24ocykpIHtcblx0XHRcdFx0cmV0dXJuIHMuY2FsbCh0aGlzLCBvYmosIGZ1bmN0aW9uIChkKSB7XG5cdFx0XHRcdFx0aWYoZCA9PT0gZmFsc2UpIHtcblx0XHRcdFx0XHRcdGNhbGxiYWNrLmNhbGwodGhpcywgZmFsc2UpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdHRoaXNbdHlwZW9mIGQgPT09ICdzdHJpbmcnID8gJ19hcHBlbmRfaHRtbF9kYXRhJyA6ICdfYXBwZW5kX2pzb25fZGF0YSddKG9iaiwgdHlwZW9mIGQgPT09ICdzdHJpbmcnID8gJCgkLnBhcnNlSFRNTChkKSkuZmlsdGVyKG5vdFRleHRPckNvbW1lbnROb2RlKSA6IGQsIGZ1bmN0aW9uIChzdGF0dXMpIHtcblx0XHRcdFx0XHRcdFx0Y2FsbGJhY2suY2FsbCh0aGlzLCBzdGF0dXMpO1xuXHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdC8vIHJldHVybiBkID09PSBmYWxzZSA/IGNhbGxiYWNrLmNhbGwodGhpcywgZmFsc2UpIDogY2FsbGJhY2suY2FsbCh0aGlzLCB0aGlzW3R5cGVvZiBkID09PSAnc3RyaW5nJyA/ICdfYXBwZW5kX2h0bWxfZGF0YScgOiAnX2FwcGVuZF9qc29uX2RhdGEnXShvYmosIHR5cGVvZiBkID09PSAnc3RyaW5nJyA/ICQoZCkgOiBkKSk7XG5cdFx0XHRcdH0uYmluZCh0aGlzKSk7XG5cdFx0XHR9XG5cdFx0XHRpZih0eXBlb2YgcyA9PT0gJ29iamVjdCcpIHtcblx0XHRcdFx0aWYocy51cmwpIHtcblx0XHRcdFx0XHRzID0gJC5leHRlbmQodHJ1ZSwge30sIHMpO1xuXHRcdFx0XHRcdGlmKCQudmFrYXRhLmlzX2Z1bmN0aW9uKHMudXJsKSkge1xuXHRcdFx0XHRcdFx0cy51cmwgPSBzLnVybC5jYWxsKHRoaXMsIG9iaik7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmKCQudmFrYXRhLmlzX2Z1bmN0aW9uKHMuZGF0YSkpIHtcblx0XHRcdFx0XHRcdHMuZGF0YSA9IHMuZGF0YS5jYWxsKHRoaXMsIG9iaik7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiAkLmFqYXgocylcblx0XHRcdFx0XHRcdC5kb25lKGZ1bmN0aW9uIChkLHQseCkge1xuXHRcdFx0XHRcdFx0XHRcdHZhciB0eXBlID0geC5nZXRSZXNwb25zZUhlYWRlcignQ29udGVudC1UeXBlJyk7XG5cdFx0XHRcdFx0XHRcdFx0aWYoKHR5cGUgJiYgdHlwZS5pbmRleE9mKCdqc29uJykgIT09IC0xKSB8fCB0eXBlb2YgZCA9PT0gXCJvYmplY3RcIikge1xuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMuX2FwcGVuZF9qc29uX2RhdGEob2JqLCBkLCBmdW5jdGlvbiAoc3RhdHVzKSB7IGNhbGxiYWNrLmNhbGwodGhpcywgc3RhdHVzKTsgfSk7XG5cdFx0XHRcdFx0XHRcdFx0XHQvL3JldHVybiBjYWxsYmFjay5jYWxsKHRoaXMsIHRoaXMuX2FwcGVuZF9qc29uX2RhdGEob2JqLCBkKSk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdGlmKCh0eXBlICYmIHR5cGUuaW5kZXhPZignaHRtbCcpICE9PSAtMSkgfHwgdHlwZW9mIGQgPT09IFwic3RyaW5nXCIpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHJldHVybiB0aGlzLl9hcHBlbmRfaHRtbF9kYXRhKG9iaiwgJCgkLnBhcnNlSFRNTChkKSkuZmlsdGVyKG5vdFRleHRPckNvbW1lbnROb2RlKSwgZnVuY3Rpb24gKHN0YXR1cykgeyBjYWxsYmFjay5jYWxsKHRoaXMsIHN0YXR1cyk7IH0pO1xuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gcmV0dXJuIGNhbGxiYWNrLmNhbGwodGhpcywgdGhpcy5fYXBwZW5kX2h0bWxfZGF0YShvYmosICQoZCkpKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLmxhc3RfZXJyb3IgPSB7ICdlcnJvcicgOiAnYWpheCcsICdwbHVnaW4nIDogJ2NvcmUnLCAnaWQnIDogJ2NvcmVfMDQnLCAncmVhc29uJyA6ICdDb3VsZCBub3QgbG9hZCBub2RlJywgJ2RhdGEnIDogSlNPTi5zdHJpbmdpZnkoeyAnaWQnIDogb2JqLmlkLCAneGhyJyA6IHggfSkgfTtcblx0XHRcdFx0XHRcdFx0XHR0aGlzLnNldHRpbmdzLmNvcmUuZXJyb3IuY2FsbCh0aGlzLCB0aGlzLl9kYXRhLmNvcmUubGFzdF9lcnJvcik7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIGNhbGxiYWNrLmNhbGwodGhpcywgZmFsc2UpO1xuXHRcdFx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdFx0XHQuZmFpbChmdW5jdGlvbiAoZikge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5sYXN0X2Vycm9yID0geyAnZXJyb3InIDogJ2FqYXgnLCAncGx1Z2luJyA6ICdjb3JlJywgJ2lkJyA6ICdjb3JlXzA0JywgJ3JlYXNvbicgOiAnQ291bGQgbm90IGxvYWQgbm9kZScsICdkYXRhJyA6IEpTT04uc3RyaW5naWZ5KHsgJ2lkJyA6IG9iai5pZCwgJ3hocicgOiBmIH0pIH07XG5cdFx0XHRcdFx0XHRcdFx0Y2FsbGJhY2suY2FsbCh0aGlzLCBmYWxzZSk7XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5zZXR0aW5ncy5jb3JlLmVycm9yLmNhbGwodGhpcywgdGhpcy5fZGF0YS5jb3JlLmxhc3RfZXJyb3IpO1xuXHRcdFx0XHRcdFx0XHR9LmJpbmQodGhpcykpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICgkLnZha2F0YS5pc19hcnJheShzKSkge1xuXHRcdFx0XHRcdHQgPSAkLmV4dGVuZCh0cnVlLCBbXSwgcyk7XG5cdFx0XHRcdH0gZWxzZSBpZiAoJC5pc1BsYWluT2JqZWN0KHMpKSB7XG5cdFx0XHRcdFx0dCA9ICQuZXh0ZW5kKHRydWUsIHt9LCBzKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0ID0gcztcblx0XHRcdFx0fVxuXHRcdFx0XHRpZihvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcy5fYXBwZW5kX2pzb25fZGF0YShvYmosIHQsIGZ1bmN0aW9uIChzdGF0dXMpIHtcblx0XHRcdFx0XHRcdGNhbGxiYWNrLmNhbGwodGhpcywgc3RhdHVzKTtcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHR0aGlzLl9kYXRhLmNvcmUubGFzdF9lcnJvciA9IHsgJ2Vycm9yJyA6ICdub2RhdGEnLCAncGx1Z2luJyA6ICdjb3JlJywgJ2lkJyA6ICdjb3JlXzA1JywgJ3JlYXNvbicgOiAnQ291bGQgbm90IGxvYWQgbm9kZScsICdkYXRhJyA6IEpTT04uc3RyaW5naWZ5KHsgJ2lkJyA6IG9iai5pZCB9KSB9O1xuXHRcdFx0XHRcdHRoaXMuc2V0dGluZ3MuY29yZS5lcnJvci5jYWxsKHRoaXMsIHRoaXMuX2RhdGEuY29yZS5sYXN0X2Vycm9yKTtcblx0XHRcdFx0XHRyZXR1cm4gY2FsbGJhY2suY2FsbCh0aGlzLCBmYWxzZSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0Ly9yZXR1cm4gY2FsbGJhY2suY2FsbCh0aGlzLCAob2JqLmlkID09PSAkLmpzdHJlZS5yb290ID8gdGhpcy5fYXBwZW5kX2pzb25fZGF0YShvYmosIHQpIDogZmFsc2UpICk7XG5cdFx0XHR9XG5cdFx0XHRpZih0eXBlb2YgcyA9PT0gJ3N0cmluZycpIHtcblx0XHRcdFx0aWYob2JqLmlkID09PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuX2FwcGVuZF9odG1sX2RhdGEob2JqLCAkKCQucGFyc2VIVE1MKHMpKS5maWx0ZXIobm90VGV4dE9yQ29tbWVudE5vZGUpLCBmdW5jdGlvbiAoc3RhdHVzKSB7XG5cdFx0XHRcdFx0XHRjYWxsYmFjay5jYWxsKHRoaXMsIHN0YXR1cyk7XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLmxhc3RfZXJyb3IgPSB7ICdlcnJvcicgOiAnbm9kYXRhJywgJ3BsdWdpbicgOiAnY29yZScsICdpZCcgOiAnY29yZV8wNicsICdyZWFzb24nIDogJ0NvdWxkIG5vdCBsb2FkIG5vZGUnLCAnZGF0YScgOiBKU09OLnN0cmluZ2lmeSh7ICdpZCcgOiBvYmouaWQgfSkgfTtcblx0XHRcdFx0XHR0aGlzLnNldHRpbmdzLmNvcmUuZXJyb3IuY2FsbCh0aGlzLCB0aGlzLl9kYXRhLmNvcmUubGFzdF9lcnJvcik7XG5cdFx0XHRcdFx0cmV0dXJuIGNhbGxiYWNrLmNhbGwodGhpcywgZmFsc2UpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdC8vcmV0dXJuIGNhbGxiYWNrLmNhbGwodGhpcywgKG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCA/IHRoaXMuX2FwcGVuZF9odG1sX2RhdGEob2JqLCAkKHMpKSA6IGZhbHNlKSApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGNhbGxiYWNrLmNhbGwodGhpcywgZmFsc2UpO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogYWRkcyBhIG5vZGUgdG8gdGhlIGxpc3Qgb2Ygbm9kZXMgdG8gcmVkcmF3LiBVc2VkIG9ubHkgaW50ZXJuYWxseS5cblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEBuYW1lIF9ub2RlX2NoYW5nZWQob2JqIFssIGNhbGxiYWNrXSlcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqXG5cdFx0ICovXG5cdFx0X25vZGVfY2hhbmdlZCA6IGZ1bmN0aW9uIChvYmopIHtcblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcbiAgICAgIGlmIChvYmogJiYgJC5pbkFycmF5KG9iai5pZCwgdGhpcy5fbW9kZWwuY2hhbmdlZCkgPT09IC0xKSB7XG5cdFx0XHRcdHRoaXMuX21vZGVsLmNoYW5nZWQucHVzaChvYmouaWQpO1xuXHRcdFx0fVxuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogYXBwZW5kcyBIVE1MIGNvbnRlbnQgdG8gdGhlIHRyZWUuIFVzZWQgaW50ZXJuYWxseS5cblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEBuYW1lIF9hcHBlbmRfaHRtbF9kYXRhKG9iaiwgZGF0YSlcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqIHRoZSBub2RlIHRvIGFwcGVuZCB0b1xuXHRcdCAqIEBwYXJhbSAge1N0cmluZ30gZGF0YSB0aGUgSFRNTCBzdHJpbmcgdG8gcGFyc2UgYW5kIGFwcGVuZFxuXHRcdCAqIEB0cmlnZ2VyIG1vZGVsLmpzdHJlZSwgY2hhbmdlZC5qc3RyZWVcblx0XHQgKi9cblx0XHRfYXBwZW5kX2h0bWxfZGF0YSA6IGZ1bmN0aW9uIChkb20sIGRhdGEsIGNiKSB7XG5cdFx0XHRkb20gPSB0aGlzLmdldF9ub2RlKGRvbSk7XG5cdFx0XHRkb20uY2hpbGRyZW4gPSBbXTtcblx0XHRcdGRvbS5jaGlsZHJlbl9kID0gW107XG5cdFx0XHR2YXIgZGF0ID0gZGF0YS5pcygndWwnKSA/IGRhdGEuY2hpbGRyZW4oKSA6IGRhdGEsXG5cdFx0XHRcdHBhciA9IGRvbS5pZCxcblx0XHRcdFx0Y2hkID0gW10sXG5cdFx0XHRcdGRwYyA9IFtdLFxuXHRcdFx0XHRtID0gdGhpcy5fbW9kZWwuZGF0YSxcblx0XHRcdFx0cCA9IG1bcGFyXSxcblx0XHRcdFx0cyA9IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZC5sZW5ndGgsXG5cdFx0XHRcdHRtcCwgaSwgajtcblx0XHRcdGRhdC5lYWNoKGZ1bmN0aW9uIChpLCB2KSB7XG5cdFx0XHRcdHRtcCA9IHRoaXMuX3BhcnNlX21vZGVsX2Zyb21faHRtbCgkKHYpLCBwYXIsIHAucGFyZW50cy5jb25jYXQoKSk7XG5cdFx0XHRcdGlmKHRtcCkge1xuXHRcdFx0XHRcdGNoZC5wdXNoKHRtcCk7XG5cdFx0XHRcdFx0ZHBjLnB1c2godG1wKTtcblx0XHRcdFx0XHRpZihtW3RtcF0uY2hpbGRyZW5fZC5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdGRwYyA9IGRwYy5jb25jYXQobVt0bXBdLmNoaWxkcmVuX2QpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHRcdHAuY2hpbGRyZW4gPSBjaGQ7XG5cdFx0XHRwLmNoaWxkcmVuX2QgPSBkcGM7XG5cdFx0XHRmb3IoaSA9IDAsIGogPSBwLnBhcmVudHMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdG1bcC5wYXJlbnRzW2ldXS5jaGlsZHJlbl9kID0gbVtwLnBhcmVudHNbaV1dLmNoaWxkcmVuX2QuY29uY2F0KGRwYyk7XG5cdFx0XHR9XG5cdFx0XHQvKipcblx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIG5ldyBkYXRhIGlzIGluc2VydGVkIHRvIHRoZSB0cmVlIG1vZGVsXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIG1vZGVsLmpzdHJlZVxuXHRcdFx0ICogQHBhcmFtIHtBcnJheX0gbm9kZXMgYW4gYXJyYXkgb2Ygbm9kZSBJRHNcblx0XHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBwYXJlbnQgdGhlIHBhcmVudCBJRCBvZiB0aGUgbm9kZXNcblx0XHRcdCAqL1xuXHRcdFx0dGhpcy50cmlnZ2VyKCdtb2RlbCcsIHsgXCJub2Rlc1wiIDogZHBjLCAncGFyZW50JyA6IHBhciB9KTtcblx0XHRcdGlmKHBhciAhPT0gJC5qc3RyZWUucm9vdCkge1xuXHRcdFx0XHR0aGlzLl9ub2RlX2NoYW5nZWQocGFyKTtcblx0XHRcdFx0dGhpcy5yZWRyYXcoKTtcblx0XHRcdH1cblx0XHRcdGVsc2Uge1xuXHRcdFx0XHR0aGlzLmdldF9jb250YWluZXJfdWwoKS5jaGlsZHJlbignLmpzdHJlZS1pbml0aWFsLW5vZGUnKS5yZW1vdmUoKTtcblx0XHRcdFx0dGhpcy5yZWRyYXcodHJ1ZSk7XG5cdFx0XHR9XG5cdFx0XHRpZih0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQubGVuZ3RoICE9PSBzKSB7XG5cdFx0XHRcdHRoaXMudHJpZ2dlcignY2hhbmdlZCcsIHsgJ2FjdGlvbicgOiAnbW9kZWwnLCAnc2VsZWN0ZWQnIDogdGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkIH0pO1xuXHRcdFx0fVxuXHRcdFx0Y2IuY2FsbCh0aGlzLCB0cnVlKTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGFwcGVuZHMgSlNPTiBjb250ZW50IHRvIHRoZSB0cmVlLiBVc2VkIGludGVybmFsbHkuXG5cdFx0ICogQHByaXZhdGVcblx0XHQgKiBAbmFtZSBfYXBwZW5kX2pzb25fZGF0YShvYmosIGRhdGEpXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9iaiB0aGUgbm9kZSB0byBhcHBlbmQgdG9cblx0XHQgKiBAcGFyYW0gIHtTdHJpbmd9IGRhdGEgdGhlIEpTT04gb2JqZWN0IHRvIHBhcnNlIGFuZCBhcHBlbmRcblx0XHQgKiBAcGFyYW0gIHtCb29sZWFufSBmb3JjZV9wcm9jZXNzaW5nIGludGVybmFsIHBhcmFtIC0gZG8gbm90IHNldFxuXHRcdCAqIEB0cmlnZ2VyIG1vZGVsLmpzdHJlZSwgY2hhbmdlZC5qc3RyZWVcblx0XHQgKi9cblx0XHRfYXBwZW5kX2pzb25fZGF0YSA6IGZ1bmN0aW9uIChkb20sIGRhdGEsIGNiLCBmb3JjZV9wcm9jZXNzaW5nKSB7XG5cdFx0XHRpZih0aGlzLmVsZW1lbnQgPT09IG51bGwpIHsgcmV0dXJuOyB9XG5cdFx0XHRkb20gPSB0aGlzLmdldF9ub2RlKGRvbSk7XG5cdFx0XHRkb20uY2hpbGRyZW4gPSBbXTtcblx0XHRcdGRvbS5jaGlsZHJlbl9kID0gW107XG5cdFx0XHQvLyAqJSRAISEhXG5cdFx0XHRpZihkYXRhLmQpIHtcblx0XHRcdFx0ZGF0YSA9IGRhdGEuZDtcblx0XHRcdFx0aWYodHlwZW9mIGRhdGEgPT09IFwic3RyaW5nXCIpIHtcblx0XHRcdFx0XHRkYXRhID0gSlNPTi5wYXJzZShkYXRhKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0aWYoISQudmFrYXRhLmlzX2FycmF5KGRhdGEpKSB7IGRhdGEgPSBbZGF0YV07IH1cblx0XHRcdHZhciB3ID0gbnVsbCxcblx0XHRcdFx0YXJncyA9IHtcblx0XHRcdFx0XHQnZGYnXHQ6IHRoaXMuX21vZGVsLmRlZmF1bHRfc3RhdGUsXG5cdFx0XHRcdFx0J2RhdCdcdDogZGF0YSxcblx0XHRcdFx0XHQncGFyJ1x0OiBkb20uaWQsXG5cdFx0XHRcdFx0J20nXHRcdDogdGhpcy5fbW9kZWwuZGF0YSxcblx0XHRcdFx0XHQndF9pZCdcdDogdGhpcy5faWQsXG5cdFx0XHRcdFx0J3RfY250J1x0OiB0aGlzLl9jbnQsXG5cdFx0XHRcdFx0J3NlbCdcdDogdGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGluc3QgPSB0aGlzLFxuXHRcdFx0XHRmdW5jID0gZnVuY3Rpb24gKGRhdGEsIHVuZGVmaW5lZCkge1xuXHRcdFx0XHRcdGlmKGRhdGEuZGF0YSkgeyBkYXRhID0gZGF0YS5kYXRhOyB9XG5cdFx0XHRcdFx0dmFyIGRhdCA9IGRhdGEuZGF0LFxuXHRcdFx0XHRcdFx0cGFyID0gZGF0YS5wYXIsXG5cdFx0XHRcdFx0XHRjaGQgPSBbXSxcblx0XHRcdFx0XHRcdGRwYyA9IFtdLFxuXHRcdFx0XHRcdFx0YWRkID0gW10sXG5cdFx0XHRcdFx0XHRkZiA9IGRhdGEuZGYsXG5cdFx0XHRcdFx0XHR0X2lkID0gZGF0YS50X2lkLFxuXHRcdFx0XHRcdFx0dF9jbnQgPSBkYXRhLnRfY250LFxuXHRcdFx0XHRcdFx0bSA9IGRhdGEubSxcblx0XHRcdFx0XHRcdHAgPSBtW3Bhcl0sXG5cdFx0XHRcdFx0XHRzZWwgPSBkYXRhLnNlbCxcblx0XHRcdFx0XHRcdHRtcCwgaSwgaiwgcnNsdCxcblx0XHRcdFx0XHRcdHBhcnNlX2ZsYXQgPSBmdW5jdGlvbiAoZCwgcCwgcHMpIHtcblx0XHRcdFx0XHRcdFx0aWYoIXBzKSB7IHBzID0gW107IH1cblx0XHRcdFx0XHRcdFx0ZWxzZSB7IHBzID0gcHMuY29uY2F0KCk7IH1cblx0XHRcdFx0XHRcdFx0aWYocCkgeyBwcy51bnNoaWZ0KHApOyB9XG5cdFx0XHRcdFx0XHRcdHZhciB0aWQgPSBkLmlkLnRvU3RyaW5nKCksXG5cdFx0XHRcdFx0XHRcdFx0aSwgaiwgYywgZSxcblx0XHRcdFx0XHRcdFx0XHR0bXAgPSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZFx0XHRcdDogdGlkLFxuXHRcdFx0XHRcdFx0XHRcdFx0dGV4dFx0XHQ6IGQudGV4dCB8fCAnJyxcblx0XHRcdFx0XHRcdFx0XHRcdGljb25cdFx0OiBkLmljb24gIT09IHVuZGVmaW5lZCA/IGQuaWNvbiA6IHRydWUsXG5cdFx0XHRcdFx0XHRcdFx0XHRwYXJlbnRcdFx0OiBwLFxuXHRcdFx0XHRcdFx0XHRcdFx0cGFyZW50c1x0XHQ6IHBzLFxuXHRcdFx0XHRcdFx0XHRcdFx0Y2hpbGRyZW5cdDogZC5jaGlsZHJlbiB8fCBbXSxcblx0XHRcdFx0XHRcdFx0XHRcdGNoaWxkcmVuX2RcdDogZC5jaGlsZHJlbl9kIHx8IFtdLFxuXHRcdFx0XHRcdFx0XHRcdFx0ZGF0YVx0XHQ6IGQuZGF0YSxcblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlXHRcdDogeyB9LFxuXHRcdFx0XHRcdFx0XHRcdFx0bGlfYXR0clx0XHQ6IHsgaWQgOiBmYWxzZSB9LFxuXHRcdFx0XHRcdFx0XHRcdFx0YV9hdHRyXHRcdDogeyBocmVmIDogJyMnIH0sXG5cdFx0XHRcdFx0XHRcdFx0XHRvcmlnaW5hbFx0OiBmYWxzZVxuXHRcdFx0XHRcdFx0XHRcdH07XG5cdFx0XHRcdFx0XHRcdGZvcihpIGluIGRmKSB7XG5cdFx0XHRcdFx0XHRcdFx0aWYoZGYuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHRtcC5zdGF0ZVtpXSA9IGRmW2ldO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRpZihkICYmIGQuZGF0YSAmJiBkLmRhdGEuanN0cmVlICYmIGQuZGF0YS5qc3RyZWUuaWNvbikge1xuXHRcdFx0XHRcdFx0XHRcdHRtcC5pY29uID0gZC5kYXRhLmpzdHJlZS5pY29uO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGlmKHRtcC5pY29uID09PSB1bmRlZmluZWQgfHwgdG1wLmljb24gPT09IG51bGwgfHwgdG1wLmljb24gPT09IFwiXCIpIHtcblx0XHRcdFx0XHRcdFx0XHR0bXAuaWNvbiA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYoZCAmJiBkLmRhdGEpIHtcblx0XHRcdFx0XHRcdFx0XHR0bXAuZGF0YSA9IGQuZGF0YTtcblx0XHRcdFx0XHRcdFx0XHRpZihkLmRhdGEuanN0cmVlKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRmb3IoaSBpbiBkLmRhdGEuanN0cmVlKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGlmKGQuZGF0YS5qc3RyZWUuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHR0bXAuc3RhdGVbaV0gPSBkLmRhdGEuanN0cmVlW2ldO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGlmKGQgJiYgdHlwZW9mIGQuc3RhdGUgPT09ICdvYmplY3QnKSB7XG5cdFx0XHRcdFx0XHRcdFx0Zm9yIChpIGluIGQuc3RhdGUpIHtcblx0XHRcdFx0XHRcdFx0XHRcdGlmKGQuc3RhdGUuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dG1wLnN0YXRlW2ldID0gZC5zdGF0ZVtpXTtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYoZCAmJiB0eXBlb2YgZC5saV9hdHRyID09PSAnb2JqZWN0Jykge1xuXHRcdFx0XHRcdFx0XHRcdGZvciAoaSBpbiBkLmxpX2F0dHIpIHtcblx0XHRcdFx0XHRcdFx0XHRcdGlmKGQubGlfYXR0ci5oYXNPd25Qcm9wZXJ0eShpKSkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0bXAubGlfYXR0cltpXSA9IGQubGlfYXR0cltpXTtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYoIXRtcC5saV9hdHRyLmlkKSB7XG5cdFx0XHRcdFx0XHRcdFx0dG1wLmxpX2F0dHIuaWQgPSB0aWQ7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYoZCAmJiB0eXBlb2YgZC5hX2F0dHIgPT09ICdvYmplY3QnKSB7XG5cdFx0XHRcdFx0XHRcdFx0Zm9yIChpIGluIGQuYV9hdHRyKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZihkLmFfYXR0ci5oYXNPd25Qcm9wZXJ0eShpKSkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0bXAuYV9hdHRyW2ldID0gZC5hX2F0dHJbaV07XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGlmKGQgJiYgZC5jaGlsZHJlbiAmJiBkLmNoaWxkcmVuID09PSB0cnVlKSB7XG5cdFx0XHRcdFx0XHRcdFx0dG1wLnN0YXRlLmxvYWRlZCA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0XHRcdHRtcC5jaGlsZHJlbiA9IFtdO1xuXHRcdFx0XHRcdFx0XHRcdHRtcC5jaGlsZHJlbl9kID0gW107XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0bVt0bXAuaWRdID0gdG1wO1xuXHRcdFx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSB0bXAuY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdFx0YyA9IHBhcnNlX2ZsYXQobVt0bXAuY2hpbGRyZW5baV1dLCB0bXAuaWQsIHBzKTtcblx0XHRcdFx0XHRcdFx0XHRlID0gbVtjXTtcblx0XHRcdFx0XHRcdFx0XHR0bXAuY2hpbGRyZW5fZC5wdXNoKGMpO1xuXHRcdFx0XHRcdFx0XHRcdGlmKGUuY2hpbGRyZW5fZC5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHRtcC5jaGlsZHJlbl9kID0gdG1wLmNoaWxkcmVuX2QuY29uY2F0KGUuY2hpbGRyZW5fZCk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGRlbGV0ZSBkLmRhdGE7XG5cdFx0XHRcdFx0XHRcdGRlbGV0ZSBkLmNoaWxkcmVuO1xuXHRcdFx0XHRcdFx0XHRtW3RtcC5pZF0ub3JpZ2luYWwgPSBkO1xuXHRcdFx0XHRcdFx0XHRpZih0bXAuc3RhdGUuc2VsZWN0ZWQpIHtcblx0XHRcdFx0XHRcdFx0XHRhZGQucHVzaCh0bXAuaWQpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdHJldHVybiB0bXAuaWQ7XG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0cGFyc2VfbmVzdCA9IGZ1bmN0aW9uIChkLCBwLCBwcykge1xuXHRcdFx0XHRcdFx0XHRpZighcHMpIHsgcHMgPSBbXTsgfVxuXHRcdFx0XHRcdFx0XHRlbHNlIHsgcHMgPSBwcy5jb25jYXQoKTsgfVxuXHRcdFx0XHRcdFx0XHRpZihwKSB7IHBzLnVuc2hpZnQocCk7IH1cblx0XHRcdFx0XHRcdFx0dmFyIHRpZCA9IGZhbHNlLCBpLCBqLCBjLCBlLCB0bXA7XG5cdFx0XHRcdFx0XHRcdGRvIHtcblx0XHRcdFx0XHRcdFx0XHR0aWQgPSAnaicgKyB0X2lkICsgJ18nICsgKCsrdF9jbnQpO1xuXHRcdFx0XHRcdFx0XHR9IHdoaWxlKG1bdGlkXSk7XG5cblx0XHRcdFx0XHRcdFx0dG1wID0ge1xuXHRcdFx0XHRcdFx0XHRcdGlkXHRcdFx0OiBmYWxzZSxcblx0XHRcdFx0XHRcdFx0XHR0ZXh0XHRcdDogdHlwZW9mIGQgPT09ICdzdHJpbmcnID8gZCA6ICcnLFxuXHRcdFx0XHRcdFx0XHRcdGljb25cdFx0OiB0eXBlb2YgZCA9PT0gJ29iamVjdCcgJiYgZC5pY29uICE9PSB1bmRlZmluZWQgPyBkLmljb24gOiB0cnVlLFxuXHRcdFx0XHRcdFx0XHRcdHBhcmVudFx0XHQ6IHAsXG5cdFx0XHRcdFx0XHRcdFx0cGFyZW50c1x0XHQ6IHBzLFxuXHRcdFx0XHRcdFx0XHRcdGNoaWxkcmVuXHQ6IFtdLFxuXHRcdFx0XHRcdFx0XHRcdGNoaWxkcmVuX2RcdDogW10sXG5cdFx0XHRcdFx0XHRcdFx0ZGF0YVx0XHQ6IG51bGwsXG5cdFx0XHRcdFx0XHRcdFx0c3RhdGVcdFx0OiB7IH0sXG5cdFx0XHRcdFx0XHRcdFx0bGlfYXR0clx0XHQ6IHsgaWQgOiBmYWxzZSB9LFxuXHRcdFx0XHRcdFx0XHRcdGFfYXR0clx0XHQ6IHsgaHJlZiA6ICcjJyB9LFxuXHRcdFx0XHRcdFx0XHRcdG9yaWdpbmFsXHQ6IGZhbHNlXG5cdFx0XHRcdFx0XHRcdH07XG5cdFx0XHRcdFx0XHRcdGZvcihpIGluIGRmKSB7XG5cdFx0XHRcdFx0XHRcdFx0aWYoZGYuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHRtcC5zdGF0ZVtpXSA9IGRmW2ldO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRpZihkICYmIGQuaWQpIHsgdG1wLmlkID0gZC5pZC50b1N0cmluZygpOyB9XG5cdFx0XHRcdFx0XHRcdGlmKGQgJiYgZC50ZXh0KSB7IHRtcC50ZXh0ID0gZC50ZXh0OyB9XG5cdFx0XHRcdFx0XHRcdGlmKGQgJiYgZC5kYXRhICYmIGQuZGF0YS5qc3RyZWUgJiYgZC5kYXRhLmpzdHJlZS5pY29uKSB7XG5cdFx0XHRcdFx0XHRcdFx0dG1wLmljb24gPSBkLmRhdGEuanN0cmVlLmljb247XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYodG1wLmljb24gPT09IHVuZGVmaW5lZCB8fCB0bXAuaWNvbiA9PT0gbnVsbCB8fCB0bXAuaWNvbiA9PT0gXCJcIikge1xuXHRcdFx0XHRcdFx0XHRcdHRtcC5pY29uID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRpZihkICYmIGQuZGF0YSkge1xuXHRcdFx0XHRcdFx0XHRcdHRtcC5kYXRhID0gZC5kYXRhO1xuXHRcdFx0XHRcdFx0XHRcdGlmKGQuZGF0YS5qc3RyZWUpIHtcblx0XHRcdFx0XHRcdFx0XHRcdGZvcihpIGluIGQuZGF0YS5qc3RyZWUpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYoZC5kYXRhLmpzdHJlZS5oYXNPd25Qcm9wZXJ0eShpKSkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRtcC5zdGF0ZVtpXSA9IGQuZGF0YS5qc3RyZWVbaV07XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYoZCAmJiB0eXBlb2YgZC5zdGF0ZSA9PT0gJ29iamVjdCcpIHtcblx0XHRcdFx0XHRcdFx0XHRmb3IgKGkgaW4gZC5zdGF0ZSkge1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYoZC5zdGF0ZS5oYXNPd25Qcm9wZXJ0eShpKSkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0bXAuc3RhdGVbaV0gPSBkLnN0YXRlW2ldO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRpZihkICYmIHR5cGVvZiBkLmxpX2F0dHIgPT09ICdvYmplY3QnKSB7XG5cdFx0XHRcdFx0XHRcdFx0Zm9yIChpIGluIGQubGlfYXR0cikge1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYoZC5saV9hdHRyLmhhc093blByb3BlcnR5KGkpKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHRtcC5saV9hdHRyW2ldID0gZC5saV9hdHRyW2ldO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRpZih0bXAubGlfYXR0ci5pZCAmJiAhdG1wLmlkKSB7XG5cdFx0XHRcdFx0XHRcdFx0dG1wLmlkID0gdG1wLmxpX2F0dHIuaWQudG9TdHJpbmcoKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRpZighdG1wLmlkKSB7XG5cdFx0XHRcdFx0XHRcdFx0dG1wLmlkID0gdGlkO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGlmKCF0bXAubGlfYXR0ci5pZCkge1xuXHRcdFx0XHRcdFx0XHRcdHRtcC5saV9hdHRyLmlkID0gdG1wLmlkO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGlmKGQgJiYgdHlwZW9mIGQuYV9hdHRyID09PSAnb2JqZWN0Jykge1xuXHRcdFx0XHRcdFx0XHRcdGZvciAoaSBpbiBkLmFfYXR0cikge1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYoZC5hX2F0dHIuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dG1wLmFfYXR0cltpXSA9IGQuYV9hdHRyW2ldO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRpZihkICYmIGQuY2hpbGRyZW4gJiYgZC5jaGlsZHJlbi5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSBkLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdFx0XHRcdFx0YyA9IHBhcnNlX25lc3QoZC5jaGlsZHJlbltpXSwgdG1wLmlkLCBwcyk7XG5cdFx0XHRcdFx0XHRcdFx0XHRlID0gbVtjXTtcblx0XHRcdFx0XHRcdFx0XHRcdHRtcC5jaGlsZHJlbi5wdXNoKGMpO1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYoZS5jaGlsZHJlbl9kLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0bXAuY2hpbGRyZW5fZCA9IHRtcC5jaGlsZHJlbl9kLmNvbmNhdChlLmNoaWxkcmVuX2QpO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR0bXAuY2hpbGRyZW5fZCA9IHRtcC5jaGlsZHJlbl9kLmNvbmNhdCh0bXAuY2hpbGRyZW4pO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGlmKGQgJiYgZC5jaGlsZHJlbiAmJiBkLmNoaWxkcmVuID09PSB0cnVlKSB7XG5cdFx0XHRcdFx0XHRcdFx0dG1wLnN0YXRlLmxvYWRlZCA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0XHRcdHRtcC5jaGlsZHJlbiA9IFtdO1xuXHRcdFx0XHRcdFx0XHRcdHRtcC5jaGlsZHJlbl9kID0gW107XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0ZGVsZXRlIGQuZGF0YTtcblx0XHRcdFx0XHRcdFx0ZGVsZXRlIGQuY2hpbGRyZW47XG5cdFx0XHRcdFx0XHRcdHRtcC5vcmlnaW5hbCA9IGQ7XG5cdFx0XHRcdFx0XHRcdG1bdG1wLmlkXSA9IHRtcDtcblx0XHRcdFx0XHRcdFx0aWYodG1wLnN0YXRlLnNlbGVjdGVkKSB7XG5cdFx0XHRcdFx0XHRcdFx0YWRkLnB1c2godG1wLmlkKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdG1wLmlkO1xuXHRcdFx0XHRcdFx0fTtcblxuXHRcdFx0XHRcdGlmKGRhdC5sZW5ndGggJiYgZGF0WzBdLmlkICE9PSB1bmRlZmluZWQgJiYgZGF0WzBdLnBhcmVudCAhPT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRcdFx0XHQvLyBGbGF0IEpTT04gc3VwcG9ydCAoZm9yIGVhc3kgaW1wb3J0IGZyb20gREIpOlxuXHRcdFx0XHRcdFx0Ly8gMSkgY29udmVydCB0byBvYmplY3QgKGZvcmVhY2gpXG5cdFx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSBkYXQubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdGlmKCFkYXRbaV0uY2hpbGRyZW4pIHtcblx0XHRcdFx0XHRcdFx0XHRkYXRbaV0uY2hpbGRyZW4gPSBbXTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRpZighZGF0W2ldLnN0YXRlKSB7XG5cdFx0XHRcdFx0XHRcdFx0ZGF0W2ldLnN0YXRlID0ge307XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0bVtkYXRbaV0uaWQudG9TdHJpbmcoKV0gPSBkYXRbaV07XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHQvLyAyKSBwb3B1bGF0ZSBjaGlsZHJlbiAoZm9yZWFjaClcblx0XHRcdFx0XHRcdGZvcihpID0gMCwgaiA9IGRhdC5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdFx0aWYgKCFtW2RhdFtpXS5wYXJlbnQudG9TdHJpbmcoKV0pIHtcblx0XHRcdFx0XHRcdFx0XHRpZiAodHlwZW9mIGluc3QgIT09IFwidW5kZWZpbmVkXCIpIHtcblx0XHRcdFx0XHRcdFx0XHRcdGluc3QuX2RhdGEuY29yZS5sYXN0X2Vycm9yID0geyAnZXJyb3InIDogJ3BhcnNlJywgJ3BsdWdpbicgOiAnY29yZScsICdpZCcgOiAnY29yZV8wNycsICdyZWFzb24nIDogJ05vZGUgd2l0aCBpbnZhbGlkIHBhcmVudCcsICdkYXRhJyA6IEpTT04uc3RyaW5naWZ5KHsgJ2lkJyA6IGRhdFtpXS5pZC50b1N0cmluZygpLCAncGFyZW50JyA6IGRhdFtpXS5wYXJlbnQudG9TdHJpbmcoKSB9KSB9O1xuXHRcdFx0XHRcdFx0XHRcdFx0aW5zdC5zZXR0aW5ncy5jb3JlLmVycm9yLmNhbGwoaW5zdCwgaW5zdC5fZGF0YS5jb3JlLmxhc3RfZXJyb3IpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdG1bZGF0W2ldLnBhcmVudC50b1N0cmluZygpXS5jaGlsZHJlbi5wdXNoKGRhdFtpXS5pZC50b1N0cmluZygpKTtcblx0XHRcdFx0XHRcdFx0Ly8gcG9wdWxhdGUgcGFyZW50LmNoaWxkcmVuX2Rcblx0XHRcdFx0XHRcdFx0cC5jaGlsZHJlbl9kLnB1c2goZGF0W2ldLmlkLnRvU3RyaW5nKCkpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0Ly8gMykgbm9ybWFsaXplICYmIHBvcHVsYXRlIHBhcmVudHMgYW5kIGNoaWxkcmVuX2Qgd2l0aCByZWN1cnNpb25cblx0XHRcdFx0XHRcdGZvcihpID0gMCwgaiA9IHAuY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdHRtcCA9IHBhcnNlX2ZsYXQobVtwLmNoaWxkcmVuW2ldXSwgcGFyLCBwLnBhcmVudHMuY29uY2F0KCkpO1xuXHRcdFx0XHRcdFx0XHRkcGMucHVzaCh0bXApO1xuXHRcdFx0XHRcdFx0XHRpZihtW3RtcF0uY2hpbGRyZW5fZC5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0XHRkcGMgPSBkcGMuY29uY2F0KG1bdG1wXS5jaGlsZHJlbl9kKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gcC5wYXJlbnRzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdFx0XHRtW3AucGFyZW50c1tpXV0uY2hpbGRyZW5fZCA9IG1bcC5wYXJlbnRzW2ldXS5jaGlsZHJlbl9kLmNvbmNhdChkcGMpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0Ly8gPykgdGhyZWVfc3RhdGUgc2VsZWN0aW9uIC0gcC5zdGF0ZS5zZWxlY3RlZCAmJiB0IC0gKGlmIHRocmVlX3N0YXRlIGZvcmVhY2goZGF0ID0+IGNoKSAtPiBmb3JlYWNoKHBhcmVudHMpIGlmKHBhcmVudC5zZWxlY3RlZCkgY2hpbGQuc2VsZWN0ZWQgPSB0cnVlO1xuXHRcdFx0XHRcdFx0cnNsdCA9IHtcblx0XHRcdFx0XHRcdFx0J2NudCcgOiB0X2NudCxcblx0XHRcdFx0XHRcdFx0J21vZCcgOiBtLFxuXHRcdFx0XHRcdFx0XHQnc2VsJyA6IHNlbCxcblx0XHRcdFx0XHRcdFx0J3BhcicgOiBwYXIsXG5cdFx0XHRcdFx0XHRcdCdkcGMnIDogZHBjLFxuXHRcdFx0XHRcdFx0XHQnYWRkJyA6IGFkZFxuXHRcdFx0XHRcdFx0fTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSBkYXQubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdHRtcCA9IHBhcnNlX25lc3QoZGF0W2ldLCBwYXIsIHAucGFyZW50cy5jb25jYXQoKSk7XG5cdFx0XHRcdFx0XHRcdGlmKHRtcCkge1xuXHRcdFx0XHRcdFx0XHRcdGNoZC5wdXNoKHRtcCk7XG5cdFx0XHRcdFx0XHRcdFx0ZHBjLnB1c2godG1wKTtcblx0XHRcdFx0XHRcdFx0XHRpZihtW3RtcF0uY2hpbGRyZW5fZC5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0XHRcdGRwYyA9IGRwYy5jb25jYXQobVt0bXBdLmNoaWxkcmVuX2QpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0cC5jaGlsZHJlbiA9IGNoZDtcblx0XHRcdFx0XHRcdHAuY2hpbGRyZW5fZCA9IGRwYztcblx0XHRcdFx0XHRcdGZvcihpID0gMCwgaiA9IHAucGFyZW50cy5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdFx0bVtwLnBhcmVudHNbaV1dLmNoaWxkcmVuX2QgPSBtW3AucGFyZW50c1tpXV0uY2hpbGRyZW5fZC5jb25jYXQoZHBjKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdHJzbHQgPSB7XG5cdFx0XHRcdFx0XHRcdCdjbnQnIDogdF9jbnQsXG5cdFx0XHRcdFx0XHRcdCdtb2QnIDogbSxcblx0XHRcdFx0XHRcdFx0J3NlbCcgOiBzZWwsXG5cdFx0XHRcdFx0XHRcdCdwYXInIDogcGFyLFxuXHRcdFx0XHRcdFx0XHQnZHBjJyA6IGRwYyxcblx0XHRcdFx0XHRcdFx0J2FkZCcgOiBhZGRcblx0XHRcdFx0XHRcdH07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmKHR5cGVvZiB3aW5kb3cgPT09ICd1bmRlZmluZWQnIHx8IHR5cGVvZiB3aW5kb3cuZG9jdW1lbnQgPT09ICd1bmRlZmluZWQnKSB7XG5cdFx0XHRcdFx0XHRwb3N0TWVzc2FnZShyc2x0KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gcnNsdDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0sXG5cdFx0XHRcdHJzbHQgPSBmdW5jdGlvbiAocnNsdCwgd29ya2VyKSB7XG5cdFx0XHRcdFx0aWYodGhpcy5lbGVtZW50ID09PSBudWxsKSB7IHJldHVybjsgfVxuXHRcdFx0XHRcdHRoaXMuX2NudCA9IHJzbHQuY250O1xuXHRcdFx0XHRcdHZhciBpLCBtID0gdGhpcy5fbW9kZWwuZGF0YTtcblx0XHRcdFx0XHRmb3IgKGkgaW4gbSkge1xuXHRcdFx0XHRcdFx0aWYgKG0uaGFzT3duUHJvcGVydHkoaSkgJiYgbVtpXS5zdGF0ZSAmJiBtW2ldLnN0YXRlLmxvYWRpbmcgJiYgcnNsdC5tb2RbaV0pIHtcblx0XHRcdFx0XHRcdFx0cnNsdC5tb2RbaV0uc3RhdGUubG9hZGluZyA9IHRydWU7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHRoaXMuX21vZGVsLmRhdGEgPSByc2x0Lm1vZDsgLy8gYnJlYWtzIHRoZSByZWZlcmVuY2UgaW4gbG9hZF9ub2RlIC0gY2FyZWZ1bFxuXG5cdFx0XHRcdFx0aWYod29ya2VyKSB7XG5cdFx0XHRcdFx0XHR2YXIgaiwgYSA9IHJzbHQuYWRkLCByID0gcnNsdC5zZWwsIHMgPSB0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQuc2xpY2UoKTtcblx0XHRcdFx0XHRcdG0gPSB0aGlzLl9tb2RlbC5kYXRhO1xuXHRcdFx0XHRcdFx0Ly8gaWYgc2VsZWN0aW9uIHdhcyBjaGFuZ2VkIHdoaWxlIGNhbGN1bGF0aW5nIGluIHdvcmtlclxuXHRcdFx0XHRcdFx0aWYoci5sZW5ndGggIT09IHMubGVuZ3RoIHx8ICQudmFrYXRhLmFycmF5X3VuaXF1ZShyLmNvbmNhdChzKSkubGVuZ3RoICE9PSByLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHQvLyBkZXNlbGVjdCBub2RlcyB0aGF0IGFyZSBubyBsb25nZXIgc2VsZWN0ZWRcblx0XHRcdFx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gci5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdFx0XHRpZigkLmluQXJyYXkocltpXSwgYSkgPT09IC0xICYmICQuaW5BcnJheShyW2ldLCBzKSA9PT0gLTEpIHtcblx0XHRcdFx0XHRcdFx0XHRcdG1bcltpXV0uc3RhdGUuc2VsZWN0ZWQgPSBmYWxzZTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0Ly8gc2VsZWN0IG5vZGVzIHRoYXQgd2VyZSBzZWxlY3RlZCBpbiB0aGUgbWVhbiB0aW1lXG5cdFx0XHRcdFx0XHRcdGZvcihpID0gMCwgaiA9IHMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdFx0aWYoJC5pbkFycmF5KHNbaV0sIHIpID09PSAtMSkge1xuXHRcdFx0XHRcdFx0XHRcdFx0bVtzW2ldXS5zdGF0ZS5zZWxlY3RlZCA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmKHJzbHQuYWRkLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkID0gdGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkLmNvbmNhdChyc2x0LmFkZCk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0dGhpcy50cmlnZ2VyKCdtb2RlbCcsIHsgXCJub2Rlc1wiIDogcnNsdC5kcGMsICdwYXJlbnQnIDogcnNsdC5wYXIgfSk7XG5cblx0XHRcdFx0XHRpZihyc2x0LnBhciAhPT0gJC5qc3RyZWUucm9vdCkge1xuXHRcdFx0XHRcdFx0dGhpcy5fbm9kZV9jaGFuZ2VkKHJzbHQucGFyKTtcblx0XHRcdFx0XHRcdHRoaXMucmVkcmF3KCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0Ly8gdGhpcy5nZXRfY29udGFpbmVyX3VsKCkuY2hpbGRyZW4oJy5qc3RyZWUtaW5pdGlhbC1ub2RlJykucmVtb3ZlKCk7XG5cdFx0XHRcdFx0XHR0aGlzLnJlZHJhdyh0cnVlKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYocnNsdC5hZGQubGVuZ3RoKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnRyaWdnZXIoJ2NoYW5nZWQnLCB7ICdhY3Rpb24nIDogJ21vZGVsJywgJ3NlbGVjdGVkJyA6IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZCB9KTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBJZiBubyB3b3JrZXIsIHRyeSB0byBtaW1pYyB3b3JrZXIgYmVoYXZpb291ciwgYnkgaW52b2tpbmcgY2IgYXN5bmNocm9ub3VzbHlcblx0XHRcdFx0XHRpZiAoIXdvcmtlciAmJiBzZXRJbW1lZGlhdGUpIHtcblx0XHRcdFx0XHRcdHNldEltbWVkaWF0ZShmdW5jdGlvbigpe1xuXHRcdFx0XHRcdFx0XHRjYi5jYWxsKGluc3QsIHRydWUpO1xuXHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0Y2IuY2FsbChpbnN0LCB0cnVlKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH07XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLmNvcmUud29ya2VyICYmIHdpbmRvdy5CbG9iICYmIHdpbmRvdy5VUkwgJiYgd2luZG93Lldvcmtlcikge1xuXHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdGlmKHRoaXMuX3dyayA9PT0gbnVsbCkge1xuXHRcdFx0XHRcdFx0dGhpcy5fd3JrID0gd2luZG93LlVSTC5jcmVhdGVPYmplY3RVUkwoXG5cdFx0XHRcdFx0XHRcdG5ldyB3aW5kb3cuQmxvYihcblx0XHRcdFx0XHRcdFx0XHRbJ3NlbGYub25tZXNzYWdlID0gJyArIGZ1bmMudG9TdHJpbmcoKV0sXG5cdFx0XHRcdFx0XHRcdFx0e3R5cGU6XCJ0ZXh0L2phdmFzY3JpcHRcIn1cblx0XHRcdFx0XHRcdFx0KVxuXHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYoIXRoaXMuX2RhdGEuY29yZS53b3JraW5nIHx8IGZvcmNlX3Byb2Nlc3NpbmcpIHtcblx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS53b3JraW5nID0gdHJ1ZTtcblx0XHRcdFx0XHRcdHcgPSBuZXcgd2luZG93Lldvcmtlcih0aGlzLl93cmspO1xuXHRcdFx0XHRcdFx0dy5vbm1lc3NhZ2UgPSBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0XHRyc2x0LmNhbGwodGhpcywgZS5kYXRhLCB0cnVlKTtcblx0XHRcdFx0XHRcdFx0dHJ5IHsgdy50ZXJtaW5hdGUoKTsgdyA9IG51bGw7IH0gY2F0Y2goaWdub3JlKSB7IH1cblx0XHRcdFx0XHRcdFx0aWYodGhpcy5fZGF0YS5jb3JlLndvcmtlcl9xdWV1ZS5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0XHR0aGlzLl9hcHBlbmRfanNvbl9kYXRhLmFwcGx5KHRoaXMsIHRoaXMuX2RhdGEuY29yZS53b3JrZXJfcXVldWUuc2hpZnQoKSk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLndvcmtpbmcgPSBmYWxzZTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fS5iaW5kKHRoaXMpO1xuXHRcdFx0XHRcdFx0aWYoIWFyZ3MucGFyKSB7XG5cdFx0XHRcdFx0XHRcdGlmKHRoaXMuX2RhdGEuY29yZS53b3JrZXJfcXVldWUubGVuZ3RoKSB7XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5fYXBwZW5kX2pzb25fZGF0YS5hcHBseSh0aGlzLCB0aGlzLl9kYXRhLmNvcmUud29ya2VyX3F1ZXVlLnNoaWZ0KCkpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS53b3JraW5nID0gZmFsc2U7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHR3LnBvc3RNZXNzYWdlKGFyZ3MpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS53b3JrZXJfcXVldWUucHVzaChbZG9tLCBkYXRhLCBjYiwgdHJ1ZV0pO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRjYXRjaChlKSB7XG5cdFx0XHRcdFx0cnNsdC5jYWxsKHRoaXMsIGZ1bmMoYXJncyksIGZhbHNlKTtcblx0XHRcdFx0XHRpZih0aGlzLl9kYXRhLmNvcmUud29ya2VyX3F1ZXVlLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0dGhpcy5fYXBwZW5kX2pzb25fZGF0YS5hcHBseSh0aGlzLCB0aGlzLl9kYXRhLmNvcmUud29ya2VyX3F1ZXVlLnNoaWZ0KCkpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS53b3JraW5nID0gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0cnNsdC5jYWxsKHRoaXMsIGZ1bmMoYXJncyksIGZhbHNlKTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIHBhcnNlcyBhIG5vZGUgZnJvbSBhIGpRdWVyeSBvYmplY3QgYW5kIGFwcGVuZHMgdGhlbSB0byB0aGUgaW4gbWVtb3J5IHRyZWUgbW9kZWwuIFVzZWQgaW50ZXJuYWxseS5cblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEBuYW1lIF9wYXJzZV9tb2RlbF9mcm9tX2h0bWwoZCBbLCBwLCBwc10pXG5cdFx0ICogQHBhcmFtICB7alF1ZXJ5fSBkIHRoZSBqUXVlcnkgb2JqZWN0IHRvIHBhcnNlXG5cdFx0ICogQHBhcmFtICB7U3RyaW5nfSBwIHRoZSBwYXJlbnQgSURcblx0XHQgKiBAcGFyYW0gIHtBcnJheX0gcHMgbGlzdCBvZiBhbGwgcGFyZW50c1xuXHRcdCAqIEByZXR1cm4ge1N0cmluZ30gdGhlIElEIG9mIHRoZSBvYmplY3QgYWRkZWQgdG8gdGhlIG1vZGVsXG5cdFx0ICovXG5cdFx0X3BhcnNlX21vZGVsX2Zyb21faHRtbCA6IGZ1bmN0aW9uIChkLCBwLCBwcykge1xuXHRcdFx0aWYoIXBzKSB7IHBzID0gW107IH1cblx0XHRcdGVsc2UgeyBwcyA9IFtdLmNvbmNhdChwcyk7IH1cblx0XHRcdGlmKHApIHsgcHMudW5zaGlmdChwKTsgfVxuXHRcdFx0dmFyIGMsIGUsIG0gPSB0aGlzLl9tb2RlbC5kYXRhLFxuXHRcdFx0XHRkYXRhID0ge1xuXHRcdFx0XHRcdGlkXHRcdFx0OiBmYWxzZSxcblx0XHRcdFx0XHR0ZXh0XHRcdDogZmFsc2UsXG5cdFx0XHRcdFx0aWNvblx0XHQ6IHRydWUsXG5cdFx0XHRcdFx0cGFyZW50XHRcdDogcCxcblx0XHRcdFx0XHRwYXJlbnRzXHRcdDogcHMsXG5cdFx0XHRcdFx0Y2hpbGRyZW5cdDogW10sXG5cdFx0XHRcdFx0Y2hpbGRyZW5fZFx0OiBbXSxcblx0XHRcdFx0XHRkYXRhXHRcdDogbnVsbCxcblx0XHRcdFx0XHRzdGF0ZVx0XHQ6IHsgfSxcblx0XHRcdFx0XHRsaV9hdHRyXHRcdDogeyBpZCA6IGZhbHNlIH0sXG5cdFx0XHRcdFx0YV9hdHRyXHRcdDogeyBocmVmIDogJyMnIH0sXG5cdFx0XHRcdFx0b3JpZ2luYWxcdDogZmFsc2Vcblx0XHRcdFx0fSwgaSwgdG1wLCB0aWQ7XG5cdFx0XHRmb3IoaSBpbiB0aGlzLl9tb2RlbC5kZWZhdWx0X3N0YXRlKSB7XG5cdFx0XHRcdGlmKHRoaXMuX21vZGVsLmRlZmF1bHRfc3RhdGUuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHRkYXRhLnN0YXRlW2ldID0gdGhpcy5fbW9kZWwuZGVmYXVsdF9zdGF0ZVtpXTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0dG1wID0gJC52YWthdGEuYXR0cmlidXRlcyhkLCB0cnVlKTtcblx0XHRcdCQuZWFjaCh0bXAsIGZ1bmN0aW9uIChpLCB2KSB7XG5cdFx0XHRcdHYgPSAkLnZha2F0YS50cmltKHYpO1xuXHRcdFx0XHRpZighdi5sZW5ndGgpIHsgcmV0dXJuIHRydWU7IH1cblx0XHRcdFx0ZGF0YS5saV9hdHRyW2ldID0gdjtcblx0XHRcdFx0aWYoaSA9PT0gJ2lkJykge1xuXHRcdFx0XHRcdGRhdGEuaWQgPSB2LnRvU3RyaW5nKCk7XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdFx0dG1wID0gZC5jaGlsZHJlbignYScpLmZpcnN0KCk7XG5cdFx0XHRpZih0bXAubGVuZ3RoKSB7XG5cdFx0XHRcdHRtcCA9ICQudmFrYXRhLmF0dHJpYnV0ZXModG1wLCB0cnVlKTtcblx0XHRcdFx0JC5lYWNoKHRtcCwgZnVuY3Rpb24gKGksIHYpIHtcblx0XHRcdFx0XHR2ID0gJC52YWthdGEudHJpbSh2KTtcblx0XHRcdFx0XHRpZih2Lmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0ZGF0YS5hX2F0dHJbaV0gPSB2O1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSk7XG5cdFx0XHR9XG5cdFx0XHR0bXAgPSBkLmNoaWxkcmVuKFwiYVwiKS5maXJzdCgpLmxlbmd0aCA/IGQuY2hpbGRyZW4oXCJhXCIpLmZpcnN0KCkuY2xvbmUoKSA6IGQuY2xvbmUoKTtcblx0XHRcdHRtcC5jaGlsZHJlbihcImlucywgaSwgdWxcIikucmVtb3ZlKCk7XG5cdFx0XHR0bXAgPSB0bXAuaHRtbCgpO1xuXHRcdFx0dG1wID0gJCgnPGRpdj48L2Rpdj4nKS5odG1sKHRtcCk7XG5cdFx0XHRkYXRhLnRleHQgPSB0aGlzLnNldHRpbmdzLmNvcmUuZm9yY2VfdGV4dCA/IHRtcC50ZXh0KCkgOiB0bXAuaHRtbCgpO1xuXHRcdFx0dG1wID0gZC5kYXRhKCk7XG5cdFx0XHRkYXRhLmRhdGEgPSB0bXAgPyAkLmV4dGVuZCh0cnVlLCB7fSwgdG1wKSA6IG51bGw7XG5cdFx0XHRkYXRhLnN0YXRlLm9wZW5lZCA9IGQuaGFzQ2xhc3MoJ2pzdHJlZS1vcGVuJyk7XG5cdFx0XHRkYXRhLnN0YXRlLnNlbGVjdGVkID0gZC5jaGlsZHJlbignYScpLmhhc0NsYXNzKCdqc3RyZWUtY2xpY2tlZCcpO1xuXHRcdFx0ZGF0YS5zdGF0ZS5kaXNhYmxlZCA9IGQuY2hpbGRyZW4oJ2EnKS5oYXNDbGFzcygnanN0cmVlLWRpc2FibGVkJyk7XG5cdFx0XHRpZihkYXRhLmRhdGEgJiYgZGF0YS5kYXRhLmpzdHJlZSkge1xuXHRcdFx0XHRmb3IoaSBpbiBkYXRhLmRhdGEuanN0cmVlKSB7XG5cdFx0XHRcdFx0aWYoZGF0YS5kYXRhLmpzdHJlZS5oYXNPd25Qcm9wZXJ0eShpKSkge1xuXHRcdFx0XHRcdFx0ZGF0YS5zdGF0ZVtpXSA9IGRhdGEuZGF0YS5qc3RyZWVbaV07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHR0bXAgPSBkLmNoaWxkcmVuKFwiYVwiKS5jaGlsZHJlbihcIi5qc3RyZWUtdGhlbWVpY29uXCIpO1xuXHRcdFx0aWYodG1wLmxlbmd0aCkge1xuXHRcdFx0XHRkYXRhLmljb24gPSB0bXAuaGFzQ2xhc3MoJ2pzdHJlZS10aGVtZWljb24taGlkZGVuJykgPyBmYWxzZSA6IHRtcC5hdHRyKCdyZWwnKTtcblx0XHRcdH1cblx0XHRcdGlmKGRhdGEuc3RhdGUuaWNvbiAhPT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRcdGRhdGEuaWNvbiA9IGRhdGEuc3RhdGUuaWNvbjtcblx0XHRcdH1cblx0XHRcdGlmKGRhdGEuaWNvbiA9PT0gdW5kZWZpbmVkIHx8IGRhdGEuaWNvbiA9PT0gbnVsbCB8fCBkYXRhLmljb24gPT09IFwiXCIpIHtcblx0XHRcdFx0ZGF0YS5pY29uID0gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdHRtcCA9IGQuY2hpbGRyZW4oXCJ1bFwiKS5jaGlsZHJlbihcImxpXCIpO1xuXHRcdFx0ZG8ge1xuXHRcdFx0XHR0aWQgPSAnaicgKyB0aGlzLl9pZCArICdfJyArICgrK3RoaXMuX2NudCk7XG5cdFx0XHR9IHdoaWxlKG1bdGlkXSk7XG5cdFx0XHRkYXRhLmlkID0gZGF0YS5saV9hdHRyLmlkID8gZGF0YS5saV9hdHRyLmlkLnRvU3RyaW5nKCkgOiB0aWQ7XG5cdFx0XHRpZih0bXAubGVuZ3RoKSB7XG5cdFx0XHRcdHRtcC5lYWNoKGZ1bmN0aW9uIChpLCB2KSB7XG5cdFx0XHRcdFx0YyA9IHRoaXMuX3BhcnNlX21vZGVsX2Zyb21faHRtbCgkKHYpLCBkYXRhLmlkLCBwcyk7XG5cdFx0XHRcdFx0ZSA9IHRoaXMuX21vZGVsLmRhdGFbY107XG5cdFx0XHRcdFx0ZGF0YS5jaGlsZHJlbi5wdXNoKGMpO1xuXHRcdFx0XHRcdGlmKGUuY2hpbGRyZW5fZC5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdGRhdGEuY2hpbGRyZW5fZCA9IGRhdGEuY2hpbGRyZW5fZC5jb25jYXQoZS5jaGlsZHJlbl9kKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0uYmluZCh0aGlzKSk7XG5cdFx0XHRcdGRhdGEuY2hpbGRyZW5fZCA9IGRhdGEuY2hpbGRyZW5fZC5jb25jYXQoZGF0YS5jaGlsZHJlbik7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0aWYoZC5oYXNDbGFzcygnanN0cmVlLWNsb3NlZCcpKSB7XG5cdFx0XHRcdFx0ZGF0YS5zdGF0ZS5sb2FkZWQgPSBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0aWYoZGF0YS5saV9hdHRyWydjbGFzcyddKSB7XG5cdFx0XHRcdGRhdGEubGlfYXR0clsnY2xhc3MnXSA9IGRhdGEubGlfYXR0clsnY2xhc3MnXS5yZXBsYWNlKCdqc3RyZWUtY2xvc2VkJywnJykucmVwbGFjZSgnanN0cmVlLW9wZW4nLCcnKTtcblx0XHRcdH1cblx0XHRcdGlmKGRhdGEuYV9hdHRyWydjbGFzcyddKSB7XG5cdFx0XHRcdGRhdGEuYV9hdHRyWydjbGFzcyddID0gZGF0YS5hX2F0dHJbJ2NsYXNzJ10ucmVwbGFjZSgnanN0cmVlLWNsaWNrZWQnLCcnKS5yZXBsYWNlKCdqc3RyZWUtZGlzYWJsZWQnLCcnKTtcblx0XHRcdH1cblx0XHRcdG1bZGF0YS5pZF0gPSBkYXRhO1xuXHRcdFx0aWYoZGF0YS5zdGF0ZS5zZWxlY3RlZCkge1xuXHRcdFx0XHR0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQucHVzaChkYXRhLmlkKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBkYXRhLmlkO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogcGFyc2VzIGEgbm9kZSBmcm9tIGEgSlNPTiBvYmplY3QgKHVzZWQgd2hlbiBkZWFsaW5nIHdpdGggZmxhdCBkYXRhLCB3aGljaCBoYXMgbm8gbmVzdGluZyBvZiBjaGlsZHJlbiwgYnV0IGhhcyBpZCBhbmQgcGFyZW50IHByb3BlcnRpZXMpIGFuZCBhcHBlbmRzIGl0IHRvIHRoZSBpbiBtZW1vcnkgdHJlZSBtb2RlbC4gVXNlZCBpbnRlcm5hbGx5LlxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICogQG5hbWUgX3BhcnNlX21vZGVsX2Zyb21fZmxhdF9qc29uKGQgWywgcCwgcHNdKVxuXHRcdCAqIEBwYXJhbSAge09iamVjdH0gZCB0aGUgSlNPTiBvYmplY3QgdG8gcGFyc2Vcblx0XHQgKiBAcGFyYW0gIHtTdHJpbmd9IHAgdGhlIHBhcmVudCBJRFxuXHRcdCAqIEBwYXJhbSAge0FycmF5fSBwcyBsaXN0IG9mIGFsbCBwYXJlbnRzXG5cdFx0ICogQHJldHVybiB7U3RyaW5nfSB0aGUgSUQgb2YgdGhlIG9iamVjdCBhZGRlZCB0byB0aGUgbW9kZWxcblx0XHQgKi9cblx0XHRfcGFyc2VfbW9kZWxfZnJvbV9mbGF0X2pzb24gOiBmdW5jdGlvbiAoZCwgcCwgcHMpIHtcblx0XHRcdGlmKCFwcykgeyBwcyA9IFtdOyB9XG5cdFx0XHRlbHNlIHsgcHMgPSBwcy5jb25jYXQoKTsgfVxuXHRcdFx0aWYocCkgeyBwcy51bnNoaWZ0KHApOyB9XG5cdFx0XHR2YXIgdGlkID0gZC5pZC50b1N0cmluZygpLFxuXHRcdFx0XHRtID0gdGhpcy5fbW9kZWwuZGF0YSxcblx0XHRcdFx0ZGYgPSB0aGlzLl9tb2RlbC5kZWZhdWx0X3N0YXRlLFxuXHRcdFx0XHRpLCBqLCBjLCBlLFxuXHRcdFx0XHR0bXAgPSB7XG5cdFx0XHRcdFx0aWRcdFx0XHQ6IHRpZCxcblx0XHRcdFx0XHR0ZXh0XHRcdDogZC50ZXh0IHx8ICcnLFxuXHRcdFx0XHRcdGljb25cdFx0OiBkLmljb24gIT09IHVuZGVmaW5lZCA/IGQuaWNvbiA6IHRydWUsXG5cdFx0XHRcdFx0cGFyZW50XHRcdDogcCxcblx0XHRcdFx0XHRwYXJlbnRzXHRcdDogcHMsXG5cdFx0XHRcdFx0Y2hpbGRyZW5cdDogZC5jaGlsZHJlbiB8fCBbXSxcblx0XHRcdFx0XHRjaGlsZHJlbl9kXHQ6IGQuY2hpbGRyZW5fZCB8fCBbXSxcblx0XHRcdFx0XHRkYXRhXHRcdDogZC5kYXRhLFxuXHRcdFx0XHRcdHN0YXRlXHRcdDogeyB9LFxuXHRcdFx0XHRcdGxpX2F0dHJcdFx0OiB7IGlkIDogZmFsc2UgfSxcblx0XHRcdFx0XHRhX2F0dHJcdFx0OiB7IGhyZWYgOiAnIycgfSxcblx0XHRcdFx0XHRvcmlnaW5hbFx0OiBmYWxzZVxuXHRcdFx0XHR9O1xuXHRcdFx0Zm9yKGkgaW4gZGYpIHtcblx0XHRcdFx0aWYoZGYuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHR0bXAuc3RhdGVbaV0gPSBkZltpXTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0aWYoZCAmJiBkLmRhdGEgJiYgZC5kYXRhLmpzdHJlZSAmJiBkLmRhdGEuanN0cmVlLmljb24pIHtcblx0XHRcdFx0dG1wLmljb24gPSBkLmRhdGEuanN0cmVlLmljb247XG5cdFx0XHR9XG5cdFx0XHRpZih0bXAuaWNvbiA9PT0gdW5kZWZpbmVkIHx8IHRtcC5pY29uID09PSBudWxsIHx8IHRtcC5pY29uID09PSBcIlwiKSB7XG5cdFx0XHRcdHRtcC5pY29uID0gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdGlmKGQgJiYgZC5kYXRhKSB7XG5cdFx0XHRcdHRtcC5kYXRhID0gZC5kYXRhO1xuXHRcdFx0XHRpZihkLmRhdGEuanN0cmVlKSB7XG5cdFx0XHRcdFx0Zm9yKGkgaW4gZC5kYXRhLmpzdHJlZSkge1xuXHRcdFx0XHRcdFx0aWYoZC5kYXRhLmpzdHJlZS5oYXNPd25Qcm9wZXJ0eShpKSkge1xuXHRcdFx0XHRcdFx0XHR0bXAuc3RhdGVbaV0gPSBkLmRhdGEuanN0cmVlW2ldO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0aWYoZCAmJiB0eXBlb2YgZC5zdGF0ZSA9PT0gJ29iamVjdCcpIHtcblx0XHRcdFx0Zm9yIChpIGluIGQuc3RhdGUpIHtcblx0XHRcdFx0XHRpZihkLnN0YXRlLmhhc093blByb3BlcnR5KGkpKSB7XG5cdFx0XHRcdFx0XHR0bXAuc3RhdGVbaV0gPSBkLnN0YXRlW2ldO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0aWYoZCAmJiB0eXBlb2YgZC5saV9hdHRyID09PSAnb2JqZWN0Jykge1xuXHRcdFx0XHRmb3IgKGkgaW4gZC5saV9hdHRyKSB7XG5cdFx0XHRcdFx0aWYoZC5saV9hdHRyLmhhc093blByb3BlcnR5KGkpKSB7XG5cdFx0XHRcdFx0XHR0bXAubGlfYXR0cltpXSA9IGQubGlfYXR0cltpXTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmKCF0bXAubGlfYXR0ci5pZCkge1xuXHRcdFx0XHR0bXAubGlfYXR0ci5pZCA9IHRpZDtcblx0XHRcdH1cblx0XHRcdGlmKGQgJiYgdHlwZW9mIGQuYV9hdHRyID09PSAnb2JqZWN0Jykge1xuXHRcdFx0XHRmb3IgKGkgaW4gZC5hX2F0dHIpIHtcblx0XHRcdFx0XHRpZihkLmFfYXR0ci5oYXNPd25Qcm9wZXJ0eShpKSkge1xuXHRcdFx0XHRcdFx0dG1wLmFfYXR0cltpXSA9IGQuYV9hdHRyW2ldO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0aWYoZCAmJiBkLmNoaWxkcmVuICYmIGQuY2hpbGRyZW4gPT09IHRydWUpIHtcblx0XHRcdFx0dG1wLnN0YXRlLmxvYWRlZCA9IGZhbHNlO1xuXHRcdFx0XHR0bXAuY2hpbGRyZW4gPSBbXTtcblx0XHRcdFx0dG1wLmNoaWxkcmVuX2QgPSBbXTtcblx0XHRcdH1cblx0XHRcdG1bdG1wLmlkXSA9IHRtcDtcblx0XHRcdGZvcihpID0gMCwgaiA9IHRtcC5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0YyA9IHRoaXMuX3BhcnNlX21vZGVsX2Zyb21fZmxhdF9qc29uKG1bdG1wLmNoaWxkcmVuW2ldXSwgdG1wLmlkLCBwcyk7XG5cdFx0XHRcdGUgPSBtW2NdO1xuXHRcdFx0XHR0bXAuY2hpbGRyZW5fZC5wdXNoKGMpO1xuXHRcdFx0XHRpZihlLmNoaWxkcmVuX2QubGVuZ3RoKSB7XG5cdFx0XHRcdFx0dG1wLmNoaWxkcmVuX2QgPSB0bXAuY2hpbGRyZW5fZC5jb25jYXQoZS5jaGlsZHJlbl9kKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0ZGVsZXRlIGQuZGF0YTtcblx0XHRcdGRlbGV0ZSBkLmNoaWxkcmVuO1xuXHRcdFx0bVt0bXAuaWRdLm9yaWdpbmFsID0gZDtcblx0XHRcdGlmKHRtcC5zdGF0ZS5zZWxlY3RlZCkge1xuXHRcdFx0XHR0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQucHVzaCh0bXAuaWQpO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRtcC5pZDtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIHBhcnNlcyBhIG5vZGUgZnJvbSBhIEpTT04gb2JqZWN0IGFuZCBhcHBlbmRzIGl0IHRvIHRoZSBpbiBtZW1vcnkgdHJlZSBtb2RlbC4gVXNlZCBpbnRlcm5hbGx5LlxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICogQG5hbWUgX3BhcnNlX21vZGVsX2Zyb21fanNvbihkIFssIHAsIHBzXSlcblx0XHQgKiBAcGFyYW0gIHtPYmplY3R9IGQgdGhlIEpTT04gb2JqZWN0IHRvIHBhcnNlXG5cdFx0ICogQHBhcmFtICB7U3RyaW5nfSBwIHRoZSBwYXJlbnQgSURcblx0XHQgKiBAcGFyYW0gIHtBcnJheX0gcHMgbGlzdCBvZiBhbGwgcGFyZW50c1xuXHRcdCAqIEByZXR1cm4ge1N0cmluZ30gdGhlIElEIG9mIHRoZSBvYmplY3QgYWRkZWQgdG8gdGhlIG1vZGVsXG5cdFx0ICovXG5cdFx0X3BhcnNlX21vZGVsX2Zyb21fanNvbiA6IGZ1bmN0aW9uIChkLCBwLCBwcykge1xuXHRcdFx0aWYoIXBzKSB7IHBzID0gW107IH1cblx0XHRcdGVsc2UgeyBwcyA9IHBzLmNvbmNhdCgpOyB9XG5cdFx0XHRpZihwKSB7IHBzLnVuc2hpZnQocCk7IH1cblx0XHRcdHZhciB0aWQgPSBmYWxzZSwgaSwgaiwgYywgZSwgbSA9IHRoaXMuX21vZGVsLmRhdGEsIGRmID0gdGhpcy5fbW9kZWwuZGVmYXVsdF9zdGF0ZSwgdG1wO1xuXHRcdFx0ZG8ge1xuXHRcdFx0XHR0aWQgPSAnaicgKyB0aGlzLl9pZCArICdfJyArICgrK3RoaXMuX2NudCk7XG5cdFx0XHR9IHdoaWxlKG1bdGlkXSk7XG5cblx0XHRcdHRtcCA9IHtcblx0XHRcdFx0aWRcdFx0XHQ6IGZhbHNlLFxuXHRcdFx0XHR0ZXh0XHRcdDogdHlwZW9mIGQgPT09ICdzdHJpbmcnID8gZCA6ICcnLFxuXHRcdFx0XHRpY29uXHRcdDogdHlwZW9mIGQgPT09ICdvYmplY3QnICYmIGQuaWNvbiAhPT0gdW5kZWZpbmVkID8gZC5pY29uIDogdHJ1ZSxcblx0XHRcdFx0cGFyZW50XHRcdDogcCxcblx0XHRcdFx0cGFyZW50c1x0XHQ6IHBzLFxuXHRcdFx0XHRjaGlsZHJlblx0OiBbXSxcblx0XHRcdFx0Y2hpbGRyZW5fZFx0OiBbXSxcblx0XHRcdFx0ZGF0YVx0XHQ6IG51bGwsXG5cdFx0XHRcdHN0YXRlXHRcdDogeyB9LFxuXHRcdFx0XHRsaV9hdHRyXHRcdDogeyBpZCA6IGZhbHNlIH0sXG5cdFx0XHRcdGFfYXR0clx0XHQ6IHsgaHJlZiA6ICcjJyB9LFxuXHRcdFx0XHRvcmlnaW5hbFx0OiBmYWxzZVxuXHRcdFx0fTtcblx0XHRcdGZvcihpIGluIGRmKSB7XG5cdFx0XHRcdGlmKGRmLmhhc093blByb3BlcnR5KGkpKSB7XG5cdFx0XHRcdFx0dG1wLnN0YXRlW2ldID0gZGZbaV07XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmKGQgJiYgZC5pZCkgeyB0bXAuaWQgPSBkLmlkLnRvU3RyaW5nKCk7IH1cblx0XHRcdGlmKGQgJiYgZC50ZXh0KSB7IHRtcC50ZXh0ID0gZC50ZXh0OyB9XG5cdFx0XHRpZihkICYmIGQuZGF0YSAmJiBkLmRhdGEuanN0cmVlICYmIGQuZGF0YS5qc3RyZWUuaWNvbikge1xuXHRcdFx0XHR0bXAuaWNvbiA9IGQuZGF0YS5qc3RyZWUuaWNvbjtcblx0XHRcdH1cblx0XHRcdGlmKHRtcC5pY29uID09PSB1bmRlZmluZWQgfHwgdG1wLmljb24gPT09IG51bGwgfHwgdG1wLmljb24gPT09IFwiXCIpIHtcblx0XHRcdFx0dG1wLmljb24gPSB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0aWYoZCAmJiBkLmRhdGEpIHtcblx0XHRcdFx0dG1wLmRhdGEgPSBkLmRhdGE7XG5cdFx0XHRcdGlmKGQuZGF0YS5qc3RyZWUpIHtcblx0XHRcdFx0XHRmb3IoaSBpbiBkLmRhdGEuanN0cmVlKSB7XG5cdFx0XHRcdFx0XHRpZihkLmRhdGEuanN0cmVlLmhhc093blByb3BlcnR5KGkpKSB7XG5cdFx0XHRcdFx0XHRcdHRtcC5zdGF0ZVtpXSA9IGQuZGF0YS5qc3RyZWVbaV07XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRpZihkICYmIHR5cGVvZiBkLnN0YXRlID09PSAnb2JqZWN0Jykge1xuXHRcdFx0XHRmb3IgKGkgaW4gZC5zdGF0ZSkge1xuXHRcdFx0XHRcdGlmKGQuc3RhdGUuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHRcdHRtcC5zdGF0ZVtpXSA9IGQuc3RhdGVbaV07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRpZihkICYmIHR5cGVvZiBkLmxpX2F0dHIgPT09ICdvYmplY3QnKSB7XG5cdFx0XHRcdGZvciAoaSBpbiBkLmxpX2F0dHIpIHtcblx0XHRcdFx0XHRpZihkLmxpX2F0dHIuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHRcdHRtcC5saV9hdHRyW2ldID0gZC5saV9hdHRyW2ldO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0aWYodG1wLmxpX2F0dHIuaWQgJiYgIXRtcC5pZCkge1xuXHRcdFx0XHR0bXAuaWQgPSB0bXAubGlfYXR0ci5pZC50b1N0cmluZygpO1xuXHRcdFx0fVxuXHRcdFx0aWYoIXRtcC5pZCkge1xuXHRcdFx0XHR0bXAuaWQgPSB0aWQ7XG5cdFx0XHR9XG5cdFx0XHRpZighdG1wLmxpX2F0dHIuaWQpIHtcblx0XHRcdFx0dG1wLmxpX2F0dHIuaWQgPSB0bXAuaWQ7XG5cdFx0XHR9XG5cdFx0XHRpZihkICYmIHR5cGVvZiBkLmFfYXR0ciA9PT0gJ29iamVjdCcpIHtcblx0XHRcdFx0Zm9yIChpIGluIGQuYV9hdHRyKSB7XG5cdFx0XHRcdFx0aWYoZC5hX2F0dHIuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHRcdHRtcC5hX2F0dHJbaV0gPSBkLmFfYXR0cltpXTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmKGQgJiYgZC5jaGlsZHJlbiAmJiBkLmNoaWxkcmVuLmxlbmd0aCkge1xuXHRcdFx0XHRmb3IoaSA9IDAsIGogPSBkLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdGMgPSB0aGlzLl9wYXJzZV9tb2RlbF9mcm9tX2pzb24oZC5jaGlsZHJlbltpXSwgdG1wLmlkLCBwcyk7XG5cdFx0XHRcdFx0ZSA9IG1bY107XG5cdFx0XHRcdFx0dG1wLmNoaWxkcmVuLnB1c2goYyk7XG5cdFx0XHRcdFx0aWYoZS5jaGlsZHJlbl9kLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0dG1wLmNoaWxkcmVuX2QgPSB0bXAuY2hpbGRyZW5fZC5jb25jYXQoZS5jaGlsZHJlbl9kKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0dG1wLmNoaWxkcmVuX2QgPSB0bXAuY2hpbGRyZW4uY29uY2F0KHRtcC5jaGlsZHJlbl9kKTtcblx0XHRcdH1cblx0XHRcdGlmKGQgJiYgZC5jaGlsZHJlbiAmJiBkLmNoaWxkcmVuID09PSB0cnVlKSB7XG5cdFx0XHRcdHRtcC5zdGF0ZS5sb2FkZWQgPSBmYWxzZTtcblx0XHRcdFx0dG1wLmNoaWxkcmVuID0gW107XG5cdFx0XHRcdHRtcC5jaGlsZHJlbl9kID0gW107XG5cdFx0XHR9XG5cdFx0XHRkZWxldGUgZC5kYXRhO1xuXHRcdFx0ZGVsZXRlIGQuY2hpbGRyZW47XG5cdFx0XHR0bXAub3JpZ2luYWwgPSBkO1xuXHRcdFx0bVt0bXAuaWRdID0gdG1wO1xuXHRcdFx0aWYodG1wLnN0YXRlLnNlbGVjdGVkKSB7XG5cdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZC5wdXNoKHRtcC5pZCk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdG1wLmlkO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogcmVkcmF3cyBhbGwgbm9kZXMgdGhhdCBuZWVkIHRvIGJlIHJlZHJhd24uIFVzZWQgaW50ZXJuYWxseS5cblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEBuYW1lIF9yZWRyYXcoKVxuXHRcdCAqIEB0cmlnZ2VyIHJlZHJhdy5qc3RyZWVcblx0XHQgKi9cblx0XHRfcmVkcmF3IDogZnVuY3Rpb24gKCkge1xuXHRcdFx0dmFyIG5vZGVzID0gdGhpcy5fbW9kZWwuZm9yY2VfZnVsbF9yZWRyYXcgPyB0aGlzLl9tb2RlbC5kYXRhWyQuanN0cmVlLnJvb3RdLmNoaWxkcmVuLmNvbmNhdChbXSkgOiB0aGlzLl9tb2RlbC5jaGFuZ2VkLmNvbmNhdChbXSksXG5cdFx0XHRcdGYgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdVTCcpLCB0bXAsIGksIGosIGZlID0gdGhpcy5fZGF0YS5jb3JlLmZvY3VzZWQ7XG5cdFx0XHRmb3IoaSA9IDAsIGogPSBub2Rlcy5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0dG1wID0gdGhpcy5yZWRyYXdfbm9kZShub2Rlc1tpXSwgdHJ1ZSwgdGhpcy5fbW9kZWwuZm9yY2VfZnVsbF9yZWRyYXcpO1xuXHRcdFx0XHRpZih0bXAgJiYgdGhpcy5fbW9kZWwuZm9yY2VfZnVsbF9yZWRyYXcpIHtcblx0XHRcdFx0XHRmLmFwcGVuZENoaWxkKHRtcCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmKHRoaXMuX21vZGVsLmZvcmNlX2Z1bGxfcmVkcmF3KSB7XG5cdFx0XHRcdGYuY2xhc3NOYW1lID0gdGhpcy5nZXRfY29udGFpbmVyX3VsKClbMF0uY2xhc3NOYW1lO1xuXHRcdFx0XHRmLnNldEF0dHJpYnV0ZSgncm9sZScsJ2dyb3VwJyk7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5lbXB0eSgpLmFwcGVuZChmKTtcblx0XHRcdFx0Ly90aGlzLmdldF9jb250YWluZXJfdWwoKVswXS5hcHBlbmRDaGlsZChmKTtcblx0XHRcdH1cblx0XHRcdGlmKGZlICE9PSBudWxsICYmIHRoaXMuc2V0dGluZ3MuY29yZS5yZXN0b3JlX2ZvY3VzKSB7XG5cdFx0XHRcdHRtcCA9IHRoaXMuZ2V0X25vZGUoZmUsIHRydWUpO1xuXHRcdFx0XHRpZih0bXAgJiYgdG1wLmxlbmd0aCAmJiB0bXAuY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJylbMF0gIT09IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpIHtcblx0XHRcdFx0XHR0bXAuY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykudHJpZ2dlcignZm9jdXMnKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHR0aGlzLl9kYXRhLmNvcmUuZm9jdXNlZCA9IG51bGw7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHRoaXMuX21vZGVsLmZvcmNlX2Z1bGxfcmVkcmF3ID0gZmFsc2U7XG5cdFx0XHR0aGlzLl9tb2RlbC5jaGFuZ2VkID0gW107XG5cdFx0XHQvKipcblx0XHRcdCAqIHRyaWdnZXJlZCBhZnRlciBub2RlcyBhcmUgcmVkcmF3blxuXHRcdFx0ICogQGV2ZW50XG5cdFx0XHQgKiBAbmFtZSByZWRyYXcuanN0cmVlXG5cdFx0XHQgKiBAcGFyYW0ge2FycmF5fSBub2RlcyB0aGUgcmVkcmF3biBub2Rlc1xuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ3JlZHJhdycsIHsgXCJub2Rlc1wiIDogbm9kZXMgfSk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiByZWRyYXdzIGFsbCBub2RlcyB0aGF0IG5lZWQgdG8gYmUgcmVkcmF3biBvciBvcHRpb25hbGx5IC0gdGhlIHdob2xlIHRyZWVcblx0XHQgKiBAbmFtZSByZWRyYXcoW2Z1bGxdKVxuXHRcdCAqIEBwYXJhbSB7Qm9vbGVhbn0gZnVsbCBpZiBzZXQgdG8gYHRydWVgIGFsbCBub2RlcyBhcmUgcmVkcmF3bi5cblx0XHQgKi9cblx0XHRyZWRyYXcgOiBmdW5jdGlvbiAoZnVsbCkge1xuXHRcdFx0aWYoZnVsbCkge1xuXHRcdFx0XHR0aGlzLl9tb2RlbC5mb3JjZV9mdWxsX3JlZHJhdyA9IHRydWU7XG5cdFx0XHR9XG5cdFx0XHQvL2lmKHRoaXMuX21vZGVsLnJlZHJhd190aW1lb3V0KSB7XG5cdFx0XHQvL1x0Y2xlYXJUaW1lb3V0KHRoaXMuX21vZGVsLnJlZHJhd190aW1lb3V0KTtcblx0XHRcdC8vfVxuXHRcdFx0Ly90aGlzLl9tb2RlbC5yZWRyYXdfdGltZW91dCA9IHNldFRpbWVvdXQoJC5wcm94eSh0aGlzLl9yZWRyYXcsIHRoaXMpLDApO1xuXHRcdFx0dGhpcy5fcmVkcmF3KCk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiByZWRyYXdzIGEgc2luZ2xlIG5vZGUncyBjaGlsZHJlbi4gVXNlZCBpbnRlcm5hbGx5LlxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICogQG5hbWUgZHJhd19jaGlsZHJlbihub2RlKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG5vZGUgdGhlIG5vZGUgd2hvc2UgY2hpbGRyZW4gd2lsbCBiZSByZWRyYXduXG5cdFx0ICovXG5cdFx0ZHJhd19jaGlsZHJlbiA6IGZ1bmN0aW9uIChub2RlKSB7XG5cdFx0XHR2YXIgb2JqID0gdGhpcy5nZXRfbm9kZShub2RlKSxcblx0XHRcdFx0aSA9IGZhbHNlLFxuXHRcdFx0XHRqID0gZmFsc2UsXG5cdFx0XHRcdGsgPSBmYWxzZSxcblx0XHRcdFx0ZCA9IGRvY3VtZW50O1xuXHRcdFx0aWYoIW9iaikgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdGlmKG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkgeyByZXR1cm4gdGhpcy5yZWRyYXcodHJ1ZSk7IH1cblx0XHRcdG5vZGUgPSB0aGlzLmdldF9ub2RlKG5vZGUsIHRydWUpO1xuXHRcdFx0aWYoIW5vZGUgfHwgIW5vZGUubGVuZ3RoKSB7IHJldHVybiBmYWxzZTsgfSAvLyBUT0RPOiBxdWljayB0b2dnbGVcblxuXHRcdFx0bm9kZS5jaGlsZHJlbignLmpzdHJlZS1jaGlsZHJlbicpLnJlbW92ZSgpO1xuXHRcdFx0bm9kZSA9IG5vZGVbMF07XG5cdFx0XHRpZihvYmouY2hpbGRyZW4ubGVuZ3RoICYmIG9iai5zdGF0ZS5sb2FkZWQpIHtcblx0XHRcdFx0ayA9IGQuY3JlYXRlRWxlbWVudCgnVUwnKTtcblx0XHRcdFx0ay5zZXRBdHRyaWJ1dGUoJ3JvbGUnLCAnZ3JvdXAnKTtcblx0XHRcdFx0ay5jbGFzc05hbWUgPSAnanN0cmVlLWNoaWxkcmVuJztcblx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gb2JqLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdGsuYXBwZW5kQ2hpbGQodGhpcy5yZWRyYXdfbm9kZShvYmouY2hpbGRyZW5baV0sIHRydWUsIHRydWUpKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRub2RlLmFwcGVuZENoaWxkKGspO1xuXHRcdFx0fVxuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogcmVkcmF3cyBhIHNpbmdsZSBub2RlLiBVc2VkIGludGVybmFsbHkuXG5cdFx0ICogQHByaXZhdGVcblx0XHQgKiBAbmFtZSByZWRyYXdfbm9kZShub2RlLCBkZWVwLCBpc19jYWxsYmFjaywgZm9yY2VfcmVuZGVyKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG5vZGUgdGhlIG5vZGUgdG8gcmVkcmF3XG5cdFx0ICogQHBhcmFtIHtCb29sZWFufSBkZWVwIHNob3VsZCBjaGlsZCBub2RlcyBiZSByZWRyYXduIHRvb1xuXHRcdCAqIEBwYXJhbSB7Qm9vbGVhbn0gaXNfY2FsbGJhY2sgaXMgdGhpcyBhIHJlY3Vyc2lvbiBjYWxsXG5cdFx0ICogQHBhcmFtIHtCb29sZWFufSBmb3JjZV9yZW5kZXIgc2hvdWxkIGNoaWxkcmVuIG9mIGNsb3NlZCBwYXJlbnRzIGJlIGRyYXduIGFueXdheVxuXHRcdCAqL1xuXHRcdHJlZHJhd19ub2RlIDogZnVuY3Rpb24gKG5vZGUsIGRlZXAsIGlzX2NhbGxiYWNrLCBmb3JjZV9yZW5kZXIpIHtcblx0XHRcdHZhciBvYmogPSB0aGlzLmdldF9ub2RlKG5vZGUpLFxuXHRcdFx0XHRwYXIgPSBmYWxzZSxcblx0XHRcdFx0aW5kID0gZmFsc2UsXG5cdFx0XHRcdG9sZCA9IGZhbHNlLFxuXHRcdFx0XHRpID0gZmFsc2UsXG5cdFx0XHRcdGogPSBmYWxzZSxcblx0XHRcdFx0ayA9IGZhbHNlLFxuXHRcdFx0XHRjID0gJycsXG5cdFx0XHRcdGQgPSBkb2N1bWVudCxcblx0XHRcdFx0bSA9IHRoaXMuX21vZGVsLmRhdGEsXG5cdFx0XHRcdGYgPSBmYWxzZSxcblx0XHRcdFx0cyA9IGZhbHNlLFxuXHRcdFx0XHR0bXAgPSBudWxsLFxuXHRcdFx0XHR0ID0gMCxcblx0XHRcdFx0bCA9IDAsXG5cdFx0XHRcdGhhc19jaGlsZHJlbiA9IGZhbHNlLFxuXHRcdFx0XHRsYXN0X3NpYmxpbmcgPSBmYWxzZTtcblx0XHRcdGlmKCFvYmopIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHRpZihvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHsgIHJldHVybiB0aGlzLnJlZHJhdyh0cnVlKTsgfVxuXHRcdFx0ZGVlcCA9IGRlZXAgfHwgb2JqLmNoaWxkcmVuLmxlbmd0aCA9PT0gMDtcblx0XHRcdG5vZGUgPSAhZG9jdW1lbnQucXVlcnlTZWxlY3RvciA/IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKG9iai5pZCkgOiB0aGlzLmVsZW1lbnRbMF0ucXVlcnlTZWxlY3RvcignIycgKyAoXCIwMTIzNDU2Nzg5XCIuaW5kZXhPZihvYmouaWRbMF0pICE9PSAtMSA/ICdcXFxcMycgKyBvYmouaWRbMF0gKyAnICcgKyBvYmouaWQuc3Vic3RyKDEpLnJlcGxhY2UoJC5qc3RyZWUuaWRyZWdleCwnXFxcXCQmJykgOiBvYmouaWQucmVwbGFjZSgkLmpzdHJlZS5pZHJlZ2V4LCdcXFxcJCYnKSkgKTsgLy8sIHRoaXMuZWxlbWVudCk7XG5cdFx0XHRpZighbm9kZSkge1xuXHRcdFx0XHRkZWVwID0gdHJ1ZTtcblx0XHRcdFx0Ly9ub2RlID0gZC5jcmVhdGVFbGVtZW50KCdMSScpO1xuXHRcdFx0XHRpZighaXNfY2FsbGJhY2spIHtcblx0XHRcdFx0XHRwYXIgPSBvYmoucGFyZW50ICE9PSAkLmpzdHJlZS5yb290ID8gJCgnIycgKyBvYmoucGFyZW50LnJlcGxhY2UoJC5qc3RyZWUuaWRyZWdleCwnXFxcXCQmJyksIHRoaXMuZWxlbWVudClbMF0gOiBudWxsO1xuXHRcdFx0XHRcdGlmKHBhciAhPT0gbnVsbCAmJiAoIXBhciB8fCAhbVtvYmoucGFyZW50XS5zdGF0ZS5vcGVuZWQpKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGluZCA9ICQuaW5BcnJheShvYmouaWQsIHBhciA9PT0gbnVsbCA/IG1bJC5qc3RyZWUucm9vdF0uY2hpbGRyZW4gOiBtW29iai5wYXJlbnRdLmNoaWxkcmVuKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0ZWxzZSB7XG5cdFx0XHRcdG5vZGUgPSAkKG5vZGUpO1xuXHRcdFx0XHRpZighaXNfY2FsbGJhY2spIHtcblx0XHRcdFx0XHRwYXIgPSBub2RlLnBhcmVudCgpLnBhcmVudCgpWzBdO1xuXHRcdFx0XHRcdGlmKHBhciA9PT0gdGhpcy5lbGVtZW50WzBdKSB7XG5cdFx0XHRcdFx0XHRwYXIgPSBudWxsO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpbmQgPSBub2RlLmluZGV4KCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0Ly8gbVtvYmouaWRdLmRhdGEgPSBub2RlLmRhdGEoKTsgLy8gdXNlIG9ubHkgbm9kZSdzIGRhdGEsIG5vIG5lZWQgdG8gdG91Y2gganF1ZXJ5IHN0b3JhZ2Vcblx0XHRcdFx0aWYoIWRlZXAgJiYgb2JqLmNoaWxkcmVuLmxlbmd0aCAmJiAhbm9kZS5jaGlsZHJlbignLmpzdHJlZS1jaGlsZHJlbicpLmxlbmd0aCkge1xuXHRcdFx0XHRcdGRlZXAgPSB0cnVlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKCFkZWVwKSB7XG5cdFx0XHRcdFx0b2xkID0gbm9kZS5jaGlsZHJlbignLmpzdHJlZS1jaGlsZHJlbicpWzBdO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGYgPSBub2RlLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpWzBdID09PSBkb2N1bWVudC5hY3RpdmVFbGVtZW50O1xuXHRcdFx0XHRub2RlLnJlbW92ZSgpO1xuXHRcdFx0XHQvL25vZGUgPSBkLmNyZWF0ZUVsZW1lbnQoJ0xJJyk7XG5cdFx0XHRcdC8vbm9kZSA9IG5vZGVbMF07XG5cdFx0XHR9XG5cdFx0XHRub2RlID0gdGhpcy5fZGF0YS5jb3JlLm5vZGUuY2xvbmVOb2RlKHRydWUpO1xuXHRcdFx0Ly8gbm9kZSBpcyBET00sIGRlZXAgaXMgYm9vbGVhblxuXG5cdFx0XHRjID0gJ2pzdHJlZS1ub2RlICc7XG5cdFx0XHRmb3IoaSBpbiBvYmoubGlfYXR0cikge1xuXHRcdFx0XHRpZihvYmoubGlfYXR0ci5oYXNPd25Qcm9wZXJ0eShpKSkge1xuXHRcdFx0XHRcdGlmKGkgPT09ICdpZCcpIHsgY29udGludWU7IH1cblx0XHRcdFx0XHRpZihpICE9PSAnY2xhc3MnKSB7XG5cdFx0XHRcdFx0XHRub2RlLnNldEF0dHJpYnV0ZShpLCBvYmoubGlfYXR0cltpXSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0YyArPSBvYmoubGlfYXR0cltpXTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmKCFvYmouYV9hdHRyLmlkKSB7XG5cdFx0XHRcdG9iai5hX2F0dHIuaWQgPSBvYmouaWQgKyAnX2FuY2hvcic7XG5cdFx0XHR9XG5cdFx0XHRub2RlLmNoaWxkTm9kZXNbMV0uc2V0QXR0cmlidXRlKCdhcmlhLXNlbGVjdGVkJywgISFvYmouc3RhdGUuc2VsZWN0ZWQpO1xuXHRcdFx0bm9kZS5jaGlsZE5vZGVzWzFdLnNldEF0dHJpYnV0ZSgnYXJpYS1sZXZlbCcsIG9iai5wYXJlbnRzLmxlbmd0aCk7XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLmNvcmUuY29tcHV0ZV9lbGVtZW50c19wb3NpdGlvbnMpIHtcblx0XHRcdFx0bm9kZS5jaGlsZE5vZGVzWzFdLnNldEF0dHJpYnV0ZSgnYXJpYS1zZXRzaXplJywgbVtvYmoucGFyZW50XS5jaGlsZHJlbi5sZW5ndGgpO1xuXHRcdFx0XHRub2RlLmNoaWxkTm9kZXNbMV0uc2V0QXR0cmlidXRlKCdhcmlhLXBvc2luc2V0JywgbVtvYmoucGFyZW50XS5jaGlsZHJlbi5pbmRleE9mKG9iai5pZCkgKyAxKTtcblx0XHRcdH1cblx0XHRcdGlmKG9iai5zdGF0ZS5kaXNhYmxlZCkge1xuXHRcdFx0XHRub2RlLmNoaWxkTm9kZXNbMV0uc2V0QXR0cmlidXRlKCdhcmlhLWRpc2FibGVkJywgdHJ1ZSk7XG5cdFx0XHR9XG5cblx0XHRcdGZvcihpID0gMCwgaiA9IG9iai5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0aWYoIW1bb2JqLmNoaWxkcmVuW2ldXS5zdGF0ZS5oaWRkZW4pIHtcblx0XHRcdFx0XHRoYXNfY2hpbGRyZW4gPSB0cnVlO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRpZihvYmoucGFyZW50ICE9PSBudWxsICYmIG1bb2JqLnBhcmVudF0gJiYgIW9iai5zdGF0ZS5oaWRkZW4pIHtcblx0XHRcdFx0aSA9ICQuaW5BcnJheShvYmouaWQsIG1bb2JqLnBhcmVudF0uY2hpbGRyZW4pO1xuXHRcdFx0XHRsYXN0X3NpYmxpbmcgPSBvYmouaWQ7XG5cdFx0XHRcdGlmKGkgIT09IC0xKSB7XG5cdFx0XHRcdFx0aSsrO1xuXHRcdFx0XHRcdGZvcihqID0gbVtvYmoucGFyZW50XS5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdGlmKCFtW21bb2JqLnBhcmVudF0uY2hpbGRyZW5baV1dLnN0YXRlLmhpZGRlbikge1xuXHRcdFx0XHRcdFx0XHRsYXN0X3NpYmxpbmcgPSBtW29iai5wYXJlbnRdLmNoaWxkcmVuW2ldO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYobGFzdF9zaWJsaW5nICE9PSBvYmouaWQpIHtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGlmKG9iai5zdGF0ZS5oaWRkZW4pIHtcblx0XHRcdFx0YyArPSAnIGpzdHJlZS1oaWRkZW4nO1xuXHRcdFx0fVxuXHRcdFx0aWYgKG9iai5zdGF0ZS5sb2FkaW5nKSB7XG5cdFx0XHRcdGMgKz0gJyBqc3RyZWUtbG9hZGluZyc7XG5cdFx0XHR9XG5cdFx0XHRpZihvYmouc3RhdGUubG9hZGVkICYmICFoYXNfY2hpbGRyZW4pIHtcblx0XHRcdFx0YyArPSAnIGpzdHJlZS1sZWFmJztcblx0XHRcdH1cblx0XHRcdGVsc2Uge1xuXHRcdFx0XHRjICs9IG9iai5zdGF0ZS5vcGVuZWQgJiYgb2JqLnN0YXRlLmxvYWRlZCA/ICcganN0cmVlLW9wZW4nIDogJyBqc3RyZWUtY2xvc2VkJztcblx0XHRcdFx0bm9kZS5jaGlsZE5vZGVzWzFdLnNldEF0dHJpYnV0ZSgnYXJpYS1leHBhbmRlZCcsIChvYmouc3RhdGUub3BlbmVkICYmIG9iai5zdGF0ZS5sb2FkZWQpICk7XG5cdFx0XHR9XG5cdFx0XHRpZihsYXN0X3NpYmxpbmcgPT09IG9iai5pZCkge1xuXHRcdFx0XHRjICs9ICcganN0cmVlLWxhc3QnO1xuXHRcdFx0fVxuXHRcdFx0bm9kZS5pZCA9IG9iai5pZDtcblx0XHRcdG5vZGUuY2xhc3NOYW1lID0gYztcblx0XHRcdGMgPSAoIG9iai5zdGF0ZS5zZWxlY3RlZCA/ICcganN0cmVlLWNsaWNrZWQnIDogJycpICsgKCBvYmouc3RhdGUuZGlzYWJsZWQgPyAnIGpzdHJlZS1kaXNhYmxlZCcgOiAnJyk7XG5cdFx0XHRmb3IoaiBpbiBvYmouYV9hdHRyKSB7XG5cdFx0XHRcdGlmKG9iai5hX2F0dHIuaGFzT3duUHJvcGVydHkoaikpIHtcblx0XHRcdFx0XHRpZihqID09PSAnaHJlZicgJiYgb2JqLmFfYXR0cltqXSA9PT0gJyMnKSB7IGNvbnRpbnVlOyB9XG5cdFx0XHRcdFx0aWYoaiAhPT0gJ2NsYXNzJykge1xuXHRcdFx0XHRcdFx0bm9kZS5jaGlsZE5vZGVzWzFdLnNldEF0dHJpYnV0ZShqLCBvYmouYV9hdHRyW2pdKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRjICs9ICcgJyArIG9iai5hX2F0dHJbal07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRpZihjLmxlbmd0aCkge1xuXHRcdFx0XHRub2RlLmNoaWxkTm9kZXNbMV0uY2xhc3NOYW1lID0gJ2pzdHJlZS1hbmNob3IgJyArIGM7XG5cdFx0XHR9XG5cdFx0XHRpZigob2JqLmljb24gJiYgb2JqLmljb24gIT09IHRydWUpIHx8IG9iai5pY29uID09PSBmYWxzZSkge1xuXHRcdFx0XHRpZihvYmouaWNvbiA9PT0gZmFsc2UpIHtcblx0XHRcdFx0XHRub2RlLmNoaWxkTm9kZXNbMV0uY2hpbGROb2Rlc1swXS5jbGFzc05hbWUgKz0gJyBqc3RyZWUtdGhlbWVpY29uLWhpZGRlbic7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSBpZihvYmouaWNvbi5pbmRleE9mKCcvJykgPT09IC0xICYmIG9iai5pY29uLmluZGV4T2YoJy4nKSA9PT0gLTEpIHtcblx0XHRcdFx0XHRub2RlLmNoaWxkTm9kZXNbMV0uY2hpbGROb2Rlc1swXS5jbGFzc05hbWUgKz0gJyAnICsgb2JqLmljb24gKyAnIGpzdHJlZS10aGVtZWljb24tY3VzdG9tJztcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRub2RlLmNoaWxkTm9kZXNbMV0uY2hpbGROb2Rlc1swXS5zdHlsZS5iYWNrZ3JvdW5kSW1hZ2UgPSAndXJsKFwiJytvYmouaWNvbisnXCIpJztcblx0XHRcdFx0XHRub2RlLmNoaWxkTm9kZXNbMV0uY2hpbGROb2Rlc1swXS5zdHlsZS5iYWNrZ3JvdW5kUG9zaXRpb24gPSAnY2VudGVyIGNlbnRlcic7XG5cdFx0XHRcdFx0bm9kZS5jaGlsZE5vZGVzWzFdLmNoaWxkTm9kZXNbMF0uc3R5bGUuYmFja2dyb3VuZFNpemUgPSAnYXV0byc7XG5cdFx0XHRcdFx0bm9kZS5jaGlsZE5vZGVzWzFdLmNoaWxkTm9kZXNbMF0uY2xhc3NOYW1lICs9ICcganN0cmVlLXRoZW1laWNvbi1jdXN0b20nO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGlmKHRoaXMuc2V0dGluZ3MuY29yZS5mb3JjZV90ZXh0KSB7XG5cdFx0XHRcdG5vZGUuY2hpbGROb2Rlc1sxXS5hcHBlbmRDaGlsZChkLmNyZWF0ZVRleHROb2RlKG9iai50ZXh0KSk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0bm9kZS5jaGlsZE5vZGVzWzFdLmlubmVySFRNTCArPSBvYmoudGV4dDtcblx0XHRcdH1cblxuXG5cdFx0XHRpZihkZWVwICYmIG9iai5jaGlsZHJlbi5sZW5ndGggJiYgKG9iai5zdGF0ZS5vcGVuZWQgfHwgZm9yY2VfcmVuZGVyKSAmJiBvYmouc3RhdGUubG9hZGVkKSB7XG5cdFx0XHRcdGsgPSBkLmNyZWF0ZUVsZW1lbnQoJ1VMJyk7XG5cdFx0XHRcdGsuc2V0QXR0cmlidXRlKCdyb2xlJywgJ2dyb3VwJyk7XG5cdFx0XHRcdGsuY2xhc3NOYW1lID0gJ2pzdHJlZS1jaGlsZHJlbic7XG5cdFx0XHRcdGZvcihpID0gMCwgaiA9IG9iai5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRrLmFwcGVuZENoaWxkKHRoaXMucmVkcmF3X25vZGUob2JqLmNoaWxkcmVuW2ldLCBkZWVwLCB0cnVlKSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0bm9kZS5hcHBlbmRDaGlsZChrKTtcblx0XHRcdH1cblx0XHRcdGlmKG9sZCkge1xuXHRcdFx0XHRub2RlLmFwcGVuZENoaWxkKG9sZCk7XG5cdFx0XHR9XG5cdFx0XHRpZighaXNfY2FsbGJhY2spIHtcblx0XHRcdFx0Ly8gYXBwZW5kIGJhY2sgdXNpbmcgcGFyIC8gaW5kXG5cdFx0XHRcdGlmKCFwYXIpIHtcblx0XHRcdFx0XHRwYXIgPSB0aGlzLmVsZW1lbnRbMF07XG5cdFx0XHRcdH1cblx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gcGFyLmNoaWxkTm9kZXMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0aWYocGFyLmNoaWxkTm9kZXNbaV0gJiYgcGFyLmNoaWxkTm9kZXNbaV0uY2xhc3NOYW1lICYmIHBhci5jaGlsZE5vZGVzW2ldLmNsYXNzTmFtZS5pbmRleE9mKCdqc3RyZWUtY2hpbGRyZW4nKSAhPT0gLTEpIHtcblx0XHRcdFx0XHRcdHRtcCA9IHBhci5jaGlsZE5vZGVzW2ldO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKCF0bXApIHtcblx0XHRcdFx0XHR0bXAgPSBkLmNyZWF0ZUVsZW1lbnQoJ1VMJyk7XG5cdFx0XHRcdFx0dG1wLnNldEF0dHJpYnV0ZSgncm9sZScsICdncm91cCcpO1xuXHRcdFx0XHRcdHRtcC5jbGFzc05hbWUgPSAnanN0cmVlLWNoaWxkcmVuJztcblx0XHRcdFx0XHRwYXIuYXBwZW5kQ2hpbGQodG1wKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRwYXIgPSB0bXA7XG5cblx0XHRcdFx0aWYoaW5kIDwgcGFyLmNoaWxkTm9kZXMubGVuZ3RoKSB7XG5cdFx0XHRcdFx0cGFyLmluc2VydEJlZm9yZShub2RlLCBwYXIuY2hpbGROb2Rlc1tpbmRdKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRwYXIuYXBwZW5kQ2hpbGQobm9kZSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYoZikge1xuXHRcdFx0XHRcdHQgPSB0aGlzLmVsZW1lbnRbMF0uc2Nyb2xsVG9wO1xuXHRcdFx0XHRcdGwgPSB0aGlzLmVsZW1lbnRbMF0uc2Nyb2xsTGVmdDtcblx0XHRcdFx0XHRub2RlLmNoaWxkTm9kZXNbMV0uZm9jdXMoKTtcblx0XHRcdFx0XHR0aGlzLmVsZW1lbnRbMF0uc2Nyb2xsVG9wID0gdDtcblx0XHRcdFx0XHR0aGlzLmVsZW1lbnRbMF0uc2Nyb2xsTGVmdCA9IGw7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmKG9iai5zdGF0ZS5vcGVuZWQgJiYgIW9iai5zdGF0ZS5sb2FkZWQpIHtcblx0XHRcdFx0b2JqLnN0YXRlLm9wZW5lZCA9IGZhbHNlO1xuXHRcdFx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHR0aGlzLm9wZW5fbm9kZShvYmouaWQsIGZhbHNlLCAwKTtcblx0XHRcdFx0fS5iaW5kKHRoaXMpLCAwKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBub2RlO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogb3BlbnMgYSBub2RlLCByZXZlYWxpbmcgaXRzIGNoaWxkcmVuLiBJZiB0aGUgbm9kZSBpcyBub3QgbG9hZGVkIGl0IHdpbGwgYmUgbG9hZGVkIGFuZCBvcGVuZWQgb25jZSByZWFkeS5cblx0XHQgKiBAbmFtZSBvcGVuX25vZGUob2JqIFssIGNhbGxiYWNrLCBhbmltYXRpb25dKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9iaiB0aGUgbm9kZSB0byBvcGVuXG5cdFx0ICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgYSBmdW5jdGlvbiB0byBleGVjdXRlIG9uY2UgdGhlIG5vZGUgaXMgb3BlbmVkXG5cdFx0ICogQHBhcmFtIHtOdW1iZXJ9IGFuaW1hdGlvbiB0aGUgYW5pbWF0aW9uIGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kcyB3aGVuIG9wZW5pbmcgdGhlIG5vZGUgKG92ZXJyaWRlcyB0aGUgYGNvcmUuYW5pbWF0aW9uYCBzZXR0aW5nKS4gVXNlIGBmYWxzZWAgZm9yIG5vIGFuaW1hdGlvbi5cblx0XHQgKiBAdHJpZ2dlciBvcGVuX25vZGUuanN0cmVlLCBhZnRlcl9vcGVuLmpzdHJlZSwgYmVmb3JlX29wZW4uanN0cmVlXG5cdFx0ICovXG5cdFx0b3Blbl9ub2RlIDogZnVuY3Rpb24gKG9iaiwgY2FsbGJhY2ssIGFuaW1hdGlvbikge1xuXHRcdFx0dmFyIHQxLCB0MiwgZCwgdDtcblx0XHRcdGlmKCQudmFrYXRhLmlzX2FycmF5KG9iaikpIHtcblx0XHRcdFx0b2JqID0gb2JqLnNsaWNlKCk7XG5cdFx0XHRcdGZvcih0MSA9IDAsIHQyID0gb2JqLmxlbmd0aDsgdDEgPCB0MjsgdDErKykge1xuXHRcdFx0XHRcdHRoaXMub3Blbl9ub2RlKG9ialt0MV0sIGNhbGxiYWNrLCBhbmltYXRpb24pO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaiB8fCBvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0YW5pbWF0aW9uID0gYW5pbWF0aW9uID09PSB1bmRlZmluZWQgPyB0aGlzLnNldHRpbmdzLmNvcmUuYW5pbWF0aW9uIDogYW5pbWF0aW9uO1xuXHRcdFx0aWYoIXRoaXMuaXNfY2xvc2VkKG9iaikpIHtcblx0XHRcdFx0aWYoY2FsbGJhY2spIHtcblx0XHRcdFx0XHRjYWxsYmFjay5jYWxsKHRoaXMsIG9iaiwgZmFsc2UpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdGlmKCF0aGlzLmlzX2xvYWRlZChvYmopKSB7XG5cdFx0XHRcdGlmKHRoaXMuaXNfbG9hZGluZyhvYmopKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0dGhpcy5vcGVuX25vZGUob2JqLCBjYWxsYmFjaywgYW5pbWF0aW9uKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcyksIDUwMCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dGhpcy5sb2FkX25vZGUob2JqLCBmdW5jdGlvbiAobywgb2spIHtcblx0XHRcdFx0XHRyZXR1cm4gb2sgPyB0aGlzLm9wZW5fbm9kZShvLCBjYWxsYmFjaywgYW5pbWF0aW9uKSA6IChjYWxsYmFjayA/IGNhbGxiYWNrLmNhbGwodGhpcywgbywgZmFsc2UpIDogZmFsc2UpO1xuXHRcdFx0XHR9KTtcblx0XHRcdH1cblx0XHRcdGVsc2Uge1xuXHRcdFx0XHRkID0gdGhpcy5nZXRfbm9kZShvYmosIHRydWUpO1xuXHRcdFx0XHR0ID0gdGhpcztcblx0XHRcdFx0aWYoZC5sZW5ndGgpIHtcblx0XHRcdFx0XHRpZihhbmltYXRpb24gJiYgZC5jaGlsZHJlbihcIi5qc3RyZWUtY2hpbGRyZW5cIikubGVuZ3RoKSB7XG5cdFx0XHRcdFx0XHRkLmNoaWxkcmVuKFwiLmpzdHJlZS1jaGlsZHJlblwiKS5zdG9wKHRydWUsIHRydWUpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZihvYmouY2hpbGRyZW4ubGVuZ3RoICYmICF0aGlzLl9maXJzdENoaWxkKGQuY2hpbGRyZW4oJy5qc3RyZWUtY2hpbGRyZW4nKVswXSkpIHtcblx0XHRcdFx0XHRcdHRoaXMuZHJhd19jaGlsZHJlbihvYmopO1xuXHRcdFx0XHRcdFx0Ly9kID0gdGhpcy5nZXRfbm9kZShvYmosIHRydWUpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZighYW5pbWF0aW9uKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnRyaWdnZXIoJ2JlZm9yZV9vcGVuJywgeyBcIm5vZGVcIiA6IG9iaiB9KTtcblx0XHRcdFx0XHRcdGRbMF0uY2xhc3NOYW1lID0gZFswXS5jbGFzc05hbWUucmVwbGFjZSgnanN0cmVlLWNsb3NlZCcsICdqc3RyZWUtb3BlbicpO1xuXHRcdFx0XHRcdFx0ZFswXS5jaGlsZE5vZGVzWzFdLnNldEF0dHJpYnV0ZShcImFyaWEtZXhwYW5kZWRcIiwgdHJ1ZSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0dGhpcy50cmlnZ2VyKCdiZWZvcmVfb3BlbicsIHsgXCJub2RlXCIgOiBvYmogfSk7XG5cdFx0XHRcdFx0XHRkXG5cdFx0XHRcdFx0XHRcdC5jaGlsZHJlbihcIi5qc3RyZWUtY2hpbGRyZW5cIikuY3NzKFwiZGlzcGxheVwiLFwibm9uZVwiKS5lbmQoKVxuXHRcdFx0XHRcdFx0XHQucmVtb3ZlQ2xhc3MoXCJqc3RyZWUtY2xvc2VkXCIpLmFkZENsYXNzKFwianN0cmVlLW9wZW5cIilcblx0XHRcdFx0XHRcdFx0XHQuY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykuYXR0cihcImFyaWEtZXhwYW5kZWRcIiwgdHJ1ZSkuZW5kKClcblx0XHRcdFx0XHRcdFx0LmNoaWxkcmVuKFwiLmpzdHJlZS1jaGlsZHJlblwiKS5zdG9wKHRydWUsIHRydWUpXG5cdFx0XHRcdFx0XHRcdFx0LnNsaWRlRG93bihhbmltYXRpb24sIGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHRoaXMuc3R5bGUuZGlzcGxheSA9IFwiXCI7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAodC5lbGVtZW50KSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHQudHJpZ2dlcihcImFmdGVyX29wZW5cIiwgeyBcIm5vZGVcIiA6IG9iaiB9KTtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0b2JqLnN0YXRlLm9wZW5lZCA9IHRydWU7XG5cdFx0XHRcdGlmKGNhbGxiYWNrKSB7XG5cdFx0XHRcdFx0Y2FsbGJhY2suY2FsbCh0aGlzLCBvYmosIHRydWUpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKCFkLmxlbmd0aCkge1xuXHRcdFx0XHRcdC8qKlxuXHRcdFx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGEgbm9kZSBpcyBhYm91dCB0byBiZSBvcGVuZWQgKGlmIHRoZSBub2RlIGlzIHN1cHBvc2VkIHRvIGJlIGluIHRoZSBET00sIGl0IHdpbGwgYmUsIGJ1dCBpdCB3b24ndCBiZSB2aXNpYmxlIHlldClcblx0XHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0XHQgKiBAbmFtZSBiZWZvcmVfb3Blbi5qc3RyZWVcblx0XHRcdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZSB0aGUgb3BlbmVkIG5vZGVcblx0XHRcdFx0XHQgKi9cblx0XHRcdFx0XHR0aGlzLnRyaWdnZXIoJ2JlZm9yZV9vcGVuJywgeyBcIm5vZGVcIiA6IG9iaiB9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYSBub2RlIGlzIG9wZW5lZCAoaWYgdGhlcmUgaXMgYW4gYW5pbWF0aW9uIGl0IHdpbGwgbm90IGJlIGNvbXBsZXRlZCB5ZXQpXG5cdFx0XHRcdCAqIEBldmVudFxuXHRcdFx0XHQgKiBAbmFtZSBvcGVuX25vZGUuanN0cmVlXG5cdFx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlIHRoZSBvcGVuZWQgbm9kZVxuXHRcdFx0XHQgKi9cblx0XHRcdFx0dGhpcy50cmlnZ2VyKCdvcGVuX25vZGUnLCB7IFwibm9kZVwiIDogb2JqIH0pO1xuXHRcdFx0XHRpZighYW5pbWF0aW9uIHx8ICFkLmxlbmd0aCkge1xuXHRcdFx0XHRcdC8qKlxuXHRcdFx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGEgbm9kZSBpcyBvcGVuZWQgYW5kIHRoZSBhbmltYXRpb24gaXMgY29tcGxldGVcblx0XHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0XHQgKiBAbmFtZSBhZnRlcl9vcGVuLmpzdHJlZVxuXHRcdFx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlIHRoZSBvcGVuZWQgbm9kZVxuXHRcdFx0XHRcdCAqL1xuXHRcdFx0XHRcdHRoaXMudHJpZ2dlcihcImFmdGVyX29wZW5cIiwgeyBcIm5vZGVcIiA6IG9iaiB9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIG9wZW5zIGV2ZXJ5IHBhcmVudCBvZiBhIG5vZGUgKG5vZGUgc2hvdWxkIGJlIGxvYWRlZClcblx0XHQgKiBAbmFtZSBfb3Blbl90byhvYmopXG5cdFx0ICogQHBhcmFtIHttaXhlZH0gb2JqIHRoZSBub2RlIHRvIHJldmVhbFxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICovXG5cdFx0X29wZW5fdG8gOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqIHx8IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHR2YXIgaSwgaiwgcCA9IG9iai5wYXJlbnRzO1xuXHRcdFx0Zm9yKGkgPSAwLCBqID0gcC5sZW5ndGg7IGkgPCBqOyBpKz0xKSB7XG5cdFx0XHRcdGlmKGkgIT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0XHR0aGlzLm9wZW5fbm9kZShwW2ldLCBmYWxzZSwgMCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiAkKCcjJyArIG9iai5pZC5yZXBsYWNlKCQuanN0cmVlLmlkcmVnZXgsJ1xcXFwkJicpLCB0aGlzLmVsZW1lbnQpO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogY2xvc2VzIGEgbm9kZSwgaGlkaW5nIGl0cyBjaGlsZHJlblxuXHRcdCAqIEBuYW1lIGNsb3NlX25vZGUob2JqIFssIGFuaW1hdGlvbl0pXG5cdFx0ICogQHBhcmFtIHttaXhlZH0gb2JqIHRoZSBub2RlIHRvIGNsb3NlXG5cdFx0ICogQHBhcmFtIHtOdW1iZXJ9IGFuaW1hdGlvbiB0aGUgYW5pbWF0aW9uIGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kcyB3aGVuIGNsb3NpbmcgdGhlIG5vZGUgKG92ZXJyaWRlcyB0aGUgYGNvcmUuYW5pbWF0aW9uYCBzZXR0aW5nKS4gVXNlIGBmYWxzZWAgZm9yIG5vIGFuaW1hdGlvbi5cblx0XHQgKiBAdHJpZ2dlciBjbG9zZV9ub2RlLmpzdHJlZSwgYWZ0ZXJfY2xvc2UuanN0cmVlXG5cdFx0ICovXG5cdFx0Y2xvc2Vfbm9kZSA6IGZ1bmN0aW9uIChvYmosIGFuaW1hdGlvbikge1xuXHRcdFx0dmFyIHQxLCB0MiwgdCwgZDtcblx0XHRcdGlmKCQudmFrYXRhLmlzX2FycmF5KG9iaikpIHtcblx0XHRcdFx0b2JqID0gb2JqLnNsaWNlKCk7XG5cdFx0XHRcdGZvcih0MSA9IDAsIHQyID0gb2JqLmxlbmd0aDsgdDEgPCB0MjsgdDErKykge1xuXHRcdFx0XHRcdHRoaXMuY2xvc2Vfbm9kZShvYmpbdDFdLCBhbmltYXRpb24pO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaiB8fCBvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0aWYodGhpcy5pc19jbG9zZWQob2JqKSkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRhbmltYXRpb24gPSBhbmltYXRpb24gPT09IHVuZGVmaW5lZCA/IHRoaXMuc2V0dGluZ3MuY29yZS5hbmltYXRpb24gOiBhbmltYXRpb247XG5cdFx0XHR0ID0gdGhpcztcblx0XHRcdGQgPSB0aGlzLmdldF9ub2RlKG9iaiwgdHJ1ZSk7XG5cblx0XHRcdG9iai5zdGF0ZS5vcGVuZWQgPSBmYWxzZTtcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYSBub2RlIGlzIGNsb3NlZCAoaWYgdGhlcmUgaXMgYW4gYW5pbWF0aW9uIGl0IHdpbGwgbm90IGJlIGNvbXBsZXRlIHlldClcblx0XHRcdCAqIEBldmVudFxuXHRcdFx0ICogQG5hbWUgY2xvc2Vfbm9kZS5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlIHRoZSBjbG9zZWQgbm9kZVxuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ2Nsb3NlX25vZGUnLHsgXCJub2RlXCIgOiBvYmogfSk7XG5cdFx0XHRpZighZC5sZW5ndGgpIHtcblx0XHRcdFx0LyoqXG5cdFx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGEgbm9kZSBpcyBjbG9zZWQgYW5kIHRoZSBhbmltYXRpb24gaXMgY29tcGxldGVcblx0XHRcdFx0ICogQGV2ZW50XG5cdFx0XHRcdCAqIEBuYW1lIGFmdGVyX2Nsb3NlLmpzdHJlZVxuXHRcdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZSB0aGUgY2xvc2VkIG5vZGVcblx0XHRcdFx0ICovXG5cdFx0XHRcdHRoaXMudHJpZ2dlcihcImFmdGVyX2Nsb3NlXCIsIHsgXCJub2RlXCIgOiBvYmogfSk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0aWYoIWFuaW1hdGlvbikge1xuXHRcdFx0XHRcdGRbMF0uY2xhc3NOYW1lID0gZFswXS5jbGFzc05hbWUucmVwbGFjZSgnanN0cmVlLW9wZW4nLCAnanN0cmVlLWNsb3NlZCcpO1xuXHRcdFx0XHRcdGQuY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykuYXR0cihcImFyaWEtZXhwYW5kZWRcIiwgZmFsc2UpO1xuXHRcdFx0XHRcdGQuY2hpbGRyZW4oJy5qc3RyZWUtY2hpbGRyZW4nKS5yZW1vdmUoKTtcblx0XHRcdFx0XHR0aGlzLnRyaWdnZXIoXCJhZnRlcl9jbG9zZVwiLCB7IFwibm9kZVwiIDogb2JqIH0pO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdGRcblx0XHRcdFx0XHRcdC5jaGlsZHJlbihcIi5qc3RyZWUtY2hpbGRyZW5cIikuYXR0cihcInN0eWxlXCIsXCJkaXNwbGF5OmJsb2NrICFpbXBvcnRhbnRcIikuZW5kKClcblx0XHRcdFx0XHRcdC5yZW1vdmVDbGFzcyhcImpzdHJlZS1vcGVuXCIpLmFkZENsYXNzKFwianN0cmVlLWNsb3NlZFwiKVxuXHRcdFx0XHRcdFx0XHQuY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykuYXR0cihcImFyaWEtZXhwYW5kZWRcIiwgZmFsc2UpLmVuZCgpXG5cdFx0XHRcdFx0XHQuY2hpbGRyZW4oXCIuanN0cmVlLWNoaWxkcmVuXCIpLnN0b3AodHJ1ZSwgdHJ1ZSkuc2xpZGVVcChhbmltYXRpb24sIGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5zdHlsZS5kaXNwbGF5ID0gXCJcIjtcblx0XHRcdFx0XHRcdFx0ZC5jaGlsZHJlbignLmpzdHJlZS1jaGlsZHJlbicpLnJlbW92ZSgpO1xuXHRcdFx0XHRcdFx0XHRpZiAodC5lbGVtZW50KSB7XG5cdFx0XHRcdFx0XHRcdFx0dC50cmlnZ2VyKFwiYWZ0ZXJfY2xvc2VcIiwgeyBcIm5vZGVcIiA6IG9iaiB9KTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIHRvZ2dsZXMgYSBub2RlIC0gY2xvc2luZyBpdCBpZiBpdCBpcyBvcGVuLCBvcGVuaW5nIGl0IGlmIGl0IGlzIGNsb3NlZFxuXHRcdCAqIEBuYW1lIHRvZ2dsZV9ub2RlKG9iailcblx0XHQgKiBAcGFyYW0ge21peGVkfSBvYmogdGhlIG5vZGUgdG8gdG9nZ2xlXG5cdFx0ICovXG5cdFx0dG9nZ2xlX25vZGUgOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHR2YXIgdDEsIHQyO1xuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkob2JqKSkge1xuXHRcdFx0XHRvYmogPSBvYmouc2xpY2UoKTtcblx0XHRcdFx0Zm9yKHQxID0gMCwgdDIgPSBvYmoubGVuZ3RoOyB0MSA8IHQyOyB0MSsrKSB7XG5cdFx0XHRcdFx0dGhpcy50b2dnbGVfbm9kZShvYmpbdDFdKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdGlmKHRoaXMuaXNfY2xvc2VkKG9iaikpIHtcblx0XHRcdFx0cmV0dXJuIHRoaXMub3Blbl9ub2RlKG9iaik7XG5cdFx0XHR9XG5cdFx0XHRpZih0aGlzLmlzX29wZW4ob2JqKSkge1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5jbG9zZV9ub2RlKG9iaik7XG5cdFx0XHR9XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBvcGVucyBhbGwgbm9kZXMgd2l0aGluIGEgbm9kZSAob3IgdGhlIHRyZWUpLCByZXZlYWxpbmcgdGhlaXIgY2hpbGRyZW4uIElmIHRoZSBub2RlIGlzIG5vdCBsb2FkZWQgaXQgd2lsbCBiZSBsb2FkZWQgYW5kIG9wZW5lZCBvbmNlIHJlYWR5LlxuXHRcdCAqIEBuYW1lIG9wZW5fYWxsKFtvYmosIGFuaW1hdGlvbiwgb3JpZ2luYWxfb2JqXSlcblx0XHQgKiBAcGFyYW0ge21peGVkfSBvYmogdGhlIG5vZGUgdG8gb3BlbiByZWN1cnNpdmVseSwgb21pdCB0byBvcGVuIGFsbCBub2RlcyBpbiB0aGUgdHJlZVxuXHRcdCAqIEBwYXJhbSB7TnVtYmVyfSBhbmltYXRpb24gdGhlIGFuaW1hdGlvbiBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgd2hlbiBvcGVuaW5nIHRoZSBub2RlcywgdGhlIGRlZmF1bHQgaXMgbm8gYW5pbWF0aW9uXG5cdFx0ICogQHBhcmFtIHtqUXVlcnl9IHJlZmVyZW5jZSB0byB0aGUgbm9kZSB0aGF0IHN0YXJ0ZWQgdGhlIHByb2Nlc3MgKGludGVybmFsIHVzZSlcblx0XHQgKiBAdHJpZ2dlciBvcGVuX2FsbC5qc3RyZWVcblx0XHQgKi9cblx0XHRvcGVuX2FsbCA6IGZ1bmN0aW9uIChvYmosIGFuaW1hdGlvbiwgb3JpZ2luYWxfb2JqKSB7XG5cdFx0XHRpZighb2JqKSB7IG9iaiA9ICQuanN0cmVlLnJvb3Q7IH1cblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdGlmKCFvYmopIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHR2YXIgZG9tID0gb2JqLmlkID09PSAkLmpzdHJlZS5yb290ID8gdGhpcy5nZXRfY29udGFpbmVyX3VsKCkgOiB0aGlzLmdldF9ub2RlKG9iaiwgdHJ1ZSksIGksIGosIF90aGlzO1xuXHRcdFx0aWYoIWRvbS5sZW5ndGgpIHtcblx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gb2JqLmNoaWxkcmVuX2QubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0aWYodGhpcy5pc19jbG9zZWQodGhpcy5fbW9kZWwuZGF0YVtvYmouY2hpbGRyZW5fZFtpXV0pKSB7XG5cdFx0XHRcdFx0XHR0aGlzLl9tb2RlbC5kYXRhW29iai5jaGlsZHJlbl9kW2ldXS5zdGF0ZS5vcGVuZWQgPSB0cnVlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdGhpcy50cmlnZ2VyKCdvcGVuX2FsbCcsIHsgXCJub2RlXCIgOiBvYmogfSk7XG5cdFx0XHR9XG5cdFx0XHRvcmlnaW5hbF9vYmogPSBvcmlnaW5hbF9vYmogfHwgZG9tO1xuXHRcdFx0X3RoaXMgPSB0aGlzO1xuXHRcdFx0ZG9tID0gdGhpcy5pc19jbG9zZWQob2JqKSA/IGRvbS5maW5kKCcuanN0cmVlLWNsb3NlZCcpLmFkZEJhY2soKSA6IGRvbS5maW5kKCcuanN0cmVlLWNsb3NlZCcpO1xuXHRcdFx0ZG9tLmVhY2goZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRfdGhpcy5vcGVuX25vZGUoXG5cdFx0XHRcdFx0dGhpcyxcblx0XHRcdFx0XHRmdW5jdGlvbihub2RlLCBzdGF0dXMpIHsgaWYoc3RhdHVzICYmIHRoaXMuaXNfcGFyZW50KG5vZGUpKSB7IHRoaXMub3Blbl9hbGwobm9kZSwgYW5pbWF0aW9uLCBvcmlnaW5hbF9vYmopOyB9IH0sXG5cdFx0XHRcdFx0YW5pbWF0aW9uIHx8IDBcblx0XHRcdFx0KTtcblx0XHRcdH0pO1xuXHRcdFx0aWYob3JpZ2luYWxfb2JqLmZpbmQoJy5qc3RyZWUtY2xvc2VkJykubGVuZ3RoID09PSAwKSB7XG5cdFx0XHRcdC8qKlxuXHRcdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiBhbiBgb3Blbl9hbGxgIGNhbGwgY29tcGxldGVzXG5cdFx0XHRcdCAqIEBldmVudFxuXHRcdFx0XHQgKiBAbmFtZSBvcGVuX2FsbC5qc3RyZWVcblx0XHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IG5vZGUgdGhlIG9wZW5lZCBub2RlXG5cdFx0XHRcdCAqL1xuXHRcdFx0XHR0aGlzLnRyaWdnZXIoJ29wZW5fYWxsJywgeyBcIm5vZGVcIiA6IHRoaXMuZ2V0X25vZGUob3JpZ2luYWxfb2JqKSB9KTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGNsb3NlcyBhbGwgbm9kZXMgd2l0aGluIGEgbm9kZSAob3IgdGhlIHRyZWUpLCByZXZlYWxpbmcgdGhlaXIgY2hpbGRyZW5cblx0XHQgKiBAbmFtZSBjbG9zZV9hbGwoW29iaiwgYW5pbWF0aW9uXSlcblx0XHQgKiBAcGFyYW0ge21peGVkfSBvYmogdGhlIG5vZGUgdG8gY2xvc2UgcmVjdXJzaXZlbHksIG9taXQgdG8gY2xvc2UgYWxsIG5vZGVzIGluIHRoZSB0cmVlXG5cdFx0ICogQHBhcmFtIHtOdW1iZXJ9IGFuaW1hdGlvbiB0aGUgYW5pbWF0aW9uIGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kcyB3aGVuIGNsb3NpbmcgdGhlIG5vZGVzLCB0aGUgZGVmYXVsdCBpcyBubyBhbmltYXRpb25cblx0XHQgKiBAdHJpZ2dlciBjbG9zZV9hbGwuanN0cmVlXG5cdFx0ICovXG5cdFx0Y2xvc2VfYWxsIDogZnVuY3Rpb24gKG9iaiwgYW5pbWF0aW9uKSB7XG5cdFx0XHRpZighb2JqKSB7IG9iaiA9ICQuanN0cmVlLnJvb3Q7IH1cblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdGlmKCFvYmopIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHR2YXIgZG9tID0gb2JqLmlkID09PSAkLmpzdHJlZS5yb290ID8gdGhpcy5nZXRfY29udGFpbmVyX3VsKCkgOiB0aGlzLmdldF9ub2RlKG9iaiwgdHJ1ZSksXG5cdFx0XHRcdF90aGlzID0gdGhpcywgaSwgajtcblx0XHRcdGlmKGRvbS5sZW5ndGgpIHtcblx0XHRcdFx0ZG9tID0gdGhpcy5pc19vcGVuKG9iaikgPyBkb20uZmluZCgnLmpzdHJlZS1vcGVuJykuYWRkQmFjaygpIDogZG9tLmZpbmQoJy5qc3RyZWUtb3BlbicpO1xuXHRcdFx0XHQkKGRvbS5nZXQoKS5yZXZlcnNlKCkpLmVhY2goZnVuY3Rpb24gKCkgeyBfdGhpcy5jbG9zZV9ub2RlKHRoaXMsIGFuaW1hdGlvbiB8fCAwKTsgfSk7XG5cdFx0XHR9XG5cdFx0XHRmb3IoaSA9IDAsIGogPSBvYmouY2hpbGRyZW5fZC5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0dGhpcy5fbW9kZWwuZGF0YVtvYmouY2hpbGRyZW5fZFtpXV0uc3RhdGUub3BlbmVkID0gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHQvKipcblx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGFuIGBjbG9zZV9hbGxgIGNhbGwgY29tcGxldGVzXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGNsb3NlX2FsbC5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlIHRoZSBjbG9zZWQgbm9kZVxuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ2Nsb3NlX2FsbCcsIHsgXCJub2RlXCIgOiBvYmogfSk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBjaGVja3MgaWYgYSBub2RlIGlzIGRpc2FibGVkIChub3Qgc2VsZWN0YWJsZSlcblx0XHQgKiBAbmFtZSBpc19kaXNhYmxlZChvYmopXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9ialxuXHRcdCAqIEByZXR1cm4ge0Jvb2xlYW59XG5cdFx0ICovXG5cdFx0aXNfZGlzYWJsZWQgOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRyZXR1cm4gb2JqICYmIG9iai5zdGF0ZSAmJiBvYmouc3RhdGUuZGlzYWJsZWQ7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBlbmFibGVzIGEgbm9kZSAtIHNvIHRoYXQgaXQgY2FuIGJlIHNlbGVjdGVkXG5cdFx0ICogQG5hbWUgZW5hYmxlX25vZGUob2JqKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9iaiB0aGUgbm9kZSB0byBlbmFibGVcblx0XHQgKiBAdHJpZ2dlciBlbmFibGVfbm9kZS5qc3RyZWVcblx0XHQgKi9cblx0XHRlbmFibGVfbm9kZSA6IGZ1bmN0aW9uIChvYmopIHtcblx0XHRcdHZhciB0MSwgdDI7XG5cdFx0XHRpZigkLnZha2F0YS5pc19hcnJheShvYmopKSB7XG5cdFx0XHRcdG9iaiA9IG9iai5zbGljZSgpO1xuXHRcdFx0XHRmb3IodDEgPSAwLCB0MiA9IG9iai5sZW5ndGg7IHQxIDwgdDI7IHQxKyspIHtcblx0XHRcdFx0XHR0aGlzLmVuYWJsZV9ub2RlKG9ialt0MV0pO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaiB8fCBvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0b2JqLnN0YXRlLmRpc2FibGVkID0gZmFsc2U7XG5cdFx0XHR0aGlzLmdldF9ub2RlKG9iaix0cnVlKS5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS5yZW1vdmVDbGFzcygnanN0cmVlLWRpc2FibGVkJykuYXR0cignYXJpYS1kaXNhYmxlZCcsIGZhbHNlKTtcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYW4gbm9kZSBpcyBlbmFibGVkXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGVuYWJsZV9ub2RlLmpzdHJlZVxuXHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IG5vZGUgdGhlIGVuYWJsZWQgbm9kZVxuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ2VuYWJsZV9ub2RlJywgeyAnbm9kZScgOiBvYmogfSk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBkaXNhYmxlcyBhIG5vZGUgLSBzbyB0aGF0IGl0IGNhbiBub3QgYmUgc2VsZWN0ZWRcblx0XHQgKiBAbmFtZSBkaXNhYmxlX25vZGUob2JqKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9iaiB0aGUgbm9kZSB0byBkaXNhYmxlXG5cdFx0ICogQHRyaWdnZXIgZGlzYWJsZV9ub2RlLmpzdHJlZVxuXHRcdCAqL1xuXHRcdGRpc2FibGVfbm9kZSA6IGZ1bmN0aW9uIChvYmopIHtcblx0XHRcdHZhciB0MSwgdDI7XG5cdFx0XHRpZigkLnZha2F0YS5pc19hcnJheShvYmopKSB7XG5cdFx0XHRcdG9iaiA9IG9iai5zbGljZSgpO1xuXHRcdFx0XHRmb3IodDEgPSAwLCB0MiA9IG9iai5sZW5ndGg7IHQxIDwgdDI7IHQxKyspIHtcblx0XHRcdFx0XHR0aGlzLmRpc2FibGVfbm9kZShvYmpbdDFdKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdGlmKCFvYmogfHwgb2JqLmlkID09PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdG9iai5zdGF0ZS5kaXNhYmxlZCA9IHRydWU7XG5cdFx0XHR0aGlzLmdldF9ub2RlKG9iaix0cnVlKS5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS5hZGRDbGFzcygnanN0cmVlLWRpc2FibGVkJykuYXR0cignYXJpYS1kaXNhYmxlZCcsIHRydWUpO1xuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiBhbiBub2RlIGlzIGRpc2FibGVkXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGRpc2FibGVfbm9kZS5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlIHRoZSBkaXNhYmxlZCBub2RlXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignZGlzYWJsZV9ub2RlJywgeyAnbm9kZScgOiBvYmogfSk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBkZXRlcm1pbmVzIGlmIGEgbm9kZSBpcyBoaWRkZW5cblx0XHQgKiBAbmFtZSBpc19oaWRkZW4ob2JqKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9iaiB0aGUgbm9kZVxuXHRcdCAqL1xuXHRcdGlzX2hpZGRlbiA6IGZ1bmN0aW9uIChvYmopIHtcblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdHJldHVybiBvYmouc3RhdGUuaGlkZGVuID09PSB0cnVlO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogaGlkZXMgYSBub2RlIC0gaXQgaXMgc3RpbGwgaW4gdGhlIHN0cnVjdHVyZSBidXQgd2lsbCBub3QgYmUgdmlzaWJsZVxuXHRcdCAqIEBuYW1lIGhpZGVfbm9kZShvYmopXG5cdFx0ICogQHBhcmFtIHttaXhlZH0gb2JqIHRoZSBub2RlIHRvIGhpZGVcblx0XHQgKiBAcGFyYW0ge0Jvb2xlYW59IHNraXBfcmVkcmF3IGludGVybmFsIHBhcmFtZXRlciBjb250cm9sbGluZyBpZiByZWRyYXcgaXMgY2FsbGVkXG5cdFx0ICogQHRyaWdnZXIgaGlkZV9ub2RlLmpzdHJlZVxuXHRcdCAqL1xuXHRcdGhpZGVfbm9kZSA6IGZ1bmN0aW9uIChvYmosIHNraXBfcmVkcmF3KSB7XG5cdFx0XHR2YXIgdDEsIHQyO1xuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkob2JqKSkge1xuXHRcdFx0XHRvYmogPSBvYmouc2xpY2UoKTtcblx0XHRcdFx0Zm9yKHQxID0gMCwgdDIgPSBvYmoubGVuZ3RoOyB0MSA8IHQyOyB0MSsrKSB7XG5cdFx0XHRcdFx0dGhpcy5oaWRlX25vZGUob2JqW3QxXSwgdHJ1ZSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCFza2lwX3JlZHJhdykge1xuXHRcdFx0XHRcdHRoaXMucmVkcmF3KCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqIHx8IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRpZighb2JqLnN0YXRlLmhpZGRlbikge1xuXHRcdFx0XHRvYmouc3RhdGUuaGlkZGVuID0gdHJ1ZTtcblx0XHRcdFx0dGhpcy5fbm9kZV9jaGFuZ2VkKG9iai5wYXJlbnQpO1xuXHRcdFx0XHRpZighc2tpcF9yZWRyYXcpIHtcblx0XHRcdFx0XHR0aGlzLnJlZHJhdygpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdC8qKlxuXHRcdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiBhbiBub2RlIGlzIGhpZGRlblxuXHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0ICogQG5hbWUgaGlkZV9ub2RlLmpzdHJlZVxuXHRcdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZSB0aGUgaGlkZGVuIG5vZGVcblx0XHRcdFx0ICovXG5cdFx0XHRcdHRoaXMudHJpZ2dlcignaGlkZV9ub2RlJywgeyAnbm9kZScgOiBvYmogfSk7XG5cdFx0XHR9XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBzaG93cyBhIG5vZGVcblx0XHQgKiBAbmFtZSBzaG93X25vZGUob2JqKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9iaiB0aGUgbm9kZSB0byBzaG93XG5cdFx0ICogQHBhcmFtIHtCb29sZWFufSBza2lwX3JlZHJhdyBpbnRlcm5hbCBwYXJhbWV0ZXIgY29udHJvbGxpbmcgaWYgcmVkcmF3IGlzIGNhbGxlZFxuXHRcdCAqIEB0cmlnZ2VyIHNob3dfbm9kZS5qc3RyZWVcblx0XHQgKi9cblx0XHRzaG93X25vZGUgOiBmdW5jdGlvbiAob2JqLCBza2lwX3JlZHJhdykge1xuXHRcdFx0dmFyIHQxLCB0Mjtcblx0XHRcdGlmKCQudmFrYXRhLmlzX2FycmF5KG9iaikpIHtcblx0XHRcdFx0b2JqID0gb2JqLnNsaWNlKCk7XG5cdFx0XHRcdGZvcih0MSA9IDAsIHQyID0gb2JqLmxlbmd0aDsgdDEgPCB0MjsgdDErKykge1xuXHRcdFx0XHRcdHRoaXMuc2hvd19ub2RlKG9ialt0MV0sIHRydWUpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICghc2tpcF9yZWRyYXcpIHtcblx0XHRcdFx0XHR0aGlzLnJlZHJhdygpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaiB8fCBvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0aWYob2JqLnN0YXRlLmhpZGRlbikge1xuXHRcdFx0XHRvYmouc3RhdGUuaGlkZGVuID0gZmFsc2U7XG5cdFx0XHRcdHRoaXMuX25vZGVfY2hhbmdlZChvYmoucGFyZW50KTtcblx0XHRcdFx0aWYoIXNraXBfcmVkcmF3KSB7XG5cdFx0XHRcdFx0dGhpcy5yZWRyYXcoKTtcblx0XHRcdFx0fVxuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYW4gbm9kZSBpcyBzaG93blxuXHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0ICogQG5hbWUgc2hvd19ub2RlLmpzdHJlZVxuXHRcdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZSB0aGUgc2hvd24gbm9kZVxuXHRcdFx0XHQgKi9cblx0XHRcdFx0dGhpcy50cmlnZ2VyKCdzaG93X25vZGUnLCB7ICdub2RlJyA6IG9iaiB9KTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGhpZGVzIGFsbCBub2Rlc1xuXHRcdCAqIEBuYW1lIGhpZGVfYWxsKClcblx0XHQgKiBAdHJpZ2dlciBoaWRlX2FsbC5qc3RyZWVcblx0XHQgKi9cblx0XHRoaWRlX2FsbCA6IGZ1bmN0aW9uIChza2lwX3JlZHJhdykge1xuXHRcdFx0dmFyIGksIG0gPSB0aGlzLl9tb2RlbC5kYXRhLCBpZHMgPSBbXTtcblx0XHRcdGZvcihpIGluIG0pIHtcblx0XHRcdFx0aWYobS5oYXNPd25Qcm9wZXJ0eShpKSAmJiBpICE9PSAkLmpzdHJlZS5yb290ICYmICFtW2ldLnN0YXRlLmhpZGRlbikge1xuXHRcdFx0XHRcdG1baV0uc3RhdGUuaGlkZGVuID0gdHJ1ZTtcblx0XHRcdFx0XHRpZHMucHVzaChpKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0dGhpcy5fbW9kZWwuZm9yY2VfZnVsbF9yZWRyYXcgPSB0cnVlO1xuXHRcdFx0aWYoIXNraXBfcmVkcmF3KSB7XG5cdFx0XHRcdHRoaXMucmVkcmF3KCk7XG5cdFx0XHR9XG5cdFx0XHQvKipcblx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGFsbCBub2RlcyBhcmUgaGlkZGVuXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGhpZGVfYWxsLmpzdHJlZVxuXHRcdFx0ICogQHBhcmFtIHtBcnJheX0gbm9kZXMgdGhlIElEcyBvZiBhbGwgaGlkZGVuIG5vZGVzXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignaGlkZV9hbGwnLCB7ICdub2RlcycgOiBpZHMgfSk7XG5cdFx0XHRyZXR1cm4gaWRzO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogc2hvd3MgYWxsIG5vZGVzXG5cdFx0ICogQG5hbWUgc2hvd19hbGwoKVxuXHRcdCAqIEB0cmlnZ2VyIHNob3dfYWxsLmpzdHJlZVxuXHRcdCAqL1xuXHRcdHNob3dfYWxsIDogZnVuY3Rpb24gKHNraXBfcmVkcmF3KSB7XG5cdFx0XHR2YXIgaSwgbSA9IHRoaXMuX21vZGVsLmRhdGEsIGlkcyA9IFtdO1xuXHRcdFx0Zm9yKGkgaW4gbSkge1xuXHRcdFx0XHRpZihtLmhhc093blByb3BlcnR5KGkpICYmIGkgIT09ICQuanN0cmVlLnJvb3QgJiYgbVtpXS5zdGF0ZS5oaWRkZW4pIHtcblx0XHRcdFx0XHRtW2ldLnN0YXRlLmhpZGRlbiA9IGZhbHNlO1xuXHRcdFx0XHRcdGlkcy5wdXNoKGkpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9tb2RlbC5mb3JjZV9mdWxsX3JlZHJhdyA9IHRydWU7XG5cdFx0XHRpZighc2tpcF9yZWRyYXcpIHtcblx0XHRcdFx0dGhpcy5yZWRyYXcoKTtcblx0XHRcdH1cblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYWxsIG5vZGVzIGFyZSBzaG93blxuXHRcdFx0ICogQGV2ZW50XG5cdFx0XHQgKiBAbmFtZSBzaG93X2FsbC5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7QXJyYXl9IG5vZGVzIHRoZSBJRHMgb2YgYWxsIHNob3duIG5vZGVzXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignc2hvd19hbGwnLCB7ICdub2RlcycgOiBpZHMgfSk7XG5cdFx0XHRyZXR1cm4gaWRzO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogY2FsbGVkIHdoZW4gYSBub2RlIGlzIHNlbGVjdGVkIGJ5IHRoZSB1c2VyLiBVc2VkIGludGVybmFsbHkuXG5cdFx0ICogQHByaXZhdGVcblx0XHQgKiBAbmFtZSBhY3RpdmF0ZV9ub2RlKG9iaiwgZSlcblx0XHQgKiBAcGFyYW0ge21peGVkfSBvYmogdGhlIG5vZGVcblx0XHQgKiBAcGFyYW0ge09iamVjdH0gZSB0aGUgcmVsYXRlZCBldmVudFxuXHRcdCAqIEB0cmlnZ2VyIGFjdGl2YXRlX25vZGUuanN0cmVlLCBjaGFuZ2VkLmpzdHJlZVxuXHRcdCAqL1xuXHRcdGFjdGl2YXRlX25vZGUgOiBmdW5jdGlvbiAob2JqLCBlKSB7XG5cdFx0XHRpZih0aGlzLmlzX2Rpc2FibGVkKG9iaikpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0aWYoIWUgfHwgdHlwZW9mIGUgIT09ICdvYmplY3QnKSB7XG5cdFx0XHRcdGUgPSB7fTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gZW5zdXJlIGxhc3RfY2xpY2tlZCBpcyBzdGlsbCBpbiB0aGUgRE9NLCBtYWtlIGl0IGZyZXNoIChtYXliZSBpdCB3YXMgbW92ZWQ/KSBhbmQgbWFrZSBzdXJlIGl0IGlzIHN0aWxsIHNlbGVjdGVkLCBpZiBub3QgLSBtYWtlIGxhc3RfY2xpY2tlZCB0aGUgbGFzdCBzZWxlY3RlZCBub2RlXG5cdFx0XHR0aGlzLl9kYXRhLmNvcmUubGFzdF9jbGlja2VkID0gdGhpcy5fZGF0YS5jb3JlLmxhc3RfY2xpY2tlZCAmJiB0aGlzLl9kYXRhLmNvcmUubGFzdF9jbGlja2VkLmlkICE9PSB1bmRlZmluZWQgPyB0aGlzLmdldF9ub2RlKHRoaXMuX2RhdGEuY29yZS5sYXN0X2NsaWNrZWQuaWQpIDogbnVsbDtcblx0XHRcdGlmKHRoaXMuX2RhdGEuY29yZS5sYXN0X2NsaWNrZWQgJiYgIXRoaXMuX2RhdGEuY29yZS5sYXN0X2NsaWNrZWQuc3RhdGUuc2VsZWN0ZWQpIHsgdGhpcy5fZGF0YS5jb3JlLmxhc3RfY2xpY2tlZCA9IG51bGw7IH1cblx0XHRcdGlmKCF0aGlzLl9kYXRhLmNvcmUubGFzdF9jbGlja2VkICYmIHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZC5sZW5ndGgpIHsgdGhpcy5fZGF0YS5jb3JlLmxhc3RfY2xpY2tlZCA9IHRoaXMuZ2V0X25vZGUodGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkW3RoaXMuX2RhdGEuY29yZS5zZWxlY3RlZC5sZW5ndGggLSAxXSk7IH1cblxuXHRcdFx0aWYoIXRoaXMuc2V0dGluZ3MuY29yZS5tdWx0aXBsZSB8fCAoIWUubWV0YUtleSAmJiAhZS5jdHJsS2V5ICYmICFlLnNoaWZ0S2V5KSB8fCAoZS5zaGlmdEtleSAmJiAoIXRoaXMuX2RhdGEuY29yZS5sYXN0X2NsaWNrZWQgfHwgIXRoaXMuZ2V0X3BhcmVudChvYmopIHx8IHRoaXMuZ2V0X3BhcmVudChvYmopICE9PSB0aGlzLl9kYXRhLmNvcmUubGFzdF9jbGlja2VkLnBhcmVudCApICkpIHtcblx0XHRcdFx0aWYoIXRoaXMuc2V0dGluZ3MuY29yZS5tdWx0aXBsZSAmJiAoZS5tZXRhS2V5IHx8IGUuY3RybEtleSB8fCBlLnNoaWZ0S2V5KSAmJiB0aGlzLmlzX3NlbGVjdGVkKG9iaikpIHtcblx0XHRcdFx0XHR0aGlzLmRlc2VsZWN0X25vZGUob2JqLCBmYWxzZSwgZSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0dGhpcy5kZXNlbGVjdF9hbGwodHJ1ZSk7XG5cdFx0XHRcdFx0dGhpcy5zZWxlY3Rfbm9kZShvYmosIGZhbHNlLCBmYWxzZSwgZSk7XG5cdFx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLmxhc3RfY2xpY2tlZCA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0ZWxzZSB7XG5cdFx0XHRcdGlmKGUuc2hpZnRLZXkpIHtcblx0XHRcdFx0XHR2YXIgbyA9IHRoaXMuZ2V0X25vZGUob2JqKS5pZCxcblx0XHRcdFx0XHRcdGwgPSB0aGlzLl9kYXRhLmNvcmUubGFzdF9jbGlja2VkLmlkLFxuXHRcdFx0XHRcdFx0cCA9IHRoaXMuZ2V0X25vZGUodGhpcy5fZGF0YS5jb3JlLmxhc3RfY2xpY2tlZC5wYXJlbnQpLmNoaWxkcmVuLFxuXHRcdFx0XHRcdFx0YyA9IGZhbHNlLFxuXHRcdFx0XHRcdFx0aSwgajtcblx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSBwLmxlbmd0aDsgaSA8IGo7IGkgKz0gMSkge1xuXHRcdFx0XHRcdFx0Ly8gc2VwYXJhdGUgSUZzIHdvcmsgd2hlbSBvIGFuZCBsIGFyZSB0aGUgc2FtZVxuXHRcdFx0XHRcdFx0aWYocFtpXSA9PT0gbykge1xuXHRcdFx0XHRcdFx0XHRjID0gIWM7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRpZihwW2ldID09PSBsKSB7XG5cdFx0XHRcdFx0XHRcdGMgPSAhYztcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmKCF0aGlzLmlzX2Rpc2FibGVkKHBbaV0pICYmIChjIHx8IHBbaV0gPT09IG8gfHwgcFtpXSA9PT0gbCkpIHtcblx0XHRcdFx0XHRcdFx0aWYgKCF0aGlzLmlzX2hpZGRlbihwW2ldKSkge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuc2VsZWN0X25vZGUocFtpXSwgdHJ1ZSwgZmFsc2UsIGUpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5kZXNlbGVjdF9ub2RlKHBbaV0sIHRydWUsIGUpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHR0aGlzLnRyaWdnZXIoJ2NoYW5nZWQnLCB7ICdhY3Rpb24nIDogJ3NlbGVjdF9ub2RlJywgJ25vZGUnIDogdGhpcy5nZXRfbm9kZShvYmopLCAnc2VsZWN0ZWQnIDogdGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkLCAnZXZlbnQnIDogZSB9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRpZighdGhpcy5pc19zZWxlY3RlZChvYmopKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnNlbGVjdF9ub2RlKG9iaiwgZmFsc2UsIGZhbHNlLCBlKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHR0aGlzLmRlc2VsZWN0X25vZGUob2JqLCBmYWxzZSwgZSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHQvKipcblx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGFuIG5vZGUgaXMgY2xpY2tlZCBvciBpbnRlcmNhdGVkIHdpdGggYnkgdGhlIHVzZXJcblx0XHRcdCAqIEBldmVudFxuXHRcdFx0ICogQG5hbWUgYWN0aXZhdGVfbm9kZS5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlXG5cdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gZXZlbnQgdGhlIG9vcmlnaW5hbCBldmVudCAoaWYgYW55KSB3aGljaCB0cmlnZ2VyZWQgdGhlIGNhbGwgKG1heSBiZSBhbiBlbXB0eSBvYmplY3QpXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignYWN0aXZhdGVfbm9kZScsIHsgJ25vZGUnIDogdGhpcy5nZXRfbm9kZShvYmopLCAnZXZlbnQnIDogZSB9KTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGFwcGxpZXMgdGhlIGhvdmVyIHN0YXRlIG9uIGEgbm9kZSwgY2FsbGVkIHdoZW4gYSBub2RlIGlzIGhvdmVyZWQgYnkgdGhlIHVzZXIuIFVzZWQgaW50ZXJuYWxseS5cblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEBuYW1lIGhvdmVyX25vZGUob2JqKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9ialxuXHRcdCAqIEB0cmlnZ2VyIGhvdmVyX25vZGUuanN0cmVlXG5cdFx0ICovXG5cdFx0aG92ZXJfbm9kZSA6IGZ1bmN0aW9uIChvYmopIHtcblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqLCB0cnVlKTtcblx0XHRcdGlmKCFvYmogfHwgIW9iai5sZW5ndGggfHwgb2JqLmNoaWxkcmVuKCcuanN0cmVlLWhvdmVyZWQnKS5sZW5ndGgpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0dmFyIG8gPSB0aGlzLmVsZW1lbnQuZmluZCgnLmpzdHJlZS1ob3ZlcmVkJyksIHQgPSB0aGlzLmVsZW1lbnQ7XG5cdFx0XHRpZihvICYmIG8ubGVuZ3RoKSB7IHRoaXMuZGVob3Zlcl9ub2RlKG8pOyB9XG5cblx0XHRcdG9iai5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS5hZGRDbGFzcygnanN0cmVlLWhvdmVyZWQnKTtcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYW4gbm9kZSBpcyBob3ZlcmVkXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGhvdmVyX25vZGUuanN0cmVlXG5cdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZVxuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ2hvdmVyX25vZGUnLCB7ICdub2RlJyA6IHRoaXMuZ2V0X25vZGUob2JqKSB9KTtcblx0XHRcdHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyB0LmF0dHIoJ2FyaWEtYWN0aXZlZGVzY2VuZGFudCcsIG9ialswXS5pZCk7IH0sIDApO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogcmVtb3ZlcyB0aGUgaG92ZXIgc3RhdGUgZnJvbSBhIG5vZGVjYWxsZWQgd2hlbiBhIG5vZGUgaXMgbm8gbG9uZ2VyIGhvdmVyZWQgYnkgdGhlIHVzZXIuIFVzZWQgaW50ZXJuYWxseS5cblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEBuYW1lIGRlaG92ZXJfbm9kZShvYmopXG5cdFx0ICogQHBhcmFtIHttaXhlZH0gb2JqXG5cdFx0ICogQHRyaWdnZXIgZGVob3Zlcl9ub2RlLmpzdHJlZVxuXHRcdCAqL1xuXHRcdGRlaG92ZXJfbm9kZSA6IGZ1bmN0aW9uIChvYmopIHtcblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqLCB0cnVlKTtcblx0XHRcdGlmKCFvYmogfHwgIW9iai5sZW5ndGggfHwgIW9iai5jaGlsZHJlbignLmpzdHJlZS1ob3ZlcmVkJykubGVuZ3RoKSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdG9iai5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS5yZW1vdmVDbGFzcygnanN0cmVlLWhvdmVyZWQnKTtcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYW4gbm9kZSBpcyBubyBsb25nZXIgaG92ZXJlZFxuXHRcdFx0ICogQGV2ZW50XG5cdFx0XHQgKiBAbmFtZSBkZWhvdmVyX25vZGUuanN0cmVlXG5cdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZVxuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ2RlaG92ZXJfbm9kZScsIHsgJ25vZGUnIDogdGhpcy5nZXRfbm9kZShvYmopIH0pO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogc2VsZWN0IGEgbm9kZVxuXHRcdCAqIEBuYW1lIHNlbGVjdF9ub2RlKG9iaiBbLCBzdXByZXNzX2V2ZW50LCBwcmV2ZW50X29wZW5dKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9iaiBhbiBhcnJheSBjYW4gYmUgdXNlZCB0byBzZWxlY3QgbXVsdGlwbGUgbm9kZXNcblx0XHQgKiBAcGFyYW0ge0Jvb2xlYW59IHN1cHJlc3NfZXZlbnQgaWYgc2V0IHRvIGB0cnVlYCB0aGUgYGNoYW5nZWQuanN0cmVlYCBldmVudCB3b24ndCBiZSB0cmlnZ2VyZWRcblx0XHQgKiBAcGFyYW0ge0Jvb2xlYW59IHByZXZlbnRfb3BlbiBpZiBzZXQgdG8gYHRydWVgIHBhcmVudHMgb2YgdGhlIHNlbGVjdGVkIG5vZGUgd29uJ3QgYmUgb3BlbmVkXG5cdFx0ICogQHRyaWdnZXIgc2VsZWN0X25vZGUuanN0cmVlLCBjaGFuZ2VkLmpzdHJlZVxuXHRcdCAqL1xuXHRcdHNlbGVjdF9ub2RlIDogZnVuY3Rpb24gKG9iaiwgc3VwcmVzc19ldmVudCwgcHJldmVudF9vcGVuLCBlKSB7XG5cdFx0XHR2YXIgZG9tLCB0MSwgdDIsIHRoO1xuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkob2JqKSkge1xuXHRcdFx0XHRvYmogPSBvYmouc2xpY2UoKTtcblx0XHRcdFx0Zm9yKHQxID0gMCwgdDIgPSBvYmoubGVuZ3RoOyB0MSA8IHQyOyB0MSsrKSB7XG5cdFx0XHRcdFx0dGhpcy5zZWxlY3Rfbm9kZShvYmpbdDFdLCBzdXByZXNzX2V2ZW50LCBwcmV2ZW50X29wZW4sIGUpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaiB8fCBvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0ZG9tID0gdGhpcy5nZXRfbm9kZShvYmosIHRydWUpO1xuXHRcdFx0aWYoIW9iai5zdGF0ZS5zZWxlY3RlZCkge1xuXHRcdFx0XHRvYmouc3RhdGUuc2VsZWN0ZWQgPSB0cnVlO1xuXHRcdFx0XHR0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQucHVzaChvYmouaWQpO1xuXHRcdFx0XHRpZighcHJldmVudF9vcGVuKSB7XG5cdFx0XHRcdFx0ZG9tID0gdGhpcy5fb3Blbl90byhvYmopO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKGRvbSAmJiBkb20ubGVuZ3RoKSB7XG5cdFx0XHRcdFx0ZG9tLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLmFkZENsYXNzKCdqc3RyZWUtY2xpY2tlZCcpLmF0dHIoJ2FyaWEtc2VsZWN0ZWQnLCB0cnVlKTtcblx0XHRcdFx0fVxuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYW4gbm9kZSBpcyBzZWxlY3RlZFxuXHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0ICogQG5hbWUgc2VsZWN0X25vZGUuanN0cmVlXG5cdFx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlXG5cdFx0XHRcdCAqIEBwYXJhbSB7QXJyYXl9IHNlbGVjdGVkIHRoZSBjdXJyZW50IHNlbGVjdGlvblxuXHRcdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gZXZlbnQgdGhlIGV2ZW50IChpZiBhbnkpIHRoYXQgdHJpZ2dlcmVkIHRoaXMgc2VsZWN0X25vZGVcblx0XHRcdFx0ICovXG5cdFx0XHRcdHRoaXMudHJpZ2dlcignc2VsZWN0X25vZGUnLCB7ICdub2RlJyA6IG9iaiwgJ3NlbGVjdGVkJyA6IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZCwgJ2V2ZW50JyA6IGUgfSk7XG5cdFx0XHRcdGlmKCFzdXByZXNzX2V2ZW50KSB7XG5cdFx0XHRcdFx0LyoqXG5cdFx0XHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gc2VsZWN0aW9uIGNoYW5nZXNcblx0XHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0XHQgKiBAbmFtZSBjaGFuZ2VkLmpzdHJlZVxuXHRcdFx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlXG5cdFx0XHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IGFjdGlvbiB0aGUgYWN0aW9uIHRoYXQgY2F1c2VkIHRoZSBzZWxlY3Rpb24gdG8gY2hhbmdlXG5cdFx0XHRcdFx0ICogQHBhcmFtIHtBcnJheX0gc2VsZWN0ZWQgdGhlIGN1cnJlbnQgc2VsZWN0aW9uXG5cdFx0XHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IGV2ZW50IHRoZSBldmVudCAoaWYgYW55KSB0aGF0IHRyaWdnZXJlZCB0aGlzIGNoYW5nZWQgZXZlbnRcblx0XHRcdFx0XHQgKi9cblx0XHRcdFx0XHR0aGlzLnRyaWdnZXIoJ2NoYW5nZWQnLCB7ICdhY3Rpb24nIDogJ3NlbGVjdF9ub2RlJywgJ25vZGUnIDogb2JqLCAnc2VsZWN0ZWQnIDogdGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkLCAnZXZlbnQnIDogZSB9KTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogZGVzZWxlY3QgYSBub2RlXG5cdFx0ICogQG5hbWUgZGVzZWxlY3Rfbm9kZShvYmogWywgc3VwcmVzc19ldmVudF0pXG5cdFx0ICogQHBhcmFtIHttaXhlZH0gb2JqIGFuIGFycmF5IGNhbiBiZSB1c2VkIHRvIGRlc2VsZWN0IG11bHRpcGxlIG5vZGVzXG5cdFx0ICogQHBhcmFtIHtCb29sZWFufSBzdXByZXNzX2V2ZW50IGlmIHNldCB0byBgdHJ1ZWAgdGhlIGBjaGFuZ2VkLmpzdHJlZWAgZXZlbnQgd29uJ3QgYmUgdHJpZ2dlcmVkXG5cdFx0ICogQHRyaWdnZXIgZGVzZWxlY3Rfbm9kZS5qc3RyZWUsIGNoYW5nZWQuanN0cmVlXG5cdFx0ICovXG5cdFx0ZGVzZWxlY3Rfbm9kZSA6IGZ1bmN0aW9uIChvYmosIHN1cHJlc3NfZXZlbnQsIGUpIHtcblx0XHRcdHZhciB0MSwgdDIsIGRvbTtcblx0XHRcdGlmKCQudmFrYXRhLmlzX2FycmF5KG9iaikpIHtcblx0XHRcdFx0b2JqID0gb2JqLnNsaWNlKCk7XG5cdFx0XHRcdGZvcih0MSA9IDAsIHQyID0gb2JqLmxlbmd0aDsgdDEgPCB0MjsgdDErKykge1xuXHRcdFx0XHRcdHRoaXMuZGVzZWxlY3Rfbm9kZShvYmpbdDFdLCBzdXByZXNzX2V2ZW50LCBlKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdGlmKCFvYmogfHwgb2JqLmlkID09PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdGRvbSA9IHRoaXMuZ2V0X25vZGUob2JqLCB0cnVlKTtcblx0XHRcdGlmKG9iai5zdGF0ZS5zZWxlY3RlZCkge1xuXHRcdFx0XHRvYmouc3RhdGUuc2VsZWN0ZWQgPSBmYWxzZTtcblx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkID0gJC52YWthdGEuYXJyYXlfcmVtb3ZlX2l0ZW0odGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkLCBvYmouaWQpO1xuXHRcdFx0XHRpZihkb20ubGVuZ3RoKSB7XG5cdFx0XHRcdFx0ZG9tLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLnJlbW92ZUNsYXNzKCdqc3RyZWUtY2xpY2tlZCcpLmF0dHIoJ2FyaWEtc2VsZWN0ZWQnLCBmYWxzZSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0LyoqXG5cdFx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGFuIG5vZGUgaXMgZGVzZWxlY3RlZFxuXHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0ICogQG5hbWUgZGVzZWxlY3Rfbm9kZS5qc3RyZWVcblx0XHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IG5vZGVcblx0XHRcdFx0ICogQHBhcmFtIHtBcnJheX0gc2VsZWN0ZWQgdGhlIGN1cnJlbnQgc2VsZWN0aW9uXG5cdFx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBldmVudCB0aGUgZXZlbnQgKGlmIGFueSkgdGhhdCB0cmlnZ2VyZWQgdGhpcyBkZXNlbGVjdF9ub2RlXG5cdFx0XHRcdCAqL1xuXHRcdFx0XHR0aGlzLnRyaWdnZXIoJ2Rlc2VsZWN0X25vZGUnLCB7ICdub2RlJyA6IG9iaiwgJ3NlbGVjdGVkJyA6IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZCwgJ2V2ZW50JyA6IGUgfSk7XG5cdFx0XHRcdGlmKCFzdXByZXNzX2V2ZW50KSB7XG5cdFx0XHRcdFx0dGhpcy50cmlnZ2VyKCdjaGFuZ2VkJywgeyAnYWN0aW9uJyA6ICdkZXNlbGVjdF9ub2RlJywgJ25vZGUnIDogb2JqLCAnc2VsZWN0ZWQnIDogdGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkLCAnZXZlbnQnIDogZSB9KTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogc2VsZWN0IGFsbCBub2RlcyBpbiB0aGUgdHJlZVxuXHRcdCAqIEBuYW1lIHNlbGVjdF9hbGwoW3N1cHJlc3NfZXZlbnRdKVxuXHRcdCAqIEBwYXJhbSB7Qm9vbGVhbn0gc3VwcmVzc19ldmVudCBpZiBzZXQgdG8gYHRydWVgIHRoZSBgY2hhbmdlZC5qc3RyZWVgIGV2ZW50IHdvbid0IGJlIHRyaWdnZXJlZFxuXHRcdCAqIEB0cmlnZ2VyIHNlbGVjdF9hbGwuanN0cmVlLCBjaGFuZ2VkLmpzdHJlZVxuXHRcdCAqL1xuXHRcdHNlbGVjdF9hbGwgOiBmdW5jdGlvbiAoc3VwcmVzc19ldmVudCkge1xuXHRcdFx0dmFyIHRtcCA9IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZC5jb25jYXQoW10pLCBpLCBqO1xuXHRcdFx0dGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkID0gdGhpcy5fbW9kZWwuZGF0YVskLmpzdHJlZS5yb290XS5jaGlsZHJlbl9kLmNvbmNhdCgpO1xuXHRcdFx0Zm9yKGkgPSAwLCBqID0gdGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRpZih0aGlzLl9tb2RlbC5kYXRhW3RoaXMuX2RhdGEuY29yZS5zZWxlY3RlZFtpXV0pIHtcblx0XHRcdFx0XHR0aGlzLl9tb2RlbC5kYXRhW3RoaXMuX2RhdGEuY29yZS5zZWxlY3RlZFtpXV0uc3RhdGUuc2VsZWN0ZWQgPSB0cnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHR0aGlzLnJlZHJhdyh0cnVlKTtcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYWxsIG5vZGVzIGFyZSBzZWxlY3RlZFxuXHRcdFx0ICogQGV2ZW50XG5cdFx0XHQgKiBAbmFtZSBzZWxlY3RfYWxsLmpzdHJlZVxuXHRcdFx0ICogQHBhcmFtIHtBcnJheX0gc2VsZWN0ZWQgdGhlIGN1cnJlbnQgc2VsZWN0aW9uXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignc2VsZWN0X2FsbCcsIHsgJ3NlbGVjdGVkJyA6IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZCB9KTtcblx0XHRcdGlmKCFzdXByZXNzX2V2ZW50KSB7XG5cdFx0XHRcdHRoaXMudHJpZ2dlcignY2hhbmdlZCcsIHsgJ2FjdGlvbicgOiAnc2VsZWN0X2FsbCcsICdzZWxlY3RlZCcgOiB0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQsICdvbGRfc2VsZWN0aW9uJyA6IHRtcCB9KTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGRlc2VsZWN0IGFsbCBzZWxlY3RlZCBub2Rlc1xuXHRcdCAqIEBuYW1lIGRlc2VsZWN0X2FsbChbc3VwcmVzc19ldmVudF0pXG5cdFx0ICogQHBhcmFtIHtCb29sZWFufSBzdXByZXNzX2V2ZW50IGlmIHNldCB0byBgdHJ1ZWAgdGhlIGBjaGFuZ2VkLmpzdHJlZWAgZXZlbnQgd29uJ3QgYmUgdHJpZ2dlcmVkXG5cdFx0ICogQHRyaWdnZXIgZGVzZWxlY3RfYWxsLmpzdHJlZSwgY2hhbmdlZC5qc3RyZWVcblx0XHQgKi9cblx0XHRkZXNlbGVjdF9hbGwgOiBmdW5jdGlvbiAoc3VwcmVzc19ldmVudCkge1xuXHRcdFx0dmFyIHRtcCA9IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZC5jb25jYXQoW10pLCBpLCBqO1xuXHRcdFx0Zm9yKGkgPSAwLCBqID0gdGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRpZih0aGlzLl9tb2RlbC5kYXRhW3RoaXMuX2RhdGEuY29yZS5zZWxlY3RlZFtpXV0pIHtcblx0XHRcdFx0XHR0aGlzLl9tb2RlbC5kYXRhW3RoaXMuX2RhdGEuY29yZS5zZWxlY3RlZFtpXV0uc3RhdGUuc2VsZWN0ZWQgPSBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0dGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkID0gW107XG5cdFx0XHR0aGlzLmVsZW1lbnQuZmluZCgnLmpzdHJlZS1jbGlja2VkJykucmVtb3ZlQ2xhc3MoJ2pzdHJlZS1jbGlja2VkJykuYXR0cignYXJpYS1zZWxlY3RlZCcsIGZhbHNlKTtcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYWxsIG5vZGVzIGFyZSBkZXNlbGVjdGVkXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGRlc2VsZWN0X2FsbC5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlIHRoZSBwcmV2aW91cyBzZWxlY3Rpb25cblx0XHRcdCAqIEBwYXJhbSB7QXJyYXl9IHNlbGVjdGVkIHRoZSBjdXJyZW50IHNlbGVjdGlvblxuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ2Rlc2VsZWN0X2FsbCcsIHsgJ3NlbGVjdGVkJyA6IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZCwgJ25vZGUnIDogdG1wIH0pO1xuXHRcdFx0aWYoIXN1cHJlc3NfZXZlbnQpIHtcblx0XHRcdFx0dGhpcy50cmlnZ2VyKCdjaGFuZ2VkJywgeyAnYWN0aW9uJyA6ICdkZXNlbGVjdF9hbGwnLCAnc2VsZWN0ZWQnIDogdGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkLCAnb2xkX3NlbGVjdGlvbicgOiB0bXAgfSk7XG5cdFx0XHR9XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBjaGVja3MgaWYgYSBub2RlIGlzIHNlbGVjdGVkXG5cdFx0ICogQG5hbWUgaXNfc2VsZWN0ZWQob2JqKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSAgb2JqXG5cdFx0ICogQHJldHVybiB7Qm9vbGVhbn1cblx0XHQgKi9cblx0XHRpc19zZWxlY3RlZCA6IGZ1bmN0aW9uIChvYmopIHtcblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdGlmKCFvYmogfHwgb2JqLmlkID09PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBvYmouc3RhdGUuc2VsZWN0ZWQ7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBnZXQgYW4gYXJyYXkgb2YgYWxsIHNlbGVjdGVkIG5vZGVzXG5cdFx0ICogQG5hbWUgZ2V0X3NlbGVjdGVkKFtmdWxsXSlcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gIGZ1bGwgaWYgc2V0IHRvIGB0cnVlYCB0aGUgcmV0dXJuZWQgYXJyYXkgd2lsbCBjb25zaXN0IG9mIHRoZSBmdWxsIG5vZGUgb2JqZWN0cywgb3RoZXJ3aXNlIC0gb25seSBJRHMgd2lsbCBiZSByZXR1cm5lZFxuXHRcdCAqIEByZXR1cm4ge0FycmF5fVxuXHRcdCAqL1xuXHRcdGdldF9zZWxlY3RlZCA6IGZ1bmN0aW9uIChmdWxsKSB7XG5cdFx0XHRyZXR1cm4gZnVsbCA/ICQubWFwKHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZCwgZnVuY3Rpb24gKGkpIHsgcmV0dXJuIHRoaXMuZ2V0X25vZGUoaSk7IH0uYmluZCh0aGlzKSkgOiB0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQuc2xpY2UoKTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGdldCBhbiBhcnJheSBvZiBhbGwgdG9wIGxldmVsIHNlbGVjdGVkIG5vZGVzIChpZ25vcmluZyBjaGlsZHJlbiBvZiBzZWxlY3RlZCBub2Rlcylcblx0XHQgKiBAbmFtZSBnZXRfdG9wX3NlbGVjdGVkKFtmdWxsXSlcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gIGZ1bGwgaWYgc2V0IHRvIGB0cnVlYCB0aGUgcmV0dXJuZWQgYXJyYXkgd2lsbCBjb25zaXN0IG9mIHRoZSBmdWxsIG5vZGUgb2JqZWN0cywgb3RoZXJ3aXNlIC0gb25seSBJRHMgd2lsbCBiZSByZXR1cm5lZFxuXHRcdCAqIEByZXR1cm4ge0FycmF5fVxuXHRcdCAqL1xuXHRcdGdldF90b3Bfc2VsZWN0ZWQgOiBmdW5jdGlvbiAoZnVsbCkge1xuXHRcdFx0dmFyIHRtcCA9IHRoaXMuZ2V0X3NlbGVjdGVkKHRydWUpLFxuXHRcdFx0XHRvYmogPSB7fSwgaSwgaiwgaywgbDtcblx0XHRcdGZvcihpID0gMCwgaiA9IHRtcC5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0b2JqW3RtcFtpXS5pZF0gPSB0bXBbaV07XG5cdFx0XHR9XG5cdFx0XHRmb3IoaSA9IDAsIGogPSB0bXAubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdGZvcihrID0gMCwgbCA9IHRtcFtpXS5jaGlsZHJlbl9kLmxlbmd0aDsgayA8IGw7IGsrKykge1xuXHRcdFx0XHRcdGlmKG9ialt0bXBbaV0uY2hpbGRyZW5fZFtrXV0pIHtcblx0XHRcdFx0XHRcdGRlbGV0ZSBvYmpbdG1wW2ldLmNoaWxkcmVuX2Rba11dO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0dG1wID0gW107XG5cdFx0XHRmb3IoaSBpbiBvYmopIHtcblx0XHRcdFx0aWYob2JqLmhhc093blByb3BlcnR5KGkpKSB7XG5cdFx0XHRcdFx0dG1wLnB1c2goaSk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiBmdWxsID8gJC5tYXAodG1wLCBmdW5jdGlvbiAoaSkgeyByZXR1cm4gdGhpcy5nZXRfbm9kZShpKTsgfS5iaW5kKHRoaXMpKSA6IHRtcDtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGdldCBhbiBhcnJheSBvZiBhbGwgYm90dG9tIGxldmVsIHNlbGVjdGVkIG5vZGVzIChpZ25vcmluZyBzZWxlY3RlZCBwYXJlbnRzKVxuXHRcdCAqIEBuYW1lIGdldF9ib3R0b21fc2VsZWN0ZWQoW2Z1bGxdKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSAgZnVsbCBpZiBzZXQgdG8gYHRydWVgIHRoZSByZXR1cm5lZCBhcnJheSB3aWxsIGNvbnNpc3Qgb2YgdGhlIGZ1bGwgbm9kZSBvYmplY3RzLCBvdGhlcndpc2UgLSBvbmx5IElEcyB3aWxsIGJlIHJldHVybmVkXG5cdFx0ICogQHJldHVybiB7QXJyYXl9XG5cdFx0ICovXG5cdFx0Z2V0X2JvdHRvbV9zZWxlY3RlZCA6IGZ1bmN0aW9uIChmdWxsKSB7XG5cdFx0XHR2YXIgdG1wID0gdGhpcy5nZXRfc2VsZWN0ZWQodHJ1ZSksXG5cdFx0XHRcdG9iaiA9IFtdLCBpLCBqO1xuXHRcdFx0Zm9yKGkgPSAwLCBqID0gdG1wLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRpZighdG1wW2ldLmNoaWxkcmVuLmxlbmd0aCkge1xuXHRcdFx0XHRcdG9iai5wdXNoKHRtcFtpXS5pZCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiBmdWxsID8gJC5tYXAob2JqLCBmdW5jdGlvbiAoaSkgeyByZXR1cm4gdGhpcy5nZXRfbm9kZShpKTsgfS5iaW5kKHRoaXMpKSA6IG9iajtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGdldHMgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHRyZWUgc28gdGhhdCBpdCBjYW4gYmUgcmVzdG9yZWQgbGF0ZXIgd2l0aCBgc2V0X3N0YXRlKHN0YXRlKWAuIFVzZWQgaW50ZXJuYWxseS5cblx0XHQgKiBAbmFtZSBnZXRfc3RhdGUoKVxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICogQHJldHVybiB7T2JqZWN0fVxuXHRcdCAqL1xuXHRcdGdldF9zdGF0ZSA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHZhciBzdGF0ZVx0PSB7XG5cdFx0XHRcdCdjb3JlJyA6IHtcblx0XHRcdFx0XHQnb3BlbicgOiBbXSxcblx0XHRcdFx0XHQnbG9hZGVkJyA6IFtdLFxuXHRcdFx0XHRcdCdzY3JvbGwnIDoge1xuXHRcdFx0XHRcdFx0J2xlZnQnIDogdGhpcy5lbGVtZW50LnNjcm9sbExlZnQoKSxcblx0XHRcdFx0XHRcdCd0b3AnIDogdGhpcy5lbGVtZW50LnNjcm9sbFRvcCgpXG5cdFx0XHRcdFx0fSxcblx0XHRcdFx0XHQvKiFcblx0XHRcdFx0XHQndGhlbWVzJyA6IHtcblx0XHRcdFx0XHRcdCduYW1lJyA6IHRoaXMuZ2V0X3RoZW1lKCksXG5cdFx0XHRcdFx0XHQnaWNvbnMnIDogdGhpcy5fZGF0YS5jb3JlLnRoZW1lcy5pY29ucyxcblx0XHRcdFx0XHRcdCdkb3RzJyA6IHRoaXMuX2RhdGEuY29yZS50aGVtZXMuZG90c1xuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0Ki9cblx0XHRcdFx0XHQnc2VsZWN0ZWQnIDogW11cblx0XHRcdFx0fVxuXHRcdFx0fSwgaTtcblx0XHRcdGZvcihpIGluIHRoaXMuX21vZGVsLmRhdGEpIHtcblx0XHRcdFx0aWYodGhpcy5fbW9kZWwuZGF0YS5oYXNPd25Qcm9wZXJ0eShpKSkge1xuXHRcdFx0XHRcdGlmKGkgIT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0XHRcdGlmKHRoaXMuX21vZGVsLmRhdGFbaV0uc3RhdGUubG9hZGVkICYmIHRoaXMuc2V0dGluZ3MuY29yZS5sb2FkZWRfc3RhdGUpIHtcblx0XHRcdFx0XHRcdFx0c3RhdGUuY29yZS5sb2FkZWQucHVzaChpKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmKHRoaXMuX21vZGVsLmRhdGFbaV0uc3RhdGUub3BlbmVkKSB7XG5cdFx0XHRcdFx0XHRcdHN0YXRlLmNvcmUub3Blbi5wdXNoKGkpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYodGhpcy5fbW9kZWwuZGF0YVtpXS5zdGF0ZS5zZWxlY3RlZCkge1xuXHRcdFx0XHRcdFx0XHRzdGF0ZS5jb3JlLnNlbGVjdGVkLnB1c2goaSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gc3RhdGU7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBzZXRzIHRoZSBzdGF0ZSBvZiB0aGUgdHJlZS4gVXNlZCBpbnRlcm5hbGx5LlxuXHRcdCAqIEBuYW1lIHNldF9zdGF0ZShzdGF0ZSBbLCBjYWxsYmFja10pXG5cdFx0ICogQHByaXZhdGVcblx0XHQgKiBAcGFyYW0ge09iamVjdH0gc3RhdGUgdGhlIHN0YXRlIHRvIHJlc3RvcmUuIEtlZXAgaW4gbWluZCB0aGlzIG9iamVjdCBpcyBwYXNzZWQgYnkgcmVmZXJlbmNlIGFuZCBqc3RyZWUgd2lsbCBtb2RpZnkgaXQuXG5cdFx0ICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2sgYW4gb3B0aW9uYWwgZnVuY3Rpb24gdG8gZXhlY3V0ZSBvbmNlIHRoZSBzdGF0ZSBpcyByZXN0b3JlZC5cblx0XHQgKiBAdHJpZ2dlciBzZXRfc3RhdGUuanN0cmVlXG5cdFx0ICovXG5cdFx0c2V0X3N0YXRlIDogZnVuY3Rpb24gKHN0YXRlLCBjYWxsYmFjaykge1xuXHRcdFx0aWYoc3RhdGUpIHtcblx0XHRcdFx0aWYoc3RhdGUuY29yZSAmJiBzdGF0ZS5jb3JlLnNlbGVjdGVkICYmIHN0YXRlLmNvcmUuaW5pdGlhbF9zZWxlY3Rpb24gPT09IHVuZGVmaW5lZCkge1xuXHRcdFx0XHRcdHN0YXRlLmNvcmUuaW5pdGlhbF9zZWxlY3Rpb24gPSB0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQuY29uY2F0KFtdKS5zb3J0KCkuam9pbignLCcpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKHN0YXRlLmNvcmUpIHtcblx0XHRcdFx0XHR2YXIgcmVzLCBuLCB0LCBfdGhpcywgaTtcblx0XHRcdFx0XHRpZihzdGF0ZS5jb3JlLmxvYWRlZCkge1xuXHRcdFx0XHRcdFx0aWYoIXRoaXMuc2V0dGluZ3MuY29yZS5sb2FkZWRfc3RhdGUgfHwgISQudmFrYXRhLmlzX2FycmF5KHN0YXRlLmNvcmUubG9hZGVkKSB8fCAhc3RhdGUuY29yZS5sb2FkZWQubGVuZ3RoKSB7XG5cdFx0XHRcdFx0XHRcdGRlbGV0ZSBzdGF0ZS5jb3JlLmxvYWRlZDtcblx0XHRcdFx0XHRcdFx0dGhpcy5zZXRfc3RhdGUoc3RhdGUsIGNhbGxiYWNrKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHR0aGlzLl9sb2FkX25vZGVzKHN0YXRlLmNvcmUubG9hZGVkLCBmdW5jdGlvbiAobm9kZXMpIHtcblx0XHRcdFx0XHRcdFx0XHRkZWxldGUgc3RhdGUuY29yZS5sb2FkZWQ7XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5zZXRfc3RhdGUoc3RhdGUsIGNhbGxiYWNrKTtcblx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmKHN0YXRlLmNvcmUub3Blbikge1xuXHRcdFx0XHRcdFx0aWYoISQudmFrYXRhLmlzX2FycmF5KHN0YXRlLmNvcmUub3BlbikgfHwgIXN0YXRlLmNvcmUub3Blbi5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0ZGVsZXRlIHN0YXRlLmNvcmUub3Blbjtcblx0XHRcdFx0XHRcdFx0dGhpcy5zZXRfc3RhdGUoc3RhdGUsIGNhbGxiYWNrKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHR0aGlzLl9sb2FkX25vZGVzKHN0YXRlLmNvcmUub3BlbiwgZnVuY3Rpb24gKG5vZGVzKSB7XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5vcGVuX25vZGUobm9kZXMsIGZhbHNlLCAwKTtcblx0XHRcdFx0XHRcdFx0XHRkZWxldGUgc3RhdGUuY29yZS5vcGVuO1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuc2V0X3N0YXRlKHN0YXRlLCBjYWxsYmFjayk7XG5cdFx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZihzdGF0ZS5jb3JlLnNjcm9sbCkge1xuXHRcdFx0XHRcdFx0aWYoc3RhdGUuY29yZS5zY3JvbGwgJiYgc3RhdGUuY29yZS5zY3JvbGwubGVmdCAhPT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuZWxlbWVudC5zY3JvbGxMZWZ0KHN0YXRlLmNvcmUuc2Nyb2xsLmxlZnQpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYoc3RhdGUuY29yZS5zY3JvbGwgJiYgc3RhdGUuY29yZS5zY3JvbGwudG9wICE9PSB1bmRlZmluZWQpIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5lbGVtZW50LnNjcm9sbFRvcChzdGF0ZS5jb3JlLnNjcm9sbC50b3ApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0ZGVsZXRlIHN0YXRlLmNvcmUuc2Nyb2xsO1xuXHRcdFx0XHRcdFx0dGhpcy5zZXRfc3RhdGUoc3RhdGUsIGNhbGxiYWNrKTtcblx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYoc3RhdGUuY29yZS5zZWxlY3RlZCkge1xuXHRcdFx0XHRcdFx0X3RoaXMgPSB0aGlzO1xuXHRcdFx0XHRcdFx0aWYgKHN0YXRlLmNvcmUuaW5pdGlhbF9zZWxlY3Rpb24gPT09IHVuZGVmaW5lZCB8fFxuXHRcdFx0XHRcdFx0XHRzdGF0ZS5jb3JlLmluaXRpYWxfc2VsZWN0aW9uID09PSB0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQuY29uY2F0KFtdKS5zb3J0KCkuam9pbignLCcpXG5cdFx0XHRcdFx0XHQpIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5kZXNlbGVjdF9hbGwoKTtcblx0XHRcdFx0XHRcdFx0JC5lYWNoKHN0YXRlLmNvcmUuc2VsZWN0ZWQsIGZ1bmN0aW9uIChpLCB2KSB7XG5cdFx0XHRcdFx0XHRcdFx0X3RoaXMuc2VsZWN0X25vZGUodiwgZmFsc2UsIHRydWUpO1xuXHRcdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGRlbGV0ZSBzdGF0ZS5jb3JlLmluaXRpYWxfc2VsZWN0aW9uO1xuXHRcdFx0XHRcdFx0ZGVsZXRlIHN0YXRlLmNvcmUuc2VsZWN0ZWQ7XG5cdFx0XHRcdFx0XHR0aGlzLnNldF9zdGF0ZShzdGF0ZSwgY2FsbGJhY2spO1xuXHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRmb3IoaSBpbiBzdGF0ZSkge1xuXHRcdFx0XHRcdFx0aWYoc3RhdGUuaGFzT3duUHJvcGVydHkoaSkgJiYgaSAhPT0gXCJjb3JlXCIgJiYgJC5pbkFycmF5KGksIHRoaXMuc2V0dGluZ3MucGx1Z2lucykgPT09IC0xKSB7XG5cdFx0XHRcdFx0XHRcdGRlbGV0ZSBzdGF0ZVtpXTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYoJC5pc0VtcHR5T2JqZWN0KHN0YXRlLmNvcmUpKSB7XG5cdFx0XHRcdFx0XHRkZWxldGUgc3RhdGUuY29yZTtcblx0XHRcdFx0XHRcdHRoaXMuc2V0X3N0YXRlKHN0YXRlLCBjYWxsYmFjayk7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKCQuaXNFbXB0eU9iamVjdChzdGF0ZSkpIHtcblx0XHRcdFx0XHRzdGF0ZSA9IG51bGw7XG5cdFx0XHRcdFx0aWYoY2FsbGJhY2spIHsgY2FsbGJhY2suY2FsbCh0aGlzKTsgfVxuXHRcdFx0XHRcdC8qKlxuXHRcdFx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGEgYHNldF9zdGF0ZWAgY2FsbCBjb21wbGV0ZXNcblx0XHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0XHQgKiBAbmFtZSBzZXRfc3RhdGUuanN0cmVlXG5cdFx0XHRcdFx0ICovXG5cdFx0XHRcdFx0dGhpcy50cmlnZ2VyKCdzZXRfc3RhdGUnKTtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiByZWZyZXNoZXMgdGhlIHRyZWUgLSBhbGwgbm9kZXMgYXJlIHJlbG9hZGVkIHdpdGggY2FsbHMgdG8gYGxvYWRfbm9kZWAuXG5cdFx0ICogQG5hbWUgcmVmcmVzaCgpXG5cdFx0ICogQHBhcmFtIHtCb29sZWFufSBza2lwX2xvYWRpbmcgYW4gb3B0aW9uIHRvIHNraXAgc2hvd2luZyB0aGUgbG9hZGluZyBpbmRpY2F0b3Jcblx0XHQgKiBAcGFyYW0ge01peGVkfSBmb3JnZXRfc3RhdGUgaWYgc2V0IHRvIGB0cnVlYCBzdGF0ZSB3aWxsIG5vdCBiZSByZWFwcGxpZWQsIGlmIHNldCB0byBhIGZ1bmN0aW9uIChyZWNlaXZpbmcgdGhlIGN1cnJlbnQgc3RhdGUgYXMgYXJndW1lbnQpIHRoZSByZXN1bHQgb2YgdGhhdCBmdW5jdGlvbiB3aWxsIGJlIHVzZWQgYXMgc3RhdGVcblx0XHQgKiBAdHJpZ2dlciByZWZyZXNoLmpzdHJlZVxuXHRcdCAqL1xuXHRcdHJlZnJlc2ggOiBmdW5jdGlvbiAoc2tpcF9sb2FkaW5nLCBmb3JnZXRfc3RhdGUpIHtcblx0XHRcdHRoaXMuX2RhdGEuY29yZS5zdGF0ZSA9IGZvcmdldF9zdGF0ZSA9PT0gdHJ1ZSA/IHt9IDogdGhpcy5nZXRfc3RhdGUoKTtcblx0XHRcdGlmKGZvcmdldF9zdGF0ZSAmJiAkLnZha2F0YS5pc19mdW5jdGlvbihmb3JnZXRfc3RhdGUpKSB7IHRoaXMuX2RhdGEuY29yZS5zdGF0ZSA9IGZvcmdldF9zdGF0ZS5jYWxsKHRoaXMsIHRoaXMuX2RhdGEuY29yZS5zdGF0ZSk7IH1cblx0XHRcdHRoaXMuX2NudCA9IDA7XG5cdFx0XHR0aGlzLl9tb2RlbC5kYXRhID0ge307XG5cdFx0XHR0aGlzLl9tb2RlbC5kYXRhWyQuanN0cmVlLnJvb3RdID0ge1xuXHRcdFx0XHRpZCA6ICQuanN0cmVlLnJvb3QsXG5cdFx0XHRcdHBhcmVudCA6IG51bGwsXG5cdFx0XHRcdHBhcmVudHMgOiBbXSxcblx0XHRcdFx0Y2hpbGRyZW4gOiBbXSxcblx0XHRcdFx0Y2hpbGRyZW5fZCA6IFtdLFxuXHRcdFx0XHRzdGF0ZSA6IHsgbG9hZGVkIDogZmFsc2UgfVxuXHRcdFx0fTtcblx0XHRcdHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZCA9IFtdO1xuXHRcdFx0dGhpcy5fZGF0YS5jb3JlLmxhc3RfY2xpY2tlZCA9IG51bGw7XG5cdFx0XHR0aGlzLl9kYXRhLmNvcmUuZm9jdXNlZCA9IG51bGw7XG5cblx0XHRcdHZhciBjID0gdGhpcy5nZXRfY29udGFpbmVyX3VsKClbMF0uY2xhc3NOYW1lO1xuXHRcdFx0aWYoIXNraXBfbG9hZGluZykge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQuaHRtbChcIjxcIitcInVsIGNsYXNzPSdcIitjK1wiJyByb2xlPSdncm91cCc+PFwiK1wibGkgY2xhc3M9J2pzdHJlZS1pbml0aWFsLW5vZGUganN0cmVlLWxvYWRpbmcganN0cmVlLWxlYWYganN0cmVlLWxhc3QnIHJvbGU9J25vbmUnIGlkPSdqXCIrdGhpcy5faWQrXCJfbG9hZGluZyc+PGkgY2xhc3M9J2pzdHJlZS1pY29uIGpzdHJlZS1vY2wnPjwvaT48XCIrXCJhIGNsYXNzPSdqc3RyZWUtYW5jaG9yJyByb2xlPSd0cmVlaXRlbScgaHJlZj0nIyc+PGkgY2xhc3M9J2pzdHJlZS1pY29uIGpzdHJlZS10aGVtZWljb24taGlkZGVuJz48L2k+XCIgKyB0aGlzLmdldF9zdHJpbmcoXCJMb2FkaW5nIC4uLlwiKSArIFwiPC9hPjwvbGk+PC91bD5cIik7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5hdHRyKCdhcmlhLWFjdGl2ZWRlc2NlbmRhbnQnLCdqJyt0aGlzLl9pZCsnX2xvYWRpbmcnKTtcblx0XHRcdH1cblx0XHRcdHRoaXMubG9hZF9ub2RlKCQuanN0cmVlLnJvb3QsIGZ1bmN0aW9uIChvLCBzKSB7XG5cdFx0XHRcdGlmKHMpIHtcblx0XHRcdFx0XHR0aGlzLmdldF9jb250YWluZXJfdWwoKVswXS5jbGFzc05hbWUgPSBjO1xuXHRcdFx0XHRcdGlmKHRoaXMuX2ZpcnN0Q2hpbGQodGhpcy5nZXRfY29udGFpbmVyX3VsKClbMF0pKSB7XG5cdFx0XHRcdFx0XHR0aGlzLmVsZW1lbnQuYXR0cignYXJpYS1hY3RpdmVkZXNjZW5kYW50Jyx0aGlzLl9maXJzdENoaWxkKHRoaXMuZ2V0X2NvbnRhaW5lcl91bCgpWzBdKS5pZCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHRoaXMuc2V0X3N0YXRlKCQuZXh0ZW5kKHRydWUsIHt9LCB0aGlzLl9kYXRhLmNvcmUuc3RhdGUpLCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0XHQvKipcblx0XHRcdFx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGEgYHJlZnJlc2hgIGNhbGwgY29tcGxldGVzXG5cdFx0XHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0XHRcdCAqIEBuYW1lIHJlZnJlc2guanN0cmVlXG5cdFx0XHRcdFx0XHQgKi9cblx0XHRcdFx0XHRcdHRoaXMudHJpZ2dlcigncmVmcmVzaCcpO1xuXHRcdFx0XHRcdH0pO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5zdGF0ZSA9IG51bGw7XG5cdFx0XHR9KTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIHJlZnJlc2hlcyBhIG5vZGUgaW4gdGhlIHRyZWUgKHJlbG9hZCBpdHMgY2hpbGRyZW4pIGFsbCBvcGVuZWQgbm9kZXMgaW5zaWRlIHRoYXQgbm9kZSBhcmUgcmVsb2FkZWQgd2l0aCBjYWxscyB0byBgbG9hZF9ub2RlYC5cblx0XHQgKiBAbmFtZSByZWZyZXNoX25vZGUob2JqKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBvYmogdGhlIG5vZGVcblx0XHQgKiBAdHJpZ2dlciByZWZyZXNoX25vZGUuanN0cmVlXG5cdFx0ICovXG5cdFx0cmVmcmVzaF9ub2RlIDogZnVuY3Rpb24gKG9iaikge1xuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaiB8fCBvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHR2YXIgb3BlbmVkID0gW10sIHRvX2xvYWQgPSBbXSwgcyA9IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZC5jb25jYXQoW10pO1xuXHRcdFx0dG9fbG9hZC5wdXNoKG9iai5pZCk7XG5cdFx0XHRpZihvYmouc3RhdGUub3BlbmVkID09PSB0cnVlKSB7IG9wZW5lZC5wdXNoKG9iai5pZCk7IH1cblx0XHRcdHRoaXMuZ2V0X25vZGUob2JqLCB0cnVlKS5maW5kKCcuanN0cmVlLW9wZW4nKS5lYWNoKGZ1bmN0aW9uKCkgeyB0b19sb2FkLnB1c2godGhpcy5pZCk7IG9wZW5lZC5wdXNoKHRoaXMuaWQpOyB9KTtcblx0XHRcdHRoaXMuX2xvYWRfbm9kZXModG9fbG9hZCwgZnVuY3Rpb24gKG5vZGVzKSB7XG5cdFx0XHRcdHRoaXMub3Blbl9ub2RlKG9wZW5lZCwgZmFsc2UsIDApO1xuXHRcdFx0XHR0aGlzLnNlbGVjdF9ub2RlKHMpO1xuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYSBub2RlIGlzIHJlZnJlc2hlZFxuXHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0ICogQG5hbWUgcmVmcmVzaF9ub2RlLmpzdHJlZVxuXHRcdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZSAtIHRoZSByZWZyZXNoZWQgbm9kZVxuXHRcdFx0XHQgKiBAcGFyYW0ge0FycmF5fSBub2RlcyAtIGFuIGFycmF5IG9mIHRoZSBJRHMgb2YgdGhlIG5vZGVzIHRoYXQgd2VyZSByZWxvYWRlZFxuXHRcdFx0XHQgKi9cblx0XHRcdFx0dGhpcy50cmlnZ2VyKCdyZWZyZXNoX25vZGUnLCB7ICdub2RlJyA6IG9iaiwgJ25vZGVzJyA6IG5vZGVzIH0pO1xuXHRcdFx0fS5iaW5kKHRoaXMpLCBmYWxzZSwgdHJ1ZSk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBzZXQgKGNoYW5nZSkgdGhlIElEIG9mIGEgbm9kZVxuXHRcdCAqIEBuYW1lIHNldF9pZChvYmosIGlkKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBvYmogdGhlIG5vZGVcblx0XHQgKiBAcGFyYW0gIHtTdHJpbmd9IGlkIHRoZSBuZXcgSURcblx0XHQgKiBAcmV0dXJuIHtCb29sZWFufVxuXHRcdCAqIEB0cmlnZ2VyIHNldF9pZC5qc3RyZWVcblx0XHQgKi9cblx0XHRzZXRfaWQgOiBmdW5jdGlvbiAob2JqLCBpZCkge1xuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaiB8fCBvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHR2YXIgaSwgaiwgbSA9IHRoaXMuX21vZGVsLmRhdGEsIG9sZCA9IG9iai5pZDtcblx0XHRcdGlkID0gaWQudG9TdHJpbmcoKTtcblx0XHRcdC8vIHVwZGF0ZSBwYXJlbnRzIChyZXBsYWNlIGN1cnJlbnQgSUQgd2l0aCBuZXcgb25lIGluIGNoaWxkcmVuIGFuZCBjaGlsZHJlbl9kKVxuXHRcdFx0bVtvYmoucGFyZW50XS5jaGlsZHJlblskLmluQXJyYXkob2JqLmlkLCBtW29iai5wYXJlbnRdLmNoaWxkcmVuKV0gPSBpZDtcblx0XHRcdGZvcihpID0gMCwgaiA9IG9iai5wYXJlbnRzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRtW29iai5wYXJlbnRzW2ldXS5jaGlsZHJlbl9kWyQuaW5BcnJheShvYmouaWQsIG1bb2JqLnBhcmVudHNbaV1dLmNoaWxkcmVuX2QpXSA9IGlkO1xuXHRcdFx0fVxuXHRcdFx0Ly8gdXBkYXRlIGNoaWxkcmVuIChyZXBsYWNlIGN1cnJlbnQgSUQgd2l0aCBuZXcgb25lIGluIHBhcmVudCBhbmQgcGFyZW50cylcblx0XHRcdGZvcihpID0gMCwgaiA9IG9iai5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0bVtvYmouY2hpbGRyZW5baV1dLnBhcmVudCA9IGlkO1xuXHRcdFx0fVxuXHRcdFx0Zm9yKGkgPSAwLCBqID0gb2JqLmNoaWxkcmVuX2QubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdG1bb2JqLmNoaWxkcmVuX2RbaV1dLnBhcmVudHNbJC5pbkFycmF5KG9iai5pZCwgbVtvYmouY2hpbGRyZW5fZFtpXV0ucGFyZW50cyldID0gaWQ7XG5cdFx0XHR9XG5cdFx0XHRpID0gJC5pbkFycmF5KG9iai5pZCwgdGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkKTtcblx0XHRcdGlmKGkgIT09IC0xKSB7IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZFtpXSA9IGlkOyB9XG5cdFx0XHQvLyB1cGRhdGUgbW9kZWwgYW5kIG9iaiBpdHNlbGYgKG9iai5pZCwgdGhpcy5fbW9kZWwuZGF0YVtLRVldKVxuXHRcdFx0aSA9IHRoaXMuZ2V0X25vZGUob2JqLmlkLCB0cnVlKTtcblx0XHRcdGlmKGkpIHtcblx0XHRcdFx0aS5hdHRyKCdpZCcsIGlkKTsgLy8uY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykuYXR0cignaWQnLCBpZCArICdfYW5jaG9yJykuZW5kKCkuYXR0cignYXJpYS1sYWJlbGxlZGJ5JywgaWQgKyAnX2FuY2hvcicpO1xuXHRcdFx0XHRpZih0aGlzLmVsZW1lbnQuYXR0cignYXJpYS1hY3RpdmVkZXNjZW5kYW50JykgPT09IG9iai5pZCkge1xuXHRcdFx0XHRcdHRoaXMuZWxlbWVudC5hdHRyKCdhcmlhLWFjdGl2ZWRlc2NlbmRhbnQnLCBpZCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGRlbGV0ZSBtW29iai5pZF07XG5cdFx0XHRvYmouaWQgPSBpZDtcblx0XHRcdG9iai5saV9hdHRyLmlkID0gaWQ7XG5cdFx0XHRtW2lkXSA9IG9iajtcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYSBub2RlIGlkIHZhbHVlIGlzIGNoYW5nZWRcblx0XHRcdCAqIEBldmVudFxuXHRcdFx0ICogQG5hbWUgc2V0X2lkLmpzdHJlZVxuXHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IG5vZGVcblx0XHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBvbGQgdGhlIG9sZCBpZFxuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ3NldF9pZCcseyBcIm5vZGVcIiA6IG9iaiwgXCJuZXdcIiA6IG9iai5pZCwgXCJvbGRcIiA6IG9sZCB9KTtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogZ2V0IHRoZSB0ZXh0IHZhbHVlIG9mIGEgbm9kZVxuXHRcdCAqIEBuYW1lIGdldF90ZXh0KG9iailcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqIHRoZSBub2RlXG5cdFx0ICogQHJldHVybiB7U3RyaW5nfVxuXHRcdCAqL1xuXHRcdGdldF90ZXh0IDogZnVuY3Rpb24gKG9iaikge1xuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0cmV0dXJuICghb2JqIHx8IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkgPyBmYWxzZSA6IG9iai50ZXh0O1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogc2V0IHRoZSB0ZXh0IHZhbHVlIG9mIGEgbm9kZS4gVXNlZCBpbnRlcm5hbGx5LCBwbGVhc2UgdXNlIGByZW5hbWVfbm9kZShvYmosIHZhbClgLlxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICogQG5hbWUgc2V0X3RleHQob2JqLCB2YWwpXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9iaiB0aGUgbm9kZSwgeW91IGNhbiBwYXNzIGFuIGFycmF5IHRvIHNldCB0aGUgdGV4dCBvbiBtdWx0aXBsZSBub2Rlc1xuXHRcdCAqIEBwYXJhbSAge1N0cmluZ30gdmFsIHRoZSBuZXcgdGV4dCB2YWx1ZVxuXHRcdCAqIEByZXR1cm4ge0Jvb2xlYW59XG5cdFx0ICogQHRyaWdnZXIgc2V0X3RleHQuanN0cmVlXG5cdFx0ICovXG5cdFx0c2V0X3RleHQgOiBmdW5jdGlvbiAob2JqLCB2YWwpIHtcblx0XHRcdHZhciB0MSwgdDI7XG5cdFx0XHRpZigkLnZha2F0YS5pc19hcnJheShvYmopKSB7XG5cdFx0XHRcdG9iaiA9IG9iai5zbGljZSgpO1xuXHRcdFx0XHRmb3IodDEgPSAwLCB0MiA9IG9iai5sZW5ndGg7IHQxIDwgdDI7IHQxKyspIHtcblx0XHRcdFx0XHR0aGlzLnNldF90ZXh0KG9ialt0MV0sIHZhbCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqIHx8IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdG9iai50ZXh0ID0gdmFsO1xuXHRcdFx0aWYodGhpcy5nZXRfbm9kZShvYmosIHRydWUpLmxlbmd0aCkge1xuXHRcdFx0XHR0aGlzLnJlZHJhd19ub2RlKG9iai5pZCk7XG5cdFx0XHR9XG5cdFx0XHQvKipcblx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGEgbm9kZSB0ZXh0IHZhbHVlIGlzIGNoYW5nZWRcblx0XHRcdCAqIEBldmVudFxuXHRcdFx0ICogQG5hbWUgc2V0X3RleHQuanN0cmVlXG5cdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gb2JqXG5cdFx0XHQgKiBAcGFyYW0ge1N0cmluZ30gdGV4dCB0aGUgbmV3IHZhbHVlXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignc2V0X3RleHQnLHsgXCJvYmpcIiA6IG9iaiwgXCJ0ZXh0XCIgOiB2YWwgfSk7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGdldHMgYSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIGEgbm9kZSAob3IgdGhlIHdob2xlIHRyZWUpXG5cdFx0ICogQG5hbWUgZ2V0X2pzb24oW29iaiwgb3B0aW9uc10pXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9ialxuXHRcdCAqIEBwYXJhbSAge09iamVjdH0gb3B0aW9uc1xuXHRcdCAqIEBwYXJhbSAge0Jvb2xlYW59IG9wdGlvbnMubm9fc3RhdGUgZG8gbm90IHJldHVybiBzdGF0ZSBpbmZvcm1hdGlvblxuXHRcdCAqIEBwYXJhbSAge0Jvb2xlYW59IG9wdGlvbnMubm9faWQgZG8gbm90IHJldHVybiBJRFxuXHRcdCAqIEBwYXJhbSAge0Jvb2xlYW59IG9wdGlvbnMubm9fY2hpbGRyZW4gZG8gbm90IGluY2x1ZGUgY2hpbGRyZW5cblx0XHQgKiBAcGFyYW0gIHtCb29sZWFufSBvcHRpb25zLm5vX2RhdGEgZG8gbm90IGluY2x1ZGUgbm9kZSBkYXRhXG5cdFx0ICogQHBhcmFtICB7Qm9vbGVhbn0gb3B0aW9ucy5ub19saV9hdHRyIGRvIG5vdCBpbmNsdWRlIExJIGF0dHJpYnV0ZXNcblx0XHQgKiBAcGFyYW0gIHtCb29sZWFufSBvcHRpb25zLm5vX2FfYXR0ciBkbyBub3QgaW5jbHVkZSBBIGF0dHJpYnV0ZXNcblx0XHQgKiBAcGFyYW0gIHtCb29sZWFufSBvcHRpb25zLmZsYXQgcmV0dXJuIGZsYXQgSlNPTiBpbnN0ZWFkIG9mIG5lc3RlZFxuXHRcdCAqIEByZXR1cm4ge09iamVjdH1cblx0XHQgKi9cblx0XHRnZXRfanNvbiA6IGZ1bmN0aW9uIChvYmosIG9wdGlvbnMsIGZsYXQpIHtcblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqIHx8ICQuanN0cmVlLnJvb3QpO1xuXHRcdFx0aWYoIW9iaikgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdGlmKG9wdGlvbnMgJiYgb3B0aW9ucy5mbGF0ICYmICFmbGF0KSB7IGZsYXQgPSBbXTsgfVxuXHRcdFx0dmFyIHRtcCA9IHtcblx0XHRcdFx0J2lkJyA6IG9iai5pZCxcblx0XHRcdFx0J3RleHQnIDogb2JqLnRleHQsXG5cdFx0XHRcdCdpY29uJyA6IHRoaXMuZ2V0X2ljb24ob2JqKSxcblx0XHRcdFx0J2xpX2F0dHInIDogJC5leHRlbmQodHJ1ZSwge30sIG9iai5saV9hdHRyKSxcblx0XHRcdFx0J2FfYXR0cicgOiAkLmV4dGVuZCh0cnVlLCB7fSwgb2JqLmFfYXR0ciksXG5cdFx0XHRcdCdzdGF0ZScgOiB7fSxcblx0XHRcdFx0J2RhdGEnIDogb3B0aW9ucyAmJiBvcHRpb25zLm5vX2RhdGEgPyBmYWxzZSA6ICQuZXh0ZW5kKHRydWUsICQudmFrYXRhLmlzX2FycmF5KG9iai5kYXRhKT9bXTp7fSwgb2JqLmRhdGEpXG5cdFx0XHRcdC8vKCB0aGlzLmdldF9ub2RlKG9iaiwgdHJ1ZSkubGVuZ3RoID8gdGhpcy5nZXRfbm9kZShvYmosIHRydWUpLmRhdGEoKSA6IG9iai5kYXRhICksXG5cdFx0XHR9LCBpLCBqO1xuXHRcdFx0aWYob3B0aW9ucyAmJiBvcHRpb25zLmZsYXQpIHtcblx0XHRcdFx0dG1wLnBhcmVudCA9IG9iai5wYXJlbnQ7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0dG1wLmNoaWxkcmVuID0gW107XG5cdFx0XHR9XG5cdFx0XHRpZighb3B0aW9ucyB8fCAhb3B0aW9ucy5ub19zdGF0ZSkge1xuXHRcdFx0XHRmb3IoaSBpbiBvYmouc3RhdGUpIHtcblx0XHRcdFx0XHRpZihvYmouc3RhdGUuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHRcdHRtcC5zdGF0ZVtpXSA9IG9iai5zdGF0ZVtpXTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGRlbGV0ZSB0bXAuc3RhdGU7XG5cdFx0XHR9XG5cdFx0XHRpZihvcHRpb25zICYmIG9wdGlvbnMubm9fbGlfYXR0cikge1xuXHRcdFx0XHRkZWxldGUgdG1wLmxpX2F0dHI7XG5cdFx0XHR9XG5cdFx0XHRpZihvcHRpb25zICYmIG9wdGlvbnMubm9fYV9hdHRyKSB7XG5cdFx0XHRcdGRlbGV0ZSB0bXAuYV9hdHRyO1xuXHRcdFx0fVxuXHRcdFx0aWYob3B0aW9ucyAmJiBvcHRpb25zLm5vX2lkKSB7XG5cdFx0XHRcdGRlbGV0ZSB0bXAuaWQ7XG5cdFx0XHRcdGlmKHRtcC5saV9hdHRyICYmIHRtcC5saV9hdHRyLmlkKSB7XG5cdFx0XHRcdFx0ZGVsZXRlIHRtcC5saV9hdHRyLmlkO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKHRtcC5hX2F0dHIgJiYgdG1wLmFfYXR0ci5pZCkge1xuXHRcdFx0XHRcdGRlbGV0ZSB0bXAuYV9hdHRyLmlkO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRpZihvcHRpb25zICYmIG9wdGlvbnMuZmxhdCAmJiBvYmouaWQgIT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0ZmxhdC5wdXNoKHRtcCk7XG5cdFx0XHR9XG5cdFx0XHRpZighb3B0aW9ucyB8fCAhb3B0aW9ucy5ub19jaGlsZHJlbikge1xuXHRcdFx0XHRmb3IoaSA9IDAsIGogPSBvYmouY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0aWYob3B0aW9ucyAmJiBvcHRpb25zLmZsYXQpIHtcblx0XHRcdFx0XHRcdHRoaXMuZ2V0X2pzb24ob2JqLmNoaWxkcmVuW2ldLCBvcHRpb25zLCBmbGF0KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHR0bXAuY2hpbGRyZW4ucHVzaCh0aGlzLmdldF9qc29uKG9iai5jaGlsZHJlbltpXSwgb3B0aW9ucykpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIG9wdGlvbnMgJiYgb3B0aW9ucy5mbGF0ID8gZmxhdCA6IChvYmouaWQgPT09ICQuanN0cmVlLnJvb3QgPyB0bXAuY2hpbGRyZW4gOiB0bXApO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogY3JlYXRlIGEgbmV3IG5vZGUgKGRvIG5vdCBjb25mdXNlIHdpdGggbG9hZF9ub2RlKVxuXHRcdCAqIEBuYW1lIGNyZWF0ZV9ub2RlKFtwYXIsIG5vZGUsIHBvcywgY2FsbGJhY2ssIGlzX2xvYWRlZF0pXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9ICAgcGFyICAgICAgIHRoZSBwYXJlbnQgbm9kZSAodG8gY3JlYXRlIGEgcm9vdCBub2RlIHVzZSBlaXRoZXIgXCIjXCIgKHN0cmluZykgb3IgYG51bGxgKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSAgIG5vZGUgICAgICB0aGUgZGF0YSBmb3IgdGhlIG5ldyBub2RlIChhIHZhbGlkIEpTT04gb2JqZWN0LCBvciBhIHNpbXBsZSBzdHJpbmcgd2l0aCB0aGUgbmFtZSlcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gICBwb3MgICAgICAgdGhlIGluZGV4IGF0IHdoaWNoIHRvIGluc2VydCB0aGUgbm9kZSwgXCJmaXJzdFwiIGFuZCBcImxhc3RcIiBhcmUgYWxzbyBzdXBwb3J0ZWQsIGRlZmF1bHQgaXMgXCJsYXN0XCJcblx0XHQgKiBAcGFyYW0gIHtGdW5jdGlvbn0gY2FsbGJhY2sgYSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgb25jZSB0aGUgbm9kZSBpcyBjcmVhdGVkXG5cdFx0ICogQHBhcmFtICB7Qm9vbGVhbn0gaXNfbG9hZGVkIGludGVybmFsIGFyZ3VtZW50IGluZGljYXRpbmcgaWYgdGhlIHBhcmVudCBub2RlIHdhcyBzdWNjZXNmdWxseSBsb2FkZWRcblx0XHQgKiBAcmV0dXJuIHtTdHJpbmd9ICAgICAgICAgICAgdGhlIElEIG9mIHRoZSBuZXdseSBjcmVhdGUgbm9kZVxuXHRcdCAqIEB0cmlnZ2VyIG1vZGVsLmpzdHJlZSwgY3JlYXRlX25vZGUuanN0cmVlXG5cdFx0ICovXG5cdFx0Y3JlYXRlX25vZGUgOiBmdW5jdGlvbiAocGFyLCBub2RlLCBwb3MsIGNhbGxiYWNrLCBpc19sb2FkZWQpIHtcblx0XHRcdGlmKHBhciA9PT0gbnVsbCkgeyBwYXIgPSAkLmpzdHJlZS5yb290OyB9XG5cdFx0XHRwYXIgPSB0aGlzLmdldF9ub2RlKHBhcik7XG5cdFx0XHRpZighcGFyKSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdFx0cG9zID0gcG9zID09PSB1bmRlZmluZWQgPyBcImxhc3RcIiA6IHBvcztcblx0XHRcdGlmKCFwb3MudG9TdHJpbmcoKS5tYXRjaCgvXihiZWZvcmV8YWZ0ZXIpJC8pICYmICFpc19sb2FkZWQgJiYgIXRoaXMuaXNfbG9hZGVkKHBhcikpIHtcblx0XHRcdFx0cmV0dXJuIHRoaXMubG9hZF9ub2RlKHBhciwgZnVuY3Rpb24gKCkgeyB0aGlzLmNyZWF0ZV9ub2RlKHBhciwgbm9kZSwgcG9zLCBjYWxsYmFjaywgdHJ1ZSk7IH0pO1xuXHRcdFx0fVxuXHRcdFx0aWYoIW5vZGUpIHsgbm9kZSA9IHsgXCJ0ZXh0XCIgOiB0aGlzLmdldF9zdHJpbmcoJ05ldyBub2RlJykgfTsgfVxuXHRcdFx0aWYodHlwZW9mIG5vZGUgPT09IFwic3RyaW5nXCIpIHtcblx0XHRcdFx0bm9kZSA9IHsgXCJ0ZXh0XCIgOiBub2RlIH07XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRub2RlID0gJC5leHRlbmQodHJ1ZSwge30sIG5vZGUpO1xuXHRcdFx0fVxuXHRcdFx0aWYobm9kZS50ZXh0ID09PSB1bmRlZmluZWQpIHsgbm9kZS50ZXh0ID0gdGhpcy5nZXRfc3RyaW5nKCdOZXcgbm9kZScpOyB9XG5cdFx0XHR2YXIgdG1wLCBkcGMsIGksIGo7XG5cblx0XHRcdGlmKHBhci5pZCA9PT0gJC5qc3RyZWUucm9vdCkge1xuXHRcdFx0XHRpZihwb3MgPT09IFwiYmVmb3JlXCIpIHsgcG9zID0gXCJmaXJzdFwiOyB9XG5cdFx0XHRcdGlmKHBvcyA9PT0gXCJhZnRlclwiKSB7IHBvcyA9IFwibGFzdFwiOyB9XG5cdFx0XHR9XG5cdFx0XHRzd2l0Y2gocG9zKSB7XG5cdFx0XHRcdGNhc2UgXCJiZWZvcmVcIjpcblx0XHRcdFx0XHR0bXAgPSB0aGlzLmdldF9ub2RlKHBhci5wYXJlbnQpO1xuXHRcdFx0XHRcdHBvcyA9ICQuaW5BcnJheShwYXIuaWQsIHRtcC5jaGlsZHJlbik7XG5cdFx0XHRcdFx0cGFyID0gdG1wO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIFwiYWZ0ZXJcIiA6XG5cdFx0XHRcdFx0dG1wID0gdGhpcy5nZXRfbm9kZShwYXIucGFyZW50KTtcblx0XHRcdFx0XHRwb3MgPSAkLmluQXJyYXkocGFyLmlkLCB0bXAuY2hpbGRyZW4pICsgMTtcblx0XHRcdFx0XHRwYXIgPSB0bXA7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgXCJpbnNpZGVcIjpcblx0XHRcdFx0Y2FzZSBcImZpcnN0XCI6XG5cdFx0XHRcdFx0cG9zID0gMDtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBcImxhc3RcIjpcblx0XHRcdFx0XHRwb3MgPSBwYXIuY2hpbGRyZW4ubGVuZ3RoO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdGlmKCFwb3MpIHsgcG9zID0gMDsgfVxuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0aWYocG9zID4gcGFyLmNoaWxkcmVuLmxlbmd0aCkgeyBwb3MgPSBwYXIuY2hpbGRyZW4ubGVuZ3RoOyB9XG5cdFx0XHRpZighbm9kZS5pZCkgeyBub2RlLmlkID0gdHJ1ZTsgfVxuXHRcdFx0aWYoIXRoaXMuY2hlY2soXCJjcmVhdGVfbm9kZVwiLCBub2RlLCBwYXIsIHBvcykpIHtcblx0XHRcdFx0dGhpcy5zZXR0aW5ncy5jb3JlLmVycm9yLmNhbGwodGhpcywgdGhpcy5fZGF0YS5jb3JlLmxhc3RfZXJyb3IpO1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRpZihub2RlLmlkID09PSB0cnVlKSB7IGRlbGV0ZSBub2RlLmlkOyB9XG5cdFx0XHRub2RlID0gdGhpcy5fcGFyc2VfbW9kZWxfZnJvbV9qc29uKG5vZGUsIHBhci5pZCwgcGFyLnBhcmVudHMuY29uY2F0KCkpO1xuXHRcdFx0aWYoIW5vZGUpIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHR0bXAgPSB0aGlzLmdldF9ub2RlKG5vZGUpO1xuXHRcdFx0ZHBjID0gW107XG5cdFx0XHRkcGMucHVzaChub2RlKTtcblx0XHRcdGRwYyA9IGRwYy5jb25jYXQodG1wLmNoaWxkcmVuX2QpO1xuXHRcdFx0dGhpcy50cmlnZ2VyKCdtb2RlbCcsIHsgXCJub2Rlc1wiIDogZHBjLCBcInBhcmVudFwiIDogcGFyLmlkIH0pO1xuXG5cdFx0XHRwYXIuY2hpbGRyZW5fZCA9IHBhci5jaGlsZHJlbl9kLmNvbmNhdChkcGMpO1xuXHRcdFx0Zm9yKGkgPSAwLCBqID0gcGFyLnBhcmVudHMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdHRoaXMuX21vZGVsLmRhdGFbcGFyLnBhcmVudHNbaV1dLmNoaWxkcmVuX2QgPSB0aGlzLl9tb2RlbC5kYXRhW3Bhci5wYXJlbnRzW2ldXS5jaGlsZHJlbl9kLmNvbmNhdChkcGMpO1xuXHRcdFx0fVxuXHRcdFx0bm9kZSA9IHRtcDtcblx0XHRcdHRtcCA9IFtdO1xuXHRcdFx0Zm9yKGkgPSAwLCBqID0gcGFyLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHR0bXBbaSA+PSBwb3MgPyBpKzEgOiBpXSA9IHBhci5jaGlsZHJlbltpXTtcblx0XHRcdH1cblx0XHRcdHRtcFtwb3NdID0gbm9kZS5pZDtcblx0XHRcdHBhci5jaGlsZHJlbiA9IHRtcDtcblxuXHRcdFx0dGhpcy5yZWRyYXdfbm9kZShwYXIsIHRydWUpO1xuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiBhIG5vZGUgaXMgY3JlYXRlZFxuXHRcdFx0ICogQGV2ZW50XG5cdFx0XHQgKiBAbmFtZSBjcmVhdGVfbm9kZS5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlXG5cdFx0XHQgKiBAcGFyYW0ge1N0cmluZ30gcGFyZW50IHRoZSBwYXJlbnQncyBJRFxuXHRcdFx0ICogQHBhcmFtIHtOdW1iZXJ9IHBvc2l0aW9uIHRoZSBwb3NpdGlvbiBvZiB0aGUgbmV3IG5vZGUgYW1vbmcgdGhlIHBhcmVudCdzIGNoaWxkcmVuXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignY3JlYXRlX25vZGUnLCB7IFwibm9kZVwiIDogdGhpcy5nZXRfbm9kZShub2RlKSwgXCJwYXJlbnRcIiA6IHBhci5pZCwgXCJwb3NpdGlvblwiIDogcG9zIH0pO1xuXHRcdFx0aWYoY2FsbGJhY2spIHsgY2FsbGJhY2suY2FsbCh0aGlzLCB0aGlzLmdldF9ub2RlKG5vZGUpKTsgfVxuXHRcdFx0cmV0dXJuIG5vZGUuaWQ7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBzZXQgdGhlIHRleHQgdmFsdWUgb2YgYSBub2RlXG5cdFx0ICogQG5hbWUgcmVuYW1lX25vZGUob2JqLCB2YWwpXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9iaiB0aGUgbm9kZSwgeW91IGNhbiBwYXNzIGFuIGFycmF5IHRvIHJlbmFtZSBtdWx0aXBsZSBub2RlcyB0byB0aGUgc2FtZSBuYW1lXG5cdFx0ICogQHBhcmFtICB7U3RyaW5nfSB2YWwgdGhlIG5ldyB0ZXh0IHZhbHVlXG5cdFx0ICogQHJldHVybiB7Qm9vbGVhbn1cblx0XHQgKiBAdHJpZ2dlciByZW5hbWVfbm9kZS5qc3RyZWVcblx0XHQgKi9cblx0XHRyZW5hbWVfbm9kZSA6IGZ1bmN0aW9uIChvYmosIHZhbCkge1xuXHRcdFx0dmFyIHQxLCB0Miwgb2xkO1xuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkob2JqKSkge1xuXHRcdFx0XHRvYmogPSBvYmouc2xpY2UoKTtcblx0XHRcdFx0Zm9yKHQxID0gMCwgdDIgPSBvYmoubGVuZ3RoOyB0MSA8IHQyOyB0MSsrKSB7XG5cdFx0XHRcdFx0dGhpcy5yZW5hbWVfbm9kZShvYmpbdDFdLCB2YWwpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaiB8fCBvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHRvbGQgPSBvYmoudGV4dDtcblx0XHRcdGlmKCF0aGlzLmNoZWNrKFwicmVuYW1lX25vZGVcIiwgb2JqLCB0aGlzLmdldF9wYXJlbnQob2JqKSwgdmFsKSkge1xuXHRcdFx0XHR0aGlzLnNldHRpbmdzLmNvcmUuZXJyb3IuY2FsbCh0aGlzLCB0aGlzLl9kYXRhLmNvcmUubGFzdF9lcnJvcik7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdHRoaXMuc2V0X3RleHQob2JqLCB2YWwpOyAvLyAuYXBwbHkodGhpcywgQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKSlcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYSBub2RlIGlzIHJlbmFtZWRcblx0XHRcdCAqIEBldmVudFxuXHRcdFx0ICogQG5hbWUgcmVuYW1lX25vZGUuanN0cmVlXG5cdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZVxuXHRcdFx0ICogQHBhcmFtIHtTdHJpbmd9IHRleHQgdGhlIG5ldyB2YWx1ZVxuXHRcdFx0ICogQHBhcmFtIHtTdHJpbmd9IG9sZCB0aGUgb2xkIHZhbHVlXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcigncmVuYW1lX25vZGUnLCB7IFwibm9kZVwiIDogb2JqLCBcInRleHRcIiA6IHZhbCwgXCJvbGRcIiA6IG9sZCB9KTtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogcmVtb3ZlIGEgbm9kZVxuXHRcdCAqIEBuYW1lIGRlbGV0ZV9ub2RlKG9iailcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqIHRoZSBub2RlLCB5b3UgY2FuIHBhc3MgYW4gYXJyYXkgdG8gZGVsZXRlIG11bHRpcGxlIG5vZGVzXG5cdFx0ICogQHJldHVybiB7Qm9vbGVhbn1cblx0XHQgKiBAdHJpZ2dlciBkZWxldGVfbm9kZS5qc3RyZWUsIGNoYW5nZWQuanN0cmVlXG5cdFx0ICovXG5cdFx0ZGVsZXRlX25vZGUgOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHR2YXIgdDEsIHQyLCBwYXIsIHBvcywgdG1wLCBpLCBqLCBrLCBsLCBjLCB0b3AsIGxmdDtcblx0XHRcdGlmKCQudmFrYXRhLmlzX2FycmF5KG9iaikpIHtcblx0XHRcdFx0b2JqID0gb2JqLnNsaWNlKCk7XG5cdFx0XHRcdGZvcih0MSA9IDAsIHQyID0gb2JqLmxlbmd0aDsgdDEgPCB0MjsgdDErKykge1xuXHRcdFx0XHRcdHRoaXMuZGVsZXRlX25vZGUob2JqW3QxXSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqIHx8IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdHBhciA9IHRoaXMuZ2V0X25vZGUob2JqLnBhcmVudCk7XG5cdFx0XHRwb3MgPSAkLmluQXJyYXkob2JqLmlkLCBwYXIuY2hpbGRyZW4pO1xuXHRcdFx0YyA9IGZhbHNlO1xuXHRcdFx0aWYoIXRoaXMuY2hlY2soXCJkZWxldGVfbm9kZVwiLCBvYmosIHBhciwgcG9zKSkge1xuXHRcdFx0XHR0aGlzLnNldHRpbmdzLmNvcmUuZXJyb3IuY2FsbCh0aGlzLCB0aGlzLl9kYXRhLmNvcmUubGFzdF9lcnJvcik7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdGlmKHBvcyAhPT0gLTEpIHtcblx0XHRcdFx0cGFyLmNoaWxkcmVuID0gJC52YWthdGEuYXJyYXlfcmVtb3ZlKHBhci5jaGlsZHJlbiwgcG9zKTtcblx0XHRcdH1cblx0XHRcdHRtcCA9IG9iai5jaGlsZHJlbl9kLmNvbmNhdChbXSk7XG5cdFx0XHR0bXAucHVzaChvYmouaWQpO1xuXHRcdFx0Zm9yKGkgPSAwLCBqID0gb2JqLnBhcmVudHMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdHRoaXMuX21vZGVsLmRhdGFbb2JqLnBhcmVudHNbaV1dLmNoaWxkcmVuX2QgPSAkLnZha2F0YS5hcnJheV9maWx0ZXIodGhpcy5fbW9kZWwuZGF0YVtvYmoucGFyZW50c1tpXV0uY2hpbGRyZW5fZCwgZnVuY3Rpb24gKHYpIHtcblx0XHRcdFx0XHRyZXR1cm4gJC5pbkFycmF5KHYsIHRtcCkgPT09IC0xO1xuXHRcdFx0XHR9KTtcblx0XHRcdH1cblx0XHRcdGZvcihrID0gMCwgbCA9IHRtcC5sZW5ndGg7IGsgPCBsOyBrKyspIHtcblx0XHRcdFx0aWYodGhpcy5fbW9kZWwuZGF0YVt0bXBba11dLnN0YXRlLnNlbGVjdGVkKSB7XG5cdFx0XHRcdFx0YyA9IHRydWU7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmIChjKSB7XG5cdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZCA9ICQudmFrYXRhLmFycmF5X2ZpbHRlcih0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQsIGZ1bmN0aW9uICh2KSB7XG5cdFx0XHRcdFx0cmV0dXJuICQuaW5BcnJheSh2LCB0bXApID09PSAtMTtcblx0XHRcdFx0fSk7XG5cdFx0XHR9XG5cdFx0XHQvKipcblx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGEgbm9kZSBpcyBkZWxldGVkXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGRlbGV0ZV9ub2RlLmpzdHJlZVxuXHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IG5vZGVcblx0XHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBwYXJlbnQgdGhlIHBhcmVudCdzIElEXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignZGVsZXRlX25vZGUnLCB7IFwibm9kZVwiIDogb2JqLCBcInBhcmVudFwiIDogcGFyLmlkIH0pO1xuXHRcdFx0aWYoYykge1xuXHRcdFx0XHR0aGlzLnRyaWdnZXIoJ2NoYW5nZWQnLCB7ICdhY3Rpb24nIDogJ2RlbGV0ZV9ub2RlJywgJ25vZGUnIDogb2JqLCAnc2VsZWN0ZWQnIDogdGhpcy5fZGF0YS5jb3JlLnNlbGVjdGVkLCAncGFyZW50JyA6IHBhci5pZCB9KTtcblx0XHRcdH1cblx0XHRcdGZvcihrID0gMCwgbCA9IHRtcC5sZW5ndGg7IGsgPCBsOyBrKyspIHtcblx0XHRcdFx0ZGVsZXRlIHRoaXMuX21vZGVsLmRhdGFbdG1wW2tdXTtcblx0XHRcdH1cblx0XHRcdGlmKCQuaW5BcnJheSh0aGlzLl9kYXRhLmNvcmUuZm9jdXNlZCwgdG1wKSAhPT0gLTEpIHtcblx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLmZvY3VzZWQgPSBudWxsO1xuXHRcdFx0XHR0b3AgPSB0aGlzLmVsZW1lbnRbMF0uc2Nyb2xsVG9wO1xuXHRcdFx0XHRsZnQgPSB0aGlzLmVsZW1lbnRbMF0uc2Nyb2xsTGVmdDtcblx0XHRcdFx0aWYocGFyLmlkID09PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdFx0aWYgKHRoaXMuX21vZGVsLmRhdGFbJC5qc3RyZWUucm9vdF0uY2hpbGRyZW5bMF0pIHtcblx0XHRcdFx0XHRcdHRoaXMuZ2V0X25vZGUodGhpcy5fbW9kZWwuZGF0YVskLmpzdHJlZS5yb290XS5jaGlsZHJlblswXSwgdHJ1ZSkuY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykudHJpZ2VyKCdmb2N1cycpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHR0aGlzLmdldF9ub2RlKHBhciwgdHJ1ZSkuY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykudHJpZ2dlcignZm9jdXMnKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aGlzLmVsZW1lbnRbMF0uc2Nyb2xsVG9wICA9IHRvcDtcblx0XHRcdFx0dGhpcy5lbGVtZW50WzBdLnNjcm9sbExlZnQgPSBsZnQ7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLnJlZHJhd19ub2RlKHBhciwgdHJ1ZSk7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGNoZWNrIGlmIGFuIG9wZXJhdGlvbiBpcyBwcmVtaXR0ZWQgb24gdGhlIHRyZWUuIFVzZWQgaW50ZXJuYWxseS5cblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEBuYW1lIGNoZWNrKGNoaywgb2JqLCBwYXIsIHBvcylcblx0XHQgKiBAcGFyYW0gIHtTdHJpbmd9IGNoayB0aGUgb3BlcmF0aW9uIHRvIGNoZWNrLCBjYW4gYmUgXCJjcmVhdGVfbm9kZVwiLCBcInJlbmFtZV9ub2RlXCIsIFwiZGVsZXRlX25vZGVcIiwgXCJjb3B5X25vZGVcIiBvciBcIm1vdmVfbm9kZVwiXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9iaiB0aGUgbm9kZVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBwYXIgdGhlIHBhcmVudFxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBwb3MgdGhlIHBvc2l0aW9uIHRvIGluc2VydCBhdCwgb3IgaWYgXCJyZW5hbWVfbm9kZVwiIC0gdGhlIG5ldyBuYW1lXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG1vcmUgc29tZSB2YXJpb3VzIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24sIGZvciBleGFtcGxlIGlmIGEgXCJtb3ZlX25vZGVcIiBvcGVyYXRpb25zIGlzIHRyaWdnZXJlZCBieSBETkQgdGhpcyB3aWxsIGJlIHRoZSBob3ZlcmVkIG5vZGVcblx0XHQgKiBAcmV0dXJuIHtCb29sZWFufVxuXHRcdCAqL1xuXHRcdGNoZWNrIDogZnVuY3Rpb24gKGNoaywgb2JqLCBwYXIsIHBvcywgbW9yZSkge1xuXHRcdFx0b2JqID0gb2JqICYmIG9iai5pZCA/IG9iaiA6IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdHBhciA9IHBhciAmJiBwYXIuaWQgPyBwYXIgOiB0aGlzLmdldF9ub2RlKHBhcik7XG5cdFx0XHR2YXIgdG1wID0gY2hrLm1hdGNoKC9ebW92ZV9ub2RlfGNvcHlfbm9kZXxjcmVhdGVfbm9kZSQvaSkgPyBwYXIgOiBvYmosXG5cdFx0XHRcdGNoYyA9IHRoaXMuc2V0dGluZ3MuY29yZS5jaGVja19jYWxsYmFjaztcblx0XHRcdGlmKGNoayA9PT0gXCJtb3ZlX25vZGVcIiB8fCBjaGsgPT09IFwiY29weV9ub2RlXCIpIHtcblx0XHRcdFx0aWYoKCFtb3JlIHx8ICFtb3JlLmlzX211bHRpKSAmJiAoY2hrID09PSBcIm1vdmVfbm9kZVwiICYmICQuaW5BcnJheShvYmouaWQsIHBhci5jaGlsZHJlbikgPT09IHBvcykpIHtcblx0XHRcdFx0XHR0aGlzLl9kYXRhLmNvcmUubGFzdF9lcnJvciA9IHsgJ2Vycm9yJyA6ICdjaGVjaycsICdwbHVnaW4nIDogJ2NvcmUnLCAnaWQnIDogJ2NvcmVfMDgnLCAncmVhc29uJyA6ICdNb3Zpbmcgbm9kZSB0byBpdHMgY3VycmVudCBwb3NpdGlvbicsICdkYXRhJyA6IEpTT04uc3RyaW5naWZ5KHsgJ2NoaycgOiBjaGssICdwb3MnIDogcG9zLCAnb2JqJyA6IG9iaiAmJiBvYmouaWQgPyBvYmouaWQgOiBmYWxzZSwgJ3BhcicgOiBwYXIgJiYgcGFyLmlkID8gcGFyLmlkIDogZmFsc2UgfSkgfTtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYoKCFtb3JlIHx8ICFtb3JlLmlzX211bHRpKSAmJiAob2JqLmlkID09PSBwYXIuaWQgfHwgKGNoayA9PT0gXCJtb3ZlX25vZGVcIiAmJiAkLmluQXJyYXkob2JqLmlkLCBwYXIuY2hpbGRyZW4pID09PSBwb3MpIHx8ICQuaW5BcnJheShwYXIuaWQsIG9iai5jaGlsZHJlbl9kKSAhPT0gLTEpKSB7XG5cdFx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLmxhc3RfZXJyb3IgPSB7ICdlcnJvcicgOiAnY2hlY2snLCAncGx1Z2luJyA6ICdjb3JlJywgJ2lkJyA6ICdjb3JlXzAxJywgJ3JlYXNvbicgOiAnTW92aW5nIHBhcmVudCBpbnNpZGUgY2hpbGQnLCAnZGF0YScgOiBKU09OLnN0cmluZ2lmeSh7ICdjaGsnIDogY2hrLCAncG9zJyA6IHBvcywgJ29iaicgOiBvYmogJiYgb2JqLmlkID8gb2JqLmlkIDogZmFsc2UsICdwYXInIDogcGFyICYmIHBhci5pZCA/IHBhci5pZCA6IGZhbHNlIH0pIH07XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRpZih0bXAgJiYgdG1wLmRhdGEpIHsgdG1wID0gdG1wLmRhdGE7IH1cblx0XHRcdGlmKHRtcCAmJiB0bXAuZnVuY3Rpb25zICYmICh0bXAuZnVuY3Rpb25zW2Noa10gPT09IGZhbHNlIHx8IHRtcC5mdW5jdGlvbnNbY2hrXSA9PT0gdHJ1ZSkpIHtcblx0XHRcdFx0aWYodG1wLmZ1bmN0aW9uc1tjaGtdID09PSBmYWxzZSkge1xuXHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5sYXN0X2Vycm9yID0geyAnZXJyb3InIDogJ2NoZWNrJywgJ3BsdWdpbicgOiAnY29yZScsICdpZCcgOiAnY29yZV8wMicsICdyZWFzb24nIDogJ05vZGUgZGF0YSBwcmV2ZW50cyBmdW5jdGlvbjogJyArIGNoaywgJ2RhdGEnIDogSlNPTi5zdHJpbmdpZnkoeyAnY2hrJyA6IGNoaywgJ3BvcycgOiBwb3MsICdvYmonIDogb2JqICYmIG9iai5pZCA/IG9iai5pZCA6IGZhbHNlLCAncGFyJyA6IHBhciAmJiBwYXIuaWQgPyBwYXIuaWQgOiBmYWxzZSB9KSB9O1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0bXAuZnVuY3Rpb25zW2Noa107XG5cdFx0XHR9XG5cdFx0XHRpZihjaGMgPT09IGZhbHNlIHx8ICgkLnZha2F0YS5pc19mdW5jdGlvbihjaGMpICYmIGNoYy5jYWxsKHRoaXMsIGNoaywgb2JqLCBwYXIsIHBvcywgbW9yZSkgPT09IGZhbHNlKSB8fCAoY2hjICYmIGNoY1tjaGtdID09PSBmYWxzZSkpIHtcblx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLmxhc3RfZXJyb3IgPSB7ICdlcnJvcicgOiAnY2hlY2snLCAncGx1Z2luJyA6ICdjb3JlJywgJ2lkJyA6ICdjb3JlXzAzJywgJ3JlYXNvbicgOiAnVXNlciBjb25maWcgZm9yIGNvcmUuY2hlY2tfY2FsbGJhY2sgcHJldmVudHMgZnVuY3Rpb246ICcgKyBjaGssICdkYXRhJyA6IEpTT04uc3RyaW5naWZ5KHsgJ2NoaycgOiBjaGssICdwb3MnIDogcG9zLCAnb2JqJyA6IG9iaiAmJiBvYmouaWQgPyBvYmouaWQgOiBmYWxzZSwgJ3BhcicgOiBwYXIgJiYgcGFyLmlkID8gcGFyLmlkIDogZmFsc2UgfSkgfTtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBnZXQgdGhlIGxhc3QgZXJyb3Jcblx0XHQgKiBAbmFtZSBsYXN0X2Vycm9yKClcblx0XHQgKiBAcmV0dXJuIHtPYmplY3R9XG5cdFx0ICovXG5cdFx0bGFzdF9lcnJvciA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHJldHVybiB0aGlzLl9kYXRhLmNvcmUubGFzdF9lcnJvcjtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIG1vdmUgYSBub2RlIHRvIGEgbmV3IHBhcmVudFxuXHRcdCAqIEBuYW1lIG1vdmVfbm9kZShvYmosIHBhciBbLCBwb3MsIGNhbGxiYWNrLCBpc19sb2FkZWRdKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBvYmogdGhlIG5vZGUgdG8gbW92ZSwgcGFzcyBhbiBhcnJheSB0byBtb3ZlIG11bHRpcGxlIG5vZGVzXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IHBhciB0aGUgbmV3IHBhcmVudFxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBwb3MgdGhlIHBvc2l0aW9uIHRvIGluc2VydCBhdCAoYmVzaWRlcyBpbnRlZ2VyIHZhbHVlcywgXCJmaXJzdFwiIGFuZCBcImxhc3RcIiBhcmUgc3VwcG9ydGVkLCBhcyB3ZWxsIGFzIFwiYmVmb3JlXCIgYW5kIFwiYWZ0ZXJcIiksIGRlZmF1bHRzIHRvIGludGVnZXIgYDBgXG5cdFx0ICogQHBhcmFtICB7ZnVuY3Rpb259IGNhbGxiYWNrIGEgZnVuY3Rpb24gdG8gY2FsbCBvbmNlIHRoZSBtb3ZlIGlzIGNvbXBsZXRlZCwgcmVjZWl2ZXMgMyBhcmd1bWVudHMgLSB0aGUgbm9kZSwgdGhlIG5ldyBwYXJlbnQgYW5kIHRoZSBwb3NpdGlvblxuXHRcdCAqIEBwYXJhbSAge0Jvb2xlYW59IGlzX2xvYWRlZCBpbnRlcm5hbCBwYXJhbWV0ZXIgaW5kaWNhdGluZyBpZiB0aGUgcGFyZW50IG5vZGUgaGFzIGJlZW4gbG9hZGVkXG5cdFx0ICogQHBhcmFtICB7Qm9vbGVhbn0gc2tpcF9yZWRyYXcgaW50ZXJuYWwgcGFyYW1ldGVyIGluZGljYXRpbmcgaWYgdGhlIHRyZWUgc2hvdWxkIGJlIHJlZHJhd25cblx0XHQgKiBAcGFyYW0gIHtCb29sZWFufSBpbnN0YW5jZSBpbnRlcm5hbCBwYXJhbWV0ZXIgaW5kaWNhdGluZyBpZiB0aGUgbm9kZSBjb21lcyBmcm9tIGFub3RoZXIgaW5zdGFuY2Vcblx0XHQgKiBAdHJpZ2dlciBtb3ZlX25vZGUuanN0cmVlXG5cdFx0ICovXG5cdFx0bW92ZV9ub2RlIDogZnVuY3Rpb24gKG9iaiwgcGFyLCBwb3MsIGNhbGxiYWNrLCBpc19sb2FkZWQsIHNraXBfcmVkcmF3LCBvcmlnaW4pIHtcblx0XHRcdHZhciB0MSwgdDIsIG9sZF9wYXIsIG9sZF9wb3MsIG5ld19wYXIsIG9sZF9pbnMsIGlzX211bHRpLCBkcGMsIHRtcCwgaSwgaiwgaywgbCwgcDtcblxuXHRcdFx0cGFyID0gdGhpcy5nZXRfbm9kZShwYXIpO1xuXHRcdFx0cG9zID0gcG9zID09PSB1bmRlZmluZWQgPyAwIDogcG9zO1xuXHRcdFx0aWYoIXBhcikgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdGlmKCFwb3MudG9TdHJpbmcoKS5tYXRjaCgvXihiZWZvcmV8YWZ0ZXIpJC8pICYmICFpc19sb2FkZWQgJiYgIXRoaXMuaXNfbG9hZGVkKHBhcikpIHtcblx0XHRcdFx0cmV0dXJuIHRoaXMubG9hZF9ub2RlKHBhciwgZnVuY3Rpb24gKCkgeyB0aGlzLm1vdmVfbm9kZShvYmosIHBhciwgcG9zLCBjYWxsYmFjaywgdHJ1ZSwgZmFsc2UsIG9yaWdpbik7IH0pO1xuXHRcdFx0fVxuXG5cdFx0XHRpZigkLnZha2F0YS5pc19hcnJheShvYmopKSB7XG5cdFx0XHRcdGlmKG9iai5sZW5ndGggPT09IDEpIHtcblx0XHRcdFx0XHRvYmogPSBvYmpbMF07XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0Ly9vYmogPSBvYmouc2xpY2UoKTtcblx0XHRcdFx0XHRmb3IodDEgPSAwLCB0MiA9IG9iai5sZW5ndGg7IHQxIDwgdDI7IHQxKyspIHtcblx0XHRcdFx0XHRcdGlmKCh0bXAgPSB0aGlzLm1vdmVfbm9kZShvYmpbdDFdLCBwYXIsIHBvcywgY2FsbGJhY2ssIGlzX2xvYWRlZCwgZmFsc2UsIG9yaWdpbikpKSB7XG5cdFx0XHRcdFx0XHRcdHBhciA9IHRtcDtcblx0XHRcdFx0XHRcdFx0cG9zID0gXCJhZnRlclwiO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHR0aGlzLnJlZHJhdygpO1xuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRvYmogPSBvYmogJiYgb2JqLmlkID8gb2JqIDogdGhpcy5nZXRfbm9kZShvYmopO1xuXG5cdFx0XHRpZighb2JqIHx8IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkgeyByZXR1cm4gZmFsc2U7IH1cblxuXHRcdFx0b2xkX3BhciA9IChvYmoucGFyZW50IHx8ICQuanN0cmVlLnJvb3QpLnRvU3RyaW5nKCk7XG5cdFx0XHRuZXdfcGFyID0gKCFwb3MudG9TdHJpbmcoKS5tYXRjaCgvXihiZWZvcmV8YWZ0ZXIpJC8pIHx8IHBhci5pZCA9PT0gJC5qc3RyZWUucm9vdCkgPyBwYXIgOiB0aGlzLmdldF9ub2RlKHBhci5wYXJlbnQpO1xuXHRcdFx0b2xkX2lucyA9IG9yaWdpbiA/IG9yaWdpbiA6ICh0aGlzLl9tb2RlbC5kYXRhW29iai5pZF0gPyB0aGlzIDogJC5qc3RyZWUucmVmZXJlbmNlKG9iai5pZCkpO1xuXHRcdFx0aXNfbXVsdGkgPSAhb2xkX2lucyB8fCAhb2xkX2lucy5faWQgfHwgKHRoaXMuX2lkICE9PSBvbGRfaW5zLl9pZCk7XG5cdFx0XHRvbGRfcG9zID0gb2xkX2lucyAmJiBvbGRfaW5zLl9pZCAmJiBvbGRfcGFyICYmIG9sZF9pbnMuX21vZGVsLmRhdGFbb2xkX3Bhcl0gJiYgb2xkX2lucy5fbW9kZWwuZGF0YVtvbGRfcGFyXS5jaGlsZHJlbiA/ICQuaW5BcnJheShvYmouaWQsIG9sZF9pbnMuX21vZGVsLmRhdGFbb2xkX3Bhcl0uY2hpbGRyZW4pIDogLTE7XG5cdFx0XHRpZihvbGRfaW5zICYmIG9sZF9pbnMuX2lkKSB7XG5cdFx0XHRcdG9iaiA9IG9sZF9pbnMuX21vZGVsLmRhdGFbb2JqLmlkXTtcblx0XHRcdH1cblxuXHRcdFx0aWYoaXNfbXVsdGkpIHtcblx0XHRcdFx0aWYoKHRtcCA9IHRoaXMuY29weV9ub2RlKG9iaiwgcGFyLCBwb3MsIGNhbGxiYWNrLCBpc19sb2FkZWQsIGZhbHNlLCBvcmlnaW4pKSkge1xuXHRcdFx0XHRcdGlmKG9sZF9pbnMpIHsgb2xkX2lucy5kZWxldGVfbm9kZShvYmopOyB9XG5cdFx0XHRcdFx0cmV0dXJuIHRtcDtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHQvL3ZhciBtID0gdGhpcy5fbW9kZWwuZGF0YTtcblx0XHRcdGlmKHBhci5pZCA9PT0gJC5qc3RyZWUucm9vdCkge1xuXHRcdFx0XHRpZihwb3MgPT09IFwiYmVmb3JlXCIpIHsgcG9zID0gXCJmaXJzdFwiOyB9XG5cdFx0XHRcdGlmKHBvcyA9PT0gXCJhZnRlclwiKSB7IHBvcyA9IFwibGFzdFwiOyB9XG5cdFx0XHR9XG5cdFx0XHRzd2l0Y2gocG9zKSB7XG5cdFx0XHRcdGNhc2UgXCJiZWZvcmVcIjpcblx0XHRcdFx0XHRwb3MgPSAkLmluQXJyYXkocGFyLmlkLCBuZXdfcGFyLmNoaWxkcmVuKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBcImFmdGVyXCIgOlxuXHRcdFx0XHRcdHBvcyA9ICQuaW5BcnJheShwYXIuaWQsIG5ld19wYXIuY2hpbGRyZW4pICsgMTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBcImluc2lkZVwiOlxuXHRcdFx0XHRjYXNlIFwiZmlyc3RcIjpcblx0XHRcdFx0XHRwb3MgPSAwO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIFwibGFzdFwiOlxuXHRcdFx0XHRcdHBvcyA9IG5ld19wYXIuY2hpbGRyZW4ubGVuZ3RoO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdGlmKCFwb3MpIHsgcG9zID0gMDsgfVxuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0aWYocG9zID4gbmV3X3Bhci5jaGlsZHJlbi5sZW5ndGgpIHsgcG9zID0gbmV3X3Bhci5jaGlsZHJlbi5sZW5ndGg7IH1cblx0XHRcdGlmKCF0aGlzLmNoZWNrKFwibW92ZV9ub2RlXCIsIG9iaiwgbmV3X3BhciwgcG9zLCB7ICdjb3JlJyA6IHRydWUsICdvcmlnaW4nIDogb3JpZ2luLCAnaXNfbXVsdGknIDogKG9sZF9pbnMgJiYgb2xkX2lucy5faWQgJiYgb2xkX2lucy5faWQgIT09IHRoaXMuX2lkKSwgJ2lzX2ZvcmVpZ24nIDogKCFvbGRfaW5zIHx8ICFvbGRfaW5zLl9pZCkgfSkpIHtcblx0XHRcdFx0dGhpcy5zZXR0aW5ncy5jb3JlLmVycm9yLmNhbGwodGhpcywgdGhpcy5fZGF0YS5jb3JlLmxhc3RfZXJyb3IpO1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRpZihvYmoucGFyZW50ID09PSBuZXdfcGFyLmlkKSB7XG5cdFx0XHRcdGRwYyA9IG5ld19wYXIuY2hpbGRyZW4uY29uY2F0KCk7XG5cdFx0XHRcdHRtcCA9ICQuaW5BcnJheShvYmouaWQsIGRwYyk7XG5cdFx0XHRcdGlmKHRtcCAhPT0gLTEpIHtcblx0XHRcdFx0XHRkcGMgPSAkLnZha2F0YS5hcnJheV9yZW1vdmUoZHBjLCB0bXApO1xuXHRcdFx0XHRcdGlmKHBvcyA+IHRtcCkgeyBwb3MtLTsgfVxuXHRcdFx0XHR9XG5cdFx0XHRcdHRtcCA9IFtdO1xuXHRcdFx0XHRmb3IoaSA9IDAsIGogPSBkcGMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0dG1wW2kgPj0gcG9zID8gaSsxIDogaV0gPSBkcGNbaV07XG5cdFx0XHRcdH1cblx0XHRcdFx0dG1wW3Bvc10gPSBvYmouaWQ7XG5cdFx0XHRcdG5ld19wYXIuY2hpbGRyZW4gPSB0bXA7XG5cdFx0XHRcdHRoaXMuX25vZGVfY2hhbmdlZChuZXdfcGFyLmlkKTtcblx0XHRcdFx0dGhpcy5yZWRyYXcobmV3X3Bhci5pZCA9PT0gJC5qc3RyZWUucm9vdCk7XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0Ly8gY2xlYW4gb2xkIHBhcmVudCBhbmQgdXBcblx0XHRcdFx0dG1wID0gb2JqLmNoaWxkcmVuX2QuY29uY2F0KCk7XG5cdFx0XHRcdHRtcC5wdXNoKG9iai5pZCk7XG5cdFx0XHRcdGZvcihpID0gMCwgaiA9IG9iai5wYXJlbnRzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdGRwYyA9IFtdO1xuXHRcdFx0XHRcdHAgPSBvbGRfaW5zLl9tb2RlbC5kYXRhW29iai5wYXJlbnRzW2ldXS5jaGlsZHJlbl9kO1xuXHRcdFx0XHRcdGZvcihrID0gMCwgbCA9IHAubGVuZ3RoOyBrIDwgbDsgaysrKSB7XG5cdFx0XHRcdFx0XHRpZigkLmluQXJyYXkocFtrXSwgdG1wKSA9PT0gLTEpIHtcblx0XHRcdFx0XHRcdFx0ZHBjLnB1c2gocFtrXSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdG9sZF9pbnMuX21vZGVsLmRhdGFbb2JqLnBhcmVudHNbaV1dLmNoaWxkcmVuX2QgPSBkcGM7XG5cdFx0XHRcdH1cblx0XHRcdFx0b2xkX2lucy5fbW9kZWwuZGF0YVtvbGRfcGFyXS5jaGlsZHJlbiA9ICQudmFrYXRhLmFycmF5X3JlbW92ZV9pdGVtKG9sZF9pbnMuX21vZGVsLmRhdGFbb2xkX3Bhcl0uY2hpbGRyZW4sIG9iai5pZCk7XG5cblx0XHRcdFx0Ly8gaW5zZXJ0IGludG8gbmV3IHBhcmVudCBhbmQgdXBcblx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gbmV3X3Bhci5wYXJlbnRzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdHRoaXMuX21vZGVsLmRhdGFbbmV3X3Bhci5wYXJlbnRzW2ldXS5jaGlsZHJlbl9kID0gdGhpcy5fbW9kZWwuZGF0YVtuZXdfcGFyLnBhcmVudHNbaV1dLmNoaWxkcmVuX2QuY29uY2F0KHRtcCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZHBjID0gW107XG5cdFx0XHRcdGZvcihpID0gMCwgaiA9IG5ld19wYXIuY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0ZHBjW2kgPj0gcG9zID8gaSsxIDogaV0gPSBuZXdfcGFyLmNoaWxkcmVuW2ldO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGRwY1twb3NdID0gb2JqLmlkO1xuXHRcdFx0XHRuZXdfcGFyLmNoaWxkcmVuID0gZHBjO1xuXHRcdFx0XHRuZXdfcGFyLmNoaWxkcmVuX2QucHVzaChvYmouaWQpO1xuXHRcdFx0XHRuZXdfcGFyLmNoaWxkcmVuX2QgPSBuZXdfcGFyLmNoaWxkcmVuX2QuY29uY2F0KG9iai5jaGlsZHJlbl9kKTtcblxuXHRcdFx0XHQvLyB1cGRhdGUgb2JqZWN0XG5cdFx0XHRcdG9iai5wYXJlbnQgPSBuZXdfcGFyLmlkO1xuXHRcdFx0XHR0bXAgPSBuZXdfcGFyLnBhcmVudHMuY29uY2F0KCk7XG5cdFx0XHRcdHRtcC51bnNoaWZ0KG5ld19wYXIuaWQpO1xuXHRcdFx0XHRwID0gb2JqLnBhcmVudHMubGVuZ3RoO1xuXHRcdFx0XHRvYmoucGFyZW50cyA9IHRtcDtcblxuXHRcdFx0XHQvLyB1cGRhdGUgb2JqZWN0IGNoaWxkcmVuXG5cdFx0XHRcdHRtcCA9IHRtcC5jb25jYXQoKTtcblx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gb2JqLmNoaWxkcmVuX2QubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0dGhpcy5fbW9kZWwuZGF0YVtvYmouY2hpbGRyZW5fZFtpXV0ucGFyZW50cyA9IHRoaXMuX21vZGVsLmRhdGFbb2JqLmNoaWxkcmVuX2RbaV1dLnBhcmVudHMuc2xpY2UoMCxwKi0xKTtcblx0XHRcdFx0XHRBcnJheS5wcm90b3R5cGUucHVzaC5hcHBseSh0aGlzLl9tb2RlbC5kYXRhW29iai5jaGlsZHJlbl9kW2ldXS5wYXJlbnRzLCB0bXApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYob2xkX3BhciA9PT0gJC5qc3RyZWUucm9vdCB8fCBuZXdfcGFyLmlkID09PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdFx0dGhpcy5fbW9kZWwuZm9yY2VfZnVsbF9yZWRyYXcgPSB0cnVlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKCF0aGlzLl9tb2RlbC5mb3JjZV9mdWxsX3JlZHJhdykge1xuXHRcdFx0XHRcdHRoaXMuX25vZGVfY2hhbmdlZChvbGRfcGFyKTtcblx0XHRcdFx0XHR0aGlzLl9ub2RlX2NoYW5nZWQobmV3X3Bhci5pZCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYoIXNraXBfcmVkcmF3KSB7XG5cdFx0XHRcdFx0dGhpcy5yZWRyYXcoKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0aWYoY2FsbGJhY2spIHsgY2FsbGJhY2suY2FsbCh0aGlzLCBvYmosIG5ld19wYXIsIHBvcyk7IH1cblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYSBub2RlIGlzIG1vdmVkXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIG1vdmVfbm9kZS5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlXG5cdFx0XHQgKiBAcGFyYW0ge1N0cmluZ30gcGFyZW50IHRoZSBwYXJlbnQncyBJRFxuXHRcdFx0ICogQHBhcmFtIHtOdW1iZXJ9IHBvc2l0aW9uIHRoZSBwb3NpdGlvbiBvZiB0aGUgbm9kZSBhbW9uZyB0aGUgcGFyZW50J3MgY2hpbGRyZW5cblx0XHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBvbGRfcGFyZW50IHRoZSBvbGQgcGFyZW50IG9mIHRoZSBub2RlXG5cdFx0XHQgKiBAcGFyYW0ge051bWJlcn0gb2xkX3Bvc2l0aW9uIHRoZSBvbGQgcG9zaXRpb24gb2YgdGhlIG5vZGVcblx0XHRcdCAqIEBwYXJhbSB7Qm9vbGVhbn0gaXNfbXVsdGkgZG8gdGhlIG5vZGUgYW5kIG5ldyBwYXJlbnQgYmVsb25nIHRvIGRpZmZlcmVudCBpbnN0YW5jZXNcblx0XHRcdCAqIEBwYXJhbSB7anNUcmVlfSBvbGRfaW5zdGFuY2UgdGhlIGluc3RhbmNlIHRoZSBub2RlIGNhbWUgZnJvbVxuXHRcdFx0ICogQHBhcmFtIHtqc1RyZWV9IG5ld19pbnN0YW5jZSB0aGUgaW5zdGFuY2Ugb2YgdGhlIG5ldyBwYXJlbnRcblx0XHRcdCAqL1xuXHRcdFx0dGhpcy50cmlnZ2VyKCdtb3ZlX25vZGUnLCB7IFwibm9kZVwiIDogb2JqLCBcInBhcmVudFwiIDogbmV3X3Bhci5pZCwgXCJwb3NpdGlvblwiIDogcG9zLCBcIm9sZF9wYXJlbnRcIiA6IG9sZF9wYXIsIFwib2xkX3Bvc2l0aW9uXCIgOiBvbGRfcG9zLCAnaXNfbXVsdGknIDogKG9sZF9pbnMgJiYgb2xkX2lucy5faWQgJiYgb2xkX2lucy5faWQgIT09IHRoaXMuX2lkKSwgJ2lzX2ZvcmVpZ24nIDogKCFvbGRfaW5zIHx8ICFvbGRfaW5zLl9pZCksICdvbGRfaW5zdGFuY2UnIDogb2xkX2lucywgJ25ld19pbnN0YW5jZScgOiB0aGlzIH0pO1xuXHRcdFx0cmV0dXJuIG9iai5pZDtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGNvcHkgYSBub2RlIHRvIGEgbmV3IHBhcmVudFxuXHRcdCAqIEBuYW1lIGNvcHlfbm9kZShvYmosIHBhciBbLCBwb3MsIGNhbGxiYWNrLCBpc19sb2FkZWRdKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBvYmogdGhlIG5vZGUgdG8gY29weSwgcGFzcyBhbiBhcnJheSB0byBjb3B5IG11bHRpcGxlIG5vZGVzXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IHBhciB0aGUgbmV3IHBhcmVudFxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBwb3MgdGhlIHBvc2l0aW9uIHRvIGluc2VydCBhdCAoYmVzaWRlcyBpbnRlZ2VyIHZhbHVlcywgXCJmaXJzdFwiIGFuZCBcImxhc3RcIiBhcmUgc3VwcG9ydGVkLCBhcyB3ZWxsIGFzIFwiYmVmb3JlXCIgYW5kIFwiYWZ0ZXJcIiksIGRlZmF1bHRzIHRvIGludGVnZXIgYDBgXG5cdFx0ICogQHBhcmFtICB7ZnVuY3Rpb259IGNhbGxiYWNrIGEgZnVuY3Rpb24gdG8gY2FsbCBvbmNlIHRoZSBtb3ZlIGlzIGNvbXBsZXRlZCwgcmVjZWl2ZXMgMyBhcmd1bWVudHMgLSB0aGUgbm9kZSwgdGhlIG5ldyBwYXJlbnQgYW5kIHRoZSBwb3NpdGlvblxuXHRcdCAqIEBwYXJhbSAge0Jvb2xlYW59IGlzX2xvYWRlZCBpbnRlcm5hbCBwYXJhbWV0ZXIgaW5kaWNhdGluZyBpZiB0aGUgcGFyZW50IG5vZGUgaGFzIGJlZW4gbG9hZGVkXG5cdFx0ICogQHBhcmFtICB7Qm9vbGVhbn0gc2tpcF9yZWRyYXcgaW50ZXJuYWwgcGFyYW1ldGVyIGluZGljYXRpbmcgaWYgdGhlIHRyZWUgc2hvdWxkIGJlIHJlZHJhd25cblx0XHQgKiBAcGFyYW0gIHtCb29sZWFufSBpbnN0YW5jZSBpbnRlcm5hbCBwYXJhbWV0ZXIgaW5kaWNhdGluZyBpZiB0aGUgbm9kZSBjb21lcyBmcm9tIGFub3RoZXIgaW5zdGFuY2Vcblx0XHQgKiBAdHJpZ2dlciBtb2RlbC5qc3RyZWUgY29weV9ub2RlLmpzdHJlZVxuXHRcdCAqL1xuXHRcdGNvcHlfbm9kZSA6IGZ1bmN0aW9uIChvYmosIHBhciwgcG9zLCBjYWxsYmFjaywgaXNfbG9hZGVkLCBza2lwX3JlZHJhdywgb3JpZ2luKSB7XG5cdFx0XHR2YXIgdDEsIHQyLCBkcGMsIHRtcCwgaSwgaiwgbm9kZSwgb2xkX3BhciwgbmV3X3Bhciwgb2xkX2lucywgaXNfbXVsdGk7XG5cblx0XHRcdHBhciA9IHRoaXMuZ2V0X25vZGUocGFyKTtcblx0XHRcdHBvcyA9IHBvcyA9PT0gdW5kZWZpbmVkID8gMCA6IHBvcztcblx0XHRcdGlmKCFwYXIpIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHRpZighcG9zLnRvU3RyaW5nKCkubWF0Y2goL14oYmVmb3JlfGFmdGVyKSQvKSAmJiAhaXNfbG9hZGVkICYmICF0aGlzLmlzX2xvYWRlZChwYXIpKSB7XG5cdFx0XHRcdHJldHVybiB0aGlzLmxvYWRfbm9kZShwYXIsIGZ1bmN0aW9uICgpIHsgdGhpcy5jb3B5X25vZGUob2JqLCBwYXIsIHBvcywgY2FsbGJhY2ssIHRydWUsIGZhbHNlLCBvcmlnaW4pOyB9KTtcblx0XHRcdH1cblxuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkob2JqKSkge1xuXHRcdFx0XHRpZihvYmoubGVuZ3RoID09PSAxKSB7XG5cdFx0XHRcdFx0b2JqID0gb2JqWzBdO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdC8vb2JqID0gb2JqLnNsaWNlKCk7XG5cdFx0XHRcdFx0Zm9yKHQxID0gMCwgdDIgPSBvYmoubGVuZ3RoOyB0MSA8IHQyOyB0MSsrKSB7XG5cdFx0XHRcdFx0XHRpZigodG1wID0gdGhpcy5jb3B5X25vZGUob2JqW3QxXSwgcGFyLCBwb3MsIGNhbGxiYWNrLCBpc19sb2FkZWQsIHRydWUsIG9yaWdpbikpKSB7XG5cdFx0XHRcdFx0XHRcdHBhciA9IHRtcDtcblx0XHRcdFx0XHRcdFx0cG9zID0gXCJhZnRlclwiO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHR0aGlzLnJlZHJhdygpO1xuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRvYmogPSBvYmogJiYgb2JqLmlkID8gb2JqIDogdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaiB8fCBvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHsgcmV0dXJuIGZhbHNlOyB9XG5cblx0XHRcdG9sZF9wYXIgPSAob2JqLnBhcmVudCB8fCAkLmpzdHJlZS5yb290KS50b1N0cmluZygpO1xuXHRcdFx0bmV3X3BhciA9ICghcG9zLnRvU3RyaW5nKCkubWF0Y2goL14oYmVmb3JlfGFmdGVyKSQvKSB8fCBwYXIuaWQgPT09ICQuanN0cmVlLnJvb3QpID8gcGFyIDogdGhpcy5nZXRfbm9kZShwYXIucGFyZW50KTtcblx0XHRcdG9sZF9pbnMgPSBvcmlnaW4gPyBvcmlnaW4gOiAodGhpcy5fbW9kZWwuZGF0YVtvYmouaWRdID8gdGhpcyA6ICQuanN0cmVlLnJlZmVyZW5jZShvYmouaWQpKTtcblx0XHRcdGlzX211bHRpID0gIW9sZF9pbnMgfHwgIW9sZF9pbnMuX2lkIHx8ICh0aGlzLl9pZCAhPT0gb2xkX2lucy5faWQpO1xuXG5cdFx0XHRpZihvbGRfaW5zICYmIG9sZF9pbnMuX2lkKSB7XG5cdFx0XHRcdG9iaiA9IG9sZF9pbnMuX21vZGVsLmRhdGFbb2JqLmlkXTtcblx0XHRcdH1cblxuXHRcdFx0aWYocGFyLmlkID09PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdGlmKHBvcyA9PT0gXCJiZWZvcmVcIikgeyBwb3MgPSBcImZpcnN0XCI7IH1cblx0XHRcdFx0aWYocG9zID09PSBcImFmdGVyXCIpIHsgcG9zID0gXCJsYXN0XCI7IH1cblx0XHRcdH1cblx0XHRcdHN3aXRjaChwb3MpIHtcblx0XHRcdFx0Y2FzZSBcImJlZm9yZVwiOlxuXHRcdFx0XHRcdHBvcyA9ICQuaW5BcnJheShwYXIuaWQsIG5ld19wYXIuY2hpbGRyZW4pO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIFwiYWZ0ZXJcIiA6XG5cdFx0XHRcdFx0cG9zID0gJC5pbkFycmF5KHBhci5pZCwgbmV3X3Bhci5jaGlsZHJlbikgKyAxO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIFwiaW5zaWRlXCI6XG5cdFx0XHRcdGNhc2UgXCJmaXJzdFwiOlxuXHRcdFx0XHRcdHBvcyA9IDA7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgXCJsYXN0XCI6XG5cdFx0XHRcdFx0cG9zID0gbmV3X3Bhci5jaGlsZHJlbi5sZW5ndGg7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdFx0aWYoIXBvcykgeyBwb3MgPSAwOyB9XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0XHRpZihwb3MgPiBuZXdfcGFyLmNoaWxkcmVuLmxlbmd0aCkgeyBwb3MgPSBuZXdfcGFyLmNoaWxkcmVuLmxlbmd0aDsgfVxuXHRcdFx0aWYoIXRoaXMuY2hlY2soXCJjb3B5X25vZGVcIiwgb2JqLCBuZXdfcGFyLCBwb3MsIHsgJ2NvcmUnIDogdHJ1ZSwgJ29yaWdpbicgOiBvcmlnaW4sICdpc19tdWx0aScgOiAob2xkX2lucyAmJiBvbGRfaW5zLl9pZCAmJiBvbGRfaW5zLl9pZCAhPT0gdGhpcy5faWQpLCAnaXNfZm9yZWlnbicgOiAoIW9sZF9pbnMgfHwgIW9sZF9pbnMuX2lkKSB9KSkge1xuXHRcdFx0XHR0aGlzLnNldHRpbmdzLmNvcmUuZXJyb3IuY2FsbCh0aGlzLCB0aGlzLl9kYXRhLmNvcmUubGFzdF9lcnJvcik7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdG5vZGUgPSBvbGRfaW5zID8gb2xkX2lucy5nZXRfanNvbihvYmosIHsgbm9faWQgOiB0cnVlLCBub19kYXRhIDogdHJ1ZSwgbm9fc3RhdGUgOiB0cnVlIH0pIDogb2JqO1xuXHRcdFx0aWYoIW5vZGUpIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHRpZihub2RlLmlkID09PSB0cnVlKSB7IGRlbGV0ZSBub2RlLmlkOyB9XG5cdFx0XHRub2RlID0gdGhpcy5fcGFyc2VfbW9kZWxfZnJvbV9qc29uKG5vZGUsIG5ld19wYXIuaWQsIG5ld19wYXIucGFyZW50cy5jb25jYXQoKSk7XG5cdFx0XHRpZighbm9kZSkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdHRtcCA9IHRoaXMuZ2V0X25vZGUobm9kZSk7XG5cdFx0XHRpZihvYmogJiYgb2JqLnN0YXRlICYmIG9iai5zdGF0ZS5sb2FkZWQgPT09IGZhbHNlKSB7IHRtcC5zdGF0ZS5sb2FkZWQgPSBmYWxzZTsgfVxuXHRcdFx0ZHBjID0gW107XG5cdFx0XHRkcGMucHVzaChub2RlKTtcblx0XHRcdGRwYyA9IGRwYy5jb25jYXQodG1wLmNoaWxkcmVuX2QpO1xuXHRcdFx0dGhpcy50cmlnZ2VyKCdtb2RlbCcsIHsgXCJub2Rlc1wiIDogZHBjLCBcInBhcmVudFwiIDogbmV3X3Bhci5pZCB9KTtcblxuXHRcdFx0Ly8gaW5zZXJ0IGludG8gbmV3IHBhcmVudCBhbmQgdXBcblx0XHRcdGZvcihpID0gMCwgaiA9IG5ld19wYXIucGFyZW50cy5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0dGhpcy5fbW9kZWwuZGF0YVtuZXdfcGFyLnBhcmVudHNbaV1dLmNoaWxkcmVuX2QgPSB0aGlzLl9tb2RlbC5kYXRhW25ld19wYXIucGFyZW50c1tpXV0uY2hpbGRyZW5fZC5jb25jYXQoZHBjKTtcblx0XHRcdH1cblx0XHRcdGRwYyA9IFtdO1xuXHRcdFx0Zm9yKGkgPSAwLCBqID0gbmV3X3Bhci5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0ZHBjW2kgPj0gcG9zID8gaSsxIDogaV0gPSBuZXdfcGFyLmNoaWxkcmVuW2ldO1xuXHRcdFx0fVxuXHRcdFx0ZHBjW3Bvc10gPSB0bXAuaWQ7XG5cdFx0XHRuZXdfcGFyLmNoaWxkcmVuID0gZHBjO1xuXHRcdFx0bmV3X3Bhci5jaGlsZHJlbl9kLnB1c2godG1wLmlkKTtcblx0XHRcdG5ld19wYXIuY2hpbGRyZW5fZCA9IG5ld19wYXIuY2hpbGRyZW5fZC5jb25jYXQodG1wLmNoaWxkcmVuX2QpO1xuXG5cdFx0XHRpZihuZXdfcGFyLmlkID09PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdHRoaXMuX21vZGVsLmZvcmNlX2Z1bGxfcmVkcmF3ID0gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdGlmKCF0aGlzLl9tb2RlbC5mb3JjZV9mdWxsX3JlZHJhdykge1xuXHRcdFx0XHR0aGlzLl9ub2RlX2NoYW5nZWQobmV3X3Bhci5pZCk7XG5cdFx0XHR9XG5cdFx0XHRpZighc2tpcF9yZWRyYXcpIHtcblx0XHRcdFx0dGhpcy5yZWRyYXcobmV3X3Bhci5pZCA9PT0gJC5qc3RyZWUucm9vdCk7XG5cdFx0XHR9XG5cdFx0XHRpZihjYWxsYmFjaykgeyBjYWxsYmFjay5jYWxsKHRoaXMsIHRtcCwgbmV3X3BhciwgcG9zKTsgfVxuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiBhIG5vZGUgaXMgY29waWVkXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGNvcHlfbm9kZS5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlIHRoZSBjb3BpZWQgbm9kZVxuXHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IG9yaWdpbmFsIHRoZSBvcmlnaW5hbCBub2RlXG5cdFx0XHQgKiBAcGFyYW0ge1N0cmluZ30gcGFyZW50IHRoZSBwYXJlbnQncyBJRFxuXHRcdFx0ICogQHBhcmFtIHtOdW1iZXJ9IHBvc2l0aW9uIHRoZSBwb3NpdGlvbiBvZiB0aGUgbm9kZSBhbW9uZyB0aGUgcGFyZW50J3MgY2hpbGRyZW5cblx0XHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBvbGRfcGFyZW50IHRoZSBvbGQgcGFyZW50IG9mIHRoZSBub2RlXG5cdFx0XHQgKiBAcGFyYW0ge051bWJlcn0gb2xkX3Bvc2l0aW9uIHRoZSBwb3NpdGlvbiBvZiB0aGUgb3JpZ2luYWwgbm9kZVxuXHRcdFx0ICogQHBhcmFtIHtCb29sZWFufSBpc19tdWx0aSBkbyB0aGUgbm9kZSBhbmQgbmV3IHBhcmVudCBiZWxvbmcgdG8gZGlmZmVyZW50IGluc3RhbmNlc1xuXHRcdFx0ICogQHBhcmFtIHtqc1RyZWV9IG9sZF9pbnN0YW5jZSB0aGUgaW5zdGFuY2UgdGhlIG5vZGUgY2FtZSBmcm9tXG5cdFx0XHQgKiBAcGFyYW0ge2pzVHJlZX0gbmV3X2luc3RhbmNlIHRoZSBpbnN0YW5jZSBvZiB0aGUgbmV3IHBhcmVudFxuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ2NvcHlfbm9kZScsIHsgXCJub2RlXCIgOiB0bXAsIFwib3JpZ2luYWxcIiA6IG9iaiwgXCJwYXJlbnRcIiA6IG5ld19wYXIuaWQsIFwicG9zaXRpb25cIiA6IHBvcywgXCJvbGRfcGFyZW50XCIgOiBvbGRfcGFyLCBcIm9sZF9wb3NpdGlvblwiIDogb2xkX2lucyAmJiBvbGRfaW5zLl9pZCAmJiBvbGRfcGFyICYmIG9sZF9pbnMuX21vZGVsLmRhdGFbb2xkX3Bhcl0gJiYgb2xkX2lucy5fbW9kZWwuZGF0YVtvbGRfcGFyXS5jaGlsZHJlbiA/ICQuaW5BcnJheShvYmouaWQsIG9sZF9pbnMuX21vZGVsLmRhdGFbb2xkX3Bhcl0uY2hpbGRyZW4pIDogLTEsJ2lzX211bHRpJyA6IChvbGRfaW5zICYmIG9sZF9pbnMuX2lkICYmIG9sZF9pbnMuX2lkICE9PSB0aGlzLl9pZCksICdpc19mb3JlaWduJyA6ICghb2xkX2lucyB8fCAhb2xkX2lucy5faWQpLCAnb2xkX2luc3RhbmNlJyA6IG9sZF9pbnMsICduZXdfaW5zdGFuY2UnIDogdGhpcyB9KTtcblx0XHRcdHJldHVybiB0bXAuaWQ7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBjdXQgYSBub2RlIChhIGxhdGVyIGNhbGwgdG8gYHBhc3RlKG9iailgIHdvdWxkIG1vdmUgdGhlIG5vZGUpXG5cdFx0ICogQG5hbWUgY3V0KG9iailcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqIG11bHRpcGxlIG9iamVjdHMgY2FuIGJlIHBhc3NlZCB1c2luZyBhbiBhcnJheVxuXHRcdCAqIEB0cmlnZ2VyIGN1dC5qc3RyZWVcblx0XHQgKi9cblx0XHRjdXQgOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHRpZighb2JqKSB7IG9iaiA9IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZC5jb25jYXQoKTsgfVxuXHRcdFx0aWYoISQudmFrYXRhLmlzX2FycmF5KG9iaikpIHsgb2JqID0gW29ial07IH1cblx0XHRcdGlmKCFvYmoubGVuZ3RoKSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdFx0dmFyIHRtcCA9IFtdLCBvLCB0MSwgdDI7XG5cdFx0XHRmb3IodDEgPSAwLCB0MiA9IG9iai5sZW5ndGg7IHQxIDwgdDI7IHQxKyspIHtcblx0XHRcdFx0byA9IHRoaXMuZ2V0X25vZGUob2JqW3QxXSk7XG5cdFx0XHRcdGlmKG8gJiYgby5pZCAmJiBvLmlkICE9PSAkLmpzdHJlZS5yb290KSB7IHRtcC5wdXNoKG8pOyB9XG5cdFx0XHR9XG5cdFx0XHRpZighdG1wLmxlbmd0aCkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdGNjcF9ub2RlID0gdG1wO1xuXHRcdFx0Y2NwX2luc3QgPSB0aGlzO1xuXHRcdFx0Y2NwX21vZGUgPSAnbW92ZV9ub2RlJztcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gbm9kZXMgYXJlIGFkZGVkIHRvIHRoZSBidWZmZXIgZm9yIG1vdmluZ1xuXHRcdFx0ICogQGV2ZW50XG5cdFx0XHQgKiBAbmFtZSBjdXQuanN0cmVlXG5cdFx0XHQgKiBAcGFyYW0ge0FycmF5fSBub2RlXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignY3V0JywgeyBcIm5vZGVcIiA6IG9iaiB9KTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGNvcHkgYSBub2RlIChhIGxhdGVyIGNhbGwgdG8gYHBhc3RlKG9iailgIHdvdWxkIGNvcHkgdGhlIG5vZGUpXG5cdFx0ICogQG5hbWUgY29weShvYmopXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9iaiBtdWx0aXBsZSBvYmplY3RzIGNhbiBiZSBwYXNzZWQgdXNpbmcgYW4gYXJyYXlcblx0XHQgKiBAdHJpZ2dlciBjb3B5LmpzdHJlZVxuXHRcdCAqL1xuXHRcdGNvcHkgOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHRpZighb2JqKSB7IG9iaiA9IHRoaXMuX2RhdGEuY29yZS5zZWxlY3RlZC5jb25jYXQoKTsgfVxuXHRcdFx0aWYoISQudmFrYXRhLmlzX2FycmF5KG9iaikpIHsgb2JqID0gW29ial07IH1cblx0XHRcdGlmKCFvYmoubGVuZ3RoKSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdFx0dmFyIHRtcCA9IFtdLCBvLCB0MSwgdDI7XG5cdFx0XHRmb3IodDEgPSAwLCB0MiA9IG9iai5sZW5ndGg7IHQxIDwgdDI7IHQxKyspIHtcblx0XHRcdFx0byA9IHRoaXMuZ2V0X25vZGUob2JqW3QxXSk7XG5cdFx0XHRcdGlmKG8gJiYgby5pZCAmJiBvLmlkICE9PSAkLmpzdHJlZS5yb290KSB7IHRtcC5wdXNoKG8pOyB9XG5cdFx0XHR9XG5cdFx0XHRpZighdG1wLmxlbmd0aCkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdGNjcF9ub2RlID0gdG1wO1xuXHRcdFx0Y2NwX2luc3QgPSB0aGlzO1xuXHRcdFx0Y2NwX21vZGUgPSAnY29weV9ub2RlJztcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gbm9kZXMgYXJlIGFkZGVkIHRvIHRoZSBidWZmZXIgZm9yIGNvcHlpbmdcblx0XHRcdCAqIEBldmVudFxuXHRcdFx0ICogQG5hbWUgY29weS5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7QXJyYXl9IG5vZGVcblx0XHRcdCAqL1xuXHRcdFx0dGhpcy50cmlnZ2VyKCdjb3B5JywgeyBcIm5vZGVcIiA6IG9iaiB9KTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGdldCB0aGUgY3VycmVudCBidWZmZXIgKGFueSBub2RlcyB0aGF0IGFyZSB3YWl0aW5nIGZvciBhIHBhc3RlIG9wZXJhdGlvbilcblx0XHQgKiBAbmFtZSBnZXRfYnVmZmVyKClcblx0XHQgKiBAcmV0dXJuIHtPYmplY3R9IGFuIG9iamVjdCBjb25zaXN0aW5nIG9mIGBtb2RlYCAoXCJjb3B5X25vZGVcIiBvciBcIm1vdmVfbm9kZVwiKSwgYG5vZGVgIChhbiBhcnJheSBvZiBvYmplY3RzKSBhbmQgYGluc3RgICh0aGUgaW5zdGFuY2UpXG5cdFx0ICovXG5cdFx0Z2V0X2J1ZmZlciA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHJldHVybiB7ICdtb2RlJyA6IGNjcF9tb2RlLCAnbm9kZScgOiBjY3Bfbm9kZSwgJ2luc3QnIDogY2NwX2luc3QgfTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGNoZWNrIGlmIHRoZXJlIGlzIHNvbWV0aGluZyBpbiB0aGUgYnVmZmVyIHRvIHBhc3RlXG5cdFx0ICogQG5hbWUgY2FuX3Bhc3RlKClcblx0XHQgKiBAcmV0dXJuIHtCb29sZWFufVxuXHRcdCAqL1xuXHRcdGNhbl9wYXN0ZSA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHJldHVybiBjY3BfbW9kZSAhPT0gZmFsc2UgJiYgY2NwX25vZGUgIT09IGZhbHNlOyAvLyAmJiBjY3BfaW5zdC5fbW9kZWwuZGF0YVtjY3Bfbm9kZV07XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBjb3B5IG9yIG1vdmUgdGhlIHByZXZpb3VzbHkgY3V0IG9yIGNvcGllZCBub2RlcyB0byBhIG5ldyBwYXJlbnRcblx0XHQgKiBAbmFtZSBwYXN0ZShvYmogWywgcG9zXSlcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqIHRoZSBuZXcgcGFyZW50XG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IHBvcyB0aGUgcG9zaXRpb24gdG8gaW5zZXJ0IGF0IChiZXNpZGVzIGludGVnZXIsIFwiZmlyc3RcIiBhbmQgXCJsYXN0XCIgYXJlIHN1cHBvcnRlZCksIGRlZmF1bHRzIHRvIGludGVnZXIgYDBgXG5cdFx0ICogQHRyaWdnZXIgcGFzdGUuanN0cmVlXG5cdFx0ICovXG5cdFx0cGFzdGUgOiBmdW5jdGlvbiAob2JqLCBwb3MpIHtcblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdGlmKCFvYmogfHwgIWNjcF9tb2RlIHx8ICFjY3BfbW9kZS5tYXRjaCgvXihjb3B5X25vZGV8bW92ZV9ub2RlKSQvKSB8fCAhY2NwX25vZGUpIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHRpZih0aGlzW2NjcF9tb2RlXShjY3Bfbm9kZSwgb2JqLCBwb3MsIGZhbHNlLCBmYWxzZSwgZmFsc2UsIGNjcF9pbnN0KSkge1xuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gcGFzdGUgaXMgaW52b2tlZFxuXHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0ICogQG5hbWUgcGFzdGUuanN0cmVlXG5cdFx0XHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBwYXJlbnQgdGhlIElEIG9mIHRoZSByZWNlaXZpbmcgbm9kZVxuXHRcdFx0XHQgKiBAcGFyYW0ge0FycmF5fSBub2RlIHRoZSBub2RlcyBpbiB0aGUgYnVmZmVyXG5cdFx0XHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBtb2RlIHRoZSBwZXJmb3JtZWQgb3BlcmF0aW9uIC0gXCJjb3B5X25vZGVcIiBvciBcIm1vdmVfbm9kZVwiXG5cdFx0XHRcdCAqL1xuXHRcdFx0XHR0aGlzLnRyaWdnZXIoJ3Bhc3RlJywgeyBcInBhcmVudFwiIDogb2JqLmlkLCBcIm5vZGVcIiA6IGNjcF9ub2RlLCBcIm1vZGVcIiA6IGNjcF9tb2RlIH0pO1xuXHRcdFx0fVxuXHRcdFx0Y2NwX25vZGUgPSBmYWxzZTtcblx0XHRcdGNjcF9tb2RlID0gZmFsc2U7XG5cdFx0XHRjY3BfaW5zdCA9IGZhbHNlO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogY2xlYXIgdGhlIGJ1ZmZlciBvZiBwcmV2aW91c2x5IGNvcGllZCBvciBjdXQgbm9kZXNcblx0XHQgKiBAbmFtZSBjbGVhcl9idWZmZXIoKVxuXHRcdCAqIEB0cmlnZ2VyIGNsZWFyX2J1ZmZlci5qc3RyZWVcblx0XHQgKi9cblx0XHRjbGVhcl9idWZmZXIgOiBmdW5jdGlvbiAoKSB7XG5cdFx0XHRjY3Bfbm9kZSA9IGZhbHNlO1xuXHRcdFx0Y2NwX21vZGUgPSBmYWxzZTtcblx0XHRcdGNjcF9pbnN0ID0gZmFsc2U7XG5cdFx0XHQvKipcblx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIHRoZSBjb3B5IC8gY3V0IGJ1ZmZlciBpcyBjbGVhcmVkXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGNsZWFyX2J1ZmZlci5qc3RyZWVcblx0XHRcdCAqL1xuXHRcdFx0dGhpcy50cmlnZ2VyKCdjbGVhcl9idWZmZXInKTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIHB1dCBhIG5vZGUgaW4gZWRpdCBtb2RlIChpbnB1dCBmaWVsZCB0byByZW5hbWUgdGhlIG5vZGUpXG5cdFx0ICogQG5hbWUgZWRpdChvYmogWywgZGVmYXVsdF90ZXh0LCBjYWxsYmFja10pXG5cdFx0ICogQHBhcmFtICB7bWl4ZWR9IG9ialxuXHRcdCAqIEBwYXJhbSAge1N0cmluZ30gZGVmYXVsdF90ZXh0IHRoZSB0ZXh0IHRvIHBvcHVsYXRlIHRoZSBpbnB1dCB3aXRoIChpZiBvbWl0dGVkIG9yIHNldCB0byBhIG5vbi1zdHJpbmcgdmFsdWUgdGhlIG5vZGUncyB0ZXh0IHZhbHVlIGlzIHVzZWQpXG5cdFx0ICogQHBhcmFtICB7RnVuY3Rpb259IGNhbGxiYWNrIGEgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIG9uY2UgdGhlIHRleHQgYm94IGlzIGJsdXJyZWQsIGl0IGlzIGNhbGxlZCBpbiB0aGUgaW5zdGFuY2UncyBzY29wZSBhbmQgcmVjZWl2ZXMgdGhlIG5vZGUsIGEgc3RhdHVzIHBhcmFtZXRlciAodHJ1ZSBpZiB0aGUgcmVuYW1lIGlzIHN1Y2Nlc3NmdWwsIGZhbHNlIG90aGVyd2lzZSksIGEgYm9vbGVhbiBpbmRpY2F0aW5nIGlmIHRoZSB1c2VyIGNhbmNlbGxlZCB0aGUgZWRpdCBhbmQgdGhlIG9yaWdpbmFsIHVuZXNjYXBlZCB2YWx1ZSBwcm92aWRlZCBieSB0aGUgdXNlci4gWW91IGNhbiBhbHNvIGFjY2VzcyB0aGUgbm9kZSdzIHRpdGxlIHVzaW5nIC50ZXh0XG5cdFx0ICovXG5cdFx0ZWRpdCA6IGZ1bmN0aW9uIChvYmosIGRlZmF1bHRfdGV4dCwgY2FsbGJhY2spIHtcblx0XHRcdHZhciBydGwsIHcsIGEsIHMsIHQsIGgxLCBoMiwgZm4sIHRtcCwgY2FuY2VsID0gZmFsc2U7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqKSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdFx0aWYoIXRoaXMuY2hlY2soXCJlZGl0XCIsIG9iaiwgdGhpcy5nZXRfcGFyZW50KG9iaikpKSB7XG5cdFx0XHRcdHRoaXMuc2V0dGluZ3MuY29yZS5lcnJvci5jYWxsKHRoaXMsIHRoaXMuX2RhdGEuY29yZS5sYXN0X2Vycm9yKTtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0dG1wID0gb2JqO1xuXHRcdFx0ZGVmYXVsdF90ZXh0ID0gdHlwZW9mIGRlZmF1bHRfdGV4dCA9PT0gJ3N0cmluZycgPyBkZWZhdWx0X3RleHQgOiBvYmoudGV4dDtcblx0XHRcdHRoaXMuc2V0X3RleHQob2JqLCBcIlwiKTtcblx0XHRcdG9iaiA9IHRoaXMuX29wZW5fdG8ob2JqKTtcblx0XHRcdHRtcC50ZXh0ID0gZGVmYXVsdF90ZXh0O1xuXG5cdFx0XHRydGwgPSB0aGlzLl9kYXRhLmNvcmUucnRsO1xuXHRcdFx0dyAgPSB0aGlzLmVsZW1lbnQud2lkdGgoKTtcblx0XHRcdHRoaXMuX2RhdGEuY29yZS5mb2N1c2VkID0gdG1wLmlkO1xuXHRcdFx0YSAgPSBvYmouY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykudHJpZ2dlcignZm9jdXMnKTtcblx0XHRcdHMgID0gJCgnPHNwYW4+PC9zcGFuPicpO1xuXHRcdFx0LyohXG5cdFx0XHRvaSA9IG9iai5jaGlsZHJlbihcImk6dmlzaWJsZVwiKSxcblx0XHRcdGFpID0gYS5jaGlsZHJlbihcImk6dmlzaWJsZVwiKSxcblx0XHRcdHcxID0gb2kud2lkdGgoKSAqIG9pLmxlbmd0aCxcblx0XHRcdHcyID0gYWkud2lkdGgoKSAqIGFpLmxlbmd0aCxcblx0XHRcdCovXG5cdFx0XHR0ICA9IGRlZmF1bHRfdGV4dDtcblx0XHRcdGgxID0gJChcIjxcIitcImRpdj48L2Rpdj5cIiwgeyBjc3MgOiB7IFwicG9zaXRpb25cIiA6IFwiYWJzb2x1dGVcIiwgXCJ0b3BcIiA6IFwiLTIwMHB4XCIsIFwibGVmdFwiIDogKHJ0bCA/IFwiMHB4XCIgOiBcIi0xMDAwcHhcIiksIFwidmlzaWJpbGl0eVwiIDogXCJoaWRkZW5cIiB9IH0pLmFwcGVuZFRvKGRvY3VtZW50LmJvZHkpO1xuXHRcdFx0aDIgPSAkKFwiPFwiK1wiaW5wdXQgLz5cIiwge1xuXHRcdFx0XHRcdFx0XCJ2YWx1ZVwiIDogdCxcblx0XHRcdFx0XHRcdFwiY2xhc3NcIiA6IFwianN0cmVlLXJlbmFtZS1pbnB1dFwiLFxuXHRcdFx0XHRcdFx0Ly8gXCJzaXplXCIgOiB0Lmxlbmd0aCxcblx0XHRcdFx0XHRcdFwiY3NzXCIgOiB7XG5cdFx0XHRcdFx0XHRcdFwicGFkZGluZ1wiIDogXCIwXCIsXG5cdFx0XHRcdFx0XHRcdFwiYm9yZGVyXCIgOiBcIjFweCBzb2xpZCBzaWx2ZXJcIixcblx0XHRcdFx0XHRcdFx0XCJib3gtc2l6aW5nXCIgOiBcImJvcmRlci1ib3hcIixcblx0XHRcdFx0XHRcdFx0XCJkaXNwbGF5XCIgOiBcImlubGluZS1ibG9ja1wiLFxuXHRcdFx0XHRcdFx0XHRcImhlaWdodFwiIDogKHRoaXMuX2RhdGEuY29yZS5saV9oZWlnaHQpICsgXCJweFwiLFxuXHRcdFx0XHRcdFx0XHRcImxpbmVIZWlnaHRcIiA6ICh0aGlzLl9kYXRhLmNvcmUubGlfaGVpZ2h0KSArIFwicHhcIixcblx0XHRcdFx0XHRcdFx0XCJ3aWR0aFwiIDogXCIxNTBweFwiIC8vIHdpbGwgYmUgc2V0IGEgYml0IGZ1cnRoZXIgZG93blxuXHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdFwiYmx1clwiIDogZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdFx0ZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcblx0XHRcdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0XHR2YXIgaSA9IHMuY2hpbGRyZW4oXCIuanN0cmVlLXJlbmFtZS1pbnB1dFwiKSxcblx0XHRcdFx0XHRcdFx0XHR2ID0gaS52YWwoKSxcblx0XHRcdFx0XHRcdFx0XHRmID0gdGhpcy5zZXR0aW5ncy5jb3JlLmZvcmNlX3RleHQsXG5cdFx0XHRcdFx0XHRcdFx0bnY7XG5cdFx0XHRcdFx0XHRcdGlmKHYgPT09IFwiXCIpIHsgdiA9IHQ7IH1cblx0XHRcdFx0XHRcdFx0aDEucmVtb3ZlKCk7XG5cdFx0XHRcdFx0XHRcdHMucmVwbGFjZVdpdGgoYSk7XG5cdFx0XHRcdFx0XHRcdHMucmVtb3ZlKCk7XG5cdFx0XHRcdFx0XHRcdHQgPSBmID8gdCA6ICQoJzxkaXY+PC9kaXY+JykuYXBwZW5kKCQucGFyc2VIVE1MKHQpKS5odG1sKCk7XG5cdFx0XHRcdFx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdFx0XHRcdFx0dGhpcy5zZXRfdGV4dChvYmosIHQpO1xuXHRcdFx0XHRcdFx0XHRudiA9ICEhdGhpcy5yZW5hbWVfbm9kZShvYmosIGYgPyAkKCc8ZGl2PjwvZGl2PicpLnRleHQodikudGV4dCgpIDogJCgnPGRpdj48L2Rpdj4nKS5hcHBlbmQoJC5wYXJzZUhUTUwodikpLmh0bWwoKSk7XG5cdFx0XHRcdFx0XHRcdGlmKCFudikge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuc2V0X3RleHQob2JqLCB0KTsgLy8gbW92ZSB0aGlzIHVwPyBhbmQgZml4ICM0ODNcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR0aGlzLl9kYXRhLmNvcmUuZm9jdXNlZCA9IHRtcC5pZDtcblx0XHRcdFx0XHRcdFx0c2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0XHRcdFx0dmFyIG5vZGUgPSB0aGlzLmdldF9ub2RlKHRtcC5pZCwgdHJ1ZSk7XG5cdFx0XHRcdFx0XHRcdFx0aWYobm9kZS5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5mb2N1c2VkID0gdG1wLmlkO1xuXHRcdFx0XHRcdFx0XHRcdFx0bm9kZS5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS50cmlnZ2VyKCdmb2N1cycpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fS5iaW5kKHRoaXMpLCAwKTtcblx0XHRcdFx0XHRcdFx0aWYoY2FsbGJhY2spIHtcblx0XHRcdFx0XHRcdFx0XHRjYWxsYmFjay5jYWxsKHRoaXMsIHRtcCwgbnYsIGNhbmNlbCwgdik7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aDIgPSBudWxsO1xuXHRcdFx0XHRcdFx0fS5iaW5kKHRoaXMpLFxuXHRcdFx0XHRcdFx0XCJrZXlkb3duXCIgOiBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0XHR2YXIga2V5ID0gZS53aGljaDtcblx0XHRcdFx0XHRcdFx0aWYoa2V5ID09PSAyNykge1xuXHRcdFx0XHRcdFx0XHRcdGNhbmNlbCA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy52YWx1ZSA9IHQ7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYoa2V5ID09PSAyNyB8fCBrZXkgPT09IDEzIHx8IGtleSA9PT0gMzcgfHwga2V5ID09PSAzOCB8fCBrZXkgPT09IDM5IHx8IGtleSA9PT0gNDAgfHwga2V5ID09PSAzMikge1xuXHRcdFx0XHRcdFx0XHRcdGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYoa2V5ID09PSAyNyB8fCBrZXkgPT09IDEzKSB7XG5cdFx0XHRcdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuYmx1cigpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0XCJjbGlja1wiIDogZnVuY3Rpb24gKGUpIHsgZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTsgfSxcblx0XHRcdFx0XHRcdFwibW91c2Vkb3duXCIgOiBmdW5jdGlvbiAoZSkgeyBlLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpOyB9LFxuXHRcdFx0XHRcdFx0XCJrZXl1cFwiIDogZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdFx0aDIud2lkdGgoTWF0aC5taW4oaDEudGV4dChcInBXXCIgKyB0aGlzLnZhbHVlKS53aWR0aCgpLHcpKTtcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRcImtleXByZXNzXCIgOiBmdW5jdGlvbihlKSB7XG5cdFx0XHRcdFx0XHRcdGlmKGUud2hpY2ggPT09IDEzKSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRmbiA9IHtcblx0XHRcdFx0XHRcdGZvbnRGYW1pbHlcdFx0OiBhLmNzcygnZm9udEZhbWlseScpXHRcdHx8ICcnLFxuXHRcdFx0XHRcdFx0Zm9udFNpemVcdFx0OiBhLmNzcygnZm9udFNpemUnKVx0XHRcdHx8ICcnLFxuXHRcdFx0XHRcdFx0Zm9udFdlaWdodFx0XHQ6IGEuY3NzKCdmb250V2VpZ2h0JylcdFx0fHwgJycsXG5cdFx0XHRcdFx0XHRmb250U3R5bGVcdFx0OiBhLmNzcygnZm9udFN0eWxlJylcdFx0fHwgJycsXG5cdFx0XHRcdFx0XHRmb250U3RyZXRjaFx0XHQ6IGEuY3NzKCdmb250U3RyZXRjaCcpXHRcdHx8ICcnLFxuXHRcdFx0XHRcdFx0Zm9udFZhcmlhbnRcdFx0OiBhLmNzcygnZm9udFZhcmlhbnQnKVx0XHR8fCAnJyxcblx0XHRcdFx0XHRcdGxldHRlclNwYWNpbmdcdDogYS5jc3MoJ2xldHRlclNwYWNpbmcnKVx0fHwgJycsXG5cdFx0XHRcdFx0XHR3b3JkU3BhY2luZ1x0XHQ6IGEuY3NzKCd3b3JkU3BhY2luZycpXHRcdHx8ICcnXG5cdFx0XHRcdH07XG5cdFx0XHRzLmF0dHIoJ2NsYXNzJywgYS5hdHRyKCdjbGFzcycpKS5hcHBlbmQoYS5jb250ZW50cygpLmNsb25lKCkpLmFwcGVuZChoMik7XG5cdFx0XHRhLnJlcGxhY2VXaXRoKHMpO1xuXHRcdFx0aDEuY3NzKGZuKTtcblx0XHRcdGgyLmNzcyhmbikud2lkdGgoTWF0aC5taW4oaDEudGV4dChcInBXXCIgKyBoMlswXS52YWx1ZSkud2lkdGgoKSx3KSlbMF0uc2VsZWN0KCk7XG5cdFx0XHQkKGRvY3VtZW50KS5vbmUoJ21vdXNlZG93bi5qc3RyZWUgdG91Y2hzdGFydC5qc3RyZWUgZG5kX3N0YXJ0LnZha2F0YScsIGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdGlmIChoMiAmJiBlLnRhcmdldCAhPT0gaDIpIHtcblx0XHRcdFx0XHQkKGgyKS50cmlnZ2VyKCdibHVyJyk7XG5cdFx0XHRcdH1cblx0XHRcdH0pO1xuXHRcdH0sXG5cblxuXHRcdC8qKlxuXHRcdCAqIGNoYW5nZXMgdGhlIHRoZW1lXG5cdFx0ICogQG5hbWUgc2V0X3RoZW1lKHRoZW1lX25hbWUgWywgdGhlbWVfdXJsXSlcblx0XHQgKiBAcGFyYW0ge1N0cmluZ30gdGhlbWVfbmFtZSB0aGUgbmFtZSBvZiB0aGUgbmV3IHRoZW1lIHRvIGFwcGx5XG5cdFx0ICogQHBhcmFtIHttaXhlZH0gdGhlbWVfdXJsICB0aGUgbG9jYXRpb24gb2YgdGhlIENTUyBmaWxlIGZvciB0aGlzIHRoZW1lLiBPbWl0IG9yIHNldCB0byBgZmFsc2VgIGlmIHlvdSBtYW51YWxseSBpbmNsdWRlZCB0aGUgZmlsZS4gU2V0IHRvIGB0cnVlYCB0byBhdXRvbG9hZCBmcm9tIHRoZSBgY29yZS50aGVtZXMuZGlyYCBkaXJlY3RvcnkuXG5cdFx0ICogQHRyaWdnZXIgc2V0X3RoZW1lLmpzdHJlZVxuXHRcdCAqL1xuXHRcdHNldF90aGVtZSA6IGZ1bmN0aW9uICh0aGVtZV9uYW1lLCB0aGVtZV91cmwpIHtcblx0XHRcdGlmKCF0aGVtZV9uYW1lKSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdFx0aWYodGhlbWVfdXJsID09PSB0cnVlKSB7XG5cdFx0XHRcdHZhciBkaXIgPSB0aGlzLnNldHRpbmdzLmNvcmUudGhlbWVzLmRpcjtcblx0XHRcdFx0aWYoIWRpcikgeyBkaXIgPSAkLmpzdHJlZS5wYXRoICsgJy90aGVtZXMnOyB9XG5cdFx0XHRcdHRoZW1lX3VybCA9IGRpciArICcvJyArIHRoZW1lX25hbWUgKyAnL3N0eWxlLmNzcyc7XG5cdFx0XHR9XG5cdFx0XHRpZih0aGVtZV91cmwgJiYgJC5pbkFycmF5KHRoZW1lX3VybCwgdGhlbWVzX2xvYWRlZCkgPT09IC0xKSB7XG5cdFx0XHRcdCQoJ2hlYWQnKS5hcHBlbmQoJzwnKydsaW5rIHJlbD1cInN0eWxlc2hlZXRcIiBocmVmPVwiJyArIHRoZW1lX3VybCArICdcIiB0eXBlPVwidGV4dC9jc3NcIiAvPicpO1xuXHRcdFx0XHR0aGVtZXNfbG9hZGVkLnB1c2godGhlbWVfdXJsKTtcblx0XHRcdH1cblx0XHRcdGlmKHRoaXMuX2RhdGEuY29yZS50aGVtZXMubmFtZSkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQ2xhc3MoJ2pzdHJlZS0nICsgdGhpcy5fZGF0YS5jb3JlLnRoZW1lcy5uYW1lKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuX2RhdGEuY29yZS50aGVtZXMubmFtZSA9IHRoZW1lX25hbWU7XG5cdFx0XHR0aGlzLmVsZW1lbnQuYWRkQ2xhc3MoJ2pzdHJlZS0nICsgdGhlbWVfbmFtZSk7XG5cdFx0XHR0aGlzLmVsZW1lbnRbdGhpcy5zZXR0aW5ncy5jb3JlLnRoZW1lcy5yZXNwb25zaXZlID8gJ2FkZENsYXNzJyA6ICdyZW1vdmVDbGFzcycgXSgnanN0cmVlLScgKyB0aGVtZV9uYW1lICsgJy1yZXNwb25zaXZlJyk7XG5cdFx0XHQvKipcblx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGEgdGhlbWUgaXMgc2V0XG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIHNldF90aGVtZS5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7U3RyaW5nfSB0aGVtZSB0aGUgbmV3IHRoZW1lXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignc2V0X3RoZW1lJywgeyAndGhlbWUnIDogdGhlbWVfbmFtZSB9KTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGdldHMgdGhlIG5hbWUgb2YgdGhlIGN1cnJlbnRseSBhcHBsaWVkIHRoZW1lIG5hbWVcblx0XHQgKiBAbmFtZSBnZXRfdGhlbWUoKVxuXHRcdCAqIEByZXR1cm4ge1N0cmluZ31cblx0XHQgKi9cblx0XHRnZXRfdGhlbWUgOiBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLl9kYXRhLmNvcmUudGhlbWVzLm5hbWU7IH0sXG5cdFx0LyoqXG5cdFx0ICogY2hhbmdlcyB0aGUgdGhlbWUgdmFyaWFudCAoaWYgdGhlIHRoZW1lIGhhcyB2YXJpYW50cylcblx0XHQgKiBAbmFtZSBzZXRfdGhlbWVfdmFyaWFudCh2YXJpYW50X25hbWUpXG5cdFx0ICogQHBhcmFtIHtTdHJpbmd8Qm9vbGVhbn0gdmFyaWFudF9uYW1lIHRoZSB2YXJpYW50IHRvIGFwcGx5IChpZiBgZmFsc2VgIGlzIHVzZWQgdGhlIGN1cnJlbnQgdmFyaWFudCBpcyByZW1vdmVkKVxuXHRcdCAqL1xuXHRcdHNldF90aGVtZV92YXJpYW50IDogZnVuY3Rpb24gKHZhcmlhbnRfbmFtZSkge1xuXHRcdFx0aWYodGhpcy5fZGF0YS5jb3JlLnRoZW1lcy52YXJpYW50KSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5yZW1vdmVDbGFzcygnanN0cmVlLScgKyB0aGlzLl9kYXRhLmNvcmUudGhlbWVzLm5hbWUgKyAnLScgKyB0aGlzLl9kYXRhLmNvcmUudGhlbWVzLnZhcmlhbnQpO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fZGF0YS5jb3JlLnRoZW1lcy52YXJpYW50ID0gdmFyaWFudF9uYW1lO1xuXHRcdFx0aWYodmFyaWFudF9uYW1lKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5hZGRDbGFzcygnanN0cmVlLScgKyB0aGlzLl9kYXRhLmNvcmUudGhlbWVzLm5hbWUgKyAnLScgKyB0aGlzLl9kYXRhLmNvcmUudGhlbWVzLnZhcmlhbnQpO1xuXHRcdFx0fVxuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogZ2V0cyB0aGUgbmFtZSBvZiB0aGUgY3VycmVudGx5IGFwcGxpZWQgdGhlbWUgdmFyaWFudFxuXHRcdCAqIEBuYW1lIGdldF90aGVtZSgpXG5cdFx0ICogQHJldHVybiB7U3RyaW5nfVxuXHRcdCAqL1xuXHRcdGdldF90aGVtZV92YXJpYW50IDogZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5fZGF0YS5jb3JlLnRoZW1lcy52YXJpYW50OyB9LFxuXHRcdC8qKlxuXHRcdCAqIHNob3dzIGEgc3RyaXBlZCBiYWNrZ3JvdW5kIG9uIHRoZSBjb250YWluZXIgKGlmIHRoZSB0aGVtZSBzdXBwb3J0cyBpdClcblx0XHQgKiBAbmFtZSBzaG93X3N0cmlwZXMoKVxuXHRcdCAqL1xuXHRcdHNob3dfc3RyaXBlcyA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHRoaXMuX2RhdGEuY29yZS50aGVtZXMuc3RyaXBlcyA9IHRydWU7XG5cdFx0XHR0aGlzLmdldF9jb250YWluZXJfdWwoKS5hZGRDbGFzcyhcImpzdHJlZS1zdHJpcGVkXCIpO1xuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiBzdHJpcGVzIGFyZSBzaG93blxuXHRcdFx0ICogQGV2ZW50XG5cdFx0XHQgKiBAbmFtZSBzaG93X3N0cmlwZXMuanN0cmVlXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignc2hvd19zdHJpcGVzJyk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBoaWRlcyB0aGUgc3RyaXBlZCBiYWNrZ3JvdW5kIG9uIHRoZSBjb250YWluZXJcblx0XHQgKiBAbmFtZSBoaWRlX3N0cmlwZXMoKVxuXHRcdCAqL1xuXHRcdGhpZGVfc3RyaXBlcyA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHRoaXMuX2RhdGEuY29yZS50aGVtZXMuc3RyaXBlcyA9IGZhbHNlO1xuXHRcdFx0dGhpcy5nZXRfY29udGFpbmVyX3VsKCkucmVtb3ZlQ2xhc3MoXCJqc3RyZWUtc3RyaXBlZFwiKTtcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gc3RyaXBlcyBhcmUgaGlkZGVuXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGhpZGVfc3RyaXBlcy5qc3RyZWVcblx0XHRcdCAqL1xuXHRcdFx0dGhpcy50cmlnZ2VyKCdoaWRlX3N0cmlwZXMnKTtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIHRvZ2dsZXMgdGhlIHN0cmlwZWQgYmFja2dyb3VuZCBvbiB0aGUgY29udGFpbmVyXG5cdFx0ICogQG5hbWUgdG9nZ2xlX3N0cmlwZXMoKVxuXHRcdCAqL1xuXHRcdHRvZ2dsZV9zdHJpcGVzIDogZnVuY3Rpb24gKCkgeyBpZih0aGlzLl9kYXRhLmNvcmUudGhlbWVzLnN0cmlwZXMpIHsgdGhpcy5oaWRlX3N0cmlwZXMoKTsgfSBlbHNlIHsgdGhpcy5zaG93X3N0cmlwZXMoKTsgfSB9LFxuXHRcdC8qKlxuXHRcdCAqIHNob3dzIHRoZSBjb25uZWN0aW5nIGRvdHMgKGlmIHRoZSB0aGVtZSBzdXBwb3J0cyBpdClcblx0XHQgKiBAbmFtZSBzaG93X2RvdHMoKVxuXHRcdCAqL1xuXHRcdHNob3dfZG90cyA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHRoaXMuX2RhdGEuY29yZS50aGVtZXMuZG90cyA9IHRydWU7XG5cdFx0XHR0aGlzLmdldF9jb250YWluZXJfdWwoKS5yZW1vdmVDbGFzcyhcImpzdHJlZS1uby1kb3RzXCIpO1xuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiBkb3RzIGFyZSBzaG93blxuXHRcdFx0ICogQGV2ZW50XG5cdFx0XHQgKiBAbmFtZSBzaG93X2RvdHMuanN0cmVlXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignc2hvd19kb3RzJyk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBoaWRlcyB0aGUgY29ubmVjdGluZyBkb3RzXG5cdFx0ICogQG5hbWUgaGlkZV9kb3RzKClcblx0XHQgKi9cblx0XHRoaWRlX2RvdHMgOiBmdW5jdGlvbiAoKSB7XG5cdFx0XHR0aGlzLl9kYXRhLmNvcmUudGhlbWVzLmRvdHMgPSBmYWxzZTtcblx0XHRcdHRoaXMuZ2V0X2NvbnRhaW5lcl91bCgpLmFkZENsYXNzKFwianN0cmVlLW5vLWRvdHNcIik7XG5cdFx0XHQvKipcblx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGRvdHMgYXJlIGhpZGRlblxuXHRcdFx0ICogQGV2ZW50XG5cdFx0XHQgKiBAbmFtZSBoaWRlX2RvdHMuanN0cmVlXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignaGlkZV9kb3RzJyk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiB0b2dnbGVzIHRoZSBjb25uZWN0aW5nIGRvdHNcblx0XHQgKiBAbmFtZSB0b2dnbGVfZG90cygpXG5cdFx0ICovXG5cdFx0dG9nZ2xlX2RvdHMgOiBmdW5jdGlvbiAoKSB7IGlmKHRoaXMuX2RhdGEuY29yZS50aGVtZXMuZG90cykgeyB0aGlzLmhpZGVfZG90cygpOyB9IGVsc2UgeyB0aGlzLnNob3dfZG90cygpOyB9IH0sXG5cdFx0LyoqXG5cdFx0ICogc2hvdyB0aGUgbm9kZSBpY29uc1xuXHRcdCAqIEBuYW1lIHNob3dfaWNvbnMoKVxuXHRcdCAqL1xuXHRcdHNob3dfaWNvbnMgOiBmdW5jdGlvbiAoKSB7XG5cdFx0XHR0aGlzLl9kYXRhLmNvcmUudGhlbWVzLmljb25zID0gdHJ1ZTtcblx0XHRcdHRoaXMuZ2V0X2NvbnRhaW5lcl91bCgpLnJlbW92ZUNsYXNzKFwianN0cmVlLW5vLWljb25zXCIpO1xuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiBpY29ucyBhcmUgc2hvd25cblx0XHRcdCAqIEBldmVudFxuXHRcdFx0ICogQG5hbWUgc2hvd19pY29ucy5qc3RyZWVcblx0XHRcdCAqL1xuXHRcdFx0dGhpcy50cmlnZ2VyKCdzaG93X2ljb25zJyk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBoaWRlIHRoZSBub2RlIGljb25zXG5cdFx0ICogQG5hbWUgaGlkZV9pY29ucygpXG5cdFx0ICovXG5cdFx0aGlkZV9pY29ucyA6IGZ1bmN0aW9uICgpIHtcblx0XHRcdHRoaXMuX2RhdGEuY29yZS50aGVtZXMuaWNvbnMgPSBmYWxzZTtcblx0XHRcdHRoaXMuZ2V0X2NvbnRhaW5lcl91bCgpLmFkZENsYXNzKFwianN0cmVlLW5vLWljb25zXCIpO1xuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiBpY29ucyBhcmUgaGlkZGVuXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGhpZGVfaWNvbnMuanN0cmVlXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignaGlkZV9pY29ucycpO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogdG9nZ2xlIHRoZSBub2RlIGljb25zXG5cdFx0ICogQG5hbWUgdG9nZ2xlX2ljb25zKClcblx0XHQgKi9cblx0XHR0b2dnbGVfaWNvbnMgOiBmdW5jdGlvbiAoKSB7IGlmKHRoaXMuX2RhdGEuY29yZS50aGVtZXMuaWNvbnMpIHsgdGhpcy5oaWRlX2ljb25zKCk7IH0gZWxzZSB7IHRoaXMuc2hvd19pY29ucygpOyB9IH0sXG5cdFx0LyoqXG5cdFx0ICogc2hvdyB0aGUgbm9kZSBlbGxpcHNpc1xuXHRcdCAqIEBuYW1lIHNob3dfaWNvbnMoKVxuXHRcdCAqL1xuXHRcdHNob3dfZWxsaXBzaXMgOiBmdW5jdGlvbiAoKSB7XG5cdFx0XHR0aGlzLl9kYXRhLmNvcmUudGhlbWVzLmVsbGlwc2lzID0gdHJ1ZTtcblx0XHRcdHRoaXMuZ2V0X2NvbnRhaW5lcl91bCgpLmFkZENsYXNzKFwianN0cmVlLWVsbGlwc2lzXCIpO1xuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiBlbGxpc2lzIGlzIHNob3duXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIHNob3dfZWxsaXBzaXMuanN0cmVlXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignc2hvd19lbGxpcHNpcycpO1xuXHRcdH0sXG5cdFx0LyoqXG5cdFx0ICogaGlkZSB0aGUgbm9kZSBlbGxpcHNpc1xuXHRcdCAqIEBuYW1lIGhpZGVfZWxsaXBzaXMoKVxuXHRcdCAqL1xuXHRcdGhpZGVfZWxsaXBzaXMgOiBmdW5jdGlvbiAoKSB7XG5cdFx0XHR0aGlzLl9kYXRhLmNvcmUudGhlbWVzLmVsbGlwc2lzID0gZmFsc2U7XG5cdFx0XHR0aGlzLmdldF9jb250YWluZXJfdWwoKS5yZW1vdmVDbGFzcyhcImpzdHJlZS1lbGxpcHNpc1wiKTtcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gZWxsaXNpcyBpcyBoaWRkZW5cblx0XHRcdCAqIEBldmVudFxuXHRcdFx0ICogQG5hbWUgaGlkZV9lbGxpcHNpcy5qc3RyZWVcblx0XHRcdCAqL1xuXHRcdFx0dGhpcy50cmlnZ2VyKCdoaWRlX2VsbGlwc2lzJyk7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiB0b2dnbGUgdGhlIG5vZGUgZWxsaXBzaXNcblx0XHQgKiBAbmFtZSB0b2dnbGVfaWNvbnMoKVxuXHRcdCAqL1xuXHRcdHRvZ2dsZV9lbGxpcHNpcyA6IGZ1bmN0aW9uICgpIHsgaWYodGhpcy5fZGF0YS5jb3JlLnRoZW1lcy5lbGxpcHNpcykgeyB0aGlzLmhpZGVfZWxsaXBzaXMoKTsgfSBlbHNlIHsgdGhpcy5zaG93X2VsbGlwc2lzKCk7IH0gfSxcblx0XHQvKipcblx0XHQgKiBzZXQgdGhlIG5vZGUgaWNvbiBmb3IgYSBub2RlXG5cdFx0ICogQG5hbWUgc2V0X2ljb24ob2JqLCBpY29uKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9ialxuXHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBpY29uIHRoZSBuZXcgaWNvbiAtIGNhbiBiZSBhIHBhdGggdG8gYW4gaWNvbiBvciBhIGNsYXNzTmFtZSwgaWYgdXNpbmcgYW4gaW1hZ2UgdGhhdCBpcyBpbiB0aGUgY3VycmVudCBkaXJlY3RvcnkgdXNlIGEgYC4vYCBwcmVmaXgsIG90aGVyd2lzZSBpdCB3aWxsIGJlIGRldGVjdGVkIGFzIGEgY2xhc3Ncblx0XHQgKi9cblx0XHRzZXRfaWNvbiA6IGZ1bmN0aW9uIChvYmosIGljb24pIHtcblx0XHRcdHZhciB0MSwgdDIsIGRvbSwgb2xkO1xuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkob2JqKSkge1xuXHRcdFx0XHRvYmogPSBvYmouc2xpY2UoKTtcblx0XHRcdFx0Zm9yKHQxID0gMCwgdDIgPSBvYmoubGVuZ3RoOyB0MSA8IHQyOyB0MSsrKSB7XG5cdFx0XHRcdFx0dGhpcy5zZXRfaWNvbihvYmpbdDFdLCBpY29uKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdGlmKCFvYmogfHwgb2JqLmlkID09PSAkLmpzdHJlZS5yb290KSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdFx0b2xkID0gb2JqLmljb247XG5cdFx0XHRvYmouaWNvbiA9IGljb24gPT09IHRydWUgfHwgaWNvbiA9PT0gbnVsbCB8fCBpY29uID09PSB1bmRlZmluZWQgfHwgaWNvbiA9PT0gJycgPyB0cnVlIDogaWNvbjtcblx0XHRcdGRvbSA9IHRoaXMuZ2V0X25vZGUob2JqLCB0cnVlKS5jaGlsZHJlbihcIi5qc3RyZWUtYW5jaG9yXCIpLmNoaWxkcmVuKFwiLmpzdHJlZS10aGVtZWljb25cIik7XG5cdFx0XHRpZihpY29uID09PSBmYWxzZSkge1xuXHRcdFx0XHRkb20ucmVtb3ZlQ2xhc3MoJ2pzdHJlZS10aGVtZWljb24tY3VzdG9tICcgKyBvbGQpLmNzcyhcImJhY2tncm91bmRcIixcIlwiKS5yZW1vdmVBdHRyKFwicmVsXCIpO1xuXHRcdFx0XHR0aGlzLmhpZGVfaWNvbihvYmopO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZihpY29uID09PSB0cnVlIHx8IGljb24gPT09IG51bGwgfHwgaWNvbiA9PT0gdW5kZWZpbmVkIHx8IGljb24gPT09ICcnKSB7XG5cdFx0XHRcdGRvbS5yZW1vdmVDbGFzcygnanN0cmVlLXRoZW1laWNvbi1jdXN0b20gJyArIG9sZCkuY3NzKFwiYmFja2dyb3VuZFwiLFwiXCIpLnJlbW92ZUF0dHIoXCJyZWxcIik7XG5cdFx0XHRcdGlmKG9sZCA9PT0gZmFsc2UpIHsgdGhpcy5zaG93X2ljb24ob2JqKTsgfVxuXHRcdFx0fVxuXHRcdFx0ZWxzZSBpZihpY29uLmluZGV4T2YoXCIvXCIpID09PSAtMSAmJiBpY29uLmluZGV4T2YoXCIuXCIpID09PSAtMSkge1xuXHRcdFx0XHRkb20ucmVtb3ZlQ2xhc3Mob2xkKS5jc3MoXCJiYWNrZ3JvdW5kXCIsXCJcIik7XG5cdFx0XHRcdGRvbS5hZGRDbGFzcyhpY29uICsgJyBqc3RyZWUtdGhlbWVpY29uLWN1c3RvbScpLmF0dHIoXCJyZWxcIixpY29uKTtcblx0XHRcdFx0aWYob2xkID09PSBmYWxzZSkgeyB0aGlzLnNob3dfaWNvbihvYmopOyB9XG5cdFx0XHR9XG5cdFx0XHRlbHNlIHtcblx0XHRcdFx0ZG9tLnJlbW92ZUNsYXNzKG9sZCkuY3NzKFwiYmFja2dyb3VuZFwiLFwiXCIpO1xuXHRcdFx0XHRkb20uYWRkQ2xhc3MoJ2pzdHJlZS10aGVtZWljb24tY3VzdG9tJykuY3NzKFwiYmFja2dyb3VuZFwiLCBcInVybCgnXCIgKyBpY29uICsgXCInKSBjZW50ZXIgY2VudGVyIG5vLXJlcGVhdFwiKS5hdHRyKFwicmVsXCIsaWNvbik7XG5cdFx0XHRcdGlmKG9sZCA9PT0gZmFsc2UpIHsgdGhpcy5zaG93X2ljb24ob2JqKTsgfVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBnZXQgdGhlIG5vZGUgaWNvbiBmb3IgYSBub2RlXG5cdFx0ICogQG5hbWUgZ2V0X2ljb24ob2JqKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9ialxuXHRcdCAqIEByZXR1cm4ge1N0cmluZ31cblx0XHQgKi9cblx0XHRnZXRfaWNvbiA6IGZ1bmN0aW9uIChvYmopIHtcblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdHJldHVybiAoIW9iaiB8fCBvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpID8gZmFsc2UgOiBvYmouaWNvbjtcblx0XHR9LFxuXHRcdC8qKlxuXHRcdCAqIGhpZGUgdGhlIGljb24gb24gYW4gaW5kaXZpZHVhbCBub2RlXG5cdFx0ICogQG5hbWUgaGlkZV9pY29uKG9iailcblx0XHQgKiBAcGFyYW0ge21peGVkfSBvYmpcblx0XHQgKi9cblx0XHRoaWRlX2ljb24gOiBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHR2YXIgdDEsIHQyO1xuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkob2JqKSkge1xuXHRcdFx0XHRvYmogPSBvYmouc2xpY2UoKTtcblx0XHRcdFx0Zm9yKHQxID0gMCwgdDIgPSBvYmoubGVuZ3RoOyB0MSA8IHQyOyB0MSsrKSB7XG5cdFx0XHRcdFx0dGhpcy5oaWRlX2ljb24ob2JqW3QxXSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqIHx8IG9iaiA9PT0gJC5qc3RyZWUucm9vdCkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdG9iai5pY29uID0gZmFsc2U7XG5cdFx0XHR0aGlzLmdldF9ub2RlKG9iaiwgdHJ1ZSkuY2hpbGRyZW4oXCIuanN0cmVlLWFuY2hvclwiKS5jaGlsZHJlbihcIi5qc3RyZWUtdGhlbWVpY29uXCIpLmFkZENsYXNzKCdqc3RyZWUtdGhlbWVpY29uLWhpZGRlbicpO1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fSxcblx0XHQvKipcblx0XHQgKiBzaG93IHRoZSBpY29uIG9uIGFuIGluZGl2aWR1YWwgbm9kZVxuXHRcdCAqIEBuYW1lIHNob3dfaWNvbihvYmopXG5cdFx0ICogQHBhcmFtIHttaXhlZH0gb2JqXG5cdFx0ICovXG5cdFx0c2hvd19pY29uIDogZnVuY3Rpb24gKG9iaikge1xuXHRcdFx0dmFyIHQxLCB0MiwgZG9tO1xuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkob2JqKSkge1xuXHRcdFx0XHRvYmogPSBvYmouc2xpY2UoKTtcblx0XHRcdFx0Zm9yKHQxID0gMCwgdDIgPSBvYmoubGVuZ3RoOyB0MSA8IHQyOyB0MSsrKSB7XG5cdFx0XHRcdFx0dGhpcy5zaG93X2ljb24ob2JqW3QxXSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqIHx8IG9iaiA9PT0gJC5qc3RyZWUucm9vdCkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdGRvbSA9IHRoaXMuZ2V0X25vZGUob2JqLCB0cnVlKTtcblx0XHRcdG9iai5pY29uID0gZG9tLmxlbmd0aCA/IGRvbS5jaGlsZHJlbihcIi5qc3RyZWUtYW5jaG9yXCIpLmNoaWxkcmVuKFwiLmpzdHJlZS10aGVtZWljb25cIikuYXR0cigncmVsJykgOiB0cnVlO1xuXHRcdFx0aWYoIW9iai5pY29uKSB7IG9iai5pY29uID0gdHJ1ZTsgfVxuXHRcdFx0ZG9tLmNoaWxkcmVuKFwiLmpzdHJlZS1hbmNob3JcIikuY2hpbGRyZW4oXCIuanN0cmVlLXRoZW1laWNvblwiKS5yZW1vdmVDbGFzcygnanN0cmVlLXRoZW1laWNvbi1oaWRkZW4nKTtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblx0fTtcblxuXHQvLyBoZWxwZXJzXG5cdCQudmFrYXRhID0ge307XG5cdC8vIGNvbGxlY3QgYXR0cmlidXRlc1xuXHQkLnZha2F0YS5hdHRyaWJ1dGVzID0gZnVuY3Rpb24obm9kZSwgd2l0aF92YWx1ZXMpIHtcblx0XHRub2RlID0gJChub2RlKVswXTtcblx0XHR2YXIgYXR0ciA9IHdpdGhfdmFsdWVzID8ge30gOiBbXTtcblx0XHRpZihub2RlICYmIG5vZGUuYXR0cmlidXRlcykge1xuXHRcdFx0JC5lYWNoKG5vZGUuYXR0cmlidXRlcywgZnVuY3Rpb24gKGksIHYpIHtcblx0XHRcdFx0aWYoJC5pbkFycmF5KHYubmFtZS50b0xvd2VyQ2FzZSgpLFsnc3R5bGUnLCdjb250ZW50ZWRpdGFibGUnLCdoYXNmb2N1cycsJ3RhYmluZGV4J10pICE9PSAtMSkgeyByZXR1cm47IH1cblx0XHRcdFx0aWYodi52YWx1ZSAhPT0gbnVsbCAmJiAkLnZha2F0YS50cmltKHYudmFsdWUpICE9PSAnJykge1xuXHRcdFx0XHRcdGlmKHdpdGhfdmFsdWVzKSB7IGF0dHJbdi5uYW1lXSA9IHYudmFsdWU7IH1cblx0XHRcdFx0XHRlbHNlIHsgYXR0ci5wdXNoKHYubmFtZSk7IH1cblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0fVxuXHRcdHJldHVybiBhdHRyO1xuXHR9O1xuXHQkLnZha2F0YS5hcnJheV91bmlxdWUgPSBmdW5jdGlvbihhcnJheSkge1xuXHRcdHZhciBhID0gW10sIGksIGosIGwsIG8gPSB7fTtcblx0XHRmb3IoaSA9IDAsIGwgPSBhcnJheS5sZW5ndGg7IGkgPCBsOyBpKyspIHtcblx0XHRcdGlmKG9bYXJyYXlbaV1dID09PSB1bmRlZmluZWQpIHtcblx0XHRcdFx0YS5wdXNoKGFycmF5W2ldKTtcblx0XHRcdFx0b1thcnJheVtpXV0gPSB0cnVlO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gYTtcblx0fTtcblx0Ly8gcmVtb3ZlIGl0ZW0gZnJvbSBhcnJheVxuXHQkLnZha2F0YS5hcnJheV9yZW1vdmUgPSBmdW5jdGlvbihhcnJheSwgZnJvbSkge1xuXHRcdGFycmF5LnNwbGljZShmcm9tLCAxKTtcblx0XHRyZXR1cm4gYXJyYXk7XG5cdFx0Ly92YXIgcmVzdCA9IGFycmF5LnNsaWNlKCh0byB8fCBmcm9tKSArIDEgfHwgYXJyYXkubGVuZ3RoKTtcblx0XHQvL2FycmF5Lmxlbmd0aCA9IGZyb20gPCAwID8gYXJyYXkubGVuZ3RoICsgZnJvbSA6IGZyb207XG5cdFx0Ly9hcnJheS5wdXNoLmFwcGx5KGFycmF5LCByZXN0KTtcblx0XHQvL3JldHVybiBhcnJheTtcblx0fTtcblx0Ly8gcmVtb3ZlIGl0ZW0gZnJvbSBhcnJheVxuXHQkLnZha2F0YS5hcnJheV9yZW1vdmVfaXRlbSA9IGZ1bmN0aW9uKGFycmF5LCBpdGVtKSB7XG5cdFx0dmFyIHRtcCA9ICQuaW5BcnJheShpdGVtLCBhcnJheSk7XG5cdFx0cmV0dXJuIHRtcCAhPT0gLTEgPyAkLnZha2F0YS5hcnJheV9yZW1vdmUoYXJyYXksIHRtcCkgOiBhcnJheTtcblx0fTtcblx0JC52YWthdGEuYXJyYXlfZmlsdGVyID0gZnVuY3Rpb24oYyxhLGIsZCxlKSB7XG5cdFx0aWYgKGMuZmlsdGVyKSB7XG5cdFx0XHRyZXR1cm4gYy5maWx0ZXIoYSwgYik7XG5cdFx0fVxuXHRcdGQ9W107XG5cdFx0Zm9yIChlIGluIGMpIHtcblx0XHRcdGlmICh+fmUrJyc9PT1lKycnICYmIGU+PTAgJiYgYS5jYWxsKGIsY1tlXSwrZSxjKSkge1xuXHRcdFx0XHRkLnB1c2goY1tlXSk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBkO1xuXHR9O1xuXHQkLnZha2F0YS50cmltID0gZnVuY3Rpb24gKHRleHQpIHtcblx0XHRyZXR1cm4gU3RyaW5nLnByb3RvdHlwZS50cmltID8gXG5cdFx0XHRTdHJpbmcucHJvdG90eXBlLnRyaW0uY2FsbCh0ZXh0LnRvU3RyaW5nKCkpIDpcblx0XHRcdHRleHQudG9TdHJpbmcoKS5yZXBsYWNlKC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZywgJycpO1xuXHR9O1xuXHQkLnZha2F0YS5pc19mdW5jdGlvbiA9IGZ1bmN0aW9uKG9iaikge1xuXHRcdHJldHVybiB0eXBlb2Ygb2JqID09PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIG9iai5ub2RlVHlwZSAhPT0gXCJudW1iZXJcIjtcblx0fTtcblx0JC52YWthdGEuaXNfYXJyYXkgPSBBcnJheS5pc0FycmF5IHx8IGZ1bmN0aW9uIChvYmopIHtcblx0XHRyZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9iaikgPT09IFwiW29iamVjdCBBcnJheV1cIjtcblx0fTtcblxuXHQvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfb2JqZWN0cy9GdW5jdGlvbi9iaW5kI3BvbHlmaWxsXG5cdGlmICghRnVuY3Rpb24ucHJvdG90eXBlLmJpbmQpIHtcblx0XHRGdW5jdGlvbi5wcm90b3R5cGUuYmluZCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHZhciB0aGF0RnVuYyA9IHRoaXMsIHRoYXRBcmcgPSBhcmd1bWVudHNbMF07XG5cdFx0XHR2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG5cdFx0XHRpZiAodHlwZW9mIHRoYXRGdW5jICE9PSAnZnVuY3Rpb24nKSB7XG5cdFx0XHRcdC8vIGNsb3Nlc3QgdGhpbmcgcG9zc2libGUgdG8gdGhlIEVDTUFTY3JpcHQgNVxuXHRcdFx0XHQvLyBpbnRlcm5hbCBJc0NhbGxhYmxlIGZ1bmN0aW9uXG5cdFx0XHRcdHRocm93IG5ldyBUeXBlRXJyb3IoJ0Z1bmN0aW9uLnByb3RvdHlwZS5iaW5kIC0gd2hhdCBpcyB0cnlpbmcgdG8gYmUgYm91bmQgaXMgbm90IGNhbGxhYmxlJyk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24oKXtcblx0XHRcdFx0dmFyIGZ1bmNBcmdzID0gYXJncy5jb25jYXQoQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKSk7XG5cdFx0XHRcdHJldHVybiB0aGF0RnVuYy5hcHBseSh0aGF0QXJnLCBmdW5jQXJncyk7XG5cdFx0XHR9O1xuXHRcdH07XG5cdH1cblxuXG4vKipcbiAqICMjIyBDaGFuZ2VkIHBsdWdpblxuICpcbiAqIFRoaXMgcGx1Z2luIGFkZHMgbW9yZSBpbmZvcm1hdGlvbiB0byB0aGUgYGNoYW5nZWQuanN0cmVlYCBldmVudC4gVGhlIG5ldyBkYXRhIGlzIGNvbnRhaW5lZCBpbiB0aGUgYGNoYW5nZWRgIGV2ZW50IGRhdGEgcHJvcGVydHksIGFuZCBjb250YWlucyBhIGxpc3RzIG9mIGBzZWxlY3RlZGAgYW5kIGBkZXNlbGVjdGVkYCBub2Rlcy5cbiAqL1xuXG5cdCQuanN0cmVlLnBsdWdpbnMuY2hhbmdlZCA9IGZ1bmN0aW9uIChvcHRpb25zLCBwYXJlbnQpIHtcblx0XHR2YXIgbGFzdCA9IFtdO1xuXHRcdHRoaXMudHJpZ2dlciA9IGZ1bmN0aW9uIChldiwgZGF0YSkge1xuXHRcdFx0dmFyIGksIGo7XG5cdFx0XHRpZighZGF0YSkge1xuXHRcdFx0XHRkYXRhID0ge307XG5cdFx0XHR9XG5cdFx0XHRpZihldi5yZXBsYWNlKCcuanN0cmVlJywnJykgPT09ICdjaGFuZ2VkJykge1xuXHRcdFx0XHRkYXRhLmNoYW5nZWQgPSB7IHNlbGVjdGVkIDogW10sIGRlc2VsZWN0ZWQgOiBbXSB9O1xuXHRcdFx0XHR2YXIgdG1wID0ge307XG5cdFx0XHRcdGZvcihpID0gMCwgaiA9IGxhc3QubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0dG1wW2xhc3RbaV1dID0gMTtcblx0XHRcdFx0fVxuXHRcdFx0XHRmb3IoaSA9IDAsIGogPSBkYXRhLnNlbGVjdGVkLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdGlmKCF0bXBbZGF0YS5zZWxlY3RlZFtpXV0pIHtcblx0XHRcdFx0XHRcdGRhdGEuY2hhbmdlZC5zZWxlY3RlZC5wdXNoKGRhdGEuc2VsZWN0ZWRbaV0pO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdHRtcFtkYXRhLnNlbGVjdGVkW2ldXSA9IDI7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGZvcihpID0gMCwgaiA9IGxhc3QubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0aWYodG1wW2xhc3RbaV1dID09PSAxKSB7XG5cdFx0XHRcdFx0XHRkYXRhLmNoYW5nZWQuZGVzZWxlY3RlZC5wdXNoKGxhc3RbaV0pO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRsYXN0ID0gZGF0YS5zZWxlY3RlZC5zbGljZSgpO1xuXHRcdFx0fVxuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiBzZWxlY3Rpb24gY2hhbmdlcyAodGhlIFwiY2hhbmdlZFwiIHBsdWdpbiBlbmhhbmNlcyB0aGUgb3JpZ2luYWwgZXZlbnQgd2l0aCBtb3JlIGRhdGEpXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGNoYW5nZWQuanN0cmVlXG5cdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZVxuXHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IGFjdGlvbiB0aGUgYWN0aW9uIHRoYXQgY2F1c2VkIHRoZSBzZWxlY3Rpb24gdG8gY2hhbmdlXG5cdFx0XHQgKiBAcGFyYW0ge0FycmF5fSBzZWxlY3RlZCB0aGUgY3VycmVudCBzZWxlY3Rpb25cblx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBjaGFuZ2VkIGFuIG9iamVjdCBjb250YWluaW5nIHR3byBwcm9wZXJ0aWVzIGBzZWxlY3RlZGAgYW5kIGBkZXNlbGVjdGVkYCAtIGJvdGggYXJyYXlzIG9mIG5vZGUgSURzLCB3aGljaCB3ZXJlIHNlbGVjdGVkIG9yIGRlc2VsZWN0ZWQgc2luY2UgdGhlIGxhc3QgY2hhbmdlZCBldmVudFxuXHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IGV2ZW50IHRoZSBldmVudCAoaWYgYW55KSB0aGF0IHRyaWdnZXJlZCB0aGlzIGNoYW5nZWQgZXZlbnRcblx0XHRcdCAqIEBwbHVnaW4gY2hhbmdlZFxuXHRcdFx0ICovXG5cdFx0XHRwYXJlbnQudHJpZ2dlci5jYWxsKHRoaXMsIGV2LCBkYXRhKTtcblx0XHR9O1xuXHRcdHRoaXMucmVmcmVzaCA9IGZ1bmN0aW9uIChza2lwX2xvYWRpbmcsIGZvcmdldF9zdGF0ZSkge1xuXHRcdFx0bGFzdCA9IFtdO1xuXHRcdFx0cmV0dXJuIHBhcmVudC5yZWZyZXNoLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cdFx0fTtcblx0fTtcblxuLyoqXG4gKiAjIyMgQ2hlY2tib3ggcGx1Z2luXG4gKlxuICogVGhpcyBwbHVnaW4gcmVuZGVycyBjaGVja2JveCBpY29ucyBpbiBmcm9udCBvZiBlYWNoIG5vZGUsIG1ha2luZyBtdWx0aXBsZSBzZWxlY3Rpb24gbXVjaCBlYXNpZXIuXG4gKiBJdCBhbHNvIHN1cHBvcnRzIHRyaS1zdGF0ZSBiZWhhdmlvciwgbWVhbmluZyB0aGF0IGlmIGEgbm9kZSBoYXMgYSBmZXcgb2YgaXRzIGNoaWxkcmVuIGNoZWNrZWQgaXQgd2lsbCBiZSByZW5kZXJlZCBhcyB1bmRldGVybWluZWQsIGFuZCBzdGF0ZSB3aWxsIGJlIHByb3BhZ2F0ZWQgdXAuXG4gKi9cblxuXHR2YXIgX2kgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdJJyk7XG5cdF9pLmNsYXNzTmFtZSA9ICdqc3RyZWUtaWNvbiBqc3RyZWUtY2hlY2tib3gnO1xuXHRfaS5zZXRBdHRyaWJ1dGUoJ3JvbGUnLCAncHJlc2VudGF0aW9uJyk7XG5cdC8qKlxuXHQgKiBzdG9yZXMgYWxsIGRlZmF1bHRzIGZvciB0aGUgY2hlY2tib3ggcGx1Z2luXG5cdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNoZWNrYm94XG5cdCAqIEBwbHVnaW4gY2hlY2tib3hcblx0ICovXG5cdCQuanN0cmVlLmRlZmF1bHRzLmNoZWNrYm94ID0ge1xuXHRcdC8qKlxuXHRcdCAqIGEgYm9vbGVhbiBpbmRpY2F0aW5nIGlmIGNoZWNrYm94ZXMgc2hvdWxkIGJlIHZpc2libGUgKGNhbiBiZSBjaGFuZ2VkIGF0IGEgbGF0ZXIgdGltZSB1c2luZyBgc2hvd19jaGVja2JveGVzKClgIGFuZCBgaGlkZV9jaGVja2JveGVzYCkuIERlZmF1bHRzIHRvIGB0cnVlYC5cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jaGVja2JveC52aXNpYmxlXG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdHZpc2libGVcdFx0XHRcdDogdHJ1ZSxcblx0XHQvKipcblx0XHQgKiBhIGJvb2xlYW4gaW5kaWNhdGluZyBpZiBjaGVja2JveGVzIHNob3VsZCBjYXNjYWRlIGRvd24gYW5kIGhhdmUgYW4gdW5kZXRlcm1pbmVkIHN0YXRlLiBEZWZhdWx0cyB0byBgdHJ1ZWAuXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuY2hlY2tib3gudGhyZWVfc3RhdGVcblx0XHQgKiBAcGx1Z2luIGNoZWNrYm94XG5cdFx0ICovXG5cdFx0dGhyZWVfc3RhdGVcdFx0XHQ6IHRydWUsXG5cdFx0LyoqXG5cdFx0ICogYSBib29sZWFuIGluZGljYXRpbmcgaWYgY2xpY2tpbmcgYW55d2hlcmUgb24gdGhlIG5vZGUgc2hvdWxkIGFjdCBhcyBjbGlja2luZyBvbiB0aGUgY2hlY2tib3guIERlZmF1bHRzIHRvIGB0cnVlYC5cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jaGVja2JveC53aG9sZV9ub2RlXG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdHdob2xlX25vZGVcdFx0XHQ6IHRydWUsXG5cdFx0LyoqXG5cdFx0ICogYSBib29sZWFuIGluZGljYXRpbmcgaWYgdGhlIHNlbGVjdGVkIHN0eWxlIG9mIGEgbm9kZSBzaG91bGQgYmUga2VwdCwgb3IgcmVtb3ZlZC4gRGVmYXVsdHMgdG8gYHRydWVgLlxuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNoZWNrYm94LmtlZXBfc2VsZWN0ZWRfc3R5bGVcblx0XHQgKiBAcGx1Z2luIGNoZWNrYm94XG5cdFx0ICovXG5cdFx0a2VlcF9zZWxlY3RlZF9zdHlsZVx0OiB0cnVlLFxuXHRcdC8qKlxuXHRcdCAqIFRoaXMgc2V0dGluZyBjb250cm9scyBob3cgY2FzY2FkaW5nIGFuZCB1bmRldGVybWluZWQgbm9kZXMgYXJlIGFwcGxpZWQuXG5cdFx0ICogSWYgJ3VwJyBpcyBpbiB0aGUgc3RyaW5nIC0gY2FzY2FkaW5nIHVwIGlzIGVuYWJsZWQsIGlmICdkb3duJyBpcyBpbiB0aGUgc3RyaW5nIC0gY2FzY2FkaW5nIGRvd24gaXMgZW5hYmxlZCwgaWYgJ3VuZGV0ZXJtaW5lZCcgaXMgaW4gdGhlIHN0cmluZyAtIHVuZGV0ZXJtaW5lZCBub2RlcyB3aWxsIGJlIHVzZWQuXG5cdFx0ICogSWYgYHRocmVlX3N0YXRlYCBpcyBzZXQgdG8gYHRydWVgIHRoaXMgc2V0dGluZyBpcyBhdXRvbWF0aWNhbGx5IHNldCB0byAndXArZG93bit1bmRldGVybWluZWQnLiBEZWZhdWx0cyB0byAnJy5cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jaGVja2JveC5jYXNjYWRlXG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdGNhc2NhZGVcdFx0XHRcdDogJycsXG5cdFx0LyoqXG5cdFx0ICogVGhpcyBzZXR0aW5nIGNvbnRyb2xzIGlmIGNoZWNrYm94IGFyZSBib3VuZCB0byB0aGUgZ2VuZXJhbCB0cmVlIHNlbGVjdGlvbiBvciB0byBhbiBpbnRlcm5hbCBhcnJheSBtYWludGFpbmVkIGJ5IHRoZSBjaGVja2JveCBwbHVnaW4uIERlZmF1bHRzIHRvIGB0cnVlYCwgb25seSBzZXQgdG8gYGZhbHNlYCBpZiB5b3Uga25vdyBleGFjdGx5IHdoYXQgeW91IGFyZSBkb2luZy5cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jaGVja2JveC50aWVfc2VsZWN0aW9uXG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdHRpZV9zZWxlY3Rpb25cdFx0OiB0cnVlLFxuXG5cdFx0LyoqXG5cdFx0ICogVGhpcyBzZXR0aW5nIGNvbnRyb2xzIGlmIGNhc2NhZGluZyBkb3duIGFmZmVjdHMgZGlzYWJsZWQgY2hlY2tib3hlc1xuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNoZWNrYm94LmNhc2NhZGVfdG9fZGlzYWJsZWRcblx0XHQgKiBAcGx1Z2luIGNoZWNrYm94XG5cdFx0ICovXG5cdFx0Y2FzY2FkZV90b19kaXNhYmxlZCA6IHRydWUsXG5cblx0XHQvKipcblx0XHQgKiBUaGlzIHNldHRpbmcgY29udHJvbHMgaWYgY2FzY2FkaW5nIGRvd24gYWZmZWN0cyBoaWRkZW4gY2hlY2tib3hlc1xuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNoZWNrYm94LmNhc2NhZGVfdG9faGlkZGVuXG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdGNhc2NhZGVfdG9faGlkZGVuIDogdHJ1ZVxuXHR9O1xuXHQkLmpzdHJlZS5wbHVnaW5zLmNoZWNrYm94ID0gZnVuY3Rpb24gKG9wdGlvbnMsIHBhcmVudCkge1xuXHRcdHRoaXMuYmluZCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHBhcmVudC5iaW5kLmNhbGwodGhpcyk7XG5cdFx0XHR0aGlzLl9kYXRhLmNoZWNrYm94LnV0byA9IGZhbHNlO1xuXHRcdFx0dGhpcy5fZGF0YS5jaGVja2JveC5zZWxlY3RlZCA9IFtdO1xuXHRcdFx0aWYodGhpcy5zZXR0aW5ncy5jaGVja2JveC50aHJlZV9zdGF0ZSkge1xuXHRcdFx0XHR0aGlzLnNldHRpbmdzLmNoZWNrYm94LmNhc2NhZGUgPSAndXArZG93bit1bmRldGVybWluZWQnO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5lbGVtZW50XG5cdFx0XHRcdC5vbihcImluaXQuanN0cmVlXCIsIGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY2hlY2tib3gudmlzaWJsZSA9IHRoaXMuc2V0dGluZ3MuY2hlY2tib3gudmlzaWJsZTtcblx0XHRcdFx0XHRcdGlmKCF0aGlzLnNldHRpbmdzLmNoZWNrYm94LmtlZXBfc2VsZWN0ZWRfc3R5bGUpIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5lbGVtZW50LmFkZENsYXNzKCdqc3RyZWUtY2hlY2tib3gtbm8tY2xpY2tlZCcpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYodGhpcy5zZXR0aW5ncy5jaGVja2JveC50aWVfc2VsZWN0aW9uKSB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuZWxlbWVudC5hZGRDbGFzcygnanN0cmVlLWNoZWNrYm94LXNlbGVjdGlvbicpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0uYmluZCh0aGlzKSlcblx0XHRcdFx0Lm9uKFwibG9hZGluZy5qc3RyZWVcIiwgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0dGhpc1sgdGhpcy5fZGF0YS5jaGVja2JveC52aXNpYmxlID8gJ3Nob3dfY2hlY2tib3hlcycgOiAnaGlkZV9jaGVja2JveGVzJyBdKCk7XG5cdFx0XHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHRcdGlmKHRoaXMuc2V0dGluZ3MuY2hlY2tib3guY2FzY2FkZS5pbmRleE9mKCd1bmRldGVybWluZWQnKSAhPT0gLTEpIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50XG5cdFx0XHRcdFx0Lm9uKCdjaGFuZ2VkLmpzdHJlZSB1bmNoZWNrX25vZGUuanN0cmVlIGNoZWNrX25vZGUuanN0cmVlIHVuY2hlY2tfYWxsLmpzdHJlZSBjaGVja19hbGwuanN0cmVlIG1vdmVfbm9kZS5qc3RyZWUgY29weV9ub2RlLmpzdHJlZSByZWRyYXcuanN0cmVlIG9wZW5fbm9kZS5qc3RyZWUnLCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0XHRcdC8vIG9ubHkgaWYgdW5kZXRlcm1pbmVkIGlzIGluIHNldHRpbmdcblx0XHRcdFx0XHRcdFx0aWYodGhpcy5fZGF0YS5jaGVja2JveC51dG8pIHsgY2xlYXJUaW1lb3V0KHRoaXMuX2RhdGEuY2hlY2tib3gudXRvKTsgfVxuXHRcdFx0XHRcdFx0XHR0aGlzLl9kYXRhLmNoZWNrYm94LnV0byA9IHNldFRpbWVvdXQodGhpcy5fdW5kZXRlcm1pbmVkLmJpbmQodGhpcyksIDUwKTtcblx0XHRcdFx0XHRcdH0uYmluZCh0aGlzKSk7XG5cdFx0XHR9XG5cdFx0XHRpZighdGhpcy5zZXR0aW5ncy5jaGVja2JveC50aWVfc2VsZWN0aW9uKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0XHRcdC5vbignbW9kZWwuanN0cmVlJywgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0XHRcdHZhciBtID0gdGhpcy5fbW9kZWwuZGF0YSxcblx0XHRcdFx0XHRcdFx0cCA9IG1bZGF0YS5wYXJlbnRdLFxuXHRcdFx0XHRcdFx0XHRkcGMgPSBkYXRhLm5vZGVzLFxuXHRcdFx0XHRcdFx0XHRpLCBqO1xuXHRcdFx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gZHBjLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdFx0XHRtW2RwY1tpXV0uc3RhdGUuY2hlY2tlZCA9IG1bZHBjW2ldXS5zdGF0ZS5jaGVja2VkIHx8IChtW2RwY1tpXV0ub3JpZ2luYWwgJiYgbVtkcGNbaV1dLm9yaWdpbmFsLnN0YXRlICYmIG1bZHBjW2ldXS5vcmlnaW5hbC5zdGF0ZS5jaGVja2VkKTtcblx0XHRcdFx0XHRcdFx0aWYobVtkcGNbaV1dLnN0YXRlLmNoZWNrZWQpIHtcblx0XHRcdFx0XHRcdFx0XHR0aGlzLl9kYXRhLmNoZWNrYm94LnNlbGVjdGVkLnB1c2goZHBjW2ldKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0uYmluZCh0aGlzKSk7XG5cdFx0XHR9XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLmNoZWNrYm94LmNhc2NhZGUuaW5kZXhPZigndXAnKSAhPT0gLTEgfHwgdGhpcy5zZXR0aW5ncy5jaGVja2JveC5jYXNjYWRlLmluZGV4T2YoJ2Rvd24nKSAhPT0gLTEpIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50XG5cdFx0XHRcdFx0Lm9uKCdtb2RlbC5qc3RyZWUnLCBmdW5jdGlvbiAoZSwgZGF0YSkge1xuXHRcdFx0XHRcdFx0XHR2YXIgbSA9IHRoaXMuX21vZGVsLmRhdGEsXG5cdFx0XHRcdFx0XHRcdFx0cCA9IG1bZGF0YS5wYXJlbnRdLFxuXHRcdFx0XHRcdFx0XHRcdGRwYyA9IGRhdGEubm9kZXMsXG5cdFx0XHRcdFx0XHRcdFx0Y2hkID0gW10sXG5cdFx0XHRcdFx0XHRcdFx0YywgaSwgaiwgaywgbCwgdG1wLCBzID0gdGhpcy5zZXR0aW5ncy5jaGVja2JveC5jYXNjYWRlLCB0ID0gdGhpcy5zZXR0aW5ncy5jaGVja2JveC50aWVfc2VsZWN0aW9uO1xuXG5cdFx0XHRcdFx0XHRcdGlmKHMuaW5kZXhPZignZG93bicpICE9PSAtMSkge1xuXHRcdFx0XHRcdFx0XHRcdC8vIGFwcGx5IGRvd25cblx0XHRcdFx0XHRcdFx0XHRpZihwLnN0YXRlWyB0ID8gJ3NlbGVjdGVkJyA6ICdjaGVja2VkJyBdKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSBkcGMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdG1bZHBjW2ldXS5zdGF0ZVsgdCA/ICdzZWxlY3RlZCcgOiAnY2hlY2tlZCcgXSA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGFbIHQgPyAnY29yZScgOiAnY2hlY2tib3gnIF0uc2VsZWN0ZWQgPSB0aGlzLl9kYXRhWyB0ID8gJ2NvcmUnIDogJ2NoZWNrYm94JyBdLnNlbGVjdGVkLmNvbmNhdChkcGMpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRcdGZvcihpID0gMCwgaiA9IGRwYy5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYobVtkcGNbaV1dLnN0YXRlWyB0ID8gJ3NlbGVjdGVkJyA6ICdjaGVja2VkJyBdKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Zm9yKGsgPSAwLCBsID0gbVtkcGNbaV1dLmNoaWxkcmVuX2QubGVuZ3RoOyBrIDwgbDsgaysrKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRtW21bZHBjW2ldXS5jaGlsZHJlbl9kW2tdXS5zdGF0ZVsgdCA/ICdzZWxlY3RlZCcgOiAnY2hlY2tlZCcgXSA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGFbIHQgPyAnY29yZScgOiAnY2hlY2tib3gnIF0uc2VsZWN0ZWQgPSB0aGlzLl9kYXRhWyB0ID8gJ2NvcmUnIDogJ2NoZWNrYm94JyBdLnNlbGVjdGVkLmNvbmNhdChtW2RwY1tpXV0uY2hpbGRyZW5fZCk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRpZihzLmluZGV4T2YoJ3VwJykgIT09IC0xKSB7XG5cdFx0XHRcdFx0XHRcdFx0Ly8gYXBwbHkgdXBcblx0XHRcdFx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSBwLmNoaWxkcmVuX2QubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZighbVtwLmNoaWxkcmVuX2RbaV1dLmNoaWxkcmVuLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRjaGQucHVzaChtW3AuY2hpbGRyZW5fZFtpXV0ucGFyZW50KTtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0Y2hkID0gJC52YWthdGEuYXJyYXlfdW5pcXVlKGNoZCk7XG5cdFx0XHRcdFx0XHRcdFx0Zm9yKGsgPSAwLCBsID0gY2hkLmxlbmd0aDsgayA8IGw7IGsrKykge1xuXHRcdFx0XHRcdFx0XHRcdFx0cCA9IG1bY2hkW2tdXTtcblx0XHRcdFx0XHRcdFx0XHRcdHdoaWxlKHAgJiYgcC5pZCAhPT0gJC5qc3RyZWUucm9vdCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRjID0gMDtcblx0XHRcdFx0XHRcdFx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gcC5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRjICs9IG1bcC5jaGlsZHJlbltpXV0uc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF07XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYoYyA9PT0gaikge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHAuc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF0gPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGFbIHQgPyAnY29yZScgOiAnY2hlY2tib3gnIF0uc2VsZWN0ZWQucHVzaChwLmlkKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHR0bXAgPSB0aGlzLmdldF9ub2RlKHAsIHRydWUpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdGlmKHRtcCAmJiB0bXAubGVuZ3RoKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR0bXAuYXR0cignYXJpYS1zZWxlY3RlZCcsIHRydWUpLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLmFkZENsYXNzKCB0ID8gJ2pzdHJlZS1jbGlja2VkJyA6ICdqc3RyZWUtY2hlY2tlZCcpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRwID0gdGhpcy5nZXRfbm9kZShwLnBhcmVudCk7XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0dGhpcy5fZGF0YVsgdCA/ICdjb3JlJyA6ICdjaGVja2JveCcgXS5zZWxlY3RlZCA9ICQudmFrYXRhLmFycmF5X3VuaXF1ZSh0aGlzLl9kYXRhWyB0ID8gJ2NvcmUnIDogJ2NoZWNrYm94JyBdLnNlbGVjdGVkKTtcblx0XHRcdFx0XHRcdH0uYmluZCh0aGlzKSlcblx0XHRcdFx0XHQub24odGhpcy5zZXR0aW5ncy5jaGVja2JveC50aWVfc2VsZWN0aW9uID8gJ3NlbGVjdF9ub2RlLmpzdHJlZScgOiAnY2hlY2tfbm9kZS5qc3RyZWUnLCBmdW5jdGlvbiAoZSwgZGF0YSkge1xuXHRcdFx0XHRcdFx0XHR2YXIgc2VsZiA9IHRoaXMsXG5cdFx0XHRcdFx0XHRcdFx0b2JqID0gZGF0YS5ub2RlLFxuXHRcdFx0XHRcdFx0XHRcdG0gPSB0aGlzLl9tb2RlbC5kYXRhLFxuXHRcdFx0XHRcdFx0XHRcdHBhciA9IHRoaXMuZ2V0X25vZGUob2JqLnBhcmVudCksXG5cdFx0XHRcdFx0XHRcdFx0aSwgaiwgYywgdG1wLCBzID0gdGhpcy5zZXR0aW5ncy5jaGVja2JveC5jYXNjYWRlLCB0ID0gdGhpcy5zZXR0aW5ncy5jaGVja2JveC50aWVfc2VsZWN0aW9uLFxuXHRcdFx0XHRcdFx0XHRcdHNlbCA9IHt9LCBjdXIgPSB0aGlzLl9kYXRhWyB0ID8gJ2NvcmUnIDogJ2NoZWNrYm94JyBdLnNlbGVjdGVkO1xuXG5cdFx0XHRcdFx0XHRcdGZvciAoaSA9IDAsIGogPSBjdXIubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdFx0c2VsW2N1cltpXV0gPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0Ly8gYXBwbHkgZG93blxuXHRcdFx0XHRcdFx0XHRpZihzLmluZGV4T2YoJ2Rvd24nKSAhPT0gLTEpIHtcblx0XHRcdFx0XHRcdFx0XHQvL3RoaXMuX2RhdGFbIHQgPyAnY29yZScgOiAnY2hlY2tib3gnIF0uc2VsZWN0ZWQgPSAkLnZha2F0YS5hcnJheV91bmlxdWUodGhpcy5fZGF0YVsgdCA/ICdjb3JlJyA6ICdjaGVja2JveCcgXS5zZWxlY3RlZC5jb25jYXQob2JqLmNoaWxkcmVuX2QpKTtcblx0XHRcdFx0XHRcdFx0XHR2YXIgc2VsZWN0ZWRJZHMgPSB0aGlzLl9jYXNjYWRlX25ld19jaGVja2VkX3N0YXRlKG9iai5pZCwgdHJ1ZSk7XG5cdFx0XHRcdFx0XHRcdFx0dmFyIHRlbXAgPSBvYmouY2hpbGRyZW5fZC5jb25jYXQob2JqLmlkKTtcblx0XHRcdFx0XHRcdFx0XHRmb3IgKGkgPSAwLCBqID0gdGVtcC5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdFx0XHRcdGlmIChzZWxlY3RlZElkcy5pbmRleE9mKHRlbXBbaV0pID4gLTEpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0c2VsW3RlbXBbaV1dID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRkZWxldGUgc2VsW3RlbXBbaV1dO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdC8vIGFwcGx5IHVwXG5cdFx0XHRcdFx0XHRcdGlmKHMuaW5kZXhPZigndXAnKSAhPT0gLTEpIHtcblx0XHRcdFx0XHRcdFx0XHR3aGlsZShwYXIgJiYgcGFyLmlkICE9PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRjID0gMDtcblx0XHRcdFx0XHRcdFx0XHRcdGZvcihpID0gMCwgaiA9IHBhci5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0YyArPSBtW3Bhci5jaGlsZHJlbltpXV0uc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF07XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0XHRpZihjID09PSBqKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHBhci5zdGF0ZVsgdCA/ICdzZWxlY3RlZCcgOiAnY2hlY2tlZCcgXSA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHNlbFtwYXIuaWRdID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0Ly90aGlzLl9kYXRhWyB0ID8gJ2NvcmUnIDogJ2NoZWNrYm94JyBdLnNlbGVjdGVkLnB1c2gocGFyLmlkKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dG1wID0gdGhpcy5nZXRfbm9kZShwYXIsIHRydWUpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRpZih0bXAgJiYgdG1wLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRtcC5hdHRyKCdhcmlhLXNlbGVjdGVkJywgdHJ1ZSkuY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykuYWRkQ2xhc3ModCA/ICdqc3RyZWUtY2xpY2tlZCcgOiAnanN0cmVlLWNoZWNrZWQnKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0cGFyID0gdGhpcy5nZXRfbm9kZShwYXIucGFyZW50KTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRjdXIgPSBbXTtcblx0XHRcdFx0XHRcdFx0Zm9yIChpIGluIHNlbCkge1xuXHRcdFx0XHRcdFx0XHRcdGlmIChzZWwuaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHRcdFx0XHRcdGN1ci5wdXNoKGkpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR0aGlzLl9kYXRhWyB0ID8gJ2NvcmUnIDogJ2NoZWNrYm94JyBdLnNlbGVjdGVkID0gY3VyO1xuXHRcdFx0XHRcdFx0fS5iaW5kKHRoaXMpKVxuXHRcdFx0XHRcdC5vbih0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24gPyAnZGVzZWxlY3RfYWxsLmpzdHJlZScgOiAndW5jaGVja19hbGwuanN0cmVlJywgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0XHRcdFx0dmFyIG9iaiA9IHRoaXMuZ2V0X25vZGUoJC5qc3RyZWUucm9vdCksXG5cdFx0XHRcdFx0XHRcdFx0bSA9IHRoaXMuX21vZGVsLmRhdGEsXG5cdFx0XHRcdFx0XHRcdFx0aSwgaiwgdG1wO1xuXHRcdFx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSBvYmouY2hpbGRyZW5fZC5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdFx0XHR0bXAgPSBtW29iai5jaGlsZHJlbl9kW2ldXTtcblx0XHRcdFx0XHRcdFx0XHRpZih0bXAgJiYgdG1wLm9yaWdpbmFsICYmIHRtcC5vcmlnaW5hbC5zdGF0ZSAmJiB0bXAub3JpZ2luYWwuc3RhdGUudW5kZXRlcm1pbmVkKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHR0bXAub3JpZ2luYWwuc3RhdGUudW5kZXRlcm1pbmVkID0gZmFsc2U7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdFx0Lm9uKHRoaXMuc2V0dGluZ3MuY2hlY2tib3gudGllX3NlbGVjdGlvbiA/ICdkZXNlbGVjdF9ub2RlLmpzdHJlZScgOiAndW5jaGVja19ub2RlLmpzdHJlZScsIGZ1bmN0aW9uIChlLCBkYXRhKSB7XG5cdFx0XHRcdFx0XHRcdHZhciBzZWxmID0gdGhpcyxcblx0XHRcdFx0XHRcdFx0XHRvYmogPSBkYXRhLm5vZGUsXG5cdFx0XHRcdFx0XHRcdFx0ZG9tID0gdGhpcy5nZXRfbm9kZShvYmosIHRydWUpLFxuXHRcdFx0XHRcdFx0XHRcdGksIGosIHRtcCwgcyA9IHRoaXMuc2V0dGluZ3MuY2hlY2tib3guY2FzY2FkZSwgdCA9IHRoaXMuc2V0dGluZ3MuY2hlY2tib3gudGllX3NlbGVjdGlvbixcblx0XHRcdFx0XHRcdFx0XHRjdXIgPSB0aGlzLl9kYXRhWyB0ID8gJ2NvcmUnIDogJ2NoZWNrYm94JyBdLnNlbGVjdGVkLCBzZWwgPSB7fSxcblx0XHRcdFx0XHRcdFx0XHRzdGlsbFNlbGVjdGVkSWRzID0gW10sXG5cdFx0XHRcdFx0XHRcdFx0YWxsSWRzID0gb2JqLmNoaWxkcmVuX2QuY29uY2F0KG9iai5pZCk7XG5cblx0XHRcdFx0XHRcdFx0Ly8gYXBwbHkgZG93blxuXHRcdFx0XHRcdFx0XHRpZihzLmluZGV4T2YoJ2Rvd24nKSAhPT0gLTEpIHtcblx0XHRcdFx0XHRcdFx0XHR2YXIgc2VsZWN0ZWRJZHMgPSB0aGlzLl9jYXNjYWRlX25ld19jaGVja2VkX3N0YXRlKG9iai5pZCwgZmFsc2UpO1xuXG5cdFx0XHRcdFx0XHRcdFx0Y3VyID0gJC52YWthdGEuYXJyYXlfZmlsdGVyKGN1ciwgZnVuY3Rpb24oaWQpIHtcblx0XHRcdFx0XHRcdFx0XHRcdHJldHVybiBhbGxJZHMuaW5kZXhPZihpZCkgPT09IC0xIHx8IHNlbGVjdGVkSWRzLmluZGV4T2YoaWQpID4gLTE7XG5cdFx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHQvLyBvbmx5IGFwcGx5IHVwIGlmIGNhc2NhZGUgdXAgaXMgZW5hYmxlZCBhbmQgaWYgdGhpcyBub2RlIGlzIG5vdCBzZWxlY3RlZFxuXHRcdFx0XHRcdFx0XHQvLyAoaWYgYWxsIGNoaWxkIG5vZGVzIGFyZSBkaXNhYmxlZCBhbmQgY2FzY2FkZV90b19kaXNhYmxlZCA9PT0gZmFsc2UgdGhlbiB0aGlzIG5vZGUgd2lsbCB0aWxsIGJlIHNlbGVjdGVkKS5cblx0XHRcdFx0XHRcdFx0aWYocy5pbmRleE9mKCd1cCcpICE9PSAtMSAmJiBjdXIuaW5kZXhPZihvYmouaWQpID09PSAtMSkge1xuXHRcdFx0XHRcdFx0XHRcdGZvcihpID0gMCwgaiA9IG9iai5wYXJlbnRzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdFx0XHRcdFx0dG1wID0gdGhpcy5fbW9kZWwuZGF0YVtvYmoucGFyZW50c1tpXV07XG5cdFx0XHRcdFx0XHRcdFx0XHR0bXAuc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF0gPSBmYWxzZTtcblx0XHRcdFx0XHRcdFx0XHRcdGlmKHRtcCAmJiB0bXAub3JpZ2luYWwgJiYgdG1wLm9yaWdpbmFsLnN0YXRlICYmIHRtcC5vcmlnaW5hbC5zdGF0ZS51bmRldGVybWluZWQpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dG1wLm9yaWdpbmFsLnN0YXRlLnVuZGV0ZXJtaW5lZCA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0dG1wID0gdGhpcy5nZXRfbm9kZShvYmoucGFyZW50c1tpXSwgdHJ1ZSk7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZih0bXAgJiYgdG1wLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0bXAuYXR0cignYXJpYS1zZWxlY3RlZCcsIGZhbHNlKS5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS5yZW1vdmVDbGFzcyh0ID8gJ2pzdHJlZS1jbGlja2VkJyA6ICdqc3RyZWUtY2hlY2tlZCcpO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRcdGN1ciA9ICQudmFrYXRhLmFycmF5X2ZpbHRlcihjdXIsIGZ1bmN0aW9uKGlkKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRyZXR1cm4gb2JqLnBhcmVudHMuaW5kZXhPZihpZCkgPT09IC0xO1xuXHRcdFx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0dGhpcy5fZGF0YVsgdCA/ICdjb3JlJyA6ICdjaGVja2JveCcgXS5zZWxlY3RlZCA9IGN1cjtcblx0XHRcdFx0XHRcdH0uYmluZCh0aGlzKSk7XG5cdFx0XHR9XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLmNoZWNrYm94LmNhc2NhZGUuaW5kZXhPZigndXAnKSAhPT0gLTEpIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50XG5cdFx0XHRcdFx0Lm9uKCdkZWxldGVfbm9kZS5qc3RyZWUnLCBmdW5jdGlvbiAoZSwgZGF0YSkge1xuXHRcdFx0XHRcdFx0XHQvLyBhcHBseSB1cCAod2hvbGUgaGFuZGxlcilcblx0XHRcdFx0XHRcdFx0dmFyIHAgPSB0aGlzLmdldF9ub2RlKGRhdGEucGFyZW50KSxcblx0XHRcdFx0XHRcdFx0XHRtID0gdGhpcy5fbW9kZWwuZGF0YSxcblx0XHRcdFx0XHRcdFx0XHRpLCBqLCBjLCB0bXAsIHQgPSB0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb247XG5cdFx0XHRcdFx0XHRcdHdoaWxlKHAgJiYgcC5pZCAhPT0gJC5qc3RyZWUucm9vdCAmJiAhcC5zdGF0ZVsgdCA/ICdzZWxlY3RlZCcgOiAnY2hlY2tlZCcgXSkge1xuXHRcdFx0XHRcdFx0XHRcdGMgPSAwO1xuXHRcdFx0XHRcdFx0XHRcdGZvcihpID0gMCwgaiA9IHAuY2hpbGRyZW4ubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRjICs9IG1bcC5jaGlsZHJlbltpXV0uc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF07XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdGlmKGogPiAwICYmIGMgPT09IGopIHtcblx0XHRcdFx0XHRcdFx0XHRcdHAuc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF0gPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRcdFx0dGhpcy5fZGF0YVsgdCA/ICdjb3JlJyA6ICdjaGVja2JveCcgXS5zZWxlY3RlZC5wdXNoKHAuaWQpO1xuXHRcdFx0XHRcdFx0XHRcdFx0dG1wID0gdGhpcy5nZXRfbm9kZShwLCB0cnVlKTtcblx0XHRcdFx0XHRcdFx0XHRcdGlmKHRtcCAmJiB0bXAubGVuZ3RoKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHRtcC5hdHRyKCdhcmlhLXNlbGVjdGVkJywgdHJ1ZSkuY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykuYWRkQ2xhc3ModCA/ICdqc3RyZWUtY2xpY2tlZCcgOiAnanN0cmVlLWNoZWNrZWQnKTtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0cCA9IHRoaXMuZ2V0X25vZGUocC5wYXJlbnQpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdFx0Lm9uKCdtb3ZlX25vZGUuanN0cmVlJywgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0XHRcdFx0Ly8gYXBwbHkgdXAgKHdob2xlIGhhbmRsZXIpXG5cdFx0XHRcdFx0XHRcdHZhciBpc19tdWx0aSA9IGRhdGEuaXNfbXVsdGksXG5cdFx0XHRcdFx0XHRcdFx0b2xkX3BhciA9IGRhdGEub2xkX3BhcmVudCxcblx0XHRcdFx0XHRcdFx0XHRuZXdfcGFyID0gdGhpcy5nZXRfbm9kZShkYXRhLnBhcmVudCksXG5cdFx0XHRcdFx0XHRcdFx0bSA9IHRoaXMuX21vZGVsLmRhdGEsXG5cdFx0XHRcdFx0XHRcdFx0cCwgYywgaSwgaiwgdG1wLCB0ID0gdGhpcy5zZXR0aW5ncy5jaGVja2JveC50aWVfc2VsZWN0aW9uO1xuXHRcdFx0XHRcdFx0XHRpZighaXNfbXVsdGkpIHtcblx0XHRcdFx0XHRcdFx0XHRwID0gdGhpcy5nZXRfbm9kZShvbGRfcGFyKTtcblx0XHRcdFx0XHRcdFx0XHR3aGlsZShwICYmIHAuaWQgIT09ICQuanN0cmVlLnJvb3QgJiYgIXAuc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF0pIHtcblx0XHRcdFx0XHRcdFx0XHRcdGMgPSAwO1xuXHRcdFx0XHRcdFx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gcC5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0YyArPSBtW3AuY2hpbGRyZW5baV1dLnN0YXRlWyB0ID8gJ3NlbGVjdGVkJyA6ICdjaGVja2VkJyBdO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0aWYoaiA+IDAgJiYgYyA9PT0gaikge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRwLnN0YXRlWyB0ID8gJ3NlbGVjdGVkJyA6ICdjaGVja2VkJyBdID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGhpcy5fZGF0YVsgdCA/ICdjb3JlJyA6ICdjaGVja2JveCcgXS5zZWxlY3RlZC5wdXNoKHAuaWQpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0bXAgPSB0aGlzLmdldF9ub2RlKHAsIHRydWUpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRpZih0bXAgJiYgdG1wLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRtcC5hdHRyKCdhcmlhLXNlbGVjdGVkJywgdHJ1ZSkuY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykuYWRkQ2xhc3ModCA/ICdqc3RyZWUtY2xpY2tlZCcgOiAnanN0cmVlLWNoZWNrZWQnKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0cCA9IHRoaXMuZ2V0X25vZGUocC5wYXJlbnQpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRwID0gbmV3X3Bhcjtcblx0XHRcdFx0XHRcdFx0d2hpbGUocCAmJiBwLmlkICE9PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdFx0XHRcdFx0YyA9IDA7XG5cdFx0XHRcdFx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gcC5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdFx0XHRcdGMgKz0gbVtwLmNoaWxkcmVuW2ldXS5zdGF0ZVsgdCA/ICdzZWxlY3RlZCcgOiAnY2hlY2tlZCcgXTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0aWYoYyA9PT0gaikge1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYoIXAuc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF0pIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0cC5zdGF0ZVsgdCA/ICdzZWxlY3RlZCcgOiAnY2hlY2tlZCcgXSA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGFbIHQgPyAnY29yZScgOiAnY2hlY2tib3gnIF0uc2VsZWN0ZWQucHVzaChwLmlkKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dG1wID0gdGhpcy5nZXRfbm9kZShwLCB0cnVlKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYodG1wICYmIHRtcC5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHR0bXAuYXR0cignYXJpYS1zZWxlY3RlZCcsIHRydWUpLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLmFkZENsYXNzKHQgPyAnanN0cmVlLWNsaWNrZWQnIDogJ2pzdHJlZS1jaGVja2VkJyk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZihwLnN0YXRlWyB0ID8gJ3NlbGVjdGVkJyA6ICdjaGVja2VkJyBdKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHAuc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF0gPSBmYWxzZTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGhpcy5fZGF0YVsgdCA/ICdjb3JlJyA6ICdjaGVja2JveCcgXS5zZWxlY3RlZCA9ICQudmFrYXRhLmFycmF5X3JlbW92ZV9pdGVtKHRoaXMuX2RhdGFbIHQgPyAnY29yZScgOiAnY2hlY2tib3gnIF0uc2VsZWN0ZWQsIHAuaWQpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0bXAgPSB0aGlzLmdldF9ub2RlKHAsIHRydWUpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRpZih0bXAgJiYgdG1wLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRtcC5hdHRyKCdhcmlhLXNlbGVjdGVkJywgZmFsc2UpLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLnJlbW92ZUNsYXNzKHQgPyAnanN0cmVlLWNsaWNrZWQnIDogJ2pzdHJlZS1jaGVja2VkJyk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0cCA9IHRoaXMuZ2V0X25vZGUocC5wYXJlbnQpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9LmJpbmQodGhpcykpO1xuXHRcdFx0fVxuXHRcdH07XG5cdFx0LyoqXG5cdFx0ICogZ2V0IGFuIGFycmF5IG9mIGFsbCBub2RlcyB3aG9zZSBzdGF0ZSBpcyBcInVuZGV0ZXJtaW5lZFwiXG5cdFx0ICogQG5hbWUgZ2V0X3VuZGV0ZXJtaW5lZChbZnVsbF0pXG5cdFx0ICogQHBhcmFtICB7Ym9vbGVhbn0gZnVsbDogaWYgc2V0IHRvIGB0cnVlYCB0aGUgcmV0dXJuZWQgYXJyYXkgd2lsbCBjb25zaXN0IG9mIHRoZSBmdWxsIG5vZGUgb2JqZWN0cywgb3RoZXJ3aXNlIC0gb25seSBJRHMgd2lsbCBiZSByZXR1cm5lZFxuXHRcdCAqIEByZXR1cm4ge0FycmF5fVxuXHRcdCAqIEBwbHVnaW4gY2hlY2tib3hcblx0XHQgKi9cblx0XHR0aGlzLmdldF91bmRldGVybWluZWQgPSBmdW5jdGlvbiAoZnVsbCkge1xuXHRcdFx0aWYgKHRoaXMuc2V0dGluZ3MuY2hlY2tib3guY2FzY2FkZS5pbmRleE9mKCd1bmRldGVybWluZWQnKSA9PT0gLTEpIHtcblx0XHRcdFx0cmV0dXJuIFtdO1xuXHRcdFx0fVxuXHRcdFx0dmFyIGksIGosIGssIGwsIG8gPSB7fSwgbSA9IHRoaXMuX21vZGVsLmRhdGEsIHQgPSB0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24sIHMgPSB0aGlzLl9kYXRhWyB0ID8gJ2NvcmUnIDogJ2NoZWNrYm94JyBdLnNlbGVjdGVkLCBwID0gW10sIHR0ID0gdGhpcywgciA9IFtdO1xuXHRcdFx0Zm9yKGkgPSAwLCBqID0gcy5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0aWYobVtzW2ldXSAmJiBtW3NbaV1dLnBhcmVudHMpIHtcblx0XHRcdFx0XHRmb3IoayA9IDAsIGwgPSBtW3NbaV1dLnBhcmVudHMubGVuZ3RoOyBrIDwgbDsgaysrKSB7XG5cdFx0XHRcdFx0XHRpZihvW21bc1tpXV0ucGFyZW50c1trXV0gIT09IHVuZGVmaW5lZCkge1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmKG1bc1tpXV0ucGFyZW50c1trXSAhPT0gJC5qc3RyZWUucm9vdCkge1xuXHRcdFx0XHRcdFx0XHRvW21bc1tpXV0ucGFyZW50c1trXV0gPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRwLnB1c2gobVtzW2ldXS5wYXJlbnRzW2tdKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdC8vIGF0dGVtcHQgZm9yIHNlcnZlciBzaWRlIHVuZGV0ZXJtaW5lZCBzdGF0ZVxuXHRcdFx0dGhpcy5lbGVtZW50LmZpbmQoJy5qc3RyZWUtY2xvc2VkJykubm90KCc6aGFzKC5qc3RyZWUtY2hpbGRyZW4pJylcblx0XHRcdFx0LmVhY2goZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdHZhciB0bXAgPSB0dC5nZXRfbm9kZSh0aGlzKSwgdG1wMjtcblx0XHRcdFx0XHRcblx0XHRcdFx0XHRpZighdG1wKSB7IHJldHVybjsgfVxuXHRcdFx0XHRcdFxuXHRcdFx0XHRcdGlmKCF0bXAuc3RhdGUubG9hZGVkKSB7XG5cdFx0XHRcdFx0XHRpZih0bXAub3JpZ2luYWwgJiYgdG1wLm9yaWdpbmFsLnN0YXRlICYmIHRtcC5vcmlnaW5hbC5zdGF0ZS51bmRldGVybWluZWQgJiYgdG1wLm9yaWdpbmFsLnN0YXRlLnVuZGV0ZXJtaW5lZCA9PT0gdHJ1ZSkge1xuXHRcdFx0XHRcdFx0XHRpZihvW3RtcC5pZF0gPT09IHVuZGVmaW5lZCAmJiB0bXAuaWQgIT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0XHRcdFx0XHRvW3RtcC5pZF0gPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRcdHAucHVzaCh0bXAuaWQpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGZvcihrID0gMCwgbCA9IHRtcC5wYXJlbnRzLmxlbmd0aDsgayA8IGw7IGsrKykge1xuXHRcdFx0XHRcdFx0XHRcdGlmKG9bdG1wLnBhcmVudHNba11dID09PSB1bmRlZmluZWQgJiYgdG1wLnBhcmVudHNba10gIT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0XHRcdFx0XHRcdG9bdG1wLnBhcmVudHNba11dID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0XHRcdHAucHVzaCh0bXAucGFyZW50c1trXSk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gdG1wLmNoaWxkcmVuX2QubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdHRtcDIgPSBtW3RtcC5jaGlsZHJlbl9kW2ldXTtcblx0XHRcdFx0XHRcdFx0aWYoIXRtcDIuc3RhdGUubG9hZGVkICYmIHRtcDIub3JpZ2luYWwgJiYgdG1wMi5vcmlnaW5hbC5zdGF0ZSAmJiB0bXAyLm9yaWdpbmFsLnN0YXRlLnVuZGV0ZXJtaW5lZCAmJiB0bXAyLm9yaWdpbmFsLnN0YXRlLnVuZGV0ZXJtaW5lZCA9PT0gdHJ1ZSkge1xuXHRcdFx0XHRcdFx0XHRcdGlmKG9bdG1wMi5pZF0gPT09IHVuZGVmaW5lZCAmJiB0bXAyLmlkICE9PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRvW3RtcDIuaWRdID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0XHRcdHAucHVzaCh0bXAyLmlkKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0Zm9yKGsgPSAwLCBsID0gdG1wMi5wYXJlbnRzLmxlbmd0aDsgayA8IGw7IGsrKykge1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYob1t0bXAyLnBhcmVudHNba11dID09PSB1bmRlZmluZWQgJiYgdG1wMi5wYXJlbnRzW2tdICE9PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdG9bdG1wMi5wYXJlbnRzW2tdXSA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHAucHVzaCh0bXAyLnBhcmVudHNba10pO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSk7XG5cdFx0XHRmb3IgKGkgPSAwLCBqID0gcC5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0aWYoIW1bcFtpXV0uc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF0pIHtcblx0XHRcdFx0XHRyLnB1c2goZnVsbCA/IG1bcFtpXV0gOiBwW2ldKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHI7XG5cdFx0fTtcblx0XHQvKipcblx0XHQgKiBzZXQgdGhlIHVuZGV0ZXJtaW5lZCBzdGF0ZSB3aGVyZSBhbmQgaWYgbmVjZXNzYXJ5LiBVc2VkIGludGVybmFsbHkuXG5cdFx0ICogQHByaXZhdGVcblx0XHQgKiBAbmFtZSBfdW5kZXRlcm1pbmVkKClcblx0XHQgKiBAcGx1Z2luIGNoZWNrYm94XG5cdFx0ICovXG5cdFx0dGhpcy5fdW5kZXRlcm1pbmVkID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0aWYodGhpcy5lbGVtZW50ID09PSBudWxsKSB7IHJldHVybjsgfVxuXHRcdFx0dmFyIHAgPSB0aGlzLmdldF91bmRldGVybWluZWQoZmFsc2UpLCBpLCBqLCBzO1xuXG5cdFx0XHR0aGlzLmVsZW1lbnQuZmluZCgnLmpzdHJlZS11bmRldGVybWluZWQnKS5yZW1vdmVDbGFzcygnanN0cmVlLXVuZGV0ZXJtaW5lZCcpO1xuXHRcdFx0Zm9yIChpID0gMCwgaiA9IHAubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdHMgPSB0aGlzLmdldF9ub2RlKHBbaV0sIHRydWUpO1xuXHRcdFx0XHRpZihzICYmIHMubGVuZ3RoKSB7XG5cdFx0XHRcdFx0cy5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS5jaGlsZHJlbignLmpzdHJlZS1jaGVja2JveCcpLmFkZENsYXNzKCdqc3RyZWUtdW5kZXRlcm1pbmVkJyk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9O1xuXHRcdHRoaXMucmVkcmF3X25vZGUgPSBmdW5jdGlvbihvYmosIGRlZXAsIGlzX2NhbGxiYWNrLCBmb3JjZV9yZW5kZXIpIHtcblx0XHRcdG9iaiA9IHBhcmVudC5yZWRyYXdfbm9kZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXHRcdFx0aWYob2JqKSB7XG5cdFx0XHRcdHZhciBpLCBqLCB0bXAgPSBudWxsLCBpY29uID0gbnVsbDtcblx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gb2JqLmNoaWxkTm9kZXMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0aWYob2JqLmNoaWxkTm9kZXNbaV0gJiYgb2JqLmNoaWxkTm9kZXNbaV0uY2xhc3NOYW1lICYmIG9iai5jaGlsZE5vZGVzW2ldLmNsYXNzTmFtZS5pbmRleE9mKFwianN0cmVlLWFuY2hvclwiKSAhPT0gLTEpIHtcblx0XHRcdFx0XHRcdHRtcCA9IG9iai5jaGlsZE5vZGVzW2ldO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKHRtcCkge1xuXHRcdFx0XHRcdGlmKCF0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24gJiYgdGhpcy5fbW9kZWwuZGF0YVtvYmouaWRdLnN0YXRlLmNoZWNrZWQpIHsgdG1wLmNsYXNzTmFtZSArPSAnIGpzdHJlZS1jaGVja2VkJzsgfVxuXHRcdFx0XHRcdGljb24gPSBfaS5jbG9uZU5vZGUoZmFsc2UpO1xuXHRcdFx0XHRcdGlmKHRoaXMuX21vZGVsLmRhdGFbb2JqLmlkXS5zdGF0ZS5jaGVja2JveF9kaXNhYmxlZCkgeyBpY29uLmNsYXNzTmFtZSArPSAnIGpzdHJlZS1jaGVja2JveC1kaXNhYmxlZCc7IH1cblx0XHRcdFx0XHR0bXAuaW5zZXJ0QmVmb3JlKGljb24sIHRtcC5jaGlsZE5vZGVzWzBdKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0aWYoIWlzX2NhbGxiYWNrICYmIHRoaXMuc2V0dGluZ3MuY2hlY2tib3guY2FzY2FkZS5pbmRleE9mKCd1bmRldGVybWluZWQnKSAhPT0gLTEpIHtcblx0XHRcdFx0aWYodGhpcy5fZGF0YS5jaGVja2JveC51dG8pIHsgY2xlYXJUaW1lb3V0KHRoaXMuX2RhdGEuY2hlY2tib3gudXRvKTsgfVxuXHRcdFx0XHR0aGlzLl9kYXRhLmNoZWNrYm94LnV0byA9IHNldFRpbWVvdXQodGhpcy5fdW5kZXRlcm1pbmVkLmJpbmQodGhpcyksIDUwKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBvYmo7XG5cdFx0fTtcblx0XHQvKipcblx0XHQgKiBzaG93IHRoZSBub2RlIGNoZWNrYm94IGljb25zXG5cdFx0ICogQG5hbWUgc2hvd19jaGVja2JveGVzKClcblx0XHQgKiBAcGx1Z2luIGNoZWNrYm94XG5cdFx0ICovXG5cdFx0dGhpcy5zaG93X2NoZWNrYm94ZXMgPSBmdW5jdGlvbiAoKSB7IHRoaXMuX2RhdGEuY29yZS50aGVtZXMuY2hlY2tib3hlcyA9IHRydWU7IHRoaXMuZ2V0X2NvbnRhaW5lcl91bCgpLnJlbW92ZUNsYXNzKFwianN0cmVlLW5vLWNoZWNrYm94ZXNcIik7IH07XG5cdFx0LyoqXG5cdFx0ICogaGlkZSB0aGUgbm9kZSBjaGVja2JveCBpY29uc1xuXHRcdCAqIEBuYW1lIGhpZGVfY2hlY2tib3hlcygpXG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdHRoaXMuaGlkZV9jaGVja2JveGVzID0gZnVuY3Rpb24gKCkgeyB0aGlzLl9kYXRhLmNvcmUudGhlbWVzLmNoZWNrYm94ZXMgPSBmYWxzZTsgdGhpcy5nZXRfY29udGFpbmVyX3VsKCkuYWRkQ2xhc3MoXCJqc3RyZWUtbm8tY2hlY2tib3hlc1wiKTsgfTtcblx0XHQvKipcblx0XHQgKiB0b2dnbGUgdGhlIG5vZGUgaWNvbnNcblx0XHQgKiBAbmFtZSB0b2dnbGVfY2hlY2tib3hlcygpXG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdHRoaXMudG9nZ2xlX2NoZWNrYm94ZXMgPSBmdW5jdGlvbiAoKSB7IGlmKHRoaXMuX2RhdGEuY29yZS50aGVtZXMuY2hlY2tib3hlcykgeyB0aGlzLmhpZGVfY2hlY2tib3hlcygpOyB9IGVsc2UgeyB0aGlzLnNob3dfY2hlY2tib3hlcygpOyB9IH07XG5cdFx0LyoqXG5cdFx0ICogY2hlY2tzIGlmIGEgbm9kZSBpcyBpbiBhbiB1bmRldGVybWluZWQgc3RhdGVcblx0XHQgKiBAbmFtZSBpc191bmRldGVybWluZWQob2JqKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSBvYmpcblx0XHQgKiBAcmV0dXJuIHtCb29sZWFufVxuXHRcdCAqL1xuXHRcdHRoaXMuaXNfdW5kZXRlcm1pbmVkID0gZnVuY3Rpb24gKG9iaikge1xuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0dmFyIHMgPSB0aGlzLnNldHRpbmdzLmNoZWNrYm94LmNhc2NhZGUsIGksIGosIHQgPSB0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24sIGQgPSB0aGlzLl9kYXRhWyB0ID8gJ2NvcmUnIDogJ2NoZWNrYm94JyBdLnNlbGVjdGVkLCBtID0gdGhpcy5fbW9kZWwuZGF0YTtcblx0XHRcdGlmKCFvYmogfHwgb2JqLnN0YXRlWyB0ID8gJ3NlbGVjdGVkJyA6ICdjaGVja2VkJyBdID09PSB0cnVlIHx8IHMuaW5kZXhPZigndW5kZXRlcm1pbmVkJykgPT09IC0xIHx8IChzLmluZGV4T2YoJ2Rvd24nKSA9PT0gLTEgJiYgcy5pbmRleE9mKCd1cCcpID09PSAtMSkpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0aWYoIW9iai5zdGF0ZS5sb2FkZWQgJiYgb2JqLm9yaWdpbmFsLnN0YXRlLnVuZGV0ZXJtaW5lZCA9PT0gdHJ1ZSkge1xuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdGZvcihpID0gMCwgaiA9IG9iai5jaGlsZHJlbl9kLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRpZigkLmluQXJyYXkob2JqLmNoaWxkcmVuX2RbaV0sIGQpICE9PSAtMSB8fCAoIW1bb2JqLmNoaWxkcmVuX2RbaV1dLnN0YXRlLmxvYWRlZCAmJiBtW29iai5jaGlsZHJlbl9kW2ldXS5vcmlnaW5hbC5zdGF0ZS51bmRldGVybWluZWQpKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9O1xuXHRcdC8qKlxuXHRcdCAqIGRpc2FibGUgYSBub2RlJ3MgY2hlY2tib3hcblx0XHQgKiBAbmFtZSBkaXNhYmxlX2NoZWNrYm94KG9iailcblx0XHQgKiBAcGFyYW0ge21peGVkfSBvYmogYW4gYXJyYXkgY2FuIGJlIHVzZWQgdG9vXG5cdFx0ICogQHRyaWdnZXIgZGlzYWJsZV9jaGVja2JveC5qc3RyZWVcblx0XHQgKiBAcGx1Z2luIGNoZWNrYm94XG5cdFx0ICovXG5cdFx0dGhpcy5kaXNhYmxlX2NoZWNrYm94ID0gZnVuY3Rpb24gKG9iaikge1xuXHRcdFx0dmFyIHQxLCB0MiwgZG9tO1xuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkob2JqKSkge1xuXHRcdFx0XHRvYmogPSBvYmouc2xpY2UoKTtcblx0XHRcdFx0Zm9yKHQxID0gMCwgdDIgPSBvYmoubGVuZ3RoOyB0MSA8IHQyOyB0MSsrKSB7XG5cdFx0XHRcdFx0dGhpcy5kaXNhYmxlX2NoZWNrYm94KG9ialt0MV0pO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaiB8fCBvYmouaWQgPT09ICQuanN0cmVlLnJvb3QpIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0ZG9tID0gdGhpcy5nZXRfbm9kZShvYmosIHRydWUpO1xuXHRcdFx0aWYoIW9iai5zdGF0ZS5jaGVja2JveF9kaXNhYmxlZCkge1xuXHRcdFx0XHRvYmouc3RhdGUuY2hlY2tib3hfZGlzYWJsZWQgPSB0cnVlO1xuXHRcdFx0XHRpZihkb20gJiYgZG9tLmxlbmd0aCkge1xuXHRcdFx0XHRcdGRvbS5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS5jaGlsZHJlbignLmpzdHJlZS1jaGVja2JveCcpLmFkZENsYXNzKCdqc3RyZWUtY2hlY2tib3gtZGlzYWJsZWQnKTtcblx0XHRcdFx0fVxuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYW4gbm9kZSdzIGNoZWNrYm94IGlzIGRpc2FibGVkXG5cdFx0XHRcdCAqIEBldmVudFxuXHRcdFx0XHQgKiBAbmFtZSBkaXNhYmxlX2NoZWNrYm94LmpzdHJlZVxuXHRcdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZVxuXHRcdFx0XHQgKiBAcGx1Z2luIGNoZWNrYm94XG5cdFx0XHRcdCAqL1xuXHRcdFx0XHR0aGlzLnRyaWdnZXIoJ2Rpc2FibGVfY2hlY2tib3gnLCB7ICdub2RlJyA6IG9iaiB9KTtcblx0XHRcdH1cblx0XHR9O1xuXHRcdC8qKlxuXHRcdCAqIGVuYWJsZSBhIG5vZGUncyBjaGVja2JveFxuXHRcdCAqIEBuYW1lIGVuYWJsZV9jaGVja2JveChvYmopXG5cdFx0ICogQHBhcmFtIHttaXhlZH0gb2JqIGFuIGFycmF5IGNhbiBiZSB1c2VkIHRvb1xuXHRcdCAqIEB0cmlnZ2VyIGVuYWJsZV9jaGVja2JveC5qc3RyZWVcblx0XHQgKiBAcGx1Z2luIGNoZWNrYm94XG5cdFx0ICovXG5cdFx0dGhpcy5lbmFibGVfY2hlY2tib3ggPSBmdW5jdGlvbiAob2JqKSB7XG5cdFx0XHR2YXIgdDEsIHQyLCBkb207XG5cdFx0XHRpZigkLnZha2F0YS5pc19hcnJheShvYmopKSB7XG5cdFx0XHRcdG9iaiA9IG9iai5zbGljZSgpO1xuXHRcdFx0XHRmb3IodDEgPSAwLCB0MiA9IG9iai5sZW5ndGg7IHQxIDwgdDI7IHQxKyspIHtcblx0XHRcdFx0XHR0aGlzLmVuYWJsZV9jaGVja2JveChvYmpbdDFdKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdGlmKCFvYmogfHwgb2JqLmlkID09PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdGRvbSA9IHRoaXMuZ2V0X25vZGUob2JqLCB0cnVlKTtcblx0XHRcdGlmKG9iai5zdGF0ZS5jaGVja2JveF9kaXNhYmxlZCkge1xuXHRcdFx0XHRvYmouc3RhdGUuY2hlY2tib3hfZGlzYWJsZWQgPSBmYWxzZTtcblx0XHRcdFx0aWYoZG9tICYmIGRvbS5sZW5ndGgpIHtcblx0XHRcdFx0XHRkb20uY2hpbGRyZW4oJy5qc3RyZWUtYW5jaG9yJykuY2hpbGRyZW4oJy5qc3RyZWUtY2hlY2tib3gnKS5yZW1vdmVDbGFzcygnanN0cmVlLWNoZWNrYm94LWRpc2FibGVkJyk7XG5cdFx0XHRcdH1cblx0XHRcdFx0LyoqXG5cdFx0XHRcdCAqIHRyaWdnZXJlZCB3aGVuIGFuIG5vZGUncyBjaGVja2JveCBpcyBlbmFibGVkXG5cdFx0XHRcdCAqIEBldmVudFxuXHRcdFx0XHQgKiBAbmFtZSBlbmFibGVfY2hlY2tib3guanN0cmVlXG5cdFx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBub2RlXG5cdFx0XHRcdCAqIEBwbHVnaW4gY2hlY2tib3hcblx0XHRcdFx0ICovXG5cdFx0XHRcdHRoaXMudHJpZ2dlcignZW5hYmxlX2NoZWNrYm94JywgeyAnbm9kZScgOiBvYmogfSk7XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdHRoaXMuYWN0aXZhdGVfbm9kZSA9IGZ1bmN0aW9uIChvYmosIGUpIHtcblx0XHRcdGlmKCQoZS50YXJnZXQpLmhhc0NsYXNzKCdqc3RyZWUtY2hlY2tib3gtZGlzYWJsZWQnKSkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24gJiYgKHRoaXMuc2V0dGluZ3MuY2hlY2tib3gud2hvbGVfbm9kZSB8fCAkKGUudGFyZ2V0KS5oYXNDbGFzcygnanN0cmVlLWNoZWNrYm94JykpKSB7XG5cdFx0XHRcdGUuY3RybEtleSA9IHRydWU7XG5cdFx0XHR9XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24gfHwgKCF0aGlzLnNldHRpbmdzLmNoZWNrYm94Lndob2xlX25vZGUgJiYgISQoZS50YXJnZXQpLmhhc0NsYXNzKCdqc3RyZWUtY2hlY2tib3gnKSkpIHtcblx0XHRcdFx0cmV0dXJuIHBhcmVudC5hY3RpdmF0ZV9ub2RlLmNhbGwodGhpcywgb2JqLCBlKTtcblx0XHRcdH1cblx0XHRcdGlmKHRoaXMuaXNfZGlzYWJsZWQob2JqKSkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRpZih0aGlzLmlzX2NoZWNrZWQob2JqKSkge1xuXHRcdFx0XHR0aGlzLnVuY2hlY2tfbm9kZShvYmosIGUpO1xuXHRcdFx0fVxuXHRcdFx0ZWxzZSB7XG5cdFx0XHRcdHRoaXMuY2hlY2tfbm9kZShvYmosIGUpO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy50cmlnZ2VyKCdhY3RpdmF0ZV9ub2RlJywgeyAnbm9kZScgOiB0aGlzLmdldF9ub2RlKG9iaikgfSk7XG5cdFx0fTtcblxuXHRcdC8qKlxuXHRcdCAqIENhc2NhZGVzIGNoZWNrZWQgc3RhdGUgdG8gYSBub2RlIGFuZCBhbGwgaXRzIGRlc2NlbmRhbnRzLiBUaGlzIGZ1bmN0aW9uIGRvZXMgTk9UIGFmZmVjdCBoaWRkZW4gYW5kIGRpc2FibGVkIG5vZGVzIChvciB0aGVpciBkZXNjZW5kYW50cykuXG5cdFx0ICogSG93ZXZlciBpZiB0aGVzZSB1bmFmZmVjdGVkIG5vZGVzIGFyZSBhbHJlYWR5IHNlbGVjdGVkIHRoZWlyIGlkcyB3aWxsIGJlIGluY2x1ZGVkIGluIHRoZSByZXR1cm5lZCBhcnJheS5cblx0XHQgKiBAcHJpdmF0ZVxuXHRcdCAqIEBuYW1lIF9jYXNjYWRlX25ld19jaGVja2VkX3N0YXRlKGlkLCBjaGVja2VkU3RhdGUpXG5cdFx0ICogQHBhcmFtIHtzdHJpbmd9IGlkIHRoZSBub2RlIElEXG5cdFx0ICogQHBhcmFtIHtib29sfSBjaGVja2VkU3RhdGUgc2hvdWxkIHRoZSBub2RlcyBiZSBjaGVja2VkIG9yIG5vdFxuXHRcdCAqIEByZXR1cm5zIHtBcnJheX0gQXJyYXkgb2YgYWxsIG5vZGUgaWQncyAoaW4gdGhpcyB0cmVlIGJyYW5jaCkgdGhhdCBhcmUgY2hlY2tlZC5cblx0XHQgKi9cblx0XHR0aGlzLl9jYXNjYWRlX25ld19jaGVja2VkX3N0YXRlID0gZnVuY3Rpb24gKGlkLCBjaGVja2VkU3RhdGUpIHtcblx0XHRcdHZhciBzZWxmID0gdGhpcztcblx0XHRcdHZhciB0ID0gdGhpcy5zZXR0aW5ncy5jaGVja2JveC50aWVfc2VsZWN0aW9uO1xuXHRcdFx0dmFyIG5vZGUgPSB0aGlzLl9tb2RlbC5kYXRhW2lkXTtcblx0XHRcdHZhciBzZWxlY3RlZE5vZGVJZHMgPSBbXTtcblx0XHRcdHZhciBzZWxlY3RlZENoaWxkcmVuSWRzID0gW10sIGksIGosIHNlbGVjdGVkQ2hpbGRJZHM7XG5cblx0XHRcdGlmIChcblx0XHRcdFx0KHRoaXMuc2V0dGluZ3MuY2hlY2tib3guY2FzY2FkZV90b19kaXNhYmxlZCB8fCAhbm9kZS5zdGF0ZS5kaXNhYmxlZCkgJiZcblx0XHRcdFx0KHRoaXMuc2V0dGluZ3MuY2hlY2tib3guY2FzY2FkZV90b19oaWRkZW4gfHwgIW5vZGUuc3RhdGUuaGlkZGVuKVxuXHRcdFx0KSB7XG5cdFx0XHRcdC8vRmlyc3QgdHJ5IGFuZCBjaGVjay91bmNoZWNrIHRoZSBjaGlsZHJlblxuXHRcdFx0XHRpZiAobm9kZS5jaGlsZHJlbikge1xuXHRcdFx0XHRcdGZvciAoaSA9IDAsIGogPSBub2RlLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdFx0dmFyIGNoaWxkSWQgPSBub2RlLmNoaWxkcmVuW2ldO1xuXHRcdFx0XHRcdFx0c2VsZWN0ZWRDaGlsZElkcyA9IHNlbGYuX2Nhc2NhZGVfbmV3X2NoZWNrZWRfc3RhdGUoY2hpbGRJZCwgY2hlY2tlZFN0YXRlKTtcblx0XHRcdFx0XHRcdHNlbGVjdGVkTm9kZUlkcyA9IHNlbGVjdGVkTm9kZUlkcy5jb25jYXQoc2VsZWN0ZWRDaGlsZElkcyk7XG5cdFx0XHRcdFx0XHRpZiAoc2VsZWN0ZWRDaGlsZElkcy5pbmRleE9mKGNoaWxkSWQpID4gLTEpIHtcblx0XHRcdFx0XHRcdFx0c2VsZWN0ZWRDaGlsZHJlbklkcy5wdXNoKGNoaWxkSWQpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHZhciBkb20gPSBzZWxmLmdldF9ub2RlKG5vZGUsIHRydWUpO1xuXG5cdFx0XHRcdC8vQSBub2RlJ3Mgc3RhdGUgaXMgdW5kZXRlcm1pbmVkIGlmIHNvbWUgYnV0IG5vdCBhbGwgb2YgaXQncyBjaGlsZHJlbiBhcmUgY2hlY2tlZC9zZWxlY3RlZCAuXG5cdFx0XHRcdHZhciB1bmRldGVybWluZWQgPSBzZWxlY3RlZENoaWxkcmVuSWRzLmxlbmd0aCA+IDAgJiYgc2VsZWN0ZWRDaGlsZHJlbklkcy5sZW5ndGggPCBub2RlLmNoaWxkcmVuLmxlbmd0aDtcblxuXHRcdFx0XHRpZihub2RlLm9yaWdpbmFsICYmIG5vZGUub3JpZ2luYWwuc3RhdGUgJiYgbm9kZS5vcmlnaW5hbC5zdGF0ZS51bmRldGVybWluZWQpIHtcblx0XHRcdFx0XHRub2RlLm9yaWdpbmFsLnN0YXRlLnVuZGV0ZXJtaW5lZCA9IHVuZGV0ZXJtaW5lZDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vSWYgYSBub2RlIGlzIHVuZGV0ZXJtaW5lZCB0aGVuIHJlbW92ZSBzZWxlY3RlZCBjbGFzc1xuXHRcdFx0XHRpZiAodW5kZXRlcm1pbmVkKSB7XG5cdFx0XHRcdFx0bm9kZS5zdGF0ZVsgdCA/ICdzZWxlY3RlZCcgOiAnY2hlY2tlZCcgXSA9IGZhbHNlO1xuXHRcdFx0XHRcdGRvbS5hdHRyKCdhcmlhLXNlbGVjdGVkJywgZmFsc2UpLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLnJlbW92ZUNsYXNzKHQgPyAnanN0cmVlLWNsaWNrZWQnIDogJ2pzdHJlZS1jaGVja2VkJyk7XG5cdFx0XHRcdH1cblx0XHRcdFx0Ly9PdGhlcndpc2UsIGlmIHRoZSBjaGVja2VkU3RhdGUgPT09IHRydWUgKGkuZS4gdGhlIG5vZGUgaXMgYmVpbmcgY2hlY2tlZCBub3cpIGFuZCBhbGwgb2YgdGhlIG5vZGUncyBjaGlsZHJlbiBhcmUgY2hlY2tlZCAoaWYgaXQgaGFzIGFueSBjaGlsZHJlbiksXG5cdFx0XHRcdC8vY2hlY2sgdGhlIG5vZGUgYW5kIHN0eWxlIGl0IGNvcnJlY3RseS5cblx0XHRcdFx0ZWxzZSBpZiAoY2hlY2tlZFN0YXRlICYmIHNlbGVjdGVkQ2hpbGRyZW5JZHMubGVuZ3RoID09PSBub2RlLmNoaWxkcmVuLmxlbmd0aCkge1xuXHRcdFx0XHRcdG5vZGUuc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF0gPSBjaGVja2VkU3RhdGU7XG5cdFx0XHRcdFx0c2VsZWN0ZWROb2RlSWRzLnB1c2gobm9kZS5pZCk7XG5cblx0XHRcdFx0XHRkb20uYXR0cignYXJpYS1zZWxlY3RlZCcsIHRydWUpLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLmFkZENsYXNzKHQgPyAnanN0cmVlLWNsaWNrZWQnIDogJ2pzdHJlZS1jaGVja2VkJyk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0bm9kZS5zdGF0ZVsgdCA/ICdzZWxlY3RlZCcgOiAnY2hlY2tlZCcgXSA9IGZhbHNlO1xuXHRcdFx0XHRcdGRvbS5hdHRyKCdhcmlhLXNlbGVjdGVkJywgZmFsc2UpLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpLnJlbW92ZUNsYXNzKHQgPyAnanN0cmVlLWNsaWNrZWQnIDogJ2pzdHJlZS1jaGVja2VkJyk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGVsc2Uge1xuXHRcdFx0XHRzZWxlY3RlZENoaWxkSWRzID0gdGhpcy5nZXRfY2hlY2tlZF9kZXNjZW5kYW50cyhpZCk7XG5cblx0XHRcdFx0aWYgKG5vZGUuc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF0pIHtcblx0XHRcdFx0XHRzZWxlY3RlZENoaWxkSWRzLnB1c2gobm9kZS5pZCk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzZWxlY3RlZE5vZGVJZHMgPSBzZWxlY3RlZE5vZGVJZHMuY29uY2F0KHNlbGVjdGVkQ2hpbGRJZHMpO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gc2VsZWN0ZWROb2RlSWRzO1xuXHRcdH07XG5cblx0XHQvKipcblx0XHQgKiBHZXRzIGlkcyBvZiBub2RlcyBzZWxlY3RlZCBpbiBicmFuY2ggKG9mIHRyZWUpIHNwZWNpZmllZCBieSBpZCAoZG9lcyBub3QgaW5jbHVkZSB0aGUgbm9kZSBzcGVjaWZpZWQgYnkgaWQpXG5cdFx0ICogQG5hbWUgZ2V0X2NoZWNrZWRfZGVzY2VuZGFudHMob2JqKVxuXHRcdCAqIEBwYXJhbSB7c3RyaW5nfSBpZCB0aGUgbm9kZSBJRFxuXHRcdCAqIEByZXR1cm4ge0FycmF5fSBhcnJheSBvZiBJRHNcblx0XHQgKiBAcGx1Z2luIGNoZWNrYm94XG5cdFx0ICovXG5cdFx0dGhpcy5nZXRfY2hlY2tlZF9kZXNjZW5kYW50cyA9IGZ1bmN0aW9uIChpZCkge1xuXHRcdFx0dmFyIHNlbGYgPSB0aGlzO1xuXHRcdFx0dmFyIHQgPSBzZWxmLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb247XG5cdFx0XHR2YXIgbm9kZSA9IHNlbGYuX21vZGVsLmRhdGFbaWRdO1xuXG5cdFx0XHRyZXR1cm4gJC52YWthdGEuYXJyYXlfZmlsdGVyKG5vZGUuY2hpbGRyZW5fZCwgZnVuY3Rpb24oX2lkKSB7XG5cdFx0XHRcdHJldHVybiBzZWxmLl9tb2RlbC5kYXRhW19pZF0uc3RhdGVbIHQgPyAnc2VsZWN0ZWQnIDogJ2NoZWNrZWQnIF07XG5cdFx0XHR9KTtcblx0XHR9O1xuXG5cdFx0LyoqXG5cdFx0ICogY2hlY2sgYSBub2RlIChvbmx5IGlmIHRpZV9zZWxlY3Rpb24gaW4gY2hlY2tib3ggc2V0dGluZ3MgaXMgZmFsc2UsIG90aGVyd2lzZSBzZWxlY3Rfbm9kZSB3aWxsIGJlIGNhbGxlZCBpbnRlcm5hbGx5KVxuXHRcdCAqIEBuYW1lIGNoZWNrX25vZGUob2JqKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9iaiBhbiBhcnJheSBjYW4gYmUgdXNlZCB0byBjaGVjayBtdWx0aXBsZSBub2Rlc1xuXHRcdCAqIEB0cmlnZ2VyIGNoZWNrX25vZGUuanN0cmVlXG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdHRoaXMuY2hlY2tfbm9kZSA9IGZ1bmN0aW9uIChvYmosIGUpIHtcblx0XHRcdGlmKHRoaXMuc2V0dGluZ3MuY2hlY2tib3gudGllX3NlbGVjdGlvbikgeyByZXR1cm4gdGhpcy5zZWxlY3Rfbm9kZShvYmosIGZhbHNlLCB0cnVlLCBlKTsgfVxuXHRcdFx0dmFyIGRvbSwgdDEsIHQyLCB0aDtcblx0XHRcdGlmKCQudmFrYXRhLmlzX2FycmF5KG9iaikpIHtcblx0XHRcdFx0b2JqID0gb2JqLnNsaWNlKCk7XG5cdFx0XHRcdGZvcih0MSA9IDAsIHQyID0gb2JqLmxlbmd0aDsgdDEgPCB0MjsgdDErKykge1xuXHRcdFx0XHRcdHRoaXMuY2hlY2tfbm9kZShvYmpbdDFdLCBlKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdG9iaiA9IHRoaXMuZ2V0X25vZGUob2JqKTtcblx0XHRcdGlmKCFvYmogfHwgb2JqLmlkID09PSAkLmpzdHJlZS5yb290KSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdGRvbSA9IHRoaXMuZ2V0X25vZGUob2JqLCB0cnVlKTtcblx0XHRcdGlmKCFvYmouc3RhdGUuY2hlY2tlZCkge1xuXHRcdFx0XHRvYmouc3RhdGUuY2hlY2tlZCA9IHRydWU7XG5cdFx0XHRcdHRoaXMuX2RhdGEuY2hlY2tib3guc2VsZWN0ZWQucHVzaChvYmouaWQpO1xuXHRcdFx0XHRpZihkb20gJiYgZG9tLmxlbmd0aCkge1xuXHRcdFx0XHRcdGRvbS5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS5hZGRDbGFzcygnanN0cmVlLWNoZWNrZWQnKTtcblx0XHRcdFx0fVxuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYW4gbm9kZSBpcyBjaGVja2VkIChvbmx5IGlmIHRpZV9zZWxlY3Rpb24gaW4gY2hlY2tib3ggc2V0dGluZ3MgaXMgZmFsc2UpXG5cdFx0XHRcdCAqIEBldmVudFxuXHRcdFx0XHQgKiBAbmFtZSBjaGVja19ub2RlLmpzdHJlZVxuXHRcdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZVxuXHRcdFx0XHQgKiBAcGFyYW0ge0FycmF5fSBzZWxlY3RlZCB0aGUgY3VycmVudCBzZWxlY3Rpb25cblx0XHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IGV2ZW50IHRoZSBldmVudCAoaWYgYW55KSB0aGF0IHRyaWdnZXJlZCB0aGlzIGNoZWNrX25vZGVcblx0XHRcdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdFx0XHQgKi9cblx0XHRcdFx0dGhpcy50cmlnZ2VyKCdjaGVja19ub2RlJywgeyAnbm9kZScgOiBvYmosICdzZWxlY3RlZCcgOiB0aGlzLl9kYXRhLmNoZWNrYm94LnNlbGVjdGVkLCAnZXZlbnQnIDogZSB9KTtcblx0XHRcdH1cblx0XHR9O1xuXHRcdC8qKlxuXHRcdCAqIHVuY2hlY2sgYSBub2RlIChvbmx5IGlmIHRpZV9zZWxlY3Rpb24gaW4gY2hlY2tib3ggc2V0dGluZ3MgaXMgZmFsc2UsIG90aGVyd2lzZSBkZXNlbGVjdF9ub2RlIHdpbGwgYmUgY2FsbGVkIGludGVybmFsbHkpXG5cdFx0ICogQG5hbWUgdW5jaGVja19ub2RlKG9iailcblx0XHQgKiBAcGFyYW0ge21peGVkfSBvYmogYW4gYXJyYXkgY2FuIGJlIHVzZWQgdG8gdW5jaGVjayBtdWx0aXBsZSBub2Rlc1xuXHRcdCAqIEB0cmlnZ2VyIHVuY2hlY2tfbm9kZS5qc3RyZWVcblx0XHQgKiBAcGx1Z2luIGNoZWNrYm94XG5cdFx0ICovXG5cdFx0dGhpcy51bmNoZWNrX25vZGUgPSBmdW5jdGlvbiAob2JqLCBlKSB7XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24pIHsgcmV0dXJuIHRoaXMuZGVzZWxlY3Rfbm9kZShvYmosIGZhbHNlLCBlKTsgfVxuXHRcdFx0dmFyIHQxLCB0MiwgZG9tO1xuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkob2JqKSkge1xuXHRcdFx0XHRvYmogPSBvYmouc2xpY2UoKTtcblx0XHRcdFx0Zm9yKHQxID0gMCwgdDIgPSBvYmoubGVuZ3RoOyB0MSA8IHQyOyB0MSsrKSB7XG5cdFx0XHRcdFx0dGhpcy51bmNoZWNrX25vZGUob2JqW3QxXSwgZSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqIHx8IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRkb20gPSB0aGlzLmdldF9ub2RlKG9iaiwgdHJ1ZSk7XG5cdFx0XHRpZihvYmouc3RhdGUuY2hlY2tlZCkge1xuXHRcdFx0XHRvYmouc3RhdGUuY2hlY2tlZCA9IGZhbHNlO1xuXHRcdFx0XHR0aGlzLl9kYXRhLmNoZWNrYm94LnNlbGVjdGVkID0gJC52YWthdGEuYXJyYXlfcmVtb3ZlX2l0ZW0odGhpcy5fZGF0YS5jaGVja2JveC5zZWxlY3RlZCwgb2JqLmlkKTtcblx0XHRcdFx0aWYoZG9tLmxlbmd0aCkge1xuXHRcdFx0XHRcdGRvbS5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS5yZW1vdmVDbGFzcygnanN0cmVlLWNoZWNrZWQnKTtcblx0XHRcdFx0fVxuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYW4gbm9kZSBpcyB1bmNoZWNrZWQgKG9ubHkgaWYgdGllX3NlbGVjdGlvbiBpbiBjaGVja2JveCBzZXR0aW5ncyBpcyBmYWxzZSlcblx0XHRcdFx0ICogQGV2ZW50XG5cdFx0XHRcdCAqIEBuYW1lIHVuY2hlY2tfbm9kZS5qc3RyZWVcblx0XHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IG5vZGVcblx0XHRcdFx0ICogQHBhcmFtIHtBcnJheX0gc2VsZWN0ZWQgdGhlIGN1cnJlbnQgc2VsZWN0aW9uXG5cdFx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBldmVudCB0aGUgZXZlbnQgKGlmIGFueSkgdGhhdCB0cmlnZ2VyZWQgdGhpcyB1bmNoZWNrX25vZGVcblx0XHRcdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdFx0XHQgKi9cblx0XHRcdFx0dGhpcy50cmlnZ2VyKCd1bmNoZWNrX25vZGUnLCB7ICdub2RlJyA6IG9iaiwgJ3NlbGVjdGVkJyA6IHRoaXMuX2RhdGEuY2hlY2tib3guc2VsZWN0ZWQsICdldmVudCcgOiBlIH0pO1xuXHRcdFx0fVxuXHRcdH07XG5cdFx0XG5cdFx0LyoqXG5cdFx0ICogY2hlY2tzIGFsbCBub2RlcyBpbiB0aGUgdHJlZSAob25seSBpZiB0aWVfc2VsZWN0aW9uIGluIGNoZWNrYm94IHNldHRpbmdzIGlzIGZhbHNlLCBvdGhlcndpc2Ugc2VsZWN0X2FsbCB3aWxsIGJlIGNhbGxlZCBpbnRlcm5hbGx5KVxuXHRcdCAqIEBuYW1lIGNoZWNrX2FsbCgpXG5cdFx0ICogQHRyaWdnZXIgY2hlY2tfYWxsLmpzdHJlZSwgY2hhbmdlZC5qc3RyZWVcblx0XHQgKiBAcGx1Z2luIGNoZWNrYm94XG5cdFx0ICovXG5cdFx0dGhpcy5jaGVja19hbGwgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24pIHsgcmV0dXJuIHRoaXMuc2VsZWN0X2FsbCgpOyB9XG5cdFx0XHR2YXIgdG1wID0gdGhpcy5fZGF0YS5jaGVja2JveC5zZWxlY3RlZC5jb25jYXQoW10pLCBpLCBqO1xuXHRcdFx0dGhpcy5fZGF0YS5jaGVja2JveC5zZWxlY3RlZCA9IHRoaXMuX21vZGVsLmRhdGFbJC5qc3RyZWUucm9vdF0uY2hpbGRyZW5fZC5jb25jYXQoKTtcblx0XHRcdGZvcihpID0gMCwgaiA9IHRoaXMuX2RhdGEuY2hlY2tib3guc2VsZWN0ZWQubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdGlmKHRoaXMuX21vZGVsLmRhdGFbdGhpcy5fZGF0YS5jaGVja2JveC5zZWxlY3RlZFtpXV0pIHtcblx0XHRcdFx0XHR0aGlzLl9tb2RlbC5kYXRhW3RoaXMuX2RhdGEuY2hlY2tib3guc2VsZWN0ZWRbaV1dLnN0YXRlLmNoZWNrZWQgPSB0cnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHR0aGlzLnJlZHJhdyh0cnVlKTtcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYWxsIG5vZGVzIGFyZSBjaGVja2VkIChvbmx5IGlmIHRpZV9zZWxlY3Rpb24gaW4gY2hlY2tib3ggc2V0dGluZ3MgaXMgZmFsc2UpXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIGNoZWNrX2FsbC5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7QXJyYXl9IHNlbGVjdGVkIHRoZSBjdXJyZW50IHNlbGVjdGlvblxuXHRcdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ2NoZWNrX2FsbCcsIHsgJ3NlbGVjdGVkJyA6IHRoaXMuX2RhdGEuY2hlY2tib3guc2VsZWN0ZWQgfSk7XG5cdFx0fTtcblx0XHQvKipcblx0XHQgKiB1bmNoZWNrIGFsbCBjaGVja2VkIG5vZGVzIChvbmx5IGlmIHRpZV9zZWxlY3Rpb24gaW4gY2hlY2tib3ggc2V0dGluZ3MgaXMgZmFsc2UsIG90aGVyd2lzZSBkZXNlbGVjdF9hbGwgd2lsbCBiZSBjYWxsZWQgaW50ZXJuYWxseSlcblx0XHQgKiBAbmFtZSB1bmNoZWNrX2FsbCgpXG5cdFx0ICogQHRyaWdnZXIgdW5jaGVja19hbGwuanN0cmVlXG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdHRoaXMudW5jaGVja19hbGwgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24pIHsgcmV0dXJuIHRoaXMuZGVzZWxlY3RfYWxsKCk7IH1cblx0XHRcdHZhciB0bXAgPSB0aGlzLl9kYXRhLmNoZWNrYm94LnNlbGVjdGVkLmNvbmNhdChbXSksIGksIGo7XG5cdFx0XHRmb3IoaSA9IDAsIGogPSB0aGlzLl9kYXRhLmNoZWNrYm94LnNlbGVjdGVkLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRpZih0aGlzLl9tb2RlbC5kYXRhW3RoaXMuX2RhdGEuY2hlY2tib3guc2VsZWN0ZWRbaV1dKSB7XG5cdFx0XHRcdFx0dGhpcy5fbW9kZWwuZGF0YVt0aGlzLl9kYXRhLmNoZWNrYm94LnNlbGVjdGVkW2ldXS5zdGF0ZS5jaGVja2VkID0gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHRoaXMuX2RhdGEuY2hlY2tib3guc2VsZWN0ZWQgPSBbXTtcblx0XHRcdHRoaXMuZWxlbWVudC5maW5kKCcuanN0cmVlLWNoZWNrZWQnKS5yZW1vdmVDbGFzcygnanN0cmVlLWNoZWNrZWQnKTtcblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gYWxsIG5vZGVzIGFyZSB1bmNoZWNrZWQgKG9ubHkgaWYgdGllX3NlbGVjdGlvbiBpbiBjaGVja2JveCBzZXR0aW5ncyBpcyBmYWxzZSlcblx0XHRcdCAqIEBldmVudFxuXHRcdFx0ICogQG5hbWUgdW5jaGVja19hbGwuanN0cmVlXG5cdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gbm9kZSB0aGUgcHJldmlvdXMgc2VsZWN0aW9uXG5cdFx0XHQgKiBAcGFyYW0ge0FycmF5fSBzZWxlY3RlZCB0aGUgY3VycmVudCBzZWxlY3Rpb25cblx0XHRcdCAqIEBwbHVnaW4gY2hlY2tib3hcblx0XHRcdCAqL1xuXHRcdFx0dGhpcy50cmlnZ2VyKCd1bmNoZWNrX2FsbCcsIHsgJ3NlbGVjdGVkJyA6IHRoaXMuX2RhdGEuY2hlY2tib3guc2VsZWN0ZWQsICdub2RlJyA6IHRtcCB9KTtcblx0XHR9O1xuXHRcdC8qKlxuXHRcdCAqIGNoZWNrcyBpZiBhIG5vZGUgaXMgY2hlY2tlZCAoaWYgdGllX3NlbGVjdGlvbiBpcyBvbiBpbiB0aGUgc2V0dGluZ3MgdGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiB0aGUgc2FtZSBhcyBpc19zZWxlY3RlZClcblx0XHQgKiBAbmFtZSBpc19jaGVja2VkKG9iailcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gIG9ialxuXHRcdCAqIEByZXR1cm4ge0Jvb2xlYW59XG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdHRoaXMuaXNfY2hlY2tlZCA9IGZ1bmN0aW9uIChvYmopIHtcblx0XHRcdGlmKHRoaXMuc2V0dGluZ3MuY2hlY2tib3gudGllX3NlbGVjdGlvbikgeyByZXR1cm4gdGhpcy5pc19zZWxlY3RlZChvYmopOyB9XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqIHx8IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdHJldHVybiBvYmouc3RhdGUuY2hlY2tlZDtcblx0XHR9O1xuXHRcdC8qKlxuXHRcdCAqIGdldCBhbiBhcnJheSBvZiBhbGwgY2hlY2tlZCBub2RlcyAoaWYgdGllX3NlbGVjdGlvbiBpcyBvbiBpbiB0aGUgc2V0dGluZ3MgdGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiB0aGUgc2FtZSBhcyBnZXRfc2VsZWN0ZWQpXG5cdFx0ICogQG5hbWUgZ2V0X2NoZWNrZWQoW2Z1bGxdKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSAgZnVsbCBpZiBzZXQgdG8gYHRydWVgIHRoZSByZXR1cm5lZCBhcnJheSB3aWxsIGNvbnNpc3Qgb2YgdGhlIGZ1bGwgbm9kZSBvYmplY3RzLCBvdGhlcndpc2UgLSBvbmx5IElEcyB3aWxsIGJlIHJldHVybmVkXG5cdFx0ICogQHJldHVybiB7QXJyYXl9XG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdHRoaXMuZ2V0X2NoZWNrZWQgPSBmdW5jdGlvbiAoZnVsbCkge1xuXHRcdFx0aWYodGhpcy5zZXR0aW5ncy5jaGVja2JveC50aWVfc2VsZWN0aW9uKSB7IHJldHVybiB0aGlzLmdldF9zZWxlY3RlZChmdWxsKTsgfVxuXHRcdFx0cmV0dXJuIGZ1bGwgPyAkLm1hcCh0aGlzLl9kYXRhLmNoZWNrYm94LnNlbGVjdGVkLCBmdW5jdGlvbiAoaSkgeyByZXR1cm4gdGhpcy5nZXRfbm9kZShpKTsgfS5iaW5kKHRoaXMpKSA6IHRoaXMuX2RhdGEuY2hlY2tib3guc2VsZWN0ZWQuc2xpY2UoKTtcblx0XHR9O1xuXHRcdC8qKlxuXHRcdCAqIGdldCBhbiBhcnJheSBvZiBhbGwgdG9wIGxldmVsIGNoZWNrZWQgbm9kZXMgKGlnbm9yaW5nIGNoaWxkcmVuIG9mIGNoZWNrZWQgbm9kZXMpIChpZiB0aWVfc2VsZWN0aW9uIGlzIG9uIGluIHRoZSBzZXR0aW5ncyB0aGlzIGZ1bmN0aW9uIHdpbGwgcmV0dXJuIHRoZSBzYW1lIGFzIGdldF90b3Bfc2VsZWN0ZWQpXG5cdFx0ICogQG5hbWUgZ2V0X3RvcF9jaGVja2VkKFtmdWxsXSlcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gIGZ1bGwgaWYgc2V0IHRvIGB0cnVlYCB0aGUgcmV0dXJuZWQgYXJyYXkgd2lsbCBjb25zaXN0IG9mIHRoZSBmdWxsIG5vZGUgb2JqZWN0cywgb3RoZXJ3aXNlIC0gb25seSBJRHMgd2lsbCBiZSByZXR1cm5lZFxuXHRcdCAqIEByZXR1cm4ge0FycmF5fVxuXHRcdCAqIEBwbHVnaW4gY2hlY2tib3hcblx0XHQgKi9cblx0XHR0aGlzLmdldF90b3BfY2hlY2tlZCA9IGZ1bmN0aW9uIChmdWxsKSB7XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24pIHsgcmV0dXJuIHRoaXMuZ2V0X3RvcF9zZWxlY3RlZChmdWxsKTsgfVxuXHRcdFx0dmFyIHRtcCA9IHRoaXMuZ2V0X2NoZWNrZWQodHJ1ZSksXG5cdFx0XHRcdG9iaiA9IHt9LCBpLCBqLCBrLCBsO1xuXHRcdFx0Zm9yKGkgPSAwLCBqID0gdG1wLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRvYmpbdG1wW2ldLmlkXSA9IHRtcFtpXTtcblx0XHRcdH1cblx0XHRcdGZvcihpID0gMCwgaiA9IHRtcC5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0Zm9yKGsgPSAwLCBsID0gdG1wW2ldLmNoaWxkcmVuX2QubGVuZ3RoOyBrIDwgbDsgaysrKSB7XG5cdFx0XHRcdFx0aWYob2JqW3RtcFtpXS5jaGlsZHJlbl9kW2tdXSkge1xuXHRcdFx0XHRcdFx0ZGVsZXRlIG9ialt0bXBbaV0uY2hpbGRyZW5fZFtrXV07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHR0bXAgPSBbXTtcblx0XHRcdGZvcihpIGluIG9iaikge1xuXHRcdFx0XHRpZihvYmouaGFzT3duUHJvcGVydHkoaSkpIHtcblx0XHRcdFx0XHR0bXAucHVzaChpKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGZ1bGwgPyAkLm1hcCh0bXAsIGZ1bmN0aW9uIChpKSB7IHJldHVybiB0aGlzLmdldF9ub2RlKGkpOyB9LmJpbmQodGhpcykpIDogdG1wO1xuXHRcdH07XG5cdFx0LyoqXG5cdFx0ICogZ2V0IGFuIGFycmF5IG9mIGFsbCBib3R0b20gbGV2ZWwgY2hlY2tlZCBub2RlcyAoaWdub3Jpbmcgc2VsZWN0ZWQgcGFyZW50cykgKGlmIHRpZV9zZWxlY3Rpb24gaXMgb24gaW4gdGhlIHNldHRpbmdzIHRoaXMgZnVuY3Rpb24gd2lsbCByZXR1cm4gdGhlIHNhbWUgYXMgZ2V0X2JvdHRvbV9zZWxlY3RlZClcblx0XHQgKiBAbmFtZSBnZXRfYm90dG9tX2NoZWNrZWQoW2Z1bGxdKVxuXHRcdCAqIEBwYXJhbSAge21peGVkfSAgZnVsbCBpZiBzZXQgdG8gYHRydWVgIHRoZSByZXR1cm5lZCBhcnJheSB3aWxsIGNvbnNpc3Qgb2YgdGhlIGZ1bGwgbm9kZSBvYmplY3RzLCBvdGhlcndpc2UgLSBvbmx5IElEcyB3aWxsIGJlIHJldHVybmVkXG5cdFx0ICogQHJldHVybiB7QXJyYXl9XG5cdFx0ICogQHBsdWdpbiBjaGVja2JveFxuXHRcdCAqL1xuXHRcdHRoaXMuZ2V0X2JvdHRvbV9jaGVja2VkID0gZnVuY3Rpb24gKGZ1bGwpIHtcblx0XHRcdGlmKHRoaXMuc2V0dGluZ3MuY2hlY2tib3gudGllX3NlbGVjdGlvbikgeyByZXR1cm4gdGhpcy5nZXRfYm90dG9tX3NlbGVjdGVkKGZ1bGwpOyB9XG5cdFx0XHR2YXIgdG1wID0gdGhpcy5nZXRfY2hlY2tlZCh0cnVlKSxcblx0XHRcdFx0b2JqID0gW10sIGksIGo7XG5cdFx0XHRmb3IoaSA9IDAsIGogPSB0bXAubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdGlmKCF0bXBbaV0uY2hpbGRyZW4ubGVuZ3RoKSB7XG5cdFx0XHRcdFx0b2JqLnB1c2godG1wW2ldLmlkKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGZ1bGwgPyAkLm1hcChvYmosIGZ1bmN0aW9uIChpKSB7IHJldHVybiB0aGlzLmdldF9ub2RlKGkpOyB9LmJpbmQodGhpcykpIDogb2JqO1xuXHRcdH07XG5cdFx0dGhpcy5sb2FkX25vZGUgPSBmdW5jdGlvbiAob2JqLCBjYWxsYmFjaykge1xuXHRcdFx0dmFyIGssIGwsIGksIGosIGMsIHRtcDtcblx0XHRcdGlmKCEkLnZha2F0YS5pc19hcnJheShvYmopICYmICF0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24pIHtcblx0XHRcdFx0dG1wID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0XHRpZih0bXAgJiYgdG1wLnN0YXRlLmxvYWRlZCkge1xuXHRcdFx0XHRcdGZvcihrID0gMCwgbCA9IHRtcC5jaGlsZHJlbl9kLmxlbmd0aDsgayA8IGw7IGsrKykge1xuXHRcdFx0XHRcdFx0aWYodGhpcy5fbW9kZWwuZGF0YVt0bXAuY2hpbGRyZW5fZFtrXV0uc3RhdGUuY2hlY2tlZCkge1xuXHRcdFx0XHRcdFx0XHRjID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0dGhpcy5fZGF0YS5jaGVja2JveC5zZWxlY3RlZCA9ICQudmFrYXRhLmFycmF5X3JlbW92ZV9pdGVtKHRoaXMuX2RhdGEuY2hlY2tib3guc2VsZWN0ZWQsIHRtcC5jaGlsZHJlbl9kW2tdKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiBwYXJlbnQubG9hZF9ub2RlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cdFx0fTtcblx0XHR0aGlzLmdldF9zdGF0ZSA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHZhciBzdGF0ZSA9IHBhcmVudC5nZXRfc3RhdGUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblx0XHRcdGlmKHRoaXMuc2V0dGluZ3MuY2hlY2tib3gudGllX3NlbGVjdGlvbikgeyByZXR1cm4gc3RhdGU7IH1cblx0XHRcdHN0YXRlLmNoZWNrYm94ID0gdGhpcy5fZGF0YS5jaGVja2JveC5zZWxlY3RlZC5zbGljZSgpO1xuXHRcdFx0cmV0dXJuIHN0YXRlO1xuXHRcdH07XG5cdFx0dGhpcy5zZXRfc3RhdGUgPSBmdW5jdGlvbiAoc3RhdGUsIGNhbGxiYWNrKSB7XG5cdFx0XHR2YXIgcmVzID0gcGFyZW50LnNldF9zdGF0ZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXHRcdFx0aWYocmVzICYmIHN0YXRlLmNoZWNrYm94KSB7XG5cdFx0XHRcdGlmKCF0aGlzLnNldHRpbmdzLmNoZWNrYm94LnRpZV9zZWxlY3Rpb24pIHtcblx0XHRcdFx0XHR0aGlzLnVuY2hlY2tfYWxsKCk7XG5cdFx0XHRcdFx0dmFyIF90aGlzID0gdGhpcztcblx0XHRcdFx0XHQkLmVhY2goc3RhdGUuY2hlY2tib3gsIGZ1bmN0aW9uIChpLCB2KSB7XG5cdFx0XHRcdFx0XHRfdGhpcy5jaGVja19ub2RlKHYpO1xuXHRcdFx0XHRcdH0pO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGRlbGV0ZSBzdGF0ZS5jaGVja2JveDtcblx0XHRcdFx0dGhpcy5zZXRfc3RhdGUoc3RhdGUsIGNhbGxiYWNrKTtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHJlcztcblx0XHR9O1xuXHRcdHRoaXMucmVmcmVzaCA9IGZ1bmN0aW9uIChza2lwX2xvYWRpbmcsIGZvcmdldF9zdGF0ZSkge1xuXHRcdFx0aWYodGhpcy5zZXR0aW5ncy5jaGVja2JveC50aWVfc2VsZWN0aW9uKSB7XG5cdFx0XHRcdHRoaXMuX2RhdGEuY2hlY2tib3guc2VsZWN0ZWQgPSBbXTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBwYXJlbnQucmVmcmVzaC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXHRcdH07XG5cdH07XG5cblx0Ly8gaW5jbHVkZSB0aGUgY2hlY2tib3ggcGx1Z2luIGJ5IGRlZmF1bHRcblx0Ly8gJC5qc3RyZWUuZGVmYXVsdHMucGx1Z2lucy5wdXNoKFwiY2hlY2tib3hcIik7XG5cblxuLyoqXG4gKiAjIyMgQ29uZGl0aW9uYWxzZWxlY3QgcGx1Z2luXG4gKlxuICogVGhpcyBwbHVnaW4gYWxsb3dzIGRlZmluaW5nIGEgY2FsbGJhY2sgdG8gYWxsb3cgb3IgZGVueSBub2RlIHNlbGVjdGlvbiBieSB1c2VyIGlucHV0IChhY3RpdmF0ZSBub2RlIG1ldGhvZCkuXG4gKi9cblxuXHQvKipcblx0ICogYSBjYWxsYmFjayAoZnVuY3Rpb24pIHdoaWNoIGlzIGludm9rZWQgaW4gdGhlIGluc3RhbmNlJ3Mgc2NvcGUgYW5kIHJlY2VpdmVzIHR3byBhcmd1bWVudHMgLSB0aGUgbm9kZSBhbmQgdGhlIGV2ZW50IHRoYXQgdHJpZ2dlcmVkIHRoZSBgYWN0aXZhdGVfbm9kZWAgY2FsbC4gUmV0dXJuaW5nIGZhbHNlIHByZXZlbnRzIHdvcmtpbmcgd2l0aCB0aGUgbm9kZSwgcmV0dXJuaW5nIHRydWUgYWxsb3dzIGludm9raW5nIGFjdGl2YXRlX25vZGUuIERlZmF1bHRzIHRvIHJldHVybmluZyBgdHJ1ZWAuXG5cdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmNoZWNrYm94LnZpc2libGVcblx0ICogQHBsdWdpbiBjaGVja2JveFxuXHQgKi9cblx0JC5qc3RyZWUuZGVmYXVsdHMuY29uZGl0aW9uYWxzZWxlY3QgPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0cnVlOyB9O1xuXHQkLmpzdHJlZS5wbHVnaW5zLmNvbmRpdGlvbmFsc2VsZWN0ID0gZnVuY3Rpb24gKG9wdGlvbnMsIHBhcmVudCkge1xuXHRcdC8vIG93biBmdW5jdGlvblxuXHRcdHRoaXMuYWN0aXZhdGVfbm9kZSA9IGZ1bmN0aW9uIChvYmosIGUpIHtcblx0XHRcdGlmKHRoaXMuc2V0dGluZ3MuY29uZGl0aW9uYWxzZWxlY3QuY2FsbCh0aGlzLCB0aGlzLmdldF9ub2RlKG9iaiksIGUpKSB7XG5cdFx0XHRcdHJldHVybiBwYXJlbnQuYWN0aXZhdGVfbm9kZS5jYWxsKHRoaXMsIG9iaiwgZSk7XG5cdFx0XHR9XG5cdFx0fTtcblx0fTtcblxuXG4vKipcbiAqICMjIyBDb250ZXh0bWVudSBwbHVnaW5cbiAqXG4gKiBTaG93cyBhIGNvbnRleHQgbWVudSB3aGVuIGEgbm9kZSBpcyByaWdodC1jbGlja2VkLlxuICovXG5cblx0LyoqXG5cdCAqIHN0b3JlcyBhbGwgZGVmYXVsdHMgZm9yIHRoZSBjb250ZXh0bWVudSBwbHVnaW5cblx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuY29udGV4dG1lbnVcblx0ICogQHBsdWdpbiBjb250ZXh0bWVudVxuXHQgKi9cblx0JC5qc3RyZWUuZGVmYXVsdHMuY29udGV4dG1lbnUgPSB7XG5cdFx0LyoqXG5cdFx0ICogYSBib29sZWFuIGluZGljYXRpbmcgaWYgdGhlIG5vZGUgc2hvdWxkIGJlIHNlbGVjdGVkIHdoZW4gdGhlIGNvbnRleHQgbWVudSBpcyBpbnZva2VkIG9uIGl0LiBEZWZhdWx0cyB0byBgdHJ1ZWAuXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuY29udGV4dG1lbnUuc2VsZWN0X25vZGVcblx0XHQgKiBAcGx1Z2luIGNvbnRleHRtZW51XG5cdFx0ICovXG5cdFx0c2VsZWN0X25vZGUgOiB0cnVlLFxuXHRcdC8qKlxuXHRcdCAqIGEgYm9vbGVhbiBpbmRpY2F0aW5nIGlmIHRoZSBtZW51IHNob3VsZCBiZSBzaG93biBhbGlnbmVkIHdpdGggdGhlIG5vZGUuIERlZmF1bHRzIHRvIGB0cnVlYCwgb3RoZXJ3aXNlIHRoZSBtb3VzZSBjb29yZGluYXRlcyBhcmUgdXNlZC5cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb250ZXh0bWVudS5zaG93X2F0X25vZGVcblx0XHQgKiBAcGx1Z2luIGNvbnRleHRtZW51XG5cdFx0ICovXG5cdFx0c2hvd19hdF9ub2RlIDogdHJ1ZSxcblx0XHQvKipcblx0XHQgKiBhbiBvYmplY3Qgb2YgYWN0aW9ucywgb3IgYSBmdW5jdGlvbiB0aGF0IGFjY2VwdHMgYSBub2RlIGFuZCBhIGNhbGxiYWNrIGZ1bmN0aW9uIGFuZCBjYWxscyB0aGUgY2FsbGJhY2sgZnVuY3Rpb24gd2l0aCBhbiBvYmplY3Qgb2YgYWN0aW9ucyBhdmFpbGFibGUgZm9yIHRoYXQgbm9kZSAoeW91IGNhbiBhbHNvIHJldHVybiB0aGUgaXRlbXMgdG9vKS5cblx0XHQgKlxuXHRcdCAqIEVhY2ggYWN0aW9uIGNvbnNpc3RzIG9mIGEga2V5IChhIHVuaXF1ZSBuYW1lKSBhbmQgYSB2YWx1ZSB3aGljaCBpcyBhbiBvYmplY3Qgd2l0aCB0aGUgZm9sbG93aW5nIHByb3BlcnRpZXMgKG9ubHkgbGFiZWwgYW5kIGFjdGlvbiBhcmUgcmVxdWlyZWQpLiBPbmNlIGEgbWVudSBpdGVtIGlzIGFjdGl2YXRlZCB0aGUgYGFjdGlvbmAgZnVuY3Rpb24gd2lsbCBiZSBpbnZva2VkIHdpdGggYW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGZvbGxvd2luZyBrZXlzOiBpdGVtIC0gdGhlIGNvbnRleHRtZW51IGl0ZW0gZGVmaW5pdGlvbiBhcyBzZWVuIGJlbG93LCByZWZlcmVuY2UgLSB0aGUgRE9NIG5vZGUgdGhhdCB3YXMgdXNlZCAodGhlIHRyZWUgbm9kZSksIGVsZW1lbnQgLSB0aGUgY29udGV4dG1lbnUgRE9NIGVsZW1lbnQsIHBvc2l0aW9uIC0gYW4gb2JqZWN0IHdpdGggeC95IHByb3BlcnRpZXMgaW5kaWNhdGluZyB0aGUgcG9zaXRpb24gb2YgdGhlIG1lbnUuXG5cdFx0ICpcblx0XHQgKiAqIGBzZXBhcmF0b3JfYmVmb3JlYCAtIGEgYm9vbGVhbiBpbmRpY2F0aW5nIGlmIHRoZXJlIHNob3VsZCBiZSBhIHNlcGFyYXRvciBiZWZvcmUgdGhpcyBpdGVtXG5cdFx0ICogKiBgc2VwYXJhdG9yX2FmdGVyYCAtIGEgYm9vbGVhbiBpbmRpY2F0aW5nIGlmIHRoZXJlIHNob3VsZCBiZSBhIHNlcGFyYXRvciBhZnRlciB0aGlzIGl0ZW1cblx0XHQgKiAqIGBfZGlzYWJsZWRgIC0gYSBib29sZWFuIGluZGljYXRpbmcgaWYgdGhpcyBhY3Rpb24gc2hvdWxkIGJlIGRpc2FibGVkXG5cdFx0ICogKiBgbGFiZWxgIC0gYSBzdHJpbmcgLSB0aGUgbmFtZSBvZiB0aGUgYWN0aW9uIChjb3VsZCBiZSBhIGZ1bmN0aW9uIHJldHVybmluZyBhIHN0cmluZylcblx0XHQgKiAqIGB0aXRsZWAgLSBhIHN0cmluZyAtIGFuIG9wdGlvbmFsIHRvb2x0aXAgZm9yIHRoZSBpdGVtXG5cdFx0ICogKiBgYWN0aW9uYCAtIGEgZnVuY3Rpb24gdG8gYmUgZXhlY3V0ZWQgaWYgdGhpcyBpdGVtIGlzIGNob3NlbiwgdGhlIGZ1bmN0aW9uIHdpbGwgcmVjZWl2ZSBcblx0XHQgKiAqIGBpY29uYCAtIGEgc3RyaW5nLCBjYW4gYmUgYSBwYXRoIHRvIGFuIGljb24gb3IgYSBjbGFzc05hbWUsIGlmIHVzaW5nIGFuIGltYWdlIHRoYXQgaXMgaW4gdGhlIGN1cnJlbnQgZGlyZWN0b3J5IHVzZSBhIGAuL2AgcHJlZml4LCBvdGhlcndpc2UgaXQgd2lsbCBiZSBkZXRlY3RlZCBhcyBhIGNsYXNzXG5cdFx0ICogKiBgc2hvcnRjdXRgIC0ga2V5Q29kZSB3aGljaCB3aWxsIHRyaWdnZXIgdGhlIGFjdGlvbiBpZiB0aGUgbWVudSBpcyBvcGVuIChmb3IgZXhhbXBsZSBgMTEzYCBmb3IgcmVuYW1lLCB3aGljaCBlcXVhbHMgRjIpXG5cdFx0ICogKiBgc2hvcnRjdXRfbGFiZWxgIC0gc2hvcnRjdXQgbGFiZWwgKGxpa2UgZm9yIGV4YW1wbGUgYEYyYCBmb3IgcmVuYW1lKVxuXHRcdCAqICogYHN1Ym1lbnVgIC0gYW4gb2JqZWN0IHdpdGggdGhlIHNhbWUgc3RydWN0dXJlIGFzICQuanN0cmVlLmRlZmF1bHRzLmNvbnRleHRtZW51Lml0ZW1zIHdoaWNoIGNhbiBiZSB1c2VkIHRvIGNyZWF0ZSBhIHN1Ym1lbnUgLSBlYWNoIGtleSB3aWxsIGJlIHJlbmRlcmVkIGFzIGEgc2VwYXJhdGUgb3B0aW9uIGluIGEgc3VibWVudSB0aGF0IHdpbGwgYXBwZWFyIG9uY2UgdGhlIGN1cnJlbnQgaXRlbSBpcyBob3ZlcmVkXG5cdFx0ICpcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5jb250ZXh0bWVudS5pdGVtc1xuXHRcdCAqIEBwbHVnaW4gY29udGV4dG1lbnVcblx0XHQgKi9cblx0XHRpdGVtcyA6IGZ1bmN0aW9uIChvLCBjYikgeyAvLyBDb3VsZCBiZSBhbiBvYmplY3QgZGlyZWN0bHlcblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdFwiY3JlYXRlXCIgOiB7XG5cdFx0XHRcdFx0XCJzZXBhcmF0b3JfYmVmb3JlXCJcdDogZmFsc2UsXG5cdFx0XHRcdFx0XCJzZXBhcmF0b3JfYWZ0ZXJcIlx0OiB0cnVlLFxuXHRcdFx0XHRcdFwiX2Rpc2FibGVkXCJcdFx0XHQ6IGZhbHNlLCAvLyh0aGlzLmNoZWNrKFwiY3JlYXRlX25vZGVcIiwgZGF0YS5yZWZlcmVuY2UsIHt9LCBcImxhc3RcIikpLFxuXHRcdFx0XHRcdFwibGFiZWxcIlx0XHRcdFx0OiBcIkNyZWF0ZVwiLFxuXHRcdFx0XHRcdFwiYWN0aW9uXCJcdFx0XHQ6IGZ1bmN0aW9uIChkYXRhKSB7XG5cdFx0XHRcdFx0XHR2YXIgaW5zdCA9ICQuanN0cmVlLnJlZmVyZW5jZShkYXRhLnJlZmVyZW5jZSksXG5cdFx0XHRcdFx0XHRcdG9iaiA9IGluc3QuZ2V0X25vZGUoZGF0YS5yZWZlcmVuY2UpO1xuXHRcdFx0XHRcdFx0aW5zdC5jcmVhdGVfbm9kZShvYmosIHt9LCBcImxhc3RcIiwgZnVuY3Rpb24gKG5ld19ub2RlKSB7XG5cdFx0XHRcdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0XHRcdFx0aW5zdC5lZGl0KG5ld19ub2RlKTtcblx0XHRcdFx0XHRcdFx0fSBjYXRjaCAoZXgpIHtcblx0XHRcdFx0XHRcdFx0XHRzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHsgaW5zdC5lZGl0KG5ld19ub2RlKTsgfSwwKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRcInJlbmFtZVwiIDoge1xuXHRcdFx0XHRcdFwic2VwYXJhdG9yX2JlZm9yZVwiXHQ6IGZhbHNlLFxuXHRcdFx0XHRcdFwic2VwYXJhdG9yX2FmdGVyXCJcdDogZmFsc2UsXG5cdFx0XHRcdFx0XCJfZGlzYWJsZWRcIlx0XHRcdDogZmFsc2UsIC8vKHRoaXMuY2hlY2soXCJyZW5hbWVfbm9kZVwiLCBkYXRhLnJlZmVyZW5jZSwgdGhpcy5nZXRfcGFyZW50KGRhdGEucmVmZXJlbmNlKSwgXCJcIikpLFxuXHRcdFx0XHRcdFwibGFiZWxcIlx0XHRcdFx0OiBcIlJlbmFtZVwiLFxuXHRcdFx0XHRcdC8qIVxuXHRcdFx0XHRcdFwic2hvcnRjdXRcIlx0XHRcdDogMTEzLFxuXHRcdFx0XHRcdFwic2hvcnRjdXRfbGFiZWxcIlx0OiAnRjInLFxuXHRcdFx0XHRcdFwiaWNvblwiXHRcdFx0XHQ6IFwiZ2x5cGhpY29uIGdseXBoaWNvbi1sZWFmXCIsXG5cdFx0XHRcdFx0Ki9cblx0XHRcdFx0XHRcImFjdGlvblwiXHRcdFx0OiBmdW5jdGlvbiAoZGF0YSkge1xuXHRcdFx0XHRcdFx0dmFyIGluc3QgPSAkLmpzdHJlZS5yZWZlcmVuY2UoZGF0YS5yZWZlcmVuY2UpLFxuXHRcdFx0XHRcdFx0XHRvYmogPSBpbnN0LmdldF9ub2RlKGRhdGEucmVmZXJlbmNlKTtcblx0XHRcdFx0XHRcdGluc3QuZWRpdChvYmopO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSxcblx0XHRcdFx0XCJyZW1vdmVcIiA6IHtcblx0XHRcdFx0XHRcInNlcGFyYXRvcl9iZWZvcmVcIlx0OiBmYWxzZSxcblx0XHRcdFx0XHRcImljb25cIlx0XHRcdFx0OiBmYWxzZSxcblx0XHRcdFx0XHRcInNlcGFyYXRvcl9hZnRlclwiXHQ6IGZhbHNlLFxuXHRcdFx0XHRcdFwiX2Rpc2FibGVkXCJcdFx0XHQ6IGZhbHNlLCAvLyh0aGlzLmNoZWNrKFwiZGVsZXRlX25vZGVcIiwgZGF0YS5yZWZlcmVuY2UsIHRoaXMuZ2V0X3BhcmVudChkYXRhLnJlZmVyZW5jZSksIFwiXCIpKSxcblx0XHRcdFx0XHRcImxhYmVsXCJcdFx0XHRcdDogXCJEZWxldGVcIixcblx0XHRcdFx0XHRcImFjdGlvblwiXHRcdFx0OiBmdW5jdGlvbiAoZGF0YSkge1xuXHRcdFx0XHRcdFx0dmFyIGluc3QgPSAkLmpzdHJlZS5yZWZlcmVuY2UoZGF0YS5yZWZlcmVuY2UpLFxuXHRcdFx0XHRcdFx0XHRvYmogPSBpbnN0LmdldF9ub2RlKGRhdGEucmVmZXJlbmNlKTtcblx0XHRcdFx0XHRcdGlmKGluc3QuaXNfc2VsZWN0ZWQob2JqKSkge1xuXHRcdFx0XHRcdFx0XHRpbnN0LmRlbGV0ZV9ub2RlKGluc3QuZ2V0X3NlbGVjdGVkKCkpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRcdGluc3QuZGVsZXRlX25vZGUob2JqKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0sXG5cdFx0XHRcdFwiY2NwXCIgOiB7XG5cdFx0XHRcdFx0XCJzZXBhcmF0b3JfYmVmb3JlXCJcdDogdHJ1ZSxcblx0XHRcdFx0XHRcImljb25cIlx0XHRcdFx0OiBmYWxzZSxcblx0XHRcdFx0XHRcInNlcGFyYXRvcl9hZnRlclwiXHQ6IGZhbHNlLFxuXHRcdFx0XHRcdFwibGFiZWxcIlx0XHRcdFx0OiBcIkVkaXRcIixcblx0XHRcdFx0XHRcImFjdGlvblwiXHRcdFx0OiBmYWxzZSxcblx0XHRcdFx0XHRcInN1Ym1lbnVcIiA6IHtcblx0XHRcdFx0XHRcdFwiY3V0XCIgOiB7XG5cdFx0XHRcdFx0XHRcdFwic2VwYXJhdG9yX2JlZm9yZVwiXHQ6IGZhbHNlLFxuXHRcdFx0XHRcdFx0XHRcInNlcGFyYXRvcl9hZnRlclwiXHQ6IGZhbHNlLFxuXHRcdFx0XHRcdFx0XHRcImxhYmVsXCJcdFx0XHRcdDogXCJDdXRcIixcblx0XHRcdFx0XHRcdFx0XCJhY3Rpb25cIlx0XHRcdDogZnVuY3Rpb24gKGRhdGEpIHtcblx0XHRcdFx0XHRcdFx0XHR2YXIgaW5zdCA9ICQuanN0cmVlLnJlZmVyZW5jZShkYXRhLnJlZmVyZW5jZSksXG5cdFx0XHRcdFx0XHRcdFx0XHRvYmogPSBpbnN0LmdldF9ub2RlKGRhdGEucmVmZXJlbmNlKTtcblx0XHRcdFx0XHRcdFx0XHRpZihpbnN0LmlzX3NlbGVjdGVkKG9iaikpIHtcblx0XHRcdFx0XHRcdFx0XHRcdGluc3QuY3V0KGluc3QuZ2V0X3RvcF9zZWxlY3RlZCgpKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpbnN0LmN1dChvYmopO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdFwiY29weVwiIDoge1xuXHRcdFx0XHRcdFx0XHRcInNlcGFyYXRvcl9iZWZvcmVcIlx0OiBmYWxzZSxcblx0XHRcdFx0XHRcdFx0XCJpY29uXCJcdFx0XHRcdDogZmFsc2UsXG5cdFx0XHRcdFx0XHRcdFwic2VwYXJhdG9yX2FmdGVyXCJcdDogZmFsc2UsXG5cdFx0XHRcdFx0XHRcdFwibGFiZWxcIlx0XHRcdFx0OiBcIkNvcHlcIixcblx0XHRcdFx0XHRcdFx0XCJhY3Rpb25cIlx0XHRcdDogZnVuY3Rpb24gKGRhdGEpIHtcblx0XHRcdFx0XHRcdFx0XHR2YXIgaW5zdCA9ICQuanN0cmVlLnJlZmVyZW5jZShkYXRhLnJlZmVyZW5jZSksXG5cdFx0XHRcdFx0XHRcdFx0XHRvYmogPSBpbnN0LmdldF9ub2RlKGRhdGEucmVmZXJlbmNlKTtcblx0XHRcdFx0XHRcdFx0XHRpZihpbnN0LmlzX3NlbGVjdGVkKG9iaikpIHtcblx0XHRcdFx0XHRcdFx0XHRcdGluc3QuY29weShpbnN0LmdldF90b3Bfc2VsZWN0ZWQoKSk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdFx0aW5zdC5jb3B5KG9iaik7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0XCJwYXN0ZVwiIDoge1xuXHRcdFx0XHRcdFx0XHRcInNlcGFyYXRvcl9iZWZvcmVcIlx0OiBmYWxzZSxcblx0XHRcdFx0XHRcdFx0XCJpY29uXCJcdFx0XHRcdDogZmFsc2UsXG5cdFx0XHRcdFx0XHRcdFwiX2Rpc2FibGVkXCJcdFx0XHQ6IGZ1bmN0aW9uIChkYXRhKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuICEkLmpzdHJlZS5yZWZlcmVuY2UoZGF0YS5yZWZlcmVuY2UpLmNhbl9wYXN0ZSgpO1xuXHRcdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0XHRcInNlcGFyYXRvcl9hZnRlclwiXHQ6IGZhbHNlLFxuXHRcdFx0XHRcdFx0XHRcImxhYmVsXCJcdFx0XHRcdDogXCJQYXN0ZVwiLFxuXHRcdFx0XHRcdFx0XHRcImFjdGlvblwiXHRcdFx0OiBmdW5jdGlvbiAoZGF0YSkge1xuXHRcdFx0XHRcdFx0XHRcdHZhciBpbnN0ID0gJC5qc3RyZWUucmVmZXJlbmNlKGRhdGEucmVmZXJlbmNlKSxcblx0XHRcdFx0XHRcdFx0XHRcdG9iaiA9IGluc3QuZ2V0X25vZGUoZGF0YS5yZWZlcmVuY2UpO1xuXHRcdFx0XHRcdFx0XHRcdGluc3QucGFzdGUob2JqKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fTtcblx0XHR9XG5cdH07XG5cblx0JC5qc3RyZWUucGx1Z2lucy5jb250ZXh0bWVudSA9IGZ1bmN0aW9uIChvcHRpb25zLCBwYXJlbnQpIHtcblx0XHR0aGlzLmJpbmQgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRwYXJlbnQuYmluZC5jYWxsKHRoaXMpO1xuXG5cdFx0XHR2YXIgbGFzdF90cyA9IDAsIGN0byA9IG51bGwsIGV4LCBleTtcblx0XHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0XHQub24oXCJpbml0LmpzdHJlZSBsb2FkaW5nLmpzdHJlZSByZWFkeS5qc3RyZWVcIiwgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0dGhpcy5nZXRfY29udGFpbmVyX3VsKCkuYWRkQ2xhc3MoJ2pzdHJlZS1jb250ZXh0bWVudScpO1xuXHRcdFx0XHRcdH0uYmluZCh0aGlzKSlcblx0XHRcdFx0Lm9uKFwiY29udGV4dG1lbnUuanN0cmVlXCIsIFwiLmpzdHJlZS1hbmNob3JcIiwgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0XHRcdGlmIChlLnRhcmdldC50YWdOYW1lLnRvTG93ZXJDYXNlKCkgPT09ICdpbnB1dCcpIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0bGFzdF90cyA9IGUuY3RybEtleSA/ICtuZXcgRGF0ZSgpIDogMDtcblx0XHRcdFx0XHRcdGlmKGRhdGEgfHwgY3RvKSB7XG5cdFx0XHRcdFx0XHRcdGxhc3RfdHMgPSAoK25ldyBEYXRlKCkpICsgMTAwMDA7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRpZihjdG8pIHtcblx0XHRcdFx0XHRcdFx0Y2xlYXJUaW1lb3V0KGN0byk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRpZighdGhpcy5pc19sb2FkaW5nKGUuY3VycmVudFRhcmdldCkpIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5zaG93X2NvbnRleHRtZW51KGUuY3VycmVudFRhcmdldCwgZS5wYWdlWCwgZS5wYWdlWSwgZSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fS5iaW5kKHRoaXMpKVxuXHRcdFx0XHQub24oXCJjbGljay5qc3RyZWVcIiwgXCIuanN0cmVlLWFuY2hvclwiLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0aWYodGhpcy5fZGF0YS5jb250ZXh0bWVudS52aXNpYmxlICYmICghbGFzdF90cyB8fCAoK25ldyBEYXRlKCkpIC0gbGFzdF90cyA+IDI1MCkpIHsgLy8gd29yayBhcm91bmQgc2FmYXJpICYgbWFjT1MgY3RybCtjbGlja1xuXHRcdFx0XHRcdFx0XHQkLnZha2F0YS5jb250ZXh0LmhpZGUoKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGxhc3RfdHMgPSAwO1xuXHRcdFx0XHRcdH0uYmluZCh0aGlzKSlcblx0XHRcdFx0Lm9uKFwidG91Y2hzdGFydC5qc3RyZWVcIiwgXCIuanN0cmVlLWFuY2hvclwiLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0aWYoIWUub3JpZ2luYWxFdmVudCB8fCAhZS5vcmlnaW5hbEV2ZW50LmNoYW5nZWRUb3VjaGVzIHx8ICFlLm9yaWdpbmFsRXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0pIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0ZXggPSBlLm9yaWdpbmFsRXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0uY2xpZW50WDtcblx0XHRcdFx0XHRcdGV5ID0gZS5vcmlnaW5hbEV2ZW50LmNoYW5nZWRUb3VjaGVzWzBdLmNsaWVudFk7XG5cdFx0XHRcdFx0XHRjdG8gPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRcdFx0JChlLmN1cnJlbnRUYXJnZXQpLnRyaWdnZXIoJ2NvbnRleHRtZW51JywgdHJ1ZSk7XG5cdFx0XHRcdFx0XHR9LCA3NTApO1xuXHRcdFx0XHRcdH0pXG5cdFx0XHRcdC5vbigndG91Y2htb3ZlLnZha2F0YS5qc3RyZWUnLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0aWYoY3RvICYmIGUub3JpZ2luYWxFdmVudCAmJiBlLm9yaWdpbmFsRXZlbnQuY2hhbmdlZFRvdWNoZXMgJiYgZS5vcmlnaW5hbEV2ZW50LmNoYW5nZWRUb3VjaGVzWzBdICYmIChNYXRoLmFicyhleCAtIGUub3JpZ2luYWxFdmVudC5jaGFuZ2VkVG91Y2hlc1swXS5jbGllbnRYKSA+IDEwIHx8IE1hdGguYWJzKGV5IC0gZS5vcmlnaW5hbEV2ZW50LmNoYW5nZWRUb3VjaGVzWzBdLmNsaWVudFkpID4gMTApKSB7XG5cdFx0XHRcdFx0XHRcdGNsZWFyVGltZW91dChjdG8pO1xuXHRcdFx0XHRcdFx0XHQkLnZha2F0YS5jb250ZXh0LmhpZGUoKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9KVxuXHRcdFx0XHQub24oJ3RvdWNoZW5kLnZha2F0YS5qc3RyZWUnLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0aWYoY3RvKSB7XG5cdFx0XHRcdFx0XHRcdGNsZWFyVGltZW91dChjdG8pO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0pO1xuXG5cdFx0XHQvKiFcblx0XHRcdGlmKCEoJ29uY29udGV4dG1lbnUnIGluIGRvY3VtZW50LmJvZHkpICYmICgnb250b3VjaHN0YXJ0JyBpbiBkb2N1bWVudC5ib2R5KSkge1xuXHRcdFx0XHR2YXIgZWwgPSBudWxsLCB0bSA9IG51bGw7XG5cdFx0XHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0XHRcdC5vbihcInRvdWNoc3RhcnRcIiwgXCIuanN0cmVlLWFuY2hvclwiLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0ZWwgPSBlLmN1cnJlbnRUYXJnZXQ7XG5cdFx0XHRcdFx0XHR0bSA9ICtuZXcgRGF0ZSgpO1xuXHRcdFx0XHRcdFx0JChkb2N1bWVudCkub25lKFwidG91Y2hlbmRcIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdFx0ZS50YXJnZXQgPSBkb2N1bWVudC5lbGVtZW50RnJvbVBvaW50KGUub3JpZ2luYWxFdmVudC50YXJnZXRUb3VjaGVzWzBdLnBhZ2VYIC0gd2luZG93LnBhZ2VYT2Zmc2V0LCBlLm9yaWdpbmFsRXZlbnQudGFyZ2V0VG91Y2hlc1swXS5wYWdlWSAtIHdpbmRvdy5wYWdlWU9mZnNldCk7XG5cdFx0XHRcdFx0XHRcdGUuY3VycmVudFRhcmdldCA9IGUudGFyZ2V0O1xuXHRcdFx0XHRcdFx0XHR0bSA9ICgoKyhuZXcgRGF0ZSgpKSkgLSB0bSk7XG5cdFx0XHRcdFx0XHRcdGlmKGUudGFyZ2V0ID09PSBlbCAmJiB0bSA+IDYwMCAmJiB0bSA8IDEwMDApIHtcblx0XHRcdFx0XHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0XHRcdFx0JChlbCkudHJpZ2dlcignY29udGV4dG1lbnUnLCBlKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRlbCA9IG51bGw7XG5cdFx0XHRcdFx0XHRcdHRtID0gbnVsbDtcblx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdH0pO1xuXHRcdFx0fVxuXHRcdFx0Ki9cblx0XHRcdCQoZG9jdW1lbnQpLm9uKFwiY29udGV4dF9oaWRlLnZha2F0YS5qc3RyZWVcIiwgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0dGhpcy5fZGF0YS5jb250ZXh0bWVudS52aXNpYmxlID0gZmFsc2U7XG5cdFx0XHRcdCQoZGF0YS5yZWZlcmVuY2UpLnJlbW92ZUNsYXNzKCdqc3RyZWUtY29udGV4dCcpO1xuXHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHR9O1xuXHRcdHRoaXMudGVhcmRvd24gPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRpZih0aGlzLl9kYXRhLmNvbnRleHRtZW51LnZpc2libGUpIHtcblx0XHRcdFx0JC52YWthdGEuY29udGV4dC5oaWRlKCk7XG5cdFx0XHR9XG5cdFx0XHQkKGRvY3VtZW50KS5vZmYoXCJjb250ZXh0X2hpZGUudmFrYXRhLmpzdHJlZVwiKTtcblx0XHRcdHBhcmVudC50ZWFyZG93bi5jYWxsKHRoaXMpO1xuXHRcdH07XG5cblx0XHQvKipcblx0XHQgKiBwcmVwYXJlIGFuZCBzaG93IHRoZSBjb250ZXh0IG1lbnUgZm9yIGEgbm9kZVxuXHRcdCAqIEBuYW1lIHNob3dfY29udGV4dG1lbnUob2JqIFssIHgsIHldKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9iaiB0aGUgbm9kZVxuXHRcdCAqIEBwYXJhbSB7TnVtYmVyfSB4IHRoZSB4LWNvb3JkaW5hdGUgcmVsYXRpdmUgdG8gdGhlIGRvY3VtZW50IHRvIHNob3cgdGhlIG1lbnUgYXRcblx0XHQgKiBAcGFyYW0ge051bWJlcn0geSB0aGUgeS1jb29yZGluYXRlIHJlbGF0aXZlIHRvIHRoZSBkb2N1bWVudCB0byBzaG93IHRoZSBtZW51IGF0XG5cdFx0ICogQHBhcmFtIHtPYmplY3R9IGUgdGhlIGV2ZW50IGlmIGF2YWlsYWJsZSB0aGF0IHRyaWdnZXJlZCB0aGUgY29udGV4dG1lbnVcblx0XHQgKiBAcGx1Z2luIGNvbnRleHRtZW51XG5cdFx0ICogQHRyaWdnZXIgc2hvd19jb250ZXh0bWVudS5qc3RyZWVcblx0XHQgKi9cblx0XHR0aGlzLnNob3dfY29udGV4dG1lbnUgPSBmdW5jdGlvbiAob2JqLCB4LCB5LCBlKSB7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighb2JqIHx8IG9iai5pZCA9PT0gJC5qc3RyZWUucm9vdCkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdHZhciBzID0gdGhpcy5zZXR0aW5ncy5jb250ZXh0bWVudSxcblx0XHRcdFx0ZCA9IHRoaXMuZ2V0X25vZGUob2JqLCB0cnVlKSxcblx0XHRcdFx0YSA9IGQuY2hpbGRyZW4oXCIuanN0cmVlLWFuY2hvclwiKSxcblx0XHRcdFx0byA9IGZhbHNlLFxuXHRcdFx0XHRpID0gZmFsc2U7XG5cdFx0XHRpZihzLnNob3dfYXRfbm9kZSB8fCB4ID09PSB1bmRlZmluZWQgfHwgeSA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRcdG8gPSBhLm9mZnNldCgpO1xuXHRcdFx0XHR4ID0gby5sZWZ0O1xuXHRcdFx0XHR5ID0gby50b3AgKyB0aGlzLl9kYXRhLmNvcmUubGlfaGVpZ2h0O1xuXHRcdFx0fVxuXHRcdFx0aWYodGhpcy5zZXR0aW5ncy5jb250ZXh0bWVudS5zZWxlY3Rfbm9kZSAmJiAhdGhpcy5pc19zZWxlY3RlZChvYmopKSB7XG5cdFx0XHRcdHRoaXMuYWN0aXZhdGVfbm9kZShvYmosIGUpO1xuXHRcdFx0fVxuXG5cdFx0XHRpID0gcy5pdGVtcztcblx0XHRcdGlmKCQudmFrYXRhLmlzX2Z1bmN0aW9uKGkpKSB7XG5cdFx0XHRcdGkgPSBpLmNhbGwodGhpcywgb2JqLCBmdW5jdGlvbiAoaSkge1xuXHRcdFx0XHRcdHRoaXMuX3Nob3dfY29udGV4dG1lbnUob2JqLCB4LCB5LCBpKTtcblx0XHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHRcdH1cblx0XHRcdGlmKCQuaXNQbGFpbk9iamVjdChpKSkge1xuXHRcdFx0XHR0aGlzLl9zaG93X2NvbnRleHRtZW51KG9iaiwgeCwgeSwgaSk7XG5cdFx0XHR9XG5cdFx0fTtcblx0XHQvKipcblx0XHQgKiBzaG93IHRoZSBwcmVwYXJlZCBjb250ZXh0IG1lbnUgZm9yIGEgbm9kZVxuXHRcdCAqIEBuYW1lIF9zaG93X2NvbnRleHRtZW51KG9iaiwgeCwgeSwgaSlcblx0XHQgKiBAcGFyYW0ge21peGVkfSBvYmogdGhlIG5vZGVcblx0XHQgKiBAcGFyYW0ge051bWJlcn0geCB0aGUgeC1jb29yZGluYXRlIHJlbGF0aXZlIHRvIHRoZSBkb2N1bWVudCB0byBzaG93IHRoZSBtZW51IGF0XG5cdFx0ICogQHBhcmFtIHtOdW1iZXJ9IHkgdGhlIHktY29vcmRpbmF0ZSByZWxhdGl2ZSB0byB0aGUgZG9jdW1lbnQgdG8gc2hvdyB0aGUgbWVudSBhdFxuXHRcdCAqIEBwYXJhbSB7TnVtYmVyfSBpIHRoZSBvYmplY3Qgb2YgaXRlbXMgdG8gc2hvd1xuXHRcdCAqIEBwbHVnaW4gY29udGV4dG1lbnVcblx0XHQgKiBAdHJpZ2dlciBzaG93X2NvbnRleHRtZW51LmpzdHJlZVxuXHRcdCAqIEBwcml2YXRlXG5cdFx0ICovXG5cdFx0dGhpcy5fc2hvd19jb250ZXh0bWVudSA9IGZ1bmN0aW9uIChvYmosIHgsIHksIGkpIHtcblx0XHRcdHZhciBkID0gdGhpcy5nZXRfbm9kZShvYmosIHRydWUpLFxuXHRcdFx0XHRhID0gZC5jaGlsZHJlbihcIi5qc3RyZWUtYW5jaG9yXCIpO1xuXHRcdFx0JChkb2N1bWVudCkub25lKFwiY29udGV4dF9zaG93LnZha2F0YS5qc3RyZWVcIiwgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0dmFyIGNscyA9ICdqc3RyZWUtY29udGV4dG1lbnUganN0cmVlLScgKyB0aGlzLmdldF90aGVtZSgpICsgJy1jb250ZXh0bWVudSc7XG5cdFx0XHRcdCQoZGF0YS5lbGVtZW50KS5hZGRDbGFzcyhjbHMpO1xuXHRcdFx0XHRhLmFkZENsYXNzKCdqc3RyZWUtY29udGV4dCcpO1xuXHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHRcdHRoaXMuX2RhdGEuY29udGV4dG1lbnUudmlzaWJsZSA9IHRydWU7XG5cdFx0XHQkLnZha2F0YS5jb250ZXh0LnNob3coYSwgeyAneCcgOiB4LCAneScgOiB5IH0sIGkpO1xuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgd2hlbiB0aGUgY29udGV4dG1lbnUgaXMgc2hvd24gZm9yIGEgbm9kZVxuXHRcdFx0ICogQGV2ZW50XG5cdFx0XHQgKiBAbmFtZSBzaG93X2NvbnRleHRtZW51LmpzdHJlZVxuXHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IG5vZGUgdGhlIG5vZGVcblx0XHRcdCAqIEBwYXJhbSB7TnVtYmVyfSB4IHRoZSB4LWNvb3JkaW5hdGUgb2YgdGhlIG1lbnUgcmVsYXRpdmUgdG8gdGhlIGRvY3VtZW50XG5cdFx0XHQgKiBAcGFyYW0ge051bWJlcn0geSB0aGUgeS1jb29yZGluYXRlIG9mIHRoZSBtZW51IHJlbGF0aXZlIHRvIHRoZSBkb2N1bWVudFxuXHRcdFx0ICogQHBsdWdpbiBjb250ZXh0bWVudVxuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ3Nob3dfY29udGV4dG1lbnUnLCB7IFwibm9kZVwiIDogb2JqLCBcInhcIiA6IHgsIFwieVwiIDogeSB9KTtcblx0XHR9O1xuXHR9O1xuXG5cdC8vIGNvbnRleHRtZW51IGhlbHBlclxuXHQoZnVuY3Rpb24gKCQpIHtcblx0XHR2YXIgcmlnaHRfdG9fbGVmdCA9IGZhbHNlLFxuXHRcdFx0dmFrYXRhX2NvbnRleHQgPSB7XG5cdFx0XHRcdGVsZW1lbnRcdFx0OiBmYWxzZSxcblx0XHRcdFx0cmVmZXJlbmNlXHQ6IGZhbHNlLFxuXHRcdFx0XHRwb3NpdGlvbl94XHQ6IDAsXG5cdFx0XHRcdHBvc2l0aW9uX3lcdDogMCxcblx0XHRcdFx0aXRlbXNcdFx0OiBbXSxcblx0XHRcdFx0aHRtbFx0XHQ6IFwiXCIsXG5cdFx0XHRcdGlzX3Zpc2libGVcdDogZmFsc2Vcblx0XHRcdH07XG5cblx0XHQkLnZha2F0YS5jb250ZXh0ID0ge1xuXHRcdFx0c2V0dGluZ3MgOiB7XG5cdFx0XHRcdGhpZGVfb25tb3VzZWxlYXZlXHQ6IDAsXG5cdFx0XHRcdGljb25zXHRcdFx0XHQ6IHRydWVcblx0XHRcdH0sXG5cdFx0XHRfdHJpZ2dlciA6IGZ1bmN0aW9uIChldmVudF9uYW1lKSB7XG5cdFx0XHRcdCQoZG9jdW1lbnQpLnRyaWdnZXJIYW5kbGVyKFwiY29udGV4dF9cIiArIGV2ZW50X25hbWUgKyBcIi52YWthdGFcIiwge1xuXHRcdFx0XHRcdFwicmVmZXJlbmNlXCJcdDogdmFrYXRhX2NvbnRleHQucmVmZXJlbmNlLFxuXHRcdFx0XHRcdFwiZWxlbWVudFwiXHQ6IHZha2F0YV9jb250ZXh0LmVsZW1lbnQsXG5cdFx0XHRcdFx0XCJwb3NpdGlvblwiXHQ6IHtcblx0XHRcdFx0XHRcdFwieFwiIDogdmFrYXRhX2NvbnRleHQucG9zaXRpb25feCxcblx0XHRcdFx0XHRcdFwieVwiIDogdmFrYXRhX2NvbnRleHQucG9zaXRpb25feVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSk7XG5cdFx0XHR9LFxuXHRcdFx0X2V4ZWN1dGUgOiBmdW5jdGlvbiAoaSkge1xuXHRcdFx0XHRpID0gdmFrYXRhX2NvbnRleHQuaXRlbXNbaV07XG5cdFx0XHRcdHJldHVybiBpICYmICghaS5fZGlzYWJsZWQgfHwgKCQudmFrYXRhLmlzX2Z1bmN0aW9uKGkuX2Rpc2FibGVkKSAmJiAhaS5fZGlzYWJsZWQoeyBcIml0ZW1cIiA6IGksIFwicmVmZXJlbmNlXCIgOiB2YWthdGFfY29udGV4dC5yZWZlcmVuY2UsIFwiZWxlbWVudFwiIDogdmFrYXRhX2NvbnRleHQuZWxlbWVudCB9KSkpICYmIGkuYWN0aW9uID8gaS5hY3Rpb24uY2FsbChudWxsLCB7XG5cdFx0XHRcdFx0XHRcdFwiaXRlbVwiXHRcdDogaSxcblx0XHRcdFx0XHRcdFx0XCJyZWZlcmVuY2VcIlx0OiB2YWthdGFfY29udGV4dC5yZWZlcmVuY2UsXG5cdFx0XHRcdFx0XHRcdFwiZWxlbWVudFwiXHQ6IHZha2F0YV9jb250ZXh0LmVsZW1lbnQsXG5cdFx0XHRcdFx0XHRcdFwicG9zaXRpb25cIlx0OiB7XG5cdFx0XHRcdFx0XHRcdFx0XCJ4XCIgOiB2YWthdGFfY29udGV4dC5wb3NpdGlvbl94LFxuXHRcdFx0XHRcdFx0XHRcdFwieVwiIDogdmFrYXRhX2NvbnRleHQucG9zaXRpb25feVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9KSA6IGZhbHNlO1xuXHRcdFx0fSxcblx0XHRcdF9wYXJzZSA6IGZ1bmN0aW9uIChvLCBpc19jYWxsYmFjaykge1xuXHRcdFx0XHRpZighbykgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdFx0aWYoIWlzX2NhbGxiYWNrKSB7XG5cdFx0XHRcdFx0dmFrYXRhX2NvbnRleHQuaHRtbFx0XHQ9IFwiXCI7XG5cdFx0XHRcdFx0dmFrYXRhX2NvbnRleHQuaXRlbXNcdD0gW107XG5cdFx0XHRcdH1cblx0XHRcdFx0dmFyIHN0ciA9IFwiXCIsXG5cdFx0XHRcdFx0c2VwID0gZmFsc2UsXG5cdFx0XHRcdFx0dG1wO1xuXG5cdFx0XHRcdGlmKGlzX2NhbGxiYWNrKSB7IHN0ciArPSBcIjxcIitcInVsPlwiOyB9XG5cdFx0XHRcdCQuZWFjaChvLCBmdW5jdGlvbiAoaSwgdmFsKSB7XG5cdFx0XHRcdFx0aWYoIXZhbCkgeyByZXR1cm4gdHJ1ZTsgfVxuXHRcdFx0XHRcdHZha2F0YV9jb250ZXh0Lml0ZW1zLnB1c2godmFsKTtcblx0XHRcdFx0XHRpZighc2VwICYmIHZhbC5zZXBhcmF0b3JfYmVmb3JlKSB7XG5cdFx0XHRcdFx0XHRzdHIgKz0gXCI8XCIrXCJsaSBjbGFzcz0ndmFrYXRhLWNvbnRleHQtc2VwYXJhdG9yJz48XCIrXCJhIGhyZWY9JyMnIFwiICsgKCQudmFrYXRhLmNvbnRleHQuc2V0dGluZ3MuaWNvbnMgPyAnJyA6ICdjbGFzcz1cInZha2F0YS1jb250ZXh0LW5vLWljb25zXCInKSArIFwiPiYjMTYwOzxcIitcIi9hPjxcIitcIi9saT5cIjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0c2VwID0gZmFsc2U7XG5cdFx0XHRcdFx0c3RyICs9IFwiPFwiK1wibGkgY2xhc3M9J1wiICsgKHZhbC5fY2xhc3MgfHwgXCJcIikgKyAodmFsLl9kaXNhYmxlZCA9PT0gdHJ1ZSB8fCAoJC52YWthdGEuaXNfZnVuY3Rpb24odmFsLl9kaXNhYmxlZCkgJiYgdmFsLl9kaXNhYmxlZCh7IFwiaXRlbVwiIDogdmFsLCBcInJlZmVyZW5jZVwiIDogdmFrYXRhX2NvbnRleHQucmVmZXJlbmNlLCBcImVsZW1lbnRcIiA6IHZha2F0YV9jb250ZXh0LmVsZW1lbnQgfSkpID8gXCIgdmFrYXRhLWNvbnRleHRtZW51LWRpc2FibGVkIFwiIDogXCJcIikgKyBcIicgXCIrKHZhbC5zaG9ydGN1dD9cIiBkYXRhLXNob3J0Y3V0PSdcIit2YWwuc2hvcnRjdXQrXCInIFwiOicnKStcIj5cIjtcblx0XHRcdFx0XHRzdHIgKz0gXCI8XCIrXCJhIGhyZWY9JyMnIHJlbD0nXCIgKyAodmFrYXRhX2NvbnRleHQuaXRlbXMubGVuZ3RoIC0gMSkgKyBcIicgXCIgKyAodmFsLnRpdGxlID8gXCJ0aXRsZT0nXCIgKyB2YWwudGl0bGUgKyBcIidcIiA6IFwiXCIpICsgXCI+XCI7XG5cdFx0XHRcdFx0aWYoJC52YWthdGEuY29udGV4dC5zZXR0aW5ncy5pY29ucykge1xuXHRcdFx0XHRcdFx0c3RyICs9IFwiPFwiK1wiaSBcIjtcblx0XHRcdFx0XHRcdGlmKHZhbC5pY29uKSB7XG5cdFx0XHRcdFx0XHRcdGlmKHZhbC5pY29uLmluZGV4T2YoXCIvXCIpICE9PSAtMSB8fCB2YWwuaWNvbi5pbmRleE9mKFwiLlwiKSAhPT0gLTEpIHsgc3RyICs9IFwiIHN0eWxlPSdiYWNrZ3JvdW5kOnVybChcXFwiXCIgKyB2YWwuaWNvbiArIFwiXFxcIikgY2VudGVyIGNlbnRlciBuby1yZXBlYXQnIFwiOyB9XG5cdFx0XHRcdFx0XHRcdGVsc2UgeyBzdHIgKz0gXCIgY2xhc3M9J1wiICsgdmFsLmljb24gKyBcIicgXCI7IH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdHN0ciArPSBcIj48XCIrXCIvaT48XCIrXCJzcGFuIGNsYXNzPSd2YWthdGEtY29udGV4dG1lbnUtc2VwJz4mIzE2MDs8XCIrXCIvc3Bhbj5cIjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0c3RyICs9ICgkLnZha2F0YS5pc19mdW5jdGlvbih2YWwubGFiZWwpID8gdmFsLmxhYmVsKHsgXCJpdGVtXCIgOiBpLCBcInJlZmVyZW5jZVwiIDogdmFrYXRhX2NvbnRleHQucmVmZXJlbmNlLCBcImVsZW1lbnRcIiA6IHZha2F0YV9jb250ZXh0LmVsZW1lbnQgfSkgOiB2YWwubGFiZWwpICsgKHZhbC5zaG9ydGN1dD8nIDxzcGFuIGNsYXNzPVwidmFrYXRhLWNvbnRleHRtZW51LXNob3J0Y3V0IHZha2F0YS1jb250ZXh0bWVudS1zaG9ydGN1dC0nK3ZhbC5zaG9ydGN1dCsnXCI+JysgKHZhbC5zaG9ydGN1dF9sYWJlbCB8fCAnJykgKyc8L3NwYW4+JzonJykgKyBcIjxcIitcIi9hPlwiO1xuXHRcdFx0XHRcdGlmKHZhbC5zdWJtZW51KSB7XG5cdFx0XHRcdFx0XHR0bXAgPSAkLnZha2F0YS5jb250ZXh0Ll9wYXJzZSh2YWwuc3VibWVudSwgdHJ1ZSk7XG5cdFx0XHRcdFx0XHRpZih0bXApIHsgc3RyICs9IHRtcDsgfVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRzdHIgKz0gXCI8XCIrXCIvbGk+XCI7XG5cdFx0XHRcdFx0aWYodmFsLnNlcGFyYXRvcl9hZnRlcikge1xuXHRcdFx0XHRcdFx0c3RyICs9IFwiPFwiK1wibGkgY2xhc3M9J3Zha2F0YS1jb250ZXh0LXNlcGFyYXRvcic+PFwiK1wiYSBocmVmPScjJyBcIiArICgkLnZha2F0YS5jb250ZXh0LnNldHRpbmdzLmljb25zID8gJycgOiAnY2xhc3M9XCJ2YWthdGEtY29udGV4dC1uby1pY29uc1wiJykgKyBcIj4mIzE2MDs8XCIrXCIvYT48XCIrXCIvbGk+XCI7XG5cdFx0XHRcdFx0XHRzZXAgPSB0cnVlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSk7XG5cdFx0XHRcdHN0ciAgPSBzdHIucmVwbGFjZSgvPGxpIGNsYXNzXFw9J3Zha2F0YS1jb250ZXh0LXNlcGFyYXRvcidcXD48XFwvbGlcXD4kLyxcIlwiKTtcblx0XHRcdFx0aWYoaXNfY2FsbGJhY2spIHsgc3RyICs9IFwiPC91bD5cIjsgfVxuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIG9uIHRoZSBkb2N1bWVudCB3aGVuIHRoZSBjb250ZXh0bWVudSBpcyBwYXJzZWQgKEhUTUwgaXMgYnVpbHQpXG5cdFx0XHRcdCAqIEBldmVudFxuXHRcdFx0XHQgKiBAcGx1Z2luIGNvbnRleHRtZW51XG5cdFx0XHRcdCAqIEBuYW1lIGNvbnRleHRfcGFyc2UudmFrYXRhXG5cdFx0XHRcdCAqIEBwYXJhbSB7alF1ZXJ5fSByZWZlcmVuY2UgdGhlIGVsZW1lbnQgdGhhdCB3YXMgcmlnaHQgY2xpY2tlZFxuXHRcdFx0XHQgKiBAcGFyYW0ge2pRdWVyeX0gZWxlbWVudCB0aGUgRE9NIGVsZW1lbnQgb2YgdGhlIG1lbnUgaXRzZWxmXG5cdFx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBwb3NpdGlvbiB0aGUgeCAmIHkgY29vcmRpbmF0ZXMgb2YgdGhlIG1lbnVcblx0XHRcdFx0ICovXG5cdFx0XHRcdGlmKCFpc19jYWxsYmFjaykgeyB2YWthdGFfY29udGV4dC5odG1sID0gc3RyOyAkLnZha2F0YS5jb250ZXh0Ll90cmlnZ2VyKFwicGFyc2VcIik7IH1cblx0XHRcdFx0cmV0dXJuIHN0ci5sZW5ndGggPiAxMCA/IHN0ciA6IGZhbHNlO1xuXHRcdFx0fSxcblx0XHRcdF9zaG93X3N1Ym1lbnUgOiBmdW5jdGlvbiAobykge1xuXHRcdFx0XHRvID0gJChvKTtcblx0XHRcdFx0aWYoIW8ubGVuZ3RoIHx8ICFvLmNoaWxkcmVuKFwidWxcIikubGVuZ3RoKSB7IHJldHVybjsgfVxuXHRcdFx0XHR2YXIgZSA9IG8uY2hpbGRyZW4oXCJ1bFwiKSxcblx0XHRcdFx0XHR4bCA9IG8ub2Zmc2V0KCkubGVmdCxcblx0XHRcdFx0XHR4ID0geGwgKyBvLm91dGVyV2lkdGgoKSxcblx0XHRcdFx0XHR5ID0gby5vZmZzZXQoKS50b3AsXG5cdFx0XHRcdFx0dyA9IGUud2lkdGgoKSxcblx0XHRcdFx0XHRoID0gZS5oZWlnaHQoKSxcblx0XHRcdFx0XHRkdyA9ICQod2luZG93KS53aWR0aCgpICsgJCh3aW5kb3cpLnNjcm9sbExlZnQoKSxcblx0XHRcdFx0XHRkaCA9ICQod2luZG93KS5oZWlnaHQoKSArICQod2luZG93KS5zY3JvbGxUb3AoKTtcblx0XHRcdFx0Ly8g0LzQvtC20LUg0LTQsCDRgdC1INGB0L/QtdGB0YLQuCDQtSDQtdC00L3QsCDQv9GA0L7QstC10YDQutCwIC0g0LTQsNC70Lgg0L3Rj9C80LAg0L3Rj9C60L7QuSDQvtGCINC60LvQsNGB0L7QstC10YLQtSDQstC10YfQtSDQvdCw0LPQvtGA0LVcblx0XHRcdFx0aWYocmlnaHRfdG9fbGVmdCkge1xuXHRcdFx0XHRcdG9beCAtICh3ICsgMTAgKyBvLm91dGVyV2lkdGgoKSkgPCAwID8gXCJhZGRDbGFzc1wiIDogXCJyZW1vdmVDbGFzc1wiXShcInZha2F0YS1jb250ZXh0LWxlZnRcIik7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0b1t4ICsgdyA+IGR3ICAmJiB4bCA+IGR3IC0geCA/IFwiYWRkQ2xhc3NcIiA6IFwicmVtb3ZlQ2xhc3NcIl0oXCJ2YWthdGEtY29udGV4dC1yaWdodFwiKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZih5ICsgaCArIDEwID4gZGgpIHtcblx0XHRcdFx0XHRlLmNzcyhcImJvdHRvbVwiLFwiLTFweFwiKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vaWYgZG9lcyBub3QgZml0IC0gc3RpY2sgaXQgdG8gdGhlIHNpZGVcblx0XHRcdFx0aWYgKG8uaGFzQ2xhc3MoJ3Zha2F0YS1jb250ZXh0LXJpZ2h0JykpIHtcblx0XHRcdFx0XHRpZiAoeGwgPCB3KSB7XG5cdFx0XHRcdFx0XHRlLmNzcyhcIm1hcmdpbi1yaWdodFwiLCB4bCAtIHcpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRpZiAoZHcgLSB4IDwgdykge1xuXHRcdFx0XHRcdFx0ZS5jc3MoXCJtYXJnaW4tbGVmdFwiLCBkdyAtIHggLSB3KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRlLnNob3coKTtcblx0XHRcdH0sXG5cdFx0XHRzaG93IDogZnVuY3Rpb24gKHJlZmVyZW5jZSwgcG9zaXRpb24sIGRhdGEpIHtcblx0XHRcdFx0dmFyIG8sIGUsIHgsIHksIHcsIGgsIGR3LCBkaCwgY29uZCA9IHRydWU7XG5cdFx0XHRcdGlmKHZha2F0YV9jb250ZXh0LmVsZW1lbnQgJiYgdmFrYXRhX2NvbnRleHQuZWxlbWVudC5sZW5ndGgpIHtcblx0XHRcdFx0XHR2YWthdGFfY29udGV4dC5lbGVtZW50LndpZHRoKCcnKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRzd2l0Y2goY29uZCkge1xuXHRcdFx0XHRcdGNhc2UgKCFwb3NpdGlvbiAmJiAhcmVmZXJlbmNlKTpcblx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0XHRjYXNlICghIXBvc2l0aW9uICYmICEhcmVmZXJlbmNlKTpcblx0XHRcdFx0XHRcdHZha2F0YV9jb250ZXh0LnJlZmVyZW5jZVx0PSByZWZlcmVuY2U7XG5cdFx0XHRcdFx0XHR2YWthdGFfY29udGV4dC5wb3NpdGlvbl94XHQ9IHBvc2l0aW9uLng7XG5cdFx0XHRcdFx0XHR2YWthdGFfY29udGV4dC5wb3NpdGlvbl95XHQ9IHBvc2l0aW9uLnk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRjYXNlICghcG9zaXRpb24gJiYgISFyZWZlcmVuY2UpOlxuXHRcdFx0XHRcdFx0dmFrYXRhX2NvbnRleHQucmVmZXJlbmNlXHQ9IHJlZmVyZW5jZTtcblx0XHRcdFx0XHRcdG8gPSByZWZlcmVuY2Uub2Zmc2V0KCk7XG5cdFx0XHRcdFx0XHR2YWthdGFfY29udGV4dC5wb3NpdGlvbl94XHQ9IG8ubGVmdCArIHJlZmVyZW5jZS5vdXRlckhlaWdodCgpO1xuXHRcdFx0XHRcdFx0dmFrYXRhX2NvbnRleHQucG9zaXRpb25feVx0PSBvLnRvcDtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGNhc2UgKCEhcG9zaXRpb24gJiYgIXJlZmVyZW5jZSk6XG5cdFx0XHRcdFx0XHR2YWthdGFfY29udGV4dC5wb3NpdGlvbl94XHQ9IHBvc2l0aW9uLng7XG5cdFx0XHRcdFx0XHR2YWthdGFfY29udGV4dC5wb3NpdGlvbl95XHQ9IHBvc2l0aW9uLnk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0XHRpZighIXJlZmVyZW5jZSAmJiAhZGF0YSAmJiAkKHJlZmVyZW5jZSkuZGF0YSgndmFrYXRhX2NvbnRleHRtZW51JykpIHtcblx0XHRcdFx0XHRkYXRhID0gJChyZWZlcmVuY2UpLmRhdGEoJ3Zha2F0YV9jb250ZXh0bWVudScpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKCQudmFrYXRhLmNvbnRleHQuX3BhcnNlKGRhdGEpKSB7XG5cdFx0XHRcdFx0dmFrYXRhX2NvbnRleHQuZWxlbWVudC5odG1sKHZha2F0YV9jb250ZXh0Lmh0bWwpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKHZha2F0YV9jb250ZXh0Lml0ZW1zLmxlbmd0aCkge1xuXHRcdFx0XHRcdHZha2F0YV9jb250ZXh0LmVsZW1lbnQuYXBwZW5kVG8oZG9jdW1lbnQuYm9keSk7XG5cdFx0XHRcdFx0ZSA9IHZha2F0YV9jb250ZXh0LmVsZW1lbnQ7XG5cdFx0XHRcdFx0eCA9IHZha2F0YV9jb250ZXh0LnBvc2l0aW9uX3g7XG5cdFx0XHRcdFx0eSA9IHZha2F0YV9jb250ZXh0LnBvc2l0aW9uX3k7XG5cdFx0XHRcdFx0dyA9IGUud2lkdGgoKTtcblx0XHRcdFx0XHRoID0gZS5oZWlnaHQoKTtcblx0XHRcdFx0XHRkdyA9ICQod2luZG93KS53aWR0aCgpICsgJCh3aW5kb3cpLnNjcm9sbExlZnQoKTtcblx0XHRcdFx0XHRkaCA9ICQod2luZG93KS5oZWlnaHQoKSArICQod2luZG93KS5zY3JvbGxUb3AoKTtcblx0XHRcdFx0XHRpZihyaWdodF90b19sZWZ0KSB7XG5cdFx0XHRcdFx0XHR4IC09IChlLm91dGVyV2lkdGgoKSAtICQocmVmZXJlbmNlKS5vdXRlcldpZHRoKCkpO1xuXHRcdFx0XHRcdFx0aWYoeCA8ICQod2luZG93KS5zY3JvbGxMZWZ0KCkgKyAyMCkge1xuXHRcdFx0XHRcdFx0XHR4ID0gJCh3aW5kb3cpLnNjcm9sbExlZnQoKSArIDIwO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZih4ICsgdyArIDIwID4gZHcpIHtcblx0XHRcdFx0XHRcdHggPSBkdyAtICh3ICsgMjApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZih5ICsgaCArIDIwID4gZGgpIHtcblx0XHRcdFx0XHRcdHkgPSBkaCAtIChoICsgMjApO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdHZha2F0YV9jb250ZXh0LmVsZW1lbnRcblx0XHRcdFx0XHRcdC5jc3MoeyBcImxlZnRcIiA6IHgsIFwidG9wXCIgOiB5IH0pXG5cdFx0XHRcdFx0XHQuc2hvdygpXG5cdFx0XHRcdFx0XHQuZmluZCgnYScpLmZpcnN0KCkudHJpZ2dlcignZm9jdXMnKS5wYXJlbnQoKS5hZGRDbGFzcyhcInZha2F0YS1jb250ZXh0LWhvdmVyXCIpO1xuXHRcdFx0XHRcdHZha2F0YV9jb250ZXh0LmlzX3Zpc2libGUgPSB0cnVlO1xuXHRcdFx0XHRcdC8qKlxuXHRcdFx0XHRcdCAqIHRyaWdnZXJlZCBvbiB0aGUgZG9jdW1lbnQgd2hlbiB0aGUgY29udGV4dG1lbnUgaXMgc2hvd25cblx0XHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0XHQgKiBAcGx1Z2luIGNvbnRleHRtZW51XG5cdFx0XHRcdFx0ICogQG5hbWUgY29udGV4dF9zaG93LnZha2F0YVxuXHRcdFx0XHRcdCAqIEBwYXJhbSB7alF1ZXJ5fSByZWZlcmVuY2UgdGhlIGVsZW1lbnQgdGhhdCB3YXMgcmlnaHQgY2xpY2tlZFxuXHRcdFx0XHRcdCAqIEBwYXJhbSB7alF1ZXJ5fSBlbGVtZW50IHRoZSBET00gZWxlbWVudCBvZiB0aGUgbWVudSBpdHNlbGZcblx0XHRcdFx0XHQgKiBAcGFyYW0ge09iamVjdH0gcG9zaXRpb24gdGhlIHggJiB5IGNvb3JkaW5hdGVzIG9mIHRoZSBtZW51XG5cdFx0XHRcdFx0ICovXG5cdFx0XHRcdFx0JC52YWthdGEuY29udGV4dC5fdHJpZ2dlcihcInNob3dcIik7XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cdFx0XHRoaWRlIDogZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRpZih2YWthdGFfY29udGV4dC5pc192aXNpYmxlKSB7XG5cdFx0XHRcdFx0dmFrYXRhX2NvbnRleHQuZWxlbWVudC5oaWRlKCkuZmluZChcInVsXCIpLmhpZGUoKS5lbmQoKS5maW5kKCc6Zm9jdXMnKS50cmlnZ2VyKCdibHVyJykuZW5kKCkuZGV0YWNoKCk7XG5cdFx0XHRcdFx0dmFrYXRhX2NvbnRleHQuaXNfdmlzaWJsZSA9IGZhbHNlO1xuXHRcdFx0XHRcdC8qKlxuXHRcdFx0XHRcdCAqIHRyaWdnZXJlZCBvbiB0aGUgZG9jdW1lbnQgd2hlbiB0aGUgY29udGV4dG1lbnUgaXMgaGlkZGVuXG5cdFx0XHRcdFx0ICogQGV2ZW50XG5cdFx0XHRcdFx0ICogQHBsdWdpbiBjb250ZXh0bWVudVxuXHRcdFx0XHRcdCAqIEBuYW1lIGNvbnRleHRfaGlkZS52YWthdGFcblx0XHRcdFx0XHQgKiBAcGFyYW0ge2pRdWVyeX0gcmVmZXJlbmNlIHRoZSBlbGVtZW50IHRoYXQgd2FzIHJpZ2h0IGNsaWNrZWRcblx0XHRcdFx0XHQgKiBAcGFyYW0ge2pRdWVyeX0gZWxlbWVudCB0aGUgRE9NIGVsZW1lbnQgb2YgdGhlIG1lbnUgaXRzZWxmXG5cdFx0XHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IHBvc2l0aW9uIHRoZSB4ICYgeSBjb29yZGluYXRlcyBvZiB0aGUgbWVudVxuXHRcdFx0XHRcdCAqL1xuXHRcdFx0XHRcdCQudmFrYXRhLmNvbnRleHQuX3RyaWdnZXIoXCJoaWRlXCIpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fTtcblx0XHQkKGZ1bmN0aW9uICgpIHtcblx0XHRcdHJpZ2h0X3RvX2xlZnQgPSAkKGRvY3VtZW50LmJvZHkpLmNzcyhcImRpcmVjdGlvblwiKSA9PT0gXCJydGxcIjtcblx0XHRcdHZhciB0byA9IGZhbHNlO1xuXG5cdFx0XHR2YWthdGFfY29udGV4dC5lbGVtZW50ID0gJChcIjx1bCBjbGFzcz0ndmFrYXRhLWNvbnRleHQnPjwvdWw+XCIpO1xuXHRcdFx0dmFrYXRhX2NvbnRleHQuZWxlbWVudFxuXHRcdFx0XHQub24oXCJtb3VzZWVudGVyXCIsIFwibGlcIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRlLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpO1xuXG5cdFx0XHRcdFx0aWYoJC5jb250YWlucyh0aGlzLCBlLnJlbGF0ZWRUYXJnZXQpKSB7XG5cdFx0XHRcdFx0XHQvLyDQv9GA0LXQvNCw0YXQvdCw0YLQviDQt9Cw0YDQsNC00LggZGVsZWdhdGUgbW91c2VsZWF2ZSDQv9C+LdC00L7Qu9GDXG5cdFx0XHRcdFx0XHQvLyAkKHRoaXMpLmZpbmQoXCIudmFrYXRhLWNvbnRleHQtaG92ZXJcIikucmVtb3ZlQ2xhc3MoXCJ2YWthdGEtY29udGV4dC1ob3ZlclwiKTtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZih0bykgeyBjbGVhclRpbWVvdXQodG8pOyB9XG5cdFx0XHRcdFx0dmFrYXRhX2NvbnRleHQuZWxlbWVudC5maW5kKFwiLnZha2F0YS1jb250ZXh0LWhvdmVyXCIpLnJlbW92ZUNsYXNzKFwidmFrYXRhLWNvbnRleHQtaG92ZXJcIikuZW5kKCk7XG5cblx0XHRcdFx0XHQkKHRoaXMpXG5cdFx0XHRcdFx0XHQuc2libGluZ3MoKS5maW5kKFwidWxcIikuaGlkZSgpLmVuZCgpLmVuZCgpXG5cdFx0XHRcdFx0XHQucGFyZW50c1VudGlsKFwiLnZha2F0YS1jb250ZXh0XCIsIFwibGlcIikuYWRkQmFjaygpLmFkZENsYXNzKFwidmFrYXRhLWNvbnRleHQtaG92ZXJcIik7XG5cdFx0XHRcdFx0JC52YWthdGEuY29udGV4dC5fc2hvd19zdWJtZW51KHRoaXMpO1xuXHRcdFx0XHR9KVxuXHRcdFx0XHQvLyDRgtC10YHRgtC+0LLQviAtINC00LDQu9C4INC90LUg0L3QsNGC0L7QstCw0YDQstCwP1xuXHRcdFx0XHQub24oXCJtb3VzZWxlYXZlXCIsIFwibGlcIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRpZigkLmNvbnRhaW5zKHRoaXMsIGUucmVsYXRlZFRhcmdldCkpIHsgcmV0dXJuOyB9XG5cdFx0XHRcdFx0JCh0aGlzKS5maW5kKFwiLnZha2F0YS1jb250ZXh0LWhvdmVyXCIpLmFkZEJhY2soKS5yZW1vdmVDbGFzcyhcInZha2F0YS1jb250ZXh0LWhvdmVyXCIpO1xuXHRcdFx0XHR9KVxuXHRcdFx0XHQub24oXCJtb3VzZWxlYXZlXCIsIGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdFx0JCh0aGlzKS5maW5kKFwiLnZha2F0YS1jb250ZXh0LWhvdmVyXCIpLnJlbW92ZUNsYXNzKFwidmFrYXRhLWNvbnRleHQtaG92ZXJcIik7XG5cdFx0XHRcdFx0aWYoJC52YWthdGEuY29udGV4dC5zZXR0aW5ncy5oaWRlX29ubW91c2VsZWF2ZSkge1xuXHRcdFx0XHRcdFx0dG8gPSBzZXRUaW1lb3V0KFxuXHRcdFx0XHRcdFx0XHQoZnVuY3Rpb24gKHQpIHtcblx0XHRcdFx0XHRcdFx0XHRyZXR1cm4gZnVuY3Rpb24gKCkgeyAkLnZha2F0YS5jb250ZXh0LmhpZGUoKTsgfTtcblx0XHRcdFx0XHRcdFx0fSh0aGlzKSksICQudmFrYXRhLmNvbnRleHQuc2V0dGluZ3MuaGlkZV9vbm1vdXNlbGVhdmUpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSlcblx0XHRcdFx0Lm9uKFwiY2xpY2tcIiwgXCJhXCIsIGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHQvL30pXG5cdFx0XHRcdC8vLm9uKFwibW91c2V1cFwiLCBcImFcIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRpZighJCh0aGlzKS50cmlnZ2VyKCdibHVyJykucGFyZW50KCkuaGFzQ2xhc3MoXCJ2YWthdGEtY29udGV4dC1kaXNhYmxlZFwiKSAmJiAkLnZha2F0YS5jb250ZXh0Ll9leGVjdXRlKCQodGhpcykuYXR0cihcInJlbFwiKSkgIT09IGZhbHNlKSB7XG5cdFx0XHRcdFx0XHQkLnZha2F0YS5jb250ZXh0LmhpZGUoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0pXG5cdFx0XHRcdC5vbigna2V5ZG93bicsICdhJywgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdHZhciBvID0gbnVsbDtcblx0XHRcdFx0XHRcdHN3aXRjaChlLndoaWNoKSB7XG5cdFx0XHRcdFx0XHRcdGNhc2UgMTM6XG5cdFx0XHRcdFx0XHRcdGNhc2UgMzI6XG5cdFx0XHRcdFx0XHRcdFx0ZS50eXBlID0gXCJjbGlja1wiO1xuXHRcdFx0XHRcdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHRcdFx0XHQkKGUuY3VycmVudFRhcmdldCkudHJpZ2dlcihlKTtcblx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0Y2FzZSAzNzpcblx0XHRcdFx0XHRcdFx0XHRpZih2YWthdGFfY29udGV4dC5pc192aXNpYmxlKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHR2YWthdGFfY29udGV4dC5lbGVtZW50LmZpbmQoXCIudmFrYXRhLWNvbnRleHQtaG92ZXJcIikubGFzdCgpLmNsb3Nlc3QoXCJsaVwiKS5maXJzdCgpLmZpbmQoXCJ1bFwiKS5oaWRlKCkuZmluZChcIi52YWthdGEtY29udGV4dC1ob3ZlclwiKS5yZW1vdmVDbGFzcyhcInZha2F0YS1jb250ZXh0LWhvdmVyXCIpLmVuZCgpLmVuZCgpLmNoaWxkcmVuKCdhJykudHJpZ2dlcignZm9jdXMnKTtcblx0XHRcdFx0XHRcdFx0XHRcdGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG5cdFx0XHRcdFx0XHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHRjYXNlIDM4OlxuXHRcdFx0XHRcdFx0XHRcdGlmKHZha2F0YV9jb250ZXh0LmlzX3Zpc2libGUpIHtcblx0XHRcdFx0XHRcdFx0XHRcdG8gPSB2YWthdGFfY29udGV4dC5lbGVtZW50LmZpbmQoXCJ1bDp2aXNpYmxlXCIpLmFkZEJhY2soKS5sYXN0KCkuY2hpbGRyZW4oXCIudmFrYXRhLWNvbnRleHQtaG92ZXJcIikucmVtb3ZlQ2xhc3MoXCJ2YWthdGEtY29udGV4dC1ob3ZlclwiKS5wcmV2QWxsKFwibGk6bm90KC52YWthdGEtY29udGV4dC1zZXBhcmF0b3IpXCIpLmZpcnN0KCk7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZighby5sZW5ndGgpIHsgbyA9IHZha2F0YV9jb250ZXh0LmVsZW1lbnQuZmluZChcInVsOnZpc2libGVcIikuYWRkQmFjaygpLmxhc3QoKS5jaGlsZHJlbihcImxpOm5vdCgudmFrYXRhLWNvbnRleHQtc2VwYXJhdG9yKVwiKS5sYXN0KCk7IH1cblx0XHRcdFx0XHRcdFx0XHRcdG8uYWRkQ2xhc3MoXCJ2YWthdGEtY29udGV4dC1ob3ZlclwiKS5jaGlsZHJlbignYScpLnRyaWdnZXIoJ2ZvY3VzJyk7XG5cdFx0XHRcdFx0XHRcdFx0XHRlLnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpO1xuXHRcdFx0XHRcdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0Y2FzZSAzOTpcblx0XHRcdFx0XHRcdFx0XHRpZih2YWthdGFfY29udGV4dC5pc192aXNpYmxlKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHR2YWthdGFfY29udGV4dC5lbGVtZW50LmZpbmQoXCIudmFrYXRhLWNvbnRleHQtaG92ZXJcIikubGFzdCgpLmNoaWxkcmVuKFwidWxcIikuc2hvdygpLmNoaWxkcmVuKFwibGk6bm90KC52YWthdGEtY29udGV4dC1zZXBhcmF0b3IpXCIpLnJlbW92ZUNsYXNzKFwidmFrYXRhLWNvbnRleHQtaG92ZXJcIikuZmlyc3QoKS5hZGRDbGFzcyhcInZha2F0YS1jb250ZXh0LWhvdmVyXCIpLmNoaWxkcmVuKCdhJykudHJpZ2dlcignZm9jdXMnKTtcblx0XHRcdFx0XHRcdFx0XHRcdGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG5cdFx0XHRcdFx0XHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHRjYXNlIDQwOlxuXHRcdFx0XHRcdFx0XHRcdGlmKHZha2F0YV9jb250ZXh0LmlzX3Zpc2libGUpIHtcblx0XHRcdFx0XHRcdFx0XHRcdG8gPSB2YWthdGFfY29udGV4dC5lbGVtZW50LmZpbmQoXCJ1bDp2aXNpYmxlXCIpLmFkZEJhY2soKS5sYXN0KCkuY2hpbGRyZW4oXCIudmFrYXRhLWNvbnRleHQtaG92ZXJcIikucmVtb3ZlQ2xhc3MoXCJ2YWthdGEtY29udGV4dC1ob3ZlclwiKS5uZXh0QWxsKFwibGk6bm90KC52YWthdGEtY29udGV4dC1zZXBhcmF0b3IpXCIpLmZpcnN0KCk7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZighby5sZW5ndGgpIHsgbyA9IHZha2F0YV9jb250ZXh0LmVsZW1lbnQuZmluZChcInVsOnZpc2libGVcIikuYWRkQmFjaygpLmxhc3QoKS5jaGlsZHJlbihcImxpOm5vdCgudmFrYXRhLWNvbnRleHQtc2VwYXJhdG9yKVwiKS5maXJzdCgpOyB9XG5cdFx0XHRcdFx0XHRcdFx0XHRvLmFkZENsYXNzKFwidmFrYXRhLWNvbnRleHQtaG92ZXJcIikuY2hpbGRyZW4oJ2EnKS50cmlnZ2VyKCdmb2N1cycpO1xuXHRcdFx0XHRcdFx0XHRcdFx0ZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcblx0XHRcdFx0XHRcdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRcdGNhc2UgMjc6XG5cdFx0XHRcdFx0XHRcdFx0JC52YWthdGEuY29udGV4dC5oaWRlKCk7XG5cdFx0XHRcdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdFx0XHRcdC8vY29uc29sZS5sb2coZS53aGljaCk7XG5cdFx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSlcblx0XHRcdFx0Lm9uKCdrZXlkb3duJywgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0dmFyIGEgPSB2YWthdGFfY29udGV4dC5lbGVtZW50LmZpbmQoJy52YWthdGEtY29udGV4dG1lbnUtc2hvcnRjdXQtJyArIGUud2hpY2gpLnBhcmVudCgpO1xuXHRcdFx0XHRcdGlmKGEucGFyZW50KCkubm90KCcudmFrYXRhLWNvbnRleHQtZGlzYWJsZWQnKSkge1xuXHRcdFx0XHRcdFx0YS50cmlnZ2VyKCdjbGljaycpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSk7XG5cblx0XHRcdCQoZG9jdW1lbnQpXG5cdFx0XHRcdC5vbihcIm1vdXNlZG93bi52YWthdGEuanN0cmVlXCIsIGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdFx0aWYodmFrYXRhX2NvbnRleHQuaXNfdmlzaWJsZSAmJiB2YWthdGFfY29udGV4dC5lbGVtZW50WzBdICE9PSBlLnRhcmdldCAgJiYgISQuY29udGFpbnModmFrYXRhX2NvbnRleHQuZWxlbWVudFswXSwgZS50YXJnZXQpKSB7XG5cdFx0XHRcdFx0XHQkLnZha2F0YS5jb250ZXh0LmhpZGUoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0pXG5cdFx0XHRcdC5vbihcImNvbnRleHRfc2hvdy52YWthdGEuanN0cmVlXCIsIGZ1bmN0aW9uIChlLCBkYXRhKSB7XG5cdFx0XHRcdFx0dmFrYXRhX2NvbnRleHQuZWxlbWVudC5maW5kKFwibGk6aGFzKHVsKVwiKS5jaGlsZHJlbihcImFcIikuYWRkQ2xhc3MoXCJ2YWthdGEtY29udGV4dC1wYXJlbnRcIik7XG5cdFx0XHRcdFx0aWYocmlnaHRfdG9fbGVmdCkge1xuXHRcdFx0XHRcdFx0dmFrYXRhX2NvbnRleHQuZWxlbWVudC5hZGRDbGFzcyhcInZha2F0YS1jb250ZXh0LXJ0bFwiKS5jc3MoXCJkaXJlY3Rpb25cIiwgXCJydGxcIik7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdC8vIGFsc28gYXBwbHkgYSBSVEwgY2xhc3M/XG5cdFx0XHRcdFx0dmFrYXRhX2NvbnRleHQuZWxlbWVudC5maW5kKFwidWxcIikuaGlkZSgpLmVuZCgpO1xuXHRcdFx0XHR9KTtcblx0XHR9KTtcblx0fSgkKSk7XG5cdC8vICQuanN0cmVlLmRlZmF1bHRzLnBsdWdpbnMucHVzaChcImNvbnRleHRtZW51XCIpO1xuXG5cbi8qKlxuICogIyMjIERyYWcnbidkcm9wIHBsdWdpblxuICpcbiAqIEVuYWJsZXMgZHJhZ2dpbmcgYW5kIGRyb3BwaW5nIG9mIG5vZGVzIGluIHRoZSB0cmVlLCByZXN1bHRpbmcgaW4gYSBtb3ZlIG9yIGNvcHkgb3BlcmF0aW9ucy5cbiAqL1xuXG5cdC8qKlxuXHQgKiBzdG9yZXMgYWxsIGRlZmF1bHRzIGZvciB0aGUgZHJhZyduJ2Ryb3AgcGx1Z2luXG5cdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmRuZFxuXHQgKiBAcGx1Z2luIGRuZFxuXHQgKi9cblx0JC5qc3RyZWUuZGVmYXVsdHMuZG5kID0ge1xuXHRcdC8qKlxuXHRcdCAqIGEgYm9vbGVhbiBpbmRpY2F0aW5nIGlmIGEgY29weSBzaG91bGQgYmUgcG9zc2libGUgd2hpbGUgZHJhZ2dpbmcgKGJ5IHByZXNzaW50IHRoZSBtZXRhIGtleSBvciBDdHJsKS4gRGVmYXVsdHMgdG8gYHRydWVgLlxuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmRuZC5jb3B5XG5cdFx0ICogQHBsdWdpbiBkbmRcblx0XHQgKi9cblx0XHRjb3B5IDogdHJ1ZSxcblx0XHQvKipcblx0XHQgKiBhIG51bWJlciBpbmRpY2F0aW5nIGhvdyBsb25nIGEgbm9kZSBzaG91bGQgcmVtYWluIGhvdmVyZWQgd2hpbGUgZHJhZ2dpbmcgdG8gYmUgb3BlbmVkLiBEZWZhdWx0cyB0byBgNTAwYC5cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5kbmQub3Blbl90aW1lb3V0XG5cdFx0ICogQHBsdWdpbiBkbmRcblx0XHQgKi9cblx0XHRvcGVuX3RpbWVvdXQgOiA1MDAsXG5cdFx0LyoqXG5cdFx0ICogYSBmdW5jdGlvbiBpbnZva2VkIGVhY2ggdGltZSBhIG5vZGUgaXMgYWJvdXQgdG8gYmUgZHJhZ2dlZCwgaW52b2tlZCBpbiB0aGUgdHJlZSdzIHNjb3BlIGFuZCByZWNlaXZlcyB0aGUgbm9kZXMgYWJvdXQgdG8gYmUgZHJhZ2dlZCBhcyBhbiBhcmd1bWVudCAoYXJyYXkpIGFuZCB0aGUgZXZlbnQgdGhhdCBzdGFydGVkIHRoZSBkcmFnIC0gcmV0dXJuIGBmYWxzZWAgdG8gcHJldmVudCBkcmFnZ2luZ1xuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmRuZC5pc19kcmFnZ2FibGVcblx0XHQgKiBAcGx1Z2luIGRuZFxuXHRcdCAqL1xuXHRcdGlzX2RyYWdnYWJsZSA6IHRydWUsXG5cdFx0LyoqXG5cdFx0ICogYSBib29sZWFuIGluZGljYXRpbmcgaWYgY2hlY2tzIHNob3VsZCBjb25zdGFudGx5IGJlIG1hZGUgd2hpbGUgdGhlIHVzZXIgaXMgZHJhZ2dpbmcgdGhlIG5vZGUgKGFzIG9wcG9zZWQgdG8gY2hlY2tpbmcgb25seSBvbiBkcm9wKSwgZGVmYXVsdCBpcyBgdHJ1ZWBcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5kbmQuY2hlY2tfd2hpbGVfZHJhZ2dpbmdcblx0XHQgKiBAcGx1Z2luIGRuZFxuXHRcdCAqL1xuXHRcdGNoZWNrX3doaWxlX2RyYWdnaW5nIDogdHJ1ZSxcblx0XHQvKipcblx0XHQgKiBhIGJvb2xlYW4gaW5kaWNhdGluZyBpZiBub2RlcyBmcm9tIHRoaXMgdHJlZSBzaG91bGQgb25seSBiZSBjb3BpZWQgd2l0aCBkbmQgKGFzIG9wcG9zZWQgdG8gbW92ZWQpLCBkZWZhdWx0IGlzIGBmYWxzZWBcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5kbmQuYWx3YXlzX2NvcHlcblx0XHQgKiBAcGx1Z2luIGRuZFxuXHRcdCAqL1xuXHRcdGFsd2F5c19jb3B5IDogZmFsc2UsXG5cdFx0LyoqXG5cdFx0ICogd2hlbiBkcm9wcGluZyBhIG5vZGUgXCJpbnNpZGVcIiwgdGhpcyBzZXR0aW5nIGluZGljYXRlcyB0aGUgcG9zaXRpb24gdGhlIG5vZGUgc2hvdWxkIGdvIHRvIC0gaXQgY2FuIGJlIGFuIGludGVnZXIgb3IgYSBzdHJpbmc6IFwiZmlyc3RcIiAoc2FtZSBhcyAwKSBvciBcImxhc3RcIiwgZGVmYXVsdCBpcyBgMGBcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5kbmQuaW5zaWRlX3Bvc1xuXHRcdCAqIEBwbHVnaW4gZG5kXG5cdFx0ICovXG5cdFx0aW5zaWRlX3BvcyA6IDAsXG5cdFx0LyoqXG5cdFx0ICogd2hlbiBzdGFydGluZyB0aGUgZHJhZyBvbiBhIG5vZGUgdGhhdCBpcyBzZWxlY3RlZCB0aGlzIHNldHRpbmcgY29udHJvbHMgaWYgYWxsIHNlbGVjdGVkIG5vZGVzIGFyZSBkcmFnZ2VkIG9yIG9ubHkgdGhlIHNpbmdsZSBub2RlLCBkZWZhdWx0IGlzIGB0cnVlYCwgd2hpY2ggbWVhbnMgYWxsIHNlbGVjdGVkIG5vZGVzIGFyZSBkcmFnZ2VkIHdoZW4gdGhlIGRyYWcgaXMgc3RhcnRlZCBvbiBhIHNlbGVjdGVkIG5vZGVcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5kbmQuZHJhZ19zZWxlY3Rpb25cblx0XHQgKiBAcGx1Z2luIGRuZFxuXHRcdCAqL1xuXHRcdGRyYWdfc2VsZWN0aW9uIDogdHJ1ZSxcblx0XHQvKipcblx0XHQgKiBjb250cm9scyB3aGV0aGVyIGRuZCB3b3JrcyBvbiB0b3VjaCBkZXZpY2VzLiBJZiBsZWZ0IGFzIGJvb2xlYW4gdHJ1ZSBkbmQgd2lsbCB3b3JrIHRoZSBzYW1lIGFzIGluIGRlc2t0b3AgYnJvd3NlcnMsIHdoaWNoIGluIHNvbWUgY2FzZXMgbWF5IGltcGFpciBzY3JvbGxpbmcuIElmIHNldCB0byBib29sZWFuIGZhbHNlIGRuZCB3aWxsIG5vdCB3b3JrIG9uIHRvdWNoIGRldmljZXMuIFRoZXJlIGlzIGEgc3BlY2lhbCB0aGlyZCBvcHRpb24gLSBzdHJpbmcgXCJzZWxlY3RlZFwiIHdoaWNoIG1lYW5zIG9ubHkgc2VsZWN0ZWQgbm9kZXMgY2FuIGJlIGRyYWdnZWQgb24gdG91Y2ggZGV2aWNlcy5cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5kbmQudG91Y2hcblx0XHQgKiBAcGx1Z2luIGRuZFxuXHRcdCAqL1xuXHRcdHRvdWNoIDogdHJ1ZSxcblx0XHQvKipcblx0XHQgKiBjb250cm9scyB3aGV0aGVyIGl0ZW1zIGNhbiBiZSBkcm9wcGVkIGFueXdoZXJlIG9uIHRoZSBub2RlLCBub3QganVzdCBvbiB0aGUgYW5jaG9yLCBieSBkZWZhdWx0IG9ubHkgdGhlIG5vZGUgYW5jaG9yIGlzIGEgdmFsaWQgZHJvcCB0YXJnZXQuIFdvcmtzIGJlc3Qgd2l0aCB0aGUgd2hvbGVyb3cgcGx1Z2luLiBJZiBlbmFibGVkIG9uIG1vYmlsZSBkZXBlbmRpbmcgb24gdGhlIGludGVyZmFjZSBpdCBtaWdodCBiZSBoYXJkIGZvciB0aGUgdXNlciB0byBjYW5jZWwgdGhlIGRyb3AsIHNpbmNlIHRoZSB3aG9sZSB0cmVlIGNvbnRhaW5lciB3aWxsIGJlIGEgdmFsaWQgZHJvcCB0YXJnZXQuXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuZG5kLmxhcmdlX2Ryb3BfdGFyZ2V0XG5cdFx0ICogQHBsdWdpbiBkbmRcblx0XHQgKi9cblx0XHRsYXJnZV9kcm9wX3RhcmdldCA6IGZhbHNlLFxuXHRcdC8qKlxuXHRcdCAqIGNvbnRyb2xzIHdoZXRoZXIgYSBkcmFnIGNhbiBiZSBpbml0aWF0ZWQgZnJvbSBhbnkgcGFydCBvZiB0aGUgbm9kZSBhbmQgbm90IGp1c3QgdGhlIHRleHQvaWNvbiBwYXJ0LCB3b3JrcyBiZXN0IHdpdGggdGhlIHdob2xlcm93IHBsdWdpbi4gS2VlcCBpbiBtaW5kIGl0IGNhbiBjYXVzZSBwcm9ibGVtcyB3aXRoIHRyZWUgc2Nyb2xsaW5nIG9uIG1vYmlsZSBkZXBlbmRpbmcgb24gdGhlIGludGVyZmFjZSAtIGluIHRoYXQgY2FzZSBzZXQgdGhlIHRvdWNoIG9wdGlvbiB0byBcInNlbGVjdGVkXCIuXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuZG5kLmxhcmdlX2RyYWdfdGFyZ2V0XG5cdFx0ICogQHBsdWdpbiBkbmRcblx0XHQgKi9cblx0XHRsYXJnZV9kcmFnX3RhcmdldCA6IGZhbHNlLFxuXHRcdC8qKlxuXHRcdCAqIGNvbnRyb2xzIHdoZXRoZXIgdXNlIEhUTUw1IGRuZCBhcGkgaW5zdGVhZCBvZiBjbGFzc2ljYWwuIFRoYXQgd2lsbCBhbGxvdyBiZXR0ZXIgaW50ZWdyYXRpb24gb2YgZG5kIGV2ZW50cyB3aXRoIG90aGVyIEhUTUw1IGNvbnRyb2xzLlxuXHRcdCAqIEByZWZlcmVuY2UgaHR0cDovL2Nhbml1c2UuY29tLyNmZWF0PWRyYWduZHJvcFxuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLmRuZC51c2VfaHRtbDVcblx0XHQgKiBAcGx1Z2luIGRuZFxuXHRcdCAqL1xuXHRcdHVzZV9odG1sNTogZmFsc2Vcblx0fTtcblx0dmFyIGRyZywgZWxtO1xuXHQvLyBUT0RPOiBub3cgY2hlY2sgd29ya3MgYnkgY2hlY2tpbmcgZm9yIGVhY2ggbm9kZSBpbmRpdmlkdWFsbHksIGhvdyBhYm91dCBtYXhfY2hpbGRyZW4sIHVuaXF1ZSwgZXRjP1xuXHQkLmpzdHJlZS5wbHVnaW5zLmRuZCA9IGZ1bmN0aW9uIChvcHRpb25zLCBwYXJlbnQpIHtcblx0XHR0aGlzLmluaXQgPSBmdW5jdGlvbiAoZWwsIG9wdGlvbnMpIHtcblx0XHRcdHBhcmVudC5pbml0LmNhbGwodGhpcywgZWwsIG9wdGlvbnMpO1xuXHRcdFx0dGhpcy5zZXR0aW5ncy5kbmQudXNlX2h0bWw1ID0gdGhpcy5zZXR0aW5ncy5kbmQudXNlX2h0bWw1ICYmICgnZHJhZ2dhYmxlJyBpbiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJykpO1xuXHRcdH07XG5cdFx0dGhpcy5iaW5kID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0cGFyZW50LmJpbmQuY2FsbCh0aGlzKTtcblxuXHRcdFx0dGhpcy5lbGVtZW50XG5cdFx0XHRcdC5vbih0aGlzLnNldHRpbmdzLmRuZC51c2VfaHRtbDUgPyAnZHJhZ3N0YXJ0LmpzdHJlZScgOiAnbW91c2Vkb3duLmpzdHJlZSB0b3VjaHN0YXJ0LmpzdHJlZScsIHRoaXMuc2V0dGluZ3MuZG5kLmxhcmdlX2RyYWdfdGFyZ2V0ID8gJy5qc3RyZWUtbm9kZScgOiAnLmpzdHJlZS1hbmNob3InLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0aWYodGhpcy5zZXR0aW5ncy5kbmQubGFyZ2VfZHJhZ190YXJnZXQgJiYgJChlLnRhcmdldCkuY2xvc2VzdCgnLmpzdHJlZS1ub2RlJylbMF0gIT09IGUuY3VycmVudFRhcmdldCkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmKGUudHlwZSA9PT0gXCJ0b3VjaHN0YXJ0XCIgJiYgKCF0aGlzLnNldHRpbmdzLmRuZC50b3VjaCB8fCAodGhpcy5zZXR0aW5ncy5kbmQudG91Y2ggPT09ICdzZWxlY3RlZCcgJiYgISQoZS5jdXJyZW50VGFyZ2V0KS5jbG9zZXN0KCcuanN0cmVlLW5vZGUnKS5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKS5oYXNDbGFzcygnanN0cmVlLWNsaWNrZWQnKSkpKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0dmFyIG9iaiA9IHRoaXMuZ2V0X25vZGUoZS50YXJnZXQpLFxuXHRcdFx0XHRcdFx0XHRtbHQgPSB0aGlzLmlzX3NlbGVjdGVkKG9iaikgJiYgdGhpcy5zZXR0aW5ncy5kbmQuZHJhZ19zZWxlY3Rpb24gPyB0aGlzLmdldF90b3Bfc2VsZWN0ZWQoKS5sZW5ndGggOiAxLFxuXHRcdFx0XHRcdFx0XHR0eHQgPSAobWx0ID4gMSA/IG1sdCArICcgJyArIHRoaXMuZ2V0X3N0cmluZygnbm9kZXMnKSA6IHRoaXMuZ2V0X3RleHQoZS5jdXJyZW50VGFyZ2V0KSk7XG5cdFx0XHRcdFx0XHRpZih0aGlzLnNldHRpbmdzLmNvcmUuZm9yY2VfdGV4dCkge1xuXHRcdFx0XHRcdFx0XHR0eHQgPSAkLnZha2F0YS5odG1sLmVzY2FwZSh0eHQpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYob2JqICYmIG9iai5pZCAmJiBvYmouaWQgIT09ICQuanN0cmVlLnJvb3QgJiYgKGUud2hpY2ggPT09IDEgfHwgZS50eXBlID09PSBcInRvdWNoc3RhcnRcIiB8fCBlLnR5cGUgPT09IFwiZHJhZ3N0YXJ0XCIpICYmXG5cdFx0XHRcdFx0XHRcdCh0aGlzLnNldHRpbmdzLmRuZC5pc19kcmFnZ2FibGUgPT09IHRydWUgfHwgKCQudmFrYXRhLmlzX2Z1bmN0aW9uKHRoaXMuc2V0dGluZ3MuZG5kLmlzX2RyYWdnYWJsZSkgJiYgdGhpcy5zZXR0aW5ncy5kbmQuaXNfZHJhZ2dhYmxlLmNhbGwodGhpcywgKG1sdCA+IDEgPyB0aGlzLmdldF90b3Bfc2VsZWN0ZWQodHJ1ZSkgOiBbb2JqXSksIGUpKSlcblx0XHRcdFx0XHRcdCkge1xuXHRcdFx0XHRcdFx0XHRkcmcgPSB7ICdqc3RyZWUnIDogdHJ1ZSwgJ29yaWdpbicgOiB0aGlzLCAnb2JqJyA6IHRoaXMuZ2V0X25vZGUob2JqLHRydWUpLCAnbm9kZXMnIDogbWx0ID4gMSA/IHRoaXMuZ2V0X3RvcF9zZWxlY3RlZCgpIDogW29iai5pZF0gfTtcblx0XHRcdFx0XHRcdFx0ZWxtID0gZS5jdXJyZW50VGFyZ2V0O1xuXHRcdFx0XHRcdFx0XHRpZiAodGhpcy5zZXR0aW5ncy5kbmQudXNlX2h0bWw1KSB7XG5cdFx0XHRcdFx0XHRcdFx0JC52YWthdGEuZG5kLl90cmlnZ2VyKCdzdGFydCcsIGUsIHsgJ2hlbHBlcic6ICQoKSwgJ2VsZW1lbnQnOiBlbG0sICdkYXRhJzogZHJnIH0pO1xuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuZWxlbWVudC50cmlnZ2VyKCdtb3VzZWRvd24uanN0cmVlJyk7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuICQudmFrYXRhLmRuZC5zdGFydChlLCBkcmcsICc8ZGl2IGlkPVwianN0cmVlLWRuZFwiIGNsYXNzPVwianN0cmVlLScgKyB0aGlzLmdldF90aGVtZSgpICsgJyBqc3RyZWUtJyArIHRoaXMuZ2V0X3RoZW1lKCkgKyAnLScgKyB0aGlzLmdldF90aGVtZV92YXJpYW50KCkgKyAnICcgKyAoIHRoaXMuc2V0dGluZ3MuY29yZS50aGVtZXMucmVzcG9uc2l2ZSA/ICcganN0cmVlLWRuZC1yZXNwb25zaXZlJyA6ICcnICkgKyAnXCI+PGkgY2xhc3M9XCJqc3RyZWUtaWNvbiBqc3RyZWUtZXJcIj48L2k+JyArIHR4dCArICc8aW5zIGNsYXNzPVwianN0cmVlLWNvcHlcIj4rPC9pbnM+PC9kaXY+Jyk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9LmJpbmQodGhpcykpO1xuXHRcdFx0aWYgKHRoaXMuc2V0dGluZ3MuZG5kLnVzZV9odG1sNSkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnRcblx0XHRcdFx0XHQub24oJ2RyYWdvdmVyLmpzdHJlZScsIGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHRcdFx0JC52YWthdGEuZG5kLl90cmlnZ2VyKCdtb3ZlJywgZSwgeyAnaGVscGVyJzogJCgpLCAnZWxlbWVudCc6IGVsbSwgJ2RhdGEnOiBkcmcgfSk7XG5cdFx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0XHRcdH0pXG5cdFx0XHRcdFx0Ly8ub24oJ2RyYWdlbnRlci5qc3RyZWUnLCB0aGlzLnNldHRpbmdzLmRuZC5sYXJnZV9kcm9wX3RhcmdldCA/ICcuanN0cmVlLW5vZGUnIDogJy5qc3RyZWUtYW5jaG9yJywgJC5wcm94eShmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdC8vXHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHQvL1x0XHQkLnZha2F0YS5kbmQuX3RyaWdnZXIoJ21vdmUnLCBlLCB7ICdoZWxwZXInOiAkKCksICdlbGVtZW50JzogZWxtLCAnZGF0YSc6IGRyZyB9KTtcblx0XHRcdFx0XHQvL1x0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0Ly9cdH0sIHRoaXMpKVxuXHRcdFx0XHRcdC5vbignZHJvcC5qc3RyZWUnLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0XHRcdCQudmFrYXRhLmRuZC5fdHJpZ2dlcignc3RvcCcsIGUsIHsgJ2hlbHBlcic6ICQoKSwgJ2VsZW1lbnQnOiBlbG0sICdkYXRhJzogZHJnIH0pO1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0XHR9LmJpbmQodGhpcykpO1xuXHRcdFx0fVxuXHRcdH07XG5cdFx0dGhpcy5yZWRyYXdfbm9kZSA9IGZ1bmN0aW9uKG9iaiwgZGVlcCwgY2FsbGJhY2ssIGZvcmNlX3JlbmRlcikge1xuXHRcdFx0b2JqID0gcGFyZW50LnJlZHJhd19ub2RlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cdFx0XHRpZiAob2JqICYmIHRoaXMuc2V0dGluZ3MuZG5kLnVzZV9odG1sNSkge1xuXHRcdFx0XHRpZiAodGhpcy5zZXR0aW5ncy5kbmQubGFyZ2VfZHJhZ190YXJnZXQpIHtcblx0XHRcdFx0XHRvYmouc2V0QXR0cmlidXRlKCdkcmFnZ2FibGUnLCB0cnVlKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR2YXIgaSwgaiwgdG1wID0gbnVsbDtcblx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSBvYmouY2hpbGROb2Rlcy5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdGlmKG9iai5jaGlsZE5vZGVzW2ldICYmIG9iai5jaGlsZE5vZGVzW2ldLmNsYXNzTmFtZSAmJiBvYmouY2hpbGROb2Rlc1tpXS5jbGFzc05hbWUuaW5kZXhPZihcImpzdHJlZS1hbmNob3JcIikgIT09IC0xKSB7XG5cdFx0XHRcdFx0XHRcdHRtcCA9IG9iai5jaGlsZE5vZGVzW2ldO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYodG1wKSB7XG5cdFx0XHRcdFx0XHR0bXAuc2V0QXR0cmlidXRlKCdkcmFnZ2FibGUnLCB0cnVlKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiBvYmo7XG5cdFx0fTtcblx0fTtcblxuXHQkKGZ1bmN0aW9uKCkge1xuXHRcdC8vIGJpbmQgb25seSBvbmNlIGZvciBhbGwgaW5zdGFuY2VzXG5cdFx0dmFyIGxhc3RtdiA9IGZhbHNlLFxuXHRcdFx0bGFzdGVyID0gZmFsc2UsXG5cdFx0XHRsYXN0ZXYgPSBmYWxzZSxcblx0XHRcdG9wZW50byA9IGZhbHNlLFxuXHRcdFx0bWFya2VyID0gJCgnPGRpdiBpZD1cImpzdHJlZS1tYXJrZXJcIj4mIzE2MDs8L2Rpdj4nKS5oaWRlKCk7IC8vLmFwcGVuZFRvKCdib2R5Jyk7XG5cblx0XHQkKGRvY3VtZW50KVxuXHRcdFx0Lm9uKCdkcmFnb3Zlci52YWthdGEuanN0cmVlJywgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0aWYgKGVsbSkge1xuXHRcdFx0XHRcdCQudmFrYXRhLmRuZC5fdHJpZ2dlcignbW92ZScsIGUsIHsgJ2hlbHBlcic6ICQoKSwgJ2VsZW1lbnQnOiBlbG0sICdkYXRhJzogZHJnIH0pO1xuXHRcdFx0XHR9XG5cdFx0XHR9KVxuXHRcdFx0Lm9uKCdkcm9wLnZha2F0YS5qc3RyZWUnLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRpZiAoZWxtKSB7XG5cdFx0XHRcdFx0JC52YWthdGEuZG5kLl90cmlnZ2VyKCdzdG9wJywgZSwgeyAnaGVscGVyJzogJCgpLCAnZWxlbWVudCc6IGVsbSwgJ2RhdGEnOiBkcmcgfSk7XG5cdFx0XHRcdFx0ZWxtID0gbnVsbDtcblx0XHRcdFx0XHRkcmcgPSBudWxsO1xuXHRcdFx0XHR9XG5cdFx0XHR9KVxuXHRcdFx0Lm9uKCdkbmRfc3RhcnQudmFrYXRhLmpzdHJlZScsIGZ1bmN0aW9uIChlLCBkYXRhKSB7XG5cdFx0XHRcdGxhc3RtdiA9IGZhbHNlO1xuXHRcdFx0XHRsYXN0ZXYgPSBmYWxzZTtcblx0XHRcdFx0aWYoIWRhdGEgfHwgIWRhdGEuZGF0YSB8fCAhZGF0YS5kYXRhLmpzdHJlZSkgeyByZXR1cm47IH1cblx0XHRcdFx0bWFya2VyLmFwcGVuZFRvKGRvY3VtZW50LmJvZHkpOyAvLy5zaG93KCk7XG5cdFx0XHR9KVxuXHRcdFx0Lm9uKCdkbmRfbW92ZS52YWthdGEuanN0cmVlJywgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0dmFyIGlzRGlmZmVyZW50Tm9kZSA9IGRhdGEuZXZlbnQudGFyZ2V0ICE9PSBsYXN0ZXYudGFyZ2V0O1xuXHRcdFx0XHRpZihvcGVudG8pIHtcblx0XHRcdFx0XHRpZiAoIWRhdGEuZXZlbnQgfHwgZGF0YS5ldmVudC50eXBlICE9PSAnZHJhZ292ZXInIHx8IGlzRGlmZmVyZW50Tm9kZSkge1xuXHRcdFx0XHRcdFx0Y2xlYXJUaW1lb3V0KG9wZW50byk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKCFkYXRhIHx8ICFkYXRhLmRhdGEgfHwgIWRhdGEuZGF0YS5qc3RyZWUpIHsgcmV0dXJuOyB9XG5cblx0XHRcdFx0Ly8gaWYgd2UgYXJlIGhvdmVyaW5nIHRoZSBtYXJrZXIgaW1hZ2UgZG8gbm90aGluZyAoY2FuIGhhcHBlbiBvbiBcImluc2lkZVwiIGRyYWdzKVxuXHRcdFx0XHRpZihkYXRhLmV2ZW50LnRhcmdldC5pZCAmJiBkYXRhLmV2ZW50LnRhcmdldC5pZCA9PT0gJ2pzdHJlZS1tYXJrZXInKSB7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGxhc3RldiA9IGRhdGEuZXZlbnQ7XG5cblx0XHRcdFx0dmFyIGlucyA9ICQuanN0cmVlLnJlZmVyZW5jZShkYXRhLmV2ZW50LnRhcmdldCksXG5cdFx0XHRcdFx0cmVmID0gZmFsc2UsXG5cdFx0XHRcdFx0b2ZmID0gZmFsc2UsXG5cdFx0XHRcdFx0cmVsID0gZmFsc2UsXG5cdFx0XHRcdFx0dG1wLCBsLCB0LCBoLCBwLCBpLCBvLCBvaywgdDEsIHQyLCBvcCwgcHMsIHByLCBpcCwgdG0sIGlzX2NvcHksIHBuLCBjO1xuXHRcdFx0XHQvLyBpZiB3ZSBhcmUgb3ZlciBhbiBpbnN0YW5jZVxuXHRcdFx0XHRpZihpbnMgJiYgaW5zLl9kYXRhICYmIGlucy5fZGF0YS5kbmQpIHtcblx0XHRcdFx0XHRtYXJrZXIuYXR0cignY2xhc3MnLCAnanN0cmVlLScgKyBpbnMuZ2V0X3RoZW1lKCkgKyAoIGlucy5zZXR0aW5ncy5jb3JlLnRoZW1lcy5yZXNwb25zaXZlID8gJyBqc3RyZWUtZG5kLXJlc3BvbnNpdmUnIDogJycgKSk7XG5cdFx0XHRcdFx0aXNfY29weSA9IGRhdGEuZGF0YS5vcmlnaW4gJiYgKGRhdGEuZGF0YS5vcmlnaW4uc2V0dGluZ3MuZG5kLmFsd2F5c19jb3B5IHx8IChkYXRhLmRhdGEub3JpZ2luLnNldHRpbmdzLmRuZC5jb3B5ICYmIChkYXRhLmV2ZW50Lm1ldGFLZXkgfHwgZGF0YS5ldmVudC5jdHJsS2V5KSkpO1xuXHRcdFx0XHRcdGRhdGEuaGVscGVyXG5cdFx0XHRcdFx0XHQuY2hpbGRyZW4oKS5hdHRyKCdjbGFzcycsICdqc3RyZWUtJyArIGlucy5nZXRfdGhlbWUoKSArICcganN0cmVlLScgKyBpbnMuZ2V0X3RoZW1lKCkgKyAnLScgKyBpbnMuZ2V0X3RoZW1lX3ZhcmlhbnQoKSArICcgJyArICggaW5zLnNldHRpbmdzLmNvcmUudGhlbWVzLnJlc3BvbnNpdmUgPyAnIGpzdHJlZS1kbmQtcmVzcG9uc2l2ZScgOiAnJyApKVxuXHRcdFx0XHRcdFx0LmZpbmQoJy5qc3RyZWUtY29weScpLmZpcnN0KClbIGlzX2NvcHkgPyAnc2hvdycgOiAnaGlkZScgXSgpO1xuXG5cdFx0XHRcdFx0Ly8gaWYgYXJlIGhvdmVyaW5nIHRoZSBjb250YWluZXIgaXRzZWxmIGFkZCBhIG5ldyByb290IG5vZGVcblx0XHRcdFx0XHQvL2NvbnNvbGUubG9nKGRhdGEuZXZlbnQpO1xuXHRcdFx0XHRcdGlmKCAoZGF0YS5ldmVudC50YXJnZXQgPT09IGlucy5lbGVtZW50WzBdIHx8IGRhdGEuZXZlbnQudGFyZ2V0ID09PSBpbnMuZ2V0X2NvbnRhaW5lcl91bCgpWzBdKSAmJiBpbnMuZ2V0X2NvbnRhaW5lcl91bCgpLmNoaWxkcmVuKCkubGVuZ3RoID09PSAwKSB7XG5cdFx0XHRcdFx0XHRvayA9IHRydWU7XG5cdFx0XHRcdFx0XHRmb3IodDEgPSAwLCB0MiA9IGRhdGEuZGF0YS5ub2Rlcy5sZW5ndGg7IHQxIDwgdDI7IHQxKyspIHtcblx0XHRcdFx0XHRcdFx0b2sgPSBvayAmJiBpbnMuY2hlY2soIChkYXRhLmRhdGEub3JpZ2luICYmIChkYXRhLmRhdGEub3JpZ2luLnNldHRpbmdzLmRuZC5hbHdheXNfY29weSB8fCAoZGF0YS5kYXRhLm9yaWdpbi5zZXR0aW5ncy5kbmQuY29weSAmJiAoZGF0YS5ldmVudC5tZXRhS2V5IHx8IGRhdGEuZXZlbnQuY3RybEtleSkpICkgPyBcImNvcHlfbm9kZVwiIDogXCJtb3ZlX25vZGVcIiksIChkYXRhLmRhdGEub3JpZ2luICYmIGRhdGEuZGF0YS5vcmlnaW4gIT09IGlucyA/IGRhdGEuZGF0YS5vcmlnaW4uZ2V0X25vZGUoZGF0YS5kYXRhLm5vZGVzW3QxXSkgOiBkYXRhLmRhdGEubm9kZXNbdDFdKSwgJC5qc3RyZWUucm9vdCwgJ2xhc3QnLCB7ICdkbmQnIDogdHJ1ZSwgJ3JlZicgOiBpbnMuZ2V0X25vZGUoJC5qc3RyZWUucm9vdCksICdwb3MnIDogJ2knLCAnb3JpZ2luJyA6IGRhdGEuZGF0YS5vcmlnaW4sICdpc19tdWx0aScgOiAoZGF0YS5kYXRhLm9yaWdpbiAmJiBkYXRhLmRhdGEub3JpZ2luICE9PSBpbnMpLCAnaXNfZm9yZWlnbicgOiAoIWRhdGEuZGF0YS5vcmlnaW4pIH0pO1xuXHRcdFx0XHRcdFx0XHRpZighb2spIHsgYnJlYWs7IH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmKG9rKSB7XG5cdFx0XHRcdFx0XHRcdGxhc3RtdiA9IHsgJ2lucycgOiBpbnMsICdwYXInIDogJC5qc3RyZWUucm9vdCwgJ3BvcycgOiAnbGFzdCcgfTtcblx0XHRcdFx0XHRcdFx0bWFya2VyLmhpZGUoKTtcblx0XHRcdFx0XHRcdFx0ZGF0YS5oZWxwZXIuZmluZCgnLmpzdHJlZS1pY29uJykuZmlyc3QoKS5yZW1vdmVDbGFzcygnanN0cmVlLWVyJykuYWRkQ2xhc3MoJ2pzdHJlZS1vaycpO1xuXHRcdFx0XHRcdFx0XHRpZiAoZGF0YS5ldmVudC5vcmlnaW5hbEV2ZW50ICYmIGRhdGEuZXZlbnQub3JpZ2luYWxFdmVudC5kYXRhVHJhbnNmZXIpIHtcblx0XHRcdFx0XHRcdFx0XHRkYXRhLmV2ZW50Lm9yaWdpbmFsRXZlbnQuZGF0YVRyYW5zZmVyLmRyb3BFZmZlY3QgPSBpc19jb3B5ID8gJ2NvcHknIDogJ21vdmUnO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHQvLyBpZiB3ZSBhcmUgaG92ZXJpbmcgYSB0cmVlIG5vZGVcblx0XHRcdFx0XHRcdHJlZiA9IGlucy5zZXR0aW5ncy5kbmQubGFyZ2VfZHJvcF90YXJnZXQgPyAkKGRhdGEuZXZlbnQudGFyZ2V0KS5jbG9zZXN0KCcuanN0cmVlLW5vZGUnKS5jaGlsZHJlbignLmpzdHJlZS1hbmNob3InKSA6ICQoZGF0YS5ldmVudC50YXJnZXQpLmNsb3Nlc3QoJy5qc3RyZWUtYW5jaG9yJyk7XG5cdFx0XHRcdFx0XHRpZihyZWYgJiYgcmVmLmxlbmd0aCAmJiByZWYucGFyZW50KCkuaXMoJy5qc3RyZWUtY2xvc2VkLCAuanN0cmVlLW9wZW4sIC5qc3RyZWUtbGVhZicpKSB7XG5cdFx0XHRcdFx0XHRcdG9mZiA9IHJlZi5vZmZzZXQoKTtcblx0XHRcdFx0XHRcdFx0cmVsID0gKGRhdGEuZXZlbnQucGFnZVkgIT09IHVuZGVmaW5lZCA/IGRhdGEuZXZlbnQucGFnZVkgOiBkYXRhLmV2ZW50Lm9yaWdpbmFsRXZlbnQucGFnZVkpIC0gb2ZmLnRvcDtcblx0XHRcdFx0XHRcdFx0aCA9IHJlZi5vdXRlckhlaWdodCgpO1xuXHRcdFx0XHRcdFx0XHRpZihyZWwgPCBoIC8gMykge1xuXHRcdFx0XHRcdFx0XHRcdG8gPSBbJ2InLCAnaScsICdhJ107XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0ZWxzZSBpZihyZWwgPiBoIC0gaCAvIDMpIHtcblx0XHRcdFx0XHRcdFx0XHRvID0gWydhJywgJ2knLCAnYiddO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdG8gPSByZWwgPiBoIC8gMiA/IFsnaScsICdhJywgJ2InXSA6IFsnaScsICdiJywgJ2EnXTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHQkLmVhY2gobywgZnVuY3Rpb24gKGosIHYpIHtcblx0XHRcdFx0XHRcdFx0XHRzd2l0Y2godikge1xuXHRcdFx0XHRcdFx0XHRcdFx0Y2FzZSAnYic6XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGwgPSBvZmYubGVmdCAtIDY7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHQgPSBvZmYudG9wO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRwID0gaW5zLmdldF9wYXJlbnQocmVmKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0aSA9IHJlZi5wYXJlbnQoKS5pbmRleCgpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRjID0gJ2pzdHJlZS1iZWxvdyc7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHRcdFx0Y2FzZSAnaSc6XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGlwID0gaW5zLnNldHRpbmdzLmRuZC5pbnNpZGVfcG9zO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0bSA9IGlucy5nZXRfbm9kZShyZWYucGFyZW50KCkpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRsID0gb2ZmLmxlZnQgLSAyO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0ID0gb2ZmLnRvcCArIGggLyAyICsgMTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0cCA9IHRtLmlkO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRpID0gaXAgPT09ICdmaXJzdCcgPyAwIDogKGlwID09PSAnbGFzdCcgPyB0bS5jaGlsZHJlbi5sZW5ndGggOiBNYXRoLm1pbihpcCwgdG0uY2hpbGRyZW4ubGVuZ3RoKSk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGMgPSAnanN0cmVlLWluc2lkZSc7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHRcdFx0Y2FzZSAnYSc6XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGwgPSBvZmYubGVmdCAtIDY7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHQgPSBvZmYudG9wICsgaDtcblx0XHRcdFx0XHRcdFx0XHRcdFx0cCA9IGlucy5nZXRfcGFyZW50KHJlZik7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGkgPSByZWYucGFyZW50KCkuaW5kZXgoKSArIDE7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGMgPSAnanN0cmVlLWFib3ZlJztcblx0XHRcdFx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdG9rID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0XHRmb3IodDEgPSAwLCB0MiA9IGRhdGEuZGF0YS5ub2Rlcy5sZW5ndGg7IHQxIDwgdDI7IHQxKyspIHtcblx0XHRcdFx0XHRcdFx0XHRcdG9wID0gZGF0YS5kYXRhLm9yaWdpbiAmJiAoZGF0YS5kYXRhLm9yaWdpbi5zZXR0aW5ncy5kbmQuYWx3YXlzX2NvcHkgfHwgKGRhdGEuZGF0YS5vcmlnaW4uc2V0dGluZ3MuZG5kLmNvcHkgJiYgKGRhdGEuZXZlbnQubWV0YUtleSB8fCBkYXRhLmV2ZW50LmN0cmxLZXkpKSkgPyBcImNvcHlfbm9kZVwiIDogXCJtb3ZlX25vZGVcIjtcblx0XHRcdFx0XHRcdFx0XHRcdHBzID0gaTtcblx0XHRcdFx0XHRcdFx0XHRcdGlmKG9wID09PSBcIm1vdmVfbm9kZVwiICYmIHYgPT09ICdhJyAmJiAoZGF0YS5kYXRhLm9yaWdpbiAmJiBkYXRhLmRhdGEub3JpZ2luID09PSBpbnMpICYmIHAgPT09IGlucy5nZXRfcGFyZW50KGRhdGEuZGF0YS5ub2Rlc1t0MV0pKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHByID0gaW5zLmdldF9ub2RlKHApO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRpZihwcyA+ICQuaW5BcnJheShkYXRhLmRhdGEubm9kZXNbdDFdLCBwci5jaGlsZHJlbikpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRwcyAtPSAxO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0XHRvayA9IG9rICYmICggKGlucyAmJiBpbnMuc2V0dGluZ3MgJiYgaW5zLnNldHRpbmdzLmRuZCAmJiBpbnMuc2V0dGluZ3MuZG5kLmNoZWNrX3doaWxlX2RyYWdnaW5nID09PSBmYWxzZSkgfHwgaW5zLmNoZWNrKG9wLCAoZGF0YS5kYXRhLm9yaWdpbiAmJiBkYXRhLmRhdGEub3JpZ2luICE9PSBpbnMgPyBkYXRhLmRhdGEub3JpZ2luLmdldF9ub2RlKGRhdGEuZGF0YS5ub2Rlc1t0MV0pIDogZGF0YS5kYXRhLm5vZGVzW3QxXSksIHAsIHBzLCB7ICdkbmQnIDogdHJ1ZSwgJ3JlZicgOiBpbnMuZ2V0X25vZGUocmVmLnBhcmVudCgpKSwgJ3BvcycgOiB2LCAnb3JpZ2luJyA6IGRhdGEuZGF0YS5vcmlnaW4sICdpc19tdWx0aScgOiAoZGF0YS5kYXRhLm9yaWdpbiAmJiBkYXRhLmRhdGEub3JpZ2luICE9PSBpbnMpLCAnaXNfZm9yZWlnbicgOiAoIWRhdGEuZGF0YS5vcmlnaW4pIH0pICk7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZighb2spIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYoaW5zICYmIGlucy5sYXN0X2Vycm9yKSB7IGxhc3RlciA9IGlucy5sYXN0X2Vycm9yKCk7IH1cblx0XHRcdFx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdGlmKHYgPT09ICdpJyAmJiByZWYucGFyZW50KCkuaXMoJy5qc3RyZWUtY2xvc2VkJykgJiYgaW5zLnNldHRpbmdzLmRuZC5vcGVuX3RpbWVvdXQpIHtcblx0XHRcdFx0XHRcdFx0XHRcdGlmICghZGF0YS5ldmVudCB8fCBkYXRhLmV2ZW50LnR5cGUgIT09ICdkcmFnb3ZlcicgfHwgaXNEaWZmZXJlbnROb2RlKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGlmIChvcGVudG8pIHsgY2xlYXJUaW1lb3V0KG9wZW50byk7IH1cblx0XHRcdFx0XHRcdFx0XHRcdFx0b3BlbnRvID0gc2V0VGltZW91dCgoZnVuY3Rpb24gKHgsIHopIHsgcmV0dXJuIGZ1bmN0aW9uICgpIHsgeC5vcGVuX25vZGUoeik7IH07IH0oaW5zLCByZWYpKSwgaW5zLnNldHRpbmdzLmRuZC5vcGVuX3RpbWVvdXQpO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRpZihvaykge1xuXHRcdFx0XHRcdFx0XHRcdFx0cG4gPSBpbnMuZ2V0X25vZGUocCwgdHJ1ZSk7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoIXBuLmhhc0NsYXNzKCcuanN0cmVlLWRuZC1wYXJlbnQnKSkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHQkKCcuanN0cmVlLWRuZC1wYXJlbnQnKS5yZW1vdmVDbGFzcygnanN0cmVlLWRuZC1wYXJlbnQnKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0cG4uYWRkQ2xhc3MoJ2pzdHJlZS1kbmQtcGFyZW50Jyk7XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0XHRsYXN0bXYgPSB7ICdpbnMnIDogaW5zLCAncGFyJyA6IHAsICdwb3MnIDogdiA9PT0gJ2knICYmIGlwID09PSAnbGFzdCcgJiYgaSA9PT0gMCAmJiAhaW5zLmlzX2xvYWRlZCh0bSkgPyAnbGFzdCcgOiBpIH07XG5cdFx0XHRcdFx0XHRcdFx0XHRtYXJrZXIuY3NzKHsgJ2xlZnQnIDogbCArICdweCcsICd0b3AnIDogdCArICdweCcgfSkuc2hvdygpO1xuXHRcdFx0XHRcdFx0XHRcdFx0bWFya2VyLnJlbW92ZUNsYXNzKCdqc3RyZWUtYWJvdmUganN0cmVlLWluc2lkZSBqc3RyZWUtYmVsb3cnKS5hZGRDbGFzcyhjKTtcblx0XHRcdFx0XHRcdFx0XHRcdGRhdGEuaGVscGVyLmZpbmQoJy5qc3RyZWUtaWNvbicpLmZpcnN0KCkucmVtb3ZlQ2xhc3MoJ2pzdHJlZS1lcicpLmFkZENsYXNzKCdqc3RyZWUtb2snKTtcblx0XHRcdFx0XHRcdFx0XHRcdGlmIChkYXRhLmV2ZW50Lm9yaWdpbmFsRXZlbnQgJiYgZGF0YS5ldmVudC5vcmlnaW5hbEV2ZW50LmRhdGFUcmFuc2Zlcikge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRkYXRhLmV2ZW50Lm9yaWdpbmFsRXZlbnQuZGF0YVRyYW5zZmVyLmRyb3BFZmZlY3QgPSBpc19jb3B5ID8gJ2NvcHknIDogJ21vdmUnO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0bGFzdGVyID0ge307XG5cdFx0XHRcdFx0XHRcdFx0XHRvID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdFx0XHRpZihvID09PSB0cnVlKSB7IHJldHVybjsgfVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHQkKCcuanN0cmVlLWRuZC1wYXJlbnQnKS5yZW1vdmVDbGFzcygnanN0cmVlLWRuZC1wYXJlbnQnKTtcblx0XHRcdFx0bGFzdG12ID0gZmFsc2U7XG5cdFx0XHRcdGRhdGEuaGVscGVyLmZpbmQoJy5qc3RyZWUtaWNvbicpLnJlbW92ZUNsYXNzKCdqc3RyZWUtb2snKS5hZGRDbGFzcygnanN0cmVlLWVyJyk7XG5cdFx0XHRcdGlmIChkYXRhLmV2ZW50Lm9yaWdpbmFsRXZlbnQgJiYgZGF0YS5ldmVudC5vcmlnaW5hbEV2ZW50LmRhdGFUcmFuc2Zlcikge1xuXHRcdFx0XHRcdC8vZGF0YS5ldmVudC5vcmlnaW5hbEV2ZW50LmRhdGFUcmFuc2Zlci5kcm9wRWZmZWN0ID0gJ25vbmUnO1xuXHRcdFx0XHR9XG5cdFx0XHRcdG1hcmtlci5oaWRlKCk7XG5cdFx0XHR9KVxuXHRcdFx0Lm9uKCdkbmRfc2Nyb2xsLnZha2F0YS5qc3RyZWUnLCBmdW5jdGlvbiAoZSwgZGF0YSkge1xuXHRcdFx0XHRpZighZGF0YSB8fCAhZGF0YS5kYXRhIHx8ICFkYXRhLmRhdGEuanN0cmVlKSB7IHJldHVybjsgfVxuXHRcdFx0XHRtYXJrZXIuaGlkZSgpO1xuXHRcdFx0XHRsYXN0bXYgPSBmYWxzZTtcblx0XHRcdFx0bGFzdGV2ID0gZmFsc2U7XG5cdFx0XHRcdGRhdGEuaGVscGVyLmZpbmQoJy5qc3RyZWUtaWNvbicpLmZpcnN0KCkucmVtb3ZlQ2xhc3MoJ2pzdHJlZS1vaycpLmFkZENsYXNzKCdqc3RyZWUtZXInKTtcblx0XHRcdH0pXG5cdFx0XHQub24oJ2RuZF9zdG9wLnZha2F0YS5qc3RyZWUnLCBmdW5jdGlvbiAoZSwgZGF0YSkge1xuXHRcdFx0XHQkKCcuanN0cmVlLWRuZC1wYXJlbnQnKS5yZW1vdmVDbGFzcygnanN0cmVlLWRuZC1wYXJlbnQnKTtcblx0XHRcdFx0aWYob3BlbnRvKSB7IGNsZWFyVGltZW91dChvcGVudG8pOyB9XG5cdFx0XHRcdGlmKCFkYXRhIHx8ICFkYXRhLmRhdGEgfHwgIWRhdGEuZGF0YS5qc3RyZWUpIHsgcmV0dXJuOyB9XG5cdFx0XHRcdG1hcmtlci5oaWRlKCkuZGV0YWNoKCk7XG5cdFx0XHRcdHZhciBpLCBqLCBub2RlcyA9IFtdO1xuXHRcdFx0XHRpZihsYXN0bXYpIHtcblx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSBkYXRhLmRhdGEubm9kZXMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRub2Rlc1tpXSA9IGRhdGEuZGF0YS5vcmlnaW4gPyBkYXRhLmRhdGEub3JpZ2luLmdldF9ub2RlKGRhdGEuZGF0YS5ub2Rlc1tpXSkgOiBkYXRhLmRhdGEubm9kZXNbaV07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGxhc3Rtdi5pbnNbIGRhdGEuZGF0YS5vcmlnaW4gJiYgKGRhdGEuZGF0YS5vcmlnaW4uc2V0dGluZ3MuZG5kLmFsd2F5c19jb3B5IHx8IChkYXRhLmRhdGEub3JpZ2luLnNldHRpbmdzLmRuZC5jb3B5ICYmIChkYXRhLmV2ZW50Lm1ldGFLZXkgfHwgZGF0YS5ldmVudC5jdHJsS2V5KSkpID8gJ2NvcHlfbm9kZScgOiAnbW92ZV9ub2RlJyBdKG5vZGVzLCBsYXN0bXYucGFyLCBsYXN0bXYucG9zLCBmYWxzZSwgZmFsc2UsIGZhbHNlLCBkYXRhLmRhdGEub3JpZ2luKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRpID0gJChkYXRhLmV2ZW50LnRhcmdldCkuY2xvc2VzdCgnLmpzdHJlZScpO1xuXHRcdFx0XHRcdGlmKGkubGVuZ3RoICYmIGxhc3RlciAmJiBsYXN0ZXIuZXJyb3IgJiYgbGFzdGVyLmVycm9yID09PSAnY2hlY2snKSB7XG5cdFx0XHRcdFx0XHRpID0gaS5qc3RyZWUodHJ1ZSk7XG5cdFx0XHRcdFx0XHRpZihpKSB7XG5cdFx0XHRcdFx0XHRcdGkuc2V0dGluZ3MuY29yZS5lcnJvci5jYWxsKHRoaXMsIGxhc3Rlcik7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGxhc3RldiA9IGZhbHNlO1xuXHRcdFx0XHRsYXN0bXYgPSBmYWxzZTtcblx0XHRcdH0pXG5cdFx0XHQub24oJ2tleXVwLmpzdHJlZSBrZXlkb3duLmpzdHJlZScsIGZ1bmN0aW9uIChlLCBkYXRhKSB7XG5cdFx0XHRcdGRhdGEgPSAkLnZha2F0YS5kbmQuX2dldCgpO1xuXHRcdFx0XHRpZihkYXRhICYmIGRhdGEuZGF0YSAmJiBkYXRhLmRhdGEuanN0cmVlKSB7XG5cdFx0XHRcdFx0aWYgKGUudHlwZSA9PT0gXCJrZXl1cFwiICYmIGUud2hpY2ggPT09IDI3KSB7XG5cdFx0XHRcdFx0XHRpZiAob3BlbnRvKSB7IGNsZWFyVGltZW91dChvcGVudG8pOyB9XG5cdFx0XHRcdFx0XHRsYXN0bXYgPSBmYWxzZTtcblx0XHRcdFx0XHRcdGxhc3RlciA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0bGFzdGV2ID0gZmFsc2U7XG5cdFx0XHRcdFx0XHRvcGVudG8gPSBmYWxzZTtcblx0XHRcdFx0XHRcdG1hcmtlci5oaWRlKCkuZGV0YWNoKCk7XG5cdFx0XHRcdFx0XHQkLnZha2F0YS5kbmQuX2NsZWFuKCk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdGRhdGEuaGVscGVyLmZpbmQoJy5qc3RyZWUtY29weScpLmZpcnN0KClbIGRhdGEuZGF0YS5vcmlnaW4gJiYgKGRhdGEuZGF0YS5vcmlnaW4uc2V0dGluZ3MuZG5kLmFsd2F5c19jb3B5IHx8IChkYXRhLmRhdGEub3JpZ2luLnNldHRpbmdzLmRuZC5jb3B5ICYmIChlLm1ldGFLZXkgfHwgZS5jdHJsS2V5KSkpID8gJ3Nob3cnIDogJ2hpZGUnIF0oKTtcblx0XHRcdFx0XHRcdGlmKGxhc3Rldikge1xuXHRcdFx0XHRcdFx0XHRsYXN0ZXYubWV0YUtleSA9IGUubWV0YUtleTtcblx0XHRcdFx0XHRcdFx0bGFzdGV2LmN0cmxLZXkgPSBlLmN0cmxLZXk7XG5cdFx0XHRcdFx0XHRcdCQudmFrYXRhLmRuZC5fdHJpZ2dlcignbW92ZScsIGxhc3Rldik7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0fSk7XG5cblx0Ly8gaGVscGVyc1xuXHQoZnVuY3Rpb24gKCQpIHtcblx0XHQkLnZha2F0YS5odG1sID0ge1xuXHRcdFx0ZGl2IDogJCgnPGRpdj48L2Rpdj4nKSxcblx0XHRcdGVzY2FwZSA6IGZ1bmN0aW9uIChzdHIpIHtcblx0XHRcdFx0cmV0dXJuICQudmFrYXRhLmh0bWwuZGl2LnRleHQoc3RyKS5odG1sKCk7XG5cdFx0XHR9LFxuXHRcdFx0c3RyaXAgOiBmdW5jdGlvbiAoc3RyKSB7XG5cdFx0XHRcdHJldHVybiAkLnZha2F0YS5odG1sLmRpdi5lbXB0eSgpLmFwcGVuZCgkLnBhcnNlSFRNTChzdHIpKS50ZXh0KCk7XG5cdFx0XHR9XG5cdFx0fTtcblx0XHQvLyBwcml2YXRlIHZhcmlhYmxlXG5cdFx0dmFyIHZha2F0YV9kbmQgPSB7XG5cdFx0XHRlbGVtZW50XHQ6IGZhbHNlLFxuXHRcdFx0dGFyZ2V0XHQ6IGZhbHNlLFxuXHRcdFx0aXNfZG93blx0OiBmYWxzZSxcblx0XHRcdGlzX2RyYWdcdDogZmFsc2UsXG5cdFx0XHRoZWxwZXJcdDogZmFsc2UsXG5cdFx0XHRoZWxwZXJfdzogMCxcblx0XHRcdGRhdGFcdDogZmFsc2UsXG5cdFx0XHRpbml0X3hcdDogMCxcblx0XHRcdGluaXRfeVx0OiAwLFxuXHRcdFx0c2Nyb2xsX2w6IDAsXG5cdFx0XHRzY3JvbGxfdDogMCxcblx0XHRcdHNjcm9sbF9lOiBmYWxzZSxcblx0XHRcdHNjcm9sbF9pOiBmYWxzZSxcblx0XHRcdGlzX3RvdWNoOiBmYWxzZVxuXHRcdH07XG5cdFx0JC52YWthdGEuZG5kID0ge1xuXHRcdFx0c2V0dGluZ3MgOiB7XG5cdFx0XHRcdHNjcm9sbF9zcGVlZFx0XHQ6IDEwLFxuXHRcdFx0XHRzY3JvbGxfcHJveGltaXR5XHQ6IDIwLFxuXHRcdFx0XHRoZWxwZXJfbGVmdFx0XHRcdDogNSxcblx0XHRcdFx0aGVscGVyX3RvcFx0XHRcdDogMTAsXG5cdFx0XHRcdHRocmVzaG9sZFx0XHRcdDogNSxcblx0XHRcdFx0dGhyZXNob2xkX3RvdWNoXHRcdDogMTBcblx0XHRcdH0sXG5cdFx0XHRfdHJpZ2dlciA6IGZ1bmN0aW9uIChldmVudF9uYW1lLCBlLCBkYXRhKSB7XG5cdFx0XHRcdGlmIChkYXRhID09PSB1bmRlZmluZWQpIHtcblx0XHRcdFx0XHRkYXRhID0gJC52YWthdGEuZG5kLl9nZXQoKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRkYXRhLmV2ZW50ID0gZTtcblx0XHRcdFx0JChkb2N1bWVudCkudHJpZ2dlckhhbmRsZXIoXCJkbmRfXCIgKyBldmVudF9uYW1lICsgXCIudmFrYXRhXCIsIGRhdGEpO1xuXHRcdFx0fSxcblx0XHRcdF9nZXQgOiBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdHJldHVybiB7XG5cdFx0XHRcdFx0XCJkYXRhXCJcdFx0OiB2YWthdGFfZG5kLmRhdGEsXG5cdFx0XHRcdFx0XCJlbGVtZW50XCJcdDogdmFrYXRhX2RuZC5lbGVtZW50LFxuXHRcdFx0XHRcdFwiaGVscGVyXCJcdDogdmFrYXRhX2RuZC5oZWxwZXJcblx0XHRcdFx0fTtcblx0XHRcdH0sXG5cdFx0XHRfY2xlYW4gOiBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdGlmKHZha2F0YV9kbmQuaGVscGVyKSB7IHZha2F0YV9kbmQuaGVscGVyLnJlbW92ZSgpOyB9XG5cdFx0XHRcdGlmKHZha2F0YV9kbmQuc2Nyb2xsX2kpIHsgY2xlYXJJbnRlcnZhbCh2YWthdGFfZG5kLnNjcm9sbF9pKTsgdmFrYXRhX2RuZC5zY3JvbGxfaSA9IGZhbHNlOyB9XG5cdFx0XHRcdHZha2F0YV9kbmQgPSB7XG5cdFx0XHRcdFx0ZWxlbWVudFx0OiBmYWxzZSxcblx0XHRcdFx0XHR0YXJnZXRcdDogZmFsc2UsXG5cdFx0XHRcdFx0aXNfZG93blx0OiBmYWxzZSxcblx0XHRcdFx0XHRpc19kcmFnXHQ6IGZhbHNlLFxuXHRcdFx0XHRcdGhlbHBlclx0OiBmYWxzZSxcblx0XHRcdFx0XHRoZWxwZXJfdzogMCxcblx0XHRcdFx0XHRkYXRhXHQ6IGZhbHNlLFxuXHRcdFx0XHRcdGluaXRfeFx0OiAwLFxuXHRcdFx0XHRcdGluaXRfeVx0OiAwLFxuXHRcdFx0XHRcdHNjcm9sbF9sOiAwLFxuXHRcdFx0XHRcdHNjcm9sbF90OiAwLFxuXHRcdFx0XHRcdHNjcm9sbF9lOiBmYWxzZSxcblx0XHRcdFx0XHRzY3JvbGxfaTogZmFsc2UsXG5cdFx0XHRcdFx0aXNfdG91Y2g6IGZhbHNlXG5cdFx0XHRcdH07XG5cdFx0XHRcdGVsbSA9IG51bGw7XG5cdFx0XHRcdCQoZG9jdW1lbnQpLm9mZihcIm1vdXNlbW92ZS52YWthdGEuanN0cmVlIHRvdWNobW92ZS52YWthdGEuanN0cmVlXCIsICQudmFrYXRhLmRuZC5kcmFnKTtcblx0XHRcdFx0JChkb2N1bWVudCkub2ZmKFwibW91c2V1cC52YWthdGEuanN0cmVlIHRvdWNoZW5kLnZha2F0YS5qc3RyZWVcIiwgJC52YWthdGEuZG5kLnN0b3ApO1xuXHRcdFx0fSxcblx0XHRcdF9zY3JvbGwgOiBmdW5jdGlvbiAoaW5pdF9vbmx5KSB7XG5cdFx0XHRcdGlmKCF2YWthdGFfZG5kLnNjcm9sbF9lIHx8ICghdmFrYXRhX2RuZC5zY3JvbGxfbCAmJiAhdmFrYXRhX2RuZC5zY3JvbGxfdCkpIHtcblx0XHRcdFx0XHRpZih2YWthdGFfZG5kLnNjcm9sbF9pKSB7IGNsZWFySW50ZXJ2YWwodmFrYXRhX2RuZC5zY3JvbGxfaSk7IHZha2F0YV9kbmQuc2Nyb2xsX2kgPSBmYWxzZTsgfVxuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZighdmFrYXRhX2RuZC5zY3JvbGxfaSkge1xuXHRcdFx0XHRcdHZha2F0YV9kbmQuc2Nyb2xsX2kgPSBzZXRJbnRlcnZhbCgkLnZha2F0YS5kbmQuX3Njcm9sbCwgMTAwKTtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYoaW5pdF9vbmx5ID09PSB0cnVlKSB7IHJldHVybiBmYWxzZTsgfVxuXG5cdFx0XHRcdHZhciBpID0gdmFrYXRhX2RuZC5zY3JvbGxfZS5zY3JvbGxUb3AoKSxcblx0XHRcdFx0XHRqID0gdmFrYXRhX2RuZC5zY3JvbGxfZS5zY3JvbGxMZWZ0KCk7XG5cdFx0XHRcdHZha2F0YV9kbmQuc2Nyb2xsX2Uuc2Nyb2xsVG9wKGkgKyB2YWthdGFfZG5kLnNjcm9sbF90ICogJC52YWthdGEuZG5kLnNldHRpbmdzLnNjcm9sbF9zcGVlZCk7XG5cdFx0XHRcdHZha2F0YV9kbmQuc2Nyb2xsX2Uuc2Nyb2xsTGVmdChqICsgdmFrYXRhX2RuZC5zY3JvbGxfbCAqICQudmFrYXRhLmRuZC5zZXR0aW5ncy5zY3JvbGxfc3BlZWQpO1xuXHRcdFx0XHRpZihpICE9PSB2YWthdGFfZG5kLnNjcm9sbF9lLnNjcm9sbFRvcCgpIHx8IGogIT09IHZha2F0YV9kbmQuc2Nyb2xsX2Uuc2Nyb2xsTGVmdCgpKSB7XG5cdFx0XHRcdFx0LyoqXG5cdFx0XHRcdFx0ICogdHJpZ2dlcmVkIG9uIHRoZSBkb2N1bWVudCB3aGVuIGEgZHJhZyBjYXVzZXMgYW4gZWxlbWVudCB0byBzY3JvbGxcblx0XHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0XHQgKiBAcGx1Z2luIGRuZFxuXHRcdFx0XHRcdCAqIEBuYW1lIGRuZF9zY3JvbGwudmFrYXRhXG5cdFx0XHRcdFx0ICogQHBhcmFtIHtNaXhlZH0gZGF0YSBhbnkgZGF0YSBzdXBwbGllZCB3aXRoIHRoZSBjYWxsIHRvICQudmFrYXRhLmRuZC5zdGFydFxuXHRcdFx0XHRcdCAqIEBwYXJhbSB7RE9NfSBlbGVtZW50IHRoZSBET00gZWxlbWVudCBiZWluZyBkcmFnZ2VkXG5cdFx0XHRcdFx0ICogQHBhcmFtIHtqUXVlcnl9IGhlbHBlciB0aGUgaGVscGVyIHNob3duIG5leHQgdG8gdGhlIG1vdXNlXG5cdFx0XHRcdFx0ICogQHBhcmFtIHtqUXVlcnl9IGV2ZW50IHRoZSBlbGVtZW50IHRoYXQgaXMgc2Nyb2xsaW5nXG5cdFx0XHRcdFx0ICovXG5cdFx0XHRcdFx0JC52YWthdGEuZG5kLl90cmlnZ2VyKFwic2Nyb2xsXCIsIHZha2F0YV9kbmQuc2Nyb2xsX2UpO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0c3RhcnQgOiBmdW5jdGlvbiAoZSwgZGF0YSwgaHRtbCkge1xuXHRcdFx0XHRpZihlLnR5cGUgPT09IFwidG91Y2hzdGFydFwiICYmIGUub3JpZ2luYWxFdmVudCAmJiBlLm9yaWdpbmFsRXZlbnQuY2hhbmdlZFRvdWNoZXMgJiYgZS5vcmlnaW5hbEV2ZW50LmNoYW5nZWRUb3VjaGVzWzBdKSB7XG5cdFx0XHRcdFx0ZS5wYWdlWCA9IGUub3JpZ2luYWxFdmVudC5jaGFuZ2VkVG91Y2hlc1swXS5wYWdlWDtcblx0XHRcdFx0XHRlLnBhZ2VZID0gZS5vcmlnaW5hbEV2ZW50LmNoYW5nZWRUb3VjaGVzWzBdLnBhZ2VZO1xuXHRcdFx0XHRcdGUudGFyZ2V0ID0gZG9jdW1lbnQuZWxlbWVudEZyb21Qb2ludChlLm9yaWdpbmFsRXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0ucGFnZVggLSB3aW5kb3cucGFnZVhPZmZzZXQsIGUub3JpZ2luYWxFdmVudC5jaGFuZ2VkVG91Y2hlc1swXS5wYWdlWSAtIHdpbmRvdy5wYWdlWU9mZnNldCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYodmFrYXRhX2RuZC5pc19kcmFnKSB7ICQudmFrYXRhLmRuZC5zdG9wKHt9KTsgfVxuXHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdGUuY3VycmVudFRhcmdldC51bnNlbGVjdGFibGUgPSBcIm9uXCI7XG5cdFx0XHRcdFx0ZS5jdXJyZW50VGFyZ2V0Lm9uc2VsZWN0c3RhcnQgPSBmdW5jdGlvbigpIHsgcmV0dXJuIGZhbHNlOyB9O1xuXHRcdFx0XHRcdGlmKGUuY3VycmVudFRhcmdldC5zdHlsZSkge1xuXHRcdFx0XHRcdFx0ZS5jdXJyZW50VGFyZ2V0LnN0eWxlLnRvdWNoQWN0aW9uID0gXCJub25lXCI7XG5cdFx0XHRcdFx0XHRlLmN1cnJlbnRUYXJnZXQuc3R5bGUubXNUb3VjaEFjdGlvbiA9IFwibm9uZVwiO1xuXHRcdFx0XHRcdFx0ZS5jdXJyZW50VGFyZ2V0LnN0eWxlLk1velVzZXJTZWxlY3QgPSBcIm5vbmVcIjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gY2F0Y2goaWdub3JlKSB7IH1cblx0XHRcdFx0dmFrYXRhX2RuZC5pbml0X3hcdD0gZS5wYWdlWDtcblx0XHRcdFx0dmFrYXRhX2RuZC5pbml0X3lcdD0gZS5wYWdlWTtcblx0XHRcdFx0dmFrYXRhX2RuZC5kYXRhXHRcdD0gZGF0YTtcblx0XHRcdFx0dmFrYXRhX2RuZC5pc19kb3duXHQ9IHRydWU7XG5cdFx0XHRcdHZha2F0YV9kbmQuZWxlbWVudFx0PSBlLmN1cnJlbnRUYXJnZXQ7XG5cdFx0XHRcdHZha2F0YV9kbmQudGFyZ2V0XHQ9IGUudGFyZ2V0O1xuXHRcdFx0XHR2YWthdGFfZG5kLmlzX3RvdWNoXHQ9IGUudHlwZSA9PT0gXCJ0b3VjaHN0YXJ0XCI7XG5cdFx0XHRcdGlmKGh0bWwgIT09IGZhbHNlKSB7XG5cdFx0XHRcdFx0dmFrYXRhX2RuZC5oZWxwZXIgPSAkKFwiPGRpdiBpZD0ndmFrYXRhLWRuZCc+PC9kaXY+XCIpLmh0bWwoaHRtbCkuY3NzKHtcblx0XHRcdFx0XHRcdFwiZGlzcGxheVwiXHRcdDogXCJibG9ja1wiLFxuXHRcdFx0XHRcdFx0XCJtYXJnaW5cIlx0XHQ6IFwiMFwiLFxuXHRcdFx0XHRcdFx0XCJwYWRkaW5nXCJcdFx0OiBcIjBcIixcblx0XHRcdFx0XHRcdFwicG9zaXRpb25cIlx0XHQ6IFwiYWJzb2x1dGVcIixcblx0XHRcdFx0XHRcdFwidG9wXCJcdFx0XHQ6IFwiLTIwMDBweFwiLFxuXHRcdFx0XHRcdFx0XCJsaW5lSGVpZ2h0XCJcdDogXCIxNnB4XCIsXG5cdFx0XHRcdFx0XHRcInpJbmRleFwiXHRcdDogXCIxMDAwMFwiXG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0JChkb2N1bWVudCkub24oXCJtb3VzZW1vdmUudmFrYXRhLmpzdHJlZSB0b3VjaG1vdmUudmFrYXRhLmpzdHJlZVwiLCAkLnZha2F0YS5kbmQuZHJhZyk7XG5cdFx0XHRcdCQoZG9jdW1lbnQpLm9uKFwibW91c2V1cC52YWthdGEuanN0cmVlIHRvdWNoZW5kLnZha2F0YS5qc3RyZWVcIiwgJC52YWthdGEuZG5kLnN0b3ApO1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9LFxuXHRcdFx0ZHJhZyA6IGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdGlmKGUudHlwZSA9PT0gXCJ0b3VjaG1vdmVcIiAmJiBlLm9yaWdpbmFsRXZlbnQgJiYgZS5vcmlnaW5hbEV2ZW50LmNoYW5nZWRUb3VjaGVzICYmIGUub3JpZ2luYWxFdmVudC5jaGFuZ2VkVG91Y2hlc1swXSkge1xuXHRcdFx0XHRcdGUucGFnZVggPSBlLm9yaWdpbmFsRXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0ucGFnZVg7XG5cdFx0XHRcdFx0ZS5wYWdlWSA9IGUub3JpZ2luYWxFdmVudC5jaGFuZ2VkVG91Y2hlc1swXS5wYWdlWTtcblx0XHRcdFx0XHRlLnRhcmdldCA9IGRvY3VtZW50LmVsZW1lbnRGcm9tUG9pbnQoZS5vcmlnaW5hbEV2ZW50LmNoYW5nZWRUb3VjaGVzWzBdLnBhZ2VYIC0gd2luZG93LnBhZ2VYT2Zmc2V0LCBlLm9yaWdpbmFsRXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0ucGFnZVkgLSB3aW5kb3cucGFnZVlPZmZzZXQpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKCF2YWthdGFfZG5kLmlzX2Rvd24pIHsgcmV0dXJuOyB9XG5cdFx0XHRcdGlmKCF2YWthdGFfZG5kLmlzX2RyYWcpIHtcblx0XHRcdFx0XHRpZihcblx0XHRcdFx0XHRcdE1hdGguYWJzKGUucGFnZVggLSB2YWthdGFfZG5kLmluaXRfeCkgPiAodmFrYXRhX2RuZC5pc190b3VjaCA/ICQudmFrYXRhLmRuZC5zZXR0aW5ncy50aHJlc2hvbGRfdG91Y2ggOiAkLnZha2F0YS5kbmQuc2V0dGluZ3MudGhyZXNob2xkKSB8fFxuXHRcdFx0XHRcdFx0TWF0aC5hYnMoZS5wYWdlWSAtIHZha2F0YV9kbmQuaW5pdF95KSA+ICh2YWthdGFfZG5kLmlzX3RvdWNoID8gJC52YWthdGEuZG5kLnNldHRpbmdzLnRocmVzaG9sZF90b3VjaCA6ICQudmFrYXRhLmRuZC5zZXR0aW5ncy50aHJlc2hvbGQpXG5cdFx0XHRcdFx0KSB7XG5cdFx0XHRcdFx0XHRpZih2YWthdGFfZG5kLmhlbHBlcikge1xuXHRcdFx0XHRcdFx0XHR2YWthdGFfZG5kLmhlbHBlci5hcHBlbmRUbyhkb2N1bWVudC5ib2R5KTtcblx0XHRcdFx0XHRcdFx0dmFrYXRhX2RuZC5oZWxwZXJfdyA9IHZha2F0YV9kbmQuaGVscGVyLm91dGVyV2lkdGgoKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdHZha2F0YV9kbmQuaXNfZHJhZyA9IHRydWU7XG5cdFx0XHRcdFx0XHQkKHZha2F0YV9kbmQudGFyZ2V0KS5vbmUoJ2NsaWNrLnZha2F0YScsIGZhbHNlKTtcblx0XHRcdFx0XHRcdC8qKlxuXHRcdFx0XHRcdFx0ICogdHJpZ2dlcmVkIG9uIHRoZSBkb2N1bWVudCB3aGVuIGEgZHJhZyBzdGFydHNcblx0XHRcdFx0XHRcdCAqIEBldmVudFxuXHRcdFx0XHRcdFx0ICogQHBsdWdpbiBkbmRcblx0XHRcdFx0XHRcdCAqIEBuYW1lIGRuZF9zdGFydC52YWthdGFcblx0XHRcdFx0XHRcdCAqIEBwYXJhbSB7TWl4ZWR9IGRhdGEgYW55IGRhdGEgc3VwcGxpZWQgd2l0aCB0aGUgY2FsbCB0byAkLnZha2F0YS5kbmQuc3RhcnRcblx0XHRcdFx0XHRcdCAqIEBwYXJhbSB7RE9NfSBlbGVtZW50IHRoZSBET00gZWxlbWVudCBiZWluZyBkcmFnZ2VkXG5cdFx0XHRcdFx0XHQgKiBAcGFyYW0ge2pRdWVyeX0gaGVscGVyIHRoZSBoZWxwZXIgc2hvd24gbmV4dCB0byB0aGUgbW91c2Vcblx0XHRcdFx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBldmVudCB0aGUgZXZlbnQgdGhhdCBjYXVzZWQgdGhlIHN0YXJ0IChwcm9iYWJseSBtb3VzZW1vdmUpXG5cdFx0XHRcdFx0XHQgKi9cblx0XHRcdFx0XHRcdCQudmFrYXRhLmRuZC5fdHJpZ2dlcihcInN0YXJ0XCIsIGUpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbHNlIHsgcmV0dXJuOyB9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHR2YXIgZCAgPSBmYWxzZSwgdyAgPSBmYWxzZSxcblx0XHRcdFx0XHRkaCA9IGZhbHNlLCB3aCA9IGZhbHNlLFxuXHRcdFx0XHRcdGR3ID0gZmFsc2UsIHd3ID0gZmFsc2UsXG5cdFx0XHRcdFx0ZHQgPSBmYWxzZSwgZGwgPSBmYWxzZSxcblx0XHRcdFx0XHRodCA9IGZhbHNlLCBobCA9IGZhbHNlO1xuXG5cdFx0XHRcdHZha2F0YV9kbmQuc2Nyb2xsX3QgPSAwO1xuXHRcdFx0XHR2YWthdGFfZG5kLnNjcm9sbF9sID0gMDtcblx0XHRcdFx0dmFrYXRhX2RuZC5zY3JvbGxfZSA9IGZhbHNlO1xuXHRcdFx0XHQkKCQoZS50YXJnZXQpLnBhcmVudHNVbnRpbChcImJvZHlcIikuYWRkQmFjaygpLmdldCgpLnJldmVyc2UoKSlcblx0XHRcdFx0XHQuZmlsdGVyKGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRcdHJldHVyblx0KC9eYXV0b3xzY3JvbGwkLykudGVzdCgkKHRoaXMpLmNzcyhcIm92ZXJmbG93XCIpKSAmJlxuXHRcdFx0XHRcdFx0XHRcdCh0aGlzLnNjcm9sbEhlaWdodCA+IHRoaXMub2Zmc2V0SGVpZ2h0IHx8IHRoaXMuc2Nyb2xsV2lkdGggPiB0aGlzLm9mZnNldFdpZHRoKTtcblx0XHRcdFx0XHR9KVxuXHRcdFx0XHRcdC5lYWNoKGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRcdHZhciB0ID0gJCh0aGlzKSwgbyA9IHQub2Zmc2V0KCk7XG5cdFx0XHRcdFx0XHRpZih0aGlzLnNjcm9sbEhlaWdodCA+IHRoaXMub2Zmc2V0SGVpZ2h0KSB7XG5cdFx0XHRcdFx0XHRcdGlmKG8udG9wICsgdC5oZWlnaHQoKSAtIGUucGFnZVkgPCAkLnZha2F0YS5kbmQuc2V0dGluZ3Muc2Nyb2xsX3Byb3hpbWl0eSlcdHsgdmFrYXRhX2RuZC5zY3JvbGxfdCA9IDE7IH1cblx0XHRcdFx0XHRcdFx0aWYoZS5wYWdlWSAtIG8udG9wIDwgJC52YWthdGEuZG5kLnNldHRpbmdzLnNjcm9sbF9wcm94aW1pdHkpXHRcdFx0XHR7IHZha2F0YV9kbmQuc2Nyb2xsX3QgPSAtMTsgfVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYodGhpcy5zY3JvbGxXaWR0aCA+IHRoaXMub2Zmc2V0V2lkdGgpIHtcblx0XHRcdFx0XHRcdFx0aWYoby5sZWZ0ICsgdC53aWR0aCgpIC0gZS5wYWdlWCA8ICQudmFrYXRhLmRuZC5zZXR0aW5ncy5zY3JvbGxfcHJveGltaXR5KVx0eyB2YWthdGFfZG5kLnNjcm9sbF9sID0gMTsgfVxuXHRcdFx0XHRcdFx0XHRpZihlLnBhZ2VYIC0gby5sZWZ0IDwgJC52YWthdGEuZG5kLnNldHRpbmdzLnNjcm9sbF9wcm94aW1pdHkpXHRcdFx0XHR7IHZha2F0YV9kbmQuc2Nyb2xsX2wgPSAtMTsgfVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYodmFrYXRhX2RuZC5zY3JvbGxfdCB8fCB2YWthdGFfZG5kLnNjcm9sbF9sKSB7XG5cdFx0XHRcdFx0XHRcdHZha2F0YV9kbmQuc2Nyb2xsX2UgPSAkKHRoaXMpO1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0aWYoIXZha2F0YV9kbmQuc2Nyb2xsX2UpIHtcblx0XHRcdFx0XHRkICA9ICQoZG9jdW1lbnQpOyB3ID0gJCh3aW5kb3cpO1xuXHRcdFx0XHRcdGRoID0gZC5oZWlnaHQoKTsgd2ggPSB3LmhlaWdodCgpO1xuXHRcdFx0XHRcdGR3ID0gZC53aWR0aCgpOyB3dyA9IHcud2lkdGgoKTtcblx0XHRcdFx0XHRkdCA9IGQuc2Nyb2xsVG9wKCk7IGRsID0gZC5zY3JvbGxMZWZ0KCk7XG5cdFx0XHRcdFx0aWYoZGggPiB3aCAmJiBlLnBhZ2VZIC0gZHQgPCAkLnZha2F0YS5kbmQuc2V0dGluZ3Muc2Nyb2xsX3Byb3hpbWl0eSlcdFx0eyB2YWthdGFfZG5kLnNjcm9sbF90ID0gLTE7ICB9XG5cdFx0XHRcdFx0aWYoZGggPiB3aCAmJiB3aCAtIChlLnBhZ2VZIC0gZHQpIDwgJC52YWthdGEuZG5kLnNldHRpbmdzLnNjcm9sbF9wcm94aW1pdHkpXHR7IHZha2F0YV9kbmQuc2Nyb2xsX3QgPSAxOyB9XG5cdFx0XHRcdFx0aWYoZHcgPiB3dyAmJiBlLnBhZ2VYIC0gZGwgPCAkLnZha2F0YS5kbmQuc2V0dGluZ3Muc2Nyb2xsX3Byb3hpbWl0eSlcdFx0eyB2YWthdGFfZG5kLnNjcm9sbF9sID0gLTE7IH1cblx0XHRcdFx0XHRpZihkdyA+IHd3ICYmIHd3IC0gKGUucGFnZVggLSBkbCkgPCAkLnZha2F0YS5kbmQuc2V0dGluZ3Muc2Nyb2xsX3Byb3hpbWl0eSlcdHsgdmFrYXRhX2RuZC5zY3JvbGxfbCA9IDE7IH1cblx0XHRcdFx0XHRpZih2YWthdGFfZG5kLnNjcm9sbF90IHx8IHZha2F0YV9kbmQuc2Nyb2xsX2wpIHtcblx0XHRcdFx0XHRcdHZha2F0YV9kbmQuc2Nyb2xsX2UgPSBkO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRpZih2YWthdGFfZG5kLnNjcm9sbF9lKSB7ICQudmFrYXRhLmRuZC5fc2Nyb2xsKHRydWUpOyB9XG5cblx0XHRcdFx0aWYodmFrYXRhX2RuZC5oZWxwZXIpIHtcblx0XHRcdFx0XHRodCA9IHBhcnNlSW50KGUucGFnZVkgKyAkLnZha2F0YS5kbmQuc2V0dGluZ3MuaGVscGVyX3RvcCwgMTApO1xuXHRcdFx0XHRcdGhsID0gcGFyc2VJbnQoZS5wYWdlWCArICQudmFrYXRhLmRuZC5zZXR0aW5ncy5oZWxwZXJfbGVmdCwgMTApO1xuXHRcdFx0XHRcdGlmKGRoICYmIGh0ICsgMjUgPiBkaCkgeyBodCA9IGRoIC0gNTA7IH1cblx0XHRcdFx0XHRpZihkdyAmJiBobCArIHZha2F0YV9kbmQuaGVscGVyX3cgPiBkdykgeyBobCA9IGR3IC0gKHZha2F0YV9kbmQuaGVscGVyX3cgKyAyKTsgfVxuXHRcdFx0XHRcdHZha2F0YV9kbmQuaGVscGVyLmNzcyh7XG5cdFx0XHRcdFx0XHRsZWZ0XHQ6IGhsICsgXCJweFwiLFxuXHRcdFx0XHRcdFx0dG9wXHRcdDogaHQgKyBcInB4XCJcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIG9uIHRoZSBkb2N1bWVudCB3aGVuIGEgZHJhZyBpcyBpbiBwcm9ncmVzc1xuXHRcdFx0XHQgKiBAZXZlbnRcblx0XHRcdFx0ICogQHBsdWdpbiBkbmRcblx0XHRcdFx0ICogQG5hbWUgZG5kX21vdmUudmFrYXRhXG5cdFx0XHRcdCAqIEBwYXJhbSB7TWl4ZWR9IGRhdGEgYW55IGRhdGEgc3VwcGxpZWQgd2l0aCB0aGUgY2FsbCB0byAkLnZha2F0YS5kbmQuc3RhcnRcblx0XHRcdFx0ICogQHBhcmFtIHtET019IGVsZW1lbnQgdGhlIERPTSBlbGVtZW50IGJlaW5nIGRyYWdnZWRcblx0XHRcdFx0ICogQHBhcmFtIHtqUXVlcnl9IGhlbHBlciB0aGUgaGVscGVyIHNob3duIG5leHQgdG8gdGhlIG1vdXNlXG5cdFx0XHRcdCAqIEBwYXJhbSB7T2JqZWN0fSBldmVudCB0aGUgZXZlbnQgdGhhdCBjYXVzZWQgdGhpcyB0byB0cmlnZ2VyIChtb3N0IGxpa2VseSBtb3VzZW1vdmUpXG5cdFx0XHRcdCAqL1xuXHRcdFx0XHQkLnZha2F0YS5kbmQuX3RyaWdnZXIoXCJtb3ZlXCIsIGUpO1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9LFxuXHRcdFx0c3RvcCA6IGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRcdGlmKGUudHlwZSA9PT0gXCJ0b3VjaGVuZFwiICYmIGUub3JpZ2luYWxFdmVudCAmJiBlLm9yaWdpbmFsRXZlbnQuY2hhbmdlZFRvdWNoZXMgJiYgZS5vcmlnaW5hbEV2ZW50LmNoYW5nZWRUb3VjaGVzWzBdKSB7XG5cdFx0XHRcdFx0ZS5wYWdlWCA9IGUub3JpZ2luYWxFdmVudC5jaGFuZ2VkVG91Y2hlc1swXS5wYWdlWDtcblx0XHRcdFx0XHRlLnBhZ2VZID0gZS5vcmlnaW5hbEV2ZW50LmNoYW5nZWRUb3VjaGVzWzBdLnBhZ2VZO1xuXHRcdFx0XHRcdGUudGFyZ2V0ID0gZG9jdW1lbnQuZWxlbWVudEZyb21Qb2ludChlLm9yaWdpbmFsRXZlbnQuY2hhbmdlZFRvdWNoZXNbMF0ucGFnZVggLSB3aW5kb3cucGFnZVhPZmZzZXQsIGUub3JpZ2luYWxFdmVudC5jaGFuZ2VkVG91Y2hlc1swXS5wYWdlWSAtIHdpbmRvdy5wYWdlWU9mZnNldCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYodmFrYXRhX2RuZC5pc19kcmFnKSB7XG5cdFx0XHRcdFx0LyoqXG5cdFx0XHRcdFx0ICogdHJpZ2dlcmVkIG9uIHRoZSBkb2N1bWVudCB3aGVuIGEgZHJhZyBzdG9wcyAodGhlIGRyYWdnZWQgZWxlbWVudCBpcyBkcm9wcGVkKVxuXHRcdFx0XHRcdCAqIEBldmVudFxuXHRcdFx0XHRcdCAqIEBwbHVnaW4gZG5kXG5cdFx0XHRcdFx0ICogQG5hbWUgZG5kX3N0b3AudmFrYXRhXG5cdFx0XHRcdFx0ICogQHBhcmFtIHtNaXhlZH0gZGF0YSBhbnkgZGF0YSBzdXBwbGllZCB3aXRoIHRoZSBjYWxsIHRvICQudmFrYXRhLmRuZC5zdGFydFxuXHRcdFx0XHRcdCAqIEBwYXJhbSB7RE9NfSBlbGVtZW50IHRoZSBET00gZWxlbWVudCBiZWluZyBkcmFnZ2VkXG5cdFx0XHRcdFx0ICogQHBhcmFtIHtqUXVlcnl9IGhlbHBlciB0aGUgaGVscGVyIHNob3duIG5leHQgdG8gdGhlIG1vdXNlXG5cdFx0XHRcdFx0ICogQHBhcmFtIHtPYmplY3R9IGV2ZW50IHRoZSBldmVudCB0aGF0IGNhdXNlZCB0aGUgc3RvcFxuXHRcdFx0XHRcdCAqL1xuXHRcdFx0XHRcdGlmIChlLnRhcmdldCAhPT0gdmFrYXRhX2RuZC50YXJnZXQpIHtcblx0XHRcdFx0XHRcdCQodmFrYXRhX2RuZC50YXJnZXQpLm9mZignY2xpY2sudmFrYXRhJyk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdCQudmFrYXRhLmRuZC5fdHJpZ2dlcihcInN0b3BcIiwgZSk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0aWYoZS50eXBlID09PSBcInRvdWNoZW5kXCIgJiYgZS50YXJnZXQgPT09IHZha2F0YV9kbmQudGFyZ2V0KSB7XG5cdFx0XHRcdFx0XHR2YXIgdG8gPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHsgJChlLnRhcmdldCkudHJpZ2dlcignY2xpY2snKTsgfSwgMTAwKTtcblx0XHRcdFx0XHRcdCQoZS50YXJnZXQpLm9uZSgnY2xpY2snLCBmdW5jdGlvbigpIHsgaWYodG8pIHsgY2xlYXJUaW1lb3V0KHRvKTsgfSB9KTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0JC52YWthdGEuZG5kLl9jbGVhbigpO1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fTtcblx0fSgkKSk7XG5cblx0Ly8gaW5jbHVkZSB0aGUgZG5kIHBsdWdpbiBieSBkZWZhdWx0XG5cdC8vICQuanN0cmVlLmRlZmF1bHRzLnBsdWdpbnMucHVzaChcImRuZFwiKTtcblxuXG4vKipcbiAqICMjIyBNYXNzbG9hZCBwbHVnaW5cbiAqXG4gKiBBZGRzIG1hc3Nsb2FkIGZ1bmN0aW9uYWxpdHkgdG8ganNUcmVlLCBzbyB0aGF0IG11bHRpcGxlIG5vZGVzIGNhbiBiZSBsb2FkZWQgaW4gYSBzaW5nbGUgcmVxdWVzdCAob25seSB1c2VmdWwgd2l0aCBsYXp5IGxvYWRpbmcpLlxuICovXG5cblx0LyoqXG5cdCAqIG1hc3Nsb2FkIGNvbmZpZ3VyYXRpb25cblx0ICpcblx0ICogSXQgaXMgcG9zc2libGUgdG8gc2V0IHRoaXMgdG8gYSBzdGFuZGFyZCBqUXVlcnktbGlrZSBBSkFYIGNvbmZpZy5cblx0ICogSW4gYWRkaXRpb24gdG8gdGhlIHN0YW5kYXJkIGpRdWVyeSBhamF4IG9wdGlvbnMgaGVyZSB5b3UgY2FuIHN1cHBseSBmdW5jdGlvbnMgZm9yIGBkYXRhYCBhbmQgYHVybGAsIHRoZSBmdW5jdGlvbnMgd2lsbCBiZSBydW4gaW4gdGhlIGN1cnJlbnQgaW5zdGFuY2UncyBzY29wZSBhbmQgYSBwYXJhbSB3aWxsIGJlIHBhc3NlZCBpbmRpY2F0aW5nIHdoaWNoIG5vZGUgSURzIG5lZWQgdG8gYmUgbG9hZGVkLCB0aGUgcmV0dXJuIHZhbHVlIG9mIHRob3NlIGZ1bmN0aW9ucyB3aWxsIGJlIHVzZWQuXG5cdCAqXG5cdCAqIFlvdSBjYW4gYWxzbyBzZXQgdGhpcyB0byBhIGZ1bmN0aW9uLCB0aGF0IGZ1bmN0aW9uIHdpbGwgcmVjZWl2ZSB0aGUgbm9kZSBJRHMgYmVpbmcgbG9hZGVkIGFzIGFyZ3VtZW50IGFuZCBhIHNlY29uZCBwYXJhbSB3aGljaCBpcyBhIGZ1bmN0aW9uIChjYWxsYmFjaykgd2hpY2ggc2hvdWxkIGJlIGNhbGxlZCB3aXRoIHRoZSByZXN1bHQuXG5cdCAqXG5cdCAqIEJvdGggdGhlIEFKQVggYW5kIHRoZSBmdW5jdGlvbiBhcHByb2FjaCByZWx5IG9uIHRoZSBzYW1lIHJldHVybiB2YWx1ZSAtIGFuIG9iamVjdCB3aGVyZSB0aGUga2V5cyBhcmUgdGhlIG5vZGUgSURzLCBhbmQgdGhlIHZhbHVlIGlzIHRoZSBjaGlsZHJlbiBvZiB0aGF0IG5vZGUgYXMgYW4gYXJyYXkuXG5cdCAqXG5cdCAqXHR7XG5cdCAqXHRcdFwiaWQxXCIgOiBbeyBcInRleHRcIiA6IFwiQ2hpbGQgb2YgSUQxXCIsIFwiaWRcIiA6IFwiYzFcIiB9LCB7IFwidGV4dFwiIDogXCJBbm90aGVyIGNoaWxkIG9mIElEMVwiLCBcImlkXCIgOiBcImMyXCIgfV0sXG5cdCAqXHRcdFwiaWQyXCIgOiBbeyBcInRleHRcIiA6IFwiQ2hpbGQgb2YgSUQyXCIsIFwiaWRcIiA6IFwiYzNcIiB9XVxuXHQgKlx0fVxuXHQgKiBcblx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMubWFzc2xvYWRcblx0ICogQHBsdWdpbiBtYXNzbG9hZFxuXHQgKi9cblx0JC5qc3RyZWUuZGVmYXVsdHMubWFzc2xvYWQgPSBudWxsO1xuXHQkLmpzdHJlZS5wbHVnaW5zLm1hc3Nsb2FkID0gZnVuY3Rpb24gKG9wdGlvbnMsIHBhcmVudCkge1xuXHRcdHRoaXMuaW5pdCA9IGZ1bmN0aW9uIChlbCwgb3B0aW9ucykge1xuXHRcdFx0dGhpcy5fZGF0YS5tYXNzbG9hZCA9IHt9O1xuXHRcdFx0cGFyZW50LmluaXQuY2FsbCh0aGlzLCBlbCwgb3B0aW9ucyk7XG5cdFx0fTtcblx0XHR0aGlzLl9sb2FkX25vZGVzID0gZnVuY3Rpb24gKG5vZGVzLCBjYWxsYmFjaywgaXNfY2FsbGJhY2ssIGZvcmNlX3JlbG9hZCkge1xuXHRcdFx0dmFyIHMgPSB0aGlzLnNldHRpbmdzLm1hc3Nsb2FkLFx0XHRcdFx0XG5cdFx0XHRcdHRvTG9hZCA9IFtdLFxuXHRcdFx0XHRtID0gdGhpcy5fbW9kZWwuZGF0YSxcblx0XHRcdFx0aSwgaiwgZG9tO1xuXHRcdFx0aWYgKCFpc19jYWxsYmFjaykge1xuXHRcdFx0XHRmb3IoaSA9IDAsIGogPSBub2Rlcy5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRpZighbVtub2Rlc1tpXV0gfHwgKCAoIW1bbm9kZXNbaV1dLnN0YXRlLmxvYWRlZCAmJiAhbVtub2Rlc1tpXV0uc3RhdGUuZmFpbGVkKSB8fCBmb3JjZV9yZWxvYWQpICkge1xuXHRcdFx0XHRcdFx0dG9Mb2FkLnB1c2gobm9kZXNbaV0pO1xuXHRcdFx0XHRcdFx0ZG9tID0gdGhpcy5nZXRfbm9kZShub2Rlc1tpXSwgdHJ1ZSk7XG5cdFx0XHRcdFx0XHRpZiAoZG9tICYmIGRvbS5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0ZG9tLmFkZENsYXNzKFwianN0cmVlLWxvYWRpbmdcIikuYXR0cignYXJpYS1idXN5Jyx0cnVlKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0dGhpcy5fZGF0YS5tYXNzbG9hZCA9IHt9O1xuXHRcdFx0XHRpZiAodG9Mb2FkLmxlbmd0aCkge1xuXHRcdFx0XHRcdGlmKCQudmFrYXRhLmlzX2Z1bmN0aW9uKHMpKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gcy5jYWxsKHRoaXMsIHRvTG9hZCwgZnVuY3Rpb24gKGRhdGEpIHtcblx0XHRcdFx0XHRcdFx0dmFyIGksIGo7XG5cdFx0XHRcdFx0XHRcdGlmKGRhdGEpIHtcblx0XHRcdFx0XHRcdFx0XHRmb3IoaSBpbiBkYXRhKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZihkYXRhLmhhc093blByb3BlcnR5KGkpKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGEubWFzc2xvYWRbaV0gPSBkYXRhW2ldO1xuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSBub2Rlcy5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHRcdFx0XHRkb20gPSB0aGlzLmdldF9ub2RlKG5vZGVzW2ldLCB0cnVlKTtcblx0XHRcdFx0XHRcdFx0XHRpZiAoZG9tICYmIGRvbS5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0XHRcdGRvbS5yZW1vdmVDbGFzcyhcImpzdHJlZS1sb2FkaW5nXCIpLmF0dHIoJ2FyaWEtYnVzeScsZmFsc2UpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRwYXJlbnQuX2xvYWRfbm9kZXMuY2FsbCh0aGlzLCBub2RlcywgY2FsbGJhY2ssIGlzX2NhbGxiYWNrLCBmb3JjZV9yZWxvYWQpO1xuXHRcdFx0XHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYodHlwZW9mIHMgPT09ICdvYmplY3QnICYmIHMgJiYgcy51cmwpIHtcblx0XHRcdFx0XHRcdHMgPSAkLmV4dGVuZCh0cnVlLCB7fSwgcyk7XG5cdFx0XHRcdFx0XHRpZigkLnZha2F0YS5pc19mdW5jdGlvbihzLnVybCkpIHtcblx0XHRcdFx0XHRcdFx0cy51cmwgPSBzLnVybC5jYWxsKHRoaXMsIHRvTG9hZCk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRpZigkLnZha2F0YS5pc19mdW5jdGlvbihzLmRhdGEpKSB7XG5cdFx0XHRcdFx0XHRcdHMuZGF0YSA9IHMuZGF0YS5jYWxsKHRoaXMsIHRvTG9hZCk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRyZXR1cm4gJC5hamF4KHMpXG5cdFx0XHRcdFx0XHRcdC5kb25lKGZ1bmN0aW9uIChkYXRhLHQseCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0dmFyIGksIGo7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZihkYXRhKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGZvcihpIGluIGRhdGEpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRpZihkYXRhLmhhc093blByb3BlcnR5KGkpKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR0aGlzLl9kYXRhLm1hc3Nsb2FkW2ldID0gZGF0YVtpXTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdGZvcihpID0gMCwgaiA9IG5vZGVzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRkb20gPSB0aGlzLmdldF9ub2RlKG5vZGVzW2ldLCB0cnVlKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKGRvbSAmJiBkb20ubGVuZ3RoKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0ZG9tLnJlbW92ZUNsYXNzKFwianN0cmVlLWxvYWRpbmdcIikuYXR0cignYXJpYS1idXN5JyxmYWxzZSk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdHBhcmVudC5fbG9hZF9ub2Rlcy5jYWxsKHRoaXMsIG5vZGVzLCBjYWxsYmFjaywgaXNfY2FsbGJhY2ssIGZvcmNlX3JlbG9hZCk7XG5cdFx0XHRcdFx0XHRcdFx0fS5iaW5kKHRoaXMpKVxuXHRcdFx0XHRcdFx0XHQuZmFpbChmdW5jdGlvbiAoZikge1xuXHRcdFx0XHRcdFx0XHRcdFx0cGFyZW50Ll9sb2FkX25vZGVzLmNhbGwodGhpcywgbm9kZXMsIGNhbGxiYWNrLCBpc19jYWxsYmFjaywgZm9yY2VfcmVsb2FkKTtcblx0XHRcdFx0XHRcdFx0XHR9LmJpbmQodGhpcykpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHBhcmVudC5fbG9hZF9ub2Rlcy5jYWxsKHRoaXMsIG5vZGVzLCBjYWxsYmFjaywgaXNfY2FsbGJhY2ssIGZvcmNlX3JlbG9hZCk7XG5cdFx0fTtcblx0XHR0aGlzLl9sb2FkX25vZGUgPSBmdW5jdGlvbiAob2JqLCBjYWxsYmFjaykge1xuXHRcdFx0dmFyIGRhdGEgPSB0aGlzLl9kYXRhLm1hc3Nsb2FkW29iai5pZF0sXG5cdFx0XHRcdHJzbHQgPSBudWxsLCBkb207XG5cdFx0XHRpZihkYXRhKSB7XG5cdFx0XHRcdHJzbHQgPSB0aGlzW3R5cGVvZiBkYXRhID09PSAnc3RyaW5nJyA/ICdfYXBwZW5kX2h0bWxfZGF0YScgOiAnX2FwcGVuZF9qc29uX2RhdGEnXShcblx0XHRcdFx0XHRvYmosXG5cdFx0XHRcdFx0dHlwZW9mIGRhdGEgPT09ICdzdHJpbmcnID8gJCgkLnBhcnNlSFRNTChkYXRhKSkuZmlsdGVyKGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMubm9kZVR5cGUgIT09IDM7IH0pIDogZGF0YSxcblx0XHRcdFx0XHRmdW5jdGlvbiAoc3RhdHVzKSB7IGNhbGxiYWNrLmNhbGwodGhpcywgc3RhdHVzKTsgfVxuXHRcdFx0XHQpO1xuXHRcdFx0XHRkb20gPSB0aGlzLmdldF9ub2RlKG9iai5pZCwgdHJ1ZSk7XG5cdFx0XHRcdGlmIChkb20gJiYgZG9tLmxlbmd0aCkge1xuXHRcdFx0XHRcdGRvbS5yZW1vdmVDbGFzcyhcImpzdHJlZS1sb2FkaW5nXCIpLmF0dHIoJ2FyaWEtYnVzeScsZmFsc2UpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGRlbGV0ZSB0aGlzLl9kYXRhLm1hc3Nsb2FkW29iai5pZF07XG5cdFx0XHRcdHJldHVybiByc2x0O1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHBhcmVudC5fbG9hZF9ub2RlLmNhbGwodGhpcywgb2JqLCBjYWxsYmFjayk7XG5cdFx0fTtcblx0fTtcblxuXG4vKipcbiAqICMjIyBTZWFyY2ggcGx1Z2luXG4gKlxuICogQWRkcyBzZWFyY2ggZnVuY3Rpb25hbGl0eSB0byBqc1RyZWUuXG4gKi9cblxuXHQvKipcblx0ICogc3RvcmVzIGFsbCBkZWZhdWx0cyBmb3IgdGhlIHNlYXJjaCBwbHVnaW5cblx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuc2VhcmNoXG5cdCAqIEBwbHVnaW4gc2VhcmNoXG5cdCAqL1xuXHQkLmpzdHJlZS5kZWZhdWx0cy5zZWFyY2ggPSB7XG5cdFx0LyoqXG5cdFx0ICogYSBqUXVlcnktbGlrZSBBSkFYIGNvbmZpZywgd2hpY2gganN0cmVlIHVzZXMgaWYgYSBzZXJ2ZXIgc2hvdWxkIGJlIHF1ZXJpZWQgZm9yIHJlc3VsdHMuXG5cdFx0ICpcblx0XHQgKiBBIGBzdHJgICh3aGljaCBpcyB0aGUgc2VhcmNoIHN0cmluZykgcGFyYW1ldGVyIHdpbGwgYmUgYWRkZWQgd2l0aCB0aGUgcmVxdWVzdCwgYW4gb3B0aW9uYWwgYGluc2lkZWAgcGFyYW1ldGVyIHdpbGwgYmUgYWRkZWQgaWYgdGhlIHNlYXJjaCBpcyBsaW1pdGVkIHRvIGEgbm9kZSBpZC4gVGhlIGV4cGVjdGVkIHJlc3VsdCBpcyBhIEpTT04gYXJyYXkgd2l0aCBub2RlcyB0aGF0IG5lZWQgdG8gYmUgb3BlbmVkIHNvIHRoYXQgbWF0Y2hpbmcgbm9kZXMgd2lsbCBiZSByZXZlYWxlZC5cblx0XHQgKiBMZWF2ZSB0aGlzIHNldHRpbmcgYXMgYGZhbHNlYCB0byBub3QgcXVlcnkgdGhlIHNlcnZlci4gWW91IGNhbiBhbHNvIHNldCB0aGlzIHRvIGEgZnVuY3Rpb24sIHdoaWNoIHdpbGwgYmUgaW52b2tlZCBpbiB0aGUgaW5zdGFuY2UncyBzY29wZSBhbmQgcmVjZWl2ZSAzIHBhcmFtZXRlcnMgLSB0aGUgc2VhcmNoIHN0cmluZywgdGhlIGNhbGxiYWNrIHRvIGNhbGwgd2l0aCB0aGUgYXJyYXkgb2Ygbm9kZXMgdG8gbG9hZCwgYW5kIHRoZSBvcHRpb25hbCBub2RlIElEIHRvIGxpbWl0IHRoZSBzZWFyY2ggdG9cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5zZWFyY2guYWpheFxuXHRcdCAqIEBwbHVnaW4gc2VhcmNoXG5cdFx0ICovXG5cdFx0YWpheCA6IGZhbHNlLFxuXHRcdC8qKlxuXHRcdCAqIEluZGljYXRlcyBpZiB0aGUgc2VhcmNoIHNob3VsZCBiZSBmdXp6eSBvciBub3QgKHNob3VsZCBgY2huZDNgIG1hdGNoIGBjaGlsZCBub2RlIDNgKS4gRGVmYXVsdCBpcyBgZmFsc2VgLlxuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLnNlYXJjaC5mdXp6eVxuXHRcdCAqIEBwbHVnaW4gc2VhcmNoXG5cdFx0ICovXG5cdFx0ZnV6enkgOiBmYWxzZSxcblx0XHQvKipcblx0XHQgKiBJbmRpY2F0ZXMgaWYgdGhlIHNlYXJjaCBzaG91bGQgYmUgY2FzZSBzZW5zaXRpdmUuIERlZmF1bHQgaXMgYGZhbHNlYC5cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5zZWFyY2guY2FzZV9zZW5zaXRpdmVcblx0XHQgKiBAcGx1Z2luIHNlYXJjaFxuXHRcdCAqL1xuXHRcdGNhc2Vfc2Vuc2l0aXZlIDogZmFsc2UsXG5cdFx0LyoqXG5cdFx0ICogSW5kaWNhdGVzIGlmIHRoZSB0cmVlIHNob3VsZCBiZSBmaWx0ZXJlZCAoYnkgZGVmYXVsdCkgdG8gc2hvdyBvbmx5IG1hdGNoaW5nIG5vZGVzIChrZWVwIGluIG1pbmQgdGhpcyBjYW4gYmUgYSBoZWF2eSBvbiBsYXJnZSB0cmVlcyBpbiBvbGQgYnJvd3NlcnMpLlxuXHRcdCAqIFRoaXMgc2V0dGluZyBjYW4gYmUgY2hhbmdlZCBhdCBydW50aW1lIHdoZW4gY2FsbGluZyB0aGUgc2VhcmNoIG1ldGhvZC4gRGVmYXVsdCBpcyBgZmFsc2VgLlxuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLnNlYXJjaC5zaG93X29ubHlfbWF0Y2hlc1xuXHRcdCAqIEBwbHVnaW4gc2VhcmNoXG5cdFx0ICovXG5cdFx0c2hvd19vbmx5X21hdGNoZXMgOiBmYWxzZSxcblx0XHQvKipcblx0XHQgKiBJbmRpY2F0ZXMgaWYgdGhlIGNoaWxkcmVuIG9mIG1hdGNoZWQgZWxlbWVudCBhcmUgc2hvd24gKHdoZW4gc2hvd19vbmx5X21hdGNoZXMgaXMgdHJ1ZSlcblx0XHQgKiBUaGlzIHNldHRpbmcgY2FuIGJlIGNoYW5nZWQgYXQgcnVudGltZSB3aGVuIGNhbGxpbmcgdGhlIHNlYXJjaCBtZXRob2QuIERlZmF1bHQgaXMgYGZhbHNlYC5cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5zZWFyY2guc2hvd19vbmx5X21hdGNoZXNfY2hpbGRyZW5cblx0XHQgKiBAcGx1Z2luIHNlYXJjaFxuXHRcdCAqL1xuXHRcdHNob3dfb25seV9tYXRjaGVzX2NoaWxkcmVuIDogZmFsc2UsXG5cdFx0LyoqXG5cdFx0ICogSW5kaWNhdGVzIGlmIGFsbCBub2RlcyBvcGVuZWQgdG8gcmV2ZWFsIHRoZSBzZWFyY2ggcmVzdWx0LCBzaG91bGQgYmUgY2xvc2VkIHdoZW4gdGhlIHNlYXJjaCBpcyBjbGVhcmVkIG9yIGEgbmV3IHNlYXJjaCBpcyBwZXJmb3JtZWQuIERlZmF1bHQgaXMgYHRydWVgLlxuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLnNlYXJjaC5jbG9zZV9vcGVuZWRfb25jbGVhclxuXHRcdCAqIEBwbHVnaW4gc2VhcmNoXG5cdFx0ICovXG5cdFx0Y2xvc2Vfb3BlbmVkX29uY2xlYXIgOiB0cnVlLFxuXHRcdC8qKlxuXHRcdCAqIEluZGljYXRlcyBpZiBvbmx5IGxlYWYgbm9kZXMgc2hvdWxkIGJlIGluY2x1ZGVkIGluIHNlYXJjaCByZXN1bHRzLiBEZWZhdWx0IGlzIGBmYWxzZWAuXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuc2VhcmNoLnNlYXJjaF9sZWF2ZXNfb25seVxuXHRcdCAqIEBwbHVnaW4gc2VhcmNoXG5cdFx0ICovXG5cdFx0c2VhcmNoX2xlYXZlc19vbmx5IDogZmFsc2UsXG5cdFx0LyoqXG5cdFx0ICogSWYgc2V0IHRvIGEgZnVuY3Rpb24gaXQgd2lsIGJlIGNhbGxlZCBpbiB0aGUgaW5zdGFuY2UncyBzY29wZSB3aXRoIHR3byBhcmd1bWVudHMgLSBzZWFyY2ggc3RyaW5nIGFuZCBub2RlICh3aGVyZSBub2RlIHdpbGwgYmUgZXZlcnkgbm9kZSBpbiB0aGUgc3RydWN0dXJlLCBzbyB1c2Ugd2l0aCBjYXV0aW9uKS5cblx0XHQgKiBJZiB0aGUgZnVuY3Rpb24gcmV0dXJucyBhIHRydXRoeSB2YWx1ZSB0aGUgbm9kZSB3aWxsIGJlIGNvbnNpZGVyZWQgYSBtYXRjaCAoaXQgbWlnaHQgbm90IGJlIGRpc3BsYXllZCBpZiBzZWFyY2hfb25seV9sZWF2ZXMgaXMgc2V0IHRvIHRydWUgYW5kIHRoZSBub2RlIGlzIG5vdCBhIGxlYWYpLiBEZWZhdWx0IGlzIGBmYWxzZWAuXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuc2VhcmNoLnNlYXJjaF9jYWxsYmFja1xuXHRcdCAqIEBwbHVnaW4gc2VhcmNoXG5cdFx0ICovXG5cdFx0c2VhcmNoX2NhbGxiYWNrIDogZmFsc2Vcblx0fTtcblxuXHQkLmpzdHJlZS5wbHVnaW5zLnNlYXJjaCA9IGZ1bmN0aW9uIChvcHRpb25zLCBwYXJlbnQpIHtcblx0XHR0aGlzLmJpbmQgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRwYXJlbnQuYmluZC5jYWxsKHRoaXMpO1xuXG5cdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5zdHIgPSBcIlwiO1xuXHRcdFx0dGhpcy5fZGF0YS5zZWFyY2guZG9tID0gJCgpO1xuXHRcdFx0dGhpcy5fZGF0YS5zZWFyY2gucmVzID0gW107XG5cdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5vcG4gPSBbXTtcblx0XHRcdHRoaXMuX2RhdGEuc2VhcmNoLnNvbSA9IGZhbHNlO1xuXHRcdFx0dGhpcy5fZGF0YS5zZWFyY2guc21jID0gZmFsc2U7XG5cdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5oZG4gPSBbXTtcblxuXHRcdFx0dGhpcy5lbGVtZW50XG5cdFx0XHRcdC5vbihcInNlYXJjaC5qc3RyZWVcIiwgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0XHRcdGlmKHRoaXMuX2RhdGEuc2VhcmNoLnNvbSAmJiBkYXRhLnJlcy5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0dmFyIG0gPSB0aGlzLl9tb2RlbC5kYXRhLCBpLCBqLCBwID0gW10sIGssIGw7XG5cdFx0XHRcdFx0XHRcdGZvcihpID0gMCwgaiA9IGRhdGEucmVzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdFx0XHRcdGlmKG1bZGF0YS5yZXNbaV1dICYmICFtW2RhdGEucmVzW2ldXS5zdGF0ZS5oaWRkZW4pIHtcblx0XHRcdFx0XHRcdFx0XHRcdHAucHVzaChkYXRhLnJlc1tpXSk7XG5cdFx0XHRcdFx0XHRcdFx0XHRwID0gcC5jb25jYXQobVtkYXRhLnJlc1tpXV0ucGFyZW50cyk7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZih0aGlzLl9kYXRhLnNlYXJjaC5zbWMpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0Zm9yIChrID0gMCwgbCA9IG1bZGF0YS5yZXNbaV1dLmNoaWxkcmVuX2QubGVuZ3RoOyBrIDwgbDsgaysrKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKG1bbVtkYXRhLnJlc1tpXV0uY2hpbGRyZW5fZFtrXV0gJiYgIW1bbVtkYXRhLnJlc1tpXV0uY2hpbGRyZW5fZFtrXV0uc3RhdGUuaGlkZGVuKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRwLnB1c2gobVtkYXRhLnJlc1tpXV0uY2hpbGRyZW5fZFtrXSk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdHAgPSAkLnZha2F0YS5hcnJheV9yZW1vdmVfaXRlbSgkLnZha2F0YS5hcnJheV91bmlxdWUocCksICQuanN0cmVlLnJvb3QpO1xuXHRcdFx0XHRcdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5oZG4gPSB0aGlzLmhpZGVfYWxsKHRydWUpO1xuXHRcdFx0XHRcdFx0XHR0aGlzLnNob3dfbm9kZShwLCB0cnVlKTtcblx0XHRcdFx0XHRcdFx0dGhpcy5yZWRyYXcodHJ1ZSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fS5iaW5kKHRoaXMpKVxuXHRcdFx0XHQub24oXCJjbGVhcl9zZWFyY2guanN0cmVlXCIsIGZ1bmN0aW9uIChlLCBkYXRhKSB7XG5cdFx0XHRcdFx0XHRpZih0aGlzLl9kYXRhLnNlYXJjaC5zb20gJiYgZGF0YS5yZXMubGVuZ3RoKSB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuc2hvd19ub2RlKHRoaXMuX2RhdGEuc2VhcmNoLmhkbiwgdHJ1ZSk7XG5cdFx0XHRcdFx0XHRcdHRoaXMucmVkcmF3KHRydWUpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0uYmluZCh0aGlzKSk7XG5cdFx0fTtcblx0XHQvKipcblx0XHQgKiB1c2VkIHRvIHNlYXJjaCB0aGUgdHJlZSBub2RlcyBmb3IgYSBnaXZlbiBzdHJpbmdcblx0XHQgKiBAbmFtZSBzZWFyY2goc3RyIFssIHNraXBfYXN5bmNdKVxuXHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgdGhlIHNlYXJjaCBzdHJpbmdcblx0XHQgKiBAcGFyYW0ge0Jvb2xlYW59IHNraXBfYXN5bmMgaWYgc2V0IHRvIHRydWUgc2VydmVyIHdpbGwgbm90IGJlIHF1ZXJpZWQgZXZlbiBpZiBjb25maWd1cmVkXG5cdFx0ICogQHBhcmFtIHtCb29sZWFufSBzaG93X29ubHlfbWF0Y2hlcyBpZiBzZXQgdG8gdHJ1ZSBvbmx5IG1hdGNoaW5nIG5vZGVzIHdpbGwgYmUgc2hvd24gKGtlZXAgaW4gbWluZCB0aGlzIGNhbiBiZSB2ZXJ5IHNsb3cgb24gbGFyZ2UgdHJlZXMgb3Igb2xkIGJyb3dzZXJzKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IGluc2lkZSBhbiBvcHRpb25hbCBub2RlIHRvIHdob3NlIGNoaWxkcmVuIHRvIGxpbWl0IHRoZSBzZWFyY2hcblx0XHQgKiBAcGFyYW0ge0Jvb2xlYW59IGFwcGVuZCBpZiBzZXQgdG8gdHJ1ZSB0aGUgcmVzdWx0cyBvZiB0aGlzIHNlYXJjaCBhcmUgYXBwZW5kZWQgdG8gdGhlIHByZXZpb3VzIHNlYXJjaFxuXHRcdCAqIEBwbHVnaW4gc2VhcmNoXG5cdFx0ICogQHRyaWdnZXIgc2VhcmNoLmpzdHJlZVxuXHRcdCAqL1xuXHRcdHRoaXMuc2VhcmNoID0gZnVuY3Rpb24gKHN0ciwgc2tpcF9hc3luYywgc2hvd19vbmx5X21hdGNoZXMsIGluc2lkZSwgYXBwZW5kLCBzaG93X29ubHlfbWF0Y2hlc19jaGlsZHJlbikge1xuXHRcdFx0aWYoc3RyID09PSBmYWxzZSB8fCAkLnZha2F0YS50cmltKHN0ci50b1N0cmluZygpKSA9PT0gXCJcIikge1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5jbGVhcl9zZWFyY2goKTtcblx0XHRcdH1cblx0XHRcdGluc2lkZSA9IHRoaXMuZ2V0X25vZGUoaW5zaWRlKTtcblx0XHRcdGluc2lkZSA9IGluc2lkZSAmJiBpbnNpZGUuaWQgPyBpbnNpZGUuaWQgOiBudWxsO1xuXHRcdFx0c3RyID0gc3RyLnRvU3RyaW5nKCk7XG5cdFx0XHR2YXIgcyA9IHRoaXMuc2V0dGluZ3Muc2VhcmNoLFxuXHRcdFx0XHRhID0gcy5hamF4ID8gcy5hamF4IDogZmFsc2UsXG5cdFx0XHRcdG0gPSB0aGlzLl9tb2RlbC5kYXRhLFxuXHRcdFx0XHRmID0gbnVsbCxcblx0XHRcdFx0ciA9IFtdLFxuXHRcdFx0XHRwID0gW10sIGksIGo7XG5cdFx0XHRpZih0aGlzLl9kYXRhLnNlYXJjaC5yZXMubGVuZ3RoICYmICFhcHBlbmQpIHtcblx0XHRcdFx0dGhpcy5jbGVhcl9zZWFyY2goKTtcblx0XHRcdH1cblx0XHRcdGlmKHNob3dfb25seV9tYXRjaGVzID09PSB1bmRlZmluZWQpIHtcblx0XHRcdFx0c2hvd19vbmx5X21hdGNoZXMgPSBzLnNob3dfb25seV9tYXRjaGVzO1xuXHRcdFx0fVxuXHRcdFx0aWYoc2hvd19vbmx5X21hdGNoZXNfY2hpbGRyZW4gPT09IHVuZGVmaW5lZCkge1xuXHRcdFx0XHRzaG93X29ubHlfbWF0Y2hlc19jaGlsZHJlbiA9IHMuc2hvd19vbmx5X21hdGNoZXNfY2hpbGRyZW47XG5cdFx0XHR9XG5cdFx0XHRpZighc2tpcF9hc3luYyAmJiBhICE9PSBmYWxzZSkge1xuXHRcdFx0XHRpZigkLnZha2F0YS5pc19mdW5jdGlvbihhKSkge1xuXHRcdFx0XHRcdHJldHVybiBhLmNhbGwodGhpcywgc3RyLCBmdW5jdGlvbiAoZCkge1xuXHRcdFx0XHRcdFx0XHRpZihkICYmIGQuZCkgeyBkID0gZC5kOyB9XG5cdFx0XHRcdFx0XHRcdHRoaXMuX2xvYWRfbm9kZXMoISQudmFrYXRhLmlzX2FycmF5KGQpID8gW10gOiAkLnZha2F0YS5hcnJheV91bmlxdWUoZCksIGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRcdFx0XHR0aGlzLnNlYXJjaChzdHIsIHRydWUsIHNob3dfb25seV9tYXRjaGVzLCBpbnNpZGUsIGFwcGVuZCwgc2hvd19vbmx5X21hdGNoZXNfY2hpbGRyZW4pO1xuXHRcdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRcdH0uYmluZCh0aGlzKSwgaW5zaWRlKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRhID0gJC5leHRlbmQoe30sIGEpO1xuXHRcdFx0XHRcdGlmKCFhLmRhdGEpIHsgYS5kYXRhID0ge307IH1cblx0XHRcdFx0XHRhLmRhdGEuc3RyID0gc3RyO1xuXHRcdFx0XHRcdGlmKGluc2lkZSkge1xuXHRcdFx0XHRcdFx0YS5kYXRhLmluc2lkZSA9IGluc2lkZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKHRoaXMuX2RhdGEuc2VhcmNoLmxhc3RSZXF1ZXN0KSB7XG5cdFx0XHRcdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5sYXN0UmVxdWVzdC5hYm9ydCgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5sYXN0UmVxdWVzdCA9ICQuYWpheChhKVxuXHRcdFx0XHRcdFx0LmZhaWwoZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0XHR0aGlzLl9kYXRhLmNvcmUubGFzdF9lcnJvciA9IHsgJ2Vycm9yJyA6ICdhamF4JywgJ3BsdWdpbicgOiAnc2VhcmNoJywgJ2lkJyA6ICdzZWFyY2hfMDEnLCAncmVhc29uJyA6ICdDb3VsZCBub3QgbG9hZCBzZWFyY2ggcGFyZW50cycsICdkYXRhJyA6IEpTT04uc3RyaW5naWZ5KGEpIH07XG5cdFx0XHRcdFx0XHRcdHRoaXMuc2V0dGluZ3MuY29yZS5lcnJvci5jYWxsKHRoaXMsIHRoaXMuX2RhdGEuY29yZS5sYXN0X2Vycm9yKTtcblx0XHRcdFx0XHRcdH0uYmluZCh0aGlzKSlcblx0XHRcdFx0XHRcdC5kb25lKGZ1bmN0aW9uIChkKSB7XG5cdFx0XHRcdFx0XHRcdGlmKGQgJiYgZC5kKSB7IGQgPSBkLmQ7IH1cblx0XHRcdFx0XHRcdFx0dGhpcy5fbG9hZF9ub2RlcyghJC52YWthdGEuaXNfYXJyYXkoZCkgPyBbXSA6ICQudmFrYXRhLmFycmF5X3VuaXF1ZShkKSwgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuc2VhcmNoKHN0ciwgdHJ1ZSwgc2hvd19vbmx5X21hdGNoZXMsIGluc2lkZSwgYXBwZW5kLCBzaG93X29ubHlfbWF0Y2hlc19jaGlsZHJlbik7XG5cdFx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcy5fZGF0YS5zZWFyY2gubGFzdFJlcXVlc3Q7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmKCFhcHBlbmQpIHtcblx0XHRcdFx0dGhpcy5fZGF0YS5zZWFyY2guc3RyID0gc3RyO1xuXHRcdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5kb20gPSAkKCk7XG5cdFx0XHRcdHRoaXMuX2RhdGEuc2VhcmNoLnJlcyA9IFtdO1xuXHRcdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5vcG4gPSBbXTtcblx0XHRcdFx0dGhpcy5fZGF0YS5zZWFyY2guc29tID0gc2hvd19vbmx5X21hdGNoZXM7XG5cdFx0XHRcdHRoaXMuX2RhdGEuc2VhcmNoLnNtYyA9IHNob3dfb25seV9tYXRjaGVzX2NoaWxkcmVuO1xuXHRcdFx0fVxuXG5cdFx0XHRmID0gbmV3ICQudmFrYXRhLnNlYXJjaChzdHIsIHRydWUsIHsgY2FzZVNlbnNpdGl2ZSA6IHMuY2FzZV9zZW5zaXRpdmUsIGZ1enp5IDogcy5mdXp6eSB9KTtcblx0XHRcdCQuZWFjaChtW2luc2lkZSA/IGluc2lkZSA6ICQuanN0cmVlLnJvb3RdLmNoaWxkcmVuX2QsIGZ1bmN0aW9uIChpaSwgaSkge1xuXHRcdFx0XHR2YXIgdiA9IG1baV07XG5cdFx0XHRcdGlmKHYudGV4dCAmJiAhdi5zdGF0ZS5oaWRkZW4gJiYgKCFzLnNlYXJjaF9sZWF2ZXNfb25seSB8fCAodi5zdGF0ZS5sb2FkZWQgJiYgdi5jaGlsZHJlbi5sZW5ndGggPT09IDApKSAmJiAoIChzLnNlYXJjaF9jYWxsYmFjayAmJiBzLnNlYXJjaF9jYWxsYmFjay5jYWxsKHRoaXMsIHN0ciwgdikpIHx8ICghcy5zZWFyY2hfY2FsbGJhY2sgJiYgZi5zZWFyY2godi50ZXh0KS5pc01hdGNoKSApICkge1xuXHRcdFx0XHRcdHIucHVzaChpKTtcblx0XHRcdFx0XHRwID0gcC5jb25jYXQodi5wYXJlbnRzKTtcblx0XHRcdFx0fVxuXHRcdFx0fSk7XG5cdFx0XHRpZihyLmxlbmd0aCkge1xuXHRcdFx0XHRwID0gJC52YWthdGEuYXJyYXlfdW5pcXVlKHApO1xuXHRcdFx0XHRmb3IoaSA9IDAsIGogPSBwLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdGlmKHBbaV0gIT09ICQuanN0cmVlLnJvb3QgJiYgbVtwW2ldXSAmJiB0aGlzLm9wZW5fbm9kZShwW2ldLCBudWxsLCAwKSA9PT0gdHJ1ZSkge1xuXHRcdFx0XHRcdFx0dGhpcy5fZGF0YS5zZWFyY2gub3BuLnB1c2gocFtpXSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGlmKCFhcHBlbmQpIHtcblx0XHRcdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5kb20gPSAkKHRoaXMuZWxlbWVudFswXS5xdWVyeVNlbGVjdG9yQWxsKCcjJyArICQubWFwKHIsIGZ1bmN0aW9uICh2KSB7IHJldHVybiBcIjAxMjM0NTY3ODlcIi5pbmRleE9mKHZbMF0pICE9PSAtMSA/ICdcXFxcMycgKyB2WzBdICsgJyAnICsgdi5zdWJzdHIoMSkucmVwbGFjZSgkLmpzdHJlZS5pZHJlZ2V4LCdcXFxcJCYnKSA6IHYucmVwbGFjZSgkLmpzdHJlZS5pZHJlZ2V4LCdcXFxcJCYnKTsgfSkuam9pbignLCAjJykpKTtcblx0XHRcdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5yZXMgPSByO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdHRoaXMuX2RhdGEuc2VhcmNoLmRvbSA9IHRoaXMuX2RhdGEuc2VhcmNoLmRvbS5hZGQoJCh0aGlzLmVsZW1lbnRbMF0ucXVlcnlTZWxlY3RvckFsbCgnIycgKyAkLm1hcChyLCBmdW5jdGlvbiAodikgeyByZXR1cm4gXCIwMTIzNDU2Nzg5XCIuaW5kZXhPZih2WzBdKSAhPT0gLTEgPyAnXFxcXDMnICsgdlswXSArICcgJyArIHYuc3Vic3RyKDEpLnJlcGxhY2UoJC5qc3RyZWUuaWRyZWdleCwnXFxcXCQmJykgOiB2LnJlcGxhY2UoJC5qc3RyZWUuaWRyZWdleCwnXFxcXCQmJyk7IH0pLmpvaW4oJywgIycpKSkpO1xuXHRcdFx0XHRcdHRoaXMuX2RhdGEuc2VhcmNoLnJlcyA9ICQudmFrYXRhLmFycmF5X3VuaXF1ZSh0aGlzLl9kYXRhLnNlYXJjaC5yZXMuY29uY2F0KHIpKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5kb20uY2hpbGRyZW4oXCIuanN0cmVlLWFuY2hvclwiKS5hZGRDbGFzcygnanN0cmVlLXNlYXJjaCcpO1xuXHRcdFx0fVxuXHRcdFx0LyoqXG5cdFx0XHQgKiB0cmlnZ2VyZWQgYWZ0ZXIgc2VhcmNoIGlzIGNvbXBsZXRlXG5cdFx0XHQgKiBAZXZlbnRcblx0XHRcdCAqIEBuYW1lIHNlYXJjaC5qc3RyZWVcblx0XHRcdCAqIEBwYXJhbSB7alF1ZXJ5fSBub2RlcyBhIGpRdWVyeSBjb2xsZWN0aW9uIG9mIG1hdGNoaW5nIG5vZGVzXG5cdFx0XHQgKiBAcGFyYW0ge1N0cmluZ30gc3RyIHRoZSBzZWFyY2ggc3RyaW5nXG5cdFx0XHQgKiBAcGFyYW0ge0FycmF5fSByZXMgYSBjb2xsZWN0aW9uIG9mIG9iamVjdHMgcmVwcmVzZWluZyB0aGUgbWF0Y2hpbmcgbm9kZXNcblx0XHRcdCAqIEBwbHVnaW4gc2VhcmNoXG5cdFx0XHQgKi9cblx0XHRcdHRoaXMudHJpZ2dlcignc2VhcmNoJywgeyBub2RlcyA6IHRoaXMuX2RhdGEuc2VhcmNoLmRvbSwgc3RyIDogc3RyLCByZXMgOiB0aGlzLl9kYXRhLnNlYXJjaC5yZXMsIHNob3dfb25seV9tYXRjaGVzIDogc2hvd19vbmx5X21hdGNoZXMgfSk7XG5cdFx0fTtcblx0XHQvKipcblx0XHQgKiB1c2VkIHRvIGNsZWFyIHRoZSBsYXN0IHNlYXJjaCAocmVtb3ZlcyBjbGFzc2VzIGFuZCBzaG93cyBhbGwgbm9kZXMgaWYgZmlsdGVyaW5nIGlzIG9uKVxuXHRcdCAqIEBuYW1lIGNsZWFyX3NlYXJjaCgpXG5cdFx0ICogQHBsdWdpbiBzZWFyY2hcblx0XHQgKiBAdHJpZ2dlciBjbGVhcl9zZWFyY2guanN0cmVlXG5cdFx0ICovXG5cdFx0dGhpcy5jbGVhcl9zZWFyY2ggPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLnNlYXJjaC5jbG9zZV9vcGVuZWRfb25jbGVhcikge1xuXHRcdFx0XHR0aGlzLmNsb3NlX25vZGUodGhpcy5fZGF0YS5zZWFyY2gub3BuLCAwKTtcblx0XHRcdH1cblx0XHRcdC8qKlxuXHRcdFx0ICogdHJpZ2dlcmVkIGFmdGVyIHNlYXJjaCBpcyBjb21wbGV0ZVxuXHRcdFx0ICogQGV2ZW50XG5cdFx0XHQgKiBAbmFtZSBjbGVhcl9zZWFyY2guanN0cmVlXG5cdFx0XHQgKiBAcGFyYW0ge2pRdWVyeX0gbm9kZXMgYSBqUXVlcnkgY29sbGVjdGlvbiBvZiBtYXRjaGluZyBub2RlcyAodGhlIHJlc3VsdCBmcm9tIHRoZSBsYXN0IHNlYXJjaClcblx0XHRcdCAqIEBwYXJhbSB7U3RyaW5nfSBzdHIgdGhlIHNlYXJjaCBzdHJpbmcgKHRoZSBsYXN0IHNlYXJjaCBzdHJpbmcpXG5cdFx0XHQgKiBAcGFyYW0ge0FycmF5fSByZXMgYSBjb2xsZWN0aW9uIG9mIG9iamVjdHMgcmVwcmVzZWluZyB0aGUgbWF0Y2hpbmcgbm9kZXMgKHRoZSByZXN1bHQgZnJvbSB0aGUgbGFzdCBzZWFyY2gpXG5cdFx0XHQgKiBAcGx1Z2luIHNlYXJjaFxuXHRcdFx0ICovXG5cdFx0XHR0aGlzLnRyaWdnZXIoJ2NsZWFyX3NlYXJjaCcsIHsgJ25vZGVzJyA6IHRoaXMuX2RhdGEuc2VhcmNoLmRvbSwgc3RyIDogdGhpcy5fZGF0YS5zZWFyY2guc3RyLCByZXMgOiB0aGlzLl9kYXRhLnNlYXJjaC5yZXMgfSk7XG5cdFx0XHRpZih0aGlzLl9kYXRhLnNlYXJjaC5yZXMubGVuZ3RoKSB7XG5cdFx0XHRcdHRoaXMuX2RhdGEuc2VhcmNoLmRvbSA9ICQodGhpcy5lbGVtZW50WzBdLnF1ZXJ5U2VsZWN0b3JBbGwoJyMnICsgJC5tYXAodGhpcy5fZGF0YS5zZWFyY2gucmVzLCBmdW5jdGlvbiAodikge1xuXHRcdFx0XHRcdHJldHVybiBcIjAxMjM0NTY3ODlcIi5pbmRleE9mKHZbMF0pICE9PSAtMSA/ICdcXFxcMycgKyB2WzBdICsgJyAnICsgdi5zdWJzdHIoMSkucmVwbGFjZSgkLmpzdHJlZS5pZHJlZ2V4LCdcXFxcJCYnKSA6IHYucmVwbGFjZSgkLmpzdHJlZS5pZHJlZ2V4LCdcXFxcJCYnKTtcblx0XHRcdFx0fSkuam9pbignLCAjJykpKTtcblx0XHRcdFx0dGhpcy5fZGF0YS5zZWFyY2guZG9tLmNoaWxkcmVuKFwiLmpzdHJlZS1hbmNob3JcIikucmVtb3ZlQ2xhc3MoXCJqc3RyZWUtc2VhcmNoXCIpO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fZGF0YS5zZWFyY2guc3RyID0gXCJcIjtcblx0XHRcdHRoaXMuX2RhdGEuc2VhcmNoLnJlcyA9IFtdO1xuXHRcdFx0dGhpcy5fZGF0YS5zZWFyY2gub3BuID0gW107XG5cdFx0XHR0aGlzLl9kYXRhLnNlYXJjaC5kb20gPSAkKCk7XG5cdFx0fTtcblxuXHRcdHRoaXMucmVkcmF3X25vZGUgPSBmdW5jdGlvbihvYmosIGRlZXAsIGNhbGxiYWNrLCBmb3JjZV9yZW5kZXIpIHtcblx0XHRcdG9iaiA9IHBhcmVudC5yZWRyYXdfbm9kZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuXHRcdFx0aWYob2JqKSB7XG5cdFx0XHRcdGlmKCQuaW5BcnJheShvYmouaWQsIHRoaXMuX2RhdGEuc2VhcmNoLnJlcykgIT09IC0xKSB7XG5cdFx0XHRcdFx0dmFyIGksIGosIHRtcCA9IG51bGw7XG5cdFx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gb2JqLmNoaWxkTm9kZXMubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRpZihvYmouY2hpbGROb2Rlc1tpXSAmJiBvYmouY2hpbGROb2Rlc1tpXS5jbGFzc05hbWUgJiYgb2JqLmNoaWxkTm9kZXNbaV0uY2xhc3NOYW1lLmluZGV4T2YoXCJqc3RyZWUtYW5jaG9yXCIpICE9PSAtMSkge1xuXHRcdFx0XHRcdFx0XHR0bXAgPSBvYmouY2hpbGROb2Rlc1tpXTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmKHRtcCkge1xuXHRcdFx0XHRcdFx0dG1wLmNsYXNzTmFtZSArPSAnIGpzdHJlZS1zZWFyY2gnO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIG9iajtcblx0XHR9O1xuXHR9O1xuXG5cdC8vIGhlbHBlcnNcblx0KGZ1bmN0aW9uICgkKSB7XG5cdFx0Ly8gZnJvbSBodHRwOi8va2lyby5tZS9wcm9qZWN0cy9mdXNlLmh0bWxcblx0XHQkLnZha2F0YS5zZWFyY2ggPSBmdW5jdGlvbihwYXR0ZXJuLCB0eHQsIG9wdGlvbnMpIHtcblx0XHRcdG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXHRcdFx0b3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCAkLnZha2F0YS5zZWFyY2guZGVmYXVsdHMsIG9wdGlvbnMpO1xuXHRcdFx0aWYob3B0aW9ucy5mdXp6eSAhPT0gZmFsc2UpIHtcblx0XHRcdFx0b3B0aW9ucy5mdXp6eSA9IHRydWU7XG5cdFx0XHR9XG5cdFx0XHRwYXR0ZXJuID0gb3B0aW9ucy5jYXNlU2Vuc2l0aXZlID8gcGF0dGVybiA6IHBhdHRlcm4udG9Mb3dlckNhc2UoKTtcblx0XHRcdHZhciBNQVRDSF9MT0NBVElPTlx0PSBvcHRpb25zLmxvY2F0aW9uLFxuXHRcdFx0XHRNQVRDSF9ESVNUQU5DRVx0PSBvcHRpb25zLmRpc3RhbmNlLFxuXHRcdFx0XHRNQVRDSF9USFJFU0hPTERcdD0gb3B0aW9ucy50aHJlc2hvbGQsXG5cdFx0XHRcdHBhdHRlcm5MZW4gPSBwYXR0ZXJuLmxlbmd0aCxcblx0XHRcdFx0bWF0Y2htYXNrLCBwYXR0ZXJuX2FscGhhYmV0LCBtYXRjaF9iaXRhcFNjb3JlLCBzZWFyY2g7XG5cdFx0XHRpZihwYXR0ZXJuTGVuID4gMzIpIHtcblx0XHRcdFx0b3B0aW9ucy5mdXp6eSA9IGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0aWYob3B0aW9ucy5mdXp6eSkge1xuXHRcdFx0XHRtYXRjaG1hc2sgPSAxIDw8IChwYXR0ZXJuTGVuIC0gMSk7XG5cdFx0XHRcdHBhdHRlcm5fYWxwaGFiZXQgPSAoZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdHZhciBtYXNrID0ge30sXG5cdFx0XHRcdFx0XHRpID0gMDtcblx0XHRcdFx0XHRmb3IgKGkgPSAwOyBpIDwgcGF0dGVybkxlbjsgaSsrKSB7XG5cdFx0XHRcdFx0XHRtYXNrW3BhdHRlcm4uY2hhckF0KGkpXSA9IDA7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGZvciAoaSA9IDA7IGkgPCBwYXR0ZXJuTGVuOyBpKyspIHtcblx0XHRcdFx0XHRcdG1hc2tbcGF0dGVybi5jaGFyQXQoaSldIHw9IDEgPDwgKHBhdHRlcm5MZW4gLSBpIC0gMSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiBtYXNrO1xuXHRcdFx0XHR9KCkpO1xuXHRcdFx0XHRtYXRjaF9iaXRhcFNjb3JlID0gZnVuY3Rpb24gKGUsIHgpIHtcblx0XHRcdFx0XHR2YXIgYWNjdXJhY3kgPSBlIC8gcGF0dGVybkxlbixcblx0XHRcdFx0XHRcdHByb3hpbWl0eSA9IE1hdGguYWJzKE1BVENIX0xPQ0FUSU9OIC0geCk7XG5cdFx0XHRcdFx0aWYoIU1BVENIX0RJU1RBTkNFKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gcHJveGltaXR5ID8gMS4wIDogYWNjdXJhY3k7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiBhY2N1cmFjeSArIChwcm94aW1pdHkgLyBNQVRDSF9ESVNUQU5DRSk7XG5cdFx0XHRcdH07XG5cdFx0XHR9XG5cdFx0XHRzZWFyY2ggPSBmdW5jdGlvbiAodGV4dCkge1xuXHRcdFx0XHR0ZXh0ID0gb3B0aW9ucy5jYXNlU2Vuc2l0aXZlID8gdGV4dCA6IHRleHQudG9Mb3dlckNhc2UoKTtcblx0XHRcdFx0aWYocGF0dGVybiA9PT0gdGV4dCB8fCB0ZXh0LmluZGV4T2YocGF0dGVybikgIT09IC0xKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRcdGlzTWF0Y2g6IHRydWUsXG5cdFx0XHRcdFx0XHRzY29yZTogMFxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYoIW9wdGlvbnMuZnV6enkpIHtcblx0XHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdFx0aXNNYXRjaDogZmFsc2UsXG5cdFx0XHRcdFx0XHRzY29yZTogMVxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdH1cblx0XHRcdFx0dmFyIGksIGosXG5cdFx0XHRcdFx0dGV4dExlbiA9IHRleHQubGVuZ3RoLFxuXHRcdFx0XHRcdHNjb3JlVGhyZXNob2xkID0gTUFUQ0hfVEhSRVNIT0xELFxuXHRcdFx0XHRcdGJlc3RMb2MgPSB0ZXh0LmluZGV4T2YocGF0dGVybiwgTUFUQ0hfTE9DQVRJT04pLFxuXHRcdFx0XHRcdGJpbk1pbiwgYmluTWlkLFxuXHRcdFx0XHRcdGJpbk1heCA9IHBhdHRlcm5MZW4gKyB0ZXh0TGVuLFxuXHRcdFx0XHRcdGxhc3RSZCwgc3RhcnQsIGZpbmlzaCwgcmQsIGNoYXJNYXRjaCxcblx0XHRcdFx0XHRzY29yZSA9IDEsXG5cdFx0XHRcdFx0bG9jYXRpb25zID0gW107XG5cdFx0XHRcdGlmIChiZXN0TG9jICE9PSAtMSkge1xuXHRcdFx0XHRcdHNjb3JlVGhyZXNob2xkID0gTWF0aC5taW4obWF0Y2hfYml0YXBTY29yZSgwLCBiZXN0TG9jKSwgc2NvcmVUaHJlc2hvbGQpO1xuXHRcdFx0XHRcdGJlc3RMb2MgPSB0ZXh0Lmxhc3RJbmRleE9mKHBhdHRlcm4sIE1BVENIX0xPQ0FUSU9OICsgcGF0dGVybkxlbik7XG5cdFx0XHRcdFx0aWYgKGJlc3RMb2MgIT09IC0xKSB7XG5cdFx0XHRcdFx0XHRzY29yZVRocmVzaG9sZCA9IE1hdGgubWluKG1hdGNoX2JpdGFwU2NvcmUoMCwgYmVzdExvYyksIHNjb3JlVGhyZXNob2xkKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0YmVzdExvYyA9IC0xO1xuXHRcdFx0XHRmb3IgKGkgPSAwOyBpIDwgcGF0dGVybkxlbjsgaSsrKSB7XG5cdFx0XHRcdFx0YmluTWluID0gMDtcblx0XHRcdFx0XHRiaW5NaWQgPSBiaW5NYXg7XG5cdFx0XHRcdFx0d2hpbGUgKGJpbk1pbiA8IGJpbk1pZCkge1xuXHRcdFx0XHRcdFx0aWYgKG1hdGNoX2JpdGFwU2NvcmUoaSwgTUFUQ0hfTE9DQVRJT04gKyBiaW5NaWQpIDw9IHNjb3JlVGhyZXNob2xkKSB7XG5cdFx0XHRcdFx0XHRcdGJpbk1pbiA9IGJpbk1pZDtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdGJpbk1heCA9IGJpbk1pZDtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGJpbk1pZCA9IE1hdGguZmxvb3IoKGJpbk1heCAtIGJpbk1pbikgLyAyICsgYmluTWluKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0YmluTWF4ID0gYmluTWlkO1xuXHRcdFx0XHRcdHN0YXJ0ID0gTWF0aC5tYXgoMSwgTUFUQ0hfTE9DQVRJT04gLSBiaW5NaWQgKyAxKTtcblx0XHRcdFx0XHRmaW5pc2ggPSBNYXRoLm1pbihNQVRDSF9MT0NBVElPTiArIGJpbk1pZCwgdGV4dExlbikgKyBwYXR0ZXJuTGVuO1xuXHRcdFx0XHRcdHJkID0gbmV3IEFycmF5KGZpbmlzaCArIDIpO1xuXHRcdFx0XHRcdHJkW2ZpbmlzaCArIDFdID0gKDEgPDwgaSkgLSAxO1xuXHRcdFx0XHRcdGZvciAoaiA9IGZpbmlzaDsgaiA+PSBzdGFydDsgai0tKSB7XG5cdFx0XHRcdFx0XHRjaGFyTWF0Y2ggPSBwYXR0ZXJuX2FscGhhYmV0W3RleHQuY2hhckF0KGogLSAxKV07XG5cdFx0XHRcdFx0XHRpZiAoaSA9PT0gMCkge1xuXHRcdFx0XHRcdFx0XHRyZFtqXSA9ICgocmRbaiArIDFdIDw8IDEpIHwgMSkgJiBjaGFyTWF0Y2g7XG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRyZFtqXSA9ICgocmRbaiArIDFdIDw8IDEpIHwgMSkgJiBjaGFyTWF0Y2ggfCAoKChsYXN0UmRbaiArIDFdIHwgbGFzdFJkW2pdKSA8PCAxKSB8IDEpIHwgbGFzdFJkW2ogKyAxXTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmIChyZFtqXSAmIG1hdGNobWFzaykge1xuXHRcdFx0XHRcdFx0XHRzY29yZSA9IG1hdGNoX2JpdGFwU2NvcmUoaSwgaiAtIDEpO1xuXHRcdFx0XHRcdFx0XHRpZiAoc2NvcmUgPD0gc2NvcmVUaHJlc2hvbGQpIHtcblx0XHRcdFx0XHRcdFx0XHRzY29yZVRocmVzaG9sZCA9IHNjb3JlO1xuXHRcdFx0XHRcdFx0XHRcdGJlc3RMb2MgPSBqIC0gMTtcblx0XHRcdFx0XHRcdFx0XHRsb2NhdGlvbnMucHVzaChiZXN0TG9jKTtcblx0XHRcdFx0XHRcdFx0XHRpZiAoYmVzdExvYyA+IE1BVENIX0xPQ0FUSU9OKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRzdGFydCA9IE1hdGgubWF4KDEsIDIgKiBNQVRDSF9MT0NBVElPTiAtIGJlc3RMb2MpO1xuXHRcdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKG1hdGNoX2JpdGFwU2NvcmUoaSArIDEsIE1BVENIX0xPQ0FUSU9OKSA+IHNjb3JlVGhyZXNob2xkKSB7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0bGFzdFJkID0gcmQ7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRpc01hdGNoOiBiZXN0TG9jID49IDAsXG5cdFx0XHRcdFx0c2NvcmU6IHNjb3JlXG5cdFx0XHRcdH07XG5cdFx0XHR9O1xuXHRcdFx0cmV0dXJuIHR4dCA9PT0gdHJ1ZSA/IHsgJ3NlYXJjaCcgOiBzZWFyY2ggfSA6IHNlYXJjaCh0eHQpO1xuXHRcdH07XG5cdFx0JC52YWthdGEuc2VhcmNoLmRlZmF1bHRzID0ge1xuXHRcdFx0bG9jYXRpb24gOiAwLFxuXHRcdFx0ZGlzdGFuY2UgOiAxMDAsXG5cdFx0XHR0aHJlc2hvbGQgOiAwLjYsXG5cdFx0XHRmdXp6eSA6IGZhbHNlLFxuXHRcdFx0Y2FzZVNlbnNpdGl2ZSA6IGZhbHNlXG5cdFx0fTtcblx0fSgkKSk7XG5cblx0Ly8gaW5jbHVkZSB0aGUgc2VhcmNoIHBsdWdpbiBieSBkZWZhdWx0XG5cdC8vICQuanN0cmVlLmRlZmF1bHRzLnBsdWdpbnMucHVzaChcInNlYXJjaFwiKTtcblxuXG4vKipcbiAqICMjIyBTb3J0IHBsdWdpblxuICpcbiAqIEF1dG9tYXRpY2FsbHkgc29ydHMgYWxsIHNpYmxpbmdzIGluIHRoZSB0cmVlIGFjY29yZGluZyB0byBhIHNvcnRpbmcgZnVuY3Rpb24uXG4gKi9cblxuXHQvKipcblx0ICogdGhlIHNldHRpbmdzIGZ1bmN0aW9uIHVzZWQgdG8gc29ydCB0aGUgbm9kZXMuXG5cdCAqIEl0IGlzIGV4ZWN1dGVkIGluIHRoZSB0cmVlJ3MgY29udGV4dCwgYWNjZXB0cyB0d28gbm9kZXMgYXMgYXJndW1lbnRzIGFuZCBzaG91bGQgcmV0dXJuIGAxYCBvciBgLTFgLlxuXHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5zb3J0XG5cdCAqIEBwbHVnaW4gc29ydFxuXHQgKi9cblx0JC5qc3RyZWUuZGVmYXVsdHMuc29ydCA9IGZ1bmN0aW9uIChhLCBiKSB7XG5cdFx0Ly9yZXR1cm4gdGhpcy5nZXRfdHlwZShhKSA9PT0gdGhpcy5nZXRfdHlwZShiKSA/ICh0aGlzLmdldF90ZXh0KGEpID4gdGhpcy5nZXRfdGV4dChiKSA/IDEgOiAtMSkgOiB0aGlzLmdldF90eXBlKGEpID49IHRoaXMuZ2V0X3R5cGUoYik7XG5cdFx0cmV0dXJuIHRoaXMuZ2V0X3RleHQoYSkgPiB0aGlzLmdldF90ZXh0KGIpID8gMSA6IC0xO1xuXHR9O1xuXHQkLmpzdHJlZS5wbHVnaW5zLnNvcnQgPSBmdW5jdGlvbiAob3B0aW9ucywgcGFyZW50KSB7XG5cdFx0dGhpcy5iaW5kID0gZnVuY3Rpb24gKCkge1xuXHRcdFx0cGFyZW50LmJpbmQuY2FsbCh0aGlzKTtcblx0XHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0XHQub24oXCJtb2RlbC5qc3RyZWVcIiwgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0XHRcdHRoaXMuc29ydChkYXRhLnBhcmVudCwgdHJ1ZSk7XG5cdFx0XHRcdFx0fS5iaW5kKHRoaXMpKVxuXHRcdFx0XHQub24oXCJyZW5hbWVfbm9kZS5qc3RyZWUgY3JlYXRlX25vZGUuanN0cmVlXCIsIGZ1bmN0aW9uIChlLCBkYXRhKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnNvcnQoZGF0YS5wYXJlbnQgfHwgZGF0YS5ub2RlLnBhcmVudCwgZmFsc2UpO1xuXHRcdFx0XHRcdFx0dGhpcy5yZWRyYXdfbm9kZShkYXRhLnBhcmVudCB8fCBkYXRhLm5vZGUucGFyZW50LCB0cnVlKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbihcIm1vdmVfbm9kZS5qc3RyZWUgY29weV9ub2RlLmpzdHJlZVwiLCBmdW5jdGlvbiAoZSwgZGF0YSkge1xuXHRcdFx0XHRcdFx0dGhpcy5zb3J0KGRhdGEucGFyZW50LCBmYWxzZSk7XG5cdFx0XHRcdFx0XHR0aGlzLnJlZHJhd19ub2RlKGRhdGEucGFyZW50LCB0cnVlKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpO1xuXHRcdH07XG5cdFx0LyoqXG5cdFx0ICogdXNlZCB0byBzb3J0IGEgbm9kZSdzIGNoaWxkcmVuXG5cdFx0ICogQHByaXZhdGVcblx0XHQgKiBAbmFtZSBzb3J0KG9iaiBbLCBkZWVwXSlcblx0XHQgKiBAcGFyYW0gIHttaXhlZH0gb2JqIHRoZSBub2RlXG5cdFx0ICogQHBhcmFtIHtCb29sZWFufSBkZWVwIGlmIHNldCB0byBgdHJ1ZWAgbm9kZXMgYXJlIHNvcnRlZCByZWN1cnNpdmVseS5cblx0XHQgKiBAcGx1Z2luIHNvcnRcblx0XHQgKiBAdHJpZ2dlciBzZWFyY2guanN0cmVlXG5cdFx0ICovXG5cdFx0dGhpcy5zb3J0ID0gZnVuY3Rpb24gKG9iaiwgZGVlcCkge1xuXHRcdFx0dmFyIGksIGo7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZihvYmogJiYgb2JqLmNoaWxkcmVuICYmIG9iai5jaGlsZHJlbi5sZW5ndGgpIHtcblx0XHRcdFx0b2JqLmNoaWxkcmVuLnNvcnQodGhpcy5zZXR0aW5ncy5zb3J0LmJpbmQodGhpcykpO1xuXHRcdFx0XHRpZihkZWVwKSB7XG5cdFx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gb2JqLmNoaWxkcmVuX2QubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnNvcnQob2JqLmNoaWxkcmVuX2RbaV0sIGZhbHNlKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9O1xuXHR9O1xuXG5cdC8vIGluY2x1ZGUgdGhlIHNvcnQgcGx1Z2luIGJ5IGRlZmF1bHRcblx0Ly8gJC5qc3RyZWUuZGVmYXVsdHMucGx1Z2lucy5wdXNoKFwic29ydFwiKTtcblxuLyoqXG4gKiAjIyMgU3RhdGUgcGx1Z2luXG4gKlxuICogU2F2ZXMgdGhlIHN0YXRlIG9mIHRoZSB0cmVlIChzZWxlY3RlZCBub2Rlcywgb3BlbmVkIG5vZGVzKSBvbiB0aGUgdXNlcidzIGNvbXB1dGVyIHVzaW5nIGF2YWlsYWJsZSBvcHRpb25zIChsb2NhbFN0b3JhZ2UsIGNvb2tpZXMsIGV0YylcbiAqL1xuXG5cdHZhciB0byA9IGZhbHNlO1xuXHQvKipcblx0ICogc3RvcmVzIGFsbCBkZWZhdWx0cyBmb3IgdGhlIHN0YXRlIHBsdWdpblxuXHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5zdGF0ZVxuXHQgKiBAcGx1Z2luIHN0YXRlXG5cdCAqL1xuXHQkLmpzdHJlZS5kZWZhdWx0cy5zdGF0ZSA9IHtcblx0XHQvKipcblx0XHQgKiBBIHN0cmluZyBmb3IgdGhlIGtleSB0byB1c2Ugd2hlbiBzYXZpbmcgdGhlIGN1cnJlbnQgdHJlZSAoY2hhbmdlIGlmIHVzaW5nIG11bHRpcGxlIHRyZWVzIGluIHlvdXIgcHJvamVjdCkuIERlZmF1bHRzIHRvIGBqc3RyZWVgLlxuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLnN0YXRlLmtleVxuXHRcdCAqIEBwbHVnaW4gc3RhdGVcblx0XHQgKi9cblx0XHRrZXlcdFx0OiAnanN0cmVlJyxcblx0XHQvKipcblx0XHQgKiBBIHNwYWNlIHNlcGFyYXRlZCBsaXN0IG9mIGV2ZW50cyB0aGF0IHRyaWdnZXIgYSBzdGF0ZSBzYXZlLiBEZWZhdWx0cyB0byBgY2hhbmdlZC5qc3RyZWUgb3Blbl9ub2RlLmpzdHJlZSBjbG9zZV9ub2RlLmpzdHJlZWAuXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMuc3RhdGUuZXZlbnRzXG5cdFx0ICogQHBsdWdpbiBzdGF0ZVxuXHRcdCAqL1xuXHRcdGV2ZW50c1x0OiAnY2hhbmdlZC5qc3RyZWUgb3Blbl9ub2RlLmpzdHJlZSBjbG9zZV9ub2RlLmpzdHJlZSBjaGVja19ub2RlLmpzdHJlZSB1bmNoZWNrX25vZGUuanN0cmVlJyxcblx0XHQvKipcblx0XHQgKiBUaW1lIGluIG1pbGxpc2Vjb25kcyBhZnRlciB3aGljaCB0aGUgc3RhdGUgd2lsbCBleHBpcmUuIERlZmF1bHRzIHRvICdmYWxzZScgbWVhbmluZyAtIG5vIGV4cGlyZS5cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5zdGF0ZS50dGxcblx0XHQgKiBAcGx1Z2luIHN0YXRlXG5cdFx0ICovXG5cdFx0dHRsXHRcdDogZmFsc2UsXG5cdFx0LyoqXG5cdFx0ICogQSBmdW5jdGlvbiB0aGF0IHdpbGwgYmUgZXhlY3V0ZWQgcHJpb3IgdG8gcmVzdG9yaW5nIHN0YXRlIHdpdGggb25lIGFyZ3VtZW50IC0gdGhlIHN0YXRlIG9iamVjdC4gQ2FuIGJlIHVzZWQgdG8gY2xlYXIgdW53YW50ZWQgcGFydHMgb2YgdGhlIHN0YXRlLlxuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLnN0YXRlLmZpbHRlclxuXHRcdCAqIEBwbHVnaW4gc3RhdGVcblx0XHQgKi9cblx0XHRmaWx0ZXJcdDogZmFsc2UsXG5cdFx0LyoqXG5cdFx0ICogU2hvdWxkIGxvYWRlZCBub2RlcyBiZSByZXN0b3JlZCAoc2V0dGluZyB0aGlzIHRvIHRydWUgbWVhbnMgdGhhdCBpdCBpcyBwb3NzaWJsZSB0aGF0IHRoZSB3aG9sZSB0cmVlIHdpbGwgYmUgbG9hZGVkIGZvciBzb21lIHVzZXJzIC0gdXNlIHdpdGggY2F1dGlvbikuIERlZmF1bHRzIHRvIGBmYWxzZWBcblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy5zdGF0ZS5wcmVzZXJ2ZV9sb2FkZWRcblx0XHQgKiBAcGx1Z2luIHN0YXRlXG5cdFx0ICovXG5cdFx0cHJlc2VydmVfbG9hZGVkIDogZmFsc2Vcblx0fTtcblx0JC5qc3RyZWUucGx1Z2lucy5zdGF0ZSA9IGZ1bmN0aW9uIChvcHRpb25zLCBwYXJlbnQpIHtcblx0XHR0aGlzLmJpbmQgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRwYXJlbnQuYmluZC5jYWxsKHRoaXMpO1xuXHRcdFx0dmFyIGJpbmQgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5vbih0aGlzLnNldHRpbmdzLnN0YXRlLmV2ZW50cywgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdGlmKHRvKSB7IGNsZWFyVGltZW91dCh0byk7IH1cblx0XHRcdFx0XHR0byA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyB0aGlzLnNhdmVfc3RhdGUoKTsgfS5iaW5kKHRoaXMpLCAxMDApO1xuXHRcdFx0XHR9LmJpbmQodGhpcykpO1xuXHRcdFx0XHQvKipcblx0XHRcdFx0ICogdHJpZ2dlcmVkIHdoZW4gdGhlIHN0YXRlIHBsdWdpbiBpcyBmaW5pc2hlZCByZXN0b3JpbmcgdGhlIHN0YXRlIChhbmQgaW1tZWRpYXRlbHkgYWZ0ZXIgcmVhZHkgaWYgdGhlcmUgaXMgbm8gc3RhdGUgdG8gcmVzdG9yZSkuXG5cdFx0XHRcdCAqIEBldmVudFxuXHRcdFx0XHQgKiBAbmFtZSBzdGF0ZV9yZWFkeS5qc3RyZWVcblx0XHRcdFx0ICogQHBsdWdpbiBzdGF0ZVxuXHRcdFx0XHQgKi9cblx0XHRcdFx0dGhpcy50cmlnZ2VyKCdzdGF0ZV9yZWFkeScpO1xuXHRcdFx0fS5iaW5kKHRoaXMpO1xuXHRcdFx0dGhpcy5lbGVtZW50XG5cdFx0XHRcdC5vbihcInJlYWR5LmpzdHJlZVwiLCBmdW5jdGlvbiAoZSwgZGF0YSkge1xuXHRcdFx0XHRcdFx0dGhpcy5lbGVtZW50Lm9uZShcInJlc3RvcmVfc3RhdGUuanN0cmVlXCIsIGJpbmQpO1xuXHRcdFx0XHRcdFx0aWYoIXRoaXMucmVzdG9yZV9zdGF0ZSgpKSB7IGJpbmQoKTsgfVxuXHRcdFx0XHRcdH0uYmluZCh0aGlzKSk7XG5cdFx0fTtcblx0XHQvKipcblx0XHQgKiBzYXZlIHRoZSBzdGF0ZVxuXHRcdCAqIEBuYW1lIHNhdmVfc3RhdGUoKVxuXHRcdCAqIEBwbHVnaW4gc3RhdGVcblx0XHQgKi9cblx0XHR0aGlzLnNhdmVfc3RhdGUgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHR2YXIgdG0gPSB0aGlzLmdldF9zdGF0ZSgpO1xuXHRcdFx0aWYgKCF0aGlzLnNldHRpbmdzLnN0YXRlLnByZXNlcnZlX2xvYWRlZCkge1xuXHRcdFx0XHRkZWxldGUgdG0uY29yZS5sb2FkZWQ7XG5cdFx0XHR9XG5cdFx0XHR2YXIgc3QgPSB7ICdzdGF0ZScgOiB0bSwgJ3R0bCcgOiB0aGlzLnNldHRpbmdzLnN0YXRlLnR0bCwgJ3NlYycgOiArKG5ldyBEYXRlKCkpIH07XG5cdFx0XHQkLnZha2F0YS5zdG9yYWdlLnNldCh0aGlzLnNldHRpbmdzLnN0YXRlLmtleSwgSlNPTi5zdHJpbmdpZnkoc3QpKTtcblx0XHR9O1xuXHRcdC8qKlxuXHRcdCAqIHJlc3RvcmUgdGhlIHN0YXRlIGZyb20gdGhlIHVzZXIncyBjb21wdXRlclxuXHRcdCAqIEBuYW1lIHJlc3RvcmVfc3RhdGUoKVxuXHRcdCAqIEBwbHVnaW4gc3RhdGVcblx0XHQgKi9cblx0XHR0aGlzLnJlc3RvcmVfc3RhdGUgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHR2YXIgayA9ICQudmFrYXRhLnN0b3JhZ2UuZ2V0KHRoaXMuc2V0dGluZ3Muc3RhdGUua2V5KTtcblx0XHRcdGlmKCEhaykgeyB0cnkgeyBrID0gSlNPTi5wYXJzZShrKTsgfSBjYXRjaChleCkgeyByZXR1cm4gZmFsc2U7IH0gfVxuXHRcdFx0aWYoISFrICYmIGsudHRsICYmIGsuc2VjICYmICsobmV3IERhdGUoKSkgLSBrLnNlYyA+IGsudHRsKSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdFx0aWYoISFrICYmIGsuc3RhdGUpIHsgayA9IGsuc3RhdGU7IH1cblx0XHRcdGlmKCEhayAmJiAkLnZha2F0YS5pc19mdW5jdGlvbih0aGlzLnNldHRpbmdzLnN0YXRlLmZpbHRlcikpIHsgayA9IHRoaXMuc2V0dGluZ3Muc3RhdGUuZmlsdGVyLmNhbGwodGhpcywgayk7IH1cblx0XHRcdGlmKCEhaykge1xuXHRcdFx0XHRpZiAoIXRoaXMuc2V0dGluZ3Muc3RhdGUucHJlc2VydmVfbG9hZGVkKSB7XG5cdFx0XHRcdFx0ZGVsZXRlIGsuY29yZS5sb2FkZWQ7XG5cdFx0XHRcdH1cblx0XHRcdFx0dGhpcy5lbGVtZW50Lm9uZShcInNldF9zdGF0ZS5qc3RyZWVcIiwgZnVuY3Rpb24gKGUsIGRhdGEpIHsgZGF0YS5pbnN0YW5jZS50cmlnZ2VyKCdyZXN0b3JlX3N0YXRlJywgeyAnc3RhdGUnIDogJC5leHRlbmQodHJ1ZSwge30sIGspIH0pOyB9KTtcblx0XHRcdFx0dGhpcy5zZXRfc3RhdGUoayk7XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH07XG5cdFx0LyoqXG5cdFx0ICogY2xlYXIgdGhlIHN0YXRlIG9uIHRoZSB1c2VyJ3MgY29tcHV0ZXJcblx0XHQgKiBAbmFtZSBjbGVhcl9zdGF0ZSgpXG5cdFx0ICogQHBsdWdpbiBzdGF0ZVxuXHRcdCAqL1xuXHRcdHRoaXMuY2xlYXJfc3RhdGUgPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRyZXR1cm4gJC52YWthdGEuc3RvcmFnZS5kZWwodGhpcy5zZXR0aW5ncy5zdGF0ZS5rZXkpO1xuXHRcdH07XG5cdH07XG5cblx0KGZ1bmN0aW9uICgkLCB1bmRlZmluZWQpIHtcblx0XHQkLnZha2F0YS5zdG9yYWdlID0ge1xuXHRcdFx0Ly8gc2ltcGx5IHNwZWNpZnlpbmcgdGhlIGZ1bmN0aW9ucyBpbiBGRiB0aHJvd3MgYW4gZXJyb3Jcblx0XHRcdHNldCA6IGZ1bmN0aW9uIChrZXksIHZhbCkgeyByZXR1cm4gd2luZG93LmxvY2FsU3RvcmFnZS5zZXRJdGVtKGtleSwgdmFsKTsgfSxcblx0XHRcdGdldCA6IGZ1bmN0aW9uIChrZXkpIHsgcmV0dXJuIHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbShrZXkpOyB9LFxuXHRcdFx0ZGVsIDogZnVuY3Rpb24gKGtleSkgeyByZXR1cm4gd2luZG93LmxvY2FsU3RvcmFnZS5yZW1vdmVJdGVtKGtleSk7IH1cblx0XHR9O1xuXHR9KCQpKTtcblxuXHQvLyBpbmNsdWRlIHRoZSBzdGF0ZSBwbHVnaW4gYnkgZGVmYXVsdFxuXHQvLyAkLmpzdHJlZS5kZWZhdWx0cy5wbHVnaW5zLnB1c2goXCJzdGF0ZVwiKTtcblxuLyoqXG4gKiAjIyMgVHlwZXMgcGx1Z2luXG4gKlxuICogTWFrZXMgaXQgcG9zc2libGUgdG8gYWRkIHByZWRlZmluZWQgdHlwZXMgZm9yIGdyb3VwcyBvZiBub2Rlcywgd2hpY2ggbWFrZSBpdCBwb3NzaWJsZSB0byBlYXNpbHkgY29udHJvbCBuZXN0aW5nIHJ1bGVzIGFuZCBpY29uIGZvciBlYWNoIGdyb3VwLlxuICovXG5cblx0LyoqXG5cdCAqIEFuIG9iamVjdCBzdG9yaW5nIGFsbCB0eXBlcyBhcyBrZXkgdmFsdWUgcGFpcnMsIHdoZXJlIHRoZSBrZXkgaXMgdGhlIHR5cGUgbmFtZSBhbmQgdGhlIHZhbHVlIGlzIGFuIG9iamVjdCB0aGF0IGNvdWxkIGNvbnRhaW4gZm9sbG93aW5nIGtleXMgKGFsbCBvcHRpb25hbCkuXG5cdCAqXG5cdCAqICogYG1heF9jaGlsZHJlbmAgdGhlIG1heGltdW0gbnVtYmVyIG9mIGltbWVkaWF0ZSBjaGlsZHJlbiB0aGlzIG5vZGUgdHlwZSBjYW4gaGF2ZS4gRG8gbm90IHNwZWNpZnkgb3Igc2V0IHRvIGAtMWAgZm9yIHVubGltaXRlZC5cblx0ICogKiBgbWF4X2RlcHRoYCB0aGUgbWF4aW11bSBudW1iZXIgb2YgbmVzdGluZyB0aGlzIG5vZGUgdHlwZSBjYW4gaGF2ZS4gQSB2YWx1ZSBvZiBgMWAgd291bGQgbWVhbiB0aGF0IHRoZSBub2RlIGNhbiBoYXZlIGNoaWxkcmVuLCBidXQgbm8gZ3JhbmRjaGlsZHJlbi4gRG8gbm90IHNwZWNpZnkgb3Igc2V0IHRvIGAtMWAgZm9yIHVubGltaXRlZC5cblx0ICogKiBgdmFsaWRfY2hpbGRyZW5gIGFuIGFycmF5IG9mIG5vZGUgdHlwZSBzdHJpbmdzLCB0aGF0IG5vZGVzIG9mIHRoaXMgdHlwZSBjYW4gaGF2ZSBhcyBjaGlsZHJlbi4gRG8gbm90IHNwZWNpZnkgb3Igc2V0IHRvIGAtMWAgZm9yIG5vIGxpbWl0cy5cblx0ICogKiBgaWNvbmAgYSBzdHJpbmcgLSBjYW4gYmUgYSBwYXRoIHRvIGFuIGljb24gb3IgYSBjbGFzc05hbWUsIGlmIHVzaW5nIGFuIGltYWdlIHRoYXQgaXMgaW4gdGhlIGN1cnJlbnQgZGlyZWN0b3J5IHVzZSBhIGAuL2AgcHJlZml4LCBvdGhlcndpc2UgaXQgd2lsbCBiZSBkZXRlY3RlZCBhcyBhIGNsYXNzLiBPbWl0IHRvIHVzZSB0aGUgZGVmYXVsdCBpY29uIGZyb20geW91ciB0aGVtZS5cblx0ICogKiBgbGlfYXR0cmAgYW4gb2JqZWN0IG9mIHZhbHVlcyB3aGljaCB3aWxsIGJlIHVzZWQgdG8gYWRkIEhUTUwgYXR0cmlidXRlcyBvbiB0aGUgcmVzdWx0aW5nIExJIERPTSBub2RlIChtZXJnZWQgd2l0aCB0aGUgbm9kZSdzIG93biBkYXRhKVxuXHQgKiAqIGBhX2F0dHJgIGFuIG9iamVjdCBvZiB2YWx1ZXMgd2hpY2ggd2lsbCBiZSB1c2VkIHRvIGFkZCBIVE1MIGF0dHJpYnV0ZXMgb24gdGhlIHJlc3VsdGluZyBBIERPTSBub2RlIChtZXJnZWQgd2l0aCB0aGUgbm9kZSdzIG93biBkYXRhKVxuXHQgKlxuXHQgKiBUaGVyZSBhcmUgdHdvIHByZWRlZmluZWQgdHlwZXM6XG5cdCAqXG5cdCAqICogYCNgIHJlcHJlc2VudHMgdGhlIHJvb3Qgb2YgdGhlIHRyZWUsIGZvciBleGFtcGxlIGBtYXhfY2hpbGRyZW5gIHdvdWxkIGNvbnRyb2wgdGhlIG1heGltdW0gbnVtYmVyIG9mIHJvb3Qgbm9kZXMuXG5cdCAqICogYGRlZmF1bHRgIHJlcHJlc2VudHMgdGhlIGRlZmF1bHQgbm9kZSAtIGFueSBzZXR0aW5ncyBoZXJlIHdpbGwgYmUgYXBwbGllZCB0byBhbGwgbm9kZXMgdGhhdCBkbyBub3QgaGF2ZSBhIHR5cGUgc3BlY2lmaWVkLlxuXHQgKlxuXHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy50eXBlc1xuXHQgKiBAcGx1Z2luIHR5cGVzXG5cdCAqL1xuXHQkLmpzdHJlZS5kZWZhdWx0cy50eXBlcyA9IHtcblx0XHQnZGVmYXVsdCcgOiB7fVxuXHR9O1xuXHQkLmpzdHJlZS5kZWZhdWx0cy50eXBlc1skLmpzdHJlZS5yb290XSA9IHt9O1xuXG5cdCQuanN0cmVlLnBsdWdpbnMudHlwZXMgPSBmdW5jdGlvbiAob3B0aW9ucywgcGFyZW50KSB7XG5cdFx0dGhpcy5pbml0ID0gZnVuY3Rpb24gKGVsLCBvcHRpb25zKSB7XG5cdFx0XHR2YXIgaSwgajtcblx0XHRcdGlmKG9wdGlvbnMgJiYgb3B0aW9ucy50eXBlcyAmJiBvcHRpb25zLnR5cGVzWydkZWZhdWx0J10pIHtcblx0XHRcdFx0Zm9yKGkgaW4gb3B0aW9ucy50eXBlcykge1xuXHRcdFx0XHRcdGlmKGkgIT09IFwiZGVmYXVsdFwiICYmIGkgIT09ICQuanN0cmVlLnJvb3QgJiYgb3B0aW9ucy50eXBlcy5oYXNPd25Qcm9wZXJ0eShpKSkge1xuXHRcdFx0XHRcdFx0Zm9yKGogaW4gb3B0aW9ucy50eXBlc1snZGVmYXVsdCddKSB7XG5cdFx0XHRcdFx0XHRcdGlmKG9wdGlvbnMudHlwZXNbJ2RlZmF1bHQnXS5oYXNPd25Qcm9wZXJ0eShqKSAmJiBvcHRpb25zLnR5cGVzW2ldW2pdID09PSB1bmRlZmluZWQpIHtcblx0XHRcdFx0XHRcdFx0XHRvcHRpb25zLnR5cGVzW2ldW2pdID0gb3B0aW9ucy50eXBlc1snZGVmYXVsdCddW2pdO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRwYXJlbnQuaW5pdC5jYWxsKHRoaXMsIGVsLCBvcHRpb25zKTtcblx0XHRcdHRoaXMuX21vZGVsLmRhdGFbJC5qc3RyZWUucm9vdF0udHlwZSA9ICQuanN0cmVlLnJvb3Q7XG5cdFx0fTtcblx0XHR0aGlzLnJlZnJlc2ggPSBmdW5jdGlvbiAoc2tpcF9sb2FkaW5nLCBmb3JnZXRfc3RhdGUpIHtcblx0XHRcdHBhcmVudC5yZWZyZXNoLmNhbGwodGhpcywgc2tpcF9sb2FkaW5nLCBmb3JnZXRfc3RhdGUpO1xuXHRcdFx0dGhpcy5fbW9kZWwuZGF0YVskLmpzdHJlZS5yb290XS50eXBlID0gJC5qc3RyZWUucm9vdDtcblx0XHR9O1xuXHRcdHRoaXMuYmluZCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0XHQub24oJ21vZGVsLmpzdHJlZScsIGZ1bmN0aW9uIChlLCBkYXRhKSB7XG5cdFx0XHRcdFx0XHR2YXIgbSA9IHRoaXMuX21vZGVsLmRhdGEsXG5cdFx0XHRcdFx0XHRcdGRwYyA9IGRhdGEubm9kZXMsXG5cdFx0XHRcdFx0XHRcdHQgPSB0aGlzLnNldHRpbmdzLnR5cGVzLFxuXHRcdFx0XHRcdFx0XHRpLCBqLCBjID0gJ2RlZmF1bHQnLCBrO1xuXHRcdFx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gZHBjLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdFx0XHRjID0gJ2RlZmF1bHQnO1xuXHRcdFx0XHRcdFx0XHRpZihtW2RwY1tpXV0ub3JpZ2luYWwgJiYgbVtkcGNbaV1dLm9yaWdpbmFsLnR5cGUgJiYgdFttW2RwY1tpXV0ub3JpZ2luYWwudHlwZV0pIHtcblx0XHRcdFx0XHRcdFx0XHRjID0gbVtkcGNbaV1dLm9yaWdpbmFsLnR5cGU7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYobVtkcGNbaV1dLmRhdGEgJiYgbVtkcGNbaV1dLmRhdGEuanN0cmVlICYmIG1bZHBjW2ldXS5kYXRhLmpzdHJlZS50eXBlICYmIHRbbVtkcGNbaV1dLmRhdGEuanN0cmVlLnR5cGVdKSB7XG5cdFx0XHRcdFx0XHRcdFx0YyA9IG1bZHBjW2ldXS5kYXRhLmpzdHJlZS50eXBlO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdG1bZHBjW2ldXS50eXBlID0gYztcblx0XHRcdFx0XHRcdFx0aWYobVtkcGNbaV1dLmljb24gPT09IHRydWUgJiYgdFtjXS5pY29uICE9PSB1bmRlZmluZWQpIHtcblx0XHRcdFx0XHRcdFx0XHRtW2RwY1tpXV0uaWNvbiA9IHRbY10uaWNvbjtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRpZih0W2NdLmxpX2F0dHIgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdFtjXS5saV9hdHRyID09PSAnb2JqZWN0Jykge1xuXHRcdFx0XHRcdFx0XHRcdGZvciAoayBpbiB0W2NdLmxpX2F0dHIpIHtcblx0XHRcdFx0XHRcdFx0XHRcdGlmICh0W2NdLmxpX2F0dHIuaGFzT3duUHJvcGVydHkoaykpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKGsgPT09ICdpZCcpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRlbHNlIGlmIChtW2RwY1tpXV0ubGlfYXR0cltrXSA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0bVtkcGNbaV1dLmxpX2F0dHJba10gPSB0W2NdLmxpX2F0dHJba107XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdFx0ZWxzZSBpZiAoayA9PT0gJ2NsYXNzJykge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdG1bZHBjW2ldXS5saV9hdHRyWydjbGFzcyddID0gdFtjXS5saV9hdHRyWydjbGFzcyddICsgJyAnICsgbVtkcGNbaV1dLmxpX2F0dHJbJ2NsYXNzJ107XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aWYodFtjXS5hX2F0dHIgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdFtjXS5hX2F0dHIgPT09ICdvYmplY3QnKSB7XG5cdFx0XHRcdFx0XHRcdFx0Zm9yIChrIGluIHRbY10uYV9hdHRyKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAodFtjXS5hX2F0dHIuaGFzT3duUHJvcGVydHkoaykpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKGsgPT09ICdpZCcpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRlbHNlIGlmIChtW2RwY1tpXV0uYV9hdHRyW2tdID09PSB1bmRlZmluZWQpIHtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRtW2RwY1tpXV0uYV9hdHRyW2tdID0gdFtjXS5hX2F0dHJba107XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdFx0ZWxzZSBpZiAoayA9PT0gJ2hyZWYnICYmIG1bZHBjW2ldXS5hX2F0dHJba10gPT09ICcjJykge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdG1bZHBjW2ldXS5hX2F0dHJbJ2hyZWYnXSA9IHRbY10uYV9hdHRyWydocmVmJ107XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdFx0ZWxzZSBpZiAoayA9PT0gJ2NsYXNzJykge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdG1bZHBjW2ldXS5hX2F0dHJbJ2NsYXNzJ10gPSB0W2NdLmFfYXR0clsnY2xhc3MnXSArICcgJyArIG1bZHBjW2ldXS5hX2F0dHJbJ2NsYXNzJ107XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdG1bJC5qc3RyZWUucm9vdF0udHlwZSA9ICQuanN0cmVlLnJvb3Q7XG5cdFx0XHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHRcdHBhcmVudC5iaW5kLmNhbGwodGhpcyk7XG5cdFx0fTtcblx0XHR0aGlzLmdldF9qc29uID0gZnVuY3Rpb24gKG9iaiwgb3B0aW9ucywgZmxhdCkge1xuXHRcdFx0dmFyIGksIGosXG5cdFx0XHRcdG0gPSB0aGlzLl9tb2RlbC5kYXRhLFxuXHRcdFx0XHRvcHQgPSBvcHRpb25zID8gJC5leHRlbmQodHJ1ZSwge30sIG9wdGlvbnMsIHtub19pZDpmYWxzZX0pIDoge30sXG5cdFx0XHRcdHRtcCA9IHBhcmVudC5nZXRfanNvbi5jYWxsKHRoaXMsIG9iaiwgb3B0LCBmbGF0KTtcblx0XHRcdGlmKHRtcCA9PT0gZmFsc2UpIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHRpZigkLnZha2F0YS5pc19hcnJheSh0bXApKSB7XG5cdFx0XHRcdGZvcihpID0gMCwgaiA9IHRtcC5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHR0bXBbaV0udHlwZSA9IHRtcFtpXS5pZCAmJiBtW3RtcFtpXS5pZF0gJiYgbVt0bXBbaV0uaWRdLnR5cGUgPyBtW3RtcFtpXS5pZF0udHlwZSA6IFwiZGVmYXVsdFwiO1xuXHRcdFx0XHRcdGlmKG9wdGlvbnMgJiYgb3B0aW9ucy5ub19pZCkge1xuXHRcdFx0XHRcdFx0ZGVsZXRlIHRtcFtpXS5pZDtcblx0XHRcdFx0XHRcdGlmKHRtcFtpXS5saV9hdHRyICYmIHRtcFtpXS5saV9hdHRyLmlkKSB7XG5cdFx0XHRcdFx0XHRcdGRlbGV0ZSB0bXBbaV0ubGlfYXR0ci5pZDtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmKHRtcFtpXS5hX2F0dHIgJiYgdG1wW2ldLmFfYXR0ci5pZCkge1xuXHRcdFx0XHRcdFx0XHRkZWxldGUgdG1wW2ldLmFfYXR0ci5pZDtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGVsc2Uge1xuXHRcdFx0XHR0bXAudHlwZSA9IHRtcC5pZCAmJiBtW3RtcC5pZF0gJiYgbVt0bXAuaWRdLnR5cGUgPyBtW3RtcC5pZF0udHlwZSA6IFwiZGVmYXVsdFwiO1xuXHRcdFx0XHRpZihvcHRpb25zICYmIG9wdGlvbnMubm9faWQpIHtcblx0XHRcdFx0XHR0bXAgPSB0aGlzLl9kZWxldGVfaWRzKHRtcCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiB0bXA7XG5cdFx0fTtcblx0XHR0aGlzLl9kZWxldGVfaWRzID0gZnVuY3Rpb24gKHRtcCkge1xuXHRcdFx0aWYoJC52YWthdGEuaXNfYXJyYXkodG1wKSkge1xuXHRcdFx0XHRmb3IodmFyIGkgPSAwLCBqID0gdG1wLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdHRtcFtpXSA9IHRoaXMuX2RlbGV0ZV9pZHModG1wW2ldKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdG1wO1xuXHRcdFx0fVxuXHRcdFx0ZGVsZXRlIHRtcC5pZDtcblx0XHRcdGlmKHRtcC5saV9hdHRyICYmIHRtcC5saV9hdHRyLmlkKSB7XG5cdFx0XHRcdGRlbGV0ZSB0bXAubGlfYXR0ci5pZDtcblx0XHRcdH1cblx0XHRcdGlmKHRtcC5hX2F0dHIgJiYgdG1wLmFfYXR0ci5pZCkge1xuXHRcdFx0XHRkZWxldGUgdG1wLmFfYXR0ci5pZDtcblx0XHRcdH1cblx0XHRcdGlmKHRtcC5jaGlsZHJlbiAmJiAkLnZha2F0YS5pc19hcnJheSh0bXAuY2hpbGRyZW4pKSB7XG5cdFx0XHRcdHRtcC5jaGlsZHJlbiA9IHRoaXMuX2RlbGV0ZV9pZHModG1wLmNoaWxkcmVuKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiB0bXA7XG5cdFx0fTtcblx0XHR0aGlzLmNoZWNrID0gZnVuY3Rpb24gKGNoaywgb2JqLCBwYXIsIHBvcywgbW9yZSkge1xuXHRcdFx0aWYocGFyZW50LmNoZWNrLmNhbGwodGhpcywgY2hrLCBvYmosIHBhciwgcG9zLCBtb3JlKSA9PT0gZmFsc2UpIHsgcmV0dXJuIGZhbHNlOyB9XG5cdFx0XHRvYmogPSBvYmogJiYgb2JqLmlkID8gb2JqIDogdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0cGFyID0gcGFyICYmIHBhci5pZCA/IHBhciA6IHRoaXMuZ2V0X25vZGUocGFyKTtcblx0XHRcdHZhciBtID0gb2JqICYmIG9iai5pZCA/IChtb3JlICYmIG1vcmUub3JpZ2luID8gbW9yZS5vcmlnaW4gOiAkLmpzdHJlZS5yZWZlcmVuY2Uob2JqLmlkKSkgOiBudWxsLCB0bXAsIGQsIGksIGo7XG5cdFx0XHRtID0gbSAmJiBtLl9tb2RlbCAmJiBtLl9tb2RlbC5kYXRhID8gbS5fbW9kZWwuZGF0YSA6IG51bGw7XG5cdFx0XHRzd2l0Y2goY2hrKSB7XG5cdFx0XHRcdGNhc2UgXCJjcmVhdGVfbm9kZVwiOlxuXHRcdFx0XHRjYXNlIFwibW92ZV9ub2RlXCI6XG5cdFx0XHRcdGNhc2UgXCJjb3B5X25vZGVcIjpcblx0XHRcdFx0XHRpZihjaGsgIT09ICdtb3ZlX25vZGUnIHx8ICQuaW5BcnJheShvYmouaWQsIHBhci5jaGlsZHJlbikgPT09IC0xKSB7XG5cdFx0XHRcdFx0XHR0bXAgPSB0aGlzLmdldF9ydWxlcyhwYXIpO1xuXHRcdFx0XHRcdFx0aWYodG1wLm1heF9jaGlsZHJlbiAhPT0gdW5kZWZpbmVkICYmIHRtcC5tYXhfY2hpbGRyZW4gIT09IC0xICYmIHRtcC5tYXhfY2hpbGRyZW4gPT09IHBhci5jaGlsZHJlbi5sZW5ndGgpIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLmxhc3RfZXJyb3IgPSB7ICdlcnJvcicgOiAnY2hlY2snLCAncGx1Z2luJyA6ICd0eXBlcycsICdpZCcgOiAndHlwZXNfMDEnLCAncmVhc29uJyA6ICdtYXhfY2hpbGRyZW4gcHJldmVudHMgZnVuY3Rpb246ICcgKyBjaGssICdkYXRhJyA6IEpTT04uc3RyaW5naWZ5KHsgJ2NoaycgOiBjaGssICdwb3MnIDogcG9zLCAnb2JqJyA6IG9iaiAmJiBvYmouaWQgPyBvYmouaWQgOiBmYWxzZSwgJ3BhcicgOiBwYXIgJiYgcGFyLmlkID8gcGFyLmlkIDogZmFsc2UgfSkgfTtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYodG1wLnZhbGlkX2NoaWxkcmVuICE9PSB1bmRlZmluZWQgJiYgdG1wLnZhbGlkX2NoaWxkcmVuICE9PSAtMSAmJiAkLmluQXJyYXkoKG9iai50eXBlIHx8ICdkZWZhdWx0JyksIHRtcC52YWxpZF9jaGlsZHJlbikgPT09IC0xKSB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5sYXN0X2Vycm9yID0geyAnZXJyb3InIDogJ2NoZWNrJywgJ3BsdWdpbicgOiAndHlwZXMnLCAnaWQnIDogJ3R5cGVzXzAyJywgJ3JlYXNvbicgOiAndmFsaWRfY2hpbGRyZW4gcHJldmVudHMgZnVuY3Rpb246ICcgKyBjaGssICdkYXRhJyA6IEpTT04uc3RyaW5naWZ5KHsgJ2NoaycgOiBjaGssICdwb3MnIDogcG9zLCAnb2JqJyA6IG9iaiAmJiBvYmouaWQgPyBvYmouaWQgOiBmYWxzZSwgJ3BhcicgOiBwYXIgJiYgcGFyLmlkID8gcGFyLmlkIDogZmFsc2UgfSkgfTtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYobSAmJiBvYmouY2hpbGRyZW5fZCAmJiBvYmoucGFyZW50cykge1xuXHRcdFx0XHRcdFx0XHRkID0gMDtcblx0XHRcdFx0XHRcdFx0Zm9yKGkgPSAwLCBqID0gb2JqLmNoaWxkcmVuX2QubGVuZ3RoOyBpIDwgajsgaSsrKSB7XG5cdFx0XHRcdFx0XHRcdFx0ZCA9IE1hdGgubWF4KGQsIG1bb2JqLmNoaWxkcmVuX2RbaV1dLnBhcmVudHMubGVuZ3RoKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRkID0gZCAtIG9iai5wYXJlbnRzLmxlbmd0aCArIDE7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRpZihkIDw9IDAgfHwgZCA9PT0gdW5kZWZpbmVkKSB7IGQgPSAxOyB9XG5cdFx0XHRcdFx0XHRkbyB7XG5cdFx0XHRcdFx0XHRcdGlmKHRtcC5tYXhfZGVwdGggIT09IHVuZGVmaW5lZCAmJiB0bXAubWF4X2RlcHRoICE9PSAtMSAmJiB0bXAubWF4X2RlcHRoIDwgZCkge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5sYXN0X2Vycm9yID0geyAnZXJyb3InIDogJ2NoZWNrJywgJ3BsdWdpbicgOiAndHlwZXMnLCAnaWQnIDogJ3R5cGVzXzAzJywgJ3JlYXNvbicgOiAnbWF4X2RlcHRoIHByZXZlbnRzIGZ1bmN0aW9uOiAnICsgY2hrLCAnZGF0YScgOiBKU09OLnN0cmluZ2lmeSh7ICdjaGsnIDogY2hrLCAncG9zJyA6IHBvcywgJ29iaicgOiBvYmogJiYgb2JqLmlkID8gb2JqLmlkIDogZmFsc2UsICdwYXInIDogcGFyICYmIHBhci5pZCA/IHBhci5pZCA6IGZhbHNlIH0pIH07XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdHBhciA9IHRoaXMuZ2V0X25vZGUocGFyLnBhcmVudCk7XG5cdFx0XHRcdFx0XHRcdHRtcCA9IHRoaXMuZ2V0X3J1bGVzKHBhcik7XG5cdFx0XHRcdFx0XHRcdGQrKztcblx0XHRcdFx0XHRcdH0gd2hpbGUocGFyKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9O1xuXHRcdC8qKlxuXHRcdCAqIHVzZWQgdG8gcmV0cmlldmUgdGhlIHR5cGUgc2V0dGluZ3Mgb2JqZWN0IGZvciBhIG5vZGVcblx0XHQgKiBAbmFtZSBnZXRfcnVsZXMob2JqKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9iaiB0aGUgbm9kZSB0byBmaW5kIHRoZSBydWxlcyBmb3Jcblx0XHQgKiBAcmV0dXJuIHtPYmplY3R9XG5cdFx0ICogQHBsdWdpbiB0eXBlc1xuXHRcdCAqL1xuXHRcdHRoaXMuZ2V0X3J1bGVzID0gZnVuY3Rpb24gKG9iaikge1xuXHRcdFx0b2JqID0gdGhpcy5nZXRfbm9kZShvYmopO1xuXHRcdFx0aWYoIW9iaikgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdHZhciB0bXAgPSB0aGlzLmdldF90eXBlKG9iaiwgdHJ1ZSk7XG5cdFx0XHRpZih0bXAubWF4X2RlcHRoID09PSB1bmRlZmluZWQpIHsgdG1wLm1heF9kZXB0aCA9IC0xOyB9XG5cdFx0XHRpZih0bXAubWF4X2NoaWxkcmVuID09PSB1bmRlZmluZWQpIHsgdG1wLm1heF9jaGlsZHJlbiA9IC0xOyB9XG5cdFx0XHRpZih0bXAudmFsaWRfY2hpbGRyZW4gPT09IHVuZGVmaW5lZCkgeyB0bXAudmFsaWRfY2hpbGRyZW4gPSAtMTsgfVxuXHRcdFx0cmV0dXJuIHRtcDtcblx0XHR9O1xuXHRcdC8qKlxuXHRcdCAqIHVzZWQgdG8gcmV0cmlldmUgdGhlIHR5cGUgc3RyaW5nIG9yIHNldHRpbmdzIG9iamVjdCBmb3IgYSBub2RlXG5cdFx0ICogQG5hbWUgZ2V0X3R5cGUob2JqIFssIHJ1bGVzXSlcblx0XHQgKiBAcGFyYW0ge21peGVkfSBvYmogdGhlIG5vZGUgdG8gZmluZCB0aGUgcnVsZXMgZm9yXG5cdFx0ICogQHBhcmFtIHtCb29sZWFufSBydWxlcyBpZiBzZXQgdG8gYHRydWVgIGluc3RlYWQgb2YgYSBzdHJpbmcgdGhlIHNldHRpbmdzIG9iamVjdCB3aWxsIGJlIHJldHVybmVkXG5cdFx0ICogQHJldHVybiB7U3RyaW5nfE9iamVjdH1cblx0XHQgKiBAcGx1Z2luIHR5cGVzXG5cdFx0ICovXG5cdFx0dGhpcy5nZXRfdHlwZSA9IGZ1bmN0aW9uIChvYmosIHJ1bGVzKSB7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRyZXR1cm4gKCFvYmopID8gZmFsc2UgOiAoIHJ1bGVzID8gJC5leHRlbmQoeyAndHlwZScgOiBvYmoudHlwZSB9LCB0aGlzLnNldHRpbmdzLnR5cGVzW29iai50eXBlXSkgOiBvYmoudHlwZSk7XG5cdFx0fTtcblx0XHQvKipcblx0XHQgKiB1c2VkIHRvIGNoYW5nZSBhIG5vZGUncyB0eXBlXG5cdFx0ICogQG5hbWUgc2V0X3R5cGUob2JqLCB0eXBlKVxuXHRcdCAqIEBwYXJhbSB7bWl4ZWR9IG9iaiB0aGUgbm9kZSB0byBjaGFuZ2Vcblx0XHQgKiBAcGFyYW0ge1N0cmluZ30gdHlwZSB0aGUgbmV3IHR5cGVcblx0XHQgKiBAcGx1Z2luIHR5cGVzXG5cdFx0ICovXG5cdFx0dGhpcy5zZXRfdHlwZSA9IGZ1bmN0aW9uIChvYmosIHR5cGUpIHtcblx0XHRcdHZhciBtID0gdGhpcy5fbW9kZWwuZGF0YSwgdCwgdDEsIHQyLCBvbGRfdHlwZSwgb2xkX2ljb24sIGssIGQsIGE7XG5cdFx0XHRpZigkLnZha2F0YS5pc19hcnJheShvYmopKSB7XG5cdFx0XHRcdG9iaiA9IG9iai5zbGljZSgpO1xuXHRcdFx0XHRmb3IodDEgPSAwLCB0MiA9IG9iai5sZW5ndGg7IHQxIDwgdDI7IHQxKyspIHtcblx0XHRcdFx0XHR0aGlzLnNldF90eXBlKG9ialt0MV0sIHR5cGUpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0dCA9IHRoaXMuc2V0dGluZ3MudHlwZXM7XG5cdFx0XHRvYmogPSB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRpZighdFt0eXBlXSB8fCAhb2JqKSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdFx0ZCA9IHRoaXMuZ2V0X25vZGUob2JqLCB0cnVlKTtcblx0XHRcdGlmIChkICYmIGQubGVuZ3RoKSB7XG5cdFx0XHRcdGEgPSBkLmNoaWxkcmVuKCcuanN0cmVlLWFuY2hvcicpO1xuXHRcdFx0fVxuXHRcdFx0b2xkX3R5cGUgPSBvYmoudHlwZTtcblx0XHRcdG9sZF9pY29uID0gdGhpcy5nZXRfaWNvbihvYmopO1xuXHRcdFx0b2JqLnR5cGUgPSB0eXBlO1xuXHRcdFx0aWYob2xkX2ljb24gPT09IHRydWUgfHwgIXRbb2xkX3R5cGVdIHx8ICh0W29sZF90eXBlXS5pY29uICE9PSB1bmRlZmluZWQgJiYgb2xkX2ljb24gPT09IHRbb2xkX3R5cGVdLmljb24pKSB7XG5cdFx0XHRcdHRoaXMuc2V0X2ljb24ob2JqLCB0W3R5cGVdLmljb24gIT09IHVuZGVmaW5lZCA/IHRbdHlwZV0uaWNvbiA6IHRydWUpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyByZW1vdmUgb2xkIHR5cGUgcHJvcHNcblx0XHRcdGlmKHRbb2xkX3R5cGVdICYmIHRbb2xkX3R5cGVdLmxpX2F0dHIgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2YgdFtvbGRfdHlwZV0ubGlfYXR0ciA9PT0gJ29iamVjdCcpIHtcblx0XHRcdFx0Zm9yIChrIGluIHRbb2xkX3R5cGVdLmxpX2F0dHIpIHtcblx0XHRcdFx0XHRpZiAodFtvbGRfdHlwZV0ubGlfYXR0ci5oYXNPd25Qcm9wZXJ0eShrKSkge1xuXHRcdFx0XHRcdFx0aWYgKGsgPT09ICdpZCcpIHtcblx0XHRcdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRlbHNlIGlmIChrID09PSAnY2xhc3MnKSB7XG5cdFx0XHRcdFx0XHRcdG1bb2JqLmlkXS5saV9hdHRyWydjbGFzcyddID0gKG1bb2JqLmlkXS5saV9hdHRyWydjbGFzcyddIHx8ICcnKS5yZXBsYWNlKHRbb2xkX3R5cGVdLmxpX2F0dHJba10sICcnKTtcblx0XHRcdFx0XHRcdFx0aWYgKGQpIHsgZC5yZW1vdmVDbGFzcyh0W29sZF90eXBlXS5saV9hdHRyW2tdKTsgfVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0ZWxzZSBpZiAobVtvYmouaWRdLmxpX2F0dHJba10gPT09IHRbb2xkX3R5cGVdLmxpX2F0dHJba10pIHtcblx0XHRcdFx0XHRcdFx0bVtvYmouaWRdLmxpX2F0dHJba10gPSBudWxsO1xuXHRcdFx0XHRcdFx0XHRpZiAoZCkgeyBkLnJlbW92ZUF0dHIoayk7IH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmKHRbb2xkX3R5cGVdICYmIHRbb2xkX3R5cGVdLmFfYXR0ciAhPT0gdW5kZWZpbmVkICYmIHR5cGVvZiB0W29sZF90eXBlXS5hX2F0dHIgPT09ICdvYmplY3QnKSB7XG5cdFx0XHRcdGZvciAoayBpbiB0W29sZF90eXBlXS5hX2F0dHIpIHtcblx0XHRcdFx0XHRpZiAodFtvbGRfdHlwZV0uYV9hdHRyLmhhc093blByb3BlcnR5KGspKSB7XG5cdFx0XHRcdFx0XHRpZiAoayA9PT0gJ2lkJykge1xuXHRcdFx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGVsc2UgaWYgKGsgPT09ICdjbGFzcycpIHtcblx0XHRcdFx0XHRcdFx0bVtvYmouaWRdLmFfYXR0clsnY2xhc3MnXSA9IChtW29iai5pZF0uYV9hdHRyWydjbGFzcyddIHx8ICcnKS5yZXBsYWNlKHRbb2xkX3R5cGVdLmFfYXR0cltrXSwgJycpO1xuXHRcdFx0XHRcdFx0XHRpZiAoYSkgeyBhLnJlbW92ZUNsYXNzKHRbb2xkX3R5cGVdLmFfYXR0cltrXSk7IH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGVsc2UgaWYgKG1bb2JqLmlkXS5hX2F0dHJba10gPT09IHRbb2xkX3R5cGVdLmFfYXR0cltrXSkge1xuXHRcdFx0XHRcdFx0XHRpZiAoayA9PT0gJ2hyZWYnKSB7XG5cdFx0XHRcdFx0XHRcdFx0bVtvYmouaWRdLmFfYXR0cltrXSA9ICcjJztcblx0XHRcdFx0XHRcdFx0XHRpZiAoYSkgeyBhLmF0dHIoJ2hyZWYnLCAnIycpOyB9XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0ZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0ZGVsZXRlIG1bb2JqLmlkXS5hX2F0dHJba107XG5cdFx0XHRcdFx0XHRcdFx0aWYgKGEpIHsgYS5yZW1vdmVBdHRyKGspOyB9XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly8gYWRkIG5ldyBwcm9wc1xuXHRcdFx0aWYodFt0eXBlXS5saV9hdHRyICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRbdHlwZV0ubGlfYXR0ciA9PT0gJ29iamVjdCcpIHtcblx0XHRcdFx0Zm9yIChrIGluIHRbdHlwZV0ubGlfYXR0cikge1xuXHRcdFx0XHRcdGlmICh0W3R5cGVdLmxpX2F0dHIuaGFzT3duUHJvcGVydHkoaykpIHtcblx0XHRcdFx0XHRcdGlmIChrID09PSAnaWQnKSB7XG5cdFx0XHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0ZWxzZSBpZiAobVtvYmouaWRdLmxpX2F0dHJba10gPT09IHVuZGVmaW5lZCkge1xuXHRcdFx0XHRcdFx0XHRtW29iai5pZF0ubGlfYXR0cltrXSA9IHRbdHlwZV0ubGlfYXR0cltrXTtcblx0XHRcdFx0XHRcdFx0aWYgKGQpIHtcblx0XHRcdFx0XHRcdFx0XHRpZiAoayA9PT0gJ2NsYXNzJykge1xuXHRcdFx0XHRcdFx0XHRcdFx0ZC5hZGRDbGFzcyh0W3R5cGVdLmxpX2F0dHJba10pO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRcdGQuYXR0cihrLCB0W3R5cGVdLmxpX2F0dHJba10pO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0ZWxzZSBpZiAoayA9PT0gJ2NsYXNzJykge1xuXHRcdFx0XHRcdFx0XHRtW29iai5pZF0ubGlfYXR0clsnY2xhc3MnXSA9IHRbdHlwZV0ubGlfYXR0cltrXSArICcgJyArIG1bb2JqLmlkXS5saV9hdHRyWydjbGFzcyddO1xuXHRcdFx0XHRcdFx0XHRpZiAoZCkgeyBkLmFkZENsYXNzKHRbdHlwZV0ubGlfYXR0cltrXSk7IH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmKHRbdHlwZV0uYV9hdHRyICE9PSB1bmRlZmluZWQgJiYgdHlwZW9mIHRbdHlwZV0uYV9hdHRyID09PSAnb2JqZWN0Jykge1xuXHRcdFx0XHRmb3IgKGsgaW4gdFt0eXBlXS5hX2F0dHIpIHtcblx0XHRcdFx0XHRpZiAodFt0eXBlXS5hX2F0dHIuaGFzT3duUHJvcGVydHkoaykpIHtcblx0XHRcdFx0XHRcdGlmIChrID09PSAnaWQnKSB7XG5cdFx0XHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0ZWxzZSBpZiAobVtvYmouaWRdLmFfYXR0cltrXSA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRcdFx0XHRcdG1bb2JqLmlkXS5hX2F0dHJba10gPSB0W3R5cGVdLmFfYXR0cltrXTtcblx0XHRcdFx0XHRcdFx0aWYgKGEpIHtcblx0XHRcdFx0XHRcdFx0XHRpZiAoayA9PT0gJ2NsYXNzJykge1xuXHRcdFx0XHRcdFx0XHRcdFx0YS5hZGRDbGFzcyh0W3R5cGVdLmFfYXR0cltrXSk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdFx0YS5hdHRyKGssIHRbdHlwZV0uYV9hdHRyW2tdKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGVsc2UgaWYgKGsgPT09ICdocmVmJyAmJiBtW29iai5pZF0uYV9hdHRyW2tdID09PSAnIycpIHtcblx0XHRcdFx0XHRcdFx0bVtvYmouaWRdLmFfYXR0clsnaHJlZiddID0gdFt0eXBlXS5hX2F0dHJbJ2hyZWYnXTtcblx0XHRcdFx0XHRcdFx0aWYgKGEpIHsgYS5hdHRyKCdocmVmJywgdFt0eXBlXS5hX2F0dHJbJ2hyZWYnXSk7IH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGVsc2UgaWYgKGsgPT09ICdjbGFzcycpIHtcblx0XHRcdFx0XHRcdFx0bVtvYmouaWRdLmFfYXR0clsnY2xhc3MnXSA9IHRbdHlwZV0uYV9hdHRyWydjbGFzcyddICsgJyAnICsgbVtvYmouaWRdLmFfYXR0clsnY2xhc3MnXTtcblx0XHRcdFx0XHRcdFx0aWYgKGEpIHsgYS5hZGRDbGFzcyh0W3R5cGVdLmFfYXR0cltrXSk7IH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fTtcblx0fTtcblx0Ly8gaW5jbHVkZSB0aGUgdHlwZXMgcGx1Z2luIGJ5IGRlZmF1bHRcblx0Ly8gJC5qc3RyZWUuZGVmYXVsdHMucGx1Z2lucy5wdXNoKFwidHlwZXNcIik7XG5cblxuLyoqXG4gKiAjIyMgVW5pcXVlIHBsdWdpblxuICpcbiAqIEVuZm9yY2VzIHRoYXQgbm8gbm9kZXMgd2l0aCB0aGUgc2FtZSBuYW1lIGNhbiBjb2V4aXN0IGFzIHNpYmxpbmdzLlxuICovXG5cblx0LyoqXG5cdCAqIHN0b3JlcyBhbGwgZGVmYXVsdHMgZm9yIHRoZSB1bmlxdWUgcGx1Z2luXG5cdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLnVuaXF1ZVxuXHQgKiBAcGx1Z2luIHVuaXF1ZVxuXHQgKi9cblx0JC5qc3RyZWUuZGVmYXVsdHMudW5pcXVlID0ge1xuXHRcdC8qKlxuXHRcdCAqIEluZGljYXRlcyBpZiB0aGUgY29tcGFyaXNvbiBzaG91bGQgYmUgY2FzZSBzZW5zaXRpdmUuIERlZmF1bHQgaXMgYGZhbHNlYC5cblx0XHQgKiBAbmFtZSAkLmpzdHJlZS5kZWZhdWx0cy51bmlxdWUuY2FzZV9zZW5zaXRpdmVcblx0XHQgKiBAcGx1Z2luIHVuaXF1ZVxuXHRcdCAqL1xuXHRcdGNhc2Vfc2Vuc2l0aXZlIDogZmFsc2UsXG5cdFx0LyoqXG5cdFx0ICogSW5kaWNhdGVzIGlmIHdoaXRlIHNwYWNlIHNob3VsZCBiZSB0cmltbWVkIGJlZm9yZSB0aGUgY29tcGFyaXNvbi4gRGVmYXVsdCBpcyBgZmFsc2VgLlxuXHRcdCAqIEBuYW1lICQuanN0cmVlLmRlZmF1bHRzLnVuaXF1ZS50cmltX3doaXRlc3BhY2Vcblx0XHQgKiBAcGx1Z2luIHVuaXF1ZVxuXHRcdCAqL1xuXHRcdHRyaW1fd2hpdGVzcGFjZSA6IGZhbHNlLFxuXHRcdC8qKlxuXHRcdCAqIEEgY2FsbGJhY2sgZXhlY3V0ZWQgaW4gdGhlIGluc3RhbmNlJ3Mgc2NvcGUgd2hlbiBhIG5ldyBub2RlIGlzIGNyZWF0ZWQgYW5kIHRoZSBuYW1lIGlzIGFscmVhZHkgdGFrZW4sIHRoZSB0d28gYXJndW1lbnRzIGFyZSB0aGUgY29uZmxpY3RpbmcgbmFtZSBhbmQgdGhlIGNvdW50ZXIuIFRoZSBkZWZhdWx0IHdpbGwgcHJvZHVjZSByZXN1bHRzIGxpa2UgYE5ldyBub2RlICgyKWAuXG5cdFx0ICogQG5hbWUgJC5qc3RyZWUuZGVmYXVsdHMudW5pcXVlLmR1cGxpY2F0ZVxuXHRcdCAqIEBwbHVnaW4gdW5pcXVlXG5cdFx0ICovXG5cdFx0ZHVwbGljYXRlIDogZnVuY3Rpb24gKG5hbWUsIGNvdW50ZXIpIHtcblx0XHRcdHJldHVybiBuYW1lICsgJyAoJyArIGNvdW50ZXIgKyAnKSc7XG5cdFx0fVxuXHR9O1xuXG5cdCQuanN0cmVlLnBsdWdpbnMudW5pcXVlID0gZnVuY3Rpb24gKG9wdGlvbnMsIHBhcmVudCkge1xuXHRcdHRoaXMuY2hlY2sgPSBmdW5jdGlvbiAoY2hrLCBvYmosIHBhciwgcG9zLCBtb3JlKSB7XG5cdFx0XHRpZihwYXJlbnQuY2hlY2suY2FsbCh0aGlzLCBjaGssIG9iaiwgcGFyLCBwb3MsIG1vcmUpID09PSBmYWxzZSkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHRcdG9iaiA9IG9iaiAmJiBvYmouaWQgPyBvYmogOiB0aGlzLmdldF9ub2RlKG9iaik7XG5cdFx0XHRwYXIgPSBwYXIgJiYgcGFyLmlkID8gcGFyIDogdGhpcy5nZXRfbm9kZShwYXIpO1xuXHRcdFx0aWYoIXBhciB8fCAhcGFyLmNoaWxkcmVuKSB7IHJldHVybiB0cnVlOyB9XG5cdFx0XHR2YXIgbiA9IGNoayA9PT0gXCJyZW5hbWVfbm9kZVwiID8gcG9zIDogb2JqLnRleHQsXG5cdFx0XHRcdGMgPSBbXSxcblx0XHRcdFx0cyA9IHRoaXMuc2V0dGluZ3MudW5pcXVlLmNhc2Vfc2Vuc2l0aXZlLFxuXHRcdFx0XHR3ID0gdGhpcy5zZXR0aW5ncy51bmlxdWUudHJpbV93aGl0ZXNwYWNlLFxuXHRcdFx0XHRtID0gdGhpcy5fbW9kZWwuZGF0YSwgaSwgaiwgdDtcblx0XHRcdGZvcihpID0gMCwgaiA9IHBhci5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0dCA9IG1bcGFyLmNoaWxkcmVuW2ldXS50ZXh0O1xuXHRcdFx0XHRpZiAoIXMpIHtcblx0XHRcdFx0XHR0ID0gdC50b0xvd2VyQ2FzZSgpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICh3KSB7XG5cdFx0XHRcdFx0dCA9IHQucmVwbGFjZSgvXltcXHNcXHVGRUZGXFx4QTBdK3xbXFxzXFx1RkVGRlxceEEwXSskL2csICcnKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRjLnB1c2godCk7XG5cdFx0XHR9XG5cdFx0XHRpZighcykgeyBuID0gbi50b0xvd2VyQ2FzZSgpOyB9XG5cdFx0XHRpZiAodykgeyBuID0gbi5yZXBsYWNlKC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZywgJycpOyB9XG5cdFx0XHRzd2l0Y2goY2hrKSB7XG5cdFx0XHRcdGNhc2UgXCJkZWxldGVfbm9kZVwiOlxuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHRjYXNlIFwicmVuYW1lX25vZGVcIjpcblx0XHRcdFx0XHR0ID0gb2JqLnRleHQgfHwgJyc7XG5cdFx0XHRcdFx0aWYgKCFzKSB7XG5cdFx0XHRcdFx0XHR0ID0gdC50b0xvd2VyQ2FzZSgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZiAodykge1xuXHRcdFx0XHRcdFx0dCA9IHQucmVwbGFjZSgvXltcXHNcXHVGRUZGXFx4QTBdK3xbXFxzXFx1RkVGRlxceEEwXSskL2csICcnKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aSA9ICgkLmluQXJyYXkobiwgYykgPT09IC0xIHx8IChvYmoudGV4dCAmJiB0ID09PSBuKSk7XG5cdFx0XHRcdFx0aWYoIWkpIHtcblx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5sYXN0X2Vycm9yID0geyAnZXJyb3InIDogJ2NoZWNrJywgJ3BsdWdpbicgOiAndW5pcXVlJywgJ2lkJyA6ICd1bmlxdWVfMDEnLCAncmVhc29uJyA6ICdDaGlsZCB3aXRoIG5hbWUgJyArIG4gKyAnIGFscmVhZHkgZXhpc3RzLiBQcmV2ZW50aW5nOiAnICsgY2hrLCAnZGF0YScgOiBKU09OLnN0cmluZ2lmeSh7ICdjaGsnIDogY2hrLCAncG9zJyA6IHBvcywgJ29iaicgOiBvYmogJiYgb2JqLmlkID8gb2JqLmlkIDogZmFsc2UsICdwYXInIDogcGFyICYmIHBhci5pZCA/IHBhci5pZCA6IGZhbHNlIH0pIH07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiBpO1xuXHRcdFx0XHRjYXNlIFwiY3JlYXRlX25vZGVcIjpcblx0XHRcdFx0XHRpID0gKCQuaW5BcnJheShuLCBjKSA9PT0gLTEpO1xuXHRcdFx0XHRcdGlmKCFpKSB7XG5cdFx0XHRcdFx0XHR0aGlzLl9kYXRhLmNvcmUubGFzdF9lcnJvciA9IHsgJ2Vycm9yJyA6ICdjaGVjaycsICdwbHVnaW4nIDogJ3VuaXF1ZScsICdpZCcgOiAndW5pcXVlXzA0JywgJ3JlYXNvbicgOiAnQ2hpbGQgd2l0aCBuYW1lICcgKyBuICsgJyBhbHJlYWR5IGV4aXN0cy4gUHJldmVudGluZzogJyArIGNoaywgJ2RhdGEnIDogSlNPTi5zdHJpbmdpZnkoeyAnY2hrJyA6IGNoaywgJ3BvcycgOiBwb3MsICdvYmonIDogb2JqICYmIG9iai5pZCA/IG9iai5pZCA6IGZhbHNlLCAncGFyJyA6IHBhciAmJiBwYXIuaWQgPyBwYXIuaWQgOiBmYWxzZSB9KSB9O1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRyZXR1cm4gaTtcblx0XHRcdFx0Y2FzZSBcImNvcHlfbm9kZVwiOlxuXHRcdFx0XHRcdGkgPSAoJC5pbkFycmF5KG4sIGMpID09PSAtMSk7XG5cdFx0XHRcdFx0aWYoIWkpIHtcblx0XHRcdFx0XHRcdHRoaXMuX2RhdGEuY29yZS5sYXN0X2Vycm9yID0geyAnZXJyb3InIDogJ2NoZWNrJywgJ3BsdWdpbicgOiAndW5pcXVlJywgJ2lkJyA6ICd1bmlxdWVfMDInLCAncmVhc29uJyA6ICdDaGlsZCB3aXRoIG5hbWUgJyArIG4gKyAnIGFscmVhZHkgZXhpc3RzLiBQcmV2ZW50aW5nOiAnICsgY2hrLCAnZGF0YScgOiBKU09OLnN0cmluZ2lmeSh7ICdjaGsnIDogY2hrLCAncG9zJyA6IHBvcywgJ29iaicgOiBvYmogJiYgb2JqLmlkID8gb2JqLmlkIDogZmFsc2UsICdwYXInIDogcGFyICYmIHBhci5pZCA/IHBhci5pZCA6IGZhbHNlIH0pIH07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiBpO1xuXHRcdFx0XHRjYXNlIFwibW92ZV9ub2RlXCI6XG5cdFx0XHRcdFx0aSA9ICggKG9iai5wYXJlbnQgPT09IHBhci5pZCAmJiAoIW1vcmUgfHwgIW1vcmUuaXNfbXVsdGkpKSB8fCAkLmluQXJyYXkobiwgYykgPT09IC0xKTtcblx0XHRcdFx0XHRpZighaSkge1xuXHRcdFx0XHRcdFx0dGhpcy5fZGF0YS5jb3JlLmxhc3RfZXJyb3IgPSB7ICdlcnJvcicgOiAnY2hlY2snLCAncGx1Z2luJyA6ICd1bmlxdWUnLCAnaWQnIDogJ3VuaXF1ZV8wMycsICdyZWFzb24nIDogJ0NoaWxkIHdpdGggbmFtZSAnICsgbiArICcgYWxyZWFkeSBleGlzdHMuIFByZXZlbnRpbmc6ICcgKyBjaGssICdkYXRhJyA6IEpTT04uc3RyaW5naWZ5KHsgJ2NoaycgOiBjaGssICdwb3MnIDogcG9zLCAnb2JqJyA6IG9iaiAmJiBvYmouaWQgPyBvYmouaWQgOiBmYWxzZSwgJ3BhcicgOiBwYXIgJiYgcGFyLmlkID8gcGFyLmlkIDogZmFsc2UgfSkgfTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIGk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9O1xuXHRcdHRoaXMuY3JlYXRlX25vZGUgPSBmdW5jdGlvbiAocGFyLCBub2RlLCBwb3MsIGNhbGxiYWNrLCBpc19sb2FkZWQpIHtcblx0XHRcdGlmKCFub2RlIHx8IG5vZGUudGV4dCA9PT0gdW5kZWZpbmVkKSB7XG5cdFx0XHRcdGlmKHBhciA9PT0gbnVsbCkge1xuXHRcdFx0XHRcdHBhciA9ICQuanN0cmVlLnJvb3Q7XG5cdFx0XHRcdH1cblx0XHRcdFx0cGFyID0gdGhpcy5nZXRfbm9kZShwYXIpO1xuXHRcdFx0XHRpZighcGFyKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHBhcmVudC5jcmVhdGVfbm9kZS5jYWxsKHRoaXMsIHBhciwgbm9kZSwgcG9zLCBjYWxsYmFjaywgaXNfbG9hZGVkKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRwb3MgPSBwb3MgPT09IHVuZGVmaW5lZCA/IFwibGFzdFwiIDogcG9zO1xuXHRcdFx0XHRpZighcG9zLnRvU3RyaW5nKCkubWF0Y2goL14oYmVmb3JlfGFmdGVyKSQvKSAmJiAhaXNfbG9hZGVkICYmICF0aGlzLmlzX2xvYWRlZChwYXIpKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHBhcmVudC5jcmVhdGVfbm9kZS5jYWxsKHRoaXMsIHBhciwgbm9kZSwgcG9zLCBjYWxsYmFjaywgaXNfbG9hZGVkKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZighbm9kZSkgeyBub2RlID0ge307IH1cblx0XHRcdFx0dmFyIHRtcCwgbiwgZHBjLCBpLCBqLCBtID0gdGhpcy5fbW9kZWwuZGF0YSwgcyA9IHRoaXMuc2V0dGluZ3MudW5pcXVlLmNhc2Vfc2Vuc2l0aXZlLCB3ID0gdGhpcy5zZXR0aW5ncy51bmlxdWUudHJpbV93aGl0ZXNwYWNlLCBjYiA9IHRoaXMuc2V0dGluZ3MudW5pcXVlLmR1cGxpY2F0ZSwgdDtcblx0XHRcdFx0biA9IHRtcCA9IHRoaXMuZ2V0X3N0cmluZygnTmV3IG5vZGUnKTtcblx0XHRcdFx0ZHBjID0gW107XG5cdFx0XHRcdGZvcihpID0gMCwgaiA9IHBhci5jaGlsZHJlbi5sZW5ndGg7IGkgPCBqOyBpKyspIHtcblx0XHRcdFx0XHR0ID0gbVtwYXIuY2hpbGRyZW5baV1dLnRleHQ7XG5cdFx0XHRcdFx0aWYgKCFzKSB7XG5cdFx0XHRcdFx0XHR0ID0gdC50b0xvd2VyQ2FzZSgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZiAodykge1xuXHRcdFx0XHRcdFx0dCA9IHQucmVwbGFjZSgvXltcXHNcXHVGRUZGXFx4QTBdK3xbXFxzXFx1RkVGRlxceEEwXSskL2csICcnKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZHBjLnB1c2godCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aSA9IDE7XG5cdFx0XHRcdHQgPSBuO1xuXHRcdFx0XHRpZiAoIXMpIHtcblx0XHRcdFx0XHR0ID0gdC50b0xvd2VyQ2FzZSgpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICh3KSB7XG5cdFx0XHRcdFx0dCA9IHQucmVwbGFjZSgvXltcXHNcXHVGRUZGXFx4QTBdK3xbXFxzXFx1RkVGRlxceEEwXSskL2csICcnKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR3aGlsZSgkLmluQXJyYXkodCwgZHBjKSAhPT0gLTEpIHtcblx0XHRcdFx0XHRuID0gY2IuY2FsbCh0aGlzLCB0bXAsICgrK2kpKS50b1N0cmluZygpO1xuXHRcdFx0XHRcdHQgPSBuO1xuXHRcdFx0XHRcdGlmICghcykge1xuXHRcdFx0XHRcdFx0dCA9IHQudG9Mb3dlckNhc2UoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKHcpIHtcblx0XHRcdFx0XHRcdHQgPSB0LnJlcGxhY2UoL15bXFxzXFx1RkVGRlxceEEwXSt8W1xcc1xcdUZFRkZcXHhBMF0rJC9nLCAnJyk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdG5vZGUudGV4dCA9IG47XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gcGFyZW50LmNyZWF0ZV9ub2RlLmNhbGwodGhpcywgcGFyLCBub2RlLCBwb3MsIGNhbGxiYWNrLCBpc19sb2FkZWQpO1xuXHRcdH07XG5cdH07XG5cblx0Ly8gaW5jbHVkZSB0aGUgdW5pcXVlIHBsdWdpbiBieSBkZWZhdWx0XG5cdC8vICQuanN0cmVlLmRlZmF1bHRzLnBsdWdpbnMucHVzaChcInVuaXF1ZVwiKTtcblxuXG4vKipcbiAqICMjIyBXaG9sZXJvdyBwbHVnaW5cbiAqXG4gKiBNYWtlcyBlYWNoIG5vZGUgYXBwZWFyIGJsb2NrIGxldmVsLiBNYWtpbmcgc2VsZWN0aW9uIGVhc2llci4gTWF5IGNhdXNlIHNsb3cgZG93biBmb3IgbGFyZ2UgdHJlZXMgaW4gb2xkIGJyb3dzZXJzLlxuICovXG5cblx0dmFyIGRpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ0RJVicpO1xuXHRkaXYuc2V0QXR0cmlidXRlKCd1bnNlbGVjdGFibGUnLCdvbicpO1xuXHRkaXYuc2V0QXR0cmlidXRlKCdyb2xlJywncHJlc2VudGF0aW9uJyk7XG5cdGRpdi5jbGFzc05hbWUgPSAnanN0cmVlLXdob2xlcm93Jztcblx0ZGl2LmlubmVySFRNTCA9ICcmIzE2MDsnO1xuXHQkLmpzdHJlZS5wbHVnaW5zLndob2xlcm93ID0gZnVuY3Rpb24gKG9wdGlvbnMsIHBhcmVudCkge1xuXHRcdHRoaXMuYmluZCA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHBhcmVudC5iaW5kLmNhbGwodGhpcyk7XG5cblx0XHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0XHQub24oJ3JlYWR5LmpzdHJlZSBzZXRfc3RhdGUuanN0cmVlJywgZnVuY3Rpb24gKCkge1xuXHRcdFx0XHRcdFx0dGhpcy5oaWRlX2RvdHMoKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbihcImluaXQuanN0cmVlIGxvYWRpbmcuanN0cmVlIHJlYWR5LmpzdHJlZVwiLCBmdW5jdGlvbiAoKSB7XG5cdFx0XHRcdFx0XHQvL2Rpdi5zdHlsZS5oZWlnaHQgPSB0aGlzLl9kYXRhLmNvcmUubGlfaGVpZ2h0ICsgJ3B4Jztcblx0XHRcdFx0XHRcdHRoaXMuZ2V0X2NvbnRhaW5lcl91bCgpLmFkZENsYXNzKCdqc3RyZWUtd2hvbGVyb3ctdWwnKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbihcImRlc2VsZWN0X2FsbC5qc3RyZWVcIiwgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0XHRcdHRoaXMuZWxlbWVudC5maW5kKCcuanN0cmVlLXdob2xlcm93LWNsaWNrZWQnKS5yZW1vdmVDbGFzcygnanN0cmVlLXdob2xlcm93LWNsaWNrZWQnKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbihcImNoYW5nZWQuanN0cmVlXCIsIGZ1bmN0aW9uIChlLCBkYXRhKSB7XG5cdFx0XHRcdFx0XHR0aGlzLmVsZW1lbnQuZmluZCgnLmpzdHJlZS13aG9sZXJvdy1jbGlja2VkJykucmVtb3ZlQ2xhc3MoJ2pzdHJlZS13aG9sZXJvdy1jbGlja2VkJyk7XG5cdFx0XHRcdFx0XHR2YXIgdG1wID0gZmFsc2UsIGksIGo7XG5cdFx0XHRcdFx0XHRmb3IoaSA9IDAsIGogPSBkYXRhLnNlbGVjdGVkLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuXHRcdFx0XHRcdFx0XHR0bXAgPSB0aGlzLmdldF9ub2RlKGRhdGEuc2VsZWN0ZWRbaV0sIHRydWUpO1xuXHRcdFx0XHRcdFx0XHRpZih0bXAgJiYgdG1wLmxlbmd0aCkge1xuXHRcdFx0XHRcdFx0XHRcdHRtcC5jaGlsZHJlbignLmpzdHJlZS13aG9sZXJvdycpLmFkZENsYXNzKCdqc3RyZWUtd2hvbGVyb3ctY2xpY2tlZCcpO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fS5iaW5kKHRoaXMpKVxuXHRcdFx0XHQub24oXCJvcGVuX25vZGUuanN0cmVlXCIsIGZ1bmN0aW9uIChlLCBkYXRhKSB7XG5cdFx0XHRcdFx0XHR0aGlzLmdldF9ub2RlKGRhdGEubm9kZSwgdHJ1ZSkuZmluZCgnLmpzdHJlZS1jbGlja2VkJykucGFyZW50KCkuY2hpbGRyZW4oJy5qc3RyZWUtd2hvbGVyb3cnKS5hZGRDbGFzcygnanN0cmVlLXdob2xlcm93LWNsaWNrZWQnKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbihcImhvdmVyX25vZGUuanN0cmVlIGRlaG92ZXJfbm9kZS5qc3RyZWVcIiwgZnVuY3Rpb24gKGUsIGRhdGEpIHtcblx0XHRcdFx0XHRcdGlmKGUudHlwZSA9PT0gXCJob3Zlcl9ub2RlXCIgJiYgdGhpcy5pc19kaXNhYmxlZChkYXRhLm5vZGUpKSB7IHJldHVybjsgfVxuXHRcdFx0XHRcdFx0dGhpcy5nZXRfbm9kZShkYXRhLm5vZGUsIHRydWUpLmNoaWxkcmVuKCcuanN0cmVlLXdob2xlcm93JylbZS50eXBlID09PSBcImhvdmVyX25vZGVcIj9cImFkZENsYXNzXCI6XCJyZW1vdmVDbGFzc1wiXSgnanN0cmVlLXdob2xlcm93LWhvdmVyZWQnKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbihcImNvbnRleHRtZW51LmpzdHJlZVwiLCBcIi5qc3RyZWUtd2hvbGVyb3dcIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdGlmICh0aGlzLl9kYXRhLmNvbnRleHRtZW51KSB7XG5cdFx0XHRcdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHRcdFx0dmFyIHRtcCA9ICQuRXZlbnQoJ2NvbnRleHRtZW51JywgeyBtZXRhS2V5IDogZS5tZXRhS2V5LCBjdHJsS2V5IDogZS5jdHJsS2V5LCBhbHRLZXkgOiBlLmFsdEtleSwgc2hpZnRLZXkgOiBlLnNoaWZ0S2V5LCBwYWdlWCA6IGUucGFnZVgsIHBhZ2VZIDogZS5wYWdlWSB9KTtcblx0XHRcdFx0XHRcdFx0JChlLmN1cnJlbnRUYXJnZXQpLmNsb3Nlc3QoXCIuanN0cmVlLW5vZGVcIikuY2hpbGRyZW4oXCIuanN0cmVlLWFuY2hvclwiKS5maXJzdCgpLnRyaWdnZXIodG1wKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC8qIVxuXHRcdFx0XHQub24oXCJtb3VzZWRvd24uanN0cmVlIHRvdWNoc3RhcnQuanN0cmVlXCIsIFwiLmpzdHJlZS13aG9sZXJvd1wiLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0aWYoZS50YXJnZXQgPT09IGUuY3VycmVudFRhcmdldCkge1xuXHRcdFx0XHRcdFx0XHR2YXIgYSA9ICQoZS5jdXJyZW50VGFyZ2V0KS5jbG9zZXN0KFwiLmpzdHJlZS1ub2RlXCIpLmNoaWxkcmVuKFwiLmpzdHJlZS1hbmNob3JcIik7XG5cdFx0XHRcdFx0XHRcdGUudGFyZ2V0ID0gYVswXTtcblx0XHRcdFx0XHRcdFx0YS50cmlnZ2VyKGUpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0pXG5cdFx0XHRcdCovXG5cdFx0XHRcdC5vbihcImNsaWNrLmpzdHJlZVwiLCBcIi5qc3RyZWUtd2hvbGVyb3dcIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG5cdFx0XHRcdFx0XHR2YXIgdG1wID0gJC5FdmVudCgnY2xpY2snLCB7IG1ldGFLZXkgOiBlLm1ldGFLZXksIGN0cmxLZXkgOiBlLmN0cmxLZXksIGFsdEtleSA6IGUuYWx0S2V5LCBzaGlmdEtleSA6IGUuc2hpZnRLZXkgfSk7XG5cdFx0XHRcdFx0XHQkKGUuY3VycmVudFRhcmdldCkuY2xvc2VzdChcIi5qc3RyZWUtbm9kZVwiKS5jaGlsZHJlbihcIi5qc3RyZWUtYW5jaG9yXCIpLmZpcnN0KCkudHJpZ2dlcih0bXApLnRyaWdnZXIoJ2ZvY3VzJyk7XG5cdFx0XHRcdFx0fSlcblx0XHRcdFx0Lm9uKFwiZGJsY2xpY2suanN0cmVlXCIsIFwiLmpzdHJlZS13aG9sZXJvd1wiLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0ZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcblx0XHRcdFx0XHRcdHZhciB0bXAgPSAkLkV2ZW50KCdkYmxjbGljaycsIHsgbWV0YUtleSA6IGUubWV0YUtleSwgY3RybEtleSA6IGUuY3RybEtleSwgYWx0S2V5IDogZS5hbHRLZXksIHNoaWZ0S2V5IDogZS5zaGlmdEtleSB9KTtcblx0XHRcdFx0XHRcdCQoZS5jdXJyZW50VGFyZ2V0KS5jbG9zZXN0KFwiLmpzdHJlZS1ub2RlXCIpLmNoaWxkcmVuKFwiLmpzdHJlZS1hbmNob3JcIikuZmlyc3QoKS50cmlnZ2VyKHRtcCkudHJpZ2dlcignZm9jdXMnKTtcblx0XHRcdFx0XHR9KVxuXHRcdFx0XHQub24oXCJjbGljay5qc3RyZWVcIiwgXCIuanN0cmVlLWxlYWYgPiAuanN0cmVlLW9jbFwiLCBmdW5jdGlvbiAoZSkge1xuXHRcdFx0XHRcdFx0ZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcblx0XHRcdFx0XHRcdHZhciB0bXAgPSAkLkV2ZW50KCdjbGljaycsIHsgbWV0YUtleSA6IGUubWV0YUtleSwgY3RybEtleSA6IGUuY3RybEtleSwgYWx0S2V5IDogZS5hbHRLZXksIHNoaWZ0S2V5IDogZS5zaGlmdEtleSB9KTtcblx0XHRcdFx0XHRcdCQoZS5jdXJyZW50VGFyZ2V0KS5jbG9zZXN0KFwiLmpzdHJlZS1ub2RlXCIpLmNoaWxkcmVuKFwiLmpzdHJlZS1hbmNob3JcIikuZmlyc3QoKS50cmlnZ2VyKHRtcCkudHJpZ2dlcignZm9jdXMnKTtcblx0XHRcdFx0XHR9LmJpbmQodGhpcykpXG5cdFx0XHRcdC5vbihcIm1vdXNlb3Zlci5qc3RyZWVcIiwgXCIuanN0cmVlLXdob2xlcm93LCAuanN0cmVlLWljb25cIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdGUuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG5cdFx0XHRcdFx0XHRpZighdGhpcy5pc19kaXNhYmxlZChlLmN1cnJlbnRUYXJnZXQpKSB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuaG92ZXJfbm9kZShlLmN1cnJlbnRUYXJnZXQpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdH0uYmluZCh0aGlzKSlcblx0XHRcdFx0Lm9uKFwibW91c2VsZWF2ZS5qc3RyZWVcIiwgXCIuanN0cmVlLW5vZGVcIiwgZnVuY3Rpb24gKGUpIHtcblx0XHRcdFx0XHRcdHRoaXMuZGVob3Zlcl9ub2RlKGUuY3VycmVudFRhcmdldCk7XG5cdFx0XHRcdFx0fS5iaW5kKHRoaXMpKTtcblx0XHR9O1xuXHRcdHRoaXMudGVhcmRvd24gPSBmdW5jdGlvbiAoKSB7XG5cdFx0XHRpZih0aGlzLnNldHRpbmdzLndob2xlcm93KSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5maW5kKFwiLmpzdHJlZS13aG9sZXJvd1wiKS5yZW1vdmUoKTtcblx0XHRcdH1cblx0XHRcdHBhcmVudC50ZWFyZG93bi5jYWxsKHRoaXMpO1xuXHRcdH07XG5cdFx0dGhpcy5yZWRyYXdfbm9kZSA9IGZ1bmN0aW9uKG9iaiwgZGVlcCwgY2FsbGJhY2ssIGZvcmNlX3JlbmRlcikge1xuXHRcdFx0b2JqID0gcGFyZW50LnJlZHJhd19ub2RlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG5cdFx0XHRpZihvYmopIHtcblx0XHRcdFx0dmFyIHRtcCA9IGRpdi5jbG9uZU5vZGUodHJ1ZSk7XG5cdFx0XHRcdC8vdG1wLnN0eWxlLmhlaWdodCA9IHRoaXMuX2RhdGEuY29yZS5saV9oZWlnaHQgKyAncHgnO1xuXHRcdFx0XHRpZigkLmluQXJyYXkob2JqLmlkLCB0aGlzLl9kYXRhLmNvcmUuc2VsZWN0ZWQpICE9PSAtMSkgeyB0bXAuY2xhc3NOYW1lICs9ICcganN0cmVlLXdob2xlcm93LWNsaWNrZWQnOyB9XG5cdFx0XHRcdGlmKHRoaXMuX2RhdGEuY29yZS5mb2N1c2VkICYmIHRoaXMuX2RhdGEuY29yZS5mb2N1c2VkID09PSBvYmouaWQpIHsgdG1wLmNsYXNzTmFtZSArPSAnIGpzdHJlZS13aG9sZXJvdy1ob3ZlcmVkJzsgfVxuXHRcdFx0XHRvYmouaW5zZXJ0QmVmb3JlKHRtcCwgb2JqLmNoaWxkTm9kZXNbMF0pO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIG9iajtcblx0XHR9O1xuXHR9O1xuXHQvLyBpbmNsdWRlIHRoZSB3aG9sZXJvdyBwbHVnaW4gYnkgZGVmYXVsdFxuXHQvLyAkLmpzdHJlZS5kZWZhdWx0cy5wbHVnaW5zLnB1c2goXCJ3aG9sZXJvd1wiKTtcblx0aWYod2luZG93LmN1c3RvbUVsZW1lbnRzICYmIE9iamVjdCAmJiBPYmplY3QuY3JlYXRlKSB7XG5cdFx0dmFyIHByb3RvID0gT2JqZWN0LmNyZWF0ZShIVE1MRWxlbWVudC5wcm90b3R5cGUpO1xuXHRcdHByb3RvLmNyZWF0ZWRDYWxsYmFjayA9IGZ1bmN0aW9uICgpIHtcblx0XHRcdHZhciBjID0geyBjb3JlIDoge30sIHBsdWdpbnMgOiBbXSB9LCBpO1xuXHRcdFx0Zm9yKGkgaW4gJC5qc3RyZWUucGx1Z2lucykge1xuXHRcdFx0XHRpZigkLmpzdHJlZS5wbHVnaW5zLmhhc093blByb3BlcnR5KGkpICYmIHRoaXMuYXR0cmlidXRlc1tpXSkge1xuXHRcdFx0XHRcdGMucGx1Z2lucy5wdXNoKGkpO1xuXHRcdFx0XHRcdGlmKHRoaXMuZ2V0QXR0cmlidXRlKGkpICYmIEpTT04ucGFyc2UodGhpcy5nZXRBdHRyaWJ1dGUoaSkpKSB7XG5cdFx0XHRcdFx0XHRjW2ldID0gSlNPTi5wYXJzZSh0aGlzLmdldEF0dHJpYnV0ZShpKSk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRmb3IoaSBpbiAkLmpzdHJlZS5kZWZhdWx0cy5jb3JlKSB7XG5cdFx0XHRcdGlmKCQuanN0cmVlLmRlZmF1bHRzLmNvcmUuaGFzT3duUHJvcGVydHkoaSkgJiYgdGhpcy5hdHRyaWJ1dGVzW2ldKSB7XG5cdFx0XHRcdFx0Yy5jb3JlW2ldID0gSlNPTi5wYXJzZSh0aGlzLmdldEF0dHJpYnV0ZShpKSkgfHwgdGhpcy5nZXRBdHRyaWJ1dGUoaSk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdCQodGhpcykuanN0cmVlKGMpO1xuXHRcdH07XG5cdFx0Ly8gcHJvdG8uYXR0cmlidXRlQ2hhbmdlZENhbGxiYWNrID0gZnVuY3Rpb24gKG5hbWUsIHByZXZpb3VzLCB2YWx1ZSkgeyB9O1xuXHRcdHRyeSB7XG5cdFx0XHR3aW5kb3cuY3VzdG9tRWxlbWVudHMuZGVmaW5lKFwidmFrYXRhLWpzdHJlZVwiLCBmdW5jdGlvbigpIHt9LCB7IHByb3RvdHlwZTogcHJvdG8gfSk7XG5cdFx0fSBjYXRjaCAoaWdub3JlKSB7IH1cblx0fVxuXG59KSk7Il0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./node_modules/jstree/dist/jstree.js\n");
/***/ }),
/***/ "jquery":
/*!*************************!*\
!*** external "jQuery" ***!
\*************************/
/***/ (function(module) {
"use strict";
module.exports = __WEBPACK_EXTERNAL_MODULE_jquery__;
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ !function() {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function() { return module['default']; } :
/******/ function() { return module; };
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ }();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ !function() {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = function(exports, definition) {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ }();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ !function() {
/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }
/******/ }();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ !function() {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ }();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module can't be inlined because the eval-source-map devtool is used.
/******/ var __webpack_exports__ = __webpack_require__("./libs/jstree/jstree.js");
/******/
/******/ return __webpack_exports__;
/******/ })()
;
});