@coon-js/siesta-lib-helper
Version:
Collection of utility- and helper-methods when working with Siesta (https://bryntum.com) in an ExtJS-Browser environment.
324 lines (284 loc) • 70.2 kB
JavaScript
const t=e=>"string"==typeof e,r=e=>"object"==typeof e,n=e=>"object"==typeof e&&"[object Object]"===Object.prototype.toString.call(e)&&e.constructor===Object,o=e=>"function"==typeof e,a=e=>Array.isArray?Array.isArray(e):"[object Array]"===Object.prototype.toString.call(e),c=e=>e instanceof RegExp,m=(e,t)=>{let n=null,o=r(t);return (a(t)?t:o?Object.entries(t):[]).some((t=>o&&t[0]===e?(n=t[1],!0):r(t)&&void 0!==t[e]?(n=t[e],!0):void 0)),n},b=function(e,r,n){if(!t(n))throw new Error('"str" must be a string');return e=[].concat(e),r=t(r)?new Array(e.length).fill(r):[].concat(r),e.forEach(((e,t)=>{n=n.replace(new RegExp(y(e),"g"),r[t]??"");})),n},d=function(e,r,n){if(!t(e)||!t(r)||!r)throw new Error('"str" must be a string');if(n&&!t(n)&&!a(n))throw new Error('"ignore" must be an array or a string');let o=new RegExp(`${y(r)}+`,"gi");if(void 0!==n){(n=(n=[].concat(n)).map((e=>y(e)))).map((t=>{let r=new RegExp(`(${y(t)+"*"})`,"gim");e=e.replace(r,t);})),n=new RegExp(`(${n.join("|")})`,"gim");let t="",i=0,a=[],c=(e,n,c,s)=>{let l=s.substring(i,c).replace(o,r);return a=a.concat([l,n]),i=c+e.length,t=s.substring(i),e};return e.match(n,c)?(e.replace(n,c),a.push(t.replace(o,r)),a.join("")):e.replace(o,r)}return e.replace(o,r)},w=function(e){const t="(?!("+Array.prototype.slice.call(arguments,1).join("|")+"))^",r=new RegExp(t,"g");return null!==e.match(r)};function y(e){return e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}var j=Object.freeze({__proto__:null,replace:b,unify:d,isNot:w});const _=function(e,t={},r,n=!1){return (e=[].concat(e)).forEach((e=>{const i=e.split("."),a=(t,i)=>{let c;return c=i.shift(),t[c]&&(!0!==n||i.length)||(t[c]=i.length?{}:o(r)?r(e):r),i.length&&a(t[c],i),t};a(t,i);})),t},$=function(e,t,r){for(var n=e.split("."),i=t;void 0!==i&&n.length;)i=i[n.shift()];return o(r)?r(i):void 0===i?r:i},k=function(e){let t=Array.prototype.slice.call(arguments,1);return t=t.map((e=>{if(n(e))return e;if(a(e)){const[t,...r]=e,n=r[0];return Object.fromEntries(Object.entries(t).filter((e=>{let t=e[0];return c(n)?null!==t.match(n):w.apply(j,[t].concat(r))})))}})),Object.assign(e,...t)};async function T(e){let t;try{t=await C(e,{method:"HEAD"}),await t.text();}catch(e){return !1}return 200===t.status}async function z(e){const t=await C(e,{method:"GET"});return await t.text()}async function C(e,r){if(!t(e))throw new Error('"url" must be a string representing the resource location');let n=await fetch(e,r);if(n.status>=400)throw new Error(`Fetching the resource ${e} failed with ${n.status} ${n.statusText}`);return n}const I=e=>e.replace(/^( *)(>+)( >*)*(?!$)/m,(e=>e.replace(/(\s)*(?!$)/g,"")));Object.freeze({__proto__:null,toBlockquote:function(e){let t=(e=>{let t=e.split("\n"),r=[],n=-1,o=null;return t.forEach((e=>{e=I(e),o!==e.indexOf(">")&&n++,o=e.indexOf(">"),r[n]||(r[n]=[]),r[n].push(e);})),r})(e),r=[];return t.forEach((e=>{r.push((e=>{if(0!==e[0].indexOf(">"))return e.join("\n");const t=e=>{"\n"===e[e.length-1]&&e.pop();};let r,n,o=0,i=[];for(e.forEach((e=>{for(n=(e+"").trim().match(/^((>)+) *?(.*?$)/ms),r=n[1].length;r>o;)t(i),o++,i.push("<blockquote>");for(;o>r;)t(i),o--,i.push("</blockquote>");i.push(n[3]),i.push("\n");}));o>0;)t(i),o--,i.push("</blockquote>");return i.join("")})(e));})),r.join("")},toEmailLink:e=>e=e.replace(/[a-zA-Z0-9+._%-]{1,256}@[a-zA-Z0-9][a-zA-Z0-9-]{0,64}(\.[a-zA-Z0-9][a-zA-Z0-9-]{0,25})+/gi,(e=>'<a href="mailto:'+e+'">'+e+"</a>")),toHyperlink:e=>e=e.replace(/(\b(https?):\/\/[-A-Z0-9+&@#/%?=~_|!:,.;]*[-A-Z0-9+&@#/%=~_|])/gi,(e=>'<a href="'+e+'">'+e+"</a>")),toLineBreak:e=>e=e.replace(/(\r\n|\n|\r)/gm,(e=>"<br />"))});class R{compile(e,t){}}class S{render(e){}}class Z extends S{constructor(e){if(super(),!o(e))throw new Error('"fn" must be of type "function"');this.fn=e;}render(e){const t=this;try{return t.fn.call({},e)}catch(e){throw new Error(`rendering "data" failed with message ${e.message}`)}}}class B extends R{compile(e,t){t.some((e=>{if(-1!==e.indexOf("-"))throw new Error(`Cannot compile template: Contains invalid key-name: ${e}`)}));const r=this,n=r.getKeys(e),o=r.buildArgumentList(n),i=r.getBlacklistedKeys(o,t||[]);if(i.length)throw new Error(`Cannot compile template: Contains invalid keys: ${i.join(", ")}`);const a=r.getFunctionConfig(o,e),c=r.getNativeFunction(a.args,a.fn);return new Z(c)}buildArgumentList(e){let t=e.map((e=>e.split(/\.|\[/)[0]));return [...new Set(t)]}getKeys(e){const t=/\$\{([^}]+)\}/gm,r=[];let n;for(;null!==(n=t.exec(e));)n.index===t.lastIndex&&t.lastIndex++,n.forEach(((e,t)=>{1===t&&r.push(e);}));return r}getBlacklistedKeys(e,t){return t.length?e.filter((e=>-1===t.indexOf(e))):[]}getFunctionConfig(e,t){return {args:`{${e.join(", ")}}`,fn:`return \`${t}\``}}getNativeFunction(e,t){return new Function(e,t)}}class K{render(e){}}class L extends K{constructor(e){super();this.compiler=new B,this.tpl=e;}render(e){const t=this;let r=Object.keys(e),n=r.join(".");return t.compiledTpls=t.compiledTpls||{},t.compiledTpls[n]||(t.compiledTpls[n]=t.compiler.compile(t.tpl,r)),t.compiledTpls[n].render(e)}}var N=Object.freeze({__proto__:null,StringCompiler:B,StringTemplate:L,make:e=>new L(e),Tpl:Z});Object.freeze({__proto__:null,esix:N,CompiledTpl:S,Compiler:R,Template:K});
/**
* coon.js
* siesta-lib-helper
* Copyright (C) 2021 Thorsten Suckow-Homberg https://github.com/coon-js/siesta-lib-helper
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/**
* Uses the specified testConfig for teh preLoader-section and applies the related paths found at
* pathConfigUrl (config-file url()) to it, then passes it to getPaths() and returns the value.
* content found at pathConfigUrl should be in a format @coon-js/extjs-link produces.
*
* @example
*
* json at "pathConfigUrl.json":
*
* {
* css: [{
* modern: [
* "foo.css"
* ],
* classic: [
* "bar.css"
* ]
*
* }],
* js: {
* modern: "modern.js",
* classic: "classic.js"
*
* }
* }
*
*
* const config = {
* loaderPath: {
* "Ext.Package": "/node_modules/@coon-js/extjs-package-loader/packages/package-loader/src/src/Package.js",
* "coon.core": "../src/",
* },
* preloads: {
* css: [{
* modern: [
* "/node_modules/@sencha/ext-modern-runtime/material/material-all_1.css",
* "/node_modules/@sencha/ext-modern-runtime/material/material-all_2.css"
* ],
* classic: [
* "/node_modules/@sencha/ext-classic-runtime/material/material-all_1.css",
* "/node_modules/@sencha/ext-classic-runtime/material/material-all_2.css",
* "/node_modules/@sencha/ext-classic-runtime/material/material-all_3.css"
* ]
* }],
* js: [
* "/node_modules/@l8js/l8/dist/l8.runtime.js", {
* modern: "/node_modules/@sencha/ext-modern-runtime/modern.engine.enterprise.js",
* classic: "/node_modules/@sencha/ext-modern-runtime/classic.engine.enterprise.js"
* }
* ]
* }};
*
* configureWithExtJsLinkPaths(config, "pathConfigUrl.json", true); // returns {
* // preload : [
* // "foo.css",
* // "/node_modules/@l8js/l8/dist/l8.runtime.js",
* // "/node_modules/@sencha/ext-modern-runtime/modern.engine.enterprise.js"
* // "modern.js"
* // ],
* // loaderPath : {
* // "Ext.Package": "/node_modules/@coon-js/extjs-package-loader/packages/package-loader/src/src/Package.js",
* // "coon.core": "../src/"
* // }
* // };
*
*
* @param {Object} testConfig
* @param {String} pathConfigUrl
* @param {Boolean} isModern
* @returns {Promise<{loaderPath: {}, preload: *[]}>}
*/
const configureWithExtJsLinkPaths = async function (testConfig, pathConfigUrl, isModern) {
if (await T(pathConfigUrl)) {
const
extjsLinkConfig = JSON.parse(await z(pathConfigUrl)),
mergedCss = {}, mergedJs = {},
collect = (section, toolkit) => {
let res = [];
section.forEach(entry => {
if (t(entry)) {
res.push(entry);
} else if (n(entry)) {
res = res.concat(entry[toolkit] ?? []);
}
});
return res;
};
["classic", "modern"].forEach(toolkit => {
let ff = m.bind(null, toolkit),
css = collect([].concat($("preload.css", testConfig)), toolkit),
js = collect([].concat($("preload.js", testConfig)), toolkit),
extCss = $("css", extjsLinkConfig, ff),
extJs = $("js", extjsLinkConfig, ff);
_(toolkit, mergedCss, [].concat(css, [].concat(extCss)));
_(toolkit, mergedJs, [].concat(js, [].concat(extJs)));
});
_("preload.css", testConfig, mergedCss, true);
_("preload.js", testConfig, mergedJs, true);
}
return getPaths(testConfig, isModern);
};
/**
* Consumes a configuration object and looks up js/css-related path information,
* then returns it pre-configured to be used with Siestas Siesta.Harness.Browser.ExtJS()#config.
*
* @example
*
* const config = {
* loaderPath: {
* "Ext.Package": "/node_modules/@coon-js/extjs-package-loader/packages/package-loader/src/src/Package.js",
* "coon.core": "../src/",
* },
* preloads: {
* css: [{
* modern: [
* "/node_modules/@sencha/ext-modern-runtime/material/material-all_1.css",
* "/node_modules/@sencha/ext-modern-runtime/material/material-all_2.css"
* ],
* classic: [
* "/node_modules/@sencha/ext-classic-runtime/material/material-all_1.css",
* "/node_modules/@sencha/ext-classic-runtime/material/material-all_2.css",
* "/node_modules/@sencha/ext-classic-runtime/material/material-all_3.css"
* ]
* }],
* js: [
* "/node_modules/@l8js/l8/dist/l8.runtime.js", {
* modern: "/node_modules/@sencha/ext-modern-runtime/modern.engine.enterprise.js",
* classic: "/node_modules/@sencha/ext-modern-runtime/classic.engine.enterprise.js"
* }
* ]
* }};
*
* getPaths(config, true); // returns {
* // preload : [
* // "/node_modules/@sencha/ext-modern-runtime/material/material-all_1.css",
* // "/node_modules/@sencha/ext-modern-runtime/material/material-all_2.css",
* // "/node_modules/@l8js/l8/dist/l8.runtime.js",
* // "/node_modules/@sencha/ext-modern-runtime/modern.engine.enterprise.js"
* // ],
* // loaderPath : {
* // "Ext.Package": "/node_modules/@coon-js/extjs-package-loader/packages/package-loader/src/src/Package.js",
* // "coon.core": "../src/"
* // }
* // };
*
*
*
*/
const getPaths = (config, isModern) => {
const
result = {preload: [], loaderPath: {}},
isObject = r,
isArray = a,
isString = t,
toolkit = isModern ? "modern" : isModern === false ? "classic" : null,
parseSection = (section) => {
section = [].concat(section);
section.forEach((entry) => {
if (isString(entry)) {
result.preload.push(entry);
} else if (isObject(entry) && toolkit !== null) {
if (isArray(entry[toolkit])) {
result.preload = result.preload.concat(entry[toolkit]);
} else if (isString(entry[toolkit])) {
result.preload.push(entry[toolkit]);
}
}
});
};
k(
result.loaderPath,
[config.loaderPath || {}, "classic", "modern"],
config.loaderPath && config.loaderPath[toolkit] ? config.loaderPath[toolkit] : {}
);
const {js, css} = config.preload || {};
parseSection(css);
parseSection(js);
return result;
};
/**
* coon.js
* siesta-lib-helper
* Copyright (C) 2021 Thorsten Suckow-Homberg https://github.com/coon-js/siesta-lib-helper
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge,
* publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
if (!coonjs.siestaTestConfigObj || !coonjs.siestaGroupsConfigObj || ! coonjs.extjsLinkConfigUrl) {
throw new Error("Config missing");
}
const
testConfig = coonjs.siestaTestConfigObj,
groups = coonjs.siestaGroupsConfigObj,
extjsLinkConfigUrl = coonjs.extjsLinkConfigUrl;
let toolkitGroups,
remainingGroups,
configuredToolkitGroups,
hasToolkitRelatedConfig = false,
urlParams = new URLSearchParams(document.location.search.substring(1)),
timeout = urlParams.get("timeout") ? parseInt(urlParams.get("timeout")) : testConfig.timeout,
forcedToolkit = urlParams.get("toolkit"),
toolkit = urlParams.get("toolkit") ?? "classic";
const
browser = new Siesta.Harness.Browser.ExtJS();
configureWithExtJsLinkPaths(testConfig, extjsLinkConfigUrl, toolkit === "modern").then((paths) => {
configuredToolkitGroups = groups.filter(entry => ["classic", "modern"].indexOf(entry.group) !== -1);
hasToolkitRelatedConfig = configuredToolkitGroups.length > 0;
toolkitGroups = groups.filter(entry => ["universal", toolkit].indexOf(entry.group) !== -1);
// we need to check if the loader specifies different classes for modern/classic here, as the tests
// might be declared as "universal", but the test cases load different files for the toolkits
toolkit = toolkitGroups.length ? toolkitGroups[0].group : "universal";
if (toolkit === "universal" && (testConfig.loaderPath.classic || testConfig.loaderPath.modern)) {
toolkit = urlParams.get("toolkit") || (testConfig.loaderPath.classic ? "classic" : "modern");
forcedToolkit = toolkit;
}
remainingGroups = groups.filter(entry => ["universal", "classic", "modern"].indexOf(entry.group) === -1);
browser.configure(Object.assign({
title: `${testConfig.name} [${toolkit}]`,
isEcmaModule: true,
disableCaching: true,
config : {
TIMEOUT : timeout
}
}, paths));
browser.start((toolkitGroups.length ? toolkitGroups : groups).concat(remainingGroups));
// classic | modern | timeout options
document.getElementById("cn_timeout").value = timeout;
if (["classic", "modern"].indexOf(toolkit) !== -1) {
document.getElementById(`cn_${toolkit}`).checked = true;
} else if (!hasToolkitRelatedConfig) {
["classic", "modern"].forEach(toolkit => document.getElementById(`cn_${toolkit}`).disabled = true);
} else if (hasToolkitRelatedConfig && ["classic", "modern"].indexOf(forcedToolkit) !== -1) {
document.getElementById(`cn_${forcedToolkit}`).checked = true;
}
document.getElementById("cn_configBtn").onclick = () => {
let timeout = document.getElementById("cn_timeout").value,
toolkit = document.getElementById("cn_classic").checked ?
"classic" :
document.getElementById("cn_modern").checked ? "modern" : "";
window.location.href = `./index.extjs-browser.html?toolkit=${toolkit}&timeout=${timeout}`;
};
});
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQm9pbGVyUGxhdGUuZXNtLmpzIiwic291cmNlcyI6WyIuLi9ub2RlX21vZHVsZXMvQGw4anMvbDgvZGlzdC9sOC5wYWNrYWdlcy5lc20uanMiLCIuLi9zcmMvaW5kZXguanMiLCIuLi9zcmMvQm9pbGVyUGxhdGUuanMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGUgZnJvbVwiY3J5cHRvLWpzL21kNS5qc1wiO2NvbnN0IHQ9ZT0+XCJzdHJpbmdcIj09dHlwZW9mIGUscj1lPT5cIm9iamVjdFwiPT10eXBlb2YgZSxuPWU9Plwib2JqZWN0XCI9PXR5cGVvZiBlJiZcIltvYmplY3QgT2JqZWN0XVwiPT09T2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGUpJiZlLmNvbnN0cnVjdG9yPT09T2JqZWN0LG89ZT0+XCJmdW5jdGlvblwiPT10eXBlb2YgZSxpPWU9PlwibnVtYmVyXCI9PXR5cGVvZiBlLGE9ZT0+QXJyYXkuaXNBcnJheT9BcnJheS5pc0FycmF5KGUpOlwiW29iamVjdCBBcnJheV1cIj09PU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChlKSxjPWU9PmUgaW5zdGFuY2VvZiBSZWdFeHAscz1mdW5jdGlvbihlKXtyZXR1cm57YTp0PT50eXBlb2YgZT09PXQsb2Y6dD0+ISFvKHQpJiZlIGluc3RhbmNlb2YgdH19LGw9e2FwcGx5OihlLHQscik9PihlPWUuX19saXF1aWRfXz9lKCk6ZSxvKGUudGhlbik/dShlLnRoZW4oKGU9PlJlZmxlY3QuYXBwbHkoZSx0LHIpKSkpOnUoZS5hcHBseSh0LHIpKSksZ2V0OihlLHQscik9PihlPWUuX19saXF1aWRfXz9lKCk6ZSxcInRoZW5cIiE9PXQmJm8oZS50aGVuKT91KGUudGhlbigoZT0+ZVt0XS5iaW5kKGUpKSkpOm8oZVt0XSk/dShlW3RdLmJpbmQoZSkpOmVbdF0pfSx1PWZ1bmN0aW9uKGUpe2lmKHIoZSkpe2NvbnN0IHQ9KCk9PmU7cmV0dXJuIHQuX19saXF1aWRfXz0hMCxuZXcgUHJveHkodCxsKX1yZXR1cm4gbyhlKT9uZXcgUHJveHkoZSxsKTplfSxwPWZ1bmN0aW9uKGUsdCl7dmFyIHIsbixvLGk9W10sYT1bXTtmb3IoKGk9KGk9ZS5tYXAoKGZ1bmN0aW9uKGUpe3JldHVybiBwYXJzZUludChlLDEwKX0pKSkuZmlsdGVyKChmdW5jdGlvbihlLHQscil7cmV0dXJuIHIuaW5kZXhPZihlLDApPT09dH0pKSkuc29ydCgoZnVuY3Rpb24oZSx0KXtyZXR1cm4gZS10fSkpLG49KHI9aS5pbmRleE9mKHBhcnNlSW50KHQsMTApKSktMTtuPj0wJiZpW25dPT09aVtuKzFdLTE7bi0tKWEudW5zaGlmdChpW25dKTtmb3IoYS5wdXNoKGlbcl0pLG49cisxLG89aS5sZW5ndGg7bjxvJiZpW25dPT09aVtuLTFdKzE7bisrKWEucHVzaChpW25dKTtyZXR1cm4gYX0sZj1mdW5jdGlvbihlKXt2YXIgdCxyPVtdO2lmKCFhKGUpKXRocm93IG5ldyBFcnJvcihcIidsaXN0JyBtdXN0IGJlIGFuIGFycmF5XCIpO3JldHVybih0PSh0PWUubWFwKChmdW5jdGlvbihlKXtyZXR1cm4gcGFyc2VJbnQoZSwxMCl9KSkpLmZpbHRlcigoZnVuY3Rpb24oZSx0LHIpe3JldHVybiByLmluZGV4T2YoZSk9PT10fSkpKS5zb3J0KChmdW5jdGlvbihlLHQpe3JldHVybiBlLXR9KSksdC5yZWR1Y2UoKGZ1bmN0aW9uKGUsdCxuLG8pe3JldHVybiB0PmUrMSYmci5wdXNoKFtdKSxyW3IubGVuZ3RoLTFdLnB1c2godCksdH0pLC0xKSxyfSxoPWZ1bmN0aW9uKGUsdCl7aWYoIWkoZSkpdGhyb3cgbmV3IEVycm9yKFwiJ3N0YXJ0JyBtdXN0IGJlIGEgbnVtYmVyXCIpO2lmKCFpKHQpKXRocm93IG5ldyBFcnJvcihcIidlbmQnIG11c3QgYmUgYSBudW1iZXJcIik7aWYoZT1wYXJzZUludChlLDEwKSwodD1wYXJzZUludCh0LDEwKSk8ZSl0aHJvdyBuZXcgRXJyb3IoYFwiZW5kXCIgKCR7dH0pIG11c3QgYmUgYSBudW1iZXIgZXF1YWwgdG8gb3IgZ3JlYXRlciB0aGFuIFwic3RhcnRcIiAoJHtlfSlgKTtyZXR1cm4gbmV3IEFycmF5KHQtZSsxKS5maWxsKHZvaWQgMCkubWFwKChmdW5jdGlvbigpe3JldHVybiBlKyt9KSl9LG09KGUsdCk9PntsZXQgbj1udWxsLG89cih0KTtyZXR1cm4oYSh0KT90Om8/T2JqZWN0LmVudHJpZXModCk6W10pLnNvbWUoKHQ9Pm8mJnRbMF09PT1lPyhuPXRbMV0sITApOnIodCkmJnZvaWQgMCE9PXRbZV0/KG49dFtlXSwhMCk6dm9pZCAwKSksbn0sZz1lPT5lLmZpbHRlcigoKGUsdCxyKT0+ci5pbmRleE9mKGUpPT09ci5sYXN0SW5kZXhPZihlKSkpLGI9ZnVuY3Rpb24oZSxyLG4pe2lmKCF0KG4pKXRocm93IG5ldyBFcnJvcignXCJzdHJcIiBtdXN0IGJlIGEgc3RyaW5nJyk7cmV0dXJuIGU9W10uY29uY2F0KGUpLHI9dChyKT9uZXcgQXJyYXkoZS5sZW5ndGgpLmZpbGwocik6W10uY29uY2F0KHIpLGUuZm9yRWFjaCgoKGUsdCk9PntuPW4ucmVwbGFjZShuZXcgUmVnRXhwKHkoZSksXCJnXCIpLHJbdF0/P1wiXCIpfSkpLG59LGQ9ZnVuY3Rpb24oZSxyLG4pe2lmKCF0KGUpfHwhdChyKXx8IXIpdGhyb3cgbmV3IEVycm9yKCdcInN0clwiIG11c3QgYmUgYSBzdHJpbmcnKTtpZihuJiYhdChuKSYmIWEobikpdGhyb3cgbmV3IEVycm9yKCdcImlnbm9yZVwiIG11c3QgYmUgYW4gYXJyYXkgb3IgYSBzdHJpbmcnKTtsZXQgbz1uZXcgUmVnRXhwKGAke3kocil9K2AsXCJnaVwiKTtpZih2b2lkIDAhPT1uKXsobj0obj1bXS5jb25jYXQobikpLm1hcCgoZT0+eShlKSkpKS5tYXAoKHQ9PntsZXQgcj1uZXcgUmVnRXhwKGAoJHt5KHQpK1wiKlwifSlgLFwiZ2ltXCIpO2U9ZS5yZXBsYWNlKHIsdCl9KSksbj1uZXcgUmVnRXhwKGAoJHtuLmpvaW4oXCJ8XCIpfSlgLFwiZ2ltXCIpO2xldCB0PVwiXCIsaT0wLGE9W10sYz0oZSxuLGMscyk9PntsZXQgbD1zLnN1YnN0cmluZyhpLGMpLnJlcGxhY2UobyxyKTtyZXR1cm4gYT1hLmNvbmNhdChbbCxuXSksaT1jK2UubGVuZ3RoLHQ9cy5zdWJzdHJpbmcoaSksZX07cmV0dXJuIGUubWF0Y2gobixjKT8oZS5yZXBsYWNlKG4sYyksYS5wdXNoKHQucmVwbGFjZShvLHIpKSxhLmpvaW4oXCJcIikpOmUucmVwbGFjZShvLHIpfXJldHVybiBlLnJlcGxhY2UobyxyKX0sdz1mdW5jdGlvbihlKXtjb25zdCB0PVwiKD8hKFwiK0FycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywxKS5qb2luKFwifFwiKStcIikpXlwiLHI9bmV3IFJlZ0V4cCh0LFwiZ1wiKTtyZXR1cm4gbnVsbCE9PWUubWF0Y2gocil9O2Z1bmN0aW9uIHkoZSl7cmV0dXJuIGUucmVwbGFjZSgvWy4qKz9eJHt9KCl8W1xcXVxcXFxdL2csXCJcXFxcJCZcIil9dmFyIGo9T2JqZWN0LmZyZWV6ZSh7X19wcm90b19fOm51bGwscmVwbGFjZTpiLHVuaWZ5OmQsaXNOb3Q6d30pO2NvbnN0IEU9ZnVuY3Rpb24oZSl7Y29uc3QgdD1PYmplY3QuY3JlYXRlKG51bGwpO3JldHVybiBPYmplY3QuYXNzaWduKHQsZSksdH0sTz1mdW5jdGlvbihlLG4sbyl7aWYoIXIoZSl8fE9iamVjdC5pc0Zyb3plbihlKXx8T2JqZWN0LmlzU2VhbGVkKGUpKXRocm93IG5ldyBFcnJvcignXCJ0YXJnZXRcIiBtdXN0IGJlIGFuIGV4dGVuc2libGUgb2JqZWN0LicpO2NvbnN0IGk9YXJndW1lbnRzLmxlbmd0aDtpZihvPWFyZ3VtZW50c1tpLTFdLGk8Mil0aHJvdyBuZXcgRXJyb3IoJ1wicHJvcGVydHlcIiBtdXN0IGJlIGEgdmFsaWQgcHJvcGVydHkgbmFtZS4nKTtpZihpPjMmJiFyKG8pKXRocm93IG5ldyBFcnJvcignXCJ2YWx1ZVwiIG11c3QgYmUgYW4gb2JqZWN0LicpO2lmKDM9PT1pJiZhKG4pJiYhcihvKSl0aHJvdyBuZXcgRXJyb3IoJ1widmFsdWVcIiBtdXN0IGJlIGFuIG9iamVjdC4nKTtsZXQgYz1hKG4pLHM9Yz9uOkFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShhcmd1bWVudHMsWzEsaS0xXSk7cmV0dXJuIHMuZm9yRWFjaCgocj0+e2lmKCF0KHIpKXRocm93IG5ldyBFcnJvcignXCJwcm9wZXJ0eVwiIG11c3QgYmUgYSB2YWxpZCBwcm9wZXJ0eSBuYW1lLicpO09iamVjdC5kZWZpbmVQcm9wZXJ0eShlLHIse3dyaXRhYmxlOiExLGNvbmZpZ3VyYWJsZTohMSx2YWx1ZTppPjN8fGM/b1tyXTpvfSl9KSksZX0seD1mdW5jdGlvbihlLHQpe2NvbnN0IG49KGUsbyk9PihPYmplY3QuZW50cmllcyhlKS5tYXAoKChbaSxhXSk9Pntjb25zdCBjPW8uY29uY2F0KGkpO2VbaV09cihhKT9uKGEsYyk6dChhLGMpfSkpLGUpO3JldHVybiBuKGUsW10pLGV9LF89ZnVuY3Rpb24oZSx0PXt9LHIsbj0hMSl7cmV0dXJuKGU9W10uY29uY2F0KGUpKS5mb3JFYWNoKChlPT57Y29uc3QgaT1lLnNwbGl0KFwiLlwiKSxhPSh0LGkpPT57bGV0IGM7cmV0dXJuIGM9aS5zaGlmdCgpLHRbY10mJighMCE9PW58fGkubGVuZ3RoKXx8KHRbY109aS5sZW5ndGg/e306byhyKT9yKGUpOnIpLGkubGVuZ3RoJiZhKHRbY10saSksdH07YSh0LGkpfSkpLHR9LHY9ZnVuY3Rpb24oZSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oe30sLi4uT2JqZWN0LmVudHJpZXMoZSkubWFwKCgoW2UsdF0pPT4oe1t0XTplfSkpKSl9LEE9ZnVuY3Rpb24oZSx0KXtyZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC5lbnRyaWVzKGUpLmZpbHRlcigoKFssZV0pPT5lIT09dCkpKX0sJD1mdW5jdGlvbihlLHQscil7Zm9yKHZhciBuPWUuc3BsaXQoXCIuXCIpLGk9dDt2b2lkIDAhPT1pJiZuLmxlbmd0aDspaT1pW24uc2hpZnQoKV07cmV0dXJuIG8ocik/cihpKTp2b2lkIDA9PT1pP3I6aX0saz1mdW5jdGlvbihlKXtsZXQgdD1BcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsMSk7cmV0dXJuIHQ9dC5tYXAoKGU9PntpZihuKGUpKXJldHVybiBlO2lmKGEoZSkpe2NvbnN0W3QsLi4ucl09ZSxuPXJbMF07cmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyh0KS5maWx0ZXIoKGU9PntsZXQgdD1lWzBdO3JldHVybiBjKG4pP251bGwhPT10Lm1hdGNoKG4pOncuYXBwbHkoaixbdF0uY29uY2F0KHIpKX0pKSl9fSkpLE9iamVjdC5hc3NpZ24oZSwuLi50KX07YXN5bmMgZnVuY3Rpb24gVChlKXtsZXQgdDt0cnl7dD1hd2FpdCBDKGUse21ldGhvZDpcIkhFQURcIn0pLGF3YWl0IHQudGV4dCgpfWNhdGNoKGUpe3JldHVybiExfXJldHVybiAyMDA9PT10LnN0YXR1c31hc3luYyBmdW5jdGlvbiB6KGUpe2NvbnN0IHQ9YXdhaXQgQyhlLHttZXRob2Q6XCJHRVRcIn0pO3JldHVybiBhd2FpdCB0LnRleHQoKX1hc3luYyBmdW5jdGlvbiBDKGUscil7aWYoIXQoZSkpdGhyb3cgbmV3IEVycm9yKCdcInVybFwiIG11c3QgYmUgYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSByZXNvdXJjZSBsb2NhdGlvbicpO2xldCBuPWF3YWl0IGZldGNoKGUscik7aWYobi5zdGF0dXM+PTQwMCl0aHJvdyBuZXcgRXJyb3IoYEZldGNoaW5nIHRoZSByZXNvdXJjZSAke2V9IGZhaWxlZCB3aXRoICR7bi5zdGF0dXN9ICR7bi5zdGF0dXNUZXh0fWApO3JldHVybiBufWNvbnN0IHE9dD0+ZSh0KS50b1N0cmluZygpLEk9ZT0+ZS5yZXBsYWNlKC9eKCAqKSg+KykoID4qKSooPyEkKS9tLChlPT5lLnJlcGxhY2UoLyhcXHMpKig/ISQpL2csXCJcIikpKTt2YXIgRj1PYmplY3QuZnJlZXplKHtfX3Byb3RvX186bnVsbCx0b0Jsb2NrcXVvdGU6ZnVuY3Rpb24oZSl7bGV0IHQ9KGU9PntsZXQgdD1lLnNwbGl0KFwiXFxuXCIpLHI9W10sbj0tMSxvPW51bGw7cmV0dXJuIHQuZm9yRWFjaCgoZT0+e2U9SShlKSxvIT09ZS5pbmRleE9mKFwiPlwiKSYmbisrLG89ZS5pbmRleE9mKFwiPlwiKSxyW25dfHwocltuXT1bXSkscltuXS5wdXNoKGUpfSkpLHJ9KShlKSxyPVtdO3JldHVybiB0LmZvckVhY2goKGU9PntyLnB1c2goKGU9PntpZigwIT09ZVswXS5pbmRleE9mKFwiPlwiKSlyZXR1cm4gZS5qb2luKFwiXFxuXCIpO2NvbnN0IHQ9ZT0+e1wiXFxuXCI9PT1lW2UubGVuZ3RoLTFdJiZlLnBvcCgpfTtsZXQgcixuLG89MCxpPVtdO2ZvcihlLmZvckVhY2goKGU9Pntmb3Iobj0oZStcIlwiKS50cmltKCkubWF0Y2goL14oKD4pKykgKj8oLio/JCkvbXMpLHI9blsxXS5sZW5ndGg7cj5vOyl0KGkpLG8rKyxpLnB1c2goXCI8YmxvY2txdW90ZT5cIik7Zm9yKDtvPnI7KXQoaSksby0tLGkucHVzaChcIjwvYmxvY2txdW90ZT5cIik7aS5wdXNoKG5bM10pLGkucHVzaChcIlxcblwiKX0pKTtvPjA7KXQoaSksby0tLGkucHVzaChcIjwvYmxvY2txdW90ZT5cIik7cmV0dXJuIGkuam9pbihcIlwiKX0pKGUpKX0pKSxyLmpvaW4oXCJcIil9LHRvRW1haWxMaW5rOmU9PmU9ZS5yZXBsYWNlKC9bYS16QS1aMC05Ky5fJS1dezEsMjU2fUBbYS16QS1aMC05XVthLXpBLVowLTktXXswLDY0fShcXC5bYS16QS1aMC05XVthLXpBLVowLTktXXswLDI1fSkrL2dpLChlPT4nPGEgaHJlZj1cIm1haWx0bzonK2UrJ1wiPicrZStcIjwvYT5cIikpLHRvSHlwZXJsaW5rOmU9PmU9ZS5yZXBsYWNlKC8oXFxiKGh0dHBzPyk6XFwvXFwvWy1BLVowLTkrJkAjLyU/PX5ffCE6LC47XSpbLUEtWjAtOSsmQCMvJT1+X3xdKS9naSwoZT0+JzxhIGhyZWY9XCInK2UrJ1wiPicrZStcIjwvYT5cIikpLHRvTGluZUJyZWFrOmU9PmU9ZS5yZXBsYWNlKC8oXFxyXFxufFxcbnxcXHIpL2dtLChlPT5cIjxiciAvPlwiKSl9KTtjbGFzcyBSe2NvbXBpbGUoZSx0KXt9fWNsYXNzIFN7cmVuZGVyKGUpe319Y2xhc3MgWiBleHRlbmRzIFN7Y29uc3RydWN0b3IoZSl7aWYoc3VwZXIoKSwhbyhlKSl0aHJvdyBuZXcgRXJyb3IoJ1wiZm5cIiBtdXN0IGJlIG9mIHR5cGUgXCJmdW5jdGlvblwiJyk7dGhpcy5mbj1lfXJlbmRlcihlKXtjb25zdCB0PXRoaXM7dHJ5e3JldHVybiB0LmZuLmNhbGwoe30sZSl9Y2F0Y2goZSl7dGhyb3cgbmV3IEVycm9yKGByZW5kZXJpbmcgXCJkYXRhXCIgZmFpbGVkIHdpdGggbWVzc2FnZSAke2UubWVzc2FnZX1gKX19fWNsYXNzIEIgZXh0ZW5kcyBSe2NvbXBpbGUoZSx0KXt0LnNvbWUoKGU9PntpZigtMSE9PWUuaW5kZXhPZihcIi1cIikpdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgY29tcGlsZSB0ZW1wbGF0ZTogQ29udGFpbnMgaW52YWxpZCBrZXktbmFtZTogJHtlfWApfSkpO2NvbnN0IHI9dGhpcyxuPXIuZ2V0S2V5cyhlKSxvPXIuYnVpbGRBcmd1bWVudExpc3QobiksaT1yLmdldEJsYWNrbGlzdGVkS2V5cyhvLHR8fFtdKTtpZihpLmxlbmd0aCl0aHJvdyBuZXcgRXJyb3IoYENhbm5vdCBjb21waWxlIHRlbXBsYXRlOiBDb250YWlucyBpbnZhbGlkIGtleXM6ICR7aS5qb2luKFwiLCBcIil9YCk7Y29uc3QgYT1yLmdldEZ1bmN0aW9uQ29uZmlnKG8sZSksYz1yLmdldE5hdGl2ZUZ1bmN0aW9uKGEuYXJncyxhLmZuKTtyZXR1cm4gbmV3IFooYyl9YnVpbGRBcmd1bWVudExpc3QoZSl7bGV0IHQ9ZS5tYXAoKGU9PmUuc3BsaXQoL1xcLnxcXFsvKVswXSkpO3JldHVyblsuLi5uZXcgU2V0KHQpXX1nZXRLZXlzKGUpe2NvbnN0IHQ9L1xcJFxceyhbXn1dKylcXH0vZ20scj1bXTtsZXQgbjtmb3IoO251bGwhPT0obj10LmV4ZWMoZSkpOyluLmluZGV4PT09dC5sYXN0SW5kZXgmJnQubGFzdEluZGV4Kyssbi5mb3JFYWNoKCgoZSx0KT0+ezE9PT10JiZyLnB1c2goZSl9KSk7cmV0dXJuIHJ9Z2V0QmxhY2tsaXN0ZWRLZXlzKGUsdCl7cmV0dXJuIHQubGVuZ3RoP2UuZmlsdGVyKChlPT4tMT09PXQuaW5kZXhPZihlKSkpOltdfWdldEZ1bmN0aW9uQ29uZmlnKGUsdCl7cmV0dXJue2FyZ3M6YHske2Uuam9pbihcIiwgXCIpfX1gLGZuOmByZXR1cm4gXFxgJHt0fVxcYGB9fWdldE5hdGl2ZUZ1bmN0aW9uKGUsdCl7cmV0dXJuIG5ldyBGdW5jdGlvbihlLHQpfX1jbGFzcyBLe3JlbmRlcihlKXt9fWNsYXNzIEwgZXh0ZW5kcyBLe2NvbnN0cnVjdG9yKGUpe3N1cGVyKCk7dGhpcy5jb21waWxlcj1uZXcgQix0aGlzLnRwbD1lfXJlbmRlcihlKXtjb25zdCB0PXRoaXM7bGV0IHI9T2JqZWN0LmtleXMoZSksbj1yLmpvaW4oXCIuXCIpO3JldHVybiB0LmNvbXBpbGVkVHBscz10LmNvbXBpbGVkVHBsc3x8e30sdC5jb21waWxlZFRwbHNbbl18fCh0LmNvbXBpbGVkVHBsc1tuXT10LmNvbXBpbGVyLmNvbXBpbGUodC50cGwscikpLHQuY29tcGlsZWRUcGxzW25dLnJlbmRlcihlKX19dmFyIE49T2JqZWN0LmZyZWV6ZSh7X19wcm90b19fOm51bGwsU3RyaW5nQ29tcGlsZXI6QixTdHJpbmdUZW1wbGF0ZTpMLG1ha2U6ZT0+bmV3IEwoZSksVHBsOlp9KSxQPU9iamVjdC5mcmVlemUoe19fcHJvdG9fXzpudWxsLGVzaXg6TixDb21waWxlZFRwbDpTLENvbXBpbGVyOlIsVGVtcGxhdGU6S30pO2V4cG9ydHtrIGFzIGFzc2lnbixfIGFzIGNoYWluLGggYXMgY3JlYXRlUmFuZ2UsZyBhcyBleHRyYWN0LG0gYXMgZmluZEZpcnN0LHYgYXMgZmxpcCxmIGFzIGdyb3VwSW5kaWNlcyxzIGFzIGlzLGEgYXMgaXNBcnJheSxvIGFzIGlzRnVuY3Rpb24sdyBhcyBpc05vdCxpIGFzIGlzTnVtYmVyLHIgYXMgaXNPYmplY3QsbiBhcyBpc1BsYWluT2JqZWN0LGMgYXMgaXNSZWdFeHAsdCBhcyBpc1N0cmluZyx1IGFzIGxpcXVpZnkscCBhcyBsaXN0TmVpZ2hib3Vycyx6IGFzIGxvYWQsTyBhcyBsb2NrLHEgYXMgbWQ1LEUgYXMgb2JqLFQgYXMgcGluZyxBIGFzIHB1cmdlLGIgYXMgcmVwbGFjZSxDIGFzIHJlcXVlc3QsUCBhcyB0ZW1wbGF0ZSxGIGFzIHRleHQsJCBhcyB1bmNoYWluLGQgYXMgdW5pZnkseCBhcyB2aXNpdH07XG4iLCIvKipcbiAqIGNvb24uanNcbiAqIHNpZXN0YS1saWItaGVscGVyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgVGhvcnN0ZW4gU3Vja293LUhvbWJlcmcgaHR0cHM6Ly9naXRodWIuY29tL2Nvb24tanMvc2llc3RhLWxpYi1oZWxwZXJcbiAqXG4gKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvblxuICogb2J0YWluaW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb25cbiAqIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbixcbiAqIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsXG4gKiBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLFxuICogYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbyxcbiAqIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuICpcbiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkXG4gKiBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAqXG4gKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELFxuICogRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTXG4gKiBPRiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuXG4gKiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSxcbiAqIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUlxuICogT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRVxuICogVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS5cbiAqL1xuXG5pbXBvcnQgKiBhcyBsOCBmcm9tIFwiQGw4anMvbDhcIjtcblxuXG4vKipcbiAqIFVzZXMgdGhlIHNwZWNpZmllZCB0ZXN0Q29uZmlnIGZvciB0ZWggcHJlTG9hZGVyLXNlY3Rpb24gYW5kIGFwcGxpZXMgdGhlIHJlbGF0ZWQgcGF0aHMgZm91bmQgYXRcbiAqIHBhdGhDb25maWdVcmwgKGNvbmZpZy1maWxlIHVybCgpKSB0byBpdCwgdGhlbiBwYXNzZXMgaXQgdG8gZ2V0UGF0aHMoKSBhbmQgcmV0dXJucyB0aGUgdmFsdWUuXG4gKiBjb250ZW50IGZvdW5kIGF0IHBhdGhDb25maWdVcmwgc2hvdWxkIGJlIGluIGEgZm9ybWF0IEBjb29uLWpzL2V4dGpzLWxpbmsgcHJvZHVjZXMuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiAganNvbiBhdCBcInBhdGhDb25maWdVcmwuanNvblwiOlxuICpcbiAqICB7XG4gKiAgICAgICBjc3M6IFt7XG4gKiAgICAgICAgICAgICAgIG1vZGVybjogW1xuICogICAgICAgICAgICAgICAgICAgXCJmb28uY3NzXCJcbiAqICAgICAgICAgICAgICAgXSxcbiAqICAgICAgICAgICAgICAgY2xhc3NpYzogW1xuICogICAgICAgICAgICAgICAgICAgXCJiYXIuY3NzXCJcbiAqICAgICAgICAgICAgICAgXVxuICpcbiAqICAgICAgIH1dLFxuICogICAgICAganM6IHtcbiAqICAgICAgICAgICAgICAgbW9kZXJuOiBcIm1vZGVybi5qc1wiLFxuICogICAgICAgICAgICAgICBjbGFzc2ljOiBcImNsYXNzaWMuanNcIlxuICpcbiAqICAgICAgfVxuICogICB9XG4gKlxuICpcbiAqICBjb25zdCBjb25maWcgPSB7XG4gKiAgICAgIGxvYWRlclBhdGg6IHtcbiAqICAgICAgIFwiRXh0LlBhY2thZ2VcIjogXCIvbm9kZV9tb2R1bGVzL0Bjb29uLWpzL2V4dGpzLXBhY2thZ2UtbG9hZGVyL3BhY2thZ2VzL3BhY2thZ2UtbG9hZGVyL3NyYy9zcmMvUGFja2FnZS5qc1wiLFxuICogICAgICAgXCJjb29uLmNvcmVcIjogXCIuLi9zcmMvXCIsXG4gKiAgIH0sXG4gKiAgIHByZWxvYWRzOiB7XG4gKiAgICAgICBjc3M6IFt7XG4gKiAgICAgICAgICAgICAgIG1vZGVybjogW1xuICogICAgICAgICAgICAgICAgICAgXCIvbm9kZV9tb2R1bGVzL0BzZW5jaGEvZXh0LW1vZGVybi1ydW50aW1lL21hdGVyaWFsL21hdGVyaWFsLWFsbF8xLmNzc1wiLFxuICogICAgICAgICAgICAgICAgICAgXCIvbm9kZV9tb2R1bGVzL0BzZW5jaGEvZXh0LW1vZGVybi1ydW50aW1lL21hdGVyaWFsL21hdGVyaWFsLWFsbF8yLmNzc1wiXG4gKiAgICAgICAgICAgICAgIF0sXG4gKiAgICAgICAgICAgICAgIGNsYXNzaWM6IFtcbiAqICAgICAgICAgICAgICAgICAgIFwiL25vZGVfbW9kdWxlcy9Ac2VuY2hhL2V4dC1jbGFzc2ljLXJ1bnRpbWUvbWF0ZXJpYWwvbWF0ZXJpYWwtYWxsXzEuY3NzXCIsXG4gKiAgICAgICAgICAgICAgICAgICBcIi9ub2RlX21vZHVsZXMvQHNlbmNoYS9leHQtY2xhc3NpYy1ydW50aW1lL21hdGVyaWFsL21hdGVyaWFsLWFsbF8yLmNzc1wiLFxuICogICAgICAgICAgICAgICAgICAgXCIvbm9kZV9tb2R1bGVzL0BzZW5jaGEvZXh0LWNsYXNzaWMtcnVudGltZS9tYXRlcmlhbC9tYXRlcmlhbC1hbGxfMy5jc3NcIlxuICogICAgICAgICAgICAgICBdXG4gKiAgICAgICB9XSxcbiAqICAgICAgIGpzOiBbXG4gKiAgICAgICAgICAgXCIvbm9kZV9tb2R1bGVzL0BsOGpzL2w4L2Rpc3QvbDgucnVudGltZS5qc1wiLCB7XG4gKiAgICAgICAgICAgICAgIG1vZGVybjogXCIvbm9kZV9tb2R1bGVzL0BzZW5jaGEvZXh0LW1vZGVybi1ydW50aW1lL21vZGVybi5lbmdpbmUuZW50ZXJwcmlzZS5qc1wiLFxuICogICAgICAgICAgICAgICBjbGFzc2ljOiBcIi9ub2RlX21vZHVsZXMvQHNlbmNoYS9leHQtbW9kZXJuLXJ1bnRpbWUvY2xhc3NpYy5lbmdpbmUuZW50ZXJwcmlzZS5qc1wiXG4gKiAgICAgICAgICAgfVxuICogICAgICAgXVxuICogICB9fTtcbiAqXG4gKiAgY29uZmlndXJlV2l0aEV4dEpzTGlua1BhdGhzKGNvbmZpZywgXCJwYXRoQ29uZmlnVXJsLmpzb25cIiwgdHJ1ZSk7IC8vIHJldHVybnMge1xuICogICAvLyAgIHByZWxvYWQgOiBbXG4gKiAgIC8vICAgICAgIFwiZm9vLmNzc1wiLFxuICogICAvLyAgICAgICBcIi9ub2RlX21vZHVsZXMvQGw4anMvbDgvZGlzdC9sOC5ydW50aW1lLmpzXCIsXG4gKiAgIC8vICAgICAgIFwiL25vZGVfbW9kdWxlcy9Ac2VuY2hhL2V4dC1tb2Rlcm4tcnVudGltZS9tb2Rlcm4uZW5naW5lLmVudGVycHJpc2UuanNcIlxuICogICAvLyAgICAgICBcIm1vZGVybi5qc1wiXG4gKiAgIC8vICAgXSxcbiAqICAgLy8gICBsb2FkZXJQYXRoIDoge1xuICogICAvLyAgICAgICBcIkV4dC5QYWNrYWdlXCI6IFwiL25vZGVfbW9kdWxlcy9AY29vbi1qcy9leHRqcy1wYWNrYWdlLWxvYWRlci9wYWNrYWdlcy9wYWNrYWdlLWxvYWRlci9zcmMvc3JjL1BhY2thZ2UuanNcIixcbiAqICAgLy8gICAgICAgXCJjb29uLmNvcmVcIjogXCIuLi9zcmMvXCJcbiAqICAgLy8gICB9XG4gKiAgLy8gfTtcbiAqXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHRlc3RDb25maWdcbiAqIEBwYXJhbSB7U3RyaW5nfSBwYXRoQ29uZmlnVXJsXG4gKiBAcGFyYW0ge0Jvb2xlYW59IGlzTW9kZXJuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx7bG9hZGVyUGF0aDoge30sIHByZWxvYWQ6ICpbXX0+fVxuICovXG5leHBvcnQgY29uc3QgY29uZmlndXJlV2l0aEV4dEpzTGlua1BhdGhzID0gYXN5bmMgZnVuY3Rpb24gKHRlc3RDb25maWcsIHBhdGhDb25maWdVcmwsIGlzTW9kZXJuKSB7XG5cbiAgICBpZiAoYXdhaXQgbDgucGluZyhwYXRoQ29uZmlnVXJsKSkge1xuXG4gICAgICAgIGNvbnN0XG4gICAgICAgICAgICBleHRqc0xpbmtDb25maWcgPSBKU09OLnBhcnNlKGF3YWl0IGw4LmxvYWQocGF0aENvbmZpZ1VybCkpLFxuICAgICAgICAgICAgbWVyZ2VkQ3NzID0ge30sIG1lcmdlZEpzID0ge30sXG4gICAgICAgICAgICBjb2xsZWN0ID0gKHNlY3Rpb24sIHRvb2xraXQpID0+IHtcbiAgICAgICAgICAgICAgICBsZXQgcmVzID0gW107XG4gICAgICAgICAgICAgICAgc2VjdGlvbi5mb3JFYWNoKGVudHJ5ID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGw4LmlzU3RyaW5nKGVudHJ5KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzLnB1c2goZW50cnkpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGw4LmlzUGxhaW5PYmplY3QoZW50cnkpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXMgPSByZXMuY29uY2F0KGVudHJ5W3Rvb2xraXRdID8/IFtdKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXM7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgIFtcImNsYXNzaWNcIiwgXCJtb2Rlcm5cIl0uZm9yRWFjaCh0b29sa2l0ID0+IHtcblxuICAgICAgICAgICAgbGV0IGZmID0gbDguZmluZEZpcnN0LmJpbmQobnVsbCwgdG9vbGtpdCksXG4gICAgICAgICAgICAgICAgY3NzID0gY29sbGVjdChbXS5jb25jYXQobDgudW5jaGFpbihcInByZWxvYWQuY3NzXCIsIHRlc3RDb25maWcpKSwgdG9vbGtpdCksXG4gICAgICAgICAgICAgICAganMgPSBjb2xsZWN0KFtdLmNvbmNhdChsOC51bmNoYWluKFwicHJlbG9hZC5qc1wiLCB0ZXN0Q29uZmlnKSksIHRvb2xraXQpLFxuICAgICAgICAgICAgICAgIGV4dENzcyA9IGw4LnVuY2hhaW4oXCJjc3NcIiwgZXh0anNMaW5rQ29uZmlnLCBmZiksXG4gICAgICAgICAgICAgICAgZXh0SnMgPSAgbDgudW5jaGFpbihcImpzXCIsIGV4dGpzTGlua0NvbmZpZywgZmYpO1xuXG5cbiAgICAgICAgICAgIGw4LmNoYWluKHRvb2xraXQsIG1lcmdlZENzcywgW10uY29uY2F0KGNzcywgW10uY29uY2F0KGV4dENzcykpKTtcbiAgICAgICAgICAgIGw4LmNoYWluKHRvb2xraXQsIG1lcmdlZEpzLCBbXS5jb25jYXQoanMsIFtdLmNvbmNhdChleHRKcykpKTtcbiAgICAgICAgfSk7XG5cblxuICAgICAgICBsOC5jaGFpbihcInByZWxvYWQuY3NzXCIsIHRlc3RDb25maWcsIG1lcmdlZENzcywgdHJ1ZSk7XG4gICAgICAgIGw4LmNoYWluKFwicHJlbG9hZC5qc1wiLCB0ZXN0Q29uZmlnLCBtZXJnZWRKcywgdHJ1ZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGdldFBhdGhzKHRlc3RDb25maWcsIGlzTW9kZXJuKTtcblxufTtcblxuXG4vKipcbiAqIENvbnN1bWVzIGEgY29uZmlndXJhdGlvbiBvYmplY3QgYW5kIGxvb2tzIHVwIGpzL2Nzcy1yZWxhdGVkIHBhdGggaW5mb3JtYXRpb24sXG4gKiB0aGVuIHJldHVybnMgaXQgcHJlLWNvbmZpZ3VyZWQgdG8gYmUgdXNlZCB3aXRoIFNpZXN0YXMgU2llc3RhLkhhcm5lc3MuQnJvd3Nlci5FeHRKUygpI2NvbmZpZy5cbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqICBjb25zdCBjb25maWcgPSB7XG4gKiAgICAgIGxvYWRlclBhdGg6IHtcbiAqICAgICAgIFwiRXh0LlBhY2thZ2VcIjogXCIvbm9kZV9tb2R1bGVzL0Bjb29uLWpzL2V4dGpzLXBhY2thZ2UtbG9hZGVyL3BhY2thZ2VzL3BhY2thZ2UtbG9hZGVyL3NyYy9zcmMvUGFja2FnZS5qc1wiLFxuICogICAgICAgXCJjb29uLmNvcmVcIjogXCIuLi9zcmMvXCIsXG4gKiAgIH0sXG4gKiAgIHByZWxvYWRzOiB7XG4gKiAgICAgICBjc3M6IFt7XG4gKiAgICAgICAgICAgICAgIG1vZGVybjogW1xuICogICAgICAgICAgICAgICAgICAgXCIvbm9kZV9tb2R1bGVzL0BzZW5jaGEvZXh0LW1vZGVybi1ydW50aW1lL21hdGVyaWFsL21hdGVyaWFsLWFsbF8xLmNzc1wiLFxuICogICAgICAgICAgICAgICAgICAgXCIvbm9kZV9tb2R1bGVzL0BzZW5jaGEvZXh0LW1vZGVybi1ydW50aW1lL21hdGVyaWFsL21hdGVyaWFsLWFsbF8yLmNzc1wiXG4gKiAgICAgICAgICAgICAgIF0sXG4gKiAgICAgICAgICAgICAgIGNsYXNzaWM6IFtcbiAqICAgICAgICAgICAgICAgICAgIFwiL25vZGVfbW9kdWxlcy9Ac2VuY2hhL2V4dC1jbGFzc2ljLXJ1bnRpbWUvbWF0ZXJpYWwvbWF0ZXJpYWwtYWxsXzEuY3NzXCIsXG4gKiAgICAgICAgICAgICAgICAgICBcIi9ub2RlX21vZHVsZXMvQHNlbmNoYS9leHQtY2xhc3NpYy1ydW50aW1lL21hdGVyaWFsL21hdGVyaWFsLWFsbF8yLmNzc1wiLFxuICogICAgICAgICAgICAgICAgICAgXCIvbm9kZV9tb2R1bGVzL0BzZW5jaGEvZXh0LWNsYXNzaWMtcnVudGltZS9tYXRlcmlhbC9tYXRlcmlhbC1hbGxfMy5jc3NcIlxuICogICAgICAgICAgICAgICBdXG4gKiAgICAgICB9XSxcbiAqICAgICAgIGpzOiBbXG4gKiAgICAgICAgICAgXCIvbm9kZV9tb2R1bGVzL0BsOGpzL2w4L2Rpc3QvbDgucnVudGltZS5qc1wiLCB7XG4gKiAgICAgICAgICAgICAgIG1vZGVybjogXCIvbm9kZV9tb2R1bGVzL0BzZW5jaGEvZXh0LW1vZGVybi1ydW50aW1lL21vZGVybi5lbmdpbmUuZW50ZXJwcmlzZS5qc1wiLFxuICogICAgICAgICAgICAgICBjbGFzc2ljOiBcIi9ub2RlX21vZHVsZXMvQHNlbmNoYS9leHQtbW9kZXJuLXJ1bnRpbWUvY2xhc3NpYy5lbmdpbmUuZW50ZXJwcmlzZS5qc1wiXG4gKiAgICAgICAgICB9XG4gKiAgICAgICBdXG4gKiAgIH19O1xuICpcbiAqICBnZXRQYXRocyhjb25maWcsIHRydWUpOyAvLyByZXR1cm5zIHtcbiAqICAgLy8gICBwcmVsb2FkIDogW1xuICogICAvLyAgICAgICBcIi9ub2RlX21vZHVsZXMvQHNlbmNoYS9leHQtbW9kZXJuLXJ1bnRpbWUvbWF0ZXJpYWwvbWF0ZXJpYWwtYWxsXzEuY3NzXCIsXG4gKiAgIC8vICAgICAgIFwiL25vZGVfbW9kdWxlcy9Ac2VuY2hhL2V4dC1tb2Rlcm4tcnVudGltZS9tYXRlcmlhbC9tYXRlcmlhbC1hbGxfMi5jc3NcIixcbiAqICAgLy8gICAgICAgXCIvbm9kZV9tb2R1bGVzL0BsOGpzL2w4L2Rpc3QvbDgucnVudGltZS5qc1wiLFxuICogICAvLyAgICAgICBcIi9ub2RlX21vZHVsZXMvQHNlbmNoYS9leHQtbW9kZXJuLXJ1bnRpbWUvbW9kZXJuLmVuZ2luZS5lbnRlcnByaXNlLmpzXCJcbiAqICAgLy8gICBdLFxuICogICAvLyAgIGxvYWRlclBhdGggOiB7XG4gKiAgIC8vICAgICAgIFwiRXh0LlBhY2thZ2VcIjogXCIvbm9kZV9tb2R1bGVzL0Bjb29uLWpzL2V4dGpzLXBhY2thZ2UtbG9hZGVyL3BhY2thZ2VzL3BhY2thZ2UtbG9hZGVyL3NyYy9zcmMvUGFja2FnZS5qc1wiLFxuICogICAvLyAgICAgICBcImNvb24uY29yZVwiOiBcIi4uL3NyYy9cIlxuICogICAvLyAgIH1cbiAqICAvLyB9O1xuICpcbiAqXG4gKlxuICovXG5leHBvcnQgY29uc3QgZ2V0UGF0aHMgPSAoY29uZmlnLCBpc01vZGVybikgPT4ge1xuXG4gICAgY29uc3RcbiAgICAgICAgcmVzdWx0ID0ge3ByZWxvYWQ6IFtdLCBsb2FkZXJQYXRoOiB7fX0sXG4gICAgICAgIGlzT2JqZWN0ID0gbDguaXNPYmplY3QsXG4gICAgICAgIGlzQXJyYXkgPSBsOC5pc0FycmF5LFxuICAgICAgICBpc1N0cmluZyA9IGw4LmlzU3RyaW5nLFxuICAgICAgICB0b29sa2l0ID0gaXNNb2Rlcm4gPyBcIm1vZGVyblwiIDogaXNNb2Rlcm4gPT09IGZhbHNlID8gXCJjbGFzc2ljXCIgOiBudWxsLFxuICAgICAgICBwYXJzZVNlY3Rpb24gPSAoc2VjdGlvbikgPT4ge1xuXG4gICAgICAgICAgICBzZWN0aW9uID0gW10uY29uY2F0KHNlY3Rpb24pO1xuXG4gICAgICAgICAgICBzZWN0aW9uLmZvckVhY2goKGVudHJ5KSA9PiB7XG5cbiAgICAgICAgICAgICAgICBpZiAoaXNTdHJpbmcoZW50cnkpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wcmVsb2FkLnB1c2goZW50cnkpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoaXNPYmplY3QoZW50cnkpICYmIHRvb2xraXQgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGlzQXJyYXkoZW50cnlbdG9vbGtpdF0pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHJlbG9hZCA9IHJlc3VsdC5wcmVsb2FkLmNvbmNhdChlbnRyeVt0b29sa2l0XSk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoaXNTdHJpbmcoZW50cnlbdG9vbGtpdF0pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQucHJlbG9hZC5wdXNoKGVudHJ5W3Rvb2xraXRdKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgfTtcblxuICAgIGw4LmFzc2lnbihcbiAgICAgICAgcmVzdWx0LmxvYWRlclBhdGgsXG4gICAgICAgIFtjb25maWcubG9hZGVyUGF0aCB8fCB7fSwgXCJjbGFzc2ljXCIsIFwibW9kZXJuXCJdLFxuICAgICAgICBjb25maWcubG9hZGVyUGF0aCAmJiBjb25maWcubG9hZGVyUGF0aFt0b29sa2l0XSA/IGNvbmZpZy5sb2FkZXJQYXRoW3Rvb2xraXRdIDoge31cbiAgICApO1xuXG4gICAgY29uc3Qge2pzLCBjc3N9ID0gY29uZmlnLnByZWxvYWQgfHwge307XG5cbiAgICBwYXJzZVNlY3Rpb24oY3NzKTtcbiAgICBwYXJzZVNlY3Rpb24oanMpO1xuXG4gICAgcmV0dXJuIHJlc3VsdDtcblxufTsiLCIvKipcbiAqIGNvb24uanNcbiAqIHNpZXN0YS1saWItaGVscGVyXG4gKiBDb3B5cmlnaHQgKEMpIDIwMjEgVGhvcnN0ZW4gU3Vja293LUhvbWJlcmcgaHR0cHM6Ly9naXRodWIuY29tL2Nvb24tanMvc2llc3RhLWxpYi1oZWxwZXJcbiAqXG4gKiBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvblxuICogb2J0YWluaW5nIGEgY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb25cbiAqIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbixcbiAqIGluY2x1ZGluZyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsXG4gKiBwdWJsaXNoLCBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLFxuICogYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbyxcbiAqIHN1YmplY3QgdG8gdGhlIGZvbGxvd2luZyBjb25kaXRpb25zOlxuICpcbiAqIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkXG4gKiBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbiAqXG4gKiBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELFxuICogRVhQUkVTUyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTXG4gKiBPRiBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuXG4gKiBJTiBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSxcbiAqIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUlxuICogT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRVxuICogVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS5cbiAqL1xuXG5pbXBvcnQge2NvbmZpZ3VyZVdpdGhFeHRKc0xpbmtQYXRoc30gZnJvbSBcIi4vaW5kZXguanNcIjtcblxuaWYgKCFjb29uanMuc2llc3RhVGVzdENvbmZpZ09iaiB8fCAhY29vbmpzLnNpZXN0YUdyb3Vwc0NvbmZpZ09iaiB8fCAhIGNvb25qcy5leHRqc0xpbmtDb25maWdVcmwpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJDb25maWcgbWlzc2luZ1wiKTtcbn1cblxuY29uc3RcbiAgICB0ZXN0Q29uZmlnID0gY29vbmpzLnNpZXN0YVRlc3RDb25maWdPYmosXG4gICAgZ3JvdXBzID0gY29vbmpzLnNpZXN0YUdyb3Vwc0NvbmZpZ09iaixcbiAgICBleHRqc0xpbmtDb25maWdVcmwgPSBjb29uanMuZXh0anNMaW5rQ29uZmlnVXJsO1xuXG5sZXQgdG9vbGtpdEdyb3VwcyxcbiAgICByZW1haW5pbmdHcm91cHMsXG4gICAgY29uZmlndXJlZFRvb2xraXRHcm91cHMsXG4gICAgaGFzVG9vbGtpdFJlbGF0ZWRDb25maWcgPSBmYWxzZSxcbiAgICB1cmxQYXJhbXMgPSBuZXcgVVJMU2VhcmNoUGFyYW1zKGRvY3VtZW50LmxvY2F0aW9uLnNlYXJjaC5zdWJzdHJpbmcoMSkpLFxuICAgIHRpbWVvdXQgPSAgdXJsUGFyYW1zLmdldChcInRpbWVvdXRcIikgPyBwYXJzZUludCh1cmxQYXJhbXMuZ2V0KFwidGltZW91dFwiKSkgOiB0ZXN0Q29uZmlnLnRpbWVvdXQsXG4gICAgZm9yY2VkVG9vbGtpdCA9IHVybFBhcmFtcy5nZXQoXCJ0b29sa2l0XCIpLFxuICAgIHRvb2xraXQgPSB1cmxQYXJhbXMuZ2V0KFwidG9vbGtpdFwiKSA/PyBcImNsYXNzaWNcIjtcblxuY29uc3RcbiAgICBicm93c2VyID0gbmV3IFNpZXN0YS5IYXJuZXNzLkJyb3dzZXIuRXh0SlMoKTtcblxuY29uZmlndXJlV2l0aEV4dEpzTGlua1BhdGhzKHRlc3RDb25maWcsIGV4dGpzTGlua0NvbmZpZ1VybCwgdG9vbGtpdCA9PT0gXCJtb2Rlcm5cIikudGhlbigocGF0aHMpID0+IHtcblxuXG4gICAgY29uZmlndXJlZFRvb2xraXRHcm91cHMgPSBncm91cHMuZmlsdGVyKGVudHJ5ID0+IFtcImNsYXNzaWNcIiwgXCJtb2Rlcm5cIl0uaW5kZXhPZihlbnRyeS5ncm91cCkgIT09IC0xKTtcbiAgICBoYXNUb29sa2l0UmVsYXRlZENvbmZpZyA9IGNvbmZpZ3VyZWRUb29sa2l0R3JvdXBzLmxlbmd0aCA+IDA7XG4gICAgdG9vbGtpdEdyb3VwcyA9IGdyb3Vwcy5maWx0ZXIoZW50cnkgPT4gW1widW5pdmVyc2FsXCIsIHRvb2xraXRdLmluZGV4T2YoZW50cnkuZ3JvdXApICE9PSAtMSk7XG4gICAgLy8gd2UgbmVlZCB0byBjaGVjayBpZiB0aGUgbG9hZGVyIHNwZWNpZmllcyBkaWZmZXJlbnQgY2xhc3NlcyBmb3IgbW9kZXJuL2NsYXNzaWMgaGVyZSwgYXMgdGhlIHRlc3RzXG4gICAgLy8gbWlnaHQgYmUgZGVjbGFyZWQgYXMgXCJ1bml2ZXJzYWxcIiwgYnV0IHRoZSB0ZXN0IGNhc2VzIGxvYWQgZGlmZmVyZW50IGZpbGVzIGZvciB0aGUgdG9vbGtpdHNcbiAgICB0b29sa2l0ID0gdG9vbGtpdEdyb3Vwcy5sZW5ndGggPyB0b29sa2l0R3JvdXBzWzBdLmdyb3VwIDogXCJ1bml2ZXJzYWxcIjtcbiAgICBpZiAodG9vbGtpdCA9PT0gXCJ1bml2ZXJzYWxcIiAmJiAodGVzdENvbmZpZy5sb2FkZXJQYXRoLmNsYXNzaWMgfHwgdGVzdENvbmZpZy5sb2FkZXJQYXRoLm1vZGVybikpIHtcbiAgICAgICAgdG9vbGtpdCA9ICB1cmxQYXJhbXMuZ2V0KFwidG9vbGtpdFwiKSB8fCAodGVzdENvbmZpZy5sb2FkZXJQYXRoLmNsYXNzaWMgPyBcImNsYXNzaWNcIiA6IFwibW9kZXJuXCIpO1xuICAgICAgICBmb3JjZWRUb29sa2l0ID0gdG9vbGtpdDtcbiAgICB9XG5cbiAgICByZW1haW5pbmdHcm91cHMgPSBncm91cHMuZmlsdGVyKGVudHJ5ID0+IFtcInVuaXZlcnNhbFwiLCBcImNsYXNzaWNcIiwgXCJtb2Rlcm5cIl0uaW5kZXhPZihlbnRyeS5ncm91cCkgPT09IC0xKTtcblxuICAgIGJyb3dzZXIuY29uZmlndXJlKE9iamVjdC5hc3NpZ24oe1xuICAgICAgICB0aXRsZTogYCR7dGVzdENvbmZpZy5uYW1lfSBbJHt0b29sa2l0fV1gLFxuICAgICAgICBpc0VjbWFNb2R1bGU6IHRydWUsXG4gICAgICAgIGRpc2FibGVDYWNoaW5nOiB0cnVlLFxuICAgICAgICBjb25maWcgOiB7XG4gICAgICAgICAgICBUSU1FT1VUIDogdGltZW91dFxuICAgICAgICB9XG4gICAgfSwgcGF0aHMpKTtcblxuICAgIGJyb3dzZXIuc3RhcnQoKHRvb2xraXRHcm91cHMubGVuZ3RoID8gdG9vbGtpdEdyb3VwcyA6IGdyb3VwcykuY29uY2F0KHJlbWFpbmluZ0dyb3VwcykpO1xuXG4gICAgLy8gY2xhc3NpYyB8IG1vZGVybiB8IHRpbWVvdXQgb3B0aW9uc1xuICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwiY25fdGltZW91dFwiKS52YWx1ZSA9IHRpbWVvdXQ7XG4gICAgaWYgKFtcImNsYXNzaWNcIiwgXCJtb2Rlcm5cIl0uaW5kZXhPZih0b29sa2l0KSAhPT0gLTEpIHtcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoYGNuXyR7dG9vbGtpdH1gKS5jaGVja2VkID0gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKCFoYXNUb29sa2l0UmVsYXRlZENvbmZpZykge1xuICAgICAgICBbXCJjbGFzc2ljXCIsIFwibW9kZXJuXCJdLmZvckVhY2godG9vbGtpdCA9PiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChgY25fJHt0b29sa2l0fWApLmRpc2FibGVkID0gdHJ1ZSk7XG4gICAgfSBlbHNlIGlmIChoYXNUb29sa2l0UmVsYXRlZENvbmZpZyAmJiBbXCJjbGFzc2ljXCIsIFwibW9kZXJuXCJdLmluZGV4T2YoZm9yY2VkVG9vbGtpdCkgIT09IC0xKSB7XG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGBjbl8ke2ZvcmNlZFRvb2xraXR9YCkuY2hlY2tlZCA9IHRydWU7XG4gICAgfVxuICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwiY25fY29uZmlnQnRuXCIpLm9uY2xpY2sgPSAoKSA9PiB7XG4gICAgICAgIGxldCB0aW1lb3V0ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJjbl90aW1lb3V0XCIpLnZhbHVlLFxuICAgICAgICAgICAgdG9vbGtpdCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFwiY25fY2xhc3NpY1wiKS5jaGVja2VkID9cbiAgICAgICAgICAgICAgICBcImNsYXNzaWNcIiA6XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXCJjbl9tb2Rlcm5cIikuY2hlY2tlZCA/IFwibW9kZXJuXCIgOiBcIlwiO1xuXG4gICAgICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gYC4vaW5kZXguZXh0anMtYnJvd3Nlci5odG1sP3Rvb2xraXQ9JHt0b29sa2l0fSZ0aW1lb3V0PSR7dGltZW91dH1gO1xuICAgIH07XG5cbn0pO1xuXG4iXSwibmFtZXMiOlsibDgucGluZyIsImw4LmxvYWQiLCJsOC5pc1N0cmluZyIsImw4LmlzUGxhaW5PYmplY3QiLCJsOC5maW5kRmlyc3QiLCJsOC51bmNoYWluIiwibDguY2hhaW4iLCJsOC5pc09iamVjdCIsImw4LmlzQXJyYXkiLCJsOC5hc3NpZ24iXSwibWFwcGluZ3MiOiJBQUFxQyxNQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxFQUFFLGlCQUFpQixHQUFHLE1BQU0sQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsV0FBVyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLFVBQVUsRUFBRSxPQUFPLENBQUMsQ0FBeUIsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxZQUFZLE1BQU0sQ0FBODBDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUEyRCxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQyx3QkFBd0IsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxLQUFLLENBQUMsdUNBQXVDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLEdBQUcsRUFBRSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUF