diff --git a/dist/index.cjs b/dist/index.cjs index db5d8a91..b9179202 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";require("colors");var e=require("fs"),t=require("path"),o=require("body-parser"),r=require("cors"),i=require("express"),n=require("multer"),s=require("http"),a=require("https"),l=require("dotenv"),c=require("express-rate-limit"),p=require("url"),u=require("https-proxy-agent"),d=require("uuid"),h=require("tarn"),g=require("puppeteer"),f=require("node:path"),m=require("node:crypto");require("prompts");var v="undefined"!=typeof document?document.currentScript:null;function y(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(o){if("default"!==o){var r=Object.getOwnPropertyDescriptor(e,o);Object.defineProperty(t,o,r.get?r:{enumerable:!0,get:function(){return e[o]}})}})),t.default=e,Object.freeze(t)}var b=y(p);l.config();const w={puppeteer:{args:{value:[],type:"string[]",description:"Array of arguments to send to puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"Highcharts version to use."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN",type:"string",description:"The CDN URL of Highcharts scripts to use."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"Highcharts core scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","draggable-points","static-scale","broken-axis","heatmap","tilemap","timeline","treemap","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","pyramid3d","networkgraph","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","stock-tools","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi"],type:"string[]",description:"Highcharts modules to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"Highcharts indicators to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional direct scripts/optional dependencies (e.g. moment.js)."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"Should all the scripts be refetched after rerunning the server."}},export:{infile:{value:!1,type:"string",description:"The input file name along with a type (json or svg). It can be a correct JSON or SVG file."},instr:{value:!1,type:"string",description:"An input in a form of a stringified JSON or SVG file. Overrides the --infile."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf or svg). Ignores the --type flag."},type:{envLink:"EXPORT_DEFAULT_TYPE",value:"png",type:"string",description:"The format of the file to export to. Can be jpeg, png, pdf or svg."},constr:{envLink:"EXPORT_DEFAULT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"The default height of the exported chart. Used when not found any value set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when not found any value set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Ranges between 1 and 5."},height:{type:"number",value:!1,description:"The default height of the exported chart. Overrides the option in the chart settings."},width:{type:"number",value:!1,description:"The width of the exported chart. Overrides the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart. Ranges between 1 and 5."},globalOptions:{value:!1,type:"string",description:"A stringified JSON or a filename with options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"A stringified JSON or a filename with theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Starts a batch job. A string that contains input/output pairs: "in=out;in=out;..".'}},customCode:{allowCodeExecution:{envLink:"HIGHCHARTS_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"If set to true, allow for the execution of arbitrary code when exporting."},allowFileResources:{envLink:"HIGHCHARTS_ALLOW_FILE_RESOURCES",value:!0,type:"boolean",description:"Allow injecting resources from the filesystem. Has no effect when running as a server."},customCode:{value:!1,type:"string",description:"A function to be called before chart initialization. Can be a filename with the js extension."},callback:{value:!1,type:"string",description:"A JavaScript file with a function to run on construction."},resources:{value:!1,type:"string",description:"An additional resource in a form of stringified JSON. It can contain files, js and css sections."},loadConfig:{value:!1,type:"string",description:"A file that contains a pre-defined config to use."},createConfig:{value:!1,type:"string",description:"Allows to set options through a prompt and save in a provided config file."}},server:{enable:{envLink:"HIGHCHARTS_SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"If set to true, starts a server on 0.0.0.0."},host:{envLink:"HIGHCHARTS_SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Also starts a server listening on the supplied hostname."},port:{envLink:"HIGHCHARTS_SERVER_PORT",value:7801,type:"number",description:"The port to use for the server. Defaults to 7801."},ssl:{enable:{envLink:"HIGHCHARTS_SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables the SSL protocol."},force:{envLink:"HIGHCHARTS_SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",description:"If set to true, forces the server to only serve over HTTPS."},port:{envLink:"HIGHCHARTS_SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"HIGHCHARTS_SSL_CERT_PATH",value:"",type:"string",description:"The path to the SSL certificate/key."}},rateLimiting:{enable:{envLink:"HIGHCHARTS_RATE_LIMIT_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting."},maxRequests:{envLink:"HIGHCHARTS_RATE_LIMIT_MAX",value:10,type:"number",description:"Max requests allowed in a one minute."},window:{envLink:"HIGHCHARTS_RATE_LIMIT_WINDOW",value:1,type:"number",description:"The time window in minutes for rate limiting."},delay:{envLink:"HIGHCHARTS_RATE_LIMIT_DELAY",value:0,type:"number",description:"The amount to delay each successive request before hitting the max."},trustProxy:{envLink:"HIGHCHARTS_RATE_LIMIT_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if behind a load balancer."},skipKey:{envLink:"HIGHCHARTS_RATE_LIMIT_SKIP_KEY",value:"",type:"number|string",description:"Allows bypassing the rate limiter and should be provided with skipToken argument."},skipToken:{envLink:"HIGHCHARTS_RATE_LIMIT_SKIP_TOKEN",value:"",type:"number|string",description:"Allows bypassing the rate limiter and should be provided with skipKey argument."}}},pool:{initialWorkers:{envLink:"HIGHCHARTS_POOL_MIN_WORKERS",value:4,type:"number",description:"The number of initial workers to spawn."},maxWorkers:{envLink:"HIGHCHARTS_POOL_MAX_WORKERS",value:8,type:"number",description:"The number of max workers to spawn."},workLimit:{envLink:"HIGHCHARTS_POOL_WORK_LIMIT",value:40,type:"number",description:"The pieces of work that can be performed before restarting process."},queueSize:{envLink:"HIGHCHARTS_POOL_QUEUE_SIZE",value:5,type:"number",description:"The size of the request overflow queue."},timeoutThreshold:{envLink:"HIGHCHARTS_POOL_TIMEOUT",value:5e3,type:"number",description:"The number of milliseconds before timing out."},acquireTimeout:{envLink:"HIGHCHARTS_POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The number of milliseconds to wait for acquiring a resource."},reaper:{envLink:"HIGHCHARTS_POOL_ENABLE_REAPER",value:!0,type:"boolean",description:"Whether or not to evict workers after a certain time period."},benchmarking:{envLink:"HIGHCHARTS_POOL_BENCHMARKING",value:!1,type:"boolean",description:"Enable benchmarking."},listenToProcessExits:{envLink:"HIGHCHARTS_POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Set to false in order to skip attaching process.exit handlers."}},logging:{level:{envLink:"HIGHCHARTS_LOG_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose)."},file:{envLink:"HIGHCHARTS_LOG_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"A name of a log file. The --logDest also needs to be set to enable file logging."},dest:{envLink:"HIGHCHARTS_LOG_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. Also enables file logging."}},ui:{enable:{envLink:"HIGHCHARTS_UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables the UI for the export server."},route:{envLink:"HIGHCHARTS_UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The route to attach the UI to."}},other:{noLogo:{envLink:"HIGHCHARTS_NO_LOGO",value:!1,type:"boolean",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}},payload:{}};w.puppeteer.args.value.join(","),w.highcharts.version.value,w.highcharts.cdnURL.value,w.highcharts.modules.value,w.highcharts.scripts.value.join(","),w.highcharts.forceFetch.value,w.export.type.value,w.export.constr.value,w.export.defaultHeight.value,w.export.defaultWidth.value,w.export.defaultScale.value,w.customCode.allowCodeExecution.value,w.customCode.allowFileResources.value,w.server.enable.value,w.server.host.value,w.server.port.value,w.server.ssl.enable.value,w.server.ssl.force.value,w.server.ssl.port.value,w.server.ssl.certPath.value,w.server.rateLimiting.enable.value,w.server.rateLimiting.maxRequests.value,w.server.rateLimiting.window.value,w.server.rateLimiting.delay.value,w.server.rateLimiting.trustProxy.value,w.server.rateLimiting.skipKey.value,w.server.rateLimiting.skipToken.value,w.pool.initialWorkers.value,w.pool.maxWorkers.value,w.pool.workLimit.value,w.pool.queueSize.value,w.pool.timeoutThreshold.value,w.pool.acquireTimeout.value,w.pool.reaper.value,w.pool.benchmarking.value,w.pool.listenToProcessExits.value,w.logging.level.value,w.logging.file.value,w.logging.dest.value,w.ui.enable.value,w.ui.route.value,w.other.noLogo.value;const x=["options","globalOptions","themeOptions","resources","payload"],T={},k=(e,t="")=>{Object.keys(e).forEach((o=>{if(!["puppeteer","highcharts"].includes(o)){const r=e[o];void 0===r.value?k(r,`${t}.${o}`):T[r.cliName||o]=`${t}.${o}`.substring(1)}}))};k(w);let S={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:"red"},{title:"warning",color:"yellow"},{title:"notice",color:"blue"},{title:"verbose",color:"gray"}],listeners:[]};for(const[e,t]of Object.entries(w.logging))S[e]=t.value;const H=(...t)=>{const[o,...r]=t,{level:i,levelsDesc:n}=S;if(0===o||o>i||i>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[o-1].title}] -`;S.listeners.forEach((e=>{e(s,r.join(" "))})),S.toFile&&(S.pathCreated||(!e.existsSync(S.dest)&&e.mkdirSync(S.dest),S.pathCreated=!0),e.appendFile(`${S.dest}${S.file}`,[s].concat(r).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),S.toFile=!1)}))),S.toConsole&&console.log.apply(void 0,[s.toString()[S.levelsDesc[o-1].color]].concat(r))},E=p.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:v&&v.src||new URL("index.cjs",document.baseURI).href)),R=(e,t=/\s\s+/g,o=" ")=>e.replaceAll(t,o).trim(),L=(e,t)=>{const o=["png","jpeg","pdf","svg"];if(t){const r=t.split(".").pop();o.includes(r)&&e!==r&&(e=r)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||o.find((t=>t===e))||"png"},C=(t=!1,o)=>{const r=["js","css","files"];let i=t,n=!1;if(o&&t.endsWith(".json"))try{t?t&&t.endsWith(".json")?i=O(e.readFileSync(t,"utf8")):(i=O(t),!0===i&&(i=O(e.readFileSync("resources.json","utf8")))):i=O(e.readFileSync("resources.json","utf8"))}catch(e){return H(3,"[cli] No resources found.")}else i=O(t),o||delete i.files;for(const e in i)r.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):H(3,"[cli] No resources found.")};function O(e,t){try{const o=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof o&&t?JSON.stringify(o):o}catch(e){return!1}}const _=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=_(e[o]));return t},A=(e,t)=>JSON.stringify(e,((e,o)=>("string"==typeof o&&((o=o.trim()).startsWith("function(")||o.startsWith("function ("))&&o.endsWith("}")&&(o=t?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof o?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:o))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function $(){console.log("Usage of CLI arguments:".bold,"\n------",`\nFor more detailed information visit readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[o,r]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(r,"value")){let e=` --${r.cliName||o} ${("<"+r.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,r.description,`[Default: ${r.value.toString().bold}]`.blue)}else e(r)};Object.keys(w).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(w[t]))})),console.log("\n")}const I=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,j=(t,o)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!o&&j(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")};var P=(e,t)=>{const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const i=c({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(H(4,"[rate-limiting] Skipping rate limiter."),!0)});e.use(i),H(3,R(`[rate-limiting] Enabled rate limiting: ${r.max} requests\n per ${r.window} minute per IP, trusting proxy:\n ${r.trustProxy}.`))};async function N(e,t={}){return new Promise(((o,r)=>{const i=(e=>e.startsWith("https")?a:s)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}l.config();const F=t.join(E,".cache"),U={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let q=!1;const G=()=>U.hcVersion=U.sources.substr(0,U.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),W=async(e,t)=>{try{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),H(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},r=await N(`${e}.js`,o);if(200===r.statusCode)return r.text;throw`${r.statusCode}`}catch(t){throw H(1,`[cache] Error fetching script ${e}.js: ${t}.`),t}},M=async(t,o)=>{const{coreScripts:r,modules:i,indicators:n,scripts:s}=t,a="latest"!==t.version&&t.version?`${t.version}/`:"";H(3,"[cache] Updating cache to Highcharts ",a);const l=[...r.map((e=>`${a}${e}`)),...i.map((e=>"map"===e?`maps/${a}modules/${e}`:`${a}modules/${e}`)),...n.map((e=>`stock/${a}indicators/${e}`))];let c;const p=process.env.PROXY_SERVER_HOST,d=process.env.PROXY_SERVER_PORT;p&&d&&(c=new u({host:p,port:+d}));const h={};try{return U.sources=(await Promise.all([...l.map((async e=>{const o=await W(`${t.cdnURL||U.cdnURL}${e}`,c);return"string"==typeof o&&(h[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1),o})),...s.map((e=>W(e,c)))])).join(";\n"),G(),e.writeFileSync(o,U.sources),h}catch(e){H(1,"[cache] Unable to update local Highcharts cache.")}},D=async o=>{let r;const i=t.join(F,"manifest.json"),n=t.join(F,"sources.js");if(q=o,!e.existsSync(F)&&e.mkdirSync(F),!e.existsSync(i)||o.forceFetch)H(3,"[cache] Fetching and caching Highcharts dependencies."),r=await M(o,n);else{let t=!1;const s=JSON.parse(e.readFileSync(i));if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{modules:a,coreScripts:l,indicators:c}=o,p=a.length+l.length+c.length;s.version!==o.version?(H(3,"[cache] Highcharts version mismatch in cache, need to re-fetch."),t=!0):Object.keys(s.modules||{}).length!==p?(H(3,"[cache] Cache and requested modules does not match, need to re-fetch."),t=!0):t=(o.modules||[]).some((e=>{if(!s.modules[e])return H(3,`[cache] The ${e} missing in cache, need to re-fetch.`),!0})),t?r=await M(o,n):(H(3,"[cache] Dependency cache is up to date, proceeding."),U.sources=e.readFileSync(n,"utf8"),r=s.modules,G())}await(async(o,r)=>{const i={version:o.version,modules:r||{}};U.activeManifest=i,H(4,"[cache] writing new manifest");try{e.writeFileSync(t.join(F,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){H(1,`[cache] Error writing cache manifest: ${e}.`)}})(o,r)};var V=async e=>!!q&&await D(Object.assign(q,{version:e})),z=()=>U,J=()=>U.hcVersion;const K=m.randomBytes(64).toString("base64url"),X=f.join("tmp",`puppeteer-${K}`),B=[`--user-data-dir=${f.join(X,"profile")}`,"--autoplay-policy=user-gesture-required","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-client-side-phishing-detection","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=AudioServiceOutOfProcess","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-speech-api","--disable-sync","--hide-crash-restore-bubble","--hide-scrollbars","--ignore-gpu-blacklist","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-zygote","--password-store=basic","--use-mock-keychain"],Y=b.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:v&&v.src||new URL("index.cjs",document.baseURI).href)),Q=e.readFileSync(Y+"/../templates/template.html","utf8");let Z;const ee=async()=>{if(!Z)return!1;const e=await Z.newPage();return await e.setContent(Q),await e.addScriptTag({path:Y+"/../.cache/sources.js"}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{H(1,"[page error]",t),await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)})),e},te=async()=>{Z.connected&&await Z.close()};const oe=b.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:v&&v.src||new URL("index.cjs",document.baseURI).href)),re=async(e,t,o)=>await e.evaluate(((e,t)=>window.triggerExport(e,t)),t,o);var ie=async(o,r,i)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))};try{const a=()=>{};H(4,"[export] Determining export path.");const l=i.export;await o.evaluate((()=>requestAnimationFrame((()=>{}))));const c=l?.options?.chart?.displayErrors&&z().activeManifest.modules.debugger;await o.evaluate((e=>window._displayErrors=e),c);const p=()=>{};let u;if(r.indexOf&&(r.indexOf("=0||r.indexOf("=0)){if(H(4,"[export] Treating as SVG."),"svg"===l.type)return r;u=!0;const e=()=>{};await o.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(r)),e()}else if(H(4,"[export] Treating as config."),l.strInj){const e=()=>{};await re(o,{chart:{height:l.height,width:l.width}},i),e()}else{r.chart.height=l.height,r.chart.width=l.width;const e=()=>{};await re(o,r,i),e()}p();const d=()=>{},h=i.customCode.resources;if(h){if(h.js&&n.push(await o.addScriptTag({content:h.js})),h.files)for(const t of h.files)try{const r=!t.startsWith("http");n.push(await o.addScriptTag(r?{content:e.readFileSync(t,"utf8")}:{url:t}))}catch(e){H(4,"[export] JS file not found.")}const r=()=>{};if(h.css){let e=h.css.match(/@import\s*([^;]*);/g);if(e)for(let r of e)r&&(r=r.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),r.startsWith("http")?n.push(await o.addStyleTag({url:r})):i.customCode.allowFileResources&&n.push(await o.addStyleTag({path:t.join(oe,r)})));n.push(await o.addStyleTag({content:h.css.replace(/@import\s*([^;]*);/g,"")||" "}))}r()}d();const g=u?await o.$eval("#chart-container svg:first-of-type",(async(e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(l.scale)):await o.evaluate((async()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),f=()=>{},m=Math.ceil(g?.chartHeight||l.height),v=Math.ceil(g?.chartWidth||l.width);await o.setViewport({height:m,width:v,deviceScaleFactor:u?1:parseFloat(l.scale)});const y=u?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await o.evaluate(y,parseFloat(l.scale));const{height:b,width:w,x:x,y:T}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}})))(o);let k;u||await o.setViewport({width:Math.round(w),height:Math.round(b),deviceScaleFactor:parseFloat(l.scale)}),f();const S=()=>{};if("svg"===l.type)k=await(async e=>await e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(o);else if("png"===l.type||"jpeg"===l.type)k=await(async(e,t,o,r)=>await Promise.race([e.screenshot({type:t,encoding:o,clip:r,omitBackground:!0}),new Promise(((e,t)=>setTimeout((()=>t(new Error("Rasterization timeout"))),1500)))]))(o,l.type,"base64",{width:v,height:m,x:x,y:T});else{if("pdf"!==l.type)throw`Unsupported output format ${l.type}`;k=await(async(e,t,o,r)=>await e.pdf({height:t+1,width:o,encoding:r}))(o,m,v,"base64")}return await o.evaluate((()=>{const e=Highcharts.charts;if(e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()})),S(),a(),await s(o),k}catch(e){return await s(o),H(1,`[export] Error encountered during export: ${e}`),e}};let ne,se=0,ae=0,le=0,ce=0,pe=0,ue={},de=!1;const he={create:async()=>{const e=d.v4();let t=!1;const o=(new Date).getTime();try{if(t=await ee(),!t||t.isClosed())throw"invalid page";H(3,`[pool] Successfully created a worker ${e} - took ${(new Date).getTime()-o} ms.`)}catch(e){throw H(1,`[pool] Error creating a new page in pool entry creation! ${e}`),"Error creating page"}return{id:e,page:t,workCount:Math.round(Math.random()*(ue.workLimit/2))}},validate:e=>!(ue.workLimit&&++e.workCount>ue.workLimit)||(H(3,"[pool] Worker failed validation:",`exceeded work limit (limit is ${ue.workLimit})`),!1),destroy:e=>{H(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()},log:(e,t)=>console.log(`${t}: ${e}`)},ge=async e=>{ne=e.puppeteerArgs;try{await(async e=>{const t=[...B,...e||[]];if(!Z){let e=0;const o=async()=>{try{H(3,"[browser] attempting to get a browser instance (try",e+")"),Z=await g.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){H(0,"[browser]",t),++e<25?(H(3,"[browser] failed:",t),await new Promise((e=>setTimeout(e,4e3))),await o()):H(0,"Max retries reached")}};try{await o()}catch(e){return H(0,"[browser] Unable to open browser"),!1}if(!Z)return H(0,"[browser] Unable to open browser"),!1}return Z})(ne)}catch(e){H(0,"[pool|browser]",e)}if(ue=e&&e.pool?{...e.pool}:{},H(3,"[pool] Initializing pool:",`min ${ue.initialWorkers}, max ${ue.maxWorkers}.`),de)return H(4,"[pool] Already initialized, please kill it before creating a new one.");ue.listenToProcessExits&&(H(4,"[pool] Attaching exit listeners to the process."),process.on("exit",(async()=>{await fe()})),process.on("SIGINT",((e,t)=>{H(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{H(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{H(4,`The ${t} error, message: ${e.message}.`)})));try{de=new h.Pool({...he,min:ue.initialWorkers,max:ue.maxWorkers,createRetryIntervalMillis:200,createTimeoutMillis:ue.acquireTimeout,acquireTimeoutMillis:ue.acquireTimeout,destroyTimeoutMillis:ue.acquireTimeout,idleTimeoutMillis:ue.timeoutThreshold,reapIntervalMillis:1e3,propagateCreateError:!1}),de.on("createFail",((e,t)=>{H(1,`[pool] Error when creating worker of an event id ${e}:`,t)})),de.on("acquireFail",((e,t)=>{H(1,`[pool] Error when acquiring worker of an event id ${e}:`,t)})),de.on("destroyFail",((e,t,o)=>{H(1,`[pool] Error when destroying worker of an id ${t.id}, event id ${e}:`,o)})),de.on("release",(e=>{H(4,`[pool] Releasing a worker of an id ${e.id}`)})),de.on("destroySuccess",((e,t)=>{H(4,`[pool] Destroyed a worker of an id ${t.id}`)}));const e=[];for(let t=0;t{de.release(e)})),H(3,`[pool] The pool is ready with ${ue.initialWorkers} initial resources waiting.`)}catch(e){throw H(1,`[pool] Couldn't create the worker pool ${e}`),e}};async function fe(){return H(3,"[pool] Killing all workers."),de.destroyed?(await te(),!0):(await de.destroy(),await te(),!0)}const me=async(e,t)=>{let o;const r=e=>{throw++ce,o&&de.release(o),"In pool.postWork: "+e};if(H(4,"[pool] Work received, starting to process."),ue.benchmarking&&ve(),++ae,!de)return H(1,"[pool] Work received, but pool has not been started."),r("Pool is not inited but work was posted to it!");try{H(4,"[pool] Acquiring worker"),o=await de.acquire().promise}catch(e){return r(`[pool] Error when acquiring available entry: ${e}`)}if(H(4,"[pool] Acquired worker handle"),!o.page)return r("Resolved worker page is invalid: pool setup is wonky");try{let i=(new Date).getTime();H(4,`[pool] Starting work on pool entry ${o.id}.`);const n=await ie(o.page,e,t);if(n instanceof Error)return"Rasterization timeout"===n.message&&(o.page.close(),o.page=await ee()),r(n);de.release(o);const s=(new Date).getTime()-i;return le+=s,pe=le/++se,H(4,`[pool] Work completed in ${s} ms.`),{data:n,options:t}}catch(e){r(`Error trying to perform puppeteer export: ${e}.`)}};function ve(){const{min:e,max:t,size:o,available:r,borrowed:i,pending:n,spareResourceCapacity:s}=de;H(4,`[pool] The minimum number of resources allowed by pool: ${e}.`),H(4,`[pool] The maximum number of resources allowed by pool: ${t}.`),H(4,`[pool] The number of all resources in pool (free or in use): ${o}.`),H(4,`[pool] The number of resources that are currently available: ${r}.`),H(4,`[pool] The number of resources that are currently acquired: ${i}.`),H(4,`[pool] The number of callers waiting to acquire a resource: ${n}.`),H(4,`[pool] The number of how many more resources can the pool manage/create: ${s}.`)}var ye=()=>({min:de.min,max:de.max,size:de.size,available:de.available,borrowed:de.borrowed,pending:de.pending,spareResourceCapacity:de.spareResourceCapacity}),be=()=>ae,we=()=>ce,xe=()=>pe,Te=()=>se;const ke=process.env.npm_package_version,Se=new Date;let He={};const Ee=()=>He,Re=(e,t,o=[])=>{const r=_(e);for(const[e,n]of Object.entries(t))r[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||o.includes(e)||void 0===r[e]?void 0!==n?n:r[e]:Re(r[e],n,o);var i;return r};function Le(e,t={},o=""){Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r],n=t&&t[r];let s;void 0===i.value?Le(i,n,`${o}.${r}`):(void 0!==n&&(i.value=n),i.envLink&&("boolean"===i.type?i.value=I([process.env[i.envLink],i.value].find((e=>e||"false"===e))):"number"===i.type?(s=+process.env[i.envLink],i.value=s>=0?s:i.value):i.type.indexOf("]")>=0&&process.env[i.envLink]?i.value=process.env[i.envLink].split(","):i.value=process.env[i.envLink]||i.value))}}))}function Ce(e){let t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:Ce(r);return t}let Oe=!1;const _e=async(t,o)=>{H(4,"[chart] Starting exporting process.");const r=((e,t={})=>{let o={};return e.svg?(o=_(t),o.export.type=e.type||e.export.type,o.export.scale=e.scale||e.export.scale,o.export.outfile=e.outfile||e.export.outfile,o.payload={svg:e.svg}):o=Re(t,e,x),o.export.outfile=o.export?.outfile||`chart.${o.export?.type||"png"}`,o})(t,Ee()),i=r.export;return r.payload?.svg&&""!==r.payload.svg?je(r.payload.svg.trim(),r,o):i.infile&&i.infile.length?(H(4,"[chart] Attempting to export from an input file."),e.readFile(i.infile,"utf8",((e,t)=>e?H(1,`[chart] Error loading input file: ${e}.`):(r.export.instr=t,je(r.export.instr.trim(),r,o))))):i.instr&&""!==i.instr||i.options&&""!==i.options?(H(4,"[chart] Attempting to export from a raw input."),I(r.customCode?.allowCodeExecution)?Ie(r,o):"string"==typeof i.instr?je(i.instr.trim(),r,o):$e(r,i.instr||i.options,o)):(H(1,R(`[chart] No input specified.\n ${JSON.stringify(i,void 0," ")}.`)),o&&o(!1,{error:!0,message:"No input specified."}))},Ae=e=>{const{chart:t,exporting:o}=e.export?.options||O(e.export?.instr),r=O(e.export?.globalOptions);let i=e.export?.scale||o?.scale||r?.exporting?.scale||e.export?.defaultScale||1;return i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const o=Math.pow(10,t||0);return Math.round(+e*o)/o})(i,2),{height:e.export?.height||o?.sourceHeight||t?.height||r?.exporting?.sourceHeight||r?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||o?.sourceWidth||t?.width||r?.exporting?.sourceWidth||r?.chart?.width||e.export?.defaultWidth||600,scale:i}},$e=(t,o,r,i)=>{let{export:n,customCode:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:Oe;if(s){if("string"==typeof t.customCode.resources)t.customCode.resources=C(t.customCode.resources,I(t.customCode.allowFileResources));else if(!t.customCode.resources)try{const o=e.readFileSync("resources.json","utf8");t.customCode.resources=C(o,I(t.customCode.allowFileResources))}catch(e){H(3,"[chart] The default resources.json file not found.")}}else s=t.customCode={};if(!a&&s){if(s.callback||s.resources||s.customCode)return r&&r(!1,{error:!0,message:R("The callback, resources and customCode have been disabled for this\n server.")});s.callback=!1,s.resources=!1,s.customCode=!1}if(o&&(o.chart=o.chart||{},o.exporting=o.exporting||{},o.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=L(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{n&&n[t]&&("string"==typeof n[t]&&n[t].endsWith(".json")?n[t]=O(e.readFileSync(n[t],"utf8"),!0):n[t]=O(n[t],!0))}catch(e){n[t]={},H(1,`[chart] The ${t} not found.`)}})),s.allowCodeExecution&&(s.customCode=j(s.customCode,s.allowFileResources)),s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=e.readFileSync(s.callback,"utf8")}catch(e){H(2,`[chart] Error loading callback: ${e}.`),s.callback=!1}else s.callback=!1;t.export={...t.export,...Ae(t)},me(n.strInj||o||i,t).then((e=>r(e))).catch((e=>(H(0,"[chart] When posting work:",e),r(!1,e))))},Ie=(e,t)=>{try{let o,r=e.export.instr||e.export.options;return"string"!=typeof r&&(o=r=A(r,e.customCode?.allowCodeExecution)),o=r.replaceAll(/\t|\n|\r/g,"").trim(),";"===o[o.length-1]&&(o=o.substring(0,o.length-1)),e.export.strInj=o,$e(e,!1,t)}catch(o){const r=R(`Malformed input detected for ${e.export?.requestId||"?"}:\n Please make sure that your JSON/JavaScript options\n are sent using the "options" attribute, and that if you're using\n SVG, it is unescaped.`);return H(1,r),t&&t(!1,JSON.stringify({error:!0,message:r}))}},je=(e,t,o)=>{const{allowCodeExecution:r}=t.customCode;if(e.indexOf("=0||e.indexOf("=0)return H(4,"[chart] Parsing input as SVG."),$e(t,!1,o,e);try{const r=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return $e(t,r,o)}catch(e){return I(r)?Ie(t,o):o&&o(!1,{error:!0,message:R("Only JSON configurations and SVG is allowed for this server. If\n this is your server, JavaScript exporting can be enabled by starting\n the server with the --allowCodeExecution flag.")})}},Pe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Ne=0;const Fe=[],Ue=[],qe=(e,t,o,r)=>{let i=!0;const{id:n,uniqueId:s,type:a,body:l}=r;return e.some((e=>{if(e){let r=e(t,o,n,s,a,l);return void 0!==r&&!0!==r&&(i=r),!0}})),i},Ge=(e,t)=>{(()=>{const e=process.hrtime.bigint()})();const o=Ee(),r=e.body,i=++Ne,n=d.v4().replace(/-/g,"");let s=L(r.type);if(!r)return t.status(400).send(R("Body is required. Sending a body? Make sure your Content-type header\n is correct. Accepted is application/json and multipart/form-data."));let a=O(r.infile||r.options||r.data);if(!a&&!r.svg)return H(2,R(`Request ${n} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Check your payload.`)),t.status(400).send(R("No correct chart data found. Please make sure you are using\n application/json or multipart/form-data headers, and that the chart\n data is in the 'infile', 'options' or 'data' attribute if sending\n JSON or in the 'svg' if sending SVG."));let l=!1;if(l=qe(Fe,e,t,{id:i,uniqueId:n,type:s,body:r}),!0!==l)return t.send(l);let c=!1;e.socket.on("close",(()=>{c=!0})),H(4,`[export] Got an incoming HTTP request ${n}.`),r.constr="string"==typeof r.constr&&r.constr||"chart";const p={export:{instr:a,type:s,constr:r.constr[0].toLowerCase()+r.constr.substr(1),height:r.height,width:r.width,scale:r.scale||o.export.scale,globalOptions:O(r.globalOptions,!0),themeOptions:O(r.themeOptions,!0)},customCode:{allowCodeExecution:Oe,allowFileResources:!1,resources:O(r.resources,!0),callback:r.callback,customCode:r.customCode}};a&&(p.export.instr=A(a,p.customCode.allowCodeExecution));const u=Re(o,p);if(u.export.options=a,u.payload={svg:r.svg||!1,b64:r.b64||!1,dataOptions:O(r.dataOptions,!0),noDownload:r.noDownload||!1,requestId:n},r.svg&&(h=u.payload.svg,["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((e=>h.match(`xlink:href="(?:(http://|https://))?${e}`)))))return t.status(400).send("SVG potentially contain at least one forbidden URL in xlink:href element.");var h;_e(u,((o,a)=>(e.socket.removeAllListeners("close"),c?H(3,R("[export] The client closed the connection before the chart was done\n processing.")):a?(H(1,R(`[export] Work: ${n} could not be completed, sending:\n ${a}`)),t.status(400).send(a.message)):o&&o.data?(s=o.options.export.type,qe(Ue,e,t,{id:i,body:o.data}),o.data?r.b64?"pdf"===s?t.send(Buffer.from(o.data,"utf8").toString("base64")):t.send(o.data):(t.header("Content-Type",Pe[s]||"image/png"),r.noDownload||t.attachment(`${e.params.filename||"chart"}.${s||"png"}`),"svg"===s?t.send(o.data):t.send(Buffer.from(o.data,"base64"))):void 0):(H(1,R(`[export] Unexpected return from chart generation, please check your\n data Request: ${n} is ${o.data}.`)),t.status(400).send("Unexpected return from chart generation, please check your data.")))))};const We=i();We.disable("x-powered-by"),We.use(r());const Me=n.memoryStorage(),De=n({storage:Me,limits:{fieldsSize:"50MB"}});We.use(De.any()),We.use(o.json({limit:"50mb"})),We.use(o.urlencoded({extended:!0,limit:"50mb"})),We.use(o.urlencoded({extended:!1,limit:"50mb"}));const Ve=e=>H(1,`[server] Socket error: ${e}`),ze=e=>{e.on("clientError",Ve),e.on("error",Ve),e.on("connection",(e=>e.on("error",(e=>Ve(e)))))},Je=async o=>{if(!o.enable)return!1;if(!o.ssl.enable&&!o.ssl.force){const e=s.createServer(We);ze(e),e.listen(o.port,o.host),H(3,`[server] Started HTTP server on ${o.host}:${o.port}.`)}if(o.ssl.enable){let r,i;try{r=await e.promises.readFile(t.posix.join(o.ssl.certPath,"server.key"),"utf8"),i=await e.promises.readFile(t.posix.join(o.ssl.certPath,"server.crt"),"utf8")}catch(e){H(1,`[server] Unable to load key/certificate from ${o.ssl.certPath}.`)}if(r&&i){const e=a.createServer(We);ze(e),e.listen(o.ssl.port,o.host),H(3,`[server] Started HTTPS server on ${o.host}:${o.ssl.port}.`)}}o.rateLimiting&&o.rateLimiting.enable&&![0,NaN].includes(o.rateLimiting.maxRequests)&&P(We,o.rateLimiting),We.use(i.static(t.posix.join(E,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:Se,uptime:Math.floor(((new Date).getTime()-Se.getTime())/1e3/60)+" minutes",version:ke,highchartsVersion:J(),averageProcessingTime:xe(),performedExports:Te(),failedExports:we(),exportAttempts:be(),sucessRatio:Te()/be()*100,pool:ye()})}))})(We),(e=>{e.post("/",Ge),e.post("/:filename",Ge)})(We),(e=>{!!e&&e.get("/",((e,o)=>{o.sendFile(t.join(E,"public","index.html"))}))})(We),(e=>{!!e&&e.post("/change_hc_version/:newVersion",(async(e,t)=>{const o=process.env.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)return t.send({error:!0,message:"Server not configured to do run-time version changes: HIGHCHARTS_ADMIN_TOKEN not set"});const r=e.get("hc-auth");if(!r||r!==o)return t.send({error:!0,message:"Invalid or missing token: set token in the hc-auth header"});const i=e.params.newVersion;if(i){try{await V(i)}catch(e){t.send({error:!0,message:e})}t.send({version:J()})}else t.send({error:!0,message:"No new version supplied"})}))})(We)};var Ke={startServer:Je,getExpress:()=>i,getApp:()=>We,use:(e,...t)=>{We.use(e,...t)},get:(e,...t)=>{We.get(e,...t)},post:(e,...t)=>{We.post(e,...t)},enableRateLimiting:e=>P(We,e)},Xe={log:H,mapToNewConfig:e=>{const t={};for(const[o,r]of Object.entries(e)){const e=T[o]?T[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}return t},setOptions:(t,o)=>(o?.length&&(He=function(t){const o=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(o>-1&&t[o+1]){const r=t[o+1];try{if(r&&r.endsWith(".json"))return JSON.parse(e.readFileSync(r))}catch(e){H(1,`[config] Unable to load config from the ${r}: ${e}`)}}return{}}(o)),Le(w,He),He=Ce(w),t&&(He=Re(He,t,x)),o?.length&&(He=function(e,t,o){for(let o=0;o(i.length-1===a&&void 0!==n[s]&&(t[++o]?n[s]=t[o]||n[s]:(console.log(`Missing argument value for ${r}!`.red,"\n"),e=$())),n[s])),e)}return e}(He,o)),He),singleExport:t=>{t.export.instr=t.export.instr||t.export.options,_e(t,((t,o)=>{o&&(H(1,`[cli] ${o.message}`),process.exit(1));const{outfile:r,type:i}=t.options.export;e.writeFileSync(r||`chart.${i}`,"svg"!==i?Buffer.from(t.data,"base64"):t.data),fe()}))},startExport:_e,batchExport:t=>{const o=[];for(let r of t.export.batch.split(";"))r=r.split("="),2===r.length&&o.push(new Promise(((o,i)=>{_e({...t,export:{...t.export,infile:r[0],outfile:r[1]}},((t,r)=>{if(r)return i(r);e.writeFileSync(t.options.export.outfile,Buffer.from(t.data,"base64")),o()}))})));Promise.all(o).then((()=>{fe()})).catch((e=>{H(1,`[chart] Error encountered during batch export: ${e}`),fe()}))},server:Ke,startServer:Je,killPool:fe,initPool:async(e={})=>{var t,o;return t=e.customCode&&e.customCode.allowCodeExecution,Oe=I(t),(o=e.logging&&parseInt(e.logging.level))>=0&&o<=S.levelsDesc.length&&(S.level=o),e.logging&&e.logging.dest&&((e,t)=>{if(S={...S,dest:e||S.dest,file:t||S.file,toFile:!0},0===S.dest.length)return H(1,"[logger] File logging init: no path supplied.");S.dest.endsWith("/")||(S.dest+="/")})(e.logging.dest,e.logging.file||"highcharts-export-server.log"),await D(e.highcharts||{version:"latest"}),await ge({pool:e.pool||{initialWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer?.args||[]}),e}};module.exports=Xe; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3V0aWxzLmpzIiwiLi4vbGliL3NlcnZlci9yYXRlX2xpbWl0LmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2NhY2hlLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vbGliL2JlbmNobWFyay5qcyIsIi4uL3RlbXBsYXRlcy9zdmdfZXhwb3J0L3N2Z19leHBvcnQuanMiLCIuLi9saWIvcG9vbC5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2hlYWx0aC5qcyIsIi4uL2xpYi9jb25maWcuanMiLCIuLi9saWIvY2hhcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3VpLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMiLCIuLi9saWIvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xuXG5kb3RlbnYuY29uZmlnKCk7XG5cbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxuLy8gYWxzbyBmcm9tIHRoZSAuZW52IGZpbGUgaWYgb25lIGV4aXN0c1xuZXhwb3J0IGNvbnN0IGRlZmF1bHRDb25maWcgPSB7XG4gIHB1cHBldGVlcjoge1xuICAgIGFyZ3M6IHtcbiAgICAgIHZhbHVlOiBbXSxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0FycmF5IG9mIGFyZ3VtZW50cyB0byBzZW5kIHRvIHB1cHBldGVlci4nXG4gICAgfVxuICB9LFxuICBoaWdoY2hhcnRzOiB7XG4gICAgdmVyc2lvbjoge1xuICAgICAgdmFsdWU6ICdsYXRlc3QnLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfVkVSU0lPTicsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIHVzZS4nXG4gICAgfSxcbiAgICBjZG5VUkw6IHtcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE4nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBDRE4gVVJMIG9mIEhpZ2hjaGFydHMgc2NyaXB0cyB0byB1c2UuJ1xuICAgIH0sXG4gICAgY29yZVNjcmlwdHM6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXG4gICAgICB2YWx1ZTogWydoaWdoY2hhcnRzJywgJ2hpZ2hjaGFydHMtbW9yZScsICdoaWdoY2hhcnRzLTNkJ10sXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC4nXG4gICAgfSxcbiAgICBtb2R1bGVzOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVTJyxcbiAgICAgIHZhbHVlOiBbXG4gICAgICAgICdzdG9jaycsXG4gICAgICAgICdtYXAnLFxuICAgICAgICAnZ2FudHQnLFxuICAgICAgICAnZXhwb3J0aW5nJyxcbiAgICAgICAgJ2V4cG9ydC1kYXRhJyxcbiAgICAgICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcbiAgICAgICAgJ2FjY2Vzc2liaWxpdHknLFxuICAgICAgICAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxuICAgICAgICAnYm9vc3QtY2FudmFzJyxcbiAgICAgICAgJ2Jvb3N0JyxcbiAgICAgICAgJ2RhdGEnLFxuICAgICAgICAnZHJhZ2dhYmxlLXBvaW50cycsXG4gICAgICAgICdzdGF0aWMtc2NhbGUnLFxuICAgICAgICAnYnJva2VuLWF4aXMnLFxuICAgICAgICAnaGVhdG1hcCcsXG4gICAgICAgICd0aWxlbWFwJyxcbiAgICAgICAgJ3RpbWVsaW5lJyxcbiAgICAgICAgJ3RyZWVtYXAnLFxuICAgICAgICAnaXRlbS1zZXJpZXMnLFxuICAgICAgICAnZHJpbGxkb3duJyxcbiAgICAgICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxuICAgICAgICAnYnVsbGV0JyxcbiAgICAgICAgJ2Z1bm5lbCcsXG4gICAgICAgICdmdW5uZWwzZCcsXG4gICAgICAgICdweXJhbWlkM2QnLFxuICAgICAgICAnbmV0d29ya2dyYXBoJyxcbiAgICAgICAgJ3BhcmV0bycsXG4gICAgICAgICdwYXR0ZXJuLWZpbGwnLFxuICAgICAgICAncGljdG9yaWFsJyxcbiAgICAgICAgJ3ByaWNlLWluZGljYXRvcicsXG4gICAgICAgICdzYW5rZXknLFxuICAgICAgICAnYXJjLWRpYWdyYW0nLFxuICAgICAgICAnZGVwZW5kZW5jeS13aGVlbCcsXG4gICAgICAgICdzZXJpZXMtbGFiZWwnLFxuICAgICAgICAnc29saWQtZ2F1Z2UnLFxuICAgICAgICAnc29uaWZpY2F0aW9uJyxcbiAgICAgICAgJ3N0b2NrLXRvb2xzJyxcbiAgICAgICAgJ3N0cmVhbWdyYXBoJyxcbiAgICAgICAgJ3N1bmJ1cnN0JyxcbiAgICAgICAgJ3ZhcmlhYmxlLXBpZScsXG4gICAgICAgICd2YXJpd2lkZScsXG4gICAgICAgICd2ZWN0b3InLFxuICAgICAgICAndmVubicsXG4gICAgICAgICd3aW5kYmFyYicsXG4gICAgICAgICd3b3JkY2xvdWQnLFxuICAgICAgICAneHJhbmdlJyxcbiAgICAgICAgJ25vLWRhdGEtdG8tZGlzcGxheScsXG4gICAgICAgICdkcmFnLXBhbmVzJyxcbiAgICAgICAgJ2RlYnVnZ2VyJyxcbiAgICAgICAgJ2R1bWJiZWxsJyxcbiAgICAgICAgJ2xvbGxpcG9wJyxcbiAgICAgICAgJ2N5bGluZGVyJyxcbiAgICAgICAgJ29yZ2FuaXphdGlvbicsXG4gICAgICAgICdkb3RwbG90JyxcbiAgICAgICAgJ21hcmtlci1jbHVzdGVycycsXG4gICAgICAgICdob2xsb3djYW5kbGVzdGljaycsXG4gICAgICAgICdoZWlraW5hc2hpJ1xuICAgICAgXSxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC4nXG4gICAgfSxcbiAgICBpbmRpY2F0b3JzOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19JTkRJQ0FUT1JTJyxcbiAgICAgIHZhbHVlOiBbJ2luZGljYXRvcnMtYWxsJ10sXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIGluZGljYXRvcnMgdG8gZmV0Y2guJ1xuICAgIH0sXG4gICAgc2NyaXB0czoge1xuICAgICAgdmFsdWU6IFtcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjM0L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xuICAgICAgXSxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0FkZGl0aW9uYWwgZGlyZWN0IHNjcmlwdHMvb3B0aW9uYWwgZGVwZW5kZW5jaWVzIChlLmcuIG1vbWVudC5qcykuJ1xuICAgIH0sXG4gICAgZm9yY2VGZXRjaDoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfRk9SQ0VfRkVUQ0gnLFxuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdTaG91bGQgYWxsIHRoZSBzY3JpcHRzIGJlIHJlZmV0Y2hlZCBhZnRlciByZXJ1bm5pbmcgdGhlIHNlcnZlci4nXG4gICAgfVxuICB9LFxuICBleHBvcnQ6IHtcbiAgICBpbmZpbGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgaW5wdXQgZmlsZSBuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IGNhbiBiZSBhIGNvcnJlY3QgSlNPTiBvciBTVkcgZmlsZS4nXG4gICAgfSxcbiAgICBpbnN0cjoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0FuIGlucHV0IGluIGEgZm9ybSBvZiBhIHN0cmluZ2lmaWVkIEpTT04gb3IgU1ZHIGZpbGUuIE92ZXJyaWRlcyB0aGUgLS1pbmZpbGUuJ1xuICAgIH0sXG4gICAgb3B0aW9uczoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjogJ0FuIGFsaWFzIGZvciB0aGUgLS1pbnN0ciBvcHRpb24uJ1xuICAgIH0sXG4gICAgb3V0ZmlsZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBvdXRwdXQgZmlsZW5hbWUgYWxvbmcgd2l0aCBhIHR5cGUgKGpwZWcsIHBuZywgcGRmIG9yIHN2ZykuIElnbm9yZXMgdGhlIC0tdHlwZSBmbGFnLidcbiAgICB9LFxuICAgIHR5cGU6IHtcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9UWVBFJyxcbiAgICAgIHZhbHVlOiAncG5nJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZm9ybWF0IG9mIHRoZSBmaWxlIHRvIGV4cG9ydCB0by4gQ2FuIGJlIGpwZWcsIHBuZywgcGRmIG9yIHN2Zy4nXG4gICAgfSxcbiAgICBjb25zdHI6IHtcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9DT05TVFInLFxuICAgICAgdmFsdWU6ICdjaGFydCcsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCBvciBnYW50dENoYXJ0LidcbiAgICB9LFxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxuICAgICAgdmFsdWU6IDQwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm90IGZvdW5kIGFueSB2YWx1ZSBzZXQuJ1xuICAgIH0sXG4gICAgZGVmYXVsdFdpZHRoOiB7XG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfV0lEVEgnLFxuICAgICAgdmFsdWU6IDYwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBub3QgZm91bmQgYW55IHZhbHVlIHNldC4nXG4gICAgfSxcbiAgICBkZWZhdWx0U2NhbGU6IHtcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXG4gICAgICB2YWx1ZTogMSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFJhbmdlcyBiZXR3ZWVuIDEgYW5kIDUuJ1xuICAgIH0sXG4gICAgaGVpZ2h0OiB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGRlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydC4gT3ZlcnJpZGVzIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcbiAgICB9LFxuICAgIHdpZHRoOiB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydC4gT3ZlcnJpZGVzIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcbiAgICB9LFxuICAgIHNjYWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydC4gUmFuZ2VzIGJldHdlZW4gMSBhbmQgNS4nXG4gICAgfSxcbiAgICBnbG9iYWxPcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgd2l0aCBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xuICAgIH0sXG4gICAgdGhlbWVPcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xuICAgIH0sXG4gICAgYmF0Y2g6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdTdGFydHMgYSBiYXRjaCBqb2IuIEEgc3RyaW5nIHRoYXQgY29udGFpbnMgaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li5cIi4nXG4gICAgfVxuICB9LFxuICBjdXN0b21Db2RlOiB7XG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19BTExPV19DT0RFX0VYRUNVVElPTicsXG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0lmIHNldCB0byB0cnVlLCBhbGxvdyBmb3IgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSB3aGVuIGV4cG9ydGluZy4nXG4gICAgfSxcbiAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBbGxvdyBpbmplY3RpbmcgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIEhhcyBubyBlZmZlY3Qgd2hlbiBydW5uaW5nIGFzIGEgc2VydmVyLidcbiAgICB9LFxuICAgIGN1c3RvbUNvZGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIENhbiBiZSBhIGZpbGVuYW1lIHdpdGggdGhlIGpzIGV4dGVuc2lvbi4nXG4gICAgfSxcbiAgICBjYWxsYmFjazoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjogJ0EgSmF2YVNjcmlwdCBmaWxlIHdpdGggYSBmdW5jdGlvbiB0byBydW4gb24gY29uc3RydWN0aW9uLidcbiAgICB9LFxuICAgIHJlc291cmNlczoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0FuIGFkZGl0aW9uYWwgcmVzb3VyY2UgaW4gYSBmb3JtIG9mIHN0cmluZ2lmaWVkIEpTT04uIEl0IGNhbiBjb250YWluIGZpbGVzLCBqcyBhbmQgY3NzIHNlY3Rpb25zLidcbiAgICB9LFxuICAgIGxvYWRDb25maWc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgdGhhdCBjb250YWlucyBhIHByZS1kZWZpbmVkIGNvbmZpZyB0byB1c2UuJ1xuICAgIH0sXG4gICAgY3JlYXRlQ29uZmlnOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQWxsb3dzIHRvIHNldCBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmUgaW4gYSBwcm92aWRlZCBjb25maWcgZmlsZS4nXG4gICAgfVxuICB9LFxuICBzZXJ2ZXI6IHtcbiAgICBlbmFibGU6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1NFUlZFUl9FTkFCTEUnLFxuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXG4gICAgICBkZXNjcmlwdGlvbjogJ0lmIHNldCB0byB0cnVlLCBzdGFydHMgYSBzZXJ2ZXIgb24gMC4wLjAuMC4nXG4gICAgfSxcbiAgICBob3N0OiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19TRVJWRVJfSE9TVCcsXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBob3N0bmFtZSBvZiB0aGUgc2VydmVyLiBBbHNvIHN0YXJ0cyBhIHNlcnZlciBsaXN0ZW5pbmcgb24gdGhlIHN1cHBsaWVkIGhvc3RuYW1lLidcbiAgICB9LFxuICAgIHBvcnQ6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1NFUlZFUl9QT1JUJyxcbiAgICAgIHZhbHVlOiA3ODAxLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IHRvIHVzZSBmb3IgdGhlIHNlcnZlci4gRGVmYXVsdHMgdG8gNzgwMS4nXG4gICAgfSxcbiAgICBzc2w6IHtcbiAgICAgIGVuYWJsZToge1xuICAgICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19TRVJWRVJfU1NMX0VOQUJMRScsXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIHRoZSBTU0wgcHJvdG9jb2wuJ1xuICAgICAgfSxcbiAgICAgIGZvcmNlOiB7XG4gICAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1NFUlZFUl9TU0xfRk9SQ0UnLFxuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlZCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdJZiBzZXQgdG8gdHJ1ZSwgZm9yY2VzIHRoZSBzZXJ2ZXIgdG8gb25seSBzZXJ2ZSBvdmVyIEhUVFBTLidcbiAgICAgIH0sXG4gICAgICBwb3J0OiB7XG4gICAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1NFUlZFUl9TU0xfUE9SVCcsXG4gICAgICAgIHZhbHVlOiA0NDMsXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcbiAgICAgIH0sXG4gICAgICBjZXJ0UGF0aDoge1xuICAgICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19TU0xfQ0VSVF9QQVRIJyxcbiAgICAgICAgdmFsdWU6ICcnLFxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleS4nXG4gICAgICB9XG4gICAgfSxcbiAgICByYXRlTGltaXRpbmc6IHtcbiAgICAgIGVuYWJsZToge1xuICAgICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19SQVRFX0xJTUlUX0VOQUJMRScsXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIHJhdGUgbGltaXRpbmcuJ1xuICAgICAgfSxcbiAgICAgIG1heFJlcXVlc3RzOiB7XG4gICAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1JBVEVfTElNSVRfTUFYJyxcbiAgICAgICAgdmFsdWU6IDEwLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdNYXggcmVxdWVzdHMgYWxsb3dlZCBpbiBhIG9uZSBtaW51dGUuJ1xuICAgICAgfSxcbiAgICAgIHdpbmRvdzoge1xuICAgICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19SQVRFX0xJTUlUX1dJTkRPVycsXG4gICAgICAgIHZhbHVlOiAxLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3cgaW4gbWludXRlcyBmb3IgcmF0ZSBsaW1pdGluZy4nXG4gICAgICB9LFxuICAgICAgZGVsYXk6IHtcbiAgICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfUkFURV9MSU1JVF9ERUxBWScsXG4gICAgICAgIHZhbHVlOiAwLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgJ1RoZSBhbW91bnQgdG8gZGVsYXkgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIGhpdHRpbmcgdGhlIG1heC4nXG4gICAgICB9LFxuICAgICAgdHJ1c3RQcm94eToge1xuICAgICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19SQVRFX0xJTUlUX1RSVVNUX1BST1hZJyxcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRoaXMgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyLidcbiAgICAgIH0sXG4gICAgICBza2lwS2V5OiB7XG4gICAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1JBVEVfTElNSVRfU0tJUF9LRVknLFxuICAgICAgICB2YWx1ZTogJycsXG4gICAgICAgIHR5cGU6ICdudW1iZXJ8c3RyaW5nJyxcbiAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggc2tpcFRva2VuIGFyZ3VtZW50LidcbiAgICAgIH0sXG4gICAgICBza2lwVG9rZW46IHtcbiAgICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfUkFURV9MSU1JVF9TS0lQX1RPS0VOJyxcbiAgICAgICAgdmFsdWU6ICcnLFxuICAgICAgICB0eXBlOiAnbnVtYmVyfHN0cmluZycsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHNraXBLZXkgYXJndW1lbnQuJ1xuICAgICAgfVxuICAgIH1cbiAgfSxcbiAgcG9vbDoge1xuICAgIGluaXRpYWxXb3JrZXJzOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19QT09MX01JTl9XT1JLRVJTJyxcbiAgICAgIHZhbHVlOiA0LFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgaW5pdGlhbCB3b3JrZXJzIHRvIHNwYXduLidcbiAgICB9LFxuICAgIG1heFdvcmtlcnM6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1BPT0xfTUFYX1dPUktFUlMnLFxuICAgICAgdmFsdWU6IDgsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXggd29ya2VycyB0byBzcGF3bi4nXG4gICAgfSxcbiAgICB3b3JrTGltaXQ6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1BPT0xfV09SS19MSU1JVCcsXG4gICAgICB2YWx1ZTogNDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIHBpZWNlcyBvZiB3b3JrIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBiZWZvcmUgcmVzdGFydGluZyBwcm9jZXNzLidcbiAgICB9LFxuICAgIHF1ZXVlU2l6ZToge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfUE9PTF9RVUVVRV9TSVpFJyxcbiAgICAgIHZhbHVlOiA1LFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBzaXplIG9mIHRoZSByZXF1ZXN0IG92ZXJmbG93IHF1ZXVlLidcbiAgICB9LFxuICAgIHRpbWVvdXRUaHJlc2hvbGQ6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1BPT0xfVElNRU9VVCcsXG4gICAgICB2YWx1ZTogNTAwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBiZWZvcmUgdGltaW5nIG91dC4nXG4gICAgfSxcbiAgICBhY3F1aXJlVGltZW91dDoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfUE9PTF9BQ1FVSVJFX1RJTUVPVVQnLFxuICAgICAgdmFsdWU6IDUwMDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xuICAgIH0sXG4gICAgcmVhcGVyOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19QT09MX0VOQUJMRV9SRUFQRVInLFxuICAgICAgdmFsdWU6IHRydWUsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIGV2aWN0IHdvcmtlcnMgYWZ0ZXIgYSBjZXJ0YWluIHRpbWUgcGVyaW9kLidcbiAgICB9LFxuICAgIGJlbmNobWFya2luZzoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfUE9PTF9CRU5DSE1BUktJTkcnLFxuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGUgYmVuY2htYXJraW5nLidcbiAgICB9LFxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19QT09MX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTJyxcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdTZXQgdG8gZmFsc2UgaW4gb3JkZXIgdG8gc2tpcCBhdHRhY2hpbmcgcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcbiAgICB9XG4gIH0sXG4gIGxvZ2dpbmc6IHtcbiAgICBsZXZlbDoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTE9HX0xFVkVMJyxcbiAgICAgIHZhbHVlOiA0LFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UpLidcbiAgICB9LFxuICAgIGZpbGU6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0xPR19GSUxFJyxcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGNsaU5hbWU6ICdsb2dGaWxlJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQSBuYW1lIG9mIGEgbG9nIGZpbGUuIFRoZSAtLWxvZ0Rlc3QgYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXG4gICAgfSxcbiAgICBkZXN0OiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19MT0dfREVTVCcsXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gQWxzbyBlbmFibGVzIGZpbGUgbG9nZ2luZy4nXG4gICAgfVxuICB9LFxuICB1aToge1xuICAgIGVuYWJsZToge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfVUlfRU5BQkxFJyxcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVVaScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgdGhlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlci4nXG4gICAgfSxcbiAgICByb3V0ZToge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfVUlfUk9VVEUnLFxuICAgICAgdmFsdWU6ICcvJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgcm91dGUgdG8gYXR0YWNoIHRoZSBVSSB0by4nXG4gICAgfVxuICB9LFxuICBvdGhlcjoge1xuICAgIG5vTG9nbzoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTk9fTE9HTycsXG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xuICAgIH1cbiAgfSxcbiAgcGF5bG9hZDoge31cbn07XG5cbi8vIFRoZSBjb25maWcgZGVzY3JpcHRpb25zIG9iamVjdCBmb3IgdGhlIHByb21wdHMgZnVuY3Rpb25hbGl0eS4gSXQgY29udGFpbnNcbi8vIGluZm9ybWF0aW9uIGxpa2U6XG4vLyAqIFR5cGUgb2YgYSBwcm9tcHRcbi8vICogTmFtZSBvZiBhbiBvcHRpb25cbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXG4vLyAqIEluaXRpYWwgdmFsdWVcbmV4cG9ydCBjb25zdCBwcm9tcHRzQ29uZmlnID0ge1xuICBwdXBwZXRlZXI6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnbGlzdCcsXG4gICAgICBuYW1lOiAnYXJncycsXG4gICAgICBtZXNzYWdlOiAnUHVwcGV0ZWVyIGFyZ3VtZW50cycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnB1cHBldGVlci5hcmdzLnZhbHVlLmpvaW4oJywnKSxcbiAgICAgIHNlcGFyYXRvcjogJywnXG4gICAgfVxuICBdLFxuICBoaWdoY2hhcnRzOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxuICAgICAgbWVzc2FnZTogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMudmVyc2lvbi52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2NkblVSTCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHVybCBvZiBDRE4nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNkblVSTC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcbiAgICAgIG5hbWU6ICdtb2R1bGVzJyxcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlcycsXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLm1vZHVsZXMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdsaXN0JyxcbiAgICAgIG5hbWU6ICdzY3JpcHRzJyxcbiAgICAgIG1lc3NhZ2U6ICdDdXN0b20gc2NyaXB0cycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuc2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZm9yY2VGZXRjaCcsXG4gICAgICBtZXNzYWdlOiAnU2hvdWxkIHJlZmV0Y2ggYWxsIHRoZSBzY3JpcHRzIGFmdGVyIGVhY2ggc2VydmVyIHJlcnVuJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5mb3JjZUZldGNoLnZhbHVlXG4gICAgfVxuICBdLFxuICBleHBvcnQ6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnc2VsZWN0JyxcbiAgICAgIG5hbWU6ICd0eXBlJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCB0eXBlIG9mIGEgZmlsZSB0byBleHBvcnQgdG8nLFxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQudHlwZS52YWx1ZX1gLFxuICAgICAgaW5pdGlhbDogMCxcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnc2VsZWN0JyxcbiAgICAgIG5hbWU6ICdjb25zdHInLFxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGNvbnN0cnVjdG9yIGZvciBIaWdoY2hhcnRzIHRvIHVzZScsXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC5jb25zdHIudmFsdWV9YCxcbiAgICAgIGluaXRpYWw6IDAsXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdkZWZhdWx0SGVpZ2h0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2RlZmF1bHRXaWR0aCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnZGVmYXVsdFNjYWxlJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxuICAgICAgbWluOiAwLjEsXG4gICAgICBtYXg6IDVcbiAgICB9XG4gIF0sXG4gIGN1c3RvbUNvZGU6IFtcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdhbGxvd0NvZGVFeGVjdXRpb24nLFxuICAgICAgbWVzc2FnZTogJ0FsbG93IHRvIGV4ZWN1dGUgY3VzdG9tIGNvZGUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Db2RlLmFsbG93Q29kZUV4ZWN1dGlvbi52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcbiAgICAgIG1lc3NhZ2U6ICdBbGxvdyBmaWxlIHJlc291cmNlcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUNvZGUuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXG4gICAgfVxuICBdLFxuICBzZXJ2ZXI6IFtcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxuICAgICAgbWVzc2FnZTogJ1N0YXJ0cyBhIHNlcnZlciBvbiAwLjAuMC4wJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2hvc3QnLFxuICAgICAgbWVzc2FnZTogJ0EgaG9zdG5hbWUgb2YgYSBzZXJ2ZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuaG9zdC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncG9ydCcsXG4gICAgICBtZXNzYWdlOiAnQSBwb3J0IG9mIGEgc2VydmVyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnBvcnQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3NzbC5lbmFibGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnc3NsLmZvcmNlJyxcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSB0byBvbmx5IHNlcnZlIG92ZXIgSFRUUFMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmZvcmNlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXG4gICAgICBtZXNzYWdlOiAnUG9ydCBvbiB3aGljaCB0byBydW4gdGhlIFNTTCBzZXJ2ZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLnBvcnQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdzc2wuY2VydFBhdGgnLFxuICAgICAgbWVzc2FnZTogJ0EgcGF0aCB3aGVyZSB0byBmaW5kIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5jZXJ0UGF0aC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmVuYWJsZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzJyxcbiAgICAgIG1lc3NhZ2U6ICdNYXggcmVxdWVzdHMgYWxsb3dlZCBpbiBhIG9uZSBtaW51dGUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcud2luZG93JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZSB3aW5kb3cgaW4gbWludXRlcyBmb3IgcmF0ZSBsaW1pdGluZycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcud2luZG93LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ1RoZSBhbW91bnQgdG8gZGVsYXkgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIGhpdHRpbmcgdGhlIG1heCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZGVsYXkudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy50cnVzdFByb3h5JyxcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdGhpcyB0byB0cnVlIGlmIGJlaGluZCBhIGxvYWQgYmFsYW5jZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcEtleScsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCBza2lwVG9rZW4gYXJndW1lbnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcFRva2VuJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHNraXBLZXkgYXJndW1lbnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxuICAgIH1cbiAgXSxcbiAgcG9vbDogW1xuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2luaXRpYWxXb3JrZXJzJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIGluaXRpYWwgd29ya2VycyB0byBzcGF3bicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuaW5pdGlhbFdvcmtlcnMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ21heFdvcmtlcnMnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWF4IHdvcmtlcnMgdG8gc3Bhd24nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1heFdvcmtlcnMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIHBpZWNlcyBvZiB3b3JrIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBiZWZvcmUgcmVzdGFydGluZyBhIHB1cHBldGVlciBwcm9jZXNzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3F1ZXVlU2l6ZScsXG4gICAgICBtZXNzYWdlOiAnVGhlIHNpemUgb2YgdGhlIHJlcXVlc3Qgb3ZlcmZsb3cgcXVldWUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnF1ZXVlU2l6ZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAndGltZW91dFRocmVzaG9sZCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBzZWNvbmRzIGJlZm9yZSB0aW1pbmcgb3V0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC50aW1lb3V0VGhyZXNob2xkLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdhY3F1aXJlVGltZW91dCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmFjcXVpcmVUaW1lb3V0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdyZWFwZXInLFxuICAgICAgbWVzc2FnZTogJ1RoZSByZWFwZXIgdG8gcmVtb3ZlIGhhbmdpbmcgcHJvY2Vzc2VzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5yZWFwZXIudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXG4gICAgICBtZXNzYWdlOiAnU2V0IGJlbmNobWFya2luZycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub1Byb2Nlc3NFeGl0cycsXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIGluIG9yZGVyIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcbiAgICB9XG4gIF0sXG4gIGxvZ2dpbmc6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdsZXZlbCcsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIGxvZyBsZXZlbCAoMDogc2lsZW50LCAxOiBlcnJvciwgMjogd2FybmluZywgMzogbm90aWNlLCA0OiB2ZXJib3NlKScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXG4gICAgICByb3VuZDogMCxcbiAgICAgIG1pbjogMCxcbiAgICAgIG1heDogNFxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2ZpbGUnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ0EgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgLS1sb2dEZXN0IGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmZpbGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdkZXN0JyxcbiAgICAgIG1lc3NhZ2U6ICdBIHBhdGggdG8gbG9nIGZpbGVzLiBJdCBlbmFibGVzIGZpbGUgbG9nZ2luZycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxuICAgIH1cbiAgXSxcbiAgdWk6IFtcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5lbmFibGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdyb3V0ZScsXG4gICAgICBtZXNzYWdlOiAnQSByb3V0ZSB0byBhdHRhY2ggdGhlIFVJIHRvJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkucm91dGUudmFsdWVcbiAgICB9XG4gIF0sXG4gIG90aGVyOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIGEgc3RhcnR1cC4gV2lsbCBiZSByZXBsYWNlZCBieSBhIHNpbXBsZSB0ZXh0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubm9Mb2dvLnZhbHVlXG4gICAgfVxuICBdXG59O1xuXG4vLyBBYnNvbHV0ZSBwcm9wcyB0aGF0LCBpbiBjYXNlIG9mIG1lcmdpbmcgcmVjdXJzaXZlbHksIG5lZWQgdG8gYmUgZm9yY2UgbWVyZ2VkXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcbiAgJ29wdGlvbnMnLFxuICAnZ2xvYmFsT3B0aW9ucycsXG4gICd0aGVtZU9wdGlvbnMnLFxuICAncmVzb3VyY2VzJyxcbiAgJ3BheWxvYWQnXG5dO1xuXG4vLyBBcmd1bWVudCBuZXN0aW5nIGxldmVsIG9mIGFsbCBleHBvcnQgc2VydmVyIG9wdGlvbnNcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XG5cbi8qKlxuICogQ3JlYXRlcyBuZXN0ZWQgYXJndW1lbnRzIGNoYWluIGZvciBhbGwgb3B0aW9uc1xuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGJhc2VkIG9uIHdoaWNoIHRoZSBpbml0aWFsIGNvbmZpZ3VyYXRpb24gYmVcbiAqIG1hZGUuXG4gKiBAcGFyYW0ge3N0cmluZyB9IHByb3BDaGFpbiAtIFJlcXVpcmVkIGZvciBjcmVhdGluZyBhIHN0cmluZyBjaGFpbiBvZlxuICogcHJvcGVydGllcyBmb3IgbmVzdGVkIGFyZ3VtZW50cy5cbiAqL1xuY29uc3QgY3JlYXRlTmVzdGVkQXJncyA9IChvYmosIHByb3BDaGFpbiA9ICcnKSA9PiB7XG4gIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaCgoaykgPT4ge1xuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XG4gICAgICBjb25zdCBlbnRyeSA9IG9ialtrXTtcbiAgICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xuICAgICAgICBjcmVhdGVOZXN0ZWRBcmdzKGVudHJ5LCBgJHtwcm9wQ2hhaW59LiR7a31gKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xuICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmNsaU5hbWUgfHwga10gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufTtcblxuY3JlYXRlTmVzdGVkQXJncyhkZWZhdWx0Q29uZmlnKTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XG5cbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcblxuLy8gVGhlIGRlZmF1bHQgbG9nZ2luZyBjb25maWdcbmxldCBsb2dnaW5nID0ge1xuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcbiAgdG9Db25zb2xlOiB0cnVlLFxuICB0b0ZpbGU6IGZhbHNlLFxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXG4gIC8vIExvZyBsZXZlbHNcbiAgbGV2ZWxzRGVzYzogW1xuICAgIHtcbiAgICAgIHRpdGxlOiAnZXJyb3InLFxuICAgICAgY29sb3I6ICdyZWQnXG4gICAgfSxcbiAgICB7XG4gICAgICB0aXRsZTogJ3dhcm5pbmcnLFxuICAgICAgY29sb3I6ICd5ZWxsb3cnXG4gICAgfSxcbiAgICB7XG4gICAgICB0aXRsZTogJ25vdGljZScsXG4gICAgICBjb2xvcjogJ2JsdWUnXG4gICAgfSxcbiAgICB7XG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxuICAgICAgY29sb3I6ICdncmF5J1xuICAgIH1cbiAgXSxcbiAgLy8gTG9nIGxpc3RlbmVyc1xuICBsaXN0ZW5lcnM6IFtdXG59O1xuXG4vLyBHYXRoZXIgaW5pdCBsb2dnaW5nIG9wdGlvbnNcbmZvciAoY29uc3QgW2tleSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhkZWZhdWx0Q29uZmlnLmxvZ2dpbmcpKSB7XG4gIGxvZ2dpbmdba2V5XSA9IG9wdGlvbi52YWx1ZTtcbn1cblxuLyoqXG4gKiBMb2dzIGEgbWVzc2FnZS4gQWNjZXB0cyBhIHZhcmlhYmxlIGFtb3VudCBvZiBhcmd1bWVudHMuIEFyZ3VtZW50cyBhZnRlclxuICogYGxldmVsYCB3aWxsIGJlIHBhc3NlZCBkaXJlY3RseSB0byBjb25zb2xlLmxvZywgYW5kL29yIHdpbGwgYmUgam9pbmVkXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxuICpcbiAqIEBwYXJhbSB7YW55fSBhcmdzIC0gQW4gYXJyYXkgb2YgYXJndW1lbnRzIHdoZXJlIHRoZSBmaXJzdCBpcyB0aGUgbG9nIGxldmVsXG4gKiBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXG4gKi9cbmV4cG9ydCBjb25zdCBsb2cgPSAoLi4uYXJncykgPT4ge1xuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XG5cbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcblxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZVxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcblxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xuXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XG4gIH0pO1xuXG4gIC8vIExvZyB0byBmaWxlXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xuICAgIGlmICghbG9nZ2luZy5wYXRoQ3JlYXRlZCkge1xuICAgICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XG4gICAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xuXG4gICAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxuICAgICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cbiAgICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSB0cnVlO1xuICAgIH1cblxuICAgIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcbiAgICBhcHBlbmRGaWxlKFxuICAgICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXG4gICAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxuICAgICAgKGVycm9yKSA9PiB7XG4gICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgIGNvbnNvbGUubG9nKGBbbG9nZ2VyXSBVbmFibGUgdG8gd3JpdGUgdG8gbG9nIGZpbGU6ICR7ZXJyb3J9YCk7XG4gICAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICAvLyBMb2cgdG8gY29uc29sZVxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcbiAgICBjb25zb2xlLmxvZy5hcHBseShcbiAgICAgIHVuZGVmaW5lZCxcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdCh0ZXh0cylcbiAgICApO1xuICB9XG59O1xuXG4vKipcbiAqIFNldHMgdGhlIGZpbGUgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dEZXN0IC0gQSBwYXRoIHRvIGxvZyB0by5cbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dGaWxlIC0gVGhlIG5hbWUgb2YgdGhlIGxvZyBmaWxlLlxuICovXG5leHBvcnQgY29uc3QgZW5hYmxlRmlsZUxvZ2dpbmcgPSAobG9nRGVzdCwgbG9nRmlsZSkgPT4ge1xuICAvLyBVcGRhdGUgbG9nZ2luZyBvcHRpb25zXG4gIGxvZ2dpbmcgPSB7XG4gICAgLi4ubG9nZ2luZyxcbiAgICBkZXN0OiBsb2dEZXN0IHx8IGxvZ2dpbmcuZGVzdCxcbiAgICBmaWxlOiBsb2dGaWxlIHx8IGxvZ2dpbmcuZmlsZSxcbiAgICB0b0ZpbGU6IHRydWVcbiAgfTtcblxuICBpZiAobG9nZ2luZy5kZXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBsb2coMSwgJ1tsb2dnZXJdIEZpbGUgbG9nZ2luZyBpbml0OiBubyBwYXRoIHN1cHBsaWVkLicpO1xuICB9XG5cbiAgaWYgKCFsb2dnaW5nLmRlc3QuZW5kc1dpdGgoJy8nKSkge1xuICAgIGxvZ2dpbmcuZGVzdCArPSAnLyc7XG4gIH1cbn07XG5cbi8qKlxuICogQWRkcyBhIGxvZyBsaXN0ZW5lci5cbiAqXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBjYWxsIHdoZW4gZ2V0dGluZyBhIGxvZyBldmVudC5cbiAqL1xuZXhwb3J0IGNvbnN0IGxpc3RlbiA9IChmbikgPT4ge1xuICBsb2dnaW5nLmxpc3RlbmVycy5wdXNoKGZuKTtcbn07XG5cbi8qKlxuICogU2V0cyB0aGUgY3VycmVudCBsb2cgbGV2ZWwuIExvZyBsZXZlbHMgYXJlOlxuICogLSAwID0gbm8gbG9nZ2luZ1xuICogLSAxID0gZXJyb3JcbiAqIC0gMiA9IHdhcm5pbmdcbiAqIC0gMyA9IG5vdGljZVxuICogLSA0ID0gdmVyYm9zZVxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdMZXZlbCAtIFRoZSBuZXcgbG9nIGxldmVsICgwIC0gNCkuXG4gKi9cbmV4cG9ydCBjb25zdCBzZXRMb2dMZXZlbCA9IChuZXdMZXZlbCkgPT4ge1xuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XG4gICAgbG9nZ2luZy5sZXZlbCA9IG5ld0xldmVsO1xuICB9XG59O1xuXG4vKipcbiAqIEVuYWJsZXMgb3IgZGlzYWJsZXMgbG9nZ2luZyB0byB0aGUgc3Rkb3V0LlxuICpcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZW5hYmxlZCAtIFdoZXRoZXIgbG9nIHRvIGNvbnNvbGUgb3Igbm90LlxuICovXG5leHBvcnQgY29uc3QgdG9nZ2xlU1RET3V0ID0gKGVuYWJsZWQpID0+IHtcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSBlbmFibGVkO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBsb2csXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxuICBsaXN0ZW4sXG4gIHNldExvZ0xldmVsLFxuICB0b2dnbGVTVERPdXRcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XG5cbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuLi9saWIvc2NoZW1hcy9jb25maWcuanMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XG5cbmV4cG9ydCBjb25zdCBfX2Rpcm5hbWUgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uLy4nLCBpbXBvcnQubWV0YS51cmwpKTtcblxuLyoqXG4gKiBDbGVhcnMgdGV4dCBmcm9tIHdoaXRlc3BhY2VzIHdpdGggYSByZWdleCBydWxlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBydWxlIC0gVGhlIHJ1bGUgZm9yIGNsZWFyaW5nIGEgc3RyaW5nLCBkZWZhdWx0IHRvIC9cXHNcXHMrL2cuXG4gKiBAcmV0dXJuIHtzdHJpbmd9IC0gQ2xlYXJlZCB0ZXh0LlxuICovXG5leHBvcnQgY29uc3QgY2xlYXJUZXh0ID0gKHRleHQsIHJ1bGUgPSAvXFxzXFxzKy9nLCByZXBsYWNlciA9ICcgJykgPT5cbiAgdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XG5cbi8qKlxuICogRGVsYXlzIGNhbGxpbmcgdGhlIGZ1bmN0aW9uIGJ5IHRpbWUgY2FsY3VsYXRlZCBiYXNlZCBvbiB0aGUgYmFja29mZlxuICogYWxnb3JpdGhtLlxuICpcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gQSBmdW5jdGlvbiB0byB0cnkgdG8gY2FsbCB3aXRoIHRoZSBiYWNrb2ZmIGFsZ29yaXRobVxuICogb24uXG4gKiBAcGFyYW0ge251bWJlcn0gYXR0ZW1wdCAtIFRoZSBudW1iZXIgb2YgYW4gYXR0ZW1wdCwgd2hlcmUgdGhlIGZpcnN0IG9uZSBpcyAwLlxuICovXG5leHBvcnQgY29uc3QgZXhwQmFja29mZiA9IGFzeW5jIChmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpID0+IHtcbiAgdHJ5IHtcbiAgICAvLyBUcnkgdG8gY2FsbCB0aGUgZnVuY3Rpb25cbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgLy8gQ2FsY3VsYXRlIGRlbGF5IGluIG1zXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcblxuICAgIC8vIElmIHRoZSBhdHRlbXB0IGV4Y2VlZHMgdGhlIG1heGltdW0gYXR0ZW1wdHMgb2YgcmVhcGVhdCwgdGhyb3cgYW4gZXJyb3JcbiAgICBpZiAoKythdHRlbXB0ID49IE1BWF9CQUNLT0ZGX0FUVEVNUFRTKSB7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG5cbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcbiAgICBsb2coXG4gICAgICAzLFxuICAgICAgYFtwb29sXSBXYWl0ZWQgJHtkZWxheUluTXN9bXMgdW50aWwgbmV4dCBjYWxsIGZvciB0aGUgcmVzb3VyY2UgaWQ6ICR7YXJnc1swXX0uYFxuICAgICk7XG5cbiAgICAvLyBUcnkgYWdhaW5cbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XG4gIH1cbn07XG5cbi8qKlxuICogRml4ZXMgdG8gc3VwcG9ydGVkIHR5cGUgZm9ybWF0IGlmIE1JTUUuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUeXBlIHRvIGJlIGNvcnJlY3RlZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gTmFtZSBvZiB0aGUgb3V0ZmlsZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGZpeFR5cGUgPSAodHlwZSwgb3V0ZmlsZSkgPT4ge1xuICAvLyBNSU1FIHR5cGVzXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcbiAgfTtcblxuICAvLyBGb3JtYXRzXG4gIGNvbnN0IGZvcm1hdHMgPSBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXTtcblxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcbiAgaWYgKG91dGZpbGUpIHtcbiAgICBjb25zdCBvdXRUeXBlID0gb3V0ZmlsZS5zcGxpdCgnLicpLnBvcCgpO1xuXG4gICAgLy8gQ2hlY2sgaWYgZXh0ZW5zaW9uIGhhcyBhIGNvcnJlY3QgdHlwZVxuICAgIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xuICAgIH1cbiAgfVxuXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XG59O1xuXG4vKipcbiAqIEhhbmRsZXMgdGhlIHByb3ZpZGVkIHJlc291cmNlcy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcmVzb3VyY2VzIC0gVGhlIHN0cmluZ2lmaWVkIHJlc291cmNlcy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBEZWNpZGUgaWYgcmVzb3VyY2VzIGZyb20gZmlsZSBhcmVcbiAqIGFsbG93ZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBoYW5kbGVSZXNvdXJjZXMgPSAocmVzb3VyY2VzID0gZmFsc2UsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xuICBjb25zdCBhbGxvd2VkUHJvcHMgPSBbJ2pzJywgJ2NzcycsICdmaWxlcyddO1xuXG4gIGxldCBoYW5kbGVkUmVzb3VyY2VzID0gcmVzb3VyY2VzO1xuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xuXG4gIC8vIFRyeSB0byBsb2FkIHJlc291cmNlcyBmcm9tIGEgZmlsZVxuICBpZiAoYWxsb3dGaWxlUmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xuICAgIHRyeSB7XG4gICAgICBpZiAoIXJlc291cmNlcykge1xuICAgICAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihcbiAgICAgICAgICByZWFkRmlsZVN5bmMoJ3Jlc291cmNlcy5qc29uJywgJ3V0ZjgnKVxuICAgICAgICApO1xuICAgICAgfSBlbHNlIGlmIChyZXNvdXJjZXMgJiYgcmVzb3VyY2VzLmVuZHNXaXRoKCcuanNvbicpKSB7XG4gICAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVzb3VyY2VzKTtcbiAgICAgICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgPT09IHRydWUpIHtcbiAgICAgICAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYygncmVzb3VyY2VzLmpzb24nLCAndXRmOCcpXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKG5vdGljZSkge1xuICAgICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xuXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxuICAgIGlmICghYWxsb3dGaWxlUmVzb3VyY2VzKSB7XG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcbiAgICB9XG4gIH1cblxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcbiAgICByZXR1cm4gbG9nKDMsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XG4gIH1cblxuICAvLyBIYW5kbGUgZmlsZXMgc2VjdGlvblxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xuICAgIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgPSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLm1hcCgoaXRlbSkgPT4gaXRlbS50cmltKCkpO1xuICAgIGlmICghaGFuZGxlZFJlc291cmNlcy5maWxlcyB8fCBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLmxlbmd0aCA8PSAwKSB7XG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcbiAgICB9XG4gIH1cblxuICAvLyBSZXR1cm4gcmVzb3VyY2VzXG4gIHJldHVybiBoYW5kbGVkUmVzb3VyY2VzO1xufTtcblxuLyoqXG4gKiBDaGVja3MgaWYgcHJvdmlkZWQgZGF0YSBpcyBvciBjYW4gYmUgYSBjb3JyZWN0IEpTT04uXG4gKlxuICogQHBhcmFtIHthbnl9IGRhdGEgLSBEYXRhIHRvIGJlIGNoZWNrZWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvU3RyaW5nIC0gSWYgdHJ1ZSwgcmV0dXJuIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xuICB0cnkge1xuICAgIC8vIEdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGlmIG5vdCBhbHJlYWR5IGJlZm9yZSBwYXJzaW5nXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXG4gICAgICB0eXBlb2YgZGF0YSAhPT0gJ3N0cmluZycgPyBKU09OLnN0cmluZ2lmeShkYXRhKSA6IGRhdGFcbiAgICApO1xuXG4gICAgLy8gUmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb24gb2YgYSBKU09OIGlmIHJlcXVpcmVkXG4gICAgaWYgKHR5cGVvZiBwYXJzZWREYXRhICE9PSAnc3RyaW5nJyAmJiB0b1N0cmluZykge1xuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xuICAgIH1cblxuICAgIC8vIFJldHVybiBhIEpTT05cbiAgICByZXR1cm4gcGFyc2VkRGF0YTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgaXRlbSBpcyBhbiBvYmplY3QuXG4gKlxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBJdGVtIHRvIGJlIGNoZWNrZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChpdGVtKSA9PlxuICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiYgaXRlbSAhPT0gbnVsbDtcblxuLyoqXG4gKiBDaGVja3MgaWYgc3RyaW5nIGNvbnRhaW5zIHByaXZhdGUgcmFuZ2UgdXJscy5cbiAqXG4gKiBAZXhwb3J0IHV0aWxzXG4gKiBAcGFyYW0gaXRlbSB7c3RyaW5nfSBpdGVtIHRvIGJlIGNoZWNrZWRcbiAqL1xuZXhwb3J0IGNvbnN0IGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQgPSAoaXRlbSkgPT4ge1xuICByZXR1cm4gW1xuICAgICdsb2NhbGhvc3QnLFxuICAgICcoMTApLiguKikuKC4qKS4oLiopJyxcbiAgICAnKDEyNykuKC4qKS4oLiopLiguKiknLFxuICAgICcoMTcyKS4oMVs2LTldfDJbMC05XXwzWzAtMV0pLiguKikuKC4qKScsXG4gICAgJygxOTIpLigxNjgpLiguKikuKC4qKSdcbiAgXS5zb21lKChpcFJlZ0V4KSA9PlxuICAgIGl0ZW0ubWF0Y2goYHhsaW5rOmhyZWY9XCIoPzooaHR0cDovL3xodHRwczovLykpPyR7aXBSZWdFeH1gKVxuICApO1xufTtcblxuLyoqXG4gKiBDcmVhdGVzIGFuZCByZXR1cm5zIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IG9iamVjdCAtIE9iamVjdCB0byBjb3B5LlxuICogQHJldHVybiB7b2JqZWN0fSAtIERlZXAgY29weSBvZiB0aGUgb2JqZWN0LlxuICovXG5leHBvcnQgY29uc3QgZGVlcENvcHkgPSAob2JqKSA9PiB7XG4gIGlmIChvYmogPT09IG51bGwgfHwgdHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gb2JqO1xuICB9XG5cbiAgY29uc3QgY29weSA9IEFycmF5LmlzQXJyYXkob2JqKSA/IFtdIDoge307XG5cbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqKSB7XG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcbiAgICAgIGNvcHlba2V5XSA9IGRlZXBDb3B5KG9ialtrZXldKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gY29weTtcbn07XG5cbi8qKlxuICogU3RyaW5naWZpZXMgb2JqZWN0IHdpdGggb3B0aW9ucy4gUG9zc2libGUgdG8gcHJlc2VydmUgZnVuY3Rpb25zIHdpdGhcbiAqIGFsbG93RnVuY3Rpb25zIGZsYWcuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBPcHRpb25zIHRvIHN0cmluZ2lmeS5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGdW5jdGlvbnMgLSBGbGFnIGZvciBrZWVwaW5nIGZ1bmN0aW9ucy5cbiAqL1xuZXhwb3J0IGNvbnN0IG9wdGlvbnNTdHJpbmdpZnkgPSAob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMpID0+IHtcbiAgY29uc3QgcmVwbGFjZXJDYWxsYmFjayA9IChuYW1lLCB2YWx1ZSkgPT4ge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcblxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xuICAgICAgaWYgKFxuICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oJykgfHwgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCcpKSAmJlxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpXG4gICAgICApIHtcbiAgICAgICAgdmFsdWUgPSBhbGxvd0Z1bmN0aW9uc1xuICAgICAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJ1xuICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcbiAgICAgIDogdmFsdWU7XG4gIH07XG5cbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShvcHRpb25zLCByZXBsYWNlckNhbGxiYWNrKS5yZXBsYWNlQWxsKFxuICAgIC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXG4gICAgJydcbiAgKTtcbn07XG5cbi8qKlxuICogUHJpbnRzIHRoZSBleHBvcnQgc2VydmVyIGxvZ28uXG4gKlxuICogQHBhcmFtIHtib29sZWFufSBub0xvZ28gLSBXaGV0aGVyIHRvIGRpc3BsYXkgbG9nbyBvciB0ZXh0LlxuICovXG5leHBvcnQgY29uc3QgcHJpbnRMb2dvID0gKG5vTG9nbykgPT4ge1xuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGVudiBvciBmcm9tIHBhY2thZ2UuanNvblxuICBjb25zdCBwYWNrYWdlVmVyc2lvbiA9XG4gICAgcHJvY2Vzcy5lbnYubnBtX3BhY2thZ2VfdmVyc2lvbiB8fFxuICAgIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG5ldyBVUkwoJy4uL3BhY2thZ2UuanNvbicsIGltcG9ydC5tZXRhLnVybCkpKVxuICAgICAgLnZlcnNpb247XG5cbiAgLy8gUHJpbnQgdGV4dCBvbmx5XG4gIGlmIChub0xvZ28pIHtcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgaGlnaGNoYXJ0cyBleHBvcnQgc2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufS4uLmApO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIFByaW50IHRoZSBsb2dvXG4gIGNvbnNvbGUubG9nKFxuICAgIHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL21zZy9zdGFydHVwLm1zZycpLnRvU3RyaW5nKCkuYm9sZC55ZWxsb3csXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufWBcbiAgKTtcbn07XG5cbi8qKlxuICogUHJpbnRzIHRoZSBDTEkgdXNhZ2UuIElmIHJlcXVpcmVkLCBpdCBjYW4gbGlzdCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xuICBjb25zdCBwYWQgPSA0ODtcbiAgY29uc3QgcmVhZG1lID0gJ2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnO1xuXG4gIC8vIERpc3BsYXkgcmVhZG1lIGluZm9ybWF0aW9uXG4gIGNvbnNvbGUubG9nKFxuICAgICdVc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcbiAgICAnXFxuLS0tLS0tJyxcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24gdmlzaXQgcmVhZG1lIGF0OiAke3JlYWRtZS5ib2xkLnllbGxvd30uYFxuICApO1xuXG4gIGNvbnN0IGN5Y2xlQ2F0ZWdvcmllcyA9IChjYXRlZ29yaWVzKSA9PiB7XG4gICAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhjYXRlZ29yaWVzKSkge1xuICAgICAgLy8gSWYgY2F0ZWdvcnkgaGFzIG1vcmUgbGV2ZWxzLCBnbyBmdXJ0aGVyXG4gICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XG4gICAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhvcHRpb24pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IGRlc2NOYW1lID0gYCAgLS0ke29wdGlvbi5jbGlOYW1lIHx8IG5hbWV9ICR7XG4gICAgICAgICAgKCc8JyArIG9wdGlvbi50eXBlICsgJz4nKS5ncmVlblxuICAgICAgICB9IGA7XG4gICAgICAgIGlmIChkZXNjTmFtZS5sZW5ndGggPCBwYWQpIHtcbiAgICAgICAgICBmb3IgKGxldCBpID0gZGVzY05hbWUubGVuZ3RoOyBpIDwgcGFkOyBpKyspIHtcbiAgICAgICAgICAgIGRlc2NOYW1lICs9ICcuJztcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBEaXNwbGF5IGNvcnJlY3RseSBhbGlnbmVkIG1lc3NhZ2VzXG4gICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgIGRlc2NOYW1lLFxuICAgICAgICAgIG9wdGlvbi5kZXNjcmlwdGlvbixcbiAgICAgICAgICBgW0RlZmF1bHQ6ICR7b3B0aW9uLnZhbHVlLnRvU3RyaW5nKCkuYm9sZH1dYC5ibHVlXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIC8vIEN5Y2xlIHRocm91Z2ggb3B0aW9ucyBvZiBlYWNoIGNhdGVnb3JpZXMgYW5kIGRpc3BsYXkgdGhlIHVzYWdlIGluZm9cbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcbiAgICAvLyBPbmx5IHB1cHBldGVlciBhbmQgaGlnaGNoYXJ0cyBjYXRlZ29yaWVzIGNhbm5vdCBiZSBjb25maWd1cmVkIHRocm91Z2ggQ0xJXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XG4gICAgICBjb25zb2xlLmxvZyhgXFxuJHtjYXRlZ29yeS50b1VwcGVyQ2FzZSgpfWAucmVkKTtcbiAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhkZWZhdWx0Q29uZmlnW2NhdGVnb3J5XSk7XG4gICAgfVxuICB9KTtcbiAgY29uc29sZS5sb2coJ1xcbicpO1xufVxuXG4vKipcbiAqIFJvdW5kcyBudW1iZXIgdG8gcGFzc2VkIHByZWNpc2lvbi5cbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBOdW1iZXIgdG8gcm91bmQuXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gQSBwcmVjaXNpb24gb2Ygcm91bmRpbmcuXG4gKi9cbmV4cG9ydCBjb25zdCByb3VuZE51bWJlciA9ICh2YWx1ZSwgcHJlY2lzaW9uID0gMSkgPT4ge1xuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xufTtcblxuLyoqXG4gKiBDYXN0cyB0aGUgaXRlbSB0byBib29sZWFuLlxuICpcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gSXRlbSB0byBiZSBjYXN0LlxuICovXG5leHBvcnQgY29uc3QgdG9Cb29sZWFuID0gKGl0ZW0pID0+XG4gIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcbiAgICA/IGZhbHNlXG4gICAgOiAhIWl0ZW07XG5cbi8qKlxuICogSWYgbmVjZXNzYXJ5LCBwbGFjZXMgYSBjdXN0b20gY29kZSBpbnNpZGUgYSBmdW5jdGlvbi5cbiAqXG4gKiBAcGFyYW0ge2FueX0gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b21Db2RlLlxuICovXG5leHBvcnQgY29uc3Qgd3JhcEFyb3VuZCA9IChjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xuXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXG4gICAgICAgID8gd3JhcEFyb3VuZChyZWFkRmlsZVN5bmMoY3VzdG9tQ29kZSwgJ3V0ZjgnKSlcbiAgICAgICAgOiBmYWxzZTtcbiAgICB9IGVsc2UgaWYgKFxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKT0+JykgfHxcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKVxuICAgICkge1xuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XG4gICAgfVxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xuICB9XG59O1xuXG4vKipcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSB0aW1lLlxuICovXG5leHBvcnQgY29uc3QgbWVhc3VyZVRpbWUgPSAoKSA9PiB7XG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBfX2Rpcm5hbWUsXG4gIGNsZWFyVGV4dCxcbiAgZXhwQmFja29mZixcbiAgZml4VHlwZSxcbiAgaGFuZGxlUmVzb3VyY2VzLFxuICBpc0NvcnJlY3RKU09OLFxuICBpc09iamVjdCxcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcbiAgb3B0aW9uc1N0cmluZ2lmeSxcbiAgcHJpbnRMb2dvLFxuICBwcmludFVzYWdlLFxuICByb3VuZE51bWJlcixcbiAgdG9Cb29sZWFuLFxuICB3cmFwQXJvdW5kLFxuICBtZWFzdXJlVGltZVxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XG5cbmltcG9ydCB7IGNsZWFyVGV4dCB9IGZyb20gJy4uL3V0aWxzLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5cbi8qKlxuICogRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciBhIGdpdmVuIGFwcC5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gYXBwIC0gVGhlIGV4cHJlc3MgYXBwLlxuICogQHBhcmFtIHtvYmplY3R9IGxpbWl0Q29uZmlnIC0gVGhlIG9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0aW5nLlxuICovXG5leHBvcnQgZGVmYXVsdCAoYXBwLCBsaW1pdENvbmZpZykgPT4ge1xuICBjb25zdCBtc2cgPVxuICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcblxuICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXG4gIGNvbnN0IHJhdGVPcHRpb25zID0ge1xuICAgIG1heDogbGltaXRDb25maWcubWF4UmVxdWVzdHMgfHwgMzAsXG4gICAgd2luZG93OiBsaW1pdENvbmZpZy53aW5kb3cgfHwgMSxcbiAgICBkZWxheTogbGltaXRDb25maWcuZGVsYXkgfHwgMCxcbiAgICB0cnVzdFByb3h5OiBsaW1pdENvbmZpZy50cnVzdFByb3h5IHx8IGZhbHNlLFxuICAgIHNraXBLZXk6IGxpbWl0Q29uZmlnLnNraXBLZXkgfHwgZmFsc2UsXG4gICAgc2tpcFRva2VuOiBsaW1pdENvbmZpZy5za2lwVG9rZW4gfHwgZmFsc2VcbiAgfTtcblxuICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcbiAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcbiAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xuICB9XG5cbiAgLy8gQ3JlYXRlIGEgbGltaXRlclxuICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcbiAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxuICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xuICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxuICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXG4gICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXG4gICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gICAgICByZXNwb25zZS5mb3JtYXQoe1xuICAgICAgICBqc29uOiAoKSA9PiB7XG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcbiAgICAgICAgfSxcbiAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSxcbiAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xuICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcbiAgICAgIGlmIChcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXG4gICAgICApIHtcbiAgICAgICAgbG9nKDQsICdbcmF0ZS1saW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXG4gIGFwcC51c2UobGltaXRlcik7XG5cbiAgbG9nKFxuICAgIDMsXG4gICAgY2xlYXJUZXh0KFxuICAgICAgYFtyYXRlLWxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmc6ICR7cmF0ZU9wdGlvbnMubWF4fSByZXF1ZXN0c1xuICAgICAgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgcGVyIElQLCB0cnVzdGluZyBwcm94eTpcbiAgICAgICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxuICAgIClcbiAgKTtcbn07XG4iLCIvKipcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXG4gKi9cblxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xuXG4vKipcbiAqIERldGVybWluZXMgdGhlIHByb3RvY29sIG9mIHRoZSBnaXZlbiBVUkwgKGVpdGhlciBgaHR0cGAgb3IgYGh0dHBzYCkuXG4gKlxuICogQGZ1bmN0aW9uXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB3aG9zZSBwcm90b2NvbCBuZWVkcyB0byBiZSBkZXRlcm1pbmVkLlxuICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgYGh0dHBzYCBtb2R1bGUgaWYgdGhlIFVSTCBzdGFydHMgd2l0aCAnaHR0cHMnLFxuICogb3RoZXJ3aXNlIHJldHVybnMgdGhlIGBodHRwYCBtb2R1bGUuXG4gKiBAcHJpdmF0ZVxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCgnaHR0cHM6Ly9leGFtcGxlLmNvbScpO1xuICogY29uc29sZS5sb2cocHJvdG9jb2wpOyAvLyBPdXRwdXRzIHRoZSAnaHR0cHMnIG1vZHVsZVxuICovXG5jb25zdCBnZXRQcm90b2NvbCA9ICh1cmwpID0+IHtcbiAgcmV0dXJuIHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwO1xufTtcblxuLyoqXG4gKiBTZW5kcyBhIEdFVCByZXF1ZXN0IHRvIHRoZSBzcGVjaWZpZWQgVVJMIHdpdGggb3B0aW9uYWwgcmVxdWVzdCBvcHRpb25zLlxuICpcbiAqIEBmdW5jdGlvblxuICogQGFzeW5jXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBmZXRjaC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBbcmVxdWVzdE9wdGlvbnM9e31dIC0gT3B0aW9uYWwgcmVxdWVzdCBvcHRpb25zIGFuZCBoZWFkZXJzLlxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUmV0dXJucyBhIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXNwb25zZSBvYmplY3QuXG4gKiBUaGUgcmVzcG9uc2Ugb2JqZWN0IGNvbnRhaW5zIGEgYC50ZXh0YCBwcm9wZXJ0eSB3aXRoIHRoZSByYXcgcmVzcG9uc2UgZGF0YS5cbiAqIEB0aHJvd3Mge0Vycm9yfSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIHJlcXVlc3QgZmFpbHMgb3IgaWYgbm8gZGF0YSBpcyBmZXRjaGVkIGZyb20gdGhlIFVSTC5cbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIGFzeW5jIGZ1bmN0aW9uIGdldERhdGEoKSB7XG4gKiAgIHRyeSB7XG4gKiAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCgnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vZGF0YScpO1xuICogICAgIGNvbnNvbGUubG9nKHJlc3BvbnNlLnRleHQpO1xuICogICB9IGNhdGNoIChlcnJvcikge1xuICogICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGZldGNoaW5nIGRhdGE6JywgZXJyb3IpO1xuICogICB9XG4gKiB9XG4gKlxuICogZ2V0RGF0YSgpO1xuICovXG5hc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XG5cbiAgICBwcm90b2NvbFxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XG4gICAgICAgIGxldCBkYXRhID0gJyc7XG5cbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcbiAgICAgICAgICBkYXRhICs9IGNodW5rO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xuICAgICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgICAgcmVqZWN0KCdOb3RoaW5nIHdhcyBmZXRjaGVkIGZyb20gdGhlIFVSTC4nKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXMudGV4dCA9IGRhdGE7XG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICB9KTtcbiAgfSk7XG59XG5cbi8qKlxuICogU2VuZHMgYSBQT1NUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgd2l0aCB0aGUgZ2l2ZW4gYm9keSBhbmQgcmVxdWVzdCBvcHRpb25zLlxuICpcbiAqIEBmdW5jdGlvblxuICogQGFzeW5jXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byB3aGljaCB0aGUgcmVxdWVzdCBzaG91bGQgYmUgc2VudC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBbYm9keT17fV0gLSBUaGUgZGF0YSB0byBiZSBzZW50IGFzIHRoZSByZXF1ZXN0IGJvZHksIGluIEpTT04gZm9ybWF0LlxuICogQHBhcmFtIHtPYmplY3R9IFtyZXF1ZXN0T3B0aW9ucz17fV0gLSBPcHRpb25hbCByZXF1ZXN0IG9wdGlvbnMgYW5kIGhlYWRlcnMuXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSAtIFJldHVybnMgYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgcGFyc2VkIEpTT04gcmVzcG9uc2UuXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSByZXF1ZXN0IGZhaWxzIG9yIGlmIHRoZSByZXNwb25zZSBjYW5ub3QgYmUgcGFyc2VkLlxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogYXN5bmMgZnVuY3Rpb24gc2VuZERhdGEoKSB7XG4gKiAgIGNvbnN0IGRhdGFUb1NlbmQgPSB7XG4gKiAgICAga2V5MTogJ3ZhbHVlMScsXG4gKiAgICAga2V5MjogJ3ZhbHVlMicsXG4gKiAgIH07XG4gKiAgIHRyeSB7XG4gKiAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBwb3N0KCdodHRwczovL2FwaS5leGFtcGxlLmNvbS9kYXRhJywgZGF0YVRvU2VuZCk7XG4gKiAgICAgY29uc29sZS5sb2cocmVzcG9uc2UpO1xuICogICB9IGNhdGNoIChlcnJvcikge1xuICogICAgIGNvbnNvbGUuZXJyb3IoJ0Vycm9yIHNlbmRpbmcgZGF0YTonLCBlcnJvcik7XG4gKiAgIH1cbiAqIH1cbiAqXG4gKiBzZW5kRGF0YSgpO1xuICovXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcblxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggcmVxdWVzdE9wdGlvbnNcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcbiAgICAgIHtcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICdDb250ZW50LUxlbmd0aCc6IGRhdGEubGVuZ3RoXG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICByZXF1ZXN0T3B0aW9uc1xuICAgICk7XG5cbiAgICBjb25zdCByZXEgPSBwcm90b2NvbFxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcblxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmVzLnRleHQgPSByZXNwb25zZURhdGE7XG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICB9KTtcblxuICAgIC8vIFdyaXRlIHRoZSByZXF1ZXN0IGJvZHkgYW5kIGVuZCB0aGUgcmVxdWVzdC5cbiAgICByZXEud3JpdGUoZGF0YSk7XG4gICAgcmVxLmVuZCgpO1xuICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgZmV0Y2g7XG5leHBvcnQgeyBmZXRjaCwgcG9zdCB9O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cbi8vIFRoZSBjYWNoZSBpdHNlbGYgaXMgc3RvcmVkIGluIC5jYWNoZSwgYW5kIGlzIGNoZWNrZWQgYnkgdGhlIGNvbmZpZyBzeXN0ZW1cbi8vIGJlZm9yZSBzdGFydGluZyB0aGUgc2VydmljZVxuXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcblxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xuaW1wb3J0IEh0dHBzUHJveHlBZ2VudCBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XG5pbXBvcnQgeyBmZXRjaCB9IGZyb20gJy4vZmV0Y2guanMnO1xuXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi9saWIvdXRpbHMuanMnO1xuXG5kb3RlbnYuY29uZmlnKCk7XG5cbmNvbnN0IGNhY2hlUGF0aCA9IGpvaW4oX19kaXJuYW1lLCAnLmNhY2hlJyk7XG5cbmNvbnN0IGNhY2hlID0ge1xuICBjZG5VUkw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20vJyxcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxuICBzb3VyY2VzOiAnJyxcbiAgaGNWZXJzaW9uOiAnJ1xufTtcblxuLy8gVE9ETzogVGhlIGNvbmZpZyBzaG91bGQgYmUgYWNjZXNzc2libGUgZ2xvYmFsbHkgc28gd2UgZG9uJ3QgaGF2ZSB0byBkbyB0aGlzIHNvcnQgb2YgdGhpbmcuLlxubGV0IGFwcGxpZWRDb25maWcgPSBmYWxzZTtcblxuLyoqXG4gKiBFeHRyYWN0cyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIGNhY2hlXG4gKi9cbmNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKCkgPT5cbiAgKGNhY2hlLmhjVmVyc2lvbiA9IGNhY2hlLnNvdXJjZXNcbiAgICAuc3Vic3RyKDAsIGNhY2hlLnNvdXJjZXMuaW5kZXhPZignKi8nKSlcbiAgICAucmVwbGFjZSgnLyonLCAnJylcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxuICAgIC50cmltKCkpO1xuXG4vKipcbiAqIFNhdmVzIHRoZSBIaWdoY2hhcnRzIHBhcnQgb2YgYSBjb25maWcgdG8gYSBtYW5pZmVzdCBmaWxlIGluIHRoZSBjYWNoZVxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25maWcgLSBIaWdoY2hhcnRzIHJlbGF0ZWQgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cbiAqL1xuY29uc3Qgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QgPSBhc3luYyAoY29uZmlnLCBmZXRjaGVkTW9kdWxlcykgPT4ge1xuICBjb25zdCBuZXdNYW5pZmVzdCA9IHtcbiAgICB2ZXJzaW9uOiBjb25maWcudmVyc2lvbixcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlcyB8fCB7fVxuICB9O1xuXG4gIC8vIFVwZGF0ZSBjYWNoZSBvYmplY3Qgd2l0aCB0aGUgY3VycmVudCBtb2R1bGVzXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XG5cbiAgbG9nKDQsICdbY2FjaGVdIHdyaXRpbmcgbmV3IG1hbmlmZXN0Jyk7XG5cbiAgdHJ5IHtcbiAgICB3cml0ZUZpbGVTeW5jKFxuICAgICAgam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyksXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXG4gICAgICAndXRmOCdcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZygxLCBgW2NhY2hlXSBFcnJvciB3cml0aW5nIGNhY2hlIG1hbmlmZXN0OiAke2Vycm9yfS5gKTtcbiAgfVxufTtcblxuLyoqXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXG4gKiBAcGFyYW0ge29iamVjdH0gcHJveHlBZ2VudCAtIFRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yIGEgcmVxdWVzdC5cbiAqL1xuY29uc3QgZmV0Y2hTY3JpcHQgPSBhc3luYyAoc2NyaXB0LCBwcm94eUFnZW50KSA9PiB7XG4gIHRyeSB7XG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXG4gICAgaWYgKHNjcmlwdC5lbmRzV2l0aCgnLmpzJykpIHtcbiAgICAgIHNjcmlwdCA9IHNjcmlwdC5zdWJzdHJpbmcoMCwgc2NyaXB0Lmxlbmd0aCAtIDMpO1xuICAgIH1cblxuICAgIGxvZyg0LCBgW2NhY2hlXSBGZXRjaGluZyBzY3JpcHQgLSAke3NjcmlwdH0uanNgKTtcblxuICAgIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxuICAgICAgPyB7XG4gICAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXG4gICAgICAgICAgdGltZW91dDogK3Byb2Nlc3MuZW52WydQUk9YWV9TRVJWRVJfVElNRU9VVCddIHx8IDUwMDBcbiAgICAgICAgfVxuICAgICAgOiB7fTtcblxuICAgIC8vIEZldGNoIHRoZSBzY3JpcHRcbiAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XG5cbiAgICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXG4gICAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCkge1xuICAgICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XG4gICAgfVxuXG4gICAgdGhyb3cgYCR7cmVzcG9uc2Uuc3RhdHVzQ29kZX1gO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZygxLCBgW2NhY2hlXSBFcnJvciBmZXRjaGluZyBzY3JpcHQgJHtzY3JpcHR9LmpzOiAke2Vycm9yfS5gKTtcbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxufTtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIGNhY2hlLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25maWcgLSBIaWdoY2hhcnRzIHJlbGF0ZWQgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIEEgcGF0aCB0byB0aGUgZmlsZSB3aGVyZSBzYXZlIHVwZGF0ZWQgc291cmNlcy5cbiAqIEByZXR1cm4ge29iamVjdH0gQW4gb2JqZWN0IHRoYXQgY29udGFpbnMgbWFwcGVkIG5hbWVzIG9mIGZldGNoZWQgSGlnaGNoYXJ0c1xuICogbW9kdWxlcyB0byB1c2UuXG4gKi9cbmNvbnN0IHVwZGF0ZUNhY2hlID0gYXN5bmMgKGNvbmZpZywgc291cmNlUGF0aCkgPT4ge1xuICBjb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVzLCBpbmRpY2F0b3JzLCBzY3JpcHRzOiBjdXN0b21TY3JpcHRzIH0gPSBjb25maWc7XG4gIGNvbnN0IGhjVmVyc2lvbiA9XG4gICAgY29uZmlnLnZlcnNpb24gPT09ICdsYXRlc3QnIHx8ICFjb25maWcudmVyc2lvbiA/ICcnIDogYCR7Y29uZmlnLnZlcnNpb259L2A7XG5cbiAgbG9nKDMsICdbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHRvIEhpZ2hjaGFydHMgJywgaGNWZXJzaW9uKTtcblxuICAvLyBHYXRoZXIgYWxsIHNjcmlwdHMgdG8gZmV0Y2hcbiAgY29uc3QgYWxsU2NyaXB0cyA9IFtcbiAgICAuLi5jb3JlU2NyaXB0cy5tYXAoKGMpID0+IGAke2hjVmVyc2lvbn0ke2N9YCksXG4gICAgLi4ubW9kdWxlcy5tYXAoKG0pID0+XG4gICAgICBtID09PSAnbWFwJyA/IGBtYXBzLyR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWAgOiBgJHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxuICAgICksXG4gICAgLi4uaW5kaWNhdG9ycy5tYXAoKGkpID0+IGBzdG9jay8ke2hjVmVyc2lvbn1pbmRpY2F0b3JzLyR7aX1gKVxuICBdO1xuXG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcbiAgbGV0IHByb3h5QWdlbnQ7XG4gIGNvbnN0IHByb3h5SG9zdCA9IHByb2Nlc3MuZW52WydQUk9YWV9TRVJWRVJfSE9TVCddO1xuICBjb25zdCBwcm94eVBvcnQgPSBwcm9jZXNzLmVudlsnUFJPWFlfU0VSVkVSX1BPUlQnXTtcblxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xuICAgIHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcbiAgICAgIGhvc3Q6IHByb3h5SG9zdCxcbiAgICAgIHBvcnQ6ICtwcm94eVBvcnRcbiAgICB9KTtcbiAgfVxuXG4gIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XG4gIHRyeSB7XG4gICAgY2FjaGUuc291cmNlcyA9IC8vIFRPRE86IGNvbnZlcnQgdG8gZm9yIGxvb3BcbiAgICAgIChcbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgIC4uLmFsbFNjcmlwdHMubWFwKGFzeW5jIChzY3JpcHQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHRleHQgPSBhd2FpdCBmZXRjaFNjcmlwdChcbiAgICAgICAgICAgICAgYCR7Y29uZmlnLmNkblVSTCB8fCBjYWNoZS5jZG5VUkx9JHtzY3JpcHR9YCxcbiAgICAgICAgICAgICAgcHJveHlBZ2VudFxuICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgLy8gSWYgZmV0Y2hlZCBjb3JyZWN0bHksIHNldCBpdFxuICAgICAgICAgICAgaWYgKHR5cGVvZiB0ZXh0ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICBmZXRjaGVkTW9kdWxlc1tcbiAgICAgICAgICAgICAgICBzY3JpcHQucmVwbGFjZShcbiAgICAgICAgICAgICAgICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxuICAgICAgICAgICAgICAgICAgJydcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgIF0gPSAxO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gdGV4dDtcbiAgICAgICAgICB9KSxcbiAgICAgICAgICAuLi5jdXN0b21TY3JpcHRzLm1hcCgoc2NyaXB0KSA9PiBmZXRjaFNjcmlwdChzY3JpcHQsIHByb3h5QWdlbnQpKVxuICAgICAgICBdKVxuICAgICAgKS5qb2luKCc7XFxuJyk7XG4gICAgZXh0cmFjdFZlcnNpb24oKTtcblxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBsb2coMSwgJ1tjYWNoZV0gVW5hYmxlIHRvIHVwZGF0ZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLicpO1xuICB9XG59O1xuXG5leHBvcnQgY29uc3QgdXBkYXRlVmVyc2lvbiA9IGFzeW5jIChuZXdWZXJzaW9uKSA9PlxuICBhcHBsaWVkQ29uZmlnXG4gICAgPyBhd2FpdCBjaGVja0NhY2hlKFxuICAgICAgICBPYmplY3QuYXNzaWduKGFwcGxpZWRDb25maWcsIHtcbiAgICAgICAgICB2ZXJzaW9uOiBuZXdWZXJzaW9uXG4gICAgICAgIH0pXG4gICAgICApXG4gICAgOiBmYWxzZTtcblxuLyoqXG4gKiBGZXRjaGVzIGFueSBtaXNzaW5nIEhpZ2hjaGFydHMgYW5kIGRlcGVuZGVuY2llc1xuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25maWcgLSBIaWdoY2hhcnRzIHJlbGF0ZWQgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKi9cbmV4cG9ydCBjb25zdCBjaGVja0NhY2hlID0gYXN5bmMgKGNvbmZpZykgPT4ge1xuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XG4gIC8vIFByZXBhcmUgcGF0aHMgdG8gbWFuaWZlc3QgYW5kIHNvdXJjZXMgZnJvbSB0aGUgLmNhY2hlIGZvbGRlclxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xuXG4gIC8vIFRPRE86IGRlYWwgd2l0aCB0cnlpbmcgdG8gc3dpdGNoIHRvIHRoZSBydW5uaW5nIHZlcnNpb25cbiAgLy8gY29uc3QgYWN0aXZlVmVyc2lvbiA9IGFwcGxpZWRDb25maWcgPyBhcHBsaWVkQ29uZmlnLnZlcnNpb24gOiBmYWxzZTtcblxuICBhcHBsaWVkQ29uZmlnID0gY29uZmlnO1xuXG4gIC8vIENyZWF0ZSB0aGUgLmNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxuICAhZXhpc3RzU3luYyhjYWNoZVBhdGgpICYmIG1rZGlyU3luYyhjYWNoZVBhdGgpO1xuXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxuICAvLyBvciBpZiB0aGUgZm9yY2VGZXRjaCBvcHRpb24gaXMgZW5hYmxlZFxuICBpZiAoIWV4aXN0c1N5bmMobWFuaWZlc3RQYXRoKSB8fCBjb25maWcuZm9yY2VGZXRjaCkge1xuICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGNvbmZpZywgc291cmNlUGF0aCk7XG4gIH0gZWxzZSB7XG4gICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcblxuICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCkpO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcbiAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcbiAgICAgIGNvbnN0IG1vZHVsZU1hcCA9IHt9O1xuICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcbiAgICB9XG5cbiAgICBjb25zdCB7IG1vZHVsZXMsIGNvcmVTY3JpcHRzLCBpbmRpY2F0b3JzIH0gPSBjb25maWc7XG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cbiAgICAgIG1vZHVsZXMubGVuZ3RoICsgY29yZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9ycy5sZW5ndGg7XG5cbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIC5jYWNoZS5cbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxuICAgIC8vIGFuZCBiYWtlIHRoZW0gaW50byBhIGdpYW50IGJsb2IuIFNhdmUgdGhlIGJsb2IuXG4gICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IGNvbmZpZy52ZXJzaW9uKSB7XG4gICAgICBsb2coMywgJ1tjYWNoZV0gSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLicpO1xuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xuICAgICAgbG9nKFxuICAgICAgICAzLFxuICAgICAgICAnW2NhY2hlXSBDYWNoZSBhbmQgcmVxdWVzdGVkIG1vZHVsZXMgZG9lcyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xuICAgICAgKTtcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBDaGVjayBlYWNoIG1vZHVsZSwgaWYgYW55dGhpbmcgaXMgbWlzc2luZyByZWZldGNoIGV2ZXJ5dGhpbmdcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAoY29uZmlnLm1vZHVsZXMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcbiAgICAgICAgaWYgKCFtYW5pZmVzdC5tb2R1bGVzW21vZHVsZU5hbWVdKSB7XG4gICAgICAgICAgbG9nKFxuICAgICAgICAgICAgMyxcbiAgICAgICAgICAgIGBbY2FjaGVdIFRoZSAke21vZHVsZU5hbWV9IG1pc3NpbmcgaW4gY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGNvbmZpZywgc291cmNlUGF0aCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XG5cbiAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcbiAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcblxuICAgICAgLy8gR2V0IGN1cnJlbnQgbW9kdWxlcyBtYXBcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcbiAgICAgIGV4dHJhY3RWZXJzaW9uKCk7XG4gICAgfVxuICB9XG5cbiAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXG4gIC8vIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdFxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChjb25maWcsIGZldGNoZWRNb2R1bGVzKTtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgY2hlY2tDYWNoZSxcbiAgdXBkYXRlVmVyc2lvbixcbiAgZ2V0Q2FjaGU6ICgpID0+IGNhY2hlLFxuICBoaWdoY2hhcnRzOiAoKSA9PiBjYWNoZS5zb3VyY2VzLFxuICB2ZXJzaW9uOiAoKSA9PiBjYWNoZS5oY1ZlcnNpb25cbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHB1cHBldGVlciBmcm9tICdwdXBwZXRlZXInO1xuaW1wb3J0IGZzIGZyb20gJ2ZzJztcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHBhdGggZnJvbSAnbm9kZTpwYXRoJztcblxuLy8gV29ya2Fyb3VuZCBmb3IgaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL2Nocm9taXVtL2lzc3Vlcy9kZXRhaWw/aWQ9MTQ2MzMyOFxuLy8gTm90IGlkZWFsIC0gbGVhdmVzIHRyYXNoIGluIHRoZSBGU1xuaW1wb3J0IHsgcmFuZG9tQnl0ZXMgfSBmcm9tICdub2RlOmNyeXB0byc7XG5jb25zdCBSQU5ET01fUElEID0gcmFuZG9tQnl0ZXMoNjQpLnRvU3RyaW5nKCdiYXNlNjR1cmwnKTtcbmNvbnN0IFBVUFBFVEVFUl9ESVIgPSBwYXRoLmpvaW4oJ3RtcCcsIGBwdXBwZXRlZXItJHtSQU5ET01fUElEfWApO1xuY29uc3QgREFUQV9ESVIgPSBwYXRoLmpvaW4oUFVQUEVURUVSX0RJUiwgJ3Byb2ZpbGUnKTtcblxuLy8gVGhlIG1pbmltYWwgYXJncyB0byBzcGVlZCB1cCB0aGUgYnJvd3NlclxuY29uc3QgbWluaW1hbEFyZ3MgPSBbXG4gIGAtLXVzZXItZGF0YS1kaXI9JHtEQVRBX0RJUn1gLFxuICAnLS1hdXRvcGxheS1wb2xpY3k9dXNlci1nZXN0dXJlLXJlcXVpcmVkJyxcbiAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLW5ldHdvcmtpbmcnLFxuICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXG4gICctLWRpc2FibGUtYmFja2dyb3VuZGluZy1vY2NsdWRlZC13aW5kb3dzJyxcbiAgJy0tZGlzYWJsZS1icmVha3BhZCcsXG4gICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcbiAgJy0tZGlzYWJsZS1jb21wb25lbnQtdXBkYXRlJyxcbiAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxuICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxuICAnLS1kaXNhYmxlLWRvbWFpbi1yZWxpYWJpbGl0eScsXG4gICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXG4gICctLWRpc2FibGUtZmVhdHVyZXM9QXVkaW9TZXJ2aWNlT3V0T2ZQcm9jZXNzJyxcbiAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxuICAnLS1kaXNhYmxlLWlwYy1mbG9vZGluZy1wcm90ZWN0aW9uJyxcbiAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcbiAgJy0tZGlzYWJsZS1vZmZlci1zdG9yZS11bm1hc2tlZC13YWxsZXQtY2FyZHMnLFxuICAnLS1kaXNhYmxlLXBvcHVwLWJsb2NraW5nJyxcbiAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcbiAgJy0tZGlzYWJsZS1wcm9tcHQtb24tcmVwb3N0JyxcbiAgJy0tZGlzYWJsZS1yZW5kZXJlci1iYWNrZ3JvdW5kaW5nJyxcbiAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcbiAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXG4gICctLWRpc2FibGUtc3BlZWNoLWFwaScsXG4gICctLWRpc2FibGUtc3luYycsXG4gICctLWhpZGUtY3Jhc2gtcmVzdG9yZS1idWJibGUnLFxuICAnLS1oaWRlLXNjcm9sbGJhcnMnLFxuICAnLS1pZ25vcmUtZ3B1LWJsYWNrbGlzdCcsXG4gICctLW1ldHJpY3MtcmVjb3JkaW5nLW9ubHknLFxuICAnLS1tdXRlLWF1ZGlvJyxcbiAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcbiAgJy0tbm8tZmlyc3QtcnVuJyxcbiAgJy0tbm8tcGluZ3MnLFxuICAnLS1uby1zYW5kYm94JyxcbiAgJy0tbm8tenlnb3RlJyxcbiAgJy0tcGFzc3dvcmQtc3RvcmU9YmFzaWMnLFxuICAnLS11c2UtbW9jay1rZXljaGFpbidcbl07XG5cbmNvbnN0IF9fZGlybmFtZSA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcblxuY29uc3QgdGVtcGxhdGUgPSBmcy5yZWFkRmlsZVN5bmMoXG4gIF9fZGlybmFtZSArICcvLi4vdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLFxuICAndXRmOCdcbik7XG5cbmxldCBicm93c2VyO1xuXG5leHBvcnQgY29uc3QgbmV3UGFnZSA9IGFzeW5jICgpID0+IHtcbiAgaWYgKCFicm93c2VyKSByZXR1cm4gZmFsc2U7XG5cbiAgY29uc3QgcCA9IGF3YWl0IGJyb3dzZXIubmV3UGFnZSgpO1xuXG4gIGF3YWl0IHAuc2V0Q29udGVudCh0ZW1wbGF0ZSk7XG4gIGF3YWl0IHAuYWRkU2NyaXB0VGFnKHsgcGF0aDogX19kaXJuYW1lICsgJy8uLi8uY2FjaGUvc291cmNlcy5qcycgfSk7XG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICBhd2FpdCBwLmV2YWx1YXRlKCgpID0+IHdpbmRvdy5zZXR1cEhpZ2hjaGFydHMoKSk7XG5cbiAgcC5vbigncGFnZWVycm9yJywgYXN5bmMgKGVycikgPT4ge1xuICAgIC8vIFRPRE86IENvbnNpZGVyIGFkZGluZyBhIHN3aXRjaCBoZXJlIHRoYXQgdHVybnMgb24gbG9nKDApIGxvZ2dpbmdcbiAgICAvLyBvbiBwYWdlIGVycm9ycy5cbiAgICBsb2coMSwgJ1twYWdlIGVycm9yXScsIGVycik7XG4gICAgYXdhaXQgcC4kZXZhbChcbiAgICAgICcjY29udGFpbmVyJyxcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgIGlmICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMpIHtcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjwvaDE+JHtlcnIudG9TdHJpbmcoKX1gXG4gICAgKTtcbiAgfSk7XG5cbiAgcmV0dXJuIHA7XG59O1xuXG5leHBvcnQgY29uc3QgY3JlYXRlID0gYXN5bmMgKHB1cHBldGVlckFyZ3MpID0+IHtcbiAgY29uc3QgYWxsQXJncyA9IFsuLi5taW5pbWFsQXJncywgLi4uKHB1cHBldGVlckFyZ3MgfHwgW10pXTtcblxuICAvLyBDcmVhdGUgYSBicm93c2VyXG4gIGlmICghYnJvd3Nlcikge1xuICAgIGxldCB0cnlDb3VudCA9IDA7XG5cbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nKFxuICAgICAgICAgIDMsXG4gICAgICAgICAgJ1ticm93c2VyXSBhdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeScsXG4gICAgICAgICAgdHJ5Q291bnQgKyAnKSdcbiAgICAgICAgKTtcblxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaCh7XG4gICAgICAgICAgaGVhZGxlc3M6ICduZXcnLFxuICAgICAgICAgIGFyZ3M6IGFsbEFyZ3MsXG4gICAgICAgICAgdXNlckRhdGFEaXI6ICcuL3RtcC8nXG4gICAgICAgIH0pO1xuICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBsb2coMCwgJ1ticm93c2VyXScsIGUpO1xuICAgICAgICBpZiAoKyt0cnlDb3VudCA8IDI1KSB7XG4gICAgICAgICAgbG9nKDMsICdbYnJvd3Nlcl0gZmFpbGVkOicsIGUpO1xuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBsb2coMCwgJ01heCByZXRyaWVzIHJlYWNoZWQnKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgb3BlbigpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGxvZygwLCAnW2Jyb3dzZXJdIFVuYWJsZSB0byBvcGVuIGJyb3dzZXInKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoIWJyb3dzZXIpIHtcbiAgICAgIGxvZygwLCAnW2Jyb3dzZXJdIFVuYWJsZSB0byBvcGVuIGJyb3dzZXInKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvLyBSZXR1cm4gYSBicm93c2VyIHByb21pc2VcbiAgcmV0dXJuIGJyb3dzZXI7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0ID0gYXN5bmMgKCkgPT4ge1xuICBpZiAoIWJyb3dzZXIpIHtcbiAgICB0aHJvdyAnTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkJztcbiAgfVxuXG4gIHJldHVybiBicm93c2VyO1xufTtcblxuZXhwb3J0IGNvbnN0IGNsb3NlID0gYXN5bmMgKCkgPT4ge1xuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5uZWN0ZWRcbiAgaWYgKGJyb3dzZXIuY29ubmVjdGVkKSB7XG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xuICB9XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGdldCxcbiAgY2xvc2UsXG4gIG5ld1BhZ2Vcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuLy8gVE9ETzogcmVtb3ZlIHRoaXMgdGVtcCBiZW5jaG1hcmsgc3R1ZmYuIEkgaGFkIHRoaXMgaWRlYSBvZiBkb2luZyBhIGdlbmVyYWwgYmVuY2htYXJraW5nXG4vLyBzeXN0ZW0sIGJ1dCBpdCBhZGRzIHNvIG11Y2ggYmxvYXQgaW4gdGhlIGNvZGUgdGhhdCBpdCBzaG91bGRuJ3QgYmUgdGhlcmUuXG5cbmltcG9ydCBiZW5jaG1hcmsgZnJvbSAnLi9iZW5jaG1hcmsuanMnO1xuaW1wb3J0IGNhY2hlIGZyb20gJy4vY2FjaGUuanMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4vLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyc7XG5cbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0ICogYXMgdXJsIGZyb20gJ3VybCc7XG5cbmNvbnN0IF9fYmFzZWRpciA9IHVybC5maWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4nLCBpbXBvcnQubWV0YS51cmwpKTtcblxuLy8gY29uc3QganNvblRlbXBsYXRlID0gcmVxdWlyZSgnLi8uLi90ZW1wbGF0ZXMvanNvbl9leHBvcnQvanNvbl9leHBvcnQuanMnKTtcblxuLyoqXG4gKiBHZXRzIHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIGNoYXJ0IERPTSBub2RlLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBwYWdlIC0gQSBwYWdlIG9mIGEgYnJvd3NlciBpbnN0YW5jZS5cbiAqIEByZXR1cm4ge29iamVjdH0gLSBBIGNsaXBwZWQgcmVnaW9uLlxuICovXG5jb25zdCBnZXRDbGlwUmVnaW9uID0gKHBhZ2UpID0+XG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICByZXR1cm4ge1xuICAgICAgeCxcbiAgICAgIHksXG4gICAgICB3aWR0aCxcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxuICAgIH07XG4gIH0pO1xuXG4vKipcbiAqIFJhc3Rlcml6ZXMgdGhlIHBhZ2UgdG8gYW4gaW1hZ2UgKFBORyBvciBKUEVHKVxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBwYWdlIC0gQSBwYWdlIG9mIGEgYnJvd3NlciBpbnN0YW5jZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIHR5cGUgb2YgYSByZXN1bHQgaW1hZ2UuXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBUaGUgdHlwZSBvZiBlbmNvZGluZyB1c2VkLlxuICogQHBhcmFtIHtzdHJpbmd9IGNsaXAgLSBUaGUgY2xpcCByZWdpb24uXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIEEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIGEgc2NyZWVuc2hvdC5cbiAqL1xuY29uc3QgY3JlYXRlSW1hZ2UgPSBhc3luYyAocGFnZSwgdHlwZSwgZW5jb2RpbmcsIGNsaXApID0+XG4gIGF3YWl0IFByb21pc2UucmFjZShbXG4gICAgcGFnZS5zY3JlZW5zaG90KHtcbiAgICAgIHR5cGUsXG4gICAgICBlbmNvZGluZyxcbiAgICAgIGNsaXAsXG5cbiAgICAgIC8vICM0NDcgLSBhbHdheXMgcmVuZGVyIG9uIGEgdHJhbnNwYXJlbnQgcGFnZVxuICAgICAgLy8gdGhpcyB3aWxsIG5vdCBhZmZlY3QgdXNlcnMgd2hvIGRvIG5vdCBleHBsaWNpdGx5IHNldFxuICAgICAgLy8gY2hhcnQuYmFja2dyb3VuZENvbG9yIHRvIGEgY29sb3Igd2l0aCBvcGFjaXR5IGxvd2VyIHRoYW4gMVxuICAgICAgb21pdEJhY2tncm91bmQ6IHRydWVcbiAgICB9KSxcbiAgICBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PlxuICAgICAgc2V0VGltZW91dCgoKSA9PiByZWplY3QobmV3IEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSksIDE1MDApXG4gICAgKVxuICBdKTtcblxuLyoqXG4gKiBUdXJucyBwYWdlIGludG8gYSBQREYuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IHBhZ2UgLSBBIHBhZ2Ugb2YgYSBicm93c2VyIGluc3RhbmNlLlxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFRoZSBoZWlnaHQgb2YgYSBjaGFydC5cbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFRoZSB3aWR0aCBvZiBhIGNoYXJ0LlxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gVGhlIHR5cGUgb2YgZW5jb2RpbmcgdXNlZC5cbiAqIEByZXR1cm4ge29iamVjdH0gLSBBIGJ1ZmZlciB3aXRoIFBERiByZXByZXNlbnRhdGlvbi5cbiAqL1xuY29uc3QgY3JlYXRlUERGID0gYXN5bmMgKHBhZ2UsIGhlaWdodCwgd2lkdGgsIGVuY29kaW5nKSA9PlxuICBhd2FpdCBwYWdlLnBkZih7XG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxuICAgIHdpZHRoLFxuICAgIGVuY29kaW5nXG4gIH0pO1xuXG4vKipcbiAqIEV4cG9ydHMgYXMgYSBTVkcuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IHBhZ2UgLSBBIHBhZ2Ugb2YgYSBicm93c2VyIGluc3RhbmNlLlxuICogQHJldHVybiB7b2JqZWN0fSAtIFRoZSBvdXRlckhUTUwgZWxlbWVudCB3aXRoIHRoZSBTVkcgcmVwcmVzZW50YXRpb24uXG4gKi9cbmNvbnN0IGNyZWF0ZVNWRyA9IGFzeW5jIChwYWdlKSA9PlxuICBhd2FpdCBwYWdlLiRldmFsKFxuICAgICcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcbiAgICAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUxcbiAgKTtcblxuLyoqIExvYWQgY29uZmlnIGludG8gYSBwYWdlIGFuZCByZW5kZXIgYSBjaGFydCAqL1xuY29uc3Qgc2V0QXNDb25maWcgPSBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+XG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgKGNoYXJ0LCBvcHRpb25zKSA9PiB3aW5kb3cudHJpZ2dlckV4cG9ydChjaGFydCwgb3B0aW9ucyksXG4gICAgY2hhcnQsXG4gICAgb3B0aW9uc1xuICApO1xuXG4vKiogTG9hZCBTVkcgaW50byBhIHBhZ2UgKi9cbi8vIGNvbnN0IHNldEFzU1ZHID0gYXN5bmMgKHBhZ2UsIHN2Z1N0cikgPT4gdHJ1ZTtcblxuLyoqXG4gKiBEb2VzIGFuIGV4cG9ydCBmb3IgYSBnaXZlbiBicm93c2VyLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBicm93c2VyIC0gQSBicm93c2VyIGluc3RhbmNlLlxuICogQHBhcmFtIHtvYmplY3R9IGNoYXJ0IC0gQ2hhcnQncyBvcHRpb25zLlxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBBbGwgb3B0aW9ucyBvYmplY3QuXG4gKiBAcmV0dXJuIHtvYmplY3R9IC0gVGhlIGRhdGEgcmV0dXJuZWQgZnJvbSBvbmUgb2YgdGhlIG1ldGhvZHMgZm9yIGV4cG9ydGluZ1xuICogYSBzcGVjaWZpYyB0eXBlIG9mIGFuIGltYWdlLlxuICovXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcbiAgLyoqXG4gICAqIEtlZXBzIHRyYWNrIG9mIGFsbCByZXNvdXJjZXMgYWRkZWQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRYWFhUYWcuIGV0Y1xuICAgKiBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xuICAgKiBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcbiAgICovXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XG5cbiAgLyoqIENsZWFyIG91dCBhbGwgc3RhdGUgc2V0IG9uIHRoZSBwYWdlIHdpdGggYWRkU2NyaXB0VGFnL2FkZFN0eWxlVGFnLiAqL1xuICBjb25zdCBjbGVhckluamVjdGVkID0gYXN5bmMgKHBhZ2UpID0+IHtcbiAgICBmb3IgKGNvbnN0IHJlcyBvZiBpbmplY3RlZFJlc291cmNlcykge1xuICAgICAgYXdhaXQgcmVzLmRpc3Bvc2UoKTtcbiAgICB9XG5cbiAgICAvLyBSZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICBjb25zdCBbLCAuLi5zY3JpcHRzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3NjcmlwdCcpO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcblxuICAgICAgLy8gUmVtb3ZlIHRhZ3NcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcbiAgICAgICAgLi4uc3R5bGVzVG9SZW1vdmUsXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcbiAgICAgIF0pIHtcbiAgICAgICAgZWxlbWVudC5yZW1vdmUoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfTtcblxuICB0cnkge1xuICAgIGNvbnN0IGV4cG9ydEJlbmNoID0gYmVuY2htYXJrKCdQdXBwZXRlZXInKTtcblxuICAgIGxvZyg0LCAnW2V4cG9ydF0gRGV0ZXJtaW5pbmcgZXhwb3J0IHBhdGguJyk7XG5cbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XG5cbiAgICAvLyBGb3JjZSBhIHJBRlxuICAgIC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vcHVwcGV0ZWVyL3B1cHBldGVlci9pc3N1ZXMvNzUwN1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKCgpID0+IHt9KSk7XG5cbiAgICAvLyBEZWNpZGUgd2hldGhlciBkaXNwbGF5IGVycm9yIG9yIGRlYmJ1Z2VyIHdyYXBwZXIgYXJvdW5kIGl0XG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XG4gICAgICBleHBvcnRPcHRpb25zPy5vcHRpb25zPy5jaGFydD8uZGlzcGxheUVycm9ycyAmJlxuICAgICAgY2FjaGUuZ2V0Q2FjaGUoKS5hY3RpdmVNYW5pZmVzdC5tb2R1bGVzLmRlYnVnZ2VyO1xuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoZCkgPT4gKHdpbmRvdy5fZGlzcGxheUVycm9ycyA9IGQpLCBkaXNwbGF5RXJyb3JzKTtcblxuICAgIGNvbnN0IHN2Z0JlbmNoID0gYmVuY2htYXJrKCdTVkcgaGFuZGxpbmcnKTtcblxuICAgIGxldCBpc1NWRztcblxuICAgIGlmIChcbiAgICAgIGNoYXJ0LmluZGV4T2YgJiZcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXG4gICAgKSB7XG4gICAgICAvLyBTVkcgSU5QVVQgSEFORExJTkdcblxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcuJyk7XG5cbiAgICAgIC8vIElmIGlucHV0IGlzIGFsc28gc3ZnLCBqdXN0IHJldHVybiBpdFxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xuICAgICAgfVxuXG4gICAgICBpc1NWRyA9IHRydWU7XG4gICAgICBjb25zdCBzZXRQYWdlQmVuY2ggPSBiZW5jaG1hcmsoJ1NldHRpbmcgY29udGVudCcpO1xuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGNoYXJ0KSk7XG4gICAgICBzZXRQYWdlQmVuY2goKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gSlNPTiBDb25maWcgaGFuZGxpbmdcblxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XG5cbiAgICAgIC8vIE5lZWQgdG8gcGVyZm9ybSBzdHJhaWdodCBpbmplY3RcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xuICAgICAgICAvLyBJbmplY3Rpb24gYmFzZWQgY29uZmlndXJhdGlvbiBleHBvcnRcbiAgICAgICAgY29uc3Qgc2V0UGFnZUJlbmNoID0gYmVuY2htYXJrKCdTZXR0aW5nIHBhZ2UgY29udGVudCAoaW5qZWN0KScpO1xuXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxuICAgICAgICAgIHBhZ2UsXG4gICAgICAgICAge1xuICAgICAgICAgICAgY2hhcnQ6IHtcbiAgICAgICAgICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcbiAgICAgICAgICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgKTtcblxuICAgICAgICBzZXRQYWdlQmVuY2goKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEJhc2ljIGNvbmZpZ3VyYXRpb24gZXhwb3J0XG5cbiAgICAgICAgY2hhcnQuY2hhcnQuaGVpZ2h0ID0gZXhwb3J0T3B0aW9ucy5oZWlnaHQ7XG4gICAgICAgIGNoYXJ0LmNoYXJ0LndpZHRoID0gZXhwb3J0T3B0aW9ucy53aWR0aDtcblxuICAgICAgICBjb25zdCBzZXRDb250ZW50QmVuY2ggPSBiZW5jaG1hcmsoJ1NldHRpbmcgcGFnZSBjb250ZW50IChjb25maWcpJyk7XG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKHBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcbiAgICAgICAgc2V0Q29udGVudEJlbmNoKCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgc3ZnQmVuY2goKTtcbiAgICBjb25zdCByZXNCZW5jaCA9IGJlbmNobWFyaygnQXBwbHlpbmcgcmVzb3VyY2VzJyk7XG5cbiAgICAvLyBVc2UgcmVzb3VyY2VzXG4gICAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Db2RlLnJlc291cmNlcztcbiAgICBpZiAocmVzb3VyY2VzKSB7XG4gICAgICAvLyBMb2FkIGN1c3RvbSBKUyBjb2RlXG4gICAgICBpZiAocmVzb3VyY2VzLmpzKSB7XG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXG4gICAgICAgICAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoe1xuICAgICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmpzXG4gICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xuICAgICAgaWYgKHJlc291cmNlcy5maWxlcykge1xuICAgICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGlzTG9jYWwgPSAhZmlsZS5zdGFydHNXaXRoKCdodHRwJykgPyB0cnVlIDogZmFsc2U7XG5cbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBzY3JpcHQgZnJvbSByZXNvdXJjZXMnIGZpbGVzXG4gICAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxuICAgICAgICAgICAgICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhcbiAgICAgICAgICAgICAgICBpc0xvY2FsXG4gICAgICAgICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICA6IHtcbiAgICAgICAgICAgICAgICAgICAgICB1cmw6IGZpbGVcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gY2F0Y2ggKG5vdGljZSkge1xuICAgICAgICAgICAgbG9nKDQsICdbZXhwb3J0XSBKUyBmaWxlIG5vdCBmb3VuZC4nKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgY29uc3QgY3NzQmVuY2ggPSBiZW5jaG1hcmsoJ0xvYWRpbmcgY3NzJyk7XG5cbiAgICAgIC8vIExvYWQgQ1NTXG4gICAgICBpZiAocmVzb3VyY2VzLmNzcykge1xuICAgICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XG4gICAgICAgIGlmIChjc3NJbXBvcnRzKSB7XG4gICAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXG4gICAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XG4gICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xuICAgICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxuICAgICAgICAgICAgICAgIC50cmltKCk7XG5cbiAgICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIGNzcyBmcm9tIHJlc291cmNlc1xuICAgICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aC5zdGFydHNXaXRoKCdodHRwJykpIHtcbiAgICAgICAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxuICAgICAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XG4gICAgICAgICAgICAgICAgICAgIHVybDogY3NzSW1wb3J0UGF0aFxuICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMuY3VzdG9tQ29kZS5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcbiAgICAgICAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxuICAgICAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyh7XG4gICAgICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Jhc2VkaXIsIGNzc0ltcG9ydFBhdGgpXG4gICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBUaGUgcmVzdCBvZiB0aGUgQ1NTIHNlY3Rpb24gd2lsbCBiZSBjb250ZW50IGJ5IG5vd1xuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxuICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoe1xuICAgICAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcbiAgICAgICAgICB9KVxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBjc3NCZW5jaCgpO1xuICAgIH1cblxuICAgIHJlc0JlbmNoKCk7XG5cbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZVxuICAgIGNvbnN0IHNpemUgPSBpc1NWR1xuICAgICAgPyBhd2FpdCBwYWdlLiRldmFsKFxuICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcbiAgICAgICAgICBhc3luYyAoZWxlbWVudCwgc2NhbGUpID0+IHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgIGNoYXJ0SGVpZ2h0OiBlbGVtZW50LmhlaWdodC5iYXNlVmFsLnZhbHVlICogc2NhbGUsXG4gICAgICAgICAgICAgIGNoYXJ0V2lkdGg6IGVsZW1lbnQud2lkdGguYmFzZVZhbC52YWx1ZSAqIHNjYWxlXG4gICAgICAgICAgICB9O1xuICAgICAgICAgIH0sXG4gICAgICAgICAgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxuICAgICAgICApXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXG4gICAgICAgICAgICBjaGFydFdpZHRoXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG5cbiAgICBjb25zdCB2cEJlbmNoID0gYmVuY2htYXJrKCdTZXR0aW5nIHZpZXdwb3J0Jyk7XG5cbiAgICAvLyBTZXQgZmluYWwgaGVpZ2h0IGFuZCB3aWR0aCBmb3Igdmlld3BvcnRcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguY2VpbChzaXplPy5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguY2VpbChzaXplPy5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpO1xuXG4gICAgLy8gU2V0IHRoZSB2aWV3cG9ydCBmb3IgdGhlIGZpcnN0IHRpbWVcbiAgICAvLyBOT1RFOiB0aGUgY2FsbCB0byBzZXRWaWV3cG9ydCBpcyBleHBlbnNpdmUgLSBjYW4gd2UgZ2V0IGF3YXkgd2l0aCBvbmx5XG4gICAgLy8gY2FsbGluZyBpdCBvbmNlLCBlLmcuIG1vdmluZyB0aGlzIG9uZSBpbnRvIHRoZSBpc1NWRyBjb25kaXRpb24gYmVsb3c/XG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxuICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxuICAgIH0pO1xuXG4gICAgLy8gUHJlcGFyZSBhIHpvb20gY2FsbGJhY2sgZm9yIHRoZSBuZXh0IGV2YWx1YXRlIGNhbGxcbiAgICBjb25zdCB6b29tQ2FsbGJhY2sgPSBpc1NWR1xuICAgICAgPyAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxuICAgICAgICAoc2NhbGUpID0+IHtcbiAgICAgICAgICAvLyBTZXQgdGhlIHpvb20gYXMgc2NhbGVcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcblxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUubWFyZ2luID0gJzBweCc7XG4gICAgICAgIH1cbiAgICAgIDogLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlcyBvZiBleHBvcnRzXG4gICAgICAgICgpID0+IHtcbiAgICAgICAgICAvLyBSZXNldCB0aGUgem9vbSBmb3Igb3RoZXIgZXhwb3J0cyB0aGFuIHRvIFNWR3NcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xuICAgICAgICB9O1xuXG4gICAgLy8gU2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSh6b29tQ2FsbGJhY2ssIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpO1xuXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcbiAgICBjb25zdCB7IGhlaWdodCwgd2lkdGgsIHgsIHkgfSA9IGF3YWl0IGdldENsaXBSZWdpb24ocGFnZSk7XG5cbiAgICBpZiAoIWlzU1ZHKSB7XG4gICAgICAvLyBTZXQgdGhlIGZpbmFsIHZpZXdwb3J0IG5vdyB0aGF0IHdlIGhhdmUgdGhlIHJlYWwgaGVpZ2h0XG4gICAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcbiAgICAgICAgd2lkdGg6IE1hdGgucm91bmQod2lkdGgpLFxuICAgICAgICBoZWlnaHQ6IE1hdGgucm91bmQoaGVpZ2h0KSxcbiAgICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHZwQmVuY2goKTtcblxuICAgIGxldCBkYXRhO1xuXG4gICAgY29uc3QgZXhwQmVuY2htYXJrID0gYmVuY2htYXJrKCdSYXN0ZXJpemluZyBjaGFydCcpO1xuXG4gICAgLy8gUkFTVEVSSVpBVElPTlxuICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XG4gICAgICAvLyBTVkdcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVTVkcocGFnZSk7XG4gICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdwbmcnIHx8IGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ2pwZWcnKSB7XG4gICAgICAvLyBQTkcgb3IgSlBFR1xuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZUltYWdlKHBhZ2UsIGV4cG9ydE9wdGlvbnMudHlwZSwgJ2Jhc2U2NCcsIHtcbiAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXG4gICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXG4gICAgICAgIHgsXG4gICAgICAgIHlcbiAgICAgIH0pO1xuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncGRmJykge1xuICAgICAgLy8gUERGXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlUERGKHBhZ2UsIHZpZXdwb3J0SGVpZ2h0LCB2aWV3cG9ydFdpZHRoLCAnYmFzZTY0Jyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IGBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0ICR7ZXhwb3J0T3B0aW9ucy50eXBlfWA7XG4gICAgfVxuXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIHRoZSBleHBvcnQgaXMgZG9uZVxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcblxuICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXG4gICAgICBpZiAob2xkQ2hhcnRzLmxlbmd0aCkge1xuICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcbiAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcbiAgICAgICAgICBvbGRDaGFydCAmJiBvbGRDaGFydC5kZXN0cm95KCk7XG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgZXhwQmVuY2htYXJrKCk7XG4gICAgZXhwb3J0QmVuY2goKTtcblxuICAgIGF3YWl0IGNsZWFySW5qZWN0ZWQocGFnZSk7XG5cbiAgICByZXR1cm4gZGF0YTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBhd2FpdCBjbGVhckluamVjdGVkKHBhZ2UpO1xuICAgIGxvZygxLCBgW2V4cG9ydF0gRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtlcnJvcn1gKTtcblxuICAgIHJldHVybiBlcnJvcjtcbiAgfVxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMiwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5jb25zdCB0aW1lcnMgPSB7fTtcblxuLy8gVE9ETzogUmVhZCBmcm9tIGNvbmZpZ1xubGV0IGVuYWJsZWQgPSBmYWxzZTtcblxuZXhwb3J0IGRlZmF1bHQgKGlkKSA9PiB7XG4gIGlmICghZW5hYmxlZCkge1xuICAgIHJldHVybiAoKSA9PiB7fTtcbiAgfVxuXG4gIHRpbWVyc1tpZF0gPSBuZXcgRGF0ZSgpO1xuICByZXR1cm4gKCkgPT4ge1xuICAgIGxvZyhcbiAgICAgIDMsXG4gICAgICBgW2JlbmNobWFya10gLSAke2lkfTogJHtuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHRpbWVyc1tpZF0uZ2V0VGltZSgpfW1zYFxuICAgICk7XG4gIH07XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XG5cbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxuPCFET0NUWVBFIGh0bWw+XG48aHRtbCBsYW5nPSdlbi1VUyc+XG4gIDxoZWFkPlxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XG4gICAgPHRpdGxlPkhpZ2hjYXJ0cyBFeHBvcnQ8L3RpdGxlPlxuICA8L2hlYWQ+XG4gIDxzdHlsZT5cbiAgICAke2Nzc1RlbXBsYXRlKCl9XG4gIDwvc3R5bGU+XG4gIDxib2R5PlxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cbiAgICAgICR7Y2hhcnR9XG4gICAgPC9kaXY+XG4gIDwvYm9keT5cbjwvaHRtbD5cblxuYDtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XG5pbXBvcnQgeyBQb29sIH0gZnJvbSAndGFybic7XG5pbXBvcnQge1xuICBjbG9zZSxcbiAgbmV3UGFnZSBhcyBicm93c2VyTmV3UGFnZSxcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXJcbn0gZnJvbSAnLi9icm93c2VyLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcblxuaW1wb3J0IHB1cHBldGVlckV4cG9ydCBmcm9tICcuL2V4cG9ydC5qcyc7XG5cbmxldCBwZXJmb3JtZWRFeHBvcnRzID0gMDtcbmxldCBleHBvcnRBdHRlbXB0cyA9IDA7XG5sZXQgdGltZVNwZW50ID0gMDtcbmxldCBkcm9wcGVkRXhwb3J0cyA9IDA7XG5sZXQgc3BlbnRBdmVyYWdlID0gMDtcbmxldCBwb29sQ29uZmlnID0ge307XG5cbi8vIFRoZSBwb29sIGluc3RhbmNlXG5sZXQgcG9vbCA9IGZhbHNlO1xuXG4vLyBDdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50c1xubGV0IHB1cHBldGVlckFyZ3M7XG5cbmNvbnN0IGZhY3RvcnkgPSB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmV3IHdvcmtlci5cbiAgICpcbiAgICogQHJldHVybiB7b2JqZWN0fSAtIEFuIG9iamVjdCB3aXRoIHRoZSBpZCBvZiBhIHJlc291cmNlLCB0aGUgd29yayBjb3VudCBhbmRcbiAgICogYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZS5cbiAgICovXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xuICAgIGNvbnN0IGlkID0gdXVpZCgpO1xuICAgIGxldCBwYWdlID0gZmFsc2U7XG5cbiAgICBjb25zdCBzID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgICB0cnkge1xuICAgICAgcGFnZSA9IGF3YWl0IGJyb3dzZXJOZXdQYWdlKCk7XG5cbiAgICAgIGlmICghcGFnZSB8fCBwYWdlLmlzQ2xvc2VkKCkpIHtcbiAgICAgICAgdGhyb3cgJ2ludmFsaWQgcGFnZSc7XG4gICAgICB9XG5cbiAgICAgIGxvZyhcbiAgICAgICAgMyxcbiAgICAgICAgYFtwb29sXSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciAke2lkfSAtIHRvb2sgJHtcbiAgICAgICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHNcbiAgICAgICAgfSBtcy5gXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2coXG4gICAgICAgIDEsXG4gICAgICAgIGBbcG9vbF0gRXJyb3IgY3JlYXRpbmcgYSBuZXcgcGFnZSBpbiBwb29sIGVudHJ5IGNyZWF0aW9uISAke2Vycm9yfWBcbiAgICAgICk7XG5cbiAgICAgIHRocm93ICdFcnJvciBjcmVhdGluZyBwYWdlJztcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgaWQsXG4gICAgICBwYWdlLFxuICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxuICAgICAgd29ya0NvdW50OiBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAocG9vbENvbmZpZy53b3JrTGltaXQgLyAyKSlcbiAgICB9O1xuICB9LFxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgYSB3b3JrZXIuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBBIGJyb3dzZXIncyBpbnN0YW5jZS5cbiAgICpcbiAgICogQHJldHVybiB7Ym9vbGVhbn0gLSBCb29sIHRoYXQgaW5kaWNhdGVzIGlmIGEgcmVzb3VyY2UgaXMgdmFsaWQgb3Igbm90LlxuICAgKi9cbiAgdmFsaWRhdGU6ICh3b3JrZXJIYW5kbGUpID0+IHtcbiAgICBpZiAoXG4gICAgICBwb29sQ29uZmlnLndvcmtMaW1pdCAmJlxuICAgICAgKyt3b3JrZXJIYW5kbGUud29ya0NvdW50ID4gcG9vbENvbmZpZy53b3JrTGltaXRcbiAgICApIHtcbiAgICAgIGxvZyhcbiAgICAgICAgMyxcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246YCxcbiAgICAgICAgYGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KWBcbiAgICAgICk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9LFxuXG4gIC8qKlxuICAgKiBEZXN0cm95cyBhIHdvcmtlci5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IHdvcmtlckhhbmRsZSAtIEEgYnJvd3NlcidzIGluc3RhbmNlLlxuICAgKi9cbiAgZGVzdHJveTogKHdvcmtlckhhbmRsZSkgPT4ge1xuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XG5cbiAgICBpZiAod29ya2VySGFuZGxlLnBhZ2UpIHtcbiAgICAgIC8vIFdlIGRvbid0IHJlYWxseSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzLlxuICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcbiAgICB9XG4gIH0sXG5cbiAgLy8gTG9nZ2VyIGZ1bmN0aW9uXG4gIGxvZzogKG1lc3NhZ2UsIGxvZ0xldmVsKSA9PiBjb25zb2xlLmxvZyhgJHtsb2dMZXZlbH06ICR7bWVzc2FnZX1gKVxufTtcblxuLyoqXG4gKiBJbml0cyB0aGUgcG9vbCBvZiByZXNvdXJjZXMuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyAtIFBvb2wgY29uZmlndXJhdGlvbiBhbG9uZyB3aXRoIGN1c3RvbSBwdXBwZXRlZXJcbiAqIGFyZ3VtZW50cyBmb3IgdGhlIHB1cHBldGVlci5sYXVuY2ggZnVuY3Rpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBpbml0ID0gYXN5bmMgKGNvbmZpZykgPT4ge1xuICAvLyBUaGUgbmV3ZXN0IHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBicm93c2VyIGNyZWF0aW9uXG4gIHB1cHBldGVlckFyZ3MgPSBjb25maWcucHVwcGV0ZWVyQXJncztcblxuICAvLyBXYWl0IHVudGlsIHdlJ3ZlIHN1Y2Vzc2Z1bGx5IGNyZWF0ZWQgYSBicm93c2VyIGluc3RhbmNlLlxuICB0cnkge1xuICAgIGF3YWl0IGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncyk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBsb2coMCwgJ1twb29sfGJyb3dzZXJdJywgZSk7XG4gIH1cblxuICAvLyBGb3IgdGhlIG1vZHVsZSBzY29wZSB1c2FnZVxuICBwb29sQ29uZmlnID0gY29uZmlnICYmIGNvbmZpZy5wb29sID8geyAuLi5jb25maWcucG9vbCB9IDoge307XG5cbiAgbG9nKFxuICAgIDMsXG4gICAgJ1twb29sXSBJbml0aWFsaXppbmcgcG9vbDonLFxuICAgIGBtaW4gJHtwb29sQ29uZmlnLmluaXRpYWxXb3JrZXJzfSwgbWF4ICR7cG9vbENvbmZpZy5tYXhXb3JrZXJzfS5gXG4gICk7XG5cbiAgaWYgKHBvb2wpIHtcbiAgICByZXR1cm4gbG9nKFxuICAgICAgNCxcbiAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXG4gICAgKTtcbiAgfVxuXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xuICBpZiAocG9vbENvbmZpZy5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xuICAgIGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XG4gIH1cblxuICB0cnkge1xuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xuICAgIHBvb2wgPSBuZXcgUG9vbCh7XG4gICAgICAvLyBHZXQgdGhlIGNyZWF0ZS92YWxpZGF0ZS9kZXN0cm95L2xvZyBmdW5jdGlvbnNcbiAgICAgIC4uLmZhY3RvcnksXG4gICAgICBtaW46IHBvb2xDb25maWcuaW5pdGlhbFdvcmtlcnMsXG4gICAgICBtYXg6IHBvb2xDb25maWcubWF4V29ya2VycyxcbiAgICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXM6IDIwMCxcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXG4gICAgICBhY3F1aXJlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5hY3F1aXJlVGltZW91dCxcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxuICAgICAgaWRsZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcudGltZW91dFRocmVzaG9sZCxcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogMTAwMCwgLy8gcG9vbENvbmZpZy5yZWFwZXIgPyAxMjAwMDAgOiAwLCBmb3Igbm93XG4gICAgICBwcm9wYWdhdGVDcmVhdGVFcnJvcjogZmFsc2VcbiAgICB9KTtcblxuICAgIC8vIFNldCBldmVudHNcbiAgICBwb29sLm9uKCdjcmVhdGVGYWlsJywgKGV2ZW50SWQsIGVycikgPT4ge1xuICAgICAgbG9nKFxuICAgICAgICAxLFxuICAgICAgICBgW3Bvb2xdIEVycm9yIHdoZW4gY3JlYXRpbmcgd29ya2VyIG9mIGFuIGV2ZW50IGlkICR7ZXZlbnRJZH06YCxcbiAgICAgICAgZXJyXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgcG9vbC5vbignYWNxdWlyZUZhaWwnLCAoZXZlbnRJZCwgZXJyKSA9PiB7XG4gICAgICBsb2coXG4gICAgICAgIDEsXG4gICAgICAgIGBbcG9vbF0gRXJyb3Igd2hlbiBhY3F1aXJpbmcgd29ya2VyIG9mIGFuIGV2ZW50IGlkICR7ZXZlbnRJZH06YCxcbiAgICAgICAgZXJyXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgcG9vbC5vbignZGVzdHJveUZhaWwnLCAoZXZlbnRJZCwgcmVzb3VyY2UsIGVycikgPT4ge1xuICAgICAgbG9nKFxuICAgICAgICAxLFxuICAgICAgICBgW3Bvb2xdIEVycm9yIHdoZW4gZGVzdHJveWluZyB3b3JrZXIgb2YgYW4gaWQgJHtyZXNvdXJjZS5pZH0sIGV2ZW50IGlkICR7ZXZlbnRJZH06YCxcbiAgICAgICAgZXJyXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgcG9vbC5vbigncmVsZWFzZScsIChyZXNvdXJjZSkgPT4ge1xuICAgICAgbG9nKDQsIGBbcG9vbF0gUmVsZWFzaW5nIGEgd29ya2VyIG9mIGFuIGlkICR7cmVzb3VyY2UuaWR9YCk7XG4gICAgfSk7XG5cbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xuICAgICAgbG9nKDQsIGBbcG9vbF0gRGVzdHJveWVkIGEgd29ya2VyIG9mIGFuIGlkICR7cmVzb3VyY2UuaWR9YCk7XG4gICAgfSk7XG5cbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XG4gICAgLy8gQ3JlYXRlIGFuIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlc1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbENvbmZpZy5pbml0aWFsV29ya2VyczsgaSsrKSB7XG4gICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2goYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZSk7XG4gICAgfVxuXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xuICAgIH0pO1xuXG4gICAgbG9nKFxuICAgICAgMyxcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkgd2l0aCAke3Bvb2xDb25maWcuaW5pdGlhbFdvcmtlcnN9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYFxuICAgICk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbG9nKDEsIGBbcG9vbF0gQ291bGRuJ3QgY3JlYXRlIHRoZSB3b3JrZXIgcG9vbCAke2Vycm9yfWApO1xuICAgIHRocm93IGVycm9yO1xuICB9XG59O1xuXG4vKipcbiAqIEF0dGFjaGVzIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKSB7XG4gIGxvZyg0LCAnW3Bvb2xdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcblxuICAvLyBLaWxsIGFsbCBwb29sIHJlc291cmNlcyBvbiBleGl0XG4gIHByb2Nlc3Mub24oJ2V4aXQnLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQga2lsbFBvb2woKTtcbiAgfSk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlIFNJR0lOVFxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCAobmFtZSwgY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfSk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlIFNJR1RFUk1cbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIChuYW1lLCBjb2RlKSA9PiB7XG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XG4gICAgcHJvY2Vzcy5leGl0KDEpO1xuICB9KTtcblxuICAvLyBIYW5kbGVyIGZvciB0aGUgdW5jYXVnaHRFeGNlcHRpb25cbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGVycm9yLCBtZXNzYWdlOiAke2Vycm9yLm1lc3NhZ2V9LmApO1xuICB9KTtcbn1cblxuLyoqXG4gKiBLaWxscyB0aGUgcG9vbCBhbmQgZmx1c2ggdGhlIGJyb3dzZXIgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBhbGwgd29ya2Vycy4nKTtcblxuICAvLyBSZXR1cm4gdHJ1ZSB3aGVuIHRoZSBwb29sIGlzIGFscmVhZHkgZGVzdHJveWVkXG4gIGlmIChwb29sLmRlc3Ryb3llZCkge1xuICAgIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlIGlmIHN0aWxsIGNvbm5lY3RlZFxuICAgIGF3YWl0IGNsb3NlKCk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICAvLyBJZiBzdGlsbCBhbGl2ZSwgZGVzdHJveSB0aGUgcG9vbCBvZiBwYWdlcyBiZWZvcmUgY2xvc2luZyBhIGJyb3dzZXJcbiAgYXdhaXQgcG9vbC5kZXN0cm95KCk7XG5cbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcbiAgYXdhaXQgY2xvc2UoKTtcbiAgcmV0dXJuIHRydWU7XG59XG5cbi8qKlxuICogUG9zdHMgd29yayB0byB0aGUgcG9vbC5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gY2hhcnQgLSBDaGFydCdzIG9wdGlvbnMuXG4gKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIEFsbCBvcHRpb25zIG9iamVjdC5cbiAqL1xuZXhwb3J0IGNvbnN0IHBvc3RXb3JrID0gYXN5bmMgKGNoYXJ0LCBvcHRpb25zKSA9PiB7XG4gIGxldCB3b3JrZXJIYW5kbGU7XG5cbiAgLy8gSGFuZGxlIGZhaWwgY29uZGl0aW9uc1xuICBjb25zdCBmYWlsID0gKG1zZykgPT4ge1xuICAgICsrZHJvcHBlZEV4cG9ydHM7XG5cbiAgICBpZiAod29ya2VySGFuZGxlKSB7XG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcbiAgICB9XG5cbiAgICB0aHJvdyAnSW4gcG9vbC5wb3N0V29yazogJyArIG1zZztcbiAgfTtcblxuICBsb2coNCwgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBzdGFydGluZyB0byBwcm9jZXNzLicpO1xuXG4gIGlmIChwb29sQ29uZmlnLmJlbmNobWFya2luZykge1xuICAgIGdldFBvb2xJbmZvKCk7XG4gIH1cblxuICArK2V4cG9ydEF0dGVtcHRzO1xuXG4gIGlmICghcG9vbCkge1xuICAgIGxvZygxLCAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicpO1xuICAgIHJldHVybiBmYWlsKCdQb29sIGlzIG5vdCBpbml0ZWQgYnV0IHdvcmsgd2FzIHBvc3RlZCB0byBpdCEnKTtcbiAgfVxuXG4gIC8vIEFjcXVpcmUgdGhlIHdvcmtlciBhbG9uZyB3aXRoIHRoZSBpZCBvZiByZXNvdXJjZSBhbmQgd29yayBjb3VudFxuICB0cnkge1xuICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmluZyB3b3JrZXInKTtcbiAgICB3b3JrZXJIYW5kbGUgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHJldHVybiBmYWlsKGBbcG9vbF0gRXJyb3Igd2hlbiBhY3F1aXJpbmcgYXZhaWxhYmxlIGVudHJ5OiAke2Vycm9yfWApO1xuICB9XG5cbiAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgd29ya2VyIGhhbmRsZScpO1xuXG4gIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcbiAgICByZXR1cm4gZmFpbCgnUmVzb2x2ZWQgd29ya2VyIHBhZ2UgaXMgaW52YWxpZDogcG9vbCBzZXR1cCBpcyB3b25reScpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBTYXZlIHRoZSBzdGFydCB0aW1lXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuXG4gICAgbG9nKDQsIGBbcG9vbF0gU3RhcnRpbmcgd29yayBvbiBwb29sIGVudHJ5ICR7d29ya2VySGFuZGxlLmlkfS5gKTtcblxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KHdvcmtlckhhbmRsZS5wYWdlLCBjaGFydCwgb3B0aW9ucyk7XG5cbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAvLyBUT0RPOiBJZiB0aGUgZXhwb3J0IGZhaWxlZCBiZWNhdXNlIHB1cHBldGVlciB0aW1lZCBvdXQsIHdlIG5lZWQgdG8gZm9yY2Uga2lsbCB0aGUgd29ya2VyIHNvIHdlIGdldCBhIG5ldyBwYWdlLiBUaGF0IG5lZWRzIHRvIGJlIGhhbmRsZWQgYmV0dGVyIHRoYW4gdGhpcyBoYWNrLlxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZSA9IGF3YWl0IGJyb3dzZXJOZXdQYWdlKCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBmYWlsKHJlc3VsdCk7XG4gICAgfVxuXG4gICAgLy8gUmVsZWFzZSB0aGUgcmVzb3VyY2UgYmFjayB0byB0aGUgcG9vbFxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xuXG4gICAgLy8gVXNlZCBmb3Igc3RhdGlzdGljcyBpbiBhdmVyYWdlVGltZSBhbmQgcHJvY2Vzc2VkV29ya0NvdW50LCB3aGljaFxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cbiAgICBjb25zdCB3b3JrRW5kID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XG4gICAgdGltZVNwZW50ICs9IGV4cG9ydFRpbWU7XG4gICAgc3BlbnRBdmVyYWdlID0gdGltZVNwZW50IC8gKytwZXJmb3JtZWRFeHBvcnRzO1xuXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfSBtcy5gKTtcblxuICAgIC8vIE90aGVyd2lzZSByZXR1cm4gdGhlIHJlc3VsdFxuICAgIHJldHVybiB7XG4gICAgICBkYXRhOiByZXN1bHQsXG4gICAgICBvcHRpb25zXG4gICAgfTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBmYWlsKGBFcnJvciB0cnlpbmcgdG8gcGVyZm9ybSBwdXBwZXRlZXIgZXhwb3J0OiAke2Vycm9yfS5gKTtcbiAgfVxufTtcblxuLyoqXG4gKiBHZXRzIHRoZSBwb29sLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbCgpIHtcbiAgcmV0dXJuIHBvb2w7XG59XG5cbmV4cG9ydCBjb25zdCBnZXRQb29sSW5mb0pTT04gPSAoKSA9PiAoe1xuICBtaW46IHBvb2wubWluLFxuICBtYXg6IHBvb2wubWF4LFxuICBzaXplOiBwb29sLnNpemUsXG4gIGF2YWlsYWJsZTogcG9vbC5hdmFpbGFibGUsXG4gIGJvcnJvd2VkOiBwb29sLmJvcnJvd2VkLFxuICBwZW5kaW5nOiBwb29sLnBlbmRpbmcsXG4gIHNwYXJlUmVzb3VyY2VDYXBhY2l0eTogcG9vbC5zcGFyZVJlc291cmNlQ2FwYWNpdHlcbn0pO1xuXG4vKipcbiAqIEdldHMgdGhlIHBvb2wncyBpbmZvcm1hdGlvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xuICBjb25zdCB7XG4gICAgbWluLFxuICAgIG1heCxcbiAgICBzaXplLFxuICAgIGF2YWlsYWJsZSxcbiAgICBib3Jyb3dlZCxcbiAgICBwZW5kaW5nLFxuICAgIHNwYXJlUmVzb3VyY2VDYXBhY2l0eVxuICB9ID0gcG9vbDtcblxuICBsb2coNCwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xuICBsb2coNCwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xuICBsb2coXG4gICAgNCxcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIHJlc291cmNlcyBpbiBwb29sIChmcmVlIG9yIGluIHVzZSk6ICR7c2l6ZX0uYFxuICApO1xuICBsb2coXG4gICAgNCxcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHRoYXQgYXJlIGN1cnJlbnRseSBhdmFpbGFibGU6ICR7YXZhaWxhYmxlfS5gXG4gICk7XG4gIGxvZyhcbiAgICA0LFxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgdGhhdCBhcmUgY3VycmVudGx5IGFjcXVpcmVkOiAke2JvcnJvd2VkfS5gXG4gICk7XG4gIGxvZyhcbiAgICA0LFxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiBjYWxsZXJzIHdhaXRpbmcgdG8gYWNxdWlyZSBhIHJlc291cmNlOiAke3BlbmRpbmd9LmBcbiAgKTtcbiAgbG9nKFxuICAgIDQsXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGhvdyBtYW55IG1vcmUgcmVzb3VyY2VzIGNhbiB0aGUgcG9vbCBtYW5hZ2UvY3JlYXRlOiAke3NwYXJlUmVzb3VyY2VDYXBhY2l0eX0uYFxuICApO1xufVxuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGluaXQsXG4gIGtpbGxQb29sLFxuICBwb3N0V29yayxcbiAgZ2V0UG9vbCxcbiAgZ2V0UG9vbEluZm8sXG4gIGdldFBvb2xJbmZvSlNPTixcbiAgd29ya0F0dGVtcHRzOiAoKSA9PiBleHBvcnRBdHRlbXB0cyxcbiAgZHJvcHBlZFdvcms6ICgpID0+IGRyb3BwZWRFeHBvcnRzLFxuICBhdmVyYWdlVGltZTogKCkgPT4gc3BlbnRBdmVyYWdlLFxuICBwcm9jZXNzZWRXb3JrQ291bnQ6ICgpID0+IHBlcmZvcm1lZEV4cG9ydHNcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IGNhY2hlIGZyb20gJy4uLy4uL2NhY2hlLmpzJztcbmltcG9ydCBwb29sIGZyb20gJy4uLy4uL3Bvb2wuanMnO1xuXG5jb25zdCBwYWNrYWdlVmVyc2lvbiA9IHByb2Nlc3MuZW52Lm5wbV9wYWNrYWdlX3ZlcnNpb247XG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xuXG4vKipcbiAqIEFkZHMgdGhlIC9oZWFsdGggcm91dGUgd2hpY2ggb3V0cHV0cyBiYXNpYyBzdGF0cyBmb3IgdGhlIHNlcnZlclxuICovXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxuICAhYXBwXG4gICAgPyBmYWxzZVxuICAgIDogYXBwLmdldCgnL2hlYWx0aCcsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgICAgICByZXNwb25zZS5zZW5kKHtcbiAgICAgICAgICBzdGF0dXM6ICdPSycsXG4gICAgICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcbiAgICAgICAgICB1cHRpbWU6XG4gICAgICAgICAgICBNYXRoLmZsb29yKFxuICAgICAgICAgICAgICAobmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MFxuICAgICAgICAgICAgKSArICcgbWludXRlcycsXG4gICAgICAgICAgdmVyc2lvbjogcGFja2FnZVZlcnNpb24sXG4gICAgICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGNhY2hlLnZlcnNpb24oKSxcbiAgICAgICAgICBhdmVyYWdlUHJvY2Vzc2luZ1RpbWU6IHBvb2wuYXZlcmFnZVRpbWUoKSxcbiAgICAgICAgICBwZXJmb3JtZWRFeHBvcnRzOiBwb29sLnByb2Nlc3NlZFdvcmtDb3VudCgpLFxuICAgICAgICAgIGZhaWxlZEV4cG9ydHM6IHBvb2wuZHJvcHBlZFdvcmsoKSxcbiAgICAgICAgICBleHBvcnRBdHRlbXB0czogcG9vbC53b3JrQXR0ZW1wdHMoKSxcbiAgICAgICAgICBzdWNlc3NSYXRpbzogKHBvb2wucHJvY2Vzc2VkV29ya0NvdW50KCkgLyBwb29sLndvcmtBdHRlbXB0cygpKSAqIDEwMCxcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXG4gICAgICAgICAgcG9vbDogcG9vbC5nZXRQb29sSW5mb0pTT04oKVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcblxuaW1wb3J0IHByb21wdHMgZnJvbSAncHJvbXB0cyc7XG5cbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IGRlZXBDb3B5LCBpc09iamVjdCwgcHJpbnRVc2FnZSwgdG9Cb29sZWFuIH0gZnJvbSAnLi91dGlscy5qcyc7XG5pbXBvcnQge1xuICBhYnNvbHV0ZVByb3BzLFxuICBkZWZhdWx0Q29uZmlnLFxuICBuZXN0ZWRBcmdzLFxuICBwcm9tcHRzQ29uZmlnXG59IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xuXG5sZXQgZ2VuZXJhbE9wdGlvbnMgPSB7fTtcblxuLyoqXG4gKiBHZXR0ZXIgZm9yIHRoZSBnZW5lcmFsIG9wdGlvbnMuXG4gKlxuICogQHJldHVybiB7b2JqZWN0fSAtIEdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRPcHRpb25zID0gKCkgPT4gZ2VuZXJhbE9wdGlvbnM7XG5cbi8qKlxuICogSW5pdGlhbGl6ZXMgYW5kIHNldHMgdGhlIGdlbmVyYWwgb3B0aW9ucyBmb3IgdGhlIHNlcnZlciBpbnN0YWNlLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSB1c2VyT3B0aW9ucyAtIEFkZGl0aW9uYWwgdXNlciBvcHRpb25zIChlLmcuIGZyb20gdGhlIG5vZGVcbiAqIG1vZHVsZSB1c2FnZSkuXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSBhcmdzIC0gQ0xJIGFyZ3VtZW50cy5cbiAqIEByZXR1cm4ge29iamVjdH0gLSBHZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxuICovXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBsb2FkQ29uZmlnRmlsZShhcmdzKTtcbiAgfVxuXG4gIC8vIFVwZGF0ZSB0aGUgZGVmYXVsdCBjb25maWcgd2l0aCBhIGNvcnJlY3Qgb3B0aW9uIHZhbHVlc1xuICB1cGRhdGVEZWZhdWx0Q29uZmlnKGRlZmF1bHRDb25maWcsIGdlbmVyYWxPcHRpb25zKTtcblxuICAvLyBTZXQgdmFsdWVzIGZvciBzZXJ2ZXIncyBvcHRpb25zIGFuZCByZXR1cm5zIHRoZW1cbiAgZ2VuZXJhbE9wdGlvbnMgPSBpbml0T3B0aW9ucyhkZWZhdWx0Q29uZmlnKTtcblxuICAvLyBBcHBseSB1c2VyIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxuICBpZiAodXNlck9wdGlvbnMpIHtcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcbiAgICBnZW5lcmFsT3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxuICAgICAgdXNlck9wdGlvbnMsXG4gICAgICBhYnNvbHV0ZVByb3BzXG4gICAgKTtcbiAgfVxuXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xuICAgIC8vIFBhaXIgcHJvdmlkZWQgYXJndW1lbnRzXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBwYWlyQXJndW1lbnRWYWx1ZShnZW5lcmFsT3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZyk7XG4gIH1cblxuICAvLyBSZXR1cm4gZmluYWwgZ2VuZXJhbCBvcHRpb25zXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcbn07XG5cbi8qKlxuICogRGlzcGxheXMgYSBwcm9tcHQgZm9yIHRoZSBtYW51YWwgY29uZmlndXJhdGlvbi5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnRmlsZU5hbWUgLSBUaGUgbmFtZSBvZiBhIGNvbmZpZ3VyYXRpb24gZmlsZS5cbiAqL1xuZXhwb3J0IGNvbnN0IG1hbnVhbENvbmZpZyA9IGFzeW5jIChjb25maWdGaWxlTmFtZSkgPT4ge1xuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxuICBsZXQgY29uZmlnRmlsZSA9IHt9O1xuXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xuICBpZiAoZXhpc3RzU3luYyhjb25maWdGaWxlTmFtZSkpIHtcbiAgICBjb25maWdGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoY29uZmlnRmlsZU5hbWUsICd1dGY4JykpO1xuICB9XG5cbiAgLy8gUXVlc3Rpb24gYWJvdXQgYSBjb25maWd1cmF0aW9uIGNhdGVnb3J5XG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcbiAgICBsZXQgcXVlc3Rpb25zQ291bnRlciA9IDA7XG4gICAgbGV0IGFsbFF1ZXN0aW9ucyA9IFtdO1xuXG4gICAgLy8gQ3JlYXRlIGEgY29ycmVzcG9uZGluZyBwcm9wZXJ0eSBpbiB0aGUgbWFudWFsQ29uZmlnIG9iamVjdFxuICAgIGZvciAoY29uc3Qgc2VjdGlvbiBvZiBjYXRlZ29yaWVzKSB7XG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXG4gICAgICBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dID0gcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXS5tYXAoKG9wdGlvbikgPT4gKHtcbiAgICAgICAgLi4ub3B0aW9uLFxuICAgICAgICBzZWN0aW9uXG4gICAgICB9KSk7XG5cbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xuICAgICAgYWxsUXVlc3Rpb25zID0gWy4uLmFsbFF1ZXN0aW9ucywgLi4ucHJvbXB0c0NvbmZpZ1tzZWN0aW9uXV07XG4gICAgfVxuXG4gICAgYXdhaXQgcHJvbXB0cyhhbGxRdWVzdGlvbnMsIHtcbiAgICAgIG9uU3VibWl0OiBhc3luYyAocHJvbXB0LCBhbnN3ZXIpID0+IHtcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZXNcbiAgICAgICAgaWYgKHByb21wdC5uYW1lID09PSAnbW9kdWxlcycpIHtcbiAgICAgICAgICBhbnN3ZXIgPSBhbnN3ZXIubGVuZ3RoXG4gICAgICAgICAgICA/IGFuc3dlci5tYXAoKG1vZHVsZSkgPT4gcHJvbXB0LmNob2ljZXNbbW9kdWxlXSlcbiAgICAgICAgICAgIDogcHJvbXB0LmNob2ljZXM7XG5cbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXVtwcm9tcHQubmFtZV0gPSBhbnN3ZXI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gPSByZWN1cnNpdmVQcm9wcyhcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dIHx8IHt9KSxcbiAgICAgICAgICAgIHByb21wdC5uYW1lLnNwbGl0KCcuJyksXG4gICAgICAgICAgICBhbnN3ZXJcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCsrcXVlc3Rpb25zQ291bnRlciA9PT0gYWxsUXVlc3Rpb25zLmxlbmd0aCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBmc1Byb21pc2VzLndyaXRlRmlsZShcbiAgICAgICAgICAgICAgY29uZmlnRmlsZU5hbWUsXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNvbmZpZ0ZpbGUsIG51bGwsIDIpLFxuICAgICAgICAgICAgICAndXRmOCdcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGxvZygxLCBgW2NvbmZpZ10gRXJyb3Igd2hpbGUgY3JlYXRpbmcgY29uZmlnLmpzb246ICR7ZXJyb3J9YCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfTtcblxuICAvLyBGaW5kIHRoZSBjYXRlZ29yaWVzXG4gIGNvbnN0IGNob2ljZXMgPSBPYmplY3Qua2V5cyhwcm9tcHRzQ29uZmlnKS5tYXAoKGNob2ljZSkgPT4gKHtcbiAgICB0aXRsZTogYCR7Y2hvaWNlfSBvcHRpb25zYCxcbiAgICB2YWx1ZTogY2hvaWNlXG4gIH0pKTtcblxuICAvLyBDYXRlZ29yeSBwcm9tcHRcbiAgcmV0dXJuIHByb21wdHMoXG4gICAge1xuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcbiAgICAgIG5hbWU6ICdjYXRlZ29yeScsXG4gICAgICBtZXNzYWdlOiAnV2hpY2ggY2F0ZWdvcnkgZG8geW91IHdhbnQgdG8gY29uZmlndXJlPycsXG4gICAgICBoaW50OiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcbiAgICAgIGluc3RydWN0aW9uczogJycsXG4gICAgICBjaG9pY2VzXG4gICAgfSxcbiAgICB7IG9uU3VibWl0IH1cbiAgKTtcbn07XG5cbi8qKlxuICogTWFwcyB0aGUgb2xkIG9wdGlvbnMgdG8gdGhlIG5ldyBjb25maWcgc3RydWN0dXJlLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBvbGRPcHRpb25zIC0gT3B0aW9ucyB0byBiZSBtYXBwZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBtYXBUb05ld0NvbmZpZyA9IChvbGRPcHRpb25zKSA9PiB7XG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvbGQtc3RydWN0dXJlZCBvcHRpb25zXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1trZXldID8gbmVzdGVkQXJnc1trZXldLnNwbGl0KCcuJykgOiBbXTtcblxuICAgIC8vIFBvcHVsYXRlIG9iamVjdCBpbiBjb3JyZWN0IHByb3BlcnRpZXMgbGV2ZWxzXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZShcbiAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxuICAgICAgICAob2JqW3Byb3BdID1cbiAgICAgICAgICBwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXggPyB2YWx1ZSA6IG9ialtwcm9wXSB8fCB7fSksXG4gICAgICBuZXdPcHRpb25zXG4gICAgKTtcbiAgfVxuICByZXR1cm4gbmV3T3B0aW9ucztcbn07XG5cbi8qKlxuICogTWVyZ2VzIHRoZSBuZXcgb3B0aW9ucyB0byB0aGUgb3B0aW9ucyBvYmplY3QuIEl0IG9taXRzIHVuZGVmaW5lZCB2YWx1ZXMuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBPbGQgb3B0aW9ucy5cbiAqIEBwYXJhbSB7b2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IG9wdGlvbnMuXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSBhYnNvbHV0ZVByb3BzIC0gQXJyYXkgb2Ygb2JqZWN0IG5hbWVzIHRoYXQgc2hvdWxkIGJlIGZvcmNlXG4gKiBtZXJnZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBtZXJnZUNvbmZpZ09wdGlvbnMgPSAob3B0aW9ucywgbmV3T3B0aW9ucywgYWJzb2x1dGVQcm9wcyA9IFtdKSA9PiB7XG4gIGNvbnN0IG1lcmdlZE9wdGlvbnMgPSBkZWVwQ29weShvcHRpb25zKTtcblxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xuICAgIG1lcmdlZE9wdGlvbnNba2V5XSA9XG4gICAgICBpc09iamVjdCh2YWx1ZSkgJiZcbiAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcbiAgICAgIG1lcmdlZE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXG4gICAgICAgID8gbWVyZ2VDb25maWdPcHRpb25zKG1lcmdlZE9wdGlvbnNba2V5XSwgdmFsdWUsIGFic29sdXRlUHJvcHMpXG4gICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxuICAgICAgICA/IHZhbHVlXG4gICAgICAgIDogbWVyZ2VkT3B0aW9uc1trZXldO1xuICB9XG5cbiAgcmV0dXJuIG1lcmdlZE9wdGlvbnM7XG59O1xuXG4vKipcbiAqIEluaXRpYWxpemVzIG9wdGlvbnMgZm9yIHRoZSBgc3RhcnRFeHBvcnRgIG1ldGhvZCBieSBtZXJnaW5nIHVzZXIgb3B0aW9uc1xuICogd2l0aCB0aGUgZ2VuZXJhbCBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7YW55fSBleHBvcnRPcHRpb25zIC0gVXNlciBvcHRpb25zIGZvciBleHBvcnRpbmcuXG4gKiBAcGFyYW0ge2FueX0gZ2VuZXJhbE9wdGlvbnMgLSBHZW5lcmFsIG9wdGlvbnMgYXJlIHVzZWQgZm9yIHRoZSBleHBvcnQgc2VydmVyLlxuICogQHJldHVybiB7b2JqZWN0fSAtIFVzZXIgb3B0aW9ucyBtZXJnZWQgd2l0aCBkZWZhdWx0IG9wdGlvbnMuXG4gKi9cbmV4cG9ydCBjb25zdCBpbml0RXhwb3J0U2V0dGluZ3MgPSAoZXhwb3J0T3B0aW9ucywgZ2VuZXJhbE9wdGlvbnMgPSB7fSkgPT4ge1xuICBsZXQgb3B0aW9ucyA9IHt9O1xuXG4gIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xuICAgIG9wdGlvbnMgPSBkZWVwQ29weShnZW5lcmFsT3B0aW9ucyk7XG4gICAgb3B0aW9ucy5leHBvcnQudHlwZSA9IGV4cG9ydE9wdGlvbnMudHlwZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC50eXBlO1xuICAgIG9wdGlvbnMuZXhwb3J0LnNjYWxlID0gZXhwb3J0T3B0aW9ucy5zY2FsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5zY2FsZTtcbiAgICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cbiAgICAgIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5vdXRmaWxlO1xuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcbiAgICAgIHN2ZzogZXhwb3J0T3B0aW9ucy5zdmdcbiAgICB9O1xuICB9IGVsc2Uge1xuICAgIG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcbiAgICAgIGV4cG9ydE9wdGlvbnMsXG4gICAgICAvLyBPbWl0IGdvaW5nIGRvd24gcmVjdXJzaXZlbHkgd2l0aCB0aGUgYmVsb3dzXG4gICAgICBhYnNvbHV0ZVByb3BzXG4gICAgKTtcbiAgfVxuXG4gIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxuICAgIG9wdGlvbnMuZXhwb3J0Py5vdXRmaWxlIHx8IGBjaGFydC4ke29wdGlvbnMuZXhwb3J0Py50eXBlIHx8ICdwbmcnfWA7XG4gIHJldHVybiBvcHRpb25zO1xufTtcblxuLyoqXG4gKiBMb2FkcyB0aGUgY29uZmlndXJhdGlvbiBmcm9tIGEgY3VzdG9tIEpTT04gZmlsZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSBhcmdzIC0gQ0xJIGFyZ3VtZW50cy5cbiAqIEByZXR1cm4ge29iamVjdH0gLSBPcHRpb25zIG9iamVjdCBmcm9tIHRoZSBKU09OIGZpbGUuXG4gKi9cbmZ1bmN0aW9uIGxvYWRDb25maWdGaWxlKGFyZ3MpIHtcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBvcHRpb24gd2FzIHVzZWRcbiAgY29uc3QgY29uZmlnSW5kZXggPSBhcmdzLmZpbmRJbmRleChcbiAgICAoYXJnKSA9PiBhcmcucmVwbGFjZSgvLS9nLCAnJykgPT09ICdsb2FkQ29uZmlnJ1xuICApO1xuXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgaGFzIGEgdmFsdWVcbiAgaWYgKGNvbmZpZ0luZGV4ID4gLTEgJiYgYXJnc1tjb25maWdJbmRleCArIDFdKSB7XG4gICAgY29uc3QgZmlsZU5hbWUgPSBhcmdzW2NvbmZpZ0luZGV4ICsgMV07XG4gICAgdHJ5IHtcbiAgICAgIC8vIENoZWNrIGlmIGFuIGFkZGl0aW9uYWwgY29uZmlnIGZpbGUgaXMgYSBjb3JyZWN0IEpTT04gZmlsZVxuICAgICAgaWYgKGZpbGVOYW1lICYmIGZpbGVOYW1lLmVuZHNXaXRoKCcuanNvbicpKSB7XG4gICAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGZpbGVOYW1lKSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZygxLCBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgY29uZmlnIGZyb20gdGhlICR7ZmlsZU5hbWV9OiAke2Vycm9yfWApO1xuICAgIH1cbiAgfVxuXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cbiAgcmV0dXJuIHt9O1xufVxuXG4vKipcbiAqIFNldHRpbmcgY29ycmVjdCB2YWx1ZXMgb2YgdGhlIG9wdGlvbnMgZnJvbSB0aGUgZGVmYXVsdCBjb25maWcuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZ09iaiAtIFRoZSBjb25maWcgb2JqZWN0IGJhc2VkIG9uIHdoaWNoIHRoZSBpbml0aWFsXG4gKiBjb25maWd1cmF0aW9uIGJlIG1hZGUuXG4gKiBAcGFyYW0ge29iamVjdH0gY3VzdG9tT2JqIC0gVGhlIGN1c3RvbSBvYmplY3Qgd2hpY2ggY2FuIGNvbnRhaW4gYWRkaXRpb25hbFxuICogb3B0aW9uIHZhbHVlcyB0byBzZXQuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gUmVxdWlyZWQgZm9yIGNyZWF0aW5nIGEgc3RyaW5nIGNoYWluIG9mXG4gKiBwcm9wZXJ0aWVzIGZvciBuZXN0ZWQgYXJndW1lbnRzLlxuICovXG5mdW5jdGlvbiB1cGRhdGVEZWZhdWx0Q29uZmlnKGNvbmZpZ09iaiwgY3VzdG9tT2JqID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XG4gIE9iamVjdC5rZXlzKGNvbmZpZ09iaikuZm9yRWFjaCgoa2V5KSA9PiB7XG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoa2V5KSkge1xuICAgICAgY29uc3QgZW50cnkgPSBjb25maWdPYmpba2V5XTtcbiAgICAgIGNvbnN0IGN1c3RvbVZhbHVlID0gY3VzdG9tT2JqICYmIGN1c3RvbU9ialtrZXldO1xuICAgICAgbGV0IG51bUVudlZhbDtcblxuICAgICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgdXBkYXRlRGVmYXVsdENvbmZpZyhlbnRyeSwgY3VzdG9tVmFsdWUsIGAke3Byb3BDaGFpbn0uJHtrZXl9YCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYSBjdXN0b20gSlNPTiBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxuICAgICAgICBpZiAoY3VzdG9tVmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIGVudHJ5LnZhbHVlID0gY3VzdG9tVmFsdWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXG4gICAgICAgIGlmIChlbnRyeS5lbnZMaW5rKSB7XG4gICAgICAgICAgLy8gTG9hZCB0aGUgZW52IHZhclxuICAgICAgICAgIGlmIChlbnRyeS50eXBlID09PSAnYm9vbGVhbicpIHtcbiAgICAgICAgICAgIGVudHJ5LnZhbHVlID0gdG9Cb29sZWFuKFxuICAgICAgICAgICAgICBbcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua10sIGVudHJ5LnZhbHVlXS5maW5kKFxuICAgICAgICAgICAgICAgIChlbCkgPT4gZWwgfHwgZWwgPT09ICdmYWxzZSdcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKGVudHJ5LnR5cGUgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICBudW1FbnZWYWwgPSArcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua107XG4gICAgICAgICAgICBlbnRyeS52YWx1ZSA9IG51bUVudlZhbCA+PSAwID8gbnVtRW52VmFsIDogZW50cnkudmFsdWU7XG4gICAgICAgICAgfSBlbHNlIGlmIChcbiAgICAgICAgICAgIGVudHJ5LnR5cGUuaW5kZXhPZignXScpID49IDAgJiZcbiAgICAgICAgICAgIHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdXG4gICAgICAgICAgKSB7XG4gICAgICAgICAgICBlbnRyeS52YWx1ZSA9IHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdLnNwbGl0KCcsJyk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGVudHJ5LnZhbHVlID0gcHJvY2Vzcy5lbnZbZW50cnkuZW52TGlua10gfHwgZW50cnkudmFsdWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9KTtcbn1cblxuLyoqXG4gKiBJbml0cyBvcHRpb25zIHJlY3Vyc2l2ZWx5LlxuICpcbiAqIEBwYXJhbSB7YW55fSBpdGVtcyAtIEl0ZW1zIHRvIHVwZGF0ZSBvcHRpb25zIGZyb20uXG4gKiBAcmV0dXJuIHtvYmplY3R9IC0gVXBkYXRlZCBvcHRpb25zIG9iamVjdC5cbiAqL1xuZnVuY3Rpb24gaW5pdE9wdGlvbnMoaXRlbXMpIHtcbiAgbGV0IG9wdGlvbnMgPSB7fTtcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XG4gICAgb3B0aW9uc1tuYW1lXSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKVxuICAgICAgPyBpdGVtLnZhbHVlXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xuICB9XG4gIHJldHVybiBvcHRpb25zO1xufVxuXG4vKipcbiAqIFBhaXJzIGFyZ3VtZW50IHdpdGggYSBjb3JyZXNwb25kaW5nIHZhbHVlLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gQWxsIHNlcnZlciBvcHRpb25zLlxuICogQHBhcmFtIHtzdHJpbmdbXX0gYXJncyAtIEFycmF5IG9mIGFyZ3VtZW50cyBmcm9tIGEgdXNlci5cbiAqIEBwYXJhbSB7b2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gVGhlIGRlZmF1bHQgY29uZmlnIG9iamVjdC5cbiAqL1xuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcbiAgICBsZXQgb3B0aW9uID0gYXJnc1tpXS5yZXBsYWNlKC8tL2csICcnKTtcblxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1tvcHRpb25dXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXG4gICAgICA6IFtdO1xuXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbcHJvcF0gIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgaWYgKGFyZ3NbKytpXSkge1xuICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXSB8fCBvYmpbcHJvcF07XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKGBNaXNzaW5nIGFyZ3VtZW50IHZhbHVlIGZvciAke29wdGlvbn0hYC5yZWQsICdcXG4nKTtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcbiAgICB9LCBvcHRpb25zKTtcbiAgfVxuXG4gIHJldHVybiBvcHRpb25zO1xufVxuXG4vKipcbiAqIFJlY3Vyc2l2ZWx5IHNldHMgYSBwcm9wZXJ0eSBpbiBhIGNvcnJlY3QgaW5kZW50YXRpb24gbGV2ZWwgYmFzZWQgb24gdGhlXG4gKiBhcnJheSBvZiBuZXN0ZWQgcHJvcGVydGllcyBuYW1lcy5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gb2JqZWN0VG9VcGRhdGUgLSBPYmplY3Qgd2hlcmUgYSBwcm9wZXJ0eSBtdXN0IGJlIHNldCBvbiBhXG4gKiBjb3JyZWN0IGxldmVsLlxuICogQHBhcmFtICB7c3RyaW5nW119bmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuYXN0ZWQgbmFtZXMgdGhhdCBpbmRpY2F0ZXNcbiAqIGluZGVudGF0aW9uIGxldmVsLlxuICogQHBhcmFtIHthbnl9IHZhbHVlIC0gQSB2YWx1ZSB0byBhc3NpZ24gdG8gdGhlIHByb3BlcnR5LlxuICogQHJldHVybiB7b2JqZWN0fSAtIFVwZGF0ZWQgb3B0aW9ucyBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIHJlY3Vyc2l2ZVByb3BzKG9iamVjdFRvVXBkYXRlLCBuZXN0ZWROYW1lcywgdmFsdWUpIHtcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcbiAgICBjb25zdCBwcm9wTmFtZSA9IG5lc3RlZE5hbWVzLnNoaWZ0KCk7XG5cbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxuICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdFRvVXBkYXRlLCBwcm9wTmFtZSkpIHtcbiAgICAgIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSA9IHt9O1xuICAgIH1cblxuICAgIC8vIENhbGwgZnVuY3Rpb24gYWdhaW4gaWYgdGhlcmUgc3RpbGwgbmFtZXMgdG8gZ29cbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcbiAgICAgIE9iamVjdC5hc3NpZ24oe30sIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSksXG4gICAgICBuZXN0ZWROYW1lcyxcbiAgICAgIHZhbHVlXG4gICAgKTtcblxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcbiAgfVxuXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcbiAgb2JqZWN0VG9VcGRhdGVbbmVzdGVkTmFtZXNbMF1dID0gdmFsdWU7XG4gIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcbn1cblxuZXhwb3J0IGRlZmF1bHQge1xuICBnZXRPcHRpb25zLFxuICBzZXRPcHRpb25zLFxuICBtYW51YWxDb25maWcsXG4gIG1hcFRvTmV3Q29uZmlnLFxuICBtZXJnZUNvbmZpZ09wdGlvbnMsXG4gIGluaXRFeHBvcnRTZXR0aW5nc1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyByZWFkRmlsZSwgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xuXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBraWxsUG9vbCwgcG9zdFdvcmsgfSBmcm9tICcuL3Bvb2wuanMnO1xuaW1wb3J0IHtcbiAgY2xlYXJUZXh0LFxuICBmaXhUeXBlLFxuICBoYW5kbGVSZXNvdXJjZXMsXG4gIGlzQ29ycmVjdEpTT04sXG4gIG9wdGlvbnNTdHJpbmdpZnksXG4gIHJvdW5kTnVtYmVyLFxuICB0b0Jvb2xlYW4sXG4gIHdyYXBBcm91bmRcbn0gZnJvbSAnLi91dGlscy5qcyc7XG5pbXBvcnQgeyBpbml0RXhwb3J0U2V0dGluZ3MsIGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XG5cbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcblxuZXhwb3J0IGNvbnN0IHN0YXJ0RXhwb3J0ID0gYXN5bmMgKHNldHRpbmdzLCBlbmRDYWxsYmFjaykgPT4ge1xuICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXG4gIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcblxuICAvLyBJbml0aWFsaXplIG9wdGlvbnNcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcblxuICAvLyBHZXQgdGhlIGV4cG9ydCBvcHRpb25zXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcblxuICAvLyBJZiBTVkcgaXMgYW4gaW5wdXQgKGFyZ3VtZW50IGNhbiBiZSBzZW50IG9ubHkgYnkgdGhlIHJlcXVlc3QpXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xuICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLnBheWxvYWQuc3ZnLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xuICB9XG5cbiAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZVxuICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgJiYgZXhwb3J0T3B0aW9ucy5pbmZpbGUubGVuZ3RoKSB7XG4gICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gaW5wdXQgZmlsZS4nKTtcblxuICAgIC8vIFRyeSB0byByZWFkIHRoZSBmaWxlXG4gICAgcmV0dXJuIHJlYWRGaWxlKGV4cG9ydE9wdGlvbnMuaW5maWxlLCAndXRmOCcsIChlcnJvciwgaW5maWxlKSA9PiB7XG4gICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgcmV0dXJuIGxvZygxLCBgW2NoYXJ0XSBFcnJvciBsb2FkaW5nIGlucHV0IGZpbGU6ICR7ZXJyb3J9LmApO1xuICAgICAgfVxuXG4gICAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxuICAgICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBpbmZpbGU7XG4gICAgICByZXR1cm4gZXhwb3J0QXNTdHJpbmcob3B0aW9ucy5leHBvcnQuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjayk7XG4gICAgfSk7XG4gIH1cblxuICAvLyBFeHBvcnQgd2l0aCBvcHRpb25zIGZyb20gdGhlIHJhdyByZXByZXNlbnRhdGlvblxuICBpZiAoXG4gICAgKGV4cG9ydE9wdGlvbnMuaW5zdHIgJiYgZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gJycpIHx8XG4gICAgKGV4cG9ydE9wdGlvbnMub3B0aW9ucyAmJiBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09ICcnKVxuICApIHtcbiAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIHJhdyBpbnB1dC4nKTtcblxuICAgIC8vIFBlcmZvcm0gYSBkaXJlY3QgaW5qZWN0IHdoZW4gZm9yY2VkXG4gICAgaWYgKHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUNvZGU/LmFsbG93Q29kZUV4ZWN1dGlvbikpIHtcbiAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcbiAgICB9XG5cbiAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcbiAgICByZXR1cm4gdHlwZW9mIGV4cG9ydE9wdGlvbnMuaW5zdHIgPT09ICdzdHJpbmcnXG4gICAgICA/IGV4cG9ydEFzU3RyaW5nKGV4cG9ydE9wdGlvbnMuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjaylcbiAgICAgIDogZG9FeHBvcnQoXG4gICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcbiAgICAgICAgICBlbmRDYWxsYmFja1xuICAgICAgICApO1xuICB9XG5cbiAgLy8gTm8gaW5wdXQgc3BlY2lmaWVkLCBwYXNzIGFuIGVycm9yIG1lc3NhZ2UgdG8gdGhlIGNhbGxiYWNrXG4gIGxvZyhcbiAgICAxLFxuICAgIGNsZWFyVGV4dChcbiAgICAgIGBbY2hhcnRdIE5vIGlucHV0IHNwZWNpZmllZC5cbiAgICAgICR7SlNPTi5zdHJpbmdpZnkoZXhwb3J0T3B0aW9ucywgdW5kZWZpbmVkLCAnICAnKX0uYFxuICAgIClcbiAgKTtcblxuICByZXR1cm4gKFxuICAgIGVuZENhbGxiYWNrICYmXG4gICAgZW5kQ2FsbGJhY2soZmFsc2UsIHtcbiAgICAgIGVycm9yOiB0cnVlLFxuICAgICAgbWVzc2FnZTogJ05vIGlucHV0IHNwZWNpZmllZC4nXG4gICAgfSlcbiAgKTtcbn07XG5cbmV4cG9ydCBjb25zdCBiYXRjaEV4cG9ydCA9IChvcHRpb25zKSA9PiB7XG4gIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XG5cbiAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIC0tYmF0Y2ggYXJndW1lbnRzXG4gIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSkge1xuICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XG4gICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XG4gICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgICAgc3RhcnRFeHBvcnQoXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgICAgICAgIGV4cG9ydDoge1xuICAgICAgICAgICAgICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxuICAgICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcbiAgICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAoaW5mbywgZXJyb3IpID0+IHtcbiAgICAgICAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3JcbiAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHJlamVjdChlcnJvcik7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxuICAgICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxuICAgICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQub3V0ZmlsZSxcbiAgICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLmRhdGEsICdiYXNlNjQnKVxuICAgICAgICAgICAgICApO1xuXG4gICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICApO1xuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBLaWxsIHRoZSBwb29sIGFmdGVyIGFsbCBleHBvcnRzIGFyZSBkb25lXG4gIFByb21pc2UuYWxsKGJhdGNoRnVuY3Rpb25zKVxuICAgIC50aGVuKCgpID0+IHtcbiAgICAgIGtpbGxQb29sKCk7XG4gICAgfSlcbiAgICAuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICBsb2coMSwgYFtjaGFydF0gRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGJhdGNoIGV4cG9ydDogJHtlcnJvcn1gKTtcbiAgICAgIGtpbGxQb29sKCk7XG4gICAgfSk7XG59O1xuXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gKG9wdGlvbnMpID0+IHtcbiAgLy8gVXNlIGluc3RyIG9yIGl0cyBhbGlhcywgb3B0aW9uc1xuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XG5cbiAgLy8gUGVyZm9ybSBhbiBleHBvcnRcbiAgc3RhcnRFeHBvcnQob3B0aW9ucywgKGluZm8sIGVycm9yKSA9PiB7XG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcbiAgICBpZiAoZXJyb3IpIHtcbiAgICAgIGxvZygxLCBgW2NsaV0gJHtlcnJvci5tZXNzYWdlfWApO1xuICAgICAgcHJvY2Vzcy5leGl0KDEpO1xuICAgIH1cblxuICAgIGNvbnN0IHsgb3V0ZmlsZSwgdHlwZSB9ID0gaW5mby5vcHRpb25zLmV4cG9ydDtcblxuICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXG4gICAgd3JpdGVGaWxlU3luYyhcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxuICAgICAgdHlwZSAhPT0gJ3N2ZycgPyBCdWZmZXIuZnJvbShpbmZvLmRhdGEsICdiYXNlNjQnKSA6IGluZm8uZGF0YVxuICAgICk7XG5cbiAgICAvLyBLaWxsIHRoZSBwb29sXG4gICAga2lsbFBvb2woKTtcbiAgfSk7XG59O1xuXG4vKipcbiAqIEZ1bmN0aW9uIGZvciBjaG9vc2luZyBjaGFydCBzaXplIGFuZCBzY2FsZSBiYXNlZCBvbiBvcHRpb25zIHByaW9yaXRpemF0aW9uLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgb2JqZWN0LlxuICogQHJldHVybiB7b2JqZWN0fSAtIEFuIG9iamVjdCB3aXRoIHVwZGF0ZWQgc2l6ZSBhbmQgc2NhbGUgZm9yIGEgY2hhcnQuXG4gKi9cbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxuICAgIG9wdGlvbnMuZXhwb3J0Py5vcHRpb25zIHx8IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmluc3RyKTtcblxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uZ2xvYmFsT3B0aW9ucyk7XG5cbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXG4gIGxldCBzY2FsZSA9XG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxuICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc2NhbGUgfHxcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XG4gICAgMTtcblxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XG5cbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcblxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXG4gIHJldHVybiB7XG4gICAgaGVpZ2h0OlxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcbiAgICAgIGNoYXJ0Py5oZWlnaHQgfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdEhlaWdodCB8fFxuICAgICAgNDAwLFxuICAgIHdpZHRoOlxuICAgICAgb3B0aW9ucy5leHBvcnQ/LndpZHRoIHx8XG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XG4gICAgICBjaGFydD8ud2lkdGggfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxuICAgICAgNjAwLFxuICAgIHNjYWxlXG4gIH07XG59O1xuXG4vKipcbiAqIEZ1bmN0aW9uIGZvciBmaW5hbCBvcHRpb25zIHByZXBhcmF0aW9uIGJlZm9yZSBleHBvcnQuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBBbGwgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge29iamVjdH0gY2hhcnRKc29uIC0gQ2hhcnQgSlNPTi5cbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGVuZCBjYWxsYmFjay5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIHJlcHJlc2VudGF0aW9uLlxuICovXG5jb25zdCBkb0V4cG9ydCA9IChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Db2RlOiBjdXN0b21Db2RlT3B0aW9ucyB9ID0gb3B0aW9ucztcblxuICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgPVxuICAgIHR5cGVvZiBjdXN0b21Db2RlT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xuICAgICAgPyBjdXN0b21Db2RlT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cbiAgICAgIDogYWxsb3dDb2RlRXhlY3V0aW9uO1xuXG4gIGlmICghY3VzdG9tQ29kZU9wdGlvbnMpIHtcbiAgICBjdXN0b21Db2RlT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tQ29kZSA9IHt9O1xuICB9IGVsc2UgaWYgKHR5cGVvZiBvcHRpb25zLmN1c3RvbUNvZGUucmVzb3VyY2VzID09PSAnc3RyaW5nJykge1xuICAgIC8vIFByb2Nlc3MgcmVzb3VyY2VzXG4gICAgb3B0aW9ucy5jdXN0b21Db2RlLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcbiAgICAgIG9wdGlvbnMuY3VzdG9tQ29kZS5yZXNvdXJjZXMsXG4gICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Db2RlLmFsbG93RmlsZVJlc291cmNlcylcbiAgICApO1xuICB9IGVsc2UgaWYgKCFvcHRpb25zLmN1c3RvbUNvZGUucmVzb3VyY2VzKSB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHJlc291cmNlcyA9IHJlYWRGaWxlU3luYygncmVzb3VyY2VzLmpzb24nLCAndXRmOCcpO1xuICAgICAgb3B0aW9ucy5jdXN0b21Db2RlLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcbiAgICAgICAgcmVzb3VyY2VzLFxuICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Db2RlLmFsbG93RmlsZVJlc291cmNlcylcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBsb2coMywgYFtjaGFydF0gVGhlIGRlZmF1bHQgcmVzb3VyY2VzLmpzb24gZmlsZSBub3QgZm91bmQuYCk7XG4gICAgfVxuICB9XG5cbiAgLy8gSWYgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnIGlzbid0IHNldCwgd2Ugc2hvdWxkIHJlZnVzZSB0aGUgdXNhZ2VcbiAgLy8gb2YgY2FsbGJhY2ssIHJlc291cmNlcywgYW5kIGN1c3RvbSBjb2RlLiBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbFxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxuICAvLyBvcHRpb24sIHRoZW4gd2Ugc2hvdWxkIHRha2UgYSBsb29rIGF0IHRoZSBvdmVyYWxsIHBvb2wgb3B0aW9uLlxuICBpZiAoIWFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCAmJiBjdXN0b21Db2RlT3B0aW9ucykge1xuICAgIGlmIChcbiAgICAgIGN1c3RvbUNvZGVPcHRpb25zLmNhbGxiYWNrIHx8XG4gICAgICBjdXN0b21Db2RlT3B0aW9ucy5yZXNvdXJjZXMgfHxcbiAgICAgIGN1c3RvbUNvZGVPcHRpb25zLmN1c3RvbUNvZGVcbiAgICApIHtcbiAgICAgIC8vIFNlbmQgYmFjayBhIGZyaWVuZGx5IG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnRcbiAgICAgIC8vIHRoZXNlIHNldHRpbmdzLlxuICAgICAgcmV0dXJuIChcbiAgICAgICAgZW5kQ2FsbGJhY2sgJiZcbiAgICAgICAgZW5kQ2FsbGJhY2soZmFsc2UsIHtcbiAgICAgICAgICBlcnJvcjogdHJ1ZSxcbiAgICAgICAgICBtZXNzYWdlOiBjbGVhclRleHQoXG4gICAgICAgICAgICBgVGhlIGNhbGxiYWNrLCByZXNvdXJjZXMgYW5kIGN1c3RvbUNvZGUgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzXG4gICAgICAgICAgICBzZXJ2ZXIuYFxuICAgICAgICAgIClcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgYWxsIGFkZGl0aW9uYWwgY3VzdG9tIGNvZGVcbiAgICBjdXN0b21Db2RlT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xuICAgIGN1c3RvbUNvZGVPcHRpb25zLnJlc291cmNlcyA9IGZhbHNlO1xuICAgIGN1c3RvbUNvZGVPcHRpb25zLmN1c3RvbUNvZGUgPSBmYWxzZTtcbiAgfVxuXG4gIC8vIENsZWFuIHByb3BlcnRpZXMgdG8ga2VlcCBpdCBsZWFuIGFuZCBtZWFuXG4gIGlmIChjaGFydEpzb24pIHtcbiAgICBjaGFydEpzb24uY2hhcnQgPSBjaGFydEpzb24uY2hhcnQgfHwge307XG4gICAgY2hhcnRKc29uLmV4cG9ydGluZyA9IGNoYXJ0SnNvbi5leHBvcnRpbmcgfHwge307XG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XG4gIH1cblxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xuICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcbiAgfVxuXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXG4gICAgICAgICkge1xuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcbiAgICAgICAgICAgIHRydWVcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxuICAgICAgICAgICAgdHJ1ZVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB7fTtcbiAgICAgIGxvZygxLCBgW2NoYXJ0XSBUaGUgJHtvcHRpb25zTmFtZX0gbm90IGZvdW5kLmApO1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gUHJlcGFyZSBjdXN0b21Db2RlXG4gIGlmIChjdXN0b21Db2RlT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pIHtcbiAgICBjdXN0b21Db2RlT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcbiAgICAgIGN1c3RvbUNvZGVPcHRpb25zLmN1c3RvbUNvZGUsXG4gICAgICBjdXN0b21Db2RlT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXNcbiAgICApO1xuICB9XG5cbiAgLy8gR2V0IHRoZSBjYWxsYmFja1xuICBpZiAoXG4gICAgY3VzdG9tQ29kZU9wdGlvbnMgJiZcbiAgICBjdXN0b21Db2RlT3B0aW9ucy5jYWxsYmFjayAmJlxuICAgIGN1c3RvbUNvZGVPcHRpb25zLmNhbGxiYWNrPy5pbmRleE9mKCd7JykgPCAwXG4gICkge1xuICAgIC8vIFRoZSBhbGxvd0ZpbGVSZXNvdXJjZXMgaXMgYWx3YXlzIHNldCB0byBmYWxzZSBmb3IgSFRUUCByZXF1ZXN0cyB0byBhdm9pZFxuICAgIC8vIGluamVjdGluZyBhcmJpdHJhcnkgZmlsZXMgZnJvbSB0aGUgZnNcbiAgICBpZiAoY3VzdG9tQ29kZU9wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjdXN0b21Db2RlT3B0aW9ucy5jYWxsYmFjayA9IHJlYWRGaWxlU3luYyhcbiAgICAgICAgICBjdXN0b21Db2RlT3B0aW9ucy5jYWxsYmFjayxcbiAgICAgICAgICAndXRmOCdcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZygyLCBgW2NoYXJ0XSBFcnJvciBsb2FkaW5nIGNhbGxiYWNrOiAke2Vycm9yfS5gKTtcbiAgICAgICAgY3VzdG9tQ29kZU9wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY3VzdG9tQ29kZU9wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcbiAgICB9XG4gIH1cblxuICAvLyBTaXplIHNlYXJjaFxuICBvcHRpb25zLmV4cG9ydCA9IHtcbiAgICAuLi5vcHRpb25zLmV4cG9ydCxcbiAgICAuLi5maW5kQ2hhcnRTaXplKG9wdGlvbnMpXG4gIH07XG5cbiAgLy8gUG9zdCB0aGUgd29yayB0byB0aGUgcG9vbFxuICBwb3N0V29yayhleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLCBvcHRpb25zKVxuICAgIC50aGVuKChyZXN1bHQpID0+IGVuZENhbGxiYWNrKHJlc3VsdCkpXG4gICAgLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgbG9nKDAsICdbY2hhcnRdIFdoZW4gcG9zdGluZyB3b3JrOicsIGVycm9yKTtcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhmYWxzZSwgZXJyb3IpO1xuICAgIH0pO1xufTtcblxuLyoqXG4gKiBGdW5jdGlvbiBmb3Igc3RyYWlnaHQgaW5qZWN0aW5nIHRoZSBjb2RlLlxuICogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXAgYSBzZXJ2ZXJcbiAqIChzZWUgIC0tYWxsb3dDb2RlRXhlY3V0aW9uKS5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIEFsbCBvcHRpb25zIG9iamVjdC5cbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGZ1bmN0aW9uIHRvIGNhbGwgd2hlbiBleHBvcnRpbmcgaXMgZG9uZS5cbiAqL1xuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xuICB0cnkge1xuICAgIGxldCBzdHJJbmo7XG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcblxuICAgIGlmICh0eXBlb2YgaW5zdHIgIT09ICdzdHJpbmcnKSB7XG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcbiAgICAgIHN0ckluaiA9IGluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcbiAgICAgICAgaW5zdHIsXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tQ29kZT8uYWxsb3dDb2RlRXhlY3V0aW9uXG4gICAgICApO1xuICAgIH1cbiAgICBzdHJJbmogPSBpbnN0ci5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnJykudHJpbSgpO1xuXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgO1xuICAgIGlmIChzdHJJbmpbc3RySW5qLmxlbmd0aCAtIDFdID09PSAnOycpIHtcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xuICAgIH1cblxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXG4gICAgb3B0aW9ucy5leHBvcnQuc3RySW5qID0gc3RySW5qO1xuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2spO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBjbGVhclRleHQoXG4gICAgICBgTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfTpcbiAgICAgIFBsZWFzZSBtYWtlIHN1cmUgdGhhdCB5b3VyIEpTT04vSmF2YVNjcmlwdCBvcHRpb25zXG4gICAgICBhcmUgc2VudCB1c2luZyB0aGUgXCJvcHRpb25zXCIgYXR0cmlidXRlLCBhbmQgdGhhdCBpZiB5b3UncmUgdXNpbmdcbiAgICAgIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcbiAgICApO1xuXG4gICAgbG9nKDEsIG1lc3NhZ2UpO1xuICAgIHJldHVybiAoXG4gICAgICBlbmRDYWxsYmFjayAmJlxuICAgICAgZW5kQ2FsbGJhY2soXG4gICAgICAgIGZhbHNlLFxuICAgICAgICBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgZXJyb3I6IHRydWUsXG4gICAgICAgICAgbWVzc2FnZVxuICAgICAgICB9KVxuICAgICAgKVxuICAgICk7XG4gIH1cbn07XG5cbi8qKlxuICogUHJlcGFyZXMgYW4gaW5wdXQgYmVmb3JlIGV4cG9ydGluZy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBTdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgU1ZHL2V4cG9ydCBvcHRpb25zLlxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBBbGwgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBmdW5jdGlvbiB0byBjYWxsIHdoZW4gZXhwb3J0aW5nIGlzIGRvbmUuXG4gKi9cbmNvbnN0IGV4cG9ydEFzU3RyaW5nID0gKHN0cmluZ1RvRXhwb3J0LCBvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Db2RlO1xuXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xuICBpZiAoXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHxcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDBcbiAgKSB7XG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2ssIHN0cmluZ1RvRXhwb3J0KTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgLy8gVHJ5IHRvIHBhcnNlIHRvIEpTT04gYW5kIGNhbGwgdGhlIGRvRXhwb3J0IGZ1bmN0aW9uXG4gICAgY29uc3QgY2hhcnRKU09OID0gSlNPTi5wYXJzZShzdHJpbmdUb0V4cG9ydC5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnICcpKTtcblxuICAgIC8vIElmIGEgY29ycmVjdCBKU09OLCBkbyB0aGUgZXhwb3J0XG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGNoYXJ0SlNPTiwgZW5kQ2FsbGJhY2spO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIC8vIE5vdCBhIHZhbGlkIEpTT05cbiAgICBpZiAodG9Cb29sZWFuKGFsbG93Q29kZUV4ZWN1dGlvbikpIHtcbiAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gRG8gbm90IGFsbG93IHN0cmFpZ2h0IGluamVjdGlvbiB3aXRob3V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZ1xuICAgICAgcmV0dXJuIChcbiAgICAgICAgZW5kQ2FsbGJhY2sgJiZcbiAgICAgICAgZW5kQ2FsbGJhY2soZmFsc2UsIHtcbiAgICAgICAgICBlcnJvcjogdHJ1ZSxcbiAgICAgICAgICBtZXNzYWdlOiBjbGVhclRleHQoXG4gICAgICAgICAgICBgT25seSBKU09OIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgaXMgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmXG4gICAgICAgICAgICB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGV4cG9ydGluZyBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZ1xuICAgICAgICAgICAgdGhlIHNlcnZlciB3aXRoIHRoZSAtLWFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLmBcbiAgICAgICAgICApXG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IGdldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICgpID0+IGFsbG93Q29kZUV4ZWN1dGlvbjtcblxuZXhwb3J0IGNvbnN0IHNldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICh2YWx1ZSkgPT4ge1xuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB0b0Jvb2xlYW4odmFsdWUpO1xufTtcblxuLyoqXG4gKiBTdGFydHMgYW4gZXhwb3J0aW5nIHByb2Nlc3NcbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gc2V0dGluZ3MgLSBTZXR0aW5ncyBmb3IgZXhwb3J0LlxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgZnVuY3Rpb24gdG8gY2FsbCB3aGVuIGV4cG9ydGluZyBpcyBkb25lLlxuICovXG5leHBvcnQgZGVmYXVsdCB7XG4gIGJhdGNoRXhwb3J0LFxuICBzaW5nbGVFeHBvcnQsXG4gIGdldEFsbG93Q29kZUV4ZWN1dGlvbixcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxuICBzdGFydEV4cG9ydCxcbiAgZmluZENoYXJ0U2l6ZVxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XG5cbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiwgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XG5pbXBvcnQgeyBnZXRPcHRpb25zLCBtZXJnZUNvbmZpZ09wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcbmltcG9ydCB7XG4gIGNsZWFyVGV4dCxcbiAgZml4VHlwZSxcbiAgaXNDb3JyZWN0SlNPTixcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcbiAgb3B0aW9uc1N0cmluZ2lmeSxcbiAgbWVhc3VyZVRpbWVcbn0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xuXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XG4gIHBuZzogJ2ltYWdlL3BuZycsXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcbiAgcGRmOiAnYXBwbGljYXRpb24vcGRmJyxcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcbn07XG5cbi8vIFRoZSByZXF1ZXN0cyBjb3VudGVyXG5sZXQgcmVxdWVzdHNDb3VudGVyID0gMDtcblxuY29uc3QgYmVuY2htYXJrID0gZmFsc2U7XG5cbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBiZWZvcmUgYSByZXF1ZXN0XG5jb25zdCBiZWZvcmVSZXF1ZXN0ID0gW107XG5cbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBhZnRlciBhIHJlcXVlc3RcbmNvbnN0IGFmdGVyUmVxdWVzdCA9IFtdO1xuXG4vKipcbiAqIENhbGxzIGNhbGxiYWNrcy5cbiAqXG4gKiBAcGFyYW0ge0FycmF5fSBjYWxsYmFja3MgLSBBbiBhcnJheSBvZiBjYWxsYmFja3MuXG4gKiBAcGFyYW0ge29iamVjdH0gcmVxdWVzdCAtIFRoZSByZXF1ZXN0LlxuICogQHBhcmFtIHtvYmplY3R9IHJlc3BvbnNlIC0gVGhlIHJlc3BvbnNlLlxuICogQHBhcmFtIHtvYmplY3R9IGRhdGEgLSBUaGUgZGF0YSB0byBzZW5kIHRvIGNhbGxiYWNrcy5cbiAqIEByZXR1cm4ge29iamVjdH0gLSBUaGUgcmVzdWx0IGZyb20gYSBjYWxsYmFjay5cbiAqL1xuY29uc3QgZG9DYWxsYmFja3MgPSAoY2FsbGJhY2tzLCByZXF1ZXN0LCByZXNwb25zZSwgZGF0YSkgPT4ge1xuICBsZXQgcmVzdWx0ID0gdHJ1ZTtcbiAgY29uc3QgeyBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkgfSA9IGRhdGE7XG5cbiAgY2FsbGJhY2tzLnNvbWUoKGNhbGxiYWNrKSA9PiB7XG4gICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICBsZXQgY2FsbFJlc3BvbnNlID0gY2FsbGJhY2socmVxdWVzdCwgcmVzcG9uc2UsIGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSk7XG5cbiAgICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHVuZGVmaW5lZCAmJiBjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcbiAgICAgICAgcmVzdWx0ID0gY2FsbFJlc3BvbnNlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIEhhbmRsZXMgYW4gZXhwb3J0LlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSByZXF1ZXN0IC0gVGhlIHJlcXVlc3QuXG4gKiBAcGFyYW0ge29iamVjdH0gcmVzcG9uc2UgLSBUaGUgcmVzcG9uc2UuXG4gKi9cbmNvbnN0IGV4cG9ydEhhbmRsZXIgPSAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcbiAgLy8gU3RhcnQgY291bnRpbmcgdGltZVxuICBjb25zdCBzdG9wQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XG5cbiAgLy8gR2V0IHRoZSBjdXJyZW50IHNlcnZlcidzIGdlbmVyYWwgb3B0aW9uc1xuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcblxuICAvLyBJbml0IGRlZmF1bHQgb3B0aW9uc1xuICBpZiAoYmVuY2htYXJrKSB7XG4gICAgY29uc29sZS5sb2coJ0luaXQgZGVmYXVsdCBvcHRpb25zOicsIHN0b3BDb3VudGVyKCksICdtcy4nKTtcbiAgfVxuXG4gIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XG4gIGNvbnN0IGlkID0gKytyZXF1ZXN0c0NvdW50ZXI7XG4gIGNvbnN0IHVuaXF1ZUlkID0gdXVpZCgpLnJlcGxhY2UoLy0vZywgJycpO1xuICBsZXQgdHlwZSA9IGZpeFR5cGUoYm9keS50eXBlKTtcblxuICAvLyBGaXggdHlwZVxuICBpZiAoYmVuY2htYXJrKSB7XG4gICAgY29uc29sZS5sb2coJ0ZpeCB0eXBlOicsIHN0b3BDb3VudGVyKCksICdtcy4nKTtcbiAgfVxuXG4gIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBib2R5XG4gIGlmICghYm9keSkge1xuICAgIHJldHVybiByZXNwb25zZS5zdGF0dXMoNDAwKS5zZW5kKFxuICAgICAgY2xlYXJUZXh0KFxuICAgICAgICBgQm9keSBpcyByZXF1aXJlZC4gU2VuZGluZyBhIGJvZHk/IE1ha2Ugc3VyZSB5b3VyIENvbnRlbnQtdHlwZSBoZWFkZXJcbiAgICAgICAgaXMgY29ycmVjdC4gQWNjZXB0ZWQgaXMgYXBwbGljYXRpb24vanNvbiBhbmQgbXVsdGlwYXJ0L2Zvcm0tZGF0YS5gXG4gICAgICApXG4gICAgKTtcbiAgfVxuXG4gIC8vIEFsbCBvZiB0aGUgYmVsb3cgY2FuIGJlIHVzZWRcbiAgbGV0IGluc3RyID0gaXNDb3JyZWN0SlNPTihib2R5LmluZmlsZSB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5kYXRhKTtcblxuICAvLyBJcyBjb3JyZWN0IEpTT05cbiAgaWYgKGJlbmNobWFyaykge1xuICAgIGNvbnNvbGUubG9nKCdJcyBjb3JyZWN0IEpTT046Jywgc3RvcENvdW50ZXIoKSwgJ21zLicpO1xuICB9XG5cbiAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIEpTT04gb3IgU1ZHIHRvIGV4cG9ydFxuICBpZiAoIWluc3RyICYmICFib2R5LnN2Zykge1xuICAgIGxvZyhcbiAgICAgIDIsXG4gICAgICBjbGVhclRleHQoXG4gICAgICAgIGBSZXF1ZXN0ICR7dW5pcXVlSWR9IGZyb20gJHtcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gQ2hlY2sgeW91ciBwYXlsb2FkLmBcbiAgICAgIClcbiAgICApO1xuXG4gICAgcmV0dXJuIHJlc3BvbnNlLnN0YXR1cyg0MDApLnNlbmQoXG4gICAgICBjbGVhclRleHQoXG4gICAgICAgIGBObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIFBsZWFzZSBtYWtlIHN1cmUgeW91IGFyZSB1c2luZ1xuICAgICAgICBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycywgYW5kIHRoYXQgdGhlIGNoYXJ0XG4gICAgICAgIGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycgb3IgJ2RhdGEnIGF0dHJpYnV0ZSBpZiBzZW5kaW5nXG4gICAgICAgIEpTT04gb3IgaW4gdGhlICdzdmcnIGlmIHNlbmRpbmcgU1ZHLmBcbiAgICAgIClcbiAgICApO1xuICB9XG5cbiAgbGV0IGNhbGxSZXNwb25zZSA9IGZhbHNlO1xuXG4gIC8vIENhbGwgdGhlIGJlZm9yZSByZXF1ZXN0IGZ1bmN0aW9uc1xuICBjYWxsUmVzcG9uc2UgPSBkb0NhbGxiYWNrcyhiZWZvcmVSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwge1xuICAgIGlkLFxuICAgIHVuaXF1ZUlkLFxuICAgIHR5cGUsXG4gICAgYm9keVxuICB9KTtcblxuICAvLyBEbyBjYWxsYmFja3NcbiAgaWYgKGJlbmNobWFyaykge1xuICAgIGNvbnNvbGUubG9nKCdEbyBjYWxsYmFja3M6Jywgc3RvcENvdW50ZXIoKSwgJ21zLicpO1xuICB9XG5cbiAgLy8gQmxvY2sgdGhlIHJlcXVlc3QgaWYgb25lIG9mIGEgY2FsbGJhY2tzIGZhaWxlZFxuICBpZiAoY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoY2FsbFJlc3BvbnNlKTtcbiAgfVxuXG4gIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xuXG4gIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcbiAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKCkgPT4ge1xuICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcbiAgfSk7XG5cbiAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0ICR7dW5pcXVlSWR9LmApO1xuXG4gIGJvZHkuY29uc3RyID0gKHR5cGVvZiBib2R5LmNvbnN0ciA9PT0gJ3N0cmluZycgJiYgYm9keS5jb25zdHIpIHx8ICdjaGFydCc7XG5cbiAgLy8gR2F0aGVyIGFuZCBvcmdhbml6ZSBvcHRpb25zIGZyb20gdGhlIHBheWxvYWRcbiAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSB7XG4gICAgZXhwb3J0OiB7XG4gICAgICBpbnN0cixcbiAgICAgIHR5cGUsXG4gICAgICBjb25zdHI6IGJvZHkuY29uc3RyWzBdLnRvTG93ZXJDYXNlKCkgKyBib2R5LmNvbnN0ci5zdWJzdHIoMSksXG4gICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxuICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXG4gICAgICBzY2FsZTogYm9keS5zY2FsZSB8fCBkZWZhdWx0T3B0aW9ucy5leHBvcnQuc2NhbGUsXG4gICAgICBnbG9iYWxPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkuZ2xvYmFsT3B0aW9ucywgdHJ1ZSksXG4gICAgICB0aGVtZU9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS50aGVtZU9wdGlvbnMsIHRydWUpXG4gICAgfSxcbiAgICBjdXN0b21Db2RlOiB7XG4gICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpLFxuICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcbiAgICAgIHJlc291cmNlczogaXNDb3JyZWN0SlNPTihib2R5LnJlc291cmNlcywgdHJ1ZSksXG4gICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcbiAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZVxuICAgIH1cbiAgfTtcblxuICAvLyBPcmdhbml6ZSBvcHRpb25zXG4gIGlmIChiZW5jaG1hcmspIHtcbiAgICBjb25zb2xlLmxvZygnT3JnYW5pemUgb3B0aW9uczonLCBzdG9wQ291bnRlcigpLCAnbXMuJyk7XG4gIH1cblxuICBpZiAoaW5zdHIpIHtcbiAgICAvLyBTdHJpbmdpZnkgSlNPTiB3aXRoIG9wdGlvbnNcbiAgICByZXF1ZXN0T3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxuICAgICAgaW5zdHIsXG4gICAgICByZXF1ZXN0T3B0aW9ucy5jdXN0b21Db2RlLmFsbG93Q29kZUV4ZWN1dGlvblxuICAgICk7XG5cbiAgICAvLyBTdHJpbmdpZnkgSlNPTiB3aXRoIG9wdGlvbnNcbiAgICBpZiAoYmVuY2htYXJrKSB7XG4gICAgICBjb25zb2xlLmxvZygnU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zOicsIHN0b3BDb3VudGVyKCksICdtcy4nKTtcbiAgICB9XG4gIH1cblxuICAvLyBNZXJnZSB0aGUgcmVxdWVzdCBvcHRpb25zIGludG8gZGVmYXVsdCBvbmVzXG4gIGNvbnN0IG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoZGVmYXVsdE9wdGlvbnMsIHJlcXVlc3RPcHRpb25zKTtcblxuICAvLyBNZXJnZSBjb25maWcgb3B0aW9uc1xuICBpZiAoYmVuY2htYXJrKSB7XG4gICAgY29uc29sZS5sb2coJ01lcmdlIGNvbmZpZyBvcHRpb25zOicsIHN0b3BDb3VudGVyKCksICdtcy4nKTtcbiAgfVxuXG4gIC8vIFNhdmUgdGhlIEpTT04gaWYgZXhpc3RzXG4gIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBpbnN0cjtcblxuICAvLyBMYXN0bHksIGFkZCB0aGUgc2VydmVyIHNwZWNpZmljIGFyZ3VtZW50cyBpbnRvIG9wdGlvbnMgYXMgcGF5bG9hZFxuICBvcHRpb25zLnBheWxvYWQgPSB7XG4gICAgc3ZnOiBib2R5LnN2ZyB8fCBmYWxzZSxcbiAgICBiNjQ6IGJvZHkuYjY0IHx8IGZhbHNlLFxuICAgIGRhdGFPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkuZGF0YU9wdGlvbnMsIHRydWUpLFxuICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCB8fCBmYWxzZSxcbiAgICByZXF1ZXN0SWQ6IHVuaXF1ZUlkXG4gIH07XG5cbiAgLy8gU2V0dGluZyBwYXlsb2FkXG4gIGlmIChiZW5jaG1hcmspIHtcbiAgICBjb25zb2xlLmxvZygnU2V0dGluZyBwYXlsb2FkOicsIHN0b3BDb3VudGVyKCksICdtcy4nKTtcbiAgfVxuXG4gIC8vIFRlc3QgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkdcbiAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQob3B0aW9ucy5wYXlsb2FkLnN2ZykpIHtcbiAgICByZXR1cm4gcmVzcG9uc2VcbiAgICAgIC5zdGF0dXMoNDAwKVxuICAgICAgLnNlbmQoXG4gICAgICAgICdTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiB4bGluazpocmVmIGVsZW1lbnQuJ1xuICAgICAgKTtcbiAgfVxuXG4gIC8vIENoZWNrIFVSTCByYW5nZVxuICBpZiAoYmVuY2htYXJrKSB7XG4gICAgY29uc29sZS5sb2coJ0NoZWNrIFVSTCByYW5nZTonLCBzdG9wQ291bnRlcigpLCAnbXMuJyk7XG4gIH1cblxuICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcbiAgc3RhcnRFeHBvcnQob3B0aW9ucywgKGluZm8sIGVycm9yKSA9PiB7XG4gICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcbiAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XG5cbiAgICAvLyBBZnRlciBQdXBwZXRlZXIgZXhwb3J0aW5nXG4gICAgaWYgKGJlbmNobWFyaykge1xuICAgICAgY29uc29sZS5sb2coJ0FmdGVyIFB1cHBldGVlciBleHBvcnRpbmc6Jywgc3RvcENvdW50ZXIoKSwgJ21zLicsICdcXG4nKTtcbiAgICB9XG5cbiAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXG4gICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XG4gICAgICByZXR1cm4gbG9nKFxuICAgICAgICAzLFxuICAgICAgICBjbGVhclRleHQoXG4gICAgICAgICAgYFtleHBvcnRdIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgd2FzIGRvbmVcbiAgICAgICAgICBwcm9jZXNzaW5nLmBcbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBJZiBlcnJvciwgcmV0dXJuIGl0XG4gICAgaWYgKGVycm9yKSB7XG4gICAgICBsb2coXG4gICAgICAgIDEsXG4gICAgICAgIGNsZWFyVGV4dChcbiAgICAgICAgICBgW2V4cG9ydF0gV29yazogJHt1bmlxdWVJZH0gY291bGQgbm90IGJlIGNvbXBsZXRlZCwgc2VuZGluZzpcbiAgICAgICAgICAke2Vycm9yfWBcbiAgICAgICAgKVxuICAgICAgKTtcbiAgICAgIHJldHVybiByZXNwb25zZS5zdGF0dXMoNDAwKS5zZW5kKGVycm9yLm1lc3NhZ2UpO1xuICAgIH1cblxuICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgcmV0dXJuIHRoZSBlcnJvclxuICAgIGlmICghaW5mbyB8fCAhaW5mby5kYXRhKSB7XG4gICAgICBsb2coXG4gICAgICAgIDEsXG4gICAgICAgIGNsZWFyVGV4dChcbiAgICAgICAgICBgW2V4cG9ydF0gVW5leHBlY3RlZCByZXR1cm4gZnJvbSBjaGFydCBnZW5lcmF0aW9uLCBwbGVhc2UgY2hlY2sgeW91clxuICAgICAgICAgIGRhdGEgUmVxdWVzdDogJHt1bmlxdWVJZH0gaXMgJHtpbmZvLmRhdGF9LmBcbiAgICAgICAgKVxuICAgICAgKTtcbiAgICAgIHJldHVybiByZXNwb25zZVxuICAgICAgICAuc3RhdHVzKDQwMClcbiAgICAgICAgLnNlbmQoXG4gICAgICAgICAgJ1VuZXhwZWN0ZWQgcmV0dXJuIGZyb20gY2hhcnQgZ2VuZXJhdGlvbiwgcGxlYXNlIGNoZWNrIHlvdXIgZGF0YS4nXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gR2V0IHRoZSB0eXBlIGZyb20gb3B0aW9uc1xuICAgIHR5cGUgPSBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGU7XG5cbiAgICAvLyBUaGUgYWZ0ZXIgcmVxdWVzdCBjYWxsYmFja3NcbiAgICBkb0NhbGxiYWNrcyhhZnRlclJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7IGlkLCBib2R5OiBpbmZvLmRhdGEgfSk7XG5cbiAgICBpZiAoaW5mby5kYXRhKSB7XG4gICAgICAvLyBJZiBvbmx5IGJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XG4gICAgICBpZiAoYm9keS5iNjQpIHtcbiAgICAgICAgLy8gQ2hlY2sgaWYgaXQgaXMgYWxyZWFkeSBiYXNlNjQgb3IgYSByYXcgU1ZHXG4gICAgICAgIGlmICh0eXBlID09PSAncGRmJykge1xuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKFxuICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5kYXRhLCAndXRmOCcpLnRvU3RyaW5nKCdiYXNlNjQnKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoaW5mby5kYXRhKTtcbiAgICAgIH1cblxuICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXG4gICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XG5cbiAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXG4gICAgICBpZiAoIWJvZHkubm9Eb3dubG9hZCkge1xuICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KFxuICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7dHlwZSB8fCAncG5nJ31gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnRcbiAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xuICAgICAgICA/IHJlc3BvbnNlLnNlbmQoaW5mby5kYXRhKVxuICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oaW5mby5kYXRhLCAnYmFzZTY0JykpO1xuICAgIH1cbiAgfSk7XG59O1xuXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XG4gIGFwcC5wb3N0KCcvJywgZXhwb3J0SGFuZGxlcik7XG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgZXhwb3J0SGFuZGxlcik7XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XG5pbXBvcnQgeyBwb3NpeCB9IGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQgYm9keVBhcnNlciBmcm9tICdib2R5LXBhcnNlcic7XG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcbmltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IG11bHRlciBmcm9tICdtdWx0ZXInO1xuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xuXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICcuL3JhdGVfbGltaXQuanMnO1xuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xuXG5pbXBvcnQgaGVhbHRoUm91dGUgZnJvbSAnLi9yb3V0ZXMvaGVhbHRoLmpzJztcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcbmltcG9ydCB2c3dpdGNoUm91dGUgZnJvbSAnLi9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMnO1xuaW1wb3J0IHVpUm91dGUgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xuXG4vLyBDcmVhdGUgZXhwcmVzcyBhcHBcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcblxuLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxuYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xuXG4vLyBFbmFibGUgQ09SUyBzdXBwb3J0XG5hcHAudXNlKGNvcnMoKSk7XG5cbi8vIEVuYWJsZSBwYXJzaW5nIG9mIGZvcm0gZGF0YSAoZmlsZXMpIHdpdGggTXVsdGVyIHBhY2thZ2VcbmNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xuY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcbiAgc3RvcmFnZSxcbiAgbGltaXRzOiB7XG4gICAgZmllbGRzU2l6ZTogJzUwTUInXG4gIH1cbn0pO1xuXG5hcHAudXNlKHVwbG9hZC5hbnkoKSk7XG5cbi8vIEVuYWJsZSBib2R5IHBhcnNlclxuYXBwLnVzZShib2R5UGFyc2VyLmpzb24oeyBsaW1pdDogJzUwbWInIH0pKTtcbmFwcC51c2UoYm9keVBhcnNlci51cmxlbmNvZGVkKHsgZXh0ZW5kZWQ6IHRydWUsIGxpbWl0OiAnNTBtYicgfSkpO1xuYXBwLnVzZShib2R5UGFyc2VyLnVybGVuY29kZWQoeyBleHRlbmRlZDogZmFsc2UsIGxpbWl0OiAnNTBtYicgfSkpO1xuXG4vKipcbiAqIEVycm9yIGhhbmRsZXIgZnVuY3Rpb24uXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGVycm9yIC0gQW4gZXJyb3Igb2JqZWN0LlxuICogQHJldHVybiB7c3RyaW5nfSAtIEFuIGVycm9yIG1lc3NhZ2UuXG4gKi9cbmNvbnN0IGVycm9ySGFuZGxlciA9IChlcnJvcikgPT4gbG9nKDEsIGBbc2VydmVyXSBTb2NrZXQgZXJyb3I6ICR7ZXJyb3J9YCk7XG5cbi8qKlxuICogQXR0YWNoZXMgZXJyb3IgaGFuZGxlcnMgZm9yIGEgc2VydmVyLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBzZXJ2ZXIgLSBUaGUgaHR0cC9odHRwcyBzZXJ2ZXIuXG4gKi9cbmNvbnN0IGF0dGFjaEVycm9ySGFuZGxlcnMgPSAoc2VydmVyKSA9PiB7XG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCBlcnJvckhhbmRsZXIpO1xuICBzZXJ2ZXIub24oJ2Vycm9yJywgZXJyb3JIYW5kbGVyKTtcbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT5cbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiBlcnJvckhhbmRsZXIoZXJyb3IsIHNvY2tldCkpXG4gICk7XG59O1xuXG5leHBvcnQgY29uc3Qgc3RhcnRTZXJ2ZXIgPSBhc3luYyAoc2VydmVyQ29uZmlnKSA9PiB7XG4gIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcbiAgaWYgKCFzZXJ2ZXJDb25maWcuZW5hYmxlKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gLy8gR2V0IHRoZSBwb29sXG4gIC8vIGNvbnN0IHBvb2wgPSBnZXRQb29sKCk7XG5cbiAgLy8gLy8gVHJ5IHRvIGNyZWF0ZSBicm93c2VyIGluc3RhbmNlIGJlZm9yZSBzdGFydGluZyB0aGUgc2VydmVyXG4gIC8vIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCk7XG5cbiAgLy8gLy8gSWYgbm90IGZvdW5kLCB0aHJvdyBhbiBlcnJvclxuICAvLyBpZiAoIXJlc291cmNlLmJyb3dzZXIpIHtcbiAgLy8gICBsb2coMSwgYFtzZXJ2ZXJdIENvdWxkIG5vdCBhY3F1aXJlIGJyb3dzZXIgaW5zdGFuY2UuYCk7XG4gIC8vICAgcHJvY2Vzcy5leGl0KDEpO1xuICAvLyB9XG5cbiAgLy8gLy8gUmVsZWFzZSB0aGUgcmVzb3VyY2VcbiAgLy8gcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcblxuICAvLyBMaXN0ZW4gSFRUUCBzZXJ2ZXJcbiAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmVuYWJsZSAmJiAhc2VydmVyQ29uZmlnLnNzbC5mb3JjZSkge1xuICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxuICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xuICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcbiAgICBhdHRhY2hFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xuICAgIC8vIExpc3RlblxuICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XG5cbiAgICBsb2coXG4gICAgICAzLFxuICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcucG9ydH0uYFxuICAgICk7XG4gIH1cblxuICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXG4gIGlmIChzZXJ2ZXJDb25maWcuc3NsLmVuYWJsZSkge1xuICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cbiAgICBsZXQga2V5LCBjZXJ0O1xuXG4gICAgdHJ5IHtcbiAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxuICAgICAga2V5ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcbiAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmtleScpLFxuICAgICAgICAndXRmOCdcbiAgICAgICk7XG5cbiAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXG4gICAgICBjZXJ0ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcbiAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmNydCcpLFxuICAgICAgICAndXRmOCdcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZyhcbiAgICAgICAgMSxcbiAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tICR7c2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aH0uYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoa2V5ICYmIGNlcnQpIHtcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcbiAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKGFwcCk7XG4gICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXG4gICAgICBhdHRhY2hFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcbiAgICAgIC8vIExpc3RlblxuICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5zc2wucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xuXG4gICAgICBsb2coXG4gICAgICAgIDMsXG4gICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5zc2wucG9ydH0uYFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBFbmFibGUgdGhlIHJhdGUgbGltaXRlciBpZiBjb25maWcgc2F5cyBzb1xuICBpZiAoXG4gICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyAmJlxuICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcuZW5hYmxlICYmXG4gICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXG4gICkge1xuICAgIHJhdGVMaW1pdChhcHAsIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcpO1xuICB9XG5cbiAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxuICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKHBvc2l4LmpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcblxuICAvLyBTZXQgdXAgcm91dGVzXG4gIGhlYWx0aFJvdXRlKGFwcCk7XG4gIGV4cG9ydFJvdXRlcyhhcHApO1xuICB1aVJvdXRlKGFwcCk7XG4gIHZzd2l0Y2hSb3V0ZShhcHApO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBleHByZXNzIGluc3RhbmNlLlxuICovXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IHtcbiAgcmV0dXJuIGV4cHJlc3M7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGFwcCBpbnN0YW5jZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldEFwcCA9ICgpID0+IHtcbiAgcmV0dXJuIGFwcDtcbn07XG5cbi8qKlxuICogQWRkcyBhIG1pZGRsZXdhcmUgdG8gdGhlIHNlcnZlci5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gcGF0aCAtIEFuIGVuZHBvaW50IHBhdGggdG8gYWRkIG1pZGRsZXdhcmVzIHRvLlxuICogQHBhcmFtIHtBcnJheX0gbWlkZGxld2FyZXMgLSBBbiB1bmxpbWl0ZWQgbnVtYmVyIG9mIG1pZGRsZXdhcmVzIHRvIHVzZVxuICogYWdhaW5zdCB0aGUgc3BlY2lmaWMgZW5kcG9pbnQuXG4gKi9cbmV4cG9ydCBjb25zdCB1c2UgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XG59O1xuXG4vKipcbiAqIEFkZHMgYSBnZXQgcm91dGUgdG8gdGhlIHNlcnZlci5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gcGF0aCAtIEFuIGVuZHBvaW50IHBhdGggdG8gYWRkIG1pZGRsZXdhcmVzIHRvLlxuICogQHBhcmFtIHtBcnJheX0gbWlkZGxld2FyZXMgLSBBbiB1bmxpbWl0ZWQgbnVtYmVyIG9mIG1pZGRsZXdhcmVzIHRvIHVzZVxuICogYWdhaW5zdCB0aGUgc3BlY2lmaWMgZW5kcG9pbnQgZm9yIEdFVCBtZXRob2QuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXQgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XG59O1xuXG4vKipcbiAqIEFkZHMgYSBwb3N0IHJvdXRlIHRvIHRoZSBzZXJ2ZXIuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IHBhdGggLSBBbiBlbmRwb2ludCBwYXRoIHRvIGFkZCBtaWRkbGV3YXJlcyB0by5cbiAqIEBwYXJhbSB7QXJyYXl9IG1pZGRsZXdhcmVzIC0gQW4gdW5saW1pdGVkIG51bWJlciBvZiBtaWRkbGV3YXJlcyB0byB1c2VcbiAqIGFnYWluc3QgdGhlIHNwZWNpZmljIGVuZHBvaW50IGZvciBQT1NUIG1ldGhvZC5cbiAqL1xuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xufTtcblxuLyoqXG4gKiBGb3JjZWZ1bGx5IGVuYWJsZXMgcmF0ZSBsaW1pdGluZy5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gbGltaXRDb25maWcgLSBUaGUgb3B0aW9ucyBvYmplY3QgZm9yIHRoZSByYXRlIGxpbWl0ZXJcbiAqIGNvbmZpZ3VyYXRpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHtcbiAgcmV0dXJuIHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgc3RhcnRTZXJ2ZXIsXG4gIGdldEV4cHJlc3MsXG4gIGdldEFwcCxcbiAgdXNlLFxuICBnZXQsXG4gIHBvc3QsXG4gIGVuYWJsZVJhdGVMaW1pdGluZ1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XG5cbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcbi8qKlxuICogQWRkcyB0aGUgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgZm9yIHRoZSBleHBvcnQgc2VydmVyXG4gKi9cbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XG4gICFhcHBcbiAgICA/IGZhbHNlXG4gICAgOiBhcHAuZ2V0KCcvJywgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSk7XG4gICAgICB9KTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgY2FjaGUgZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xuXG4vKipcbiAqIEFkZHMgYSByb3V0ZSB0aGF0IGNhbiBiZSB1c2VkIHRvIGNoYW5nZSB0aGUgSEMgdmVyc2lvbiBvbiB0aGUgc2VydmVyXG4gKiBUT0RPOiBBZGQgYXV0aCB0b2tlbiBhbmQgY29ubmVjdCB0byBBUElcbiAqL1xuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cbiAgIWFwcFxuICAgID8gZmFsc2VcbiAgICA6IGFwcC5wb3N0KCcvY2hhbmdlX2hjX3ZlcnNpb24vOm5ld1ZlcnNpb24nLCBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcbiAgICAgICAgY29uc3QgY3Rva2VuID0gcHJvY2Vzcy5lbnYuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcblxuICAgICAgICBpZiAoIWN0b2tlbiB8fCAhY3Rva2VuLmxlbmd0aCkge1xuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKHtcbiAgICAgICAgICAgIGVycm9yOiB0cnVlLFxuICAgICAgICAgICAgbWVzc2FnZTpcbiAgICAgICAgICAgICAgJ1NlcnZlciBub3QgY29uZmlndXJlZCB0byBkbyBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gbm90IHNldCdcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcblxuICAgICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBjdG9rZW4pIHtcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZCh7XG4gICAgICAgICAgICBlcnJvcjogdHJ1ZSxcbiAgICAgICAgICAgIG1lc3NhZ2U6ICdJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IHNldCB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXInXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcblxuICAgICAgICBpZiAobmV3VmVyc2lvbikge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXG4gICAgICAgICAgICBhd2FpdCBjYWNoZS51cGRhdGVWZXJzaW9uKG5ld1ZlcnNpb24pO1xuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJlc3BvbnNlLnNlbmQoe1xuICAgICAgICAgICAgICBlcnJvcjogdHJ1ZSxcbiAgICAgICAgICAgICAgbWVzc2FnZTogZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmVzcG9uc2Uuc2VuZCh7XG4gICAgICAgICAgICB2ZXJzaW9uOiBjYWNoZS52ZXJzaW9uKClcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXNwb25zZS5zZW5kKHtcbiAgICAgICAgICAgIGVycm9yOiB0cnVlLFxuICAgICAgICAgICAgbWVzc2FnZTogJ05vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkJ1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vLyBBZGQgdGhlIG1haW4gZGlyZWN0b3J5IGluIHRoZSBnbG9iYWwgb2JqZWN0XG5pbXBvcnQgJ2NvbG9ycyc7XG5cbmltcG9ydCBzZXJ2ZXIsIHsgc3RhcnRTZXJ2ZXIgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xuaW1wb3J0IHtcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxuICBiYXRjaEV4cG9ydCxcbiAgc2luZ2xlRXhwb3J0LFxuICBzdGFydEV4cG9ydFxufSBmcm9tICcuL2NoYXJ0LmpzJztcbmltcG9ydCB7IG1hcFRvTmV3Q29uZmlnLCBzZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xuaW1wb3J0IHsgbG9nLCBzZXRMb2dMZXZlbCwgZW5hYmxlRmlsZUxvZ2dpbmcgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBraWxsUG9vbCwgaW5pdCB9IGZyb20gJy4vcG9vbC5qcyc7XG5pbXBvcnQgeyBjaGVja0NhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgbG9nLFxuICBtYXBUb05ld0NvbmZpZyxcbiAgc2V0T3B0aW9ucyxcbiAgc2luZ2xlRXhwb3J0LFxuICBzdGFydEV4cG9ydCxcbiAgYmF0Y2hFeHBvcnQsXG4gIHNlcnZlcixcbiAgc3RhcnRTZXJ2ZXIsXG4gIGtpbGxQb29sLFxuICBpbml0UG9vbDogYXN5bmMgKG9wdGlvbnMgPSB7fSkgPT4ge1xuICAgIC8vIFNldCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXG4gICAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKFxuICAgICAgb3B0aW9ucy5jdXN0b21Db2RlICYmIG9wdGlvbnMuY3VzdG9tQ29kZS5hbGxvd0NvZGVFeGVjdXRpb25cbiAgICApO1xuXG4gICAgLy8gU2V0IHRoZSBsb2cgbGV2ZWxcbiAgICBzZXRMb2dMZXZlbChvcHRpb25zLmxvZ2dpbmcgJiYgcGFyc2VJbnQob3B0aW9ucy5sb2dnaW5nLmxldmVsKSk7XG5cbiAgICAvLyBTZXQgdGhlIGxvZyBmaWxlIHBhdGggYW5kIG5hbWVcbiAgICBpZiAob3B0aW9ucy5sb2dnaW5nICYmIG9wdGlvbnMubG9nZ2luZy5kZXN0KSB7XG4gICAgICBlbmFibGVGaWxlTG9nZ2luZyhcbiAgICAgICAgb3B0aW9ucy5sb2dnaW5nLmRlc3QsXG4gICAgICAgIG9wdGlvbnMubG9nZ2luZy5maWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJ1xuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXG4gICAgYXdhaXQgY2hlY2tDYWNoZShvcHRpb25zLmhpZ2hjaGFydHMgfHwgeyB2ZXJzaW9uOiAnbGF0ZXN0JyB9KTtcblxuICAgIC8vIEluaXQgdGhlIHBvb2xcbiAgICBhd2FpdCBpbml0KHtcbiAgICAgIHBvb2w6IG9wdGlvbnMucG9vbCB8fCB7XG4gICAgICAgIGluaXRpYWxXb3JrZXJzOiAxLFxuICAgICAgICBtYXhXb3JrZXJzOiAxXG4gICAgICB9LFxuICAgICAgcHVwcGV0ZWVyQXJnczogb3B0aW9ucy5wdXBwZXRlZXI/LmFyZ3MgfHwgW11cbiAgICB9KTtcblxuICAgIC8vIFJldHVybiB1cGRhdGVkIG9wdGlvbnNcbiAgICByZXR1cm4gb3B0aW9ucztcbiAgfVxufTtcbiJdLCJuYW1lcyI6WyJkb3RlbnYiLCJjb25maWciLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJlbnZMaW5rIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVzIiwiaW5kaWNhdG9ycyIsInNjcmlwdHMiLCJmb3JjZUZldGNoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwiY3VzdG9tQ29kZSIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImNhbGxiYWNrIiwicmVzb3VyY2VzIiwibG9hZENvbmZpZyIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsImVuYWJsZSIsImNsaU5hbWUiLCJob3N0IiwicG9ydCIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJwb29sIiwiaW5pdGlhbFdvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwicXVldWVTaXplIiwidGltZW91dFRocmVzaG9sZCIsImFjcXVpcmVUaW1lb3V0IiwicmVhcGVyIiwiYmVuY2htYXJraW5nIiwibGlzdGVuVG9Qcm9jZXNzRXhpdHMiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vTG9nbyIsInBheWxvYWQiLCJqb2luIiwiYWJzb2x1dGVQcm9wcyIsIm5lc3RlZEFyZ3MiLCJjcmVhdGVOZXN0ZWRBcmdzIiwib2JqIiwicHJvcENoYWluIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJrIiwiaW5jbHVkZXMiLCJlbnRyeSIsInN1YnN0cmluZyIsInRvQ29uc29sZSIsInRvRmlsZSIsInBhdGhDcmVhdGVkIiwibGV2ZWxzRGVzYyIsInRpdGxlIiwiY29sb3IiLCJsaXN0ZW5lcnMiLCJrZXkiLCJvcHRpb24iLCJlbnRyaWVzIiwibG9nIiwibmV3TGV2ZWwiLCJ0ZXh0cyIsImxlbmd0aCIsInByZWZpeCIsIkRhdGUiLCJ0b1N0cmluZyIsInNwbGl0IiwidHJpbSIsImZuIiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJlcnJvciIsImNvbnNvbGUiLCJhcHBseSIsInVuZGVmaW5lZCIsIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0Iiwic3JjIiwiYmFzZVVSSSIsImNsZWFyVGV4dCIsInRleHQiLCJydWxlIiwicmVwbGFjZXIiLCJyZXBsYWNlQWxsIiwiZml4VHlwZSIsImZvcm1hdHMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJoYW5kbGVSZXNvdXJjZXMiLCJhbGxvd2VkUHJvcHMiLCJoYW5kbGVkUmVzb3VyY2VzIiwiY29ycmVjdFJlc291cmNlcyIsImVuZHNXaXRoIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsIm5vdGljZSIsImZpbGVzIiwicHJvcE5hbWUiLCJtYXAiLCJpdGVtIiwiZGF0YSIsInBhcnNlZERhdGEiLCJKU09OIiwicGFyc2UiLCJzdHJpbmdpZnkiLCJkZWVwQ29weSIsImNvcHkiLCJBcnJheSIsImlzQXJyYXkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJvcHRpb25zU3RyaW5naWZ5IiwiYWxsb3dGdW5jdGlvbnMiLCJuYW1lIiwic3RhcnRzV2l0aCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwiY2F0ZWdvcmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwidG9VcHBlckNhc2UiLCJyZWQiLCJ0b0Jvb2xlYW4iLCJ3cmFwQXJvdW5kIiwicmVwbGFjZSIsInJhdGVMaW1pdCIsImFwcCIsImxpbWl0Q29uZmlnIiwibXNnIiwicmF0ZU9wdGlvbnMiLCJtYXgiLCJsaW1pdGVyIiwid2luZG93TXMiLCJkZWxheU1zIiwiaGFuZGxlciIsInJlcXVlc3QiLCJyZXNwb25zZSIsImZvcm1hdCIsImpzb24iLCJzdGF0dXMiLCJzZW5kIiwibWVzc2FnZSIsImRlZmF1bHQiLCJza2lwIiwicXVlcnkiLCJhY2Nlc3NfdG9rZW4iLCJ1c2UiLCJhc3luYyIsImZldGNoIiwidXJsIiwicmVxdWVzdE9wdGlvbnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInByb3RvY29sIiwiaHR0cHMiLCJodHRwIiwiZ2V0UHJvdG9jb2wiLCJnZXQiLCJyZXMiLCJvbiIsImNodW5rIiwiY2FjaGVQYXRoIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJhcHBsaWVkQ29uZmlnIiwiZXh0cmFjdFZlcnNpb24iLCJzdWJzdHIiLCJpbmRleE9mIiwiZmV0Y2hTY3JpcHQiLCJzY3JpcHQiLCJwcm94eUFnZW50IiwiYWdlbnQiLCJ0aW1lb3V0IiwicHJvY2VzcyIsImVudiIsInN0YXR1c0NvZGUiLCJ1cGRhdGVDYWNoZSIsInNvdXJjZVBhdGgiLCJjdXN0b21TY3JpcHRzIiwiYWxsU2NyaXB0cyIsImMiLCJtIiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwiSHR0cHNQcm94eUFnZW50IiwiZmV0Y2hlZE1vZHVsZXMiLCJhbGwiLCJ3cml0ZUZpbGVTeW5jIiwiY2hlY2tDYWNoZSIsIm1hbmlmZXN0UGF0aCIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZU1hcCIsIm51bWJlck9mTW9kdWxlcyIsInNvbWUiLCJtb2R1bGVOYW1lIiwibmV3TWFuaWZlc3QiLCJzYXZlQ29uZmlnVG9NYW5pZmVzdCIsImNhY2hlJDEiLCJuZXdWZXJzaW9uIiwiYXNzaWduIiwiUkFORE9NX1BJRCIsInJhbmRvbUJ5dGVzIiwiUFVQUEVURUVSX0RJUiIsInBhdGgiLCJtaW5pbWFsQXJncyIsInRlbXBsYXRlIiwiZnMiLCJicm93c2VyIiwibmV3UGFnZSIsInAiLCJzZXRDb250ZW50IiwiYWRkU2NyaXB0VGFnIiwiZXZhbHVhdGUiLCJzZXR1cEhpZ2hjaGFydHMiLCJlcnIiLCIkZXZhbCIsImVsZW1lbnQiLCJlcnJvck1lc3NhZ2UiLCJfZGlzcGxheUVycm9ycyIsImlubmVySFRNTCIsImNsb3NlIiwiY29ubmVjdGVkIiwiX19iYXNlZGlyIiwic2V0QXNDb25maWciLCJwYWdlIiwiY2hhcnQiLCJ0cmlnZ2VyRXhwb3J0IiwicHVwcGV0ZWVyRXhwb3J0IiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJjbGVhckluamVjdGVkIiwiZGlzcG9zZSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwicmVtb3ZlIiwiZXhwb3J0QmVuY2giLCJleHBvcnRPcHRpb25zIiwicmVxdWVzdEFuaW1hdGlvbkZyYW1lIiwiZGlzcGxheUVycm9ycyIsImRlYnVnZ2VyIiwiZCIsInN2Z0JlbmNoIiwiaXNTVkciLCJzZXRQYWdlQmVuY2giLCJzdmdUZW1wbGF0ZSIsInN0ckluaiIsInNldENvbnRlbnRCZW5jaCIsInJlc0JlbmNoIiwianMiLCJwdXNoIiwiY29udGVudCIsImlzTG9jYWwiLCJjc3NCZW5jaCIsImNzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJhZGRTdHlsZVRhZyIsInNpemUiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwicGFyc2VGbG9hdCIsIkhpZ2hjaGFydHMiLCJjaGFydHMiLCJ2cEJlbmNoIiwidmlld3BvcnRIZWlnaHQiLCJNYXRoIiwiY2VpbCIsInZpZXdwb3J0V2lkdGgiLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwiem9vbUNhbGxiYWNrIiwiYm9keSIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsIngiLCJ5IiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidHJ1bmMiLCJnZXRDbGlwUmVnaW9uIiwicm91bmQiLCJleHBCZW5jaG1hcmsiLCJvdXRlckhUTUwiLCJjcmVhdGVTVkciLCJlbmNvZGluZyIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsIm9taXRCYWNrZ3JvdW5kIiwic2V0VGltZW91dCIsIkVycm9yIiwiY3JlYXRlSW1hZ2UiLCJwZGYiLCJjcmVhdGVQREYiLCJvbGRDaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzaGlmdCIsInB1cHBldGVlckFyZ3MiLCJwZXJmb3JtZWRFeHBvcnRzIiwiZXhwb3J0QXR0ZW1wdHMiLCJ0aW1lU3BlbnQiLCJkcm9wcGVkRXhwb3J0cyIsInNwZW50QXZlcmFnZSIsInBvb2xDb25maWciLCJmYWN0b3J5IiwiY3JlYXRlIiwiaWQiLCJ1dWlkIiwicyIsImdldFRpbWUiLCJicm93c2VyTmV3UGFnZSIsImlzQ2xvc2VkIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJsb2dMZXZlbCIsImluaXQiLCJhbGxBcmdzIiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwiaGVhZGxlc3MiLCJ1c2VyRGF0YURpciIsImUiLCJjcmVhdGVCcm93c2VyIiwia2lsbFBvb2wiLCJjb2RlIiwiZXhpdCIsIlBvb2wiLCJtaW4iLCJjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzIiwiY3JlYXRlVGltZW91dE1pbGxpcyIsImFjcXVpcmVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiZXZlbnRJZCIsInJlc291cmNlIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsImRlc3Ryb3llZCIsInBvc3RXb3JrIiwiZmFpbCIsImdldFBvb2xJbmZvIiwid29ya1N0YXJ0IiwicmVzdWx0IiwiZXhwb3J0VGltZSIsImF2YWlsYWJsZSIsImJvcnJvd2VkIiwicGVuZGluZyIsInNwYXJlUmVzb3VyY2VDYXBhY2l0eSIsInBvb2wkMSIsInBhY2thZ2VWZXJzaW9uIiwibnBtX3BhY2thZ2VfdmVyc2lvbiIsInNlcnZlclN0YXJ0VGltZSIsImdlbmVyYWxPcHRpb25zIiwiZ2V0T3B0aW9ucyIsIm1lcmdlQ29uZmlnT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJtZXJnZWRPcHRpb25zIiwidXBkYXRlRGVmYXVsdENvbmZpZyIsImNvbmZpZ09iaiIsImN1c3RvbU9iaiIsImN1c3RvbVZhbHVlIiwibnVtRW52VmFsIiwiZWwiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwic3RhcnRFeHBvcnQiLCJzZXR0aW5ncyIsImVuZENhbGxiYWNrIiwic3ZnIiwiaW5pdEV4cG9ydFNldHRpbmdzIiwiZXhwb3J0QXNTdHJpbmciLCJyZWFkRmlsZSIsImRvU3RyYWlnaHRJbmplY3QiLCJkb0V4cG9ydCIsImZpbmRDaGFydFNpemUiLCJleHBvcnRpbmciLCJwcmVjaXNpb24iLCJtdWx0aXBsaWVyIiwicG93Iiwicm91bmROdW1iZXIiLCJzb3VyY2VIZWlnaHQiLCJzb3VyY2VXaWR0aCIsImNoYXJ0SnNvbiIsImN1c3RvbUNvZGVPcHRpb25zIiwiYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkIiwiZW5hYmxlZCIsIm9wdGlvbnNOYW1lIiwidGhlbiIsImNhdGNoIiwicmVxdWVzdElkIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJyZXZlcnNlZE1pbWUiLCJwbmciLCJqcGVnIiwiZ2lmIiwicmVxdWVzdHNDb3VudGVyIiwiYmVmb3JlUmVxdWVzdCIsImFmdGVyUmVxdWVzdCIsImRvQ2FsbGJhY2tzIiwiY2FsbGJhY2tzIiwidW5pcXVlSWQiLCJjYWxsUmVzcG9uc2UiLCJleHBvcnRIYW5kbGVyIiwic3RhcnQiLCJocnRpbWUiLCJiaWdpbnQiLCJtZWFzdXJlVGltZSIsImRlZmF1bHRPcHRpb25zIiwiaGVhZGVycyIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJ0b0xvd2VyQ2FzZSIsImI2NCIsImRhdGFPcHRpb25zIiwibm9Eb3dubG9hZCIsImlwUmVnRXgiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJwYXJhbXMiLCJmaWxlbmFtZSIsImV4cHJlc3MiLCJkaXNhYmxlIiwiY29ycyIsInN0b3JhZ2UiLCJtdWx0ZXIiLCJtZW1vcnlTdG9yYWdlIiwidXBsb2FkIiwibGltaXRzIiwiZmllbGRzU2l6ZSIsImFueSIsImJvZHlQYXJzZXIiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsImVycm9ySGFuZGxlciIsImF0dGFjaEVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJjZXJ0IiwiZnNQcm9taXNlcyIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJoZWFsdGhSb3V0ZSIsInBvc3QiLCJleHBvcnRSb3V0ZXMiLCJzZW5kRmlsZSIsInVpUm91dGUiLCJjdG9rZW4iLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwidG9rZW4iLCJ2c3dpdGNoUm91dGUiLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJlbmFibGVSYXRlTGltaXRpbmciLCJpbmRleCIsIm1hcFRvTmV3Q29uZmlnIiwib2xkT3B0aW9ucyIsInByb3BlcnRpZXNDaGFpbiIsInJlZHVjZSIsInByb3AiLCJzZXRPcHRpb25zIiwidXNlck9wdGlvbnMiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJwYWlyQXJndW1lbnRWYWx1ZSIsInNpbmdsZUV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiaW5pdFBvb2wiLCJwYXJzZUludCIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5hYmxlRmlsZUxvZ2dpbmciXSwibWFwcGluZ3MiOiI2dUJBaUJBQSxFQUFPQyxTQUlBLE1BQU1DLEVBQWdCLENBQzNCQyxVQUFXLENBQ1RDLEtBQU0sQ0FDSkMsTUFBTyxHQUNQQyxLQUFNLFdBQ05DLFlBQWEsNkNBR2pCQyxXQUFZLENBQ1ZDLFFBQVMsQ0FDUEosTUFBTyxTQUNQSyxRQUFTLHFCQUNUSixLQUFNLFNBQ05DLFlBQWEsOEJBRWZJLE9BQVEsQ0FDTk4sTUFBTywrQkFDUEssUUFBUyxpQkFD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 +"use strict";require("colors");var e=require("fs"),t=require("path"),o=require("body-parser"),r=require("cors"),i=require("express"),n=require("multer"),s=require("http"),a=require("https"),l=require("dotenv"),c=require("express-rate-limit"),p=require("url"),u=require("https-proxy-agent"),d=require("uuid"),h=require("tarn"),g=require("puppeteer"),f=require("node:path"),m=require("node:crypto");require("prompts");var v="undefined"!=typeof document?document.currentScript:null;function y(e){var t=Object.create(null);return e&&Object.keys(e).forEach((function(o){if("default"!==o){var r=Object.getOwnPropertyDescriptor(e,o);Object.defineProperty(t,o,r.get?r:{enumerable:!0,get:function(){return e[o]}})}})),t.default=e,Object.freeze(t)}var b=y(p);l.config();const w={puppeteer:{args:{value:[],type:"string[]",description:"Array of arguments to send to puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"Highcharts version to use."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN",type:"string",description:"The CDN URL of Highcharts scripts to use."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"Highcharts core scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","draggable-points","static-scale","broken-axis","heatmap","tilemap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","pyramid3d","networkgraph","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","stock-tools","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi"],type:"string[]",description:"Highcharts modules to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"Highcharts indicators to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional direct scripts/optional dependencies (e.g. moment.js)."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"Should all the scripts be refetched after rerunning the server."}},export:{infile:{value:!1,type:"string",description:"The input file name along with a type (json or svg). It can be a correct JSON or SVG file."},instr:{value:!1,type:"string",description:"An input in a form of a stringified JSON or SVG file. Overrides the --infile."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf or svg). Ignores the --type flag."},type:{envLink:"EXPORT_DEFAULT_TYPE",value:"png",type:"string",description:"The format of the file to export to. Can be jpeg, png, pdf or svg."},constr:{envLink:"EXPORT_DEFAULT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"The default height of the exported chart. Used when not found any value set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when not found any value set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Ranges between 1 and 5."},height:{type:"number",value:!1,description:"The default height of the exported chart. Overrides the option in the chart settings."},width:{type:"number",value:!1,description:"The width of the exported chart. Overrides the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart. Ranges between 1 and 5."},globalOptions:{value:!1,type:"string",description:"A stringified JSON or a filename with options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"A stringified JSON or a filename with theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Starts a batch job. A string that contains input/output pairs: "in=out;in=out;..".'}},customCode:{allowCodeExecution:{envLink:"HIGHCHARTS_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"If set to true, allow for the execution of arbitrary code when exporting."},allowFileResources:{envLink:"HIGHCHARTS_ALLOW_FILE_RESOURCES",value:!0,type:"boolean",description:"Allow injecting resources from the filesystem. Has no effect when running as a server."},customCode:{value:!1,type:"string",description:"A function to be called before chart initialization. Can be a filename with the js extension."},callback:{value:!1,type:"string",description:"A JavaScript file with a function to run on construction."},resources:{value:!1,type:"string",description:"An additional resource in a form of stringified JSON. It can contain files, js and css sections."},loadConfig:{value:!1,type:"string",description:"A file that contains a pre-defined config to use."},createConfig:{value:!1,type:"string",description:"Allows to set options through a prompt and save in a provided config file."}},server:{enable:{envLink:"HIGHCHARTS_SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"If set to true, starts a server on 0.0.0.0."},host:{envLink:"HIGHCHARTS_SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Also starts a server listening on the supplied hostname."},port:{envLink:"HIGHCHARTS_SERVER_PORT",value:7801,type:"number",description:"The port to use for the server. Defaults to 7801."},ssl:{enable:{envLink:"HIGHCHARTS_SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables the SSL protocol."},force:{envLink:"HIGHCHARTS_SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",description:"If set to true, forces the server to only serve over HTTPS."},port:{envLink:"HIGHCHARTS_SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"HIGHCHARTS_SSL_CERT_PATH",value:"",type:"string",description:"The path to the SSL certificate/key."}},rateLimiting:{enable:{envLink:"HIGHCHARTS_RATE_LIMIT_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting."},maxRequests:{envLink:"HIGHCHARTS_RATE_LIMIT_MAX",value:10,type:"number",description:"Max requests allowed in a one minute."},window:{envLink:"HIGHCHARTS_RATE_LIMIT_WINDOW",value:1,type:"number",description:"The time window in minutes for rate limiting."},delay:{envLink:"HIGHCHARTS_RATE_LIMIT_DELAY",value:0,type:"number",description:"The amount to delay each successive request before hitting the max."},trustProxy:{envLink:"HIGHCHARTS_RATE_LIMIT_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if behind a load balancer."},skipKey:{envLink:"HIGHCHARTS_RATE_LIMIT_SKIP_KEY",value:"",type:"number|string",description:"Allows bypassing the rate limiter and should be provided with skipToken argument."},skipToken:{envLink:"HIGHCHARTS_RATE_LIMIT_SKIP_TOKEN",value:"",type:"number|string",description:"Allows bypassing the rate limiter and should be provided with skipKey argument."}}},pool:{initialWorkers:{envLink:"HIGHCHARTS_POOL_MIN_WORKERS",value:4,type:"number",description:"The number of initial workers to spawn."},maxWorkers:{envLink:"HIGHCHARTS_POOL_MAX_WORKERS",value:8,type:"number",description:"The number of max workers to spawn."},workLimit:{envLink:"HIGHCHARTS_POOL_WORK_LIMIT",value:40,type:"number",description:"The pieces of work that can be performed before restarting process."},queueSize:{envLink:"HIGHCHARTS_POOL_QUEUE_SIZE",value:5,type:"number",description:"The size of the request overflow queue."},timeoutThreshold:{envLink:"HIGHCHARTS_POOL_TIMEOUT",value:5e3,type:"number",description:"The number of milliseconds before timing out."},acquireTimeout:{envLink:"HIGHCHARTS_POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The number of milliseconds to wait for acquiring a resource."},reaper:{envLink:"HIGHCHARTS_POOL_ENABLE_REAPER",value:!0,type:"boolean",description:"Whether or not to evict workers after a certain time period."},benchmarking:{envLink:"HIGHCHARTS_POOL_BENCHMARKING",value:!1,type:"boolean",description:"Enable benchmarking."},listenToProcessExits:{envLink:"HIGHCHARTS_POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Set to false in order to skip attaching process.exit handlers."}},logging:{level:{envLink:"HIGHCHARTS_LOG_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose)."},file:{envLink:"HIGHCHARTS_LOG_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"A name of a log file. The --logDest also needs to be set to enable file logging."},dest:{envLink:"HIGHCHARTS_LOG_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. Also enables file logging."}},ui:{enable:{envLink:"HIGHCHARTS_UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables the UI for the export server."},route:{envLink:"HIGHCHARTS_UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The route to attach the UI to."}},other:{noLogo:{envLink:"HIGHCHARTS_NO_LOGO",value:!1,type:"boolean",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}},payload:{}};w.puppeteer.args.value.join(","),w.highcharts.version.value,w.highcharts.cdnURL.value,w.highcharts.modules.value,w.highcharts.scripts.value.join(","),w.highcharts.forceFetch.value,w.export.type.value,w.export.constr.value,w.export.defaultHeight.value,w.export.defaultWidth.value,w.export.defaultScale.value,w.customCode.allowCodeExecution.value,w.customCode.allowFileResources.value,w.server.enable.value,w.server.host.value,w.server.port.value,w.server.ssl.enable.value,w.server.ssl.force.value,w.server.ssl.port.value,w.server.ssl.certPath.value,w.server.rateLimiting.enable.value,w.server.rateLimiting.maxRequests.value,w.server.rateLimiting.window.value,w.server.rateLimiting.delay.value,w.server.rateLimiting.trustProxy.value,w.server.rateLimiting.skipKey.value,w.server.rateLimiting.skipToken.value,w.pool.initialWorkers.value,w.pool.maxWorkers.value,w.pool.workLimit.value,w.pool.queueSize.value,w.pool.timeoutThreshold.value,w.pool.acquireTimeout.value,w.pool.reaper.value,w.pool.benchmarking.value,w.pool.listenToProcessExits.value,w.logging.level.value,w.logging.file.value,w.logging.dest.value,w.ui.enable.value,w.ui.route.value,w.other.noLogo.value;const x=["options","globalOptions","themeOptions","resources","payload"],T={},k=(e,t="")=>{Object.keys(e).forEach((o=>{if(!["puppeteer","highcharts"].includes(o)){const r=e[o];void 0===r.value?k(r,`${t}.${o}`):T[r.cliName||o]=`${t}.${o}`.substring(1)}}))};k(w);let S={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:"red"},{title:"warning",color:"yellow"},{title:"notice",color:"blue"},{title:"verbose",color:"gray"}],listeners:[]};for(const[e,t]of Object.entries(w.logging))S[e]=t.value;const H=(...t)=>{const[o,...r]=t,{level:i,levelsDesc:n}=S;if(0===o||o>i||i>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[o-1].title}] -`;S.listeners.forEach((e=>{e(s,r.join(" "))})),S.toFile&&(S.pathCreated||(!e.existsSync(S.dest)&&e.mkdirSync(S.dest),S.pathCreated=!0),e.appendFile(`${S.dest}${S.file}`,[s].concat(r).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),S.toFile=!1)}))),S.toConsole&&console.log.apply(void 0,[s.toString()[S.levelsDesc[o-1].color]].concat(r))},E=p.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:v&&v.src||new URL("index.cjs",document.baseURI).href)),R=(e,t=/\s\s+/g,o=" ")=>e.replaceAll(t,o).trim(),L=(e,t)=>{const o=["png","jpeg","pdf","svg"];if(t){const r=t.split(".").pop();o.includes(r)&&e!==r&&(e=r)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||o.find((t=>t===e))||"png"},C=(t=!1,o)=>{const r=["js","css","files"];let i=t,n=!1;if(o&&t.endsWith(".json"))try{t?t&&t.endsWith(".json")?i=O(e.readFileSync(t,"utf8")):(i=O(t),!0===i&&(i=O(e.readFileSync("resources.json","utf8")))):i=O(e.readFileSync("resources.json","utf8"))}catch(e){return H(3,"[cli] No resources found.")}else i=O(t),o||delete i.files;for(const e in i)r.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):H(3,"[cli] No resources found.")};function O(e,t){try{const o=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof o&&t?JSON.stringify(o):o}catch(e){return!1}}const _=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=_(e[o]));return t},A=(e,t)=>JSON.stringify(e,((e,o)=>("string"==typeof o&&((o=o.trim()).startsWith("function(")||o.startsWith("function ("))&&o.endsWith("}")&&(o=t?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof o?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:o))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function $(){console.log("Usage of CLI arguments:".bold,"\n------",`\nFor more detailed information visit readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[o,r]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(r,"value")){let e=` --${r.cliName||o} ${("<"+r.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,r.description,`[Default: ${r.value.toString().bold}]`.blue)}else e(r)};Object.keys(w).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(w[t]))})),console.log("\n")}const I=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,j=(t,o)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!o&&j(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")};var P=(e,t)=>{const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const i=c({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(H(4,"[rate-limiting] Skipping rate limiter."),!0)});e.use(i),H(3,R(`[rate-limiting] Enabled rate limiting: ${r.max} requests\n per ${r.window} minute per IP, trusting proxy:\n ${r.trustProxy}.`))};async function N(e,t={}){return new Promise(((o,r)=>{const i=(e=>e.startsWith("https")?a:s)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}l.config();const F=t.join(E,".cache"),U={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let q=!1;const G=()=>U.hcVersion=U.sources.substr(0,U.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),W=async(e,t)=>{try{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),H(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},r=await N(`${e}.js`,o);if(200===r.statusCode)return r.text;throw`${r.statusCode}`}catch(t){throw H(1,`[cache] Error fetching script ${e}.js: ${t}.`),t}},M=async(t,o)=>{const{coreScripts:r,modules:i,indicators:n,scripts:s}=t,a="latest"!==t.version&&t.version?`${t.version}/`:"";H(3,"[cache] Updating cache to Highcharts ",a);const l=[...r.map((e=>`${a}${e}`)),...i.map((e=>"map"===e?`maps/${a}modules/${e}`:`${a}modules/${e}`)),...n.map((e=>`stock/${a}indicators/${e}`))];let c;const p=process.env.PROXY_SERVER_HOST,d=process.env.PROXY_SERVER_PORT;p&&d&&(c=new u({host:p,port:+d}));const h={};try{return U.sources=(await Promise.all([...l.map((async e=>{const o=await W(`${t.cdnURL||U.cdnURL}${e}`,c);return"string"==typeof o&&(h[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1),o})),...s.map((e=>W(e,c)))])).join(";\n"),G(),e.writeFileSync(o,U.sources),h}catch(e){H(1,"[cache] Unable to update local Highcharts cache.")}},D=async o=>{let r;const i=t.join(F,"manifest.json"),n=t.join(F,"sources.js");if(q=o,!e.existsSync(F)&&e.mkdirSync(F),!e.existsSync(i)||o.forceFetch)H(3,"[cache] Fetching and caching Highcharts dependencies."),r=await M(o,n);else{let t=!1;const s=JSON.parse(e.readFileSync(i));if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{modules:a,coreScripts:l,indicators:c}=o,p=a.length+l.length+c.length;s.version!==o.version?(H(3,"[cache] Highcharts version mismatch in cache, need to re-fetch."),t=!0):Object.keys(s.modules||{}).length!==p?(H(3,"[cache] Cache and requested modules does not match, need to re-fetch."),t=!0):t=(o.modules||[]).some((e=>{if(!s.modules[e])return H(3,`[cache] The ${e} missing in cache, need to re-fetch.`),!0})),t?r=await M(o,n):(H(3,"[cache] Dependency cache is up to date, proceeding."),U.sources=e.readFileSync(n,"utf8"),r=s.modules,G())}await(async(o,r)=>{const i={version:o.version,modules:r||{}};U.activeManifest=i,H(4,"[cache] writing new manifest");try{e.writeFileSync(t.join(F,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){H(1,`[cache] Error writing cache manifest: ${e}.`)}})(o,r)};var V=async e=>!!q&&await D(Object.assign(q,{version:e})),z=()=>U,J=()=>U.hcVersion;const K=m.randomBytes(64).toString("base64url"),X=f.join("tmp",`puppeteer-${K}`),B=[`--user-data-dir=${f.join(X,"profile")}`,"--autoplay-policy=user-gesture-required","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-client-side-phishing-detection","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=AudioServiceOutOfProcess","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-speech-api","--disable-sync","--hide-crash-restore-bubble","--hide-scrollbars","--ignore-gpu-blacklist","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-zygote","--password-store=basic","--use-mock-keychain"],Y=b.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:v&&v.src||new URL("index.cjs",document.baseURI).href)),Q=e.readFileSync(Y+"/../templates/template.html","utf8");let Z;const ee=async()=>{if(!Z)return!1;const e=await Z.newPage();return await e.setContent(Q),await e.addScriptTag({path:Y+"/../.cache/sources.js"}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{H(1,"[page error]",t),await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)})),e},te=async()=>{Z.connected&&await Z.close()};const oe=b.fileURLToPath(new URL(".","undefined"==typeof document?require("url").pathToFileURL(__filename).href:v&&v.src||new URL("index.cjs",document.baseURI).href)),re=async(e,t,o)=>await e.evaluate(((e,t)=>window.triggerExport(e,t)),t,o);var ie=async(o,r,i)=>{const n=[],s=async e=>{for(const e of n)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))};try{const a=()=>{};H(4,"[export] Determining export path.");const l=i.export;await o.evaluate((()=>requestAnimationFrame((()=>{}))));const c=l?.options?.chart?.displayErrors&&z().activeManifest.modules.debugger;await o.evaluate((e=>window._displayErrors=e),c);const p=()=>{};let u;if(r.indexOf&&(r.indexOf("=0||r.indexOf("=0)){if(H(4,"[export] Treating as SVG."),"svg"===l.type)return r;u=!0;const e=()=>{};await o.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(r)),e()}else if(H(4,"[export] Treating as config."),l.strInj){const e=()=>{};await re(o,{chart:{height:l.height,width:l.width}},i),e()}else{r.chart.height=l.height,r.chart.width=l.width;const e=()=>{};await re(o,r,i),e()}p();const d=()=>{},h=i.customCode.resources;if(h){if(h.js&&n.push(await o.addScriptTag({content:h.js})),h.files)for(const t of h.files)try{const r=!t.startsWith("http");n.push(await o.addScriptTag(r?{content:e.readFileSync(t,"utf8")}:{url:t}))}catch(e){H(4,"[export] JS file not found.")}const r=()=>{};if(h.css){let e=h.css.match(/@import\s*([^;]*);/g);if(e)for(let r of e)r&&(r=r.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),r.startsWith("http")?n.push(await o.addStyleTag({url:r})):i.customCode.allowFileResources&&n.push(await o.addStyleTag({path:t.join(oe,r)})));n.push(await o.addStyleTag({content:h.css.replace(/@import\s*([^;]*);/g,"")||" "}))}r()}d();const g=u?await o.$eval("#chart-container svg:first-of-type",(async(e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(l.scale)):await o.evaluate((async()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),f=()=>{},m=Math.ceil(g?.chartHeight||l.height),v=Math.ceil(g?.chartWidth||l.width);await o.setViewport({height:m,width:v,deviceScaleFactor:u?1:parseFloat(l.scale)});const y=u?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await o.evaluate(y,parseFloat(l.scale));const{height:b,width:w,x:x,y:T}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}})))(o);let k;u||await o.setViewport({width:Math.round(w),height:Math.round(b),deviceScaleFactor:parseFloat(l.scale)}),f();const S=()=>{};if("svg"===l.type)k=await(async e=>await e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(o);else if("png"===l.type||"jpeg"===l.type)k=await(async(e,t,o,r)=>await Promise.race([e.screenshot({type:t,encoding:o,clip:r,omitBackground:!0}),new Promise(((e,t)=>setTimeout((()=>t(new Error("Rasterization timeout"))),1500)))]))(o,l.type,"base64",{width:v,height:m,x:x,y:T});else{if("pdf"!==l.type)throw`Unsupported output format ${l.type}`;k=await(async(e,t,o,r)=>await e.pdf({height:t+1,width:o,encoding:r}))(o,m,v,"base64")}return await o.evaluate((()=>{const e=Highcharts.charts;if(e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()})),S(),a(),await s(o),k}catch(e){return await s(o),H(1,`[export] Error encountered during export: ${e}`),e}};let ne,se=0,ae=0,le=0,ce=0,pe=0,ue={},de=!1;const he={create:async()=>{const e=d.v4();let t=!1;const o=(new Date).getTime();try{if(t=await ee(),!t||t.isClosed())throw"invalid page";H(3,`[pool] Successfully created a worker ${e} - took ${(new Date).getTime()-o} ms.`)}catch(e){throw H(1,`[pool] Error creating a new page in pool entry creation! ${e}`),"Error creating page"}return{id:e,page:t,workCount:Math.round(Math.random()*(ue.workLimit/2))}},validate:e=>!(ue.workLimit&&++e.workCount>ue.workLimit)||(H(3,"[pool] Worker failed validation:",`exceeded work limit (limit is ${ue.workLimit})`),!1),destroy:e=>{H(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()},log:(e,t)=>console.log(`${t}: ${e}`)},ge=async e=>{ne=e.puppeteerArgs;try{await(async e=>{const t=[...B,...e||[]];if(!Z){let e=0;const o=async()=>{try{H(3,"[browser] attempting to get a browser instance (try",e+")"),Z=await g.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){H(0,"[browser]",t),++e<25?(H(3,"[browser] failed:",t),await new Promise((e=>setTimeout(e,4e3))),await o()):H(0,"Max retries reached")}};try{await o()}catch(e){return H(0,"[browser] Unable to open browser"),!1}if(!Z)return H(0,"[browser] Unable to open browser"),!1}return Z})(ne)}catch(e){H(0,"[pool|browser]",e)}if(ue=e&&e.pool?{...e.pool}:{},H(3,"[pool] Initializing pool:",`min ${ue.initialWorkers}, max ${ue.maxWorkers}.`),de)return H(4,"[pool] Already initialized, please kill it before creating a new one.");ue.listenToProcessExits&&(H(4,"[pool] Attaching exit listeners to the process."),process.on("exit",(async()=>{await fe()})),process.on("SIGINT",((e,t)=>{H(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{H(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{H(4,`The ${t} error, message: ${e.message}.`)})));try{de=new h.Pool({...he,min:ue.initialWorkers,max:ue.maxWorkers,createRetryIntervalMillis:200,createTimeoutMillis:ue.acquireTimeout,acquireTimeoutMillis:ue.acquireTimeout,destroyTimeoutMillis:ue.acquireTimeout,idleTimeoutMillis:ue.timeoutThreshold,reapIntervalMillis:1e3,propagateCreateError:!1}),de.on("createFail",((e,t)=>{H(1,`[pool] Error when creating worker of an event id ${e}:`,t)})),de.on("acquireFail",((e,t)=>{H(1,`[pool] Error when acquiring worker of an event id ${e}:`,t)})),de.on("destroyFail",((e,t,o)=>{H(1,`[pool] Error when destroying worker of an id ${t.id}, event id ${e}:`,o)})),de.on("release",(e=>{H(4,`[pool] Releasing a worker of an id ${e.id}`)})),de.on("destroySuccess",((e,t)=>{H(4,`[pool] Destroyed a worker of an id ${t.id}`)}));const e=[];for(let t=0;t{de.release(e)})),H(3,`[pool] The pool is ready with ${ue.initialWorkers} initial resources waiting.`)}catch(e){throw H(1,`[pool] Couldn't create the worker pool ${e}`),e}};async function fe(){return H(3,"[pool] Killing all workers."),de.destroyed?(await te(),!0):(await de.destroy(),await te(),!0)}const me=async(e,t)=>{let o;const r=e=>{throw++ce,o&&de.release(o),"In pool.postWork: "+e};if(H(4,"[pool] Work received, starting to process."),ue.benchmarking&&ve(),++ae,!de)return H(1,"[pool] Work received, but pool has not been started."),r("Pool is not inited but work was posted to it!");try{H(4,"[pool] Acquiring worker"),o=await de.acquire().promise}catch(e){return r(`[pool] Error when acquiring available entry: ${e}`)}if(H(4,"[pool] Acquired worker handle"),!o.page)return r("Resolved worker page is invalid: pool setup is wonky");try{let i=(new Date).getTime();H(4,`[pool] Starting work on pool entry ${o.id}.`);const n=await ie(o.page,e,t);if(n instanceof Error)return"Rasterization timeout"===n.message&&(o.page.close(),o.page=await ee()),r(n);de.release(o);const s=(new Date).getTime()-i;return le+=s,pe=le/++se,H(4,`[pool] Work completed in ${s} ms.`),{data:n,options:t}}catch(e){r(`Error trying to perform puppeteer export: ${e}.`)}};function ve(){const{min:e,max:t,size:o,available:r,borrowed:i,pending:n,spareResourceCapacity:s}=de;H(4,`[pool] The minimum number of resources allowed by pool: ${e}.`),H(4,`[pool] The maximum number of resources allowed by pool: ${t}.`),H(4,`[pool] The number of all resources in pool (free or in use): ${o}.`),H(4,`[pool] The number of resources that are currently available: ${r}.`),H(4,`[pool] The number of resources that are currently acquired: ${i}.`),H(4,`[pool] The number of callers waiting to acquire a resource: ${n}.`),H(4,`[pool] The number of how many more resources can the pool manage/create: ${s}.`)}var ye=()=>({min:de.min,max:de.max,size:de.size,available:de.available,borrowed:de.borrowed,pending:de.pending,spareResourceCapacity:de.spareResourceCapacity}),be=()=>ae,we=()=>ce,xe=()=>pe,Te=()=>se;const ke=process.env.npm_package_version,Se=new Date;let He={};const Ee=()=>He,Re=(e,t,o=[])=>{const r=_(e);for(const[e,n]of Object.entries(t))r[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||o.includes(e)||void 0===r[e]?void 0!==n?n:r[e]:Re(r[e],n,o);var i;return r};function Le(e,t={},o=""){Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r],n=t&&t[r];let s;void 0===i.value?Le(i,n,`${o}.${r}`):(void 0!==n&&(i.value=n),i.envLink&&("boolean"===i.type?i.value=I([process.env[i.envLink],i.value].find((e=>e||"false"===e))):"number"===i.type?(s=+process.env[i.envLink],i.value=s>=0?s:i.value):i.type.indexOf("]")>=0&&process.env[i.envLink]?i.value=process.env[i.envLink].split(","):i.value=process.env[i.envLink]||i.value))}}))}function Ce(e){let t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:Ce(r);return t}let Oe=!1;const _e=async(t,o)=>{H(4,"[chart] Starting exporting process.");const r=((e,t={})=>{let o={};return e.svg?(o=_(t),o.export.type=e.type||e.export.type,o.export.scale=e.scale||e.export.scale,o.export.outfile=e.outfile||e.export.outfile,o.payload={svg:e.svg}):o=Re(t,e,x),o.export.outfile=o.export?.outfile||`chart.${o.export?.type||"png"}`,o})(t,Ee()),i=r.export;return r.payload?.svg&&""!==r.payload.svg?je(r.payload.svg.trim(),r,o):i.infile&&i.infile.length?(H(4,"[chart] Attempting to export from an input file."),e.readFile(i.infile,"utf8",((e,t)=>e?H(1,`[chart] Error loading input file: ${e}.`):(r.export.instr=t,je(r.export.instr.trim(),r,o))))):i.instr&&""!==i.instr||i.options&&""!==i.options?(H(4,"[chart] Attempting to export from a raw input."),I(r.customCode?.allowCodeExecution)?Ie(r,o):"string"==typeof i.instr?je(i.instr.trim(),r,o):$e(r,i.instr||i.options,o)):(H(1,R(`[chart] No input specified.\n ${JSON.stringify(i,void 0," ")}.`)),o&&o(!1,{error:!0,message:"No input specified."}))},Ae=e=>{const{chart:t,exporting:o}=e.export?.options||O(e.export?.instr),r=O(e.export?.globalOptions);let i=e.export?.scale||o?.scale||r?.exporting?.scale||e.export?.defaultScale||1;return i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const o=Math.pow(10,t||0);return Math.round(+e*o)/o})(i,2),{height:e.export?.height||o?.sourceHeight||t?.height||r?.exporting?.sourceHeight||r?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||o?.sourceWidth||t?.width||r?.exporting?.sourceWidth||r?.chart?.width||e.export?.defaultWidth||600,scale:i}},$e=(t,o,r,i)=>{let{export:n,customCode:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:Oe;if(s){if("string"==typeof t.customCode.resources)t.customCode.resources=C(t.customCode.resources,I(t.customCode.allowFileResources));else if(!t.customCode.resources)try{const o=e.readFileSync("resources.json","utf8");t.customCode.resources=C(o,I(t.customCode.allowFileResources))}catch(e){H(3,"[chart] The default resources.json file not found.")}}else s=t.customCode={};if(!a&&s){if(s.callback||s.resources||s.customCode)return r&&r(!1,{error:!0,message:R("The callback, resources and customCode have been disabled for this\n server.")});s.callback=!1,s.resources=!1,s.customCode=!1}if(o&&(o.chart=o.chart||{},o.exporting=o.exporting||{},o.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=L(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{n&&n[t]&&("string"==typeof n[t]&&n[t].endsWith(".json")?n[t]=O(e.readFileSync(n[t],"utf8"),!0):n[t]=O(n[t],!0))}catch(e){n[t]={},H(1,`[chart] The ${t} not found.`)}})),s.allowCodeExecution&&(s.customCode=j(s.customCode,s.allowFileResources)),s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=e.readFileSync(s.callback,"utf8")}catch(e){H(2,`[chart] Error loading callback: ${e}.`),s.callback=!1}else s.callback=!1;t.export={...t.export,...Ae(t)},me(n.strInj||o||i,t).then((e=>r(e))).catch((e=>(H(0,"[chart] When posting work:",e),r(!1,e))))},Ie=(e,t)=>{try{let o,r=e.export.instr||e.export.options;return"string"!=typeof r&&(o=r=A(r,e.customCode?.allowCodeExecution)),o=r.replaceAll(/\t|\n|\r/g,"").trim(),";"===o[o.length-1]&&(o=o.substring(0,o.length-1)),e.export.strInj=o,$e(e,!1,t)}catch(o){const r=R(`Malformed input detected for ${e.export?.requestId||"?"}:\n Please make sure that your JSON/JavaScript options\n are sent using the "options" attribute, and that if you're using\n SVG, it is unescaped.`);return H(1,r),t&&t(!1,JSON.stringify({error:!0,message:r}))}},je=(e,t,o)=>{const{allowCodeExecution:r}=t.customCode;if(e.indexOf("=0||e.indexOf("=0)return H(4,"[chart] Parsing input as SVG."),$e(t,!1,o,e);try{const r=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return $e(t,r,o)}catch(e){return I(r)?Ie(t,o):o&&o(!1,{error:!0,message:R("Only JSON configurations and SVG is allowed for this server. If\n this is your server, JavaScript exporting can be enabled by starting\n the server with the --allowCodeExecution flag.")})}},Pe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Ne=0;const Fe=[],Ue=[],qe=(e,t,o,r)=>{let i=!0;const{id:n,uniqueId:s,type:a,body:l}=r;return e.some((e=>{if(e){let r=e(t,o,n,s,a,l);return void 0!==r&&!0!==r&&(i=r),!0}})),i},Ge=(e,t)=>{(()=>{const e=process.hrtime.bigint()})();const o=Ee(),r=e.body,i=++Ne,n=d.v4().replace(/-/g,"");let s=L(r.type);if(!r)return t.status(400).send(R("Body is required. Sending a body? Make sure your Content-type header\n is correct. Accepted is application/json and multipart/form-data."));let a=O(r.infile||r.options||r.data);if(!a&&!r.svg)return H(2,R(`Request ${n} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Check your payload.`)),t.status(400).send(R("No correct chart data found. Please make sure you are using\n application/json or multipart/form-data headers, and that the chart\n data is in the 'infile', 'options' or 'data' attribute if sending\n JSON or in the 'svg' if sending SVG."));let l=!1;if(l=qe(Fe,e,t,{id:i,uniqueId:n,type:s,body:r}),!0!==l)return t.send(l);let c=!1;e.socket.on("close",(()=>{c=!0})),H(4,`[export] Got an incoming HTTP request ${n}.`),r.constr="string"==typeof r.constr&&r.constr||"chart";const p={export:{instr:a,type:s,constr:r.constr[0].toLowerCase()+r.constr.substr(1),height:r.height,width:r.width,scale:r.scale||o.export.scale,globalOptions:O(r.globalOptions,!0),themeOptions:O(r.themeOptions,!0)},customCode:{allowCodeExecution:Oe,allowFileResources:!1,resources:O(r.resources,!0),callback:r.callback,customCode:r.customCode}};a&&(p.export.instr=A(a,p.customCode.allowCodeExecution));const u=Re(o,p);if(u.export.options=a,u.payload={svg:r.svg||!1,b64:r.b64||!1,dataOptions:O(r.dataOptions,!0),noDownload:r.noDownload||!1,requestId:n},r.svg&&(h=u.payload.svg,["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((e=>h.match(`xlink:href="(?:(http://|https://))?${e}`)))))return t.status(400).send("SVG potentially contain at least one forbidden URL in xlink:href element.");var h;_e(u,((o,a)=>(e.socket.removeAllListeners("close"),c?H(3,R("[export] The client closed the connection before the chart was done\n processing.")):a?(H(1,R(`[export] Work: ${n} could not be completed, sending:\n ${a}`)),t.status(400).send(a.message)):o&&o.data?(s=o.options.export.type,qe(Ue,e,t,{id:i,body:o.data}),o.data?r.b64?"pdf"===s?t.send(Buffer.from(o.data,"utf8").toString("base64")):t.send(o.data):(t.header("Content-Type",Pe[s]||"image/png"),r.noDownload||t.attachment(`${e.params.filename||"chart"}.${s||"png"}`),"svg"===s?t.send(o.data):t.send(Buffer.from(o.data,"base64"))):void 0):(H(1,R(`[export] Unexpected return from chart generation, please check your\n data Request: ${n} is ${o.data}.`)),t.status(400).send("Unexpected return from chart generation, please check your data.")))))};const We=i();We.disable("x-powered-by"),We.use(r());const Me=n.memoryStorage(),De=n({storage:Me,limits:{fieldsSize:"50MB"}});We.use(De.any()),We.use(o.json({limit:"50mb"})),We.use(o.urlencoded({extended:!0,limit:"50mb"})),We.use(o.urlencoded({extended:!1,limit:"50mb"}));const Ve=e=>H(1,`[server] Socket error: ${e}`),ze=e=>{e.on("clientError",Ve),e.on("error",Ve),e.on("connection",(e=>e.on("error",(e=>Ve(e)))))},Je=async o=>{if(!o.enable)return!1;if(!o.ssl.enable&&!o.ssl.force){const e=s.createServer(We);ze(e),e.listen(o.port,o.host),H(3,`[server] Started HTTP server on ${o.host}:${o.port}.`)}if(o.ssl.enable){let r,i;try{r=await e.promises.readFile(t.posix.join(o.ssl.certPath,"server.key"),"utf8"),i=await e.promises.readFile(t.posix.join(o.ssl.certPath,"server.crt"),"utf8")}catch(e){H(1,`[server] Unable to load key/certificate from ${o.ssl.certPath}.`)}if(r&&i){const e=a.createServer(We);ze(e),e.listen(o.ssl.port,o.host),H(3,`[server] Started HTTPS server on ${o.host}:${o.ssl.port}.`)}}o.rateLimiting&&o.rateLimiting.enable&&![0,NaN].includes(o.rateLimiting.maxRequests)&&P(We,o.rateLimiting),We.use(i.static(t.posix.join(E,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:Se,uptime:Math.floor(((new Date).getTime()-Se.getTime())/1e3/60)+" minutes",version:ke,highchartsVersion:J(),averageProcessingTime:xe(),performedExports:Te(),failedExports:we(),exportAttempts:be(),sucessRatio:Te()/be()*100,pool:ye()})}))})(We),(e=>{e.post("/",Ge),e.post("/:filename",Ge)})(We),(e=>{!!e&&e.get("/",((e,o)=>{o.sendFile(t.join(E,"public","index.html"))}))})(We),(e=>{!!e&&e.post("/change_hc_version/:newVersion",(async(e,t)=>{const o=process.env.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)return t.send({error:!0,message:"Server not configured to do run-time version changes: HIGHCHARTS_ADMIN_TOKEN not set"});const r=e.get("hc-auth");if(!r||r!==o)return t.send({error:!0,message:"Invalid or missing token: set token in the hc-auth header"});const i=e.params.newVersion;if(i){try{await V(i)}catch(e){t.send({error:!0,message:e})}t.send({version:J()})}else t.send({error:!0,message:"No new version supplied"})}))})(We)};var Ke={startServer:Je,getExpress:()=>i,getApp:()=>We,use:(e,...t)=>{We.use(e,...t)},get:(e,...t)=>{We.get(e,...t)},post:(e,...t)=>{We.post(e,...t)},enableRateLimiting:e=>P(We,e)},Xe={log:H,mapToNewConfig:e=>{const t={};for(const[o,r]of Object.entries(e)){const e=T[o]?T[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}return t},setOptions:(t,o)=>(o?.length&&(He=function(t){const o=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(o>-1&&t[o+1]){const r=t[o+1];try{if(r&&r.endsWith(".json"))return JSON.parse(e.readFileSync(r))}catch(e){H(1,`[config] Unable to load config from the ${r}: ${e}`)}}return{}}(o)),Le(w,He),He=Ce(w),t&&(He=Re(He,t,x)),o?.length&&(He=function(e,t,o){for(let o=0;o(i.length-1===a&&void 0!==n[s]&&(t[++o]?n[s]=t[o]||n[s]:(console.log(`Missing argument value for ${r}!`.red,"\n"),e=$())),n[s])),e)}return e}(He,o)),He),singleExport:t=>{t.export.instr=t.export.instr||t.export.options,_e(t,((t,o)=>{o&&(H(1,`[cli] ${o.message}`),process.exit(1));const{outfile:r,type:i}=t.options.export;e.writeFileSync(r||`chart.${i}`,"svg"!==i?Buffer.from(t.data,"base64"):t.data),fe()}))},startExport:_e,batchExport:t=>{const o=[];for(let r of t.export.batch.split(";"))r=r.split("="),2===r.length&&o.push(new Promise(((o,i)=>{_e({...t,export:{...t.export,infile:r[0],outfile:r[1]}},((t,r)=>{if(r)return i(r);e.writeFileSync(t.options.export.outfile,Buffer.from(t.data,"base64")),o()}))})));Promise.all(o).then((()=>{fe()})).catch((e=>{H(1,`[chart] Error encountered during batch export: ${e}`),fe()}))},server:Ke,startServer:Je,killPool:fe,initPool:async(e={})=>{var t,o;return t=e.customCode&&e.customCode.allowCodeExecution,Oe=I(t),(o=e.logging&&parseInt(e.logging.level))>=0&&o<=S.levelsDesc.length&&(S.level=o),e.logging&&e.logging.dest&&((e,t)=>{if(S={...S,dest:e||S.dest,file:t||S.file,toFile:!0},0===S.dest.length)return H(1,"[logger] File logging init: no path supplied.");S.dest.endsWith("/")||(S.dest+="/")})(e.logging.dest,e.logging.file||"highcharts-export-server.log"),await D(e.highcharts||{version:"latest"}),await ge({pool:e.pool||{initialWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer?.args||[]}),e}};module.exports=Xe; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3V0aWxzLmpzIiwiLi4vbGliL3NlcnZlci9yYXRlX2xpbWl0LmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2NhY2hlLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vbGliL2JlbmNobWFyay5qcyIsIi4uL3RlbXBsYXRlcy9zdmdfZXhwb3J0L3N2Z19leHBvcnQuanMiLCIuLi9saWIvcG9vbC5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2hlYWx0aC5qcyIsIi4uL2xpYi9jb25maWcuanMiLCIuLi9saWIvY2hhcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3VpLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMiLCIuLi9saWIvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xuXG5kb3RlbnYuY29uZmlnKCk7XG5cbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxuLy8gYWxzbyBmcm9tIHRoZSAuZW52IGZpbGUgaWYgb25lIGV4aXN0c1xuZXhwb3J0IGNvbnN0IGRlZmF1bHRDb25maWcgPSB7XG4gIHB1cHBldGVlcjoge1xuICAgIGFyZ3M6IHtcbiAgICAgIHZhbHVlOiBbXSxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0FycmF5IG9mIGFyZ3VtZW50cyB0byBzZW5kIHRvIHB1cHBldGVlci4nXG4gICAgfVxuICB9LFxuICBoaWdoY2hhcnRzOiB7XG4gICAgdmVyc2lvbjoge1xuICAgICAgdmFsdWU6ICdsYXRlc3QnLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfVkVSU0lPTicsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIHVzZS4nXG4gICAgfSxcbiAgICBjZG5VUkw6IHtcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE4nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBDRE4gVVJMIG9mIEhpZ2hjaGFydHMgc2NyaXB0cyB0byB1c2UuJ1xuICAgIH0sXG4gICAgY29yZVNjcmlwdHM6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXG4gICAgICB2YWx1ZTogWydoaWdoY2hhcnRzJywgJ2hpZ2hjaGFydHMtbW9yZScsICdoaWdoY2hhcnRzLTNkJ10sXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC4nXG4gICAgfSxcbiAgICBtb2R1bGVzOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVTJyxcbiAgICAgIHZhbHVlOiBbXG4gICAgICAgICdzdG9jaycsXG4gICAgICAgICdtYXAnLFxuICAgICAgICAnZ2FudHQnLFxuICAgICAgICAnZXhwb3J0aW5nJyxcbiAgICAgICAgJ2V4cG9ydC1kYXRhJyxcbiAgICAgICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcbiAgICAgICAgJ2FjY2Vzc2liaWxpdHknLFxuICAgICAgICAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxuICAgICAgICAnYm9vc3QtY2FudmFzJyxcbiAgICAgICAgJ2Jvb3N0JyxcbiAgICAgICAgJ2RhdGEnLFxuICAgICAgICAnZHJhZ2dhYmxlLXBvaW50cycsXG4gICAgICAgICdzdGF0aWMtc2NhbGUnLFxuICAgICAgICAnYnJva2VuLWF4aXMnLFxuICAgICAgICAnaGVhdG1hcCcsXG4gICAgICAgICd0aWxlbWFwJyxcbiAgICAgICAgJ3RpbWVsaW5lJyxcbiAgICAgICAgJ3RyZWVtYXAnLFxuICAgICAgICAndHJlZWdyYXBoJyxcbiAgICAgICAgJ2l0ZW0tc2VyaWVzJyxcbiAgICAgICAgJ2RyaWxsZG93bicsXG4gICAgICAgICdoaXN0b2dyYW0tYmVsbGN1cnZlJyxcbiAgICAgICAgJ2J1bGxldCcsXG4gICAgICAgICdmdW5uZWwnLFxuICAgICAgICAnZnVubmVsM2QnLFxuICAgICAgICAncHlyYW1pZDNkJyxcbiAgICAgICAgJ25ldHdvcmtncmFwaCcsXG4gICAgICAgICdwYXJldG8nLFxuICAgICAgICAncGF0dGVybi1maWxsJyxcbiAgICAgICAgJ3BpY3RvcmlhbCcsXG4gICAgICAgICdwcmljZS1pbmRpY2F0b3InLFxuICAgICAgICAnc2Fua2V5JyxcbiAgICAgICAgJ2FyYy1kaWFncmFtJyxcbiAgICAgICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxuICAgICAgICAnc2VyaWVzLWxhYmVsJyxcbiAgICAgICAgJ3NvbGlkLWdhdWdlJyxcbiAgICAgICAgJ3NvbmlmaWNhdGlvbicsXG4gICAgICAgICdzdG9jay10b29scycsXG4gICAgICAgICdzdHJlYW1ncmFwaCcsXG4gICAgICAgICdzdW5idXJzdCcsXG4gICAgICAgICd2YXJpYWJsZS1waWUnLFxuICAgICAgICAndmFyaXdpZGUnLFxuICAgICAgICAndmVjdG9yJyxcbiAgICAgICAgJ3Zlbm4nLFxuICAgICAgICAnd2luZGJhcmInLFxuICAgICAgICAnd29yZGNsb3VkJyxcbiAgICAgICAgJ3hyYW5nZScsXG4gICAgICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxuICAgICAgICAnZHJhZy1wYW5lcycsXG4gICAgICAgICdkZWJ1Z2dlcicsXG4gICAgICAgICdkdW1iYmVsbCcsXG4gICAgICAgICdsb2xsaXBvcCcsXG4gICAgICAgICdjeWxpbmRlcicsXG4gICAgICAgICdvcmdhbml6YXRpb24nLFxuICAgICAgICAnZG90cGxvdCcsXG4gICAgICAgICdtYXJrZXItY2x1c3RlcnMnLFxuICAgICAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxuICAgICAgICAnaGVpa2luYXNoaSdcbiAgICAgIF0sXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guJ1xuICAgIH0sXG4gICAgaW5kaWNhdG9yczoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfSU5ESUNBVE9SUycsXG4gICAgICB2YWx1ZTogWydpbmRpY2F0b3JzLWFsbCddLFxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBpbmRpY2F0b3JzIHRvIGZldGNoLidcbiAgICB9LFxuICAgIHNjcmlwdHM6IHtcbiAgICAgIHZhbHVlOiBbXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4yOS40L21vbWVudC5taW4uanMnLFxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LXRpbWV6b25lLzAuNS4zNC9tb21lbnQtdGltZXpvbmUtd2l0aC1kYXRhLm1pbi5qcydcbiAgICAgIF0sXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBZGRpdGlvbmFsIGRpcmVjdCBzY3JpcHRzL29wdGlvbmFsIGRlcGVuZGVuY2llcyAoZS5nLiBtb21lbnQuanMpLidcbiAgICB9LFxuICAgIGZvcmNlRmV0Y2g6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnU2hvdWxkIGFsbCB0aGUgc2NyaXB0cyBiZSByZWZldGNoZWQgYWZ0ZXIgcmVydW5uaW5nIHRoZSBzZXJ2ZXIuJ1xuICAgIH1cbiAgfSxcbiAgZXhwb3J0OiB7XG4gICAgaW5maWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGlucHV0IGZpbGUgbmFtZSBhbG9uZyB3aXRoIGEgdHlwZSAoanNvbiBvciBzdmcpLiBJdCBjYW4gYmUgYSBjb3JyZWN0IEpTT04gb3IgU1ZHIGZpbGUuJ1xuICAgIH0sXG4gICAgaW5zdHI6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBbiBpbnB1dCBpbiBhIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLiBPdmVycmlkZXMgdGhlIC0taW5maWxlLidcbiAgICB9LFxuICAgIG9wdGlvbnM6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcbiAgICB9LFxuICAgIG91dGZpbGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiBvciBzdmcpLiBJZ25vcmVzIHRoZSAtLXR5cGUgZmxhZy4nXG4gICAgfSxcbiAgICB0eXBlOiB7XG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfVFlQRScsXG4gICAgICB2YWx1ZTogJ3BuZycsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGZvcm1hdCBvZiB0aGUgZmlsZSB0byBleHBvcnQgdG8uIENhbiBiZSBqcGVnLCBwbmcsIHBkZiBvciBzdmcuJ1xuICAgIH0sXG4gICAgY29uc3RyOiB7XG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfQ09OU1RSJyxcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBjb25zdHJ1Y3RvciB0byB1c2UuIENhbiBiZSBjaGFydCwgc3RvY2tDaGFydCwgbWFwQ2hhcnQgb3IgZ2FudHRDaGFydC4nXG4gICAgfSxcbiAgICBkZWZhdWx0SGVpZ2h0OiB7XG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfSEVJR0hUJyxcbiAgICAgIHZhbHVlOiA0MDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGRlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vdCBmb3VuZCBhbnkgdmFsdWUgc2V0LidcbiAgICB9LFxuICAgIGRlZmF1bHRXaWR0aDoge1xuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcbiAgICAgIHZhbHVlOiA2MDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGRlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm90IGZvdW5kIGFueSB2YWx1ZSBzZXQuJ1xuICAgIH0sXG4gICAgZGVmYXVsdFNjYWxlOiB7XG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfU0NBTEUnLFxuICAgICAgdmFsdWU6IDEsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGRlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBSYW5nZXMgYmV0d2VlbiAxIGFuZCA1LidcbiAgICB9LFxuICAgIGhlaWdodDoge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkZWZhdWx0IGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIE92ZXJyaWRlcyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXG4gICAgfSxcbiAgICB3aWR0aDoge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIE92ZXJyaWRlcyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXG4gICAgfSxcbiAgICBzY2FsZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFJhbmdlcyBiZXR3ZWVuIDEgYW5kIDUuJ1xuICAgIH0sXG4gICAgZ2xvYmFsT3B0aW9uczoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0Egc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIHdpdGggb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcbiAgICB9LFxuICAgIHRoZW1lT3B0aW9uczoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0Egc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIHdpdGggdGhlbWUgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcbiAgICB9LFxuICAgIGJhdGNoOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnU3RhcnRzIGEgYmF0Y2ggam9iLiBBIHN0cmluZyB0aGF0IGNvbnRhaW5zIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uXCIuJ1xuICAgIH1cbiAgfSxcbiAgY3VzdG9tQ29kZToge1xuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdJZiBzZXQgdG8gdHJ1ZSwgYWxsb3cgZm9yIHRoZSBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgd2hlbiBleHBvcnRpbmcuJ1xuICAgIH0sXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19BTExPV19GSUxFX1JFU09VUkNFUycsXG4gICAgICB2YWx1ZTogdHJ1ZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQWxsb3cgaW5qZWN0aW5nIHJlc291cmNlcyBmcm9tIHRoZSBmaWxlc3lzdGVtLiBIYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXG4gICAgfSxcbiAgICBjdXN0b21Db2RlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBDYW4gYmUgYSBmaWxlbmFtZSB3aXRoIHRoZSBqcyBleHRlbnNpb24uJ1xuICAgIH0sXG4gICAgY2FsbGJhY2s6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246ICdBIEphdmFTY3JpcHQgZmlsZSB3aXRoIGEgZnVuY3Rpb24gdG8gcnVuIG9uIGNvbnN0cnVjdGlvbi4nXG4gICAgfSxcbiAgICByZXNvdXJjZXM6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBbiBhZGRpdGlvbmFsIHJlc291cmNlIGluIGEgZm9ybSBvZiBzdHJpbmdpZmllZCBKU09OLiBJdCBjYW4gY29udGFpbiBmaWxlcywganMgYW5kIGNzcyBzZWN0aW9ucy4nXG4gICAgfSxcbiAgICBsb2FkQ29uZmlnOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQSBmaWxlIHRoYXQgY29udGFpbnMgYSBwcmUtZGVmaW5lZCBjb25maWcgdG8gdXNlLidcbiAgICB9LFxuICAgIGNyZWF0ZUNvbmZpZzoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0FsbG93cyB0byBzZXQgb3B0aW9ucyB0aHJvdWdoIGEgcHJvbXB0IGFuZCBzYXZlIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xuICAgIH1cbiAgfSxcbiAgc2VydmVyOiB7XG4gICAgZW5hYmxlOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19TRVJWRVJfRU5BQkxFJyxcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxuICAgICAgZGVzY3JpcHRpb246ICdJZiBzZXQgdG8gdHJ1ZSwgc3RhcnRzIGEgc2VydmVyIG9uIDAuMC4wLjAuJ1xuICAgIH0sXG4gICAgaG9zdDoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfU0VSVkVSX0hPU1QnLFxuICAgICAgdmFsdWU6ICcwLjAuMC4wJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgaG9zdG5hbWUgb2YgdGhlIHNlcnZlci4gQWxzbyBzdGFydHMgYSBzZXJ2ZXIgbGlzdGVuaW5nIG9uIHRoZSBzdXBwbGllZCBob3N0bmFtZS4nXG4gICAgfSxcbiAgICBwb3J0OiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19TRVJWRVJfUE9SVCcsXG4gICAgICB2YWx1ZTogNzgwMSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCB0byB1c2UgZm9yIHRoZSBzZXJ2ZXIuIERlZmF1bHRzIHRvIDc4MDEuJ1xuICAgIH0sXG4gICAgc3NsOiB7XG4gICAgICBlbmFibGU6IHtcbiAgICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfU0VSVkVSX1NTTF9FTkFCTEUnLFxuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyB0aGUgU1NMIHByb3RvY29sLidcbiAgICAgIH0sXG4gICAgICBmb3JjZToge1xuICAgICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19TRVJWRVJfU1NMX0ZPUkNFJyxcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZWQnLFxuICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAnSWYgc2V0IHRvIHRydWUsIGZvcmNlcyB0aGUgc2VydmVyIHRvIG9ubHkgc2VydmUgb3ZlciBIVFRQUy4nXG4gICAgICB9LFxuICAgICAgcG9ydDoge1xuICAgICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19TRVJWRVJfU1NMX1BPUlQnLFxuICAgICAgICB2YWx1ZTogNDQzLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9uIHdoaWNoIHRvIHJ1biB0aGUgU1NMIHNlcnZlci4nXG4gICAgICB9LFxuICAgICAgY2VydFBhdGg6IHtcbiAgICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfU1NMX0NFUlRfUEFUSCcsXG4gICAgICAgIHZhbHVlOiAnJyxcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBhdGggdG8gdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXkuJ1xuICAgICAgfVxuICAgIH0sXG4gICAgcmF0ZUxpbWl0aW5nOiB7XG4gICAgICBlbmFibGU6IHtcbiAgICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfUkFURV9MSU1JVF9FTkFCTEUnLFxuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVJhdGVMaW1pdGluZycsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nLidcbiAgICAgIH0sXG4gICAgICBtYXhSZXF1ZXN0czoge1xuICAgICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19SQVRFX0xJTUlUX01BWCcsXG4gICAgICAgIHZhbHVlOiAxMCxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnTWF4IHJlcXVlc3RzIGFsbG93ZWQgaW4gYSBvbmUgbWludXRlLidcbiAgICAgIH0sXG4gICAgICB3aW5kb3c6IHtcbiAgICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfUkFURV9MSU1JVF9XSU5ET1cnLFxuICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHRpbWUgd2luZG93IGluIG1pbnV0ZXMgZm9yIHJhdGUgbGltaXRpbmcuJ1xuICAgICAgfSxcbiAgICAgIGRlbGF5OiB7XG4gICAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1JBVEVfTElNSVRfREVMQVknLFxuICAgICAgICB2YWx1ZTogMCxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdUaGUgYW1vdW50IHRvIGRlbGF5IGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSBoaXR0aW5nIHRoZSBtYXguJ1xuICAgICAgfSxcbiAgICAgIHRydXN0UHJveHk6IHtcbiAgICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfUkFURV9MSU1JVF9UUlVTVF9QUk9YWScsXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NldCB0aGlzIHRvIHRydWUgaWYgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXG4gICAgICB9LFxuICAgICAgc2tpcEtleToge1xuICAgICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19SQVRFX0xJTUlUX1NLSVBfS0VZJyxcbiAgICAgICAgdmFsdWU6ICcnLFxuICAgICAgICB0eXBlOiAnbnVtYmVyfHN0cmluZycsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHNraXBUb2tlbiBhcmd1bWVudC4nXG4gICAgICB9LFxuICAgICAgc2tpcFRva2VuOiB7XG4gICAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1JBVEVfTElNSVRfU0tJUF9UT0tFTicsXG4gICAgICAgIHZhbHVlOiAnJyxcbiAgICAgICAgdHlwZTogJ251bWJlcnxzdHJpbmcnLFxuICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCBza2lwS2V5IGFyZ3VtZW50LidcbiAgICAgIH1cbiAgICB9XG4gIH0sXG4gIHBvb2w6IHtcbiAgICBpbml0aWFsV29ya2Vyczoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfUE9PTF9NSU5fV09SS0VSUycsXG4gICAgICB2YWx1ZTogNCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIGluaXRpYWwgd29ya2VycyB0byBzcGF3bi4nXG4gICAgfSxcbiAgICBtYXhXb3JrZXJzOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19QT09MX01BWF9XT1JLRVJTJyxcbiAgICAgIHZhbHVlOiA4LFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWF4IHdvcmtlcnMgdG8gc3Bhd24uJ1xuICAgIH0sXG4gICAgd29ya0xpbWl0OiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19QT09MX1dPUktfTElNSVQnLFxuICAgICAgdmFsdWU6IDQwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgcHJvY2Vzcy4nXG4gICAgfSxcbiAgICBxdWV1ZVNpemU6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1BPT0xfUVVFVUVfU0laRScsXG4gICAgICB2YWx1ZTogNSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgc2l6ZSBvZiB0aGUgcmVxdWVzdCBvdmVyZmxvdyBxdWV1ZS4nXG4gICAgfSxcbiAgICB0aW1lb3V0VGhyZXNob2xkOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19QT09MX1RJTUVPVVQnLFxuICAgICAgdmFsdWU6IDUwMDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgYmVmb3JlIHRpbWluZyBvdXQuJ1xuICAgIH0sXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcbiAgICAgIHZhbHVlOiA1MDAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlLidcbiAgICB9LFxuICAgIHJlYXBlcjoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfUE9PTF9FTkFCTEVfUkVBUEVSJyxcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdXaGV0aGVyIG9yIG5vdCB0byBldmljdCB3b3JrZXJzIGFmdGVyIGEgY2VydGFpbiB0aW1lIHBlcmlvZC4nXG4gICAgfSxcbiAgICBiZW5jaG1hcmtpbmc6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1BPT0xfQkVOQ0hNQVJLSU5HJyxcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlIGJlbmNobWFya2luZy4nXG4gICAgfSxcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfUE9PTF9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXG4gICAgICB2YWx1ZTogdHJ1ZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnU2V0IHRvIGZhbHNlIGluIG9yZGVyIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycy4nXG4gICAgfVxuICB9LFxuICBsb2dnaW5nOiB7XG4gICAgbGV2ZWw6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0xPR19MRVZFTCcsXG4gICAgICB2YWx1ZTogNCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGxvZyBsZXZlbCAoMDogc2lsZW50LCAxOiBlcnJvciwgMjogd2FybmluZywgMzogbm90aWNlLCA0OiB2ZXJib3NlKS4nXG4gICAgfSxcbiAgICBmaWxlOiB7XG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19MT0dfRklMRScsXG4gICAgICB2YWx1ZTogJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0EgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgLS1sb2dEZXN0IGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xuICAgIH0sXG4gICAgZGVzdDoge1xuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTE9HX0RFU1QnLFxuICAgICAgdmFsdWU6ICdsb2cvJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgY2xpTmFtZTogJ2xvZ0Rlc3QnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIEFsc28gZW5hYmxlcyBmaWxlIGxvZ2dpbmcuJ1xuICAgIH1cbiAgfSxcbiAgdWk6IHtcbiAgICBlbmFibGU6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1VJX0VOQUJMRScsXG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xuICAgIH0sXG4gICAgcm91dGU6IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1VJX1JPVVRFJyxcbiAgICAgIHZhbHVlOiAnLycsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGNsaU5hbWU6ICd1aVJvdXRlJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUkgdG8uJ1xuICAgIH1cbiAgfSxcbiAgb3RoZXI6IHtcbiAgICBub0xvZ286IHtcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX05PX0xPR08nLFxuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIGEgc3RhcnR1cC4gV2lsbCBiZSByZXBsYWNlZCBieSBhIHNpbXBsZSB0ZXh0LidcbiAgICB9XG4gIH0sXG4gIHBheWxvYWQ6IHt9XG59O1xuXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXG4vLyBpbmZvcm1hdGlvbiBsaWtlOlxuLy8gKiBUeXBlIG9mIGEgcHJvbXB0XG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXG4vLyAqIFNob3J0IGRlc2NyaXB0aW9uIG9mIGEgY2hvc2VuIG9wdGlvblxuLy8gKiBJbml0aWFsIHZhbHVlXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcbiAgcHVwcGV0ZWVyOiBbXG4gICAge1xuICAgICAgdHlwZTogJ2xpc3QnLFxuICAgICAgbmFtZTogJ2FyZ3MnLFxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBhcmd1bWVudHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xuICAgIH1cbiAgXSxcbiAgaGlnaGNoYXJ0czogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICd2ZXJzaW9uJyxcbiAgICAgIG1lc3NhZ2U6ICdIaWdoY2hhcnRzIHZlcnNpb24nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdjZG5VUkwnLFxuICAgICAgbWVzc2FnZTogJ1RoZSB1cmwgb2YgQ0ROJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXG4gICAgICBuYW1lOiAnbW9kdWxlcycsXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIG1vZHVsZXMnLFxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5tb2R1bGVzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbGlzdCcsXG4gICAgICBuYW1lOiAnc2NyaXB0cycsXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnNjcmlwdHMudmFsdWUuam9pbignLCcpLFxuICAgICAgc2VwYXJhdG9yOiAnLCdcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxuICAgICAgbWVzc2FnZTogJ1Nob3VsZCByZWZldGNoIGFsbCB0aGUgc2NyaXB0cyBhZnRlciBlYWNoIHNlcnZlciByZXJ1bicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxuICAgIH1cbiAgXSxcbiAgZXhwb3J0OiBbXG4gICAge1xuICAgICAgdHlwZTogJ3NlbGVjdCcsXG4gICAgICBuYW1lOiAndHlwZScsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgdHlwZSBvZiBhIGZpbGUgdG8gZXhwb3J0IHRvJyxcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LnR5cGUudmFsdWV9YCxcbiAgICAgIGluaXRpYWw6IDAsXG4gICAgICBjaG9pY2VzOiBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3NlbGVjdCcsXG4gICAgICBuYW1lOiAnY29uc3RyJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cyB0byB1c2UnLFxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQuY29uc3RyLnZhbHVlfWAsXG4gICAgICBpbml0aWFsOiAwLFxuICAgICAgY2hvaWNlczogWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnZGVmYXVsdEhlaWdodCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0SGVpZ2h0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdkZWZhdWx0V2lkdGgnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0V2lkdGgudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2RlZmF1bHRTY2FsZScsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRTY2FsZS52YWx1ZSxcbiAgICAgIG1pbjogMC4xLFxuICAgICAgbWF4OiA1XG4gICAgfVxuICBdLFxuICBjdXN0b21Db2RlOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnYWxsb3dDb2RlRXhlY3V0aW9uJyxcbiAgICAgIG1lc3NhZ2U6ICdBbGxvdyB0byBleGVjdXRlIGN1c3RvbSBjb2RlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tQ29kZS5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2FsbG93RmlsZVJlc291cmNlcycsXG4gICAgICBtZXNzYWdlOiAnQWxsb3cgZmlsZSByZXNvdXJjZXMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Db2RlLmFsbG93RmlsZVJlc291cmNlcy52YWx1ZVxuICAgIH1cbiAgXSxcbiAgc2VydmVyOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcbiAgICAgIG1lc3NhZ2U6ICdTdGFydHMgYSBzZXJ2ZXIgb24gMC4wLjAuMCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5lbmFibGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdob3N0JyxcbiAgICAgIG1lc3NhZ2U6ICdBIGhvc3RuYW1lIG9mIGEgc2VydmVyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmhvc3QudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3BvcnQnLFxuICAgICAgbWVzc2FnZTogJ0EgcG9ydCBvZiBhIHNlcnZlcicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgU1NMIHByb3RvY29sJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5lbmFibGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgdG8gb25seSBzZXJ2ZSBvdmVyIEhUVFBTJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnc3NsLnBvcnQnLFxuICAgICAgbWVzc2FnZTogJ1BvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5wb3J0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcbiAgICAgIG1lc3NhZ2U6ICdBIHBhdGggd2hlcmUgdG8gZmluZCB0aGUgU1NMIGNlcnRpZmljYXRlL2tleScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSByYXRlIGxpbWl0aW5nJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5lbmFibGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXG4gICAgICBtZXNzYWdlOiAnTWF4IHJlcXVlc3RzIGFsbG93ZWQgaW4gYSBvbmUgbWludXRlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXG4gICAgICBtZXNzYWdlOiAnVGhlIHRpbWUgd2luZG93IGluIG1pbnV0ZXMgZm9yIHJhdGUgbGltaXRpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmRlbGF5JyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdUaGUgYW1vdW50IHRvIGRlbGF5IGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSBoaXR0aW5nIHRoZSBtYXgnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmRlbGF5LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXG4gICAgICBtZXNzYWdlOiAnU2V0IHRoaXMgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy50cnVzdFByb3h5LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBLZXknLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggc2tpcFRva2VuIGFyZ3VtZW50JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwS2V5LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBUb2tlbicsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCBza2lwS2V5IGFyZ3VtZW50JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwVG9rZW4udmFsdWVcbiAgICB9XG4gIF0sXG4gIHBvb2w6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdpbml0aWFsV29ya2VycycsXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBpbml0aWFsIHdvcmtlcnMgdG8gc3Bhd24nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmluaXRpYWxXb3JrZXJzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdtYXhXb3JrZXJzJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1heCB3b3JrZXJzIHRvIHNwYXduJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICd3b3JrTGltaXQnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBwdXBwZXRlZXIgcHJvY2VzcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wud29ya0xpbWl0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdxdWV1ZVNpemUnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBzaXplIG9mIHRoZSByZXF1ZXN0IG92ZXJmbG93IHF1ZXVlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5xdWV1ZVNpemUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3RpbWVvdXRUaHJlc2hvbGQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2Ygc2Vjb25kcyBiZWZvcmUgdGltaW5nIG91dCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wudGltZW91dFRocmVzaG9sZC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5hY3F1aXJlVGltZW91dC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAncmVhcGVyJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmVhcGVyIHRvIHJlbW92ZSBoYW5naW5nIHByb2Nlc3NlcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wucmVhcGVyLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxuICAgICAgbWVzc2FnZTogJ1NldCBiZW5jaG1hcmtpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmJlbmNobWFya2luZy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxuICAgICAgbWVzc2FnZTogJ1NldCB0byBmYWxzZSBpbiBvcmRlciB0byBza2lwIGF0dGFjaGluZyBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmxpc3RlblRvUHJvY2Vzc0V4aXRzLnZhbHVlXG4gICAgfVxuICBdLFxuICBsb2dnaW5nOiBbXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ1RoZSBsb2cgbGV2ZWwgKDA6IHNpbGVudCwgMTogZXJyb3IsIDI6IHdhcm5pbmcsIDM6IG5vdGljZSwgNDogdmVyYm9zZSknLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmxldmVsLnZhbHVlLFxuICAgICAgcm91bmQ6IDAsXG4gICAgICBtaW46IDAsXG4gICAgICBtYXg6IDRcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdmaWxlJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdBIG5hbWUgb2YgYSBsb2cgZmlsZS4gVGhlIC0tbG9nRGVzdCBhbHNvIG5lZWRzIHRvIGJlIHNldCB0byBlbmFibGUgZmlsZSBsb2dnaW5nJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnZGVzdCcsXG4gICAgICBtZXNzYWdlOiAnQSBwYXRoIHRvIGxvZyBmaWxlcy4gSXQgZW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmRlc3QudmFsdWVcbiAgICB9XG4gIF0sXG4gIHVpOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAncm91dGUnLFxuICAgICAgbWVzc2FnZTogJ0Egcm91dGUgdG8gYXR0YWNoIHRoZSBVSSB0bycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXG4gICAgfVxuICBdLFxuICBvdGhlcjogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ25vTG9nbycsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnU2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBhIHN0YXJ0dXAuIFdpbGwgYmUgcmVwbGFjZWQgYnkgYSBzaW1wbGUgdGV4dCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxuICAgIH1cbiAgXVxufTtcblxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxuZXhwb3J0IGNvbnN0IGFic29sdXRlUHJvcHMgPSBbXG4gICdvcHRpb25zJyxcbiAgJ2dsb2JhbE9wdGlvbnMnLFxuICAndGhlbWVPcHRpb25zJyxcbiAgJ3Jlc291cmNlcycsXG4gICdwYXlsb2FkJ1xuXTtcblxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXG5leHBvcnQgY29uc3QgbmVzdGVkQXJncyA9IHt9O1xuXG4vKipcbiAqIENyZWF0ZXMgbmVzdGVkIGFyZ3VtZW50cyBjaGFpbiBmb3IgYWxsIG9wdGlvbnNcbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gb2JqIC0gVGhlIG9iamVjdCBiYXNlZCBvbiB3aGljaCB0aGUgaW5pdGlhbCBjb25maWd1cmF0aW9uIGJlXG4gKiBtYWRlLlxuICogQHBhcmFtIHtzdHJpbmcgfSBwcm9wQ2hhaW4gLSBSZXF1aXJlZCBmb3IgY3JlYXRpbmcgYSBzdHJpbmcgY2hhaW4gb2ZcbiAqIHByb3BlcnRpZXMgZm9yIG5lc3RlZCBhcmd1bWVudHMuXG4gKi9cbmNvbnN0IGNyZWF0ZU5lc3RlZEFyZ3MgPSAob2JqLCBwcm9wQ2hhaW4gPSAnJykgPT4ge1xuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhrKSkge1xuICAgICAgY29uc3QgZW50cnkgPSBvYmpba107XG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAvLyBHbyBkZWVwZXIgaW4gdGhlIG5lc3RlZCBhcmd1bWVudHNcbiAgICAgICAgY3JlYXRlTmVzdGVkQXJncyhlbnRyeSwgYCR7cHJvcENoYWlufS4ke2t9YCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBDcmVhdGUgdGhlIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHNcbiAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5jbGlOYW1lIHx8IGtdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XG4gICAgICB9XG4gICAgfVxuICB9KTtcbn07XG5cbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgYXBwZW5kRmlsZSwgZXhpc3RzU3luYywgbWtkaXJTeW5jIH0gZnJvbSAnZnMnO1xuXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XG5cbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXG5sZXQgbG9nZ2luZyA9IHtcbiAgLy8gRmxhZ3MgZm9yIGxvZ2dpbmcgc3RhdHVzXG4gIHRvQ29uc29sZTogdHJ1ZSxcbiAgdG9GaWxlOiBmYWxzZSxcbiAgcGF0aENyZWF0ZWQ6IGZhbHNlLFxuICAvLyBMb2cgbGV2ZWxzXG4gIGxldmVsc0Rlc2M6IFtcbiAgICB7XG4gICAgICB0aXRsZTogJ2Vycm9yJyxcbiAgICAgIGNvbG9yOiAncmVkJ1xuICAgIH0sXG4gICAge1xuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcbiAgICAgIGNvbG9yOiAneWVsbG93J1xuICAgIH0sXG4gICAge1xuICAgICAgdGl0bGU6ICdub3RpY2UnLFxuICAgICAgY29sb3I6ICdibHVlJ1xuICAgIH0sXG4gICAge1xuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcbiAgICAgIGNvbG9yOiAnZ3JheSdcbiAgICB9XG4gIF0sXG4gIC8vIExvZyBsaXN0ZW5lcnNcbiAgbGlzdGVuZXJzOiBbXVxufTtcblxuLy8gR2F0aGVyIGluaXQgbG9nZ2luZyBvcHRpb25zXG5mb3IgKGNvbnN0IFtrZXksIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMoZGVmYXVsdENvbmZpZy5sb2dnaW5nKSkge1xuICBsb2dnaW5nW2tleV0gPSBvcHRpb24udmFsdWU7XG59XG5cbi8qKlxuICogTG9ncyBhIG1lc3NhZ2UuIEFjY2VwdHMgYSB2YXJpYWJsZSBhbW91bnQgb2YgYXJndW1lbnRzLiBBcmd1bWVudHMgYWZ0ZXJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cbiAqXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxuICovXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xuXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XG5cbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XG5cbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcblxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xuICB9KTtcblxuICAvLyBMb2cgdG8gZmlsZVxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcbiAgICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcbiAgICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxuICAgICAgIWV4aXN0c1N5bmMobG9nZ2luZy5kZXN0KSAmJiBta2RpclN5bmMobG9nZ2luZy5kZXN0KTtcblxuICAgICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcbiAgICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXG4gICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcbiAgICB9XG5cbiAgICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXG4gICAgYXBwZW5kRmlsZShcbiAgICAgIGAke2xvZ2dpbmcuZGVzdH0ke2xvZ2dpbmcuZmlsZX1gLFxuICAgICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcbiAgICAgIChlcnJvcikgPT4ge1xuICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xuICAgICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgLy8gTG9nIHRvIGNvbnNvbGVcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XG4gICAgY29uc29sZS5sb2cuYXBwbHkoXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBTZXRzIHRoZSBmaWxlIGxvZ2dpbmcgY29uZmlndXJhdGlvbi5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRGVzdCAtIEEgcGF0aCB0byBsb2cgdG8uXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRmlsZSAtIFRoZSBuYW1lIG9mIHRoZSBsb2cgZmlsZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGVuYWJsZUZpbGVMb2dnaW5nID0gKGxvZ0Rlc3QsIGxvZ0ZpbGUpID0+IHtcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xuICBsb2dnaW5nID0ge1xuICAgIC4uLmxvZ2dpbmcsXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXG4gICAgZmlsZTogbG9nRmlsZSB8fCBsb2dnaW5nLmZpbGUsXG4gICAgdG9GaWxlOiB0cnVlXG4gIH07XG5cbiAgaWYgKGxvZ2dpbmcuZGVzdC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdDogbm8gcGF0aCBzdXBwbGllZC4nKTtcbiAgfVxuXG4gIGlmICghbG9nZ2luZy5kZXN0LmVuZHNXaXRoKCcvJykpIHtcbiAgICBsb2dnaW5nLmRlc3QgKz0gJy8nO1xuICB9XG59O1xuXG4vKipcbiAqIEFkZHMgYSBsb2cgbGlzdGVuZXIuXG4gKlxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gY2FsbCB3aGVuIGdldHRpbmcgYSBsb2cgZXZlbnQuXG4gKi9cbmV4cG9ydCBjb25zdCBsaXN0ZW4gPSAoZm4pID0+IHtcbiAgbG9nZ2luZy5saXN0ZW5lcnMucHVzaChmbik7XG59O1xuXG4vKipcbiAqIFNldHMgdGhlIGN1cnJlbnQgbG9nIGxldmVsLiBMb2cgbGV2ZWxzIGFyZTpcbiAqIC0gMCA9IG5vIGxvZ2dpbmdcbiAqIC0gMSA9IGVycm9yXG4gKiAtIDIgPSB3YXJuaW5nXG4gKiAtIDMgPSBub3RpY2VcbiAqIC0gNCA9IHZlcmJvc2VcbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCAoMCAtIDQpLlxuICovXG5leHBvcnQgY29uc3Qgc2V0TG9nTGV2ZWwgPSAobmV3TGV2ZWwpID0+IHtcbiAgaWYgKG5ld0xldmVsID49IDAgJiYgbmV3TGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xuICAgIGxvZ2dpbmcubGV2ZWwgPSBuZXdMZXZlbDtcbiAgfVxufTtcblxuLyoqXG4gKiBFbmFibGVzIG9yIGRpc2FibGVzIGxvZ2dpbmcgdG8gdGhlIHN0ZG91dC5cbiAqXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGVuYWJsZWQgLSBXaGV0aGVyIGxvZyB0byBjb25zb2xlIG9yIG5vdC5cbiAqL1xuZXhwb3J0IGNvbnN0IHRvZ2dsZVNURE91dCA9IChlbmFibGVkKSA9PiB7XG4gIGxvZ2dpbmcudG9Db25zb2xlID0gZW5hYmxlZDtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgbG9nLFxuICBlbmFibGVGaWxlTG9nZ2luZyxcbiAgbGlzdGVuLFxuICBzZXRMb2dMZXZlbCxcbiAgdG9nZ2xlU1RET3V0XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tICd1cmwnO1xuXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcblxuY29uc3QgTUFYX0JBQ0tPRkZfQVRURU1QVFMgPSA2O1xuXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XG5cbi8qKlxuICogQ2xlYXJzIHRleHQgZnJvbSB3aGl0ZXNwYWNlcyB3aXRoIGEgcmVnZXggcnVsZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcnVsZSAtIFRoZSBydWxlIGZvciBjbGVhcmluZyBhIHN0cmluZywgZGVmYXVsdCB0byAvXFxzXFxzKy9nLlxuICogQHJldHVybiB7c3RyaW5nfSAtIENsZWFyZWQgdGV4dC5cbiAqL1xuZXhwb3J0IGNvbnN0IGNsZWFyVGV4dCA9ICh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpID0+XG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xuXG4vKipcbiAqIERlbGF5cyBjYWxsaW5nIHRoZSBmdW5jdGlvbiBieSB0aW1lIGNhbGN1bGF0ZWQgYmFzZWQgb24gdGhlIGJhY2tvZmZcbiAqIGFsZ29yaXRobS5cbiAqXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiAtIEEgZnVuY3Rpb24gdG8gdHJ5IHRvIGNhbGwgd2l0aCB0aGUgYmFja29mZiBhbGdvcml0aG1cbiAqIG9uLlxuICogQHBhcmFtIHtudW1iZXJ9IGF0dGVtcHQgLSBUaGUgbnVtYmVyIG9mIGFuIGF0dGVtcHQsIHdoZXJlIHRoZSBmaXJzdCBvbmUgaXMgMC5cbiAqL1xuZXhwb3J0IGNvbnN0IGV4cEJhY2tvZmYgPSBhc3luYyAoZm4sIGF0dGVtcHQgPSAwLCAuLi5hcmdzKSA9PiB7XG4gIHRyeSB7XG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXG4gICAgcmV0dXJuIGF3YWl0IGZuKC4uLmFyZ3MpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xuICAgIGNvbnN0IGRlbGF5SW5NcyA9IDIgKiogYXR0ZW1wdCAqIDEwMDA7XG5cbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlYXBlYXQsIHRocm93IGFuIGVycm9yXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgZGVsYXlJbk1zKSk7XG4gICAgbG9nKFxuICAgICAgMyxcbiAgICAgIGBbcG9vbF0gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIGlkOiAke2FyZ3NbMF19LmBcbiAgICApO1xuXG4gICAgLy8gVHJ5IGFnYWluXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xuICB9XG59O1xuXG4vKipcbiAqIEZpeGVzIHRvIHN1cHBvcnRlZCB0eXBlIGZvcm1hdCBpZiBNSU1FLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVHlwZSB0byBiZSBjb3JyZWN0ZWQuXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIE5hbWUgb2YgdGhlIG91dGZpbGUuXG4gKi9cbmV4cG9ydCBjb25zdCBmaXhUeXBlID0gKHR5cGUsIG91dGZpbGUpID0+IHtcbiAgLy8gTUlNRSB0eXBlc1xuICBjb25zdCBtaW1lVHlwZXMgPSB7XG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXG4gIH07XG5cbiAgLy8gRm9ybWF0c1xuICBjb25zdCBmb3JtYXRzID0gWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ107XG5cbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXG4gIGlmIChvdXRmaWxlKSB7XG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcblxuICAgIC8vIENoZWNrIGlmIGV4dGVuc2lvbiBoYXMgYSBjb3JyZWN0IHR5cGVcbiAgICBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XG4gICAgICB0eXBlID0gb3V0VHlwZTtcbiAgICB9XG4gIH1cblxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xufTtcblxuLyoqXG4gKiBIYW5kbGVzIHRoZSBwcm92aWRlZCByZXNvdXJjZXMuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHJlc291cmNlcyAtIFRoZSBzdHJpbmdpZmllZCByZXNvdXJjZXMuXG4gKiBAcGFyYW0ge3N0cmluZ30gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRGVjaWRlIGlmIHJlc291cmNlcyBmcm9tIGZpbGUgYXJlXG4gKiBhbGxvd2VkLlxuICovXG5leHBvcnQgY29uc3QgaGFuZGxlUmVzb3VyY2VzID0gKHJlc291cmNlcyA9IGZhbHNlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcblxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcblxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcbiAgICB0cnkge1xuICAgICAgaWYgKCFyZXNvdXJjZXMpIHtcbiAgICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04oXG4gICAgICAgICAgcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4JylcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSBpZiAocmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xuICAgICAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZWFkRmlsZVN5bmMocmVzb3VyY2VzLCAndXRmOCcpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlc291cmNlcyk7XG4gICAgICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzID09PSB0cnVlKSB7XG4gICAgICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04oXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoJ3Jlc291cmNlcy5qc29uJywgJ3V0ZjgnKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChub3RpY2UpIHtcbiAgICAgIHJldHVybiBsb2coMywgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXG4gICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVzb3VyY2VzKTtcblxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cbiAgICBpZiAoIWFsbG93RmlsZVJlc291cmNlcykge1xuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XG4gICAgfVxuICB9XG5cbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcbiAgICB9XG4gIH1cblxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XG4gICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xuICB9XG5cbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cbiAgaWYgKGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMpIHtcbiAgICBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzID0gaGFuZGxlZFJlc291cmNlcy5maWxlcy5tYXAoKGl0ZW0pID0+IGl0ZW0udHJpbSgpKTtcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XG4gICAgfVxuICB9XG5cbiAgLy8gUmV0dXJuIHJlc291cmNlc1xuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcbn07XG5cbi8qKlxuICogQ2hlY2tzIGlmIHByb3ZpZGVkIGRhdGEgaXMgb3IgY2FuIGJlIGEgY29ycmVjdCBKU09OLlxuICpcbiAqIEBwYXJhbSB7YW55fSBkYXRhIC0gRGF0YSB0byBiZSBjaGVja2VkLlxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIElmIHRydWUsIHJldHVybiBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvbi5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzQ29ycmVjdEpTT04oZGF0YSwgdG9TdHJpbmcpIHtcbiAgdHJ5IHtcbiAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBpZiBub3QgYWxyZWFkeSBiZWZvcmUgcGFyc2luZ1xuICAgIGNvbnN0IHBhcnNlZERhdGEgPSBKU09OLnBhcnNlKFxuICAgICAgdHlwZW9mIGRhdGEgIT09ICdzdHJpbmcnID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiBkYXRhXG4gICAgKTtcblxuICAgIC8vIFJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uIG9mIGEgSlNPTiBpZiByZXF1aXJlZFxuICAgIGlmICh0eXBlb2YgcGFyc2VkRGF0YSAhPT0gJ3N0cmluZycgJiYgdG9TdHJpbmcpIHtcbiAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShwYXJzZWREYXRhKTtcbiAgICB9XG5cbiAgICAvLyBSZXR1cm4gYSBKU09OXG4gICAgcmV0dXJuIHBhcnNlZERhdGE7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGl0ZW0gaXMgYW4gb2JqZWN0LlxuICpcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gSXRlbSB0byBiZSBjaGVja2VkLlxuICovXG5leHBvcnQgY29uc3QgaXNPYmplY3QgPSAoaXRlbSkgPT5cbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGl0ZW0pICYmIGl0ZW0gIT09IG51bGw7XG5cbi8qKlxuICogQ2hlY2tzIGlmIHN0cmluZyBjb250YWlucyBwcml2YXRlIHJhbmdlIHVybHMuXG4gKlxuICogQGV4cG9ydCB1dGlsc1xuICogQHBhcmFtIGl0ZW0ge3N0cmluZ30gaXRlbSB0byBiZSBjaGVja2VkXG4gKi9cbmV4cG9ydCBjb25zdCBpc1ByaXZhdGVSYW5nZVVybEZvdW5kID0gKGl0ZW0pID0+IHtcbiAgcmV0dXJuIFtcbiAgICAnbG9jYWxob3N0JyxcbiAgICAnKDEwKS4oLiopLiguKikuKC4qKScsXG4gICAgJygxMjcpLiguKikuKC4qKS4oLiopJyxcbiAgICAnKDE3MikuKDFbNi05XXwyWzAtOV18M1swLTFdKS4oLiopLiguKiknLFxuICAgICcoMTkyKS4oMTY4KS4oLiopLiguKiknXG4gIF0uc29tZSgoaXBSZWdFeCkgPT5cbiAgICBpdGVtLm1hdGNoKGB4bGluazpocmVmPVwiKD86KGh0dHA6Ly98aHR0cHM6Ly8pKT8ke2lwUmVnRXh9YClcbiAgKTtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhbmQgcmV0dXJucyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0LlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBvYmplY3QgLSBPYmplY3QgdG8gY29weS5cbiAqIEByZXR1cm4ge29iamVjdH0gLSBEZWVwIGNvcHkgb2YgdGhlIG9iamVjdC5cbiAqL1xuZXhwb3J0IGNvbnN0IGRlZXBDb3B5ID0gKG9iaikgPT4ge1xuICBpZiAob2JqID09PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XG4gICAgcmV0dXJuIG9iajtcbiAgfVxuXG4gIGNvbnN0IGNvcHkgPSBBcnJheS5pc0FycmF5KG9iaikgPyBbXSA6IHt9O1xuXG4gIGZvciAoY29uc3Qga2V5IGluIG9iaikge1xuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBrZXkpKSB7XG4gICAgICBjb3B5W2tleV0gPSBkZWVwQ29weShvYmpba2V5XSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGNvcHk7XG59O1xuXG4vKipcbiAqIFN0cmluZ2lmaWVzIG9iamVjdCB3aXRoIG9wdGlvbnMuIFBvc3NpYmxlIHRvIHByZXNlcnZlIGZ1bmN0aW9ucyB3aXRoXG4gKiBhbGxvd0Z1bmN0aW9ucyBmbGFnLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gT3B0aW9ucyB0byBzdHJpbmdpZnkuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gRmxhZyBmb3Iga2VlcGluZyBmdW5jdGlvbnMuXG4gKi9cbmV4cG9ydCBjb25zdCBvcHRpb25zU3RyaW5naWZ5ID0gKG9wdGlvbnMsIGFsbG93RnVuY3Rpb25zKSA9PiB7XG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAobmFtZSwgdmFsdWUpID0+IHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xuICAgICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XG5cbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcbiAgICAgIGlmIChcbiAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCcpIHx8IHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgnKSkgJiZcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKVxuICAgICAgKSB7XG4gICAgICAgIHZhbHVlID0gYWxsb3dGdW5jdGlvbnNcbiAgICAgICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxuICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbidcbiAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXG4gICAgICA6IHZhbHVlO1xuICB9O1xuXG4gIC8vIFN0cmluZ2lmeSBvcHRpb25zIGFuZCBpZiByZXF1aXJlZCwgcmVwbGFjZSBzcGVjaWFsIGZ1bmN0aW9ucyBtYXJrc1xuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcbiAgICAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxuICAgICcnXG4gICk7XG59O1xuXG4vKipcbiAqIFByaW50cyB0aGUgZXhwb3J0IHNlcnZlciBsb2dvLlxuICpcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gV2hldGhlciB0byBkaXNwbGF5IGxvZ28gb3IgdGV4dC5cbiAqL1xuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBlbnYgb3IgZnJvbSBwYWNrYWdlLmpzb25cbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPVxuICAgIHByb2Nlc3MuZW52Lm5wbV9wYWNrYWdlX3ZlcnNpb24gfHxcbiAgICBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhuZXcgVVJMKCcuLi9wYWNrYWdlLmpzb24nLCBpbXBvcnQubWV0YS51cmwpKSlcbiAgICAgIC52ZXJzaW9uO1xuXG4gIC8vIFByaW50IHRleHQgb25seVxuICBpZiAobm9Mb2dvKSB7XG4gICAgY29uc29sZS5sb2coYFN0YXJ0aW5nIGhpZ2hjaGFydHMgZXhwb3J0IHNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn0uLi5gKTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBQcmludCB0aGUgbG9nb1xuICBjb25zb2xlLmxvZyhcbiAgICByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy9tc2cvc3RhcnR1cC5tc2cnKS50b1N0cmluZygpLmJvbGQueWVsbG93LFxuICAgIGB2JHtwYWNrYWdlVmVyc2lvbn1gXG4gICk7XG59O1xuXG4vKipcbiAqIFByaW50cyB0aGUgQ0xJIHVzYWdlLiBJZiByZXF1aXJlZCwgaXQgY2FuIGxpc3QgcHJvcGVydGllcyByZWN1cnNpdmVseVxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRVc2FnZSgpIHtcbiAgY29uc3QgcGFkID0gNDg7XG4gIGNvbnN0IHJlYWRtZSA9ICdodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lJztcblxuICAvLyBEaXNwbGF5IHJlYWRtZSBpbmZvcm1hdGlvblxuICBjb25zb2xlLmxvZyhcbiAgICAnVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXG4gICAgJ1xcbi0tLS0tLScsXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uIHZpc2l0IHJlYWRtZSBhdDogJHtyZWFkbWUuYm9sZC55ZWxsb3d9LmBcbiAgKTtcblxuICBjb25zdCBjeWNsZUNhdGVnb3JpZXMgPSAoY2F0ZWdvcmllcykgPT4ge1xuICAgIGZvciAoY29uc3QgW25hbWUsIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMoY2F0ZWdvcmllcykpIHtcbiAgICAgIC8vIElmIGNhdGVnb3J5IGhhcyBtb3JlIGxldmVscywgZ28gZnVydGhlclxuICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xuICAgICAgICBjeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCBkZXNjTmFtZSA9IGAgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfSAke1xuICAgICAgICAgICgnPCcgKyBvcHRpb24udHlwZSArICc+JykuZ3JlZW5cbiAgICAgICAgfSBgO1xuICAgICAgICBpZiAoZGVzY05hbWUubGVuZ3RoIDwgcGFkKSB7XG4gICAgICAgICAgZm9yIChsZXQgaSA9IGRlc2NOYW1lLmxlbmd0aDsgaSA8IHBhZDsgaSsrKSB7XG4gICAgICAgICAgICBkZXNjTmFtZSArPSAnLic7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICBkZXNjTmFtZSxcbiAgICAgICAgICBvcHRpb24uZGVzY3JpcHRpb24sXG4gICAgICAgICAgYFtEZWZhdWx0OiAke29wdGlvbi52YWx1ZS50b1N0cmluZygpLmJvbGR9XWAuYmx1ZVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICAvLyBDeWNsZSB0aHJvdWdoIG9wdGlvbnMgb2YgZWFjaCBjYXRlZ29yaWVzIGFuZCBkaXNwbGF5IHRoZSB1c2FnZSBpbmZvXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XG4gICAgLy8gT25seSBwdXBwZXRlZXIgYW5kIGhpZ2hjaGFydHMgY2F0ZWdvcmllcyBjYW5ub3QgYmUgY29uZmlndXJlZCB0aHJvdWdoIENMSVxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGNhdGVnb3J5KSkge1xuICAgICAgY29uc29sZS5sb2coYFxcbiR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLnJlZCk7XG4gICAgICBjeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xuICAgIH1cbiAgfSk7XG4gIGNvbnNvbGUubG9nKCdcXG4nKTtcbn1cblxuLyoqXG4gKiBSb3VuZHMgbnVtYmVyIHRvIHBhc3NlZCBwcmVjaXNpb24uXG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gTnVtYmVyIHRvIHJvdW5kLlxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIEEgcHJlY2lzaW9uIG9mIHJvdW5kaW5nLlxuICovXG5leHBvcnQgY29uc3Qgcm91bmROdW1iZXIgPSAodmFsdWUsIHByZWNpc2lvbiA9IDEpID0+IHtcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcbn07XG5cbi8qKlxuICogQ2FzdHMgdGhlIGl0ZW0gdG8gYm9vbGVhbi5cbiAqXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIEl0ZW0gdG8gYmUgY2FzdC5cbiAqL1xuZXhwb3J0IGNvbnN0IHRvQm9vbGVhbiA9IChpdGVtKSA9PlxuICBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXG4gICAgPyBmYWxzZVxuICAgIDogISFpdGVtO1xuXG4vKipcbiAqIElmIG5lY2Vzc2FyeSwgcGxhY2VzIGEgY3VzdG9tIGNvZGUgaW5zaWRlIGEgZnVuY3Rpb24uXG4gKlxuICogQHBhcmFtIHthbnl9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tQ29kZS5cbiAqL1xuZXhwb3J0IGNvbnN0IHdyYXBBcm91bmQgPSAoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcblxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xuICAgICAgICA/IHdyYXBBcm91bmQocmVhZEZpbGVTeW5jKGN1c3RvbUNvZGUsICd1dGY4JykpXG4gICAgICAgIDogZmFsc2U7XG4gICAgfSBlbHNlIGlmIChcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oKScpIHx8XG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpID0+JylcbiAgICApIHtcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xuICAgIH1cbiAgICByZXR1cm4gY3VzdG9tQ29kZS5yZXBsYWNlKC87JC8sICcnKTtcbiAgfVxufTtcblxuLyoqXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgdGltZS5cbiAqL1xuZXhwb3J0IGNvbnN0IG1lYXN1cmVUaW1lID0gKCkgPT4ge1xuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgX19kaXJuYW1lLFxuICBjbGVhclRleHQsXG4gIGV4cEJhY2tvZmYsXG4gIGZpeFR5cGUsXG4gIGhhbmRsZVJlc291cmNlcyxcbiAgaXNDb3JyZWN0SlNPTixcbiAgaXNPYmplY3QsXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXG4gIG9wdGlvbnNTdHJpbmdpZnksXG4gIHByaW50TG9nbyxcbiAgcHJpbnRVc2FnZSxcbiAgcm91bmROdW1iZXIsXG4gIHRvQm9vbGVhbixcbiAgd3JhcEFyb3VuZCxcbiAgbWVhc3VyZVRpbWVcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xuXG5pbXBvcnQgeyBjbGVhclRleHQgfSBmcm9tICcuLi91dGlscy5qcyc7XG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuXG4vKipcbiAqIEVuYWJsZXMgcmF0ZSBsaW1pdGluZyBmb3IgYSBnaXZlbiBhcHAuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGFwcCAtIFRoZSBleHByZXNzIGFwcC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBsaW1pdENvbmZpZyAtIFRoZSBvcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGluZy5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgKGFwcCwgbGltaXRDb25maWcpID0+IHtcbiAgY29uc3QgbXNnID1cbiAgICAnVG9vIG1hbnkgcmVxdWVzdHMsIHlvdSBoYXZlIGJlZW4gcmF0ZSBsaW1pdGVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XG5cbiAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxuICBjb25zdCByYXRlT3B0aW9ucyA9IHtcbiAgICBtYXg6IGxpbWl0Q29uZmlnLm1heFJlcXVlc3RzIHx8IDMwLFxuICAgIHdpbmRvdzogbGltaXRDb25maWcud2luZG93IHx8IDEsXG4gICAgZGVsYXk6IGxpbWl0Q29uZmlnLmRlbGF5IHx8IDAsXG4gICAgdHJ1c3RQcm94eTogbGltaXRDb25maWcudHJ1c3RQcm94eSB8fCBmYWxzZSxcbiAgICBza2lwS2V5OiBsaW1pdENvbmZpZy5za2lwS2V5IHx8IGZhbHNlLFxuICAgIHNraXBUb2tlbjogbGltaXRDb25maWcuc2tpcFRva2VuIHx8IGZhbHNlXG4gIH07XG5cbiAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XG4gIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XG4gICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcbiAgfVxuXG4gIC8vIENyZWF0ZSBhIGxpbWl0ZXJcbiAgY29uc3QgbGltaXRlciA9IHJhdGVMaW1pdCh7XG4gICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcbiAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgd2luZG93TXNcbiAgICBtYXg6IHJhdGVPcHRpb25zLm1heCxcbiAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxuICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxuICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcbiAgICAgICAganNvbjogKCkgPT4ge1xuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlOiBtc2cgfSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlZmF1bHQ6ICgpID0+IHtcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKG1zZyk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0sXG4gICAgc2tpcDogKHJlcXVlc3QpID0+IHtcbiAgICAgIC8vIEFsbG93IGJ5cGFzc2luZyB0aGUgbGltaXRlciBpZiBhIHZhbGlkIGtleS90b2tlbiBoYXMgYmVlbiBzZW50XG4gICAgICBpZiAoXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBLZXkgIT09IGZhbHNlICYmXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBUb2tlbiAhPT0gZmFsc2UgJiZcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxuICAgICAgKSB7XG4gICAgICAgIGxvZyg0LCAnW3JhdGUtbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9KTtcblxuICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxuICBhcHAudXNlKGxpbWl0ZXIpO1xuXG4gIGxvZyhcbiAgICAzLFxuICAgIGNsZWFyVGV4dChcbiAgICAgIGBbcmF0ZS1saW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nOiAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHNcbiAgICAgIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIHBlciBJUCwgdHJ1c3RpbmcgcHJveHk6XG4gICAgICAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcbiAgICApXG4gICk7XG59O1xuIiwiLyoqXG4gKiBUaGlzIG1vZHVsZSBleHBvcnRzIHR3byBmdW5jdGlvbnM6IGZldGNoIChmb3IgR0VUIHJlcXVlc3RzKSBhbmQgcG9zdCAoZm9yIFBPU1QgcmVxdWVzdHMpLlxuICovXG5cbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcblxuLyoqXG4gKiBEZXRlcm1pbmVzIHRoZSBwcm90b2NvbCBvZiB0aGUgZ2l2ZW4gVVJMIChlaXRoZXIgYGh0dHBgIG9yIGBodHRwc2ApLlxuICpcbiAqIEBmdW5jdGlvblxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgd2hvc2UgcHJvdG9jb2wgbmVlZHMgdG8gYmUgZGV0ZXJtaW5lZC5cbiAqIEByZXR1cm5zIHtPYmplY3R9IFJldHVybnMgdGhlIGBodHRwc2AgbW9kdWxlIGlmIHRoZSBVUkwgc3RhcnRzIHdpdGggJ2h0dHBzJyxcbiAqIG90aGVyd2lzZSByZXR1cm5zIHRoZSBgaHR0cGAgbW9kdWxlLlxuICogQHByaXZhdGVcbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2woJ2h0dHBzOi8vZXhhbXBsZS5jb20nKTtcbiAqIGNvbnNvbGUubG9nKHByb3RvY29sKTsgLy8gT3V0cHV0cyB0aGUgJ2h0dHBzJyBtb2R1bGVcbiAqL1xuY29uc3QgZ2V0UHJvdG9jb2wgPSAodXJsKSA9PiB7XG4gIHJldHVybiB1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cDtcbn07XG5cbi8qKlxuICogU2VuZHMgYSBHRVQgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIG9wdGlvbmFsIHJlcXVlc3Qgb3B0aW9ucy5cbiAqXG4gKiBAZnVuY3Rpb25cbiAqIEBhc3luY1xuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2guXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbmFsIHJlcXVlc3Qgb3B0aW9ucyBhbmQgaGVhZGVycy5cbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFJldHVybnMgYSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgcmVzcG9uc2Ugb2JqZWN0LlxuICogVGhlIHJlc3BvbnNlIG9iamVjdCBjb250YWlucyBhIGAudGV4dGAgcHJvcGVydHkgd2l0aCB0aGUgcmF3IHJlc3BvbnNlIGRhdGEuXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSByZXF1ZXN0IGZhaWxzIG9yIGlmIG5vIGRhdGEgaXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiBhc3luYyBmdW5jdGlvbiBnZXREYXRhKCkge1xuICogICB0cnkge1xuICogICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goJ2h0dHBzOi8vYXBpLmV4YW1wbGUuY29tL2RhdGEnKTtcbiAqICAgICBjb25zb2xlLmxvZyhyZXNwb25zZS50ZXh0KTtcbiAqICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAqICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBmZXRjaGluZyBkYXRhOicsIGVycm9yKTtcbiAqICAgfVxuICogfVxuICpcbiAqIGdldERhdGEoKTtcbiAqL1xuYXN5bmMgZnVuY3Rpb24gZmV0Y2godXJsLCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xuXG4gICAgcHJvdG9jb2xcbiAgICAgIC5nZXQodXJsLCByZXF1ZXN0T3B0aW9ucywgKHJlcykgPT4ge1xuICAgICAgICBsZXQgZGF0YSA9ICcnO1xuXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcbiAgICAgICAgICBpZiAoIWRhdGEpIHtcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xuICAgICAgICAgIHJlc29sdmUocmVzKTtcbiAgICAgICAgfSk7XG4gICAgICB9KVxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIFNlbmRzIGEgUE9TVCByZXF1ZXN0IHRvIHRoZSBzcGVjaWZpZWQgVVJMIHdpdGggdGhlIGdpdmVuIGJvZHkgYW5kIHJlcXVlc3Qgb3B0aW9ucy5cbiAqXG4gKiBAZnVuY3Rpb25cbiAqIEBhc3luY1xuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gd2hpY2ggdGhlIHJlcXVlc3Qgc2hvdWxkIGJlIHNlbnQuXG4gKiBAcGFyYW0ge09iamVjdH0gW2JvZHk9e31dIC0gVGhlIGRhdGEgdG8gYmUgc2VudCBhcyB0aGUgcmVxdWVzdCBib2R5LCBpbiBKU09OIGZvcm1hdC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBbcmVxdWVzdE9wdGlvbnM9e31dIC0gT3B0aW9uYWwgcmVxdWVzdCBvcHRpb25zIGFuZCBoZWFkZXJzLlxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gLSBSZXR1cm5zIGEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHBhcnNlZCBKU09OIHJlc3BvbnNlLlxuICogQHRocm93cyB7RXJyb3J9IFRocm93cyBhbiBlcnJvciBpZiB0aGUgcmVxdWVzdCBmYWlscyBvciBpZiB0aGUgcmVzcG9uc2UgY2Fubm90IGJlIHBhcnNlZC5cbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIGFzeW5jIGZ1bmN0aW9uIHNlbmREYXRhKCkge1xuICogICBjb25zdCBkYXRhVG9TZW5kID0ge1xuICogICAgIGtleTE6ICd2YWx1ZTEnLFxuICogICAgIGtleTI6ICd2YWx1ZTInLFxuICogICB9O1xuICogICB0cnkge1xuICogICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgcG9zdCgnaHR0cHM6Ly9hcGkuZXhhbXBsZS5jb20vZGF0YScsIGRhdGFUb1NlbmQpO1xuICogICAgIGNvbnNvbGUubG9nKHJlc3BvbnNlKTtcbiAqICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAqICAgICBjb25zb2xlLmVycm9yKCdFcnJvciBzZW5kaW5nIGRhdGE6JywgZXJyb3IpO1xuICogICB9XG4gKiB9XG4gKlxuICogc2VuZERhdGEoKTtcbiAqL1xuYXN5bmMgZnVuY3Rpb24gcG9zdCh1cmwsIGJvZHkgPSB7fSwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcbiAgICBjb25zdCBkYXRhID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XG5cbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXG4gICAgICB7XG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgcmVxdWVzdE9wdGlvbnNcbiAgICApO1xuXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcbiAgICAgIC5yZXF1ZXN0KHVybCwgb3B0aW9ucywgKHJlcykgPT4ge1xuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XG5cbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xuICAgICAgICAgICAgcmVzb2x2ZShyZXMpO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KVxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSk7XG5cbiAgICAvLyBXcml0ZSB0aGUgcmVxdWVzdCBib2R5IGFuZCBlbmQgdGhlIHJlcXVlc3QuXG4gICAgcmVxLndyaXRlKGRhdGEpO1xuICAgIHJlcS5lbmQoKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IGZldGNoO1xuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXG4vLyBUaGUgY2FjaGUgaXRzZWxmIGlzIHN0b3JlZCBpbiAuY2FjaGUsIGFuZCBpcyBjaGVja2VkIGJ5IHRoZSBjb25maWcgc3lzdGVtXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcblxuaW1wb3J0IHsgZXhpc3RzU3luYywgbWtkaXJTeW5jLCByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XG5cbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcbmltcG9ydCBIdHRwc1Byb3h5QWdlbnQgZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcblxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vbGliL3V0aWxzLmpzJztcblxuZG90ZW52LmNvbmZpZygpO1xuXG5jb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgJy5jYWNoZScpO1xuXG5jb25zdCBjYWNoZSA9IHtcbiAgY2RuVVJMOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcbiAgc291cmNlczogJycsXG4gIGhjVmVyc2lvbjogJydcbn07XG5cbi8vIFRPRE86IFRoZSBjb25maWcgc2hvdWxkIGJlIGFjY2Vzc3NpYmxlIGdsb2JhbGx5IHNvIHdlIGRvbid0IGhhdmUgdG8gZG8gdGhpcyBzb3J0IG9mIHRoaW5nLi5cbmxldCBhcHBsaWVkQ29uZmlnID0gZmFsc2U7XG5cbi8qKlxuICogRXh0cmFjdHMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBjYWNoZVxuICovXG5jb25zdCBleHRyYWN0VmVyc2lvbiA9ICgpID0+XG4gIChjYWNoZS5oY1ZlcnNpb24gPSBjYWNoZS5zb3VyY2VzXG4gICAgLnN1YnN0cigwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXG4gICAgLnJlcGxhY2UoJy8qJywgJycpXG4gICAgLnJlcGxhY2UoJyovJywgJycpXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcbiAgICAudHJpbSgpKTtcblxuLyoqXG4gKiBTYXZlcyB0aGUgSGlnaGNoYXJ0cyBwYXJ0IG9mIGEgY29uZmlnIHRvIGEgbWFuaWZlc3QgZmlsZSBpbiB0aGUgY2FjaGVcbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cyByZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHRoYXQgY29udGFpbnMgbWFwcGVkIG5hbWVzIG9mXG4gKiBmZXRjaGVkIEhpZ2hjaGFydHMgbW9kdWxlcyB0byB1c2UuXG4gKi9cbmNvbnN0IHNhdmVDb25maWdUb01hbmlmZXN0ID0gYXN5bmMgKGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpID0+IHtcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XG4gICAgdmVyc2lvbjogY29uZmlnLnZlcnNpb24sXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXMgfHwge31cbiAgfTtcblxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IG5ld01hbmlmZXN0O1xuXG4gIGxvZyg0LCAnW2NhY2hlXSB3cml0aW5nIG5ldyBtYW5pZmVzdCcpO1xuXG4gIHRyeSB7XG4gICAgd3JpdGVGaWxlU3luYyhcbiAgICAgIGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpLFxuICAgICAgSlNPTi5zdHJpbmdpZnkobmV3TWFuaWZlc3QpLFxuICAgICAgJ3V0ZjgnXG4gICAgKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBsb2coMSwgYFtjYWNoZV0gRXJyb3Igd3JpdGluZyBjYWNoZSBtYW5pZmVzdDogJHtlcnJvcn0uYCk7XG4gIH1cbn07XG5cbi8qKlxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5QWdlbnQgLSBUaGUgcHJveHkgYWdlbnQgdG8gdXNlIGZvciBhIHJlcXVlc3QuXG4gKi9cbmNvbnN0IGZldGNoU2NyaXB0ID0gYXN5bmMgKHNjcmlwdCwgcHJveHlBZ2VudCkgPT4ge1xuICB0cnkge1xuICAgIC8vIEdldCByaWQgb2YgdGhlIC5qcyBmcm9tIHRoZSBjdXN0b20gc3RyaW5nc1xuICAgIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XG4gICAgICBzY3JpcHQgPSBzY3JpcHQuc3Vic3RyaW5nKDAsIHNjcmlwdC5sZW5ndGggLSAzKTtcbiAgICB9XG5cbiAgICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XG5cbiAgICAvLyBJZiBleGlzdHMsIGFkZCBwcm94eSBhZ2VudCB0byByZXF1ZXN0IG9wdGlvbnNcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHByb3h5QWdlbnRcbiAgICAgID8ge1xuICAgICAgICAgIGFnZW50OiBwcm94eUFnZW50LFxuICAgICAgICAgIHRpbWVvdXQ6ICtwcm9jZXNzLmVudlsnUFJPWFlfU0VSVkVSX1RJTUVPVVQnXSB8fCA1MDAwXG4gICAgICAgIH1cbiAgICAgIDoge307XG5cbiAgICAvLyBGZXRjaCB0aGUgc2NyaXB0XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xuXG4gICAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxuICAgIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDApIHtcbiAgICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xuICAgIH1cblxuICAgIHRocm93IGAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9YDtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBsb2coMSwgYFtjYWNoZV0gRXJyb3IgZmV0Y2hpbmcgc2NyaXB0ICR7c2NyaXB0fS5qczogJHtlcnJvcn0uYCk7XG4gICAgdGhyb3cgZXJyb3I7XG4gIH1cbn07XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgSGlnaGNoYXJ0cyBjYWNoZS5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cyByZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBBIHBhdGggdG8gdGhlIGZpbGUgd2hlcmUgc2F2ZSB1cGRhdGVkIHNvdXJjZXMuXG4gKiBAcmV0dXJuIHtvYmplY3R9IEFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIG1hcHBlZCBuYW1lcyBvZiBmZXRjaGVkIEhpZ2hjaGFydHNcbiAqIG1vZHVsZXMgdG8gdXNlLlxuICovXG5jb25zdCB1cGRhdGVDYWNoZSA9IGFzeW5jIChjb25maWcsIHNvdXJjZVBhdGgpID0+IHtcbiAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlcywgaW5kaWNhdG9ycywgc2NyaXB0czogY3VzdG9tU2NyaXB0cyB9ID0gY29uZmlnO1xuICBjb25zdCBoY1ZlcnNpb24gPVxuICAgIGNvbmZpZy52ZXJzaW9uID09PSAnbGF0ZXN0JyB8fCAhY29uZmlnLnZlcnNpb24gPyAnJyA6IGAke2NvbmZpZy52ZXJzaW9ufS9gO1xuXG4gIGxvZygzLCAnW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB0byBIaWdoY2hhcnRzICcsIGhjVmVyc2lvbik7XG5cbiAgLy8gR2F0aGVyIGFsbCBzY3JpcHRzIHRvIGZldGNoXG4gIGNvbnN0IGFsbFNjcmlwdHMgPSBbXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChjKSA9PiBgJHtoY1ZlcnNpb259JHtjfWApLFxuICAgIC4uLm1vZHVsZXMubWFwKChtKSA9PlxuICAgICAgbSA9PT0gJ21hcCcgPyBgbWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gIDogYCR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcbiAgICApLFxuICAgIC4uLmluZGljYXRvcnMubWFwKChpKSA9PiBgc3RvY2svJHtoY1ZlcnNpb259aW5kaWNhdG9ycy8ke2l9YClcbiAgXTtcblxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXG4gIGxldCBwcm94eUFnZW50O1xuICBjb25zdCBwcm94eUhvc3QgPSBwcm9jZXNzLmVudlsnUFJPWFlfU0VSVkVSX0hPU1QnXTtcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJvY2Vzcy5lbnZbJ1BST1hZX1NFUlZFUl9QT1JUJ107XG5cbiAgaWYgKHByb3h5SG9zdCAmJiBwcm94eVBvcnQpIHtcbiAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XG4gICAgICBob3N0OiBwcm94eUhvc3QsXG4gICAgICBwb3J0OiArcHJveHlQb3J0XG4gICAgfSk7XG4gIH1cblxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xuICB0cnkge1xuICAgIGNhY2hlLnNvdXJjZXMgPSAvLyBUT0RPOiBjb252ZXJ0IHRvIGZvciBsb29wXG4gICAgICAoXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAuLi5hbGxTY3JpcHRzLm1hcChhc3luYyAoc2NyaXB0KSA9PiB7XG4gICAgICAgICAgICBjb25zdCB0ZXh0ID0gYXdhaXQgZmV0Y2hTY3JpcHQoXG4gICAgICAgICAgICAgIGAke2NvbmZpZy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMfSR7c2NyaXB0fWAsXG4gICAgICAgICAgICAgIHByb3h5QWdlbnRcbiAgICAgICAgICAgICk7XG5cbiAgICAgICAgICAgIC8vIElmIGZldGNoZWQgY29ycmVjdGx5LCBzZXQgaXRcbiAgICAgICAgICAgIGlmICh0eXBlb2YgdGV4dCA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgZmV0Y2hlZE1vZHVsZXNbXG4gICAgICAgICAgICAgICAgc2NyaXB0LnJlcGxhY2UoXG4gICAgICAgICAgICAgICAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcbiAgICAgICAgICAgICAgICAgICcnXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICBdID0gMTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHRleHQ7XG4gICAgICAgICAgfSksXG4gICAgICAgICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT4gZmV0Y2hTY3JpcHQoc2NyaXB0LCBwcm94eUFnZW50KSlcbiAgICAgICAgXSlcbiAgICAgICkuam9pbignO1xcbicpO1xuICAgIGV4dHJhY3RWZXJzaW9uKCk7XG5cbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcbiAgICByZXR1cm4gZmV0Y2hlZE1vZHVsZXM7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbG9nKDEsICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS4nKTtcbiAgfVxufTtcblxuZXhwb3J0IGNvbnN0IHVwZGF0ZVZlcnNpb24gPSBhc3luYyAobmV3VmVyc2lvbikgPT5cbiAgYXBwbGllZENvbmZpZ1xuICAgID8gYXdhaXQgY2hlY2tDYWNoZShcbiAgICAgICAgT2JqZWN0LmFzc2lnbihhcHBsaWVkQ29uZmlnLCB7XG4gICAgICAgICAgdmVyc2lvbjogbmV3VmVyc2lvblxuICAgICAgICB9KVxuICAgICAgKVxuICAgIDogZmFsc2U7XG5cbi8qKlxuICogRmV0Y2hlcyBhbnkgbWlzc2luZyBIaWdoY2hhcnRzIGFuZCBkZXBlbmRlbmNpZXNcbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cyByZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxuICovXG5leHBvcnQgY29uc3QgY2hlY2tDYWNoZSA9IGFzeW5jIChjb25maWcpID0+IHtcbiAgbGV0IGZldGNoZWRNb2R1bGVzO1xuICAvLyBQcmVwYXJlIHBhdGhzIHRvIG1hbmlmZXN0IGFuZCBzb3VyY2VzIGZyb20gdGhlIC5jYWNoZSBmb2xkZXJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XG4gIGNvbnN0IHNvdXJjZVBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ3NvdXJjZXMuanMnKTtcblxuICAvLyBUT0RPOiBkZWFsIHdpdGggdHJ5aW5nIHRvIHN3aXRjaCB0byB0aGUgcnVubmluZyB2ZXJzaW9uXG4gIC8vIGNvbnN0IGFjdGl2ZVZlcnNpb24gPSBhcHBsaWVkQ29uZmlnID8gYXBwbGllZENvbmZpZy52ZXJzaW9uIDogZmFsc2U7XG5cbiAgYXBwbGllZENvbmZpZyA9IGNvbmZpZztcblxuICAvLyBDcmVhdGUgdGhlIC5jYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcbiAgIWV4aXN0c1N5bmMoY2FjaGVQYXRoKSAmJiBta2RpclN5bmMoY2FjaGVQYXRoKTtcblxuICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIG1hbmlmZXN0Lmpzb24gZG9lcyBub3QgZXhpc3RcbiAgLy8gb3IgaWYgdGhlIGZvcmNlRmV0Y2ggb3B0aW9uIGlzIGVuYWJsZWRcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgY29uZmlnLmZvcmNlRmV0Y2gpIHtcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XG4gICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShjb25maWcsIHNvdXJjZVBhdGgpO1xuICB9IGVsc2Uge1xuICAgIGxldCByZXF1ZXN0VXBkYXRlID0gZmFsc2U7XG5cbiAgICAvLyBSZWFkIHRoZSBtYW5pZmVzdCBKU09OXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpKTtcblxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2R1bGVzIGlzIGFuIGFycmF5LCBpZiBzbywgd2UgcmV3cml0ZSBpdCB0byBhIG1hcCB0byBtYWtlXG4gICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlcy5cbiAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XG4gICAgICBjb25zdCBtb2R1bGVNYXAgPSB7fTtcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMuZm9yRWFjaCgobSkgPT4gKG1vZHVsZU1hcFttXSA9IDEpKTtcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XG4gICAgfVxuXG4gICAgY29uc3QgeyBtb2R1bGVzLCBjb3JlU2NyaXB0cywgaW5kaWNhdG9ycyB9ID0gY29uZmlnO1xuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XG4gICAgICBtb2R1bGVzLmxlbmd0aCArIGNvcmVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvcnMubGVuZ3RoO1xuXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGNvbmZpZyB3aXRoIHRoZSBjb250ZW50cyBpbiAuY2FjaGUuXG4gICAgLy8gSWYgdGhlcmUgYXJlIGNoYW5nZXMsIGZldGNoIHJlcXVlc3RlZCBtb2R1bGVzIGFuZCBwcm9kdWN0cyxcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBjb25maWcudmVyc2lvbikge1xuICAgICAgbG9nKDMsICdbY2FjaGVdIEhpZ2hjaGFydHMgdmVyc2lvbiBtaXNtYXRjaCBpbiBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nKTtcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xuICAgIH0gZWxzZSBpZiAoT2JqZWN0LmtleXMobWFuaWZlc3QubW9kdWxlcyB8fCB7fSkubGVuZ3RoICE9PSBudW1iZXJPZk1vZHVsZXMpIHtcbiAgICAgIGxvZyhcbiAgICAgICAgMyxcbiAgICAgICAgJ1tjYWNoZV0gQ2FjaGUgYW5kIHJlcXVlc3RlZCBtb2R1bGVzIGRvZXMgbm90IG1hdGNoLCBuZWVkIHRvIHJlLWZldGNoLidcbiAgICAgICk7XG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKGNvbmZpZy5tb2R1bGVzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xuICAgICAgICAgIGxvZyhcbiAgICAgICAgICAgIDMsXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBtaXNzaW5nIGluIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLmBcbiAgICAgICAgICApO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCB1cGRhdGVDYWNoZShjb25maWcsIHNvdXJjZVBhdGgpO1xuICAgIH0gZWxzZSB7XG4gICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xuXG4gICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXG4gICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XG5cbiAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IG1hbmlmZXN0Lm1vZHVsZXM7XG4gICAgICBleHRyYWN0VmVyc2lvbigpO1xuICAgIH1cbiAgfVxuXG4gIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcbiAgYXdhaXQgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoY29uZmlnLCBmZXRjaGVkTW9kdWxlcyk7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGNoZWNrQ2FjaGUsXG4gIHVwZGF0ZVZlcnNpb24sXG4gIGdldENhY2hlOiAoKSA9PiBjYWNoZSxcbiAgaGlnaGNoYXJ0czogKCkgPT4gY2FjaGUuc291cmNlcyxcbiAgdmVyc2lvbjogKCkgPT4gY2FjaGUuaGNWZXJzaW9uXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcbmltcG9ydCBmcyBmcm9tICdmcyc7XG5pbXBvcnQgKiBhcyB1cmwgZnJvbSAndXJsJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XG5cbi8vIFdvcmthcm91bmQgZm9yIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTE0NjMzMjhcbi8vIE5vdCBpZGVhbCAtIGxlYXZlcyB0cmFzaCBpbiB0aGUgRlNcbmltcG9ydCB7IHJhbmRvbUJ5dGVzIH0gZnJvbSAnbm9kZTpjcnlwdG8nO1xuY29uc3QgUkFORE9NX1BJRCA9IHJhbmRvbUJ5dGVzKDY0KS50b1N0cmluZygnYmFzZTY0dXJsJyk7XG5jb25zdCBQVVBQRVRFRVJfRElSID0gcGF0aC5qb2luKCd0bXAnLCBgcHVwcGV0ZWVyLSR7UkFORE9NX1BJRH1gKTtcbmNvbnN0IERBVEFfRElSID0gcGF0aC5qb2luKFBVUFBFVEVFUl9ESVIsICdwcm9maWxlJyk7XG5cbi8vIFRoZSBtaW5pbWFsIGFyZ3MgdG8gc3BlZWQgdXAgdGhlIGJyb3dzZXJcbmNvbnN0IG1pbmltYWxBcmdzID0gW1xuICBgLS11c2VyLWRhdGEtZGlyPSR7REFUQV9ESVJ9YCxcbiAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXG4gICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcbiAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLXRpbWVyLXRocm90dGxpbmcnLFxuICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXG4gICctLWRpc2FibGUtYnJlYWtwYWQnLFxuICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXG4gICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXG4gICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcbiAgJy0tZGlzYWJsZS1kZXYtc2htLXVzYWdlJyxcbiAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxuICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxuICAnLS1kaXNhYmxlLWZlYXR1cmVzPUF1ZGlvU2VydmljZU91dE9mUHJvY2VzcycsXG4gICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcbiAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXG4gICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXG4gICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcbiAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXG4gICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXG4gICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXG4gICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXG4gICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXG4gICctLWRpc2FibGUtc2V0dWlkLXNhbmRib3gnLFxuICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxuICAnLS1kaXNhYmxlLXN5bmMnLFxuICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcbiAgJy0taGlkZS1zY3JvbGxiYXJzJyxcbiAgJy0taWdub3JlLWdwdS1ibGFja2xpc3QnLFxuICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcbiAgJy0tbXV0ZS1hdWRpbycsXG4gICctLW5vLWRlZmF1bHQtYnJvd3Nlci1jaGVjaycsXG4gICctLW5vLWZpcnN0LXJ1bicsXG4gICctLW5vLXBpbmdzJyxcbiAgJy0tbm8tc2FuZGJveCcsXG4gICctLW5vLXp5Z290ZScsXG4gICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcbiAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXG5dO1xuXG5jb25zdCBfX2Rpcm5hbWUgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XG5cbmNvbnN0IHRlbXBsYXRlID0gZnMucmVhZEZpbGVTeW5jKFxuICBfX2Rpcm5hbWUgKyAnLy4uL3RlbXBsYXRlcy90ZW1wbGF0ZS5odG1sJyxcbiAgJ3V0ZjgnXG4pO1xuXG5sZXQgYnJvd3NlcjtcblxuZXhwb3J0IGNvbnN0IG5ld1BhZ2UgPSBhc3luYyAoKSA9PiB7XG4gIGlmICghYnJvd3NlcikgcmV0dXJuIGZhbHNlO1xuXG4gIGNvbnN0IHAgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcblxuICBhd2FpdCBwLnNldENvbnRlbnQodGVtcGxhdGUpO1xuICBhd2FpdCBwLmFkZFNjcmlwdFRhZyh7IHBhdGg6IF9fZGlybmFtZSArICcvLi4vLmNhY2hlL3NvdXJjZXMuanMnIH0pO1xuICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgYXdhaXQgcC5ldmFsdWF0ZSgoKSA9PiB3aW5kb3cuc2V0dXBIaWdoY2hhcnRzKCkpO1xuXG4gIHAub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnIpID0+IHtcbiAgICAvLyBUT0RPOiBDb25zaWRlciBhZGRpbmcgYSBzd2l0Y2ggaGVyZSB0aGF0IHR1cm5zIG9uIGxvZygwKSBsb2dnaW5nXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXG4gICAgbG9nKDEsICdbcGFnZSBlcnJvcl0nLCBlcnIpO1xuICAgIGF3YWl0IHAuJGV2YWwoXG4gICAgICAnI2NvbnRhaW5lcicsXG4gICAgICAoZWxlbWVudCwgZXJyb3JNZXNzYWdlKSA9PiB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XG4gICAgICAgICAgZWxlbWVudC5pbm5lckhUTUwgPSBlcnJvck1lc3NhZ2U7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBgPGgxPkNoYXJ0IGlucHV0IGRhdGEgZXJyb3I8L2gxPiR7ZXJyLnRvU3RyaW5nKCl9YFxuICAgICk7XG4gIH0pO1xuXG4gIHJldHVybiBwO1xufTtcblxuZXhwb3J0IGNvbnN0IGNyZWF0ZSA9IGFzeW5jIChwdXBwZXRlZXJBcmdzKSA9PiB7XG4gIGNvbnN0IGFsbEFyZ3MgPSBbLi4ubWluaW1hbEFyZ3MsIC4uLihwdXBwZXRlZXJBcmdzIHx8IFtdKV07XG5cbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxuICBpZiAoIWJyb3dzZXIpIHtcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xuXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGxvZyhcbiAgICAgICAgICAzLFxuICAgICAgICAgICdbYnJvd3Nlcl0gYXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnknLFxuICAgICAgICAgIHRyeUNvdW50ICsgJyknXG4gICAgICAgICk7XG5cbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2goe1xuICAgICAgICAgIGhlYWRsZXNzOiAnbmV3JyxcbiAgICAgICAgICBhcmdzOiBhbGxBcmdzLFxuICAgICAgICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJ1xuICAgICAgICB9KTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgbG9nKDAsICdbYnJvd3Nlcl0nLCBlKTtcbiAgICAgICAgaWYgKCsrdHJ5Q291bnQgPCAyNSkge1xuICAgICAgICAgIGxvZygzLCAnW2Jyb3dzZXJdIGZhaWxlZDonLCBlKTtcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcbiAgICAgICAgICBhd2FpdCBvcGVuKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbG9nKDAsICdNYXggcmV0cmllcyByZWFjaGVkJyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IG9wZW4oKTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBsb2coMCwgJ1ticm93c2VyXSBVbmFibGUgdG8gb3BlbiBicm93c2VyJyk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKCFicm93c2VyKSB7XG4gICAgICBsb2coMCwgJ1ticm93c2VyXSBVbmFibGUgdG8gb3BlbiBicm93c2VyJyk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBwcm9taXNlXG4gIHJldHVybiBicm93c2VyO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldCA9IGFzeW5jICgpID0+IHtcbiAgaWYgKCFicm93c2VyKSB7XG4gICAgdGhyb3cgJ05vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZCc7XG4gIH1cblxuICByZXR1cm4gYnJvd3Nlcjtcbn07XG5cbmV4cG9ydCBjb25zdCBjbG9zZSA9IGFzeW5jICgpID0+IHtcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgd2hlbiBjb25ubmVjdGVkXG4gIGlmIChicm93c2VyLmNvbm5lY3RlZCkge1xuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcbiAgfVxufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBnZXQsXG4gIGNsb3NlLFxuICBuZXdQYWdlXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbi8vIFRPRE86IHJlbW92ZSB0aGlzIHRlbXAgYmVuY2htYXJrIHN0dWZmLiBJIGhhZCB0aGlzIGlkZWEgb2YgZG9pbmcgYSBnZW5lcmFsIGJlbmNobWFya2luZ1xuLy8gc3lzdGVtLCBidXQgaXQgYWRkcyBzbyBtdWNoIGJsb2F0IGluIHRoZSBjb2RlIHRoYXQgaXQgc2hvdWxkbid0IGJlIHRoZXJlLlxuXG5pbXBvcnQgYmVuY2htYXJrIGZyb20gJy4vYmVuY2htYXJrLmpzJztcbmltcG9ydCBjYWNoZSBmcm9tICcuL2NhY2hlLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCBzdmdUZW1wbGF0ZSBmcm9tICcuLy4uL3RlbXBsYXRlcy9zdmdfZXhwb3J0L3N2Z19leHBvcnQuanMnO1xuXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCAqIGFzIHVybCBmcm9tICd1cmwnO1xuXG5jb25zdCBfX2Jhc2VkaXIgPSB1cmwuZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuJywgaW1wb3J0Lm1ldGEudXJsKSk7XG5cbi8vIGNvbnN0IGpzb25UZW1wbGF0ZSA9IHJlcXVpcmUoJy4vLi4vdGVtcGxhdGVzL2pzb25fZXhwb3J0L2pzb25fZXhwb3J0LmpzJyk7XG5cbi8qKlxuICogR2V0cyB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBjaGFydCBET00gbm9kZS5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gcGFnZSAtIEEgcGFnZSBvZiBhIGJyb3dzZXIgaW5zdGFuY2UuXG4gKiBAcmV0dXJuIHtvYmplY3R9IC0gQSBjbGlwcGVkIHJlZ2lvbi5cbiAqL1xuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxuICBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHgsXG4gICAgICB5LFxuICAgICAgd2lkdGgsXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcbiAgICB9O1xuICB9KTtcblxuLyoqXG4gKiBSYXN0ZXJpemVzIHRoZSBwYWdlIHRvIGFuIGltYWdlIChQTkcgb3IgSlBFRylcbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gcGFnZSAtIEEgcGFnZSBvZiBhIGJyb3dzZXIgaW5zdGFuY2UuXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSB0eXBlIG9mIGEgcmVzdWx0IGltYWdlLlxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gVGhlIHR5cGUgb2YgZW5jb2RpbmcgdXNlZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBjbGlwIC0gVGhlIGNsaXAgcmVnaW9uLlxuICogQHJldHVybnMge3N0cmluZ30gLSBBIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiBhIHNjcmVlbnNob3QuXG4gKi9cbmNvbnN0IGNyZWF0ZUltYWdlID0gYXN5bmMgKHBhZ2UsIHR5cGUsIGVuY29kaW5nLCBjbGlwKSA9PlxuICBhd2FpdCBQcm9taXNlLnJhY2UoW1xuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XG4gICAgICB0eXBlLFxuICAgICAgZW5jb2RpbmcsXG4gICAgICBjbGlwLFxuXG4gICAgICAvLyAjNDQ3IC0gYWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2VcbiAgICAgIC8vIHRoaXMgd2lsbCBub3QgYWZmZWN0IHVzZXJzIHdobyBkbyBub3QgZXhwbGljaXRseSBzZXRcbiAgICAgIC8vIGNoYXJ0LmJhY2tncm91bmRDb2xvciB0byBhIGNvbG9yIHdpdGggb3BhY2l0eSBsb3dlciB0aGFuIDFcbiAgICAgIG9taXRCYWNrZ3JvdW5kOiB0cnVlXG4gICAgfSksXG4gICAgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT5cbiAgICAgIHNldFRpbWVvdXQoKCkgPT4gcmVqZWN0KG5ldyBFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLCAxNTAwKVxuICAgIClcbiAgXSk7XG5cbi8qKlxuICogVHVybnMgcGFnZSBpbnRvIGEgUERGLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBwYWdlIC0gQSBwYWdlIG9mIGEgYnJvd3NlciBpbnN0YW5jZS5cbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBUaGUgaGVpZ2h0IG9mIGEgY2hhcnQuXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBUaGUgd2lkdGggb2YgYSBjaGFydC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIFRoZSB0eXBlIG9mIGVuY29kaW5nIHVzZWQuXG4gKiBAcmV0dXJuIHtvYmplY3R9IC0gQSBidWZmZXIgd2l0aCBQREYgcmVwcmVzZW50YXRpb24uXG4gKi9cbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChwYWdlLCBoZWlnaHQsIHdpZHRoLCBlbmNvZGluZykgPT5cbiAgYXdhaXQgcGFnZS5wZGYoe1xuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xuICAgIGhlaWdodDogaGVpZ2h0ICsgMSxcbiAgICB3aWR0aCxcbiAgICBlbmNvZGluZ1xuICB9KTtcblxuLyoqXG4gKiBFeHBvcnRzIGFzIGEgU1ZHLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBwYWdlIC0gQSBwYWdlIG9mIGEgYnJvd3NlciBpbnN0YW5jZS5cbiAqIEByZXR1cm4ge29iamVjdH0gLSBUaGUgb3V0ZXJIVE1MIGVsZW1lbnQgd2l0aCB0aGUgU1ZHIHJlcHJlc2VudGF0aW9uLlxuICovXG5jb25zdCBjcmVhdGVTVkcgPSBhc3luYyAocGFnZSkgPT5cbiAgYXdhaXQgcGFnZS4kZXZhbChcbiAgICAnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsXG4gICAgKGVsZW1lbnQpID0+IGVsZW1lbnQub3V0ZXJIVE1MXG4gICk7XG5cbi8qKiBMb2FkIGNvbmZpZyBpbnRvIGEgcGFnZSBhbmQgcmVuZGVyIGEgY2hhcnQgKi9cbmNvbnN0IHNldEFzQ29uZmlnID0gYXN5bmMgKHBhZ2UsIGNoYXJ0LCBvcHRpb25zKSA9PlxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKFxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgIChjaGFydCwgb3B0aW9ucykgPT4gd2luZG93LnRyaWdnZXJFeHBvcnQoY2hhcnQsIG9wdGlvbnMpLFxuICAgIGNoYXJ0LFxuICAgIG9wdGlvbnNcbiAgKTtcblxuLyoqIExvYWQgU1ZHIGludG8gYSBwYWdlICovXG4vLyBjb25zdCBzZXRBc1NWRyA9IGFzeW5jIChwYWdlLCBzdmdTdHIpID0+IHRydWU7XG5cbi8qKlxuICogRG9lcyBhbiBleHBvcnQgZm9yIGEgZ2l2ZW4gYnJvd3Nlci5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gYnJvd3NlciAtIEEgYnJvd3NlciBpbnN0YW5jZS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBjaGFydCAtIENoYXJ0J3Mgb3B0aW9ucy5cbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgb2JqZWN0LlxuICogQHJldHVybiB7b2JqZWN0fSAtIFRoZSBkYXRhIHJldHVybmVkIGZyb20gb25lIG9mIHRoZSBtZXRob2RzIGZvciBleHBvcnRpbmdcbiAqIGEgc3BlY2lmaWMgdHlwZSBvZiBhbiBpbWFnZS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgYXN5bmMgKHBhZ2UsIGNoYXJ0LCBvcHRpb25zKSA9PiB7XG4gIC8qKlxuICAgKiBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcbiAgICogSXQncyBWSVRBTCB0aGF0IGFsbCBhZGRlZCByZXNvdXJjZXMgZW5kcyB1cCBoZXJlIHNvIHdlIGNhbiBjbGVhciB0aGluZ3NcbiAgICogb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXG4gICAqL1xuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xuXG4gIC8qKiBDbGVhciBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gKi9cbiAgY29uc3QgY2xlYXJJbmplY3RlZCA9IGFzeW5jIChwYWdlKSA9PiB7XG4gICAgZm9yIChjb25zdCByZXMgb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcbiAgICAgIGF3YWl0IHJlcy5kaXNwb3NlKCk7XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgY29uc3QgWywgLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgY29uc3QgWywgLi4uc3R5bGVzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3N0eWxlJyk7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XG5cbiAgICAgIC8vIFJlbW92ZSB0YWdzXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xuICAgICAgICAuLi5zY3JpcHRzVG9SZW1vdmUsXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXG4gICAgICBdKSB7XG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgdHJ5IHtcbiAgICBjb25zdCBleHBvcnRCZW5jaCA9IGJlbmNobWFyaygnUHVwcGV0ZWVyJyk7XG5cbiAgICBsb2coNCwgJ1tleHBvcnRdIERldGVybWluaW5nIGV4cG9ydCBwYXRoLicpO1xuXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xuXG4gICAgLy8gRm9yY2UgYSByQUZcbiAgICAvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3B1cHBldGVlci9wdXBwZXRlZXIvaXNzdWVzLzc1MDdcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHJlcXVlc3RBbmltYXRpb25GcmFtZSgoKSA9PiB7fSkpO1xuXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxuICAgIGNvbnN0IGRpc3BsYXlFcnJvcnMgPVxuICAgICAgZXhwb3J0T3B0aW9ucz8ub3B0aW9ucz8uY2hhcnQ/LmRpc3BsYXlFcnJvcnMgJiZcbiAgICAgIGNhY2hlLmdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcblxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKGQpID0+ICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMgPSBkKSwgZGlzcGxheUVycm9ycyk7XG5cbiAgICBjb25zdCBzdmdCZW5jaCA9IGJlbmNobWFyaygnU1ZHIGhhbmRsaW5nJyk7XG5cbiAgICBsZXQgaXNTVkc7XG5cbiAgICBpZiAoXG4gICAgICBjaGFydC5pbmRleE9mICYmXG4gICAgICAoY2hhcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgY2hhcnQuaW5kZXhPZignPD94bWwnKSA+PSAwKVxuICAgICkge1xuICAgICAgLy8gU1ZHIElOUFVUIEhBTkRMSU5HXG5cbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xuXG4gICAgICAvLyBJZiBpbnB1dCBpcyBhbHNvIHN2ZywganVzdCByZXR1cm4gaXRcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XG4gICAgICAgIHJldHVybiBjaGFydDtcbiAgICAgIH1cblxuICAgICAgaXNTVkcgPSB0cnVlO1xuICAgICAgY29uc3Qgc2V0UGFnZUJlbmNoID0gYmVuY2htYXJrKCdTZXR0aW5nIGNvbnRlbnQnKTtcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShjaGFydCkpO1xuICAgICAgc2V0UGFnZUJlbmNoKCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIEpTT04gQ29uZmlnIGhhbmRsaW5nXG5cbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgY29uZmlnLicpO1xuXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdHJJbmopIHtcbiAgICAgICAgLy8gSW5qZWN0aW9uIGJhc2VkIGNvbmZpZ3VyYXRpb24gZXhwb3J0XG4gICAgICAgIGNvbnN0IHNldFBhZ2VCZW5jaCA9IGJlbmNobWFyaygnU2V0dGluZyBwYWdlIGNvbnRlbnQgKGluamVjdCknKTtcblxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhcbiAgICAgICAgICBwYWdlLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGNoYXJ0OiB7XG4gICAgICAgICAgICAgIGhlaWdodDogZXhwb3J0T3B0aW9ucy5oZWlnaHQsXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvcHRpb25zXG4gICAgICAgICk7XG5cbiAgICAgICAgc2V0UGFnZUJlbmNoKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBCYXNpYyBjb25maWd1cmF0aW9uIGV4cG9ydFxuXG4gICAgICAgIGNoYXJ0LmNoYXJ0LmhlaWdodCA9IGV4cG9ydE9wdGlvbnMuaGVpZ2h0O1xuICAgICAgICBjaGFydC5jaGFydC53aWR0aCA9IGV4cG9ydE9wdGlvbnMud2lkdGg7XG5cbiAgICAgICAgY29uc3Qgc2V0Q29udGVudEJlbmNoID0gYmVuY2htYXJrKCdTZXR0aW5nIHBhZ2UgY29udGVudCAoY29uZmlnKScpO1xuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhwYWdlLCBjaGFydCwgb3B0aW9ucyk7XG4gICAgICAgIHNldENvbnRlbnRCZW5jaCgpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHN2Z0JlbmNoKCk7XG4gICAgY29uc3QgcmVzQmVuY2ggPSBiZW5jaG1hcmsoJ0FwcGx5aW5nIHJlc291cmNlcycpO1xuXG4gICAgLy8gVXNlIHJlc291cmNlc1xuICAgIGNvbnN0IHJlc291cmNlcyA9IG9wdGlvbnMuY3VzdG9tQ29kZS5yZXNvdXJjZXM7XG4gICAgaWYgKHJlc291cmNlcykge1xuICAgICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxuICAgICAgaWYgKHJlc291cmNlcy5qcykge1xuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxuICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHtcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xuICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIExvYWQgc2NyaXB0cyBmcm9tIGFsbCBjdXN0b20gZmlsZXNcbiAgICAgIGlmIChyZXNvdXJjZXMuZmlsZXMpIHtcbiAgICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHJlc291cmNlcy5maWxlcykge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xuXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xuICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcbiAgICAgICAgICAgICAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoXG4gICAgICAgICAgICAgICAgaXNMb2NhbFxuICAgICAgICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4JylcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgOiB7XG4gICAgICAgICAgICAgICAgICAgICAgdXJsOiBmaWxlXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGNhdGNoIChub3RpY2UpIHtcbiAgICAgICAgICAgIGxvZyg0LCAnW2V4cG9ydF0gSlMgZmlsZSBub3QgZm91bmQuJyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGNzc0JlbmNoID0gYmVuY2htYXJrKCdMb2FkaW5nIGNzcycpO1xuXG4gICAgICAvLyBMb2FkIENTU1xuICAgICAgaWYgKHJlc291cmNlcy5jc3MpIHtcbiAgICAgICAgbGV0IGNzc0ltcG9ydHMgPSByZXNvdXJjZXMuY3NzLm1hdGNoKC9AaW1wb3J0XFxzKihbXjtdKik7L2cpO1xuICAgICAgICBpZiAoY3NzSW1wb3J0cykge1xuICAgICAgICAgIC8vIEhhbmRsZSBjc3Mgc2VjdGlvblxuICAgICAgICAgIGZvciAobGV0IGNzc0ltcG9ydFBhdGggb2YgY3NzSW1wb3J0cykge1xuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGgpIHtcbiAgICAgICAgICAgICAgY3NzSW1wb3J0UGF0aCA9IGNzc0ltcG9ydFBhdGhcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgndXJsKCcsICcnKVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKCdAaW1wb3J0JywgJycpXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL1wiL2csICcnKVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8nL2csICcnKVxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC87LywgJycpXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL1xcKS9nLCAnJylcbiAgICAgICAgICAgICAgICAudHJpbSgpO1xuXG4gICAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcbiAgICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XG4gICAgICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcbiAgICAgICAgICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoe1xuICAgICAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcbiAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25zLmN1c3RvbUNvZGUuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XG4gICAgICAgICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcbiAgICAgICAgICAgICAgICAgIGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoe1xuICAgICAgICAgICAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4oX19iYXNlZGlyLCBjc3NJbXBvcnRQYXRoKVxuICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChcbiAgICAgICAgICBhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKHtcbiAgICAgICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXG4gICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgY3NzQmVuY2goKTtcbiAgICB9XG5cbiAgICByZXNCZW5jaCgpO1xuXG4gICAgLy8gR2V0IHRoZSByZWFsIGNoYXJ0IHNpemVcbiAgICBjb25zdCBzaXplID0gaXNTVkdcbiAgICAgID8gYXdhaXQgcGFnZS4kZXZhbChcbiAgICAgICAgICAnI2NoYXJ0LWNvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsXG4gICAgICAgICAgYXN5bmMgKGVsZW1lbnQsIHNjYWxlKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICBjaGFydEhlaWdodDogZWxlbWVudC5oZWlnaHQuYmFzZVZhbC52YWx1ZSAqIHNjYWxlLFxuICAgICAgICAgICAgICBjaGFydFdpZHRoOiBlbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICB9LFxuICAgICAgICAgIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcbiAgICAgICAgKVxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxuICAgICAgICAgICAgY2hhcnRXaWR0aFxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuXG4gICAgY29uc3QgdnBCZW5jaCA9IGJlbmNobWFyaygnU2V0dGluZyB2aWV3cG9ydCcpO1xuXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmNlaWwoc2l6ZT8uY2hhcnRIZWlnaHQgfHwgZXhwb3J0T3B0aW9ucy5oZWlnaHQpO1xuICAgIGNvbnN0IHZpZXdwb3J0V2lkdGggPSBNYXRoLmNlaWwoc2l6ZT8uY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcblxuICAgIC8vIFNldCB0aGUgdmlld3BvcnQgZm9yIHRoZSBmaXJzdCB0aW1lXG4gICAgLy8gTk9URTogdGhlIGNhbGwgdG8gc2V0Vmlld3BvcnQgaXMgZXhwZW5zaXZlIC0gY2FuIHdlIGdldCBhd2F5IHdpdGggb25seVxuICAgIC8vIGNhbGxpbmcgaXQgb25jZSwgZS5nLiBtb3ZpbmcgdGhpcyBvbmUgaW50byB0aGUgaXNTVkcgY29uZGl0aW9uIGJlbG93P1xuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xuICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcbiAgICB9KTtcblxuICAgIC8vIFByZXBhcmUgYSB6b29tIGNhbGxiYWNrIGZvciB0aGUgbmV4dCBldmFsdWF0ZSBjYWxsXG4gICAgY29uc3Qgem9vbUNhbGxiYWNrID0gaXNTVkdcbiAgICAgID8gLy8gSW4gY2FzZSBvZiBTVkcgdGhlIHpvb20gbXVzdCBiZSBzZXQgZGlyZWN0bHkgZm9yIGJvZHlcbiAgICAgICAgKHNjYWxlKSA9PiB7XG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gc2NhbGU7XG5cbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xuICAgICAgICB9XG4gICAgICA6IC8vIE5vIG5lZWQgZm9yIHN1Y2ggc2NhbGUgbWFuaXB1bGF0aW9uIGluIGNhc2Ugb2Ygb3RoZXIgdHlwZXMgb2YgZXhwb3J0c1xuICAgICAgICAoKSA9PiB7XG4gICAgICAgICAgLy8gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gMTtcbiAgICAgICAgfTtcblxuICAgIC8vIFNldCB0aGUgem9vbSBhY2NvcmRpbmdseVxuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoem9vbUNhbGxiYWNrLCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKTtcblxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXG4gICAgY29uc3QgeyBoZWlnaHQsIHdpZHRoLCB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xuXG4gICAgaWYgKCFpc1NWRykge1xuICAgICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxuICAgICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XG4gICAgICAgIHdpZHRoOiBNYXRoLnJvdW5kKHdpZHRoKSxcbiAgICAgICAgaGVpZ2h0OiBNYXRoLnJvdW5kKGhlaWdodCksXG4gICAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICB2cEJlbmNoKCk7XG5cbiAgICBsZXQgZGF0YTtcblxuICAgIGNvbnN0IGV4cEJlbmNobWFyayA9IGJlbmNobWFyaygnUmFzdGVyaXppbmcgY2hhcnQnKTtcblxuICAgIC8vIFJBU1RFUklaQVRJT05cbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xuICAgICAgLy8gU1ZHXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlU1ZHKHBhZ2UpO1xuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncG5nJyB8fCBleHBvcnRPcHRpb25zLnR5cGUgPT09ICdqcGVnJykge1xuICAgICAgLy8gUE5HIG9yIEpQRUdcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVJbWFnZShwYWdlLCBleHBvcnRPcHRpb25zLnR5cGUsICdiYXNlNjQnLCB7XG4gICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxuICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxuICAgICAgICB4LFxuICAgICAgICB5XG4gICAgICB9KTtcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BkZicpIHtcbiAgICAgIC8vIFBERlxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVBERihwYWdlLCB2aWV3cG9ydEhlaWdodCwgdmlld3BvcnRXaWR0aCwgJ2Jhc2U2NCcpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBgVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX1gO1xuICAgIH1cblxuICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciB0aGUgZXhwb3J0IGlzIGRvbmVcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgY29uc3Qgb2xkQ2hhcnRzID0gSGlnaGNoYXJ0cy5jaGFydHM7XG5cbiAgICAgIC8vIENoZWNrIGluIGFueSBhbHJlYWR5IGV4aXN0aW5nIGNoYXJ0c1xuICAgICAgaWYgKG9sZENoYXJ0cy5sZW5ndGgpIHtcbiAgICAgICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzXG4gICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XG4gICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGV4cEJlbmNobWFyaygpO1xuICAgIGV4cG9ydEJlbmNoKCk7XG5cbiAgICBhd2FpdCBjbGVhckluamVjdGVkKHBhZ2UpO1xuXG4gICAgcmV0dXJuIGRhdGE7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgYXdhaXQgY2xlYXJJbmplY3RlZChwYWdlKTtcbiAgICBsb2coMSwgYFtleHBvcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQ6ICR7ZXJyb3J9YCk7XG5cbiAgICByZXR1cm4gZXJyb3I7XG4gIH1cbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjIsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuY29uc3QgdGltZXJzID0ge307XG5cbi8vIFRPRE86IFJlYWQgZnJvbSBjb25maWdcbmxldCBlbmFibGVkID0gZmFsc2U7XG5cbmV4cG9ydCBkZWZhdWx0IChpZCkgPT4ge1xuICBpZiAoIWVuYWJsZWQpIHtcbiAgICByZXR1cm4gKCkgPT4ge307XG4gIH1cblxuICB0aW1lcnNbaWRdID0gbmV3IERhdGUoKTtcbiAgcmV0dXJuICgpID0+IHtcbiAgICBsb2coXG4gICAgICAzLFxuICAgICAgYFtiZW5jaG1hcmtdIC0gJHtpZH06ICR7bmV3IERhdGUoKS5nZXRUaW1lKCkgLSB0aW1lcnNbaWRdLmdldFRpbWUoKX1tc2BcbiAgICApO1xuICB9O1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgY3NzVGVtcGxhdGUgZnJvbSAnLi9jc3MuanMnO1xuXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcbjwhRE9DVFlQRSBodG1sPlxuPGh0bWwgbGFuZz0nZW4tVVMnPlxuICA8aGVhZD5cbiAgICA8bWV0YSBodHRwLWVxdWl2PVwiQ29udGVudC1UeXBlXCIgY29udGVudD1cInRleHQvaHRtbDsgY2hhcnNldD11dGYtOFwiPlxuICAgIDx0aXRsZT5IaWdoY2FydHMgRXhwb3J0PC90aXRsZT5cbiAgPC9oZWFkPlxuICA8c3R5bGU+XG4gICAgJHtjc3NUZW1wbGF0ZSgpfVxuICA8L3N0eWxlPlxuICA8Ym9keT5cbiAgICA8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+XG4gICAgICAke2NoYXJ0fVxuICAgIDwvZGl2PlxuICA8L2JvZHk+XG48L2h0bWw+XG5cbmA7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xuaW1wb3J0IHtcbiAgY2xvc2UsXG4gIG5ld1BhZ2UgYXMgYnJvd3Nlck5ld1BhZ2UsXG4gIGNyZWF0ZSBhcyBjcmVhdGVCcm93c2VyXG59IGZyb20gJy4vYnJvd3Nlci5qcyc7XG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5cbmltcG9ydCBwdXBwZXRlZXJFeHBvcnQgZnJvbSAnLi9leHBvcnQuanMnO1xuXG5sZXQgcGVyZm9ybWVkRXhwb3J0cyA9IDA7XG5sZXQgZXhwb3J0QXR0ZW1wdHMgPSAwO1xubGV0IHRpbWVTcGVudCA9IDA7XG5sZXQgZHJvcHBlZEV4cG9ydHMgPSAwO1xubGV0IHNwZW50QXZlcmFnZSA9IDA7XG5sZXQgcG9vbENvbmZpZyA9IHt9O1xuXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxubGV0IHBvb2wgPSBmYWxzZTtcblxuLy8gQ3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHNcbmxldCBwdXBwZXRlZXJBcmdzO1xuXG5jb25zdCBmYWN0b3J5ID0ge1xuICAvKipcbiAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIuXG4gICAqXG4gICAqIEByZXR1cm4ge29iamVjdH0gLSBBbiBvYmplY3Qgd2l0aCB0aGUgaWQgb2YgYSByZXNvdXJjZSwgdGhlIHdvcmsgY291bnQgYW5kXG4gICAqIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UuXG4gICAqL1xuICBjcmVhdGU6IGFzeW5jICgpID0+IHtcbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcbiAgICBsZXQgcGFnZSA9IGZhbHNlO1xuXG4gICAgY29uc3QgcyA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuXG4gICAgdHJ5IHtcbiAgICAgIHBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xuXG4gICAgICBpZiAoIXBhZ2UgfHwgcGFnZS5pc0Nsb3NlZCgpKSB7XG4gICAgICAgIHRocm93ICdpbnZhbGlkIHBhZ2UnO1xuICAgICAgfVxuXG4gICAgICBsb2coXG4gICAgICAgIDMsXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XG4gICAgICAgICAgbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzXG4gICAgICAgIH0gbXMuYFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nKFxuICAgICAgICAxLFxuICAgICAgICBgW3Bvb2xdIEVycm9yIGNyZWF0aW5nIGEgbmV3IHBhZ2UgaW4gcG9vbCBlbnRyeSBjcmVhdGlvbiEgJHtlcnJvcn1gXG4gICAgICApO1xuXG4gICAgICB0aHJvdyAnRXJyb3IgY3JlYXRpbmcgcGFnZSc7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlkLFxuICAgICAgcGFnZSxcbiAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXG4gICAgfTtcbiAgfSxcblxuICAvKipcbiAgICogVmFsaWRhdGVzIGEgd29ya2VyLlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gd29ya2VySGFuZGxlIC0gQSBicm93c2VyJ3MgaW5zdGFuY2UuXG4gICAqXG4gICAqIEByZXR1cm4ge2Jvb2xlYW59IC0gQm9vbCB0aGF0IGluZGljYXRlcyBpZiBhIHJlc291cmNlIGlzIHZhbGlkIG9yIG5vdC5cbiAgICovXG4gIHZhbGlkYXRlOiAod29ya2VySGFuZGxlKSA9PiB7XG4gICAgaWYgKFxuICAgICAgcG9vbENvbmZpZy53b3JrTGltaXQgJiZcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XG4gICAgKSB7XG4gICAgICBsb2coXG4gICAgICAgIDMsXG4gICAgICAgIGBbcG9vbF0gV29ya2VyIGZhaWxlZCB2YWxpZGF0aW9uOmAsXG4gICAgICAgIGBleGNlZWRlZCB3b3JrIGxpbWl0IChsaW1pdCBpcyAke3Bvb2xDb25maWcud29ya0xpbWl0fSlgXG4gICAgICApO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSxcblxuICAvKipcbiAgICogRGVzdHJveXMgYSB3b3JrZXIuXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBBIGJyb3dzZXIncyBpbnN0YW5jZS5cbiAgICovXG4gIGRlc3Ryb3k6ICh3b3JrZXJIYW5kbGUpID0+IHtcbiAgICBsb2coMywgYFtwb29sXSBEZXN0cm95aW5nIHBvb2wgZW50cnkgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xuXG4gICAgaWYgKHdvcmtlckhhbmRsZS5wYWdlKSB7XG4gICAgICAvLyBXZSBkb24ndCByZWFsbHkgbmVlZCB0byB3YWl0IGFyb3VuZCBmb3IgdGhpcy5cbiAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XG4gICAgfVxuICB9LFxuXG4gIC8vIExvZ2dlciBmdW5jdGlvblxuICBsb2c6IChtZXNzYWdlLCBsb2dMZXZlbCkgPT4gY29uc29sZS5sb2coYCR7bG9nTGV2ZWx9OiAke21lc3NhZ2V9YClcbn07XG5cbi8qKlxuICogSW5pdHMgdGhlIHBvb2wgb2YgcmVzb3VyY2VzLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25maWcgLSBQb29sIGNvbmZpZ3VyYXRpb24gYWxvbmcgd2l0aCBjdXN0b20gcHVwcGV0ZWVyXG4gKiBhcmd1bWVudHMgZm9yIHRoZSBwdXBwZXRlZXIubGF1bmNoIGZ1bmN0aW9uLlxuICovXG5leHBvcnQgY29uc3QgaW5pdCA9IGFzeW5jIChjb25maWcpID0+IHtcbiAgLy8gVGhlIG5ld2VzdCBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgYnJvd3NlciBjcmVhdGlvblxuICBwdXBwZXRlZXJBcmdzID0gY29uZmlnLnB1cHBldGVlckFyZ3M7XG5cbiAgLy8gV2FpdCB1bnRpbCB3ZSd2ZSBzdWNlc3NmdWxseSBjcmVhdGVkIGEgYnJvd3NlciBpbnN0YW5jZS5cbiAgdHJ5IHtcbiAgICBhd2FpdCBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgbG9nKDAsICdbcG9vbHxicm93c2VyXScsIGUpO1xuICB9XG5cbiAgLy8gRm9yIHRoZSBtb2R1bGUgc2NvcGUgdXNhZ2VcbiAgcG9vbENvbmZpZyA9IGNvbmZpZyAmJiBjb25maWcucG9vbCA/IHsgLi4uY29uZmlnLnBvb2wgfSA6IHt9O1xuXG4gIGxvZyhcbiAgICAzLFxuICAgICdbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2w6JyxcbiAgICBgbWluICR7cG9vbENvbmZpZy5pbml0aWFsV29ya2Vyc30sIG1heCAke3Bvb2xDb25maWcubWF4V29ya2Vyc30uYFxuICApO1xuXG4gIGlmIChwb29sKSB7XG4gICAgcmV0dXJuIGxvZyhcbiAgICAgIDQsXG4gICAgICAnW3Bvb2xdIEFscmVhZHkgaW5pdGlhbGl6ZWQsIHBsZWFzZSBraWxsIGl0IGJlZm9yZSBjcmVhdGluZyBhIG5ldyBvbmUuJ1xuICAgICk7XG4gIH1cblxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcbiAgaWYgKHBvb2xDb25maWcubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcbiAgICBwb29sID0gbmV3IFBvb2woe1xuICAgICAgLy8gR2V0IHRoZSBjcmVhdGUvdmFsaWRhdGUvZGVzdHJveS9sb2cgZnVuY3Rpb25zXG4gICAgICAuLi5mYWN0b3J5LFxuICAgICAgbWluOiBwb29sQ29uZmlnLmluaXRpYWxXb3JrZXJzLFxuICAgICAgbWF4OiBwb29sQ29uZmlnLm1heFdvcmtlcnMsXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiAyMDAsXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbENvbmZpZy5hY3F1aXJlVGltZW91dCxcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLnRpbWVvdXRUaHJlc2hvbGQsXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IDEwMDAsIC8vIHBvb2xDb25maWcucmVhcGVyID8gMTIwMDAwIDogMCwgZm9yIG5vd1xuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXG4gICAgfSk7XG5cbiAgICAvLyBTZXQgZXZlbnRzXG4gICAgcG9vbC5vbignY3JlYXRlRmFpbCcsIChldmVudElkLCBlcnIpID0+IHtcbiAgICAgIGxvZyhcbiAgICAgICAgMSxcbiAgICAgICAgYFtwb29sXSBFcnJvciB3aGVuIGNyZWF0aW5nIHdvcmtlciBvZiBhbiBldmVudCBpZCAke2V2ZW50SWR9OmAsXG4gICAgICAgIGVyclxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIHBvb2wub24oJ2FjcXVpcmVGYWlsJywgKGV2ZW50SWQsIGVycikgPT4ge1xuICAgICAgbG9nKFxuICAgICAgICAxLFxuICAgICAgICBgW3Bvb2xdIEVycm9yIHdoZW4gYWNxdWlyaW5nIHdvcmtlciBvZiBhbiBldmVudCBpZCAke2V2ZW50SWR9OmAsXG4gICAgICAgIGVyclxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIHBvb2wub24oJ2Rlc3Ryb3lGYWlsJywgKGV2ZW50SWQsIHJlc291cmNlLCBlcnIpID0+IHtcbiAgICAgIGxvZyhcbiAgICAgICAgMSxcbiAgICAgICAgYFtwb29sXSBFcnJvciB3aGVuIGRlc3Ryb3lpbmcgd29ya2VyIG9mIGFuIGlkICR7cmVzb3VyY2UuaWR9LCBldmVudCBpZCAke2V2ZW50SWR9OmAsXG4gICAgICAgIGVyclxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIHBvb2wub24oJ3JlbGVhc2UnLCAocmVzb3VyY2UpID0+IHtcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIFJlbGVhc2luZyBhIHdvcmtlciBvZiBhbiBpZCAke3Jlc291cmNlLmlkfWApO1xuICAgIH0pO1xuXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIERlc3Ryb3llZCBhIHdvcmtlciBvZiBhbiBpZCAke3Jlc291cmNlLmlkfWApO1xuICAgIH0pO1xuXG4gICAgY29uc3QgaW5pdGlhbFJlc291cmNlcyA9IFtdO1xuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xDb25maWcuaW5pdGlhbFdvcmtlcnM7IGkrKykge1xuICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2UpO1xuICAgIH1cblxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcbiAgICB9KTtcblxuICAgIGxvZyhcbiAgICAgIDMsXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5IHdpdGggJHtwb29sQ29uZmlnLmluaXRpYWxXb3JrZXJzfSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmBcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZygxLCBgW3Bvb2xdIENvdWxkbid0IGNyZWF0ZSB0aGUgd29ya2VyIHBvb2wgJHtlcnJvcn1gKTtcbiAgICB0aHJvdyBlcnJvcjtcbiAgfVxufTtcblxuLyoqXG4gKiBBdHRhY2hlcyBwcm9jZXNzJyBleGl0IGxpc3RlbmVycy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCkge1xuICBsb2coNCwgJ1twb29sXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XG5cbiAgLy8gS2lsbCBhbGwgcG9vbCByZXNvdXJjZXMgb24gZXhpdFxuICBwcm9jZXNzLm9uKCdleGl0JywgYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IGtpbGxQb29sKCk7XG4gIH0pO1xuXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSBTSUdJTlRcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgKG5hbWUsIGNvZGUpID0+IHtcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcbiAgICBwcm9jZXNzLmV4aXQoMSk7XG4gIH0pO1xuXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSBTSUdURVJNXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCAobmFtZSwgY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xuICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgfSk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlIHVuY2F1Z2h0RXhjZXB0aW9uXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBlcnJvciwgbWVzc2FnZTogJHtlcnJvci5tZXNzYWdlfS5gKTtcbiAgfSk7XG59XG5cbi8qKlxuICogS2lsbHMgdGhlIHBvb2wgYW5kIGZsdXNoIHRoZSBicm93c2VyIGluc3RhbmNlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XG4gIGxvZygzLCAnW3Bvb2xdIEtpbGxpbmcgYWxsIHdvcmtlcnMuJyk7XG5cbiAgLy8gUmV0dXJuIHRydWUgd2hlbiB0aGUgcG9vbCBpcyBhbHJlYWR5IGRlc3Ryb3llZFxuICBpZiAocG9vbC5kZXN0cm95ZWQpIHtcbiAgICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZSBpZiBzdGlsbCBjb25uZWN0ZWRcbiAgICBhd2FpdCBjbG9zZSgpO1xuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXG4gIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xuXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlXG4gIGF3YWl0IGNsb3NlKCk7XG4gIHJldHVybiB0cnVlO1xufVxuXG4vKipcbiAqIFBvc3RzIHdvcmsgdG8gdGhlIHBvb2wuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGNoYXJ0IC0gQ2hhcnQncyBvcHRpb25zLlxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBBbGwgb3B0aW9ucyBvYmplY3QuXG4gKi9cbmV4cG9ydCBjb25zdCBwb3N0V29yayA9IGFzeW5jIChjaGFydCwgb3B0aW9ucykgPT4ge1xuICBsZXQgd29ya2VySGFuZGxlO1xuXG4gIC8vIEhhbmRsZSBmYWlsIGNvbmRpdGlvbnNcbiAgY29uc3QgZmFpbCA9IChtc2cpID0+IHtcbiAgICArK2Ryb3BwZWRFeHBvcnRzO1xuXG4gICAgaWYgKHdvcmtlckhhbmRsZSkge1xuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XG4gICAgfVxuXG4gICAgdGhyb3cgJ0luIHBvb2wucG9zdFdvcms6ICcgKyBtc2c7XG4gIH07XG5cbiAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcblxuICBpZiAocG9vbENvbmZpZy5iZW5jaG1hcmtpbmcpIHtcbiAgICBnZXRQb29sSW5mbygpO1xuICB9XG5cbiAgKytleHBvcnRBdHRlbXB0cztcblxuICBpZiAoIXBvb2wpIHtcbiAgICBsb2coMSwgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nKTtcbiAgICByZXR1cm4gZmFpbCgnUG9vbCBpcyBub3QgaW5pdGVkIGJ1dCB3b3JrIHdhcyBwb3N0ZWQgdG8gaXQhJyk7XG4gIH1cblxuICAvLyBBY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQgb2YgcmVzb3VyY2UgYW5kIHdvcmsgY291bnRcbiAgdHJ5IHtcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgd29ya2VyJyk7XG4gICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4gZmFpbChgW3Bvb2xdIEVycm9yIHdoZW4gYWNxdWlyaW5nIGF2YWlsYWJsZSBlbnRyeTogJHtlcnJvcn1gKTtcbiAgfVxuXG4gIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmVkIHdvcmtlciBoYW5kbGUnKTtcblxuICBpZiAoIXdvcmtlckhhbmRsZS5wYWdlKSB7XG4gICAgcmV0dXJuIGZhaWwoJ1Jlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHBvb2wgc2V0dXAgaXMgd29ua3knKTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxuICAgIGxldCB3b3JrU3RhcnQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcblxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XG5cbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHB1cHBldGVlckV4cG9ydCh3b3JrZXJIYW5kbGUucGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xuXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cbiAgICAgIGlmIChyZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpIHtcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBicm93c2VyTmV3UGFnZSgpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gZmFpbChyZXN1bHQpO1xuICAgIH1cblxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcblxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXG4gICAgY29uc3Qgd29ya0VuZCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xuICAgIHRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xuICAgIHNwZW50QXZlcmFnZSA9IHRpbWVTcGVudCAvICsrcGVyZm9ybWVkRXhwb3J0cztcblxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XG5cbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcbiAgICByZXR1cm4ge1xuICAgICAgZGF0YTogcmVzdWx0LFxuICAgICAgb3B0aW9uc1xuICAgIH07XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgZmFpbChgRXJyb3IgdHJ5aW5nIHRvIHBlcmZvcm0gcHVwcGV0ZWVyIGV4cG9ydDogJHtlcnJvcn0uYCk7XG4gIH1cbn07XG5cbi8qKlxuICogR2V0cyB0aGUgcG9vbC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XG4gIHJldHVybiBwb29sO1xufVxuXG5leHBvcnQgY29uc3QgZ2V0UG9vbEluZm9KU09OID0gKCkgPT4gKHtcbiAgbWluOiBwb29sLm1pbixcbiAgbWF4OiBwb29sLm1heCxcbiAgc2l6ZTogcG9vbC5zaXplLFxuICBhdmFpbGFibGU6IHBvb2wuYXZhaWxhYmxlLFxuICBib3Jyb3dlZDogcG9vbC5ib3Jyb3dlZCxcbiAgcGVuZGluZzogcG9vbC5wZW5kaW5nLFxuICBzcGFyZVJlc291cmNlQ2FwYWNpdHk6IHBvb2wuc3BhcmVSZXNvdXJjZUNhcGFjaXR5XG59KTtcblxuLyoqXG4gKiBHZXRzIHRoZSBwb29sJ3MgaW5mb3JtYXRpb24uXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcbiAgY29uc3Qge1xuICAgIG1pbixcbiAgICBtYXgsXG4gICAgc2l6ZSxcbiAgICBhdmFpbGFibGUsXG4gICAgYm9ycm93ZWQsXG4gICAgcGVuZGluZyxcbiAgICBzcGFyZVJlc291cmNlQ2FwYWNpdHlcbiAgfSA9IHBvb2w7XG5cbiAgbG9nKDQsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcbiAgbG9nKDQsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcbiAgbG9nKFxuICAgIDQsXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCByZXNvdXJjZXMgaW4gcG9vbCAoZnJlZSBvciBpbiB1c2UpOiAke3NpemV9LmBcbiAgKTtcbiAgbG9nKFxuICAgIDQsXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB0aGF0IGFyZSBjdXJyZW50bHkgYXZhaWxhYmxlOiAke2F2YWlsYWJsZX0uYFxuICApO1xuICBsb2coXG4gICAgNCxcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHRoYXQgYXJlIGN1cnJlbnRseSBhY3F1aXJlZDogJHtib3Jyb3dlZH0uYFxuICApO1xuICBsb2coXG4gICAgNCxcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgY2FsbGVycyB3YWl0aW5nIHRvIGFjcXVpcmUgYSByZXNvdXJjZTogJHtwZW5kaW5nfS5gXG4gICk7XG4gIGxvZyhcbiAgICA0LFxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiBob3cgbWFueSBtb3JlIHJlc291cmNlcyBjYW4gdGhlIHBvb2wgbWFuYWdlL2NyZWF0ZTogJHtzcGFyZVJlc291cmNlQ2FwYWNpdHl9LmBcbiAgKTtcbn1cblxuZXhwb3J0IGRlZmF1bHQge1xuICBpbml0LFxuICBraWxsUG9vbCxcbiAgcG9zdFdvcmssXG4gIGdldFBvb2wsXG4gIGdldFBvb2xJbmZvLFxuICBnZXRQb29sSW5mb0pTT04sXG4gIHdvcmtBdHRlbXB0czogKCkgPT4gZXhwb3J0QXR0ZW1wdHMsXG4gIGRyb3BwZWRXb3JrOiAoKSA9PiBkcm9wcGVkRXhwb3J0cyxcbiAgYXZlcmFnZVRpbWU6ICgpID0+IHNwZW50QXZlcmFnZSxcbiAgcHJvY2Vzc2VkV29ya0NvdW50OiAoKSA9PiBwZXJmb3JtZWRFeHBvcnRzXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDIzLCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCBjYWNoZSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XG5pbXBvcnQgcG9vbCBmcm9tICcuLi8uLi9wb29sLmpzJztcblxuY29uc3QgcGFja2FnZVZlcnNpb24gPSBwcm9jZXNzLmVudi5ucG1fcGFja2FnZV92ZXJzaW9uO1xuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcblxuLyoqXG4gKiBBZGRzIHRoZSAvaGVhbHRoIHJvdXRlIHdoaWNoIG91dHB1dHMgYmFzaWMgc3RhdHMgZm9yIHRoZSBzZXJ2ZXJcbiAqL1xuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cbiAgIWFwcFxuICAgID8gZmFsc2VcbiAgICA6IGFwcC5nZXQoJy9oZWFsdGgnLCAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcbiAgICAgICAgcmVzcG9uc2Uuc2VuZCh7XG4gICAgICAgICAgc3RhdHVzOiAnT0snLFxuICAgICAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXG4gICAgICAgICAgdXB0aW1lOlxuICAgICAgICAgICAgTWF0aC5mbG9vcihcbiAgICAgICAgICAgICAgKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjBcbiAgICAgICAgICAgICkgKyAnIG1pbnV0ZXMnLFxuICAgICAgICAgIHZlcnNpb246IHBhY2thZ2VWZXJzaW9uLFxuICAgICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBjYWNoZS52ZXJzaW9uKCksXG4gICAgICAgICAgYXZlcmFnZVByb2Nlc3NpbmdUaW1lOiBwb29sLmF2ZXJhZ2VUaW1lKCksXG4gICAgICAgICAgcGVyZm9ybWVkRXhwb3J0czogcG9vbC5wcm9jZXNzZWRXb3JrQ291bnQoKSxcbiAgICAgICAgICBmYWlsZWRFeHBvcnRzOiBwb29sLmRyb3BwZWRXb3JrKCksXG4gICAgICAgICAgZXhwb3J0QXR0ZW1wdHM6IHBvb2wud29ya0F0dGVtcHRzKCksXG4gICAgICAgICAgc3VjZXNzUmF0aW86IChwb29sLnByb2Nlc3NlZFdvcmtDb3VudCgpIC8gcG9vbC53b3JrQXR0ZW1wdHMoKSkgKiAxMDAsXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxuICAgICAgICAgIHBvb2w6IHBvb2wuZ2V0UG9vbEluZm9KU09OKClcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBleGlzdHNTeW5jLCByZWFkRmlsZVN5bmMsIHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XG5cbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xuXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xuaW1wb3J0IHtcbiAgYWJzb2x1dGVQcm9wcyxcbiAgZGVmYXVsdENvbmZpZyxcbiAgbmVzdGVkQXJncyxcbiAgcHJvbXB0c0NvbmZpZ1xufSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcblxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XG5cbi8qKlxuICogR2V0dGVyIGZvciB0aGUgZ2VuZXJhbCBvcHRpb25zLlxuICpcbiAqIEByZXR1cm4ge29iamVjdH0gLSBHZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxuICovXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xuXG4vKipcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZS5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gdXNlck9wdGlvbnMgLSBBZGRpdGlvbmFsIHVzZXIgb3B0aW9ucyAoZS5nLiBmcm9tIHRoZSBub2RlXG4gKiBtb2R1bGUgdXNhZ2UpLlxuICogQHBhcmFtIHtzdHJpbmdbXX0gYXJncyAtIENMSSBhcmd1bWVudHMuXG4gKiBAcmV0dXJuIHtvYmplY3R9IC0gR2VuZXJhbCBvcHRpb25zIG9iamVjdC5cbiAqL1xuZXhwb3J0IGNvbnN0IHNldE9wdGlvbnMgPSAodXNlck9wdGlvbnMsIGFyZ3MpID0+IHtcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XG4gICAgLy8gR2V0IHRoZSBhZGRpdGlvbmFsIG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gZmlsZVxuICAgIGdlbmVyYWxPcHRpb25zID0gbG9hZENvbmZpZ0ZpbGUoYXJncyk7XG4gIH1cblxuICAvLyBVcGRhdGUgdGhlIGRlZmF1bHQgY29uZmlnIHdpdGggYSBjb3JyZWN0IG9wdGlvbiB2YWx1ZXNcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XG5cbiAgLy8gU2V0IHZhbHVlcyBmb3Igc2VydmVyJ3Mgb3B0aW9ucyBhbmQgcmV0dXJucyB0aGVtXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XG5cbiAgLy8gQXBwbHkgdXNlciBvcHRpb25zIGlmIHRoZXJlIGFyZSBhbnlcbiAgaWYgKHVzZXJPcHRpb25zKSB7XG4gICAgLy8gTWVyZ2UgdXNlciBvcHRpb25zXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcbiAgICAgIHVzZXJPcHRpb25zLFxuICAgICAgYWJzb2x1dGVQcm9wc1xuICAgICk7XG4gIH1cblxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcbiAgICAvLyBQYWlyIHByb3ZpZGVkIGFyZ3VtZW50c1xuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xuICB9XG5cbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xuICByZXR1cm4gZ2VuZXJhbE9wdGlvbnM7XG59O1xuXG4vKipcbiAqIERpc3BsYXlzIGEgcHJvbXB0IGZvciB0aGUgbWFudWFsIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgYSBjb25maWd1cmF0aW9uIGZpbGUuXG4gKi9cbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcbiAgLy8gUHJlcGFyZSBhIGNvbmZpZyBvYmplY3RcbiAgbGV0IGNvbmZpZ0ZpbGUgPSB7fTtcblxuICAvLyBDaGVjayBpZiBwcm92aWRlZCBjb25maWcgZmlsZSBleGlzdHNcbiAgaWYgKGV4aXN0c1N5bmMoY29uZmlnRmlsZU5hbWUpKSB7XG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcbiAgfVxuXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxuICBjb25zdCBvblN1Ym1pdCA9IGFzeW5jIChwLCBjYXRlZ29yaWVzKSA9PiB7XG4gICAgbGV0IHF1ZXN0aW9uc0NvdW50ZXIgPSAwO1xuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcblxuICAgIC8vIENyZWF0ZSBhIGNvcnJlc3BvbmRpbmcgcHJvcGVydHkgaW4gdGhlIG1hbnVhbENvbmZpZyBvYmplY3RcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xuICAgICAgLy8gTWFyayBlYWNoIG9wdGlvbiB3aXRoIGEgc2VjdGlvblxuICAgICAgcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXSA9IHByb21wdHNDb25maWdbc2VjdGlvbl0ubWFwKChvcHRpb24pID0+ICh7XG4gICAgICAgIC4uLm9wdGlvbixcbiAgICAgICAgc2VjdGlvblxuICAgICAgfSkpO1xuXG4gICAgICAvLyBDb2xsZWN0IHRoZSBxdWVzdGlvbnNcbiAgICAgIGFsbFF1ZXN0aW9ucyA9IFsuLi5hbGxRdWVzdGlvbnMsIC4uLnByb21wdHNDb25maWdbc2VjdGlvbl1dO1xuICAgIH1cblxuICAgIGF3YWl0IHByb21wdHMoYWxsUXVlc3Rpb25zLCB7XG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XG4gICAgICAgIC8vIEdldCB0aGUgZGVmYXVsdCBtb2R1bGVzXG4gICAgICAgIGlmIChwcm9tcHQubmFtZSA9PT0gJ21vZHVsZXMnKSB7XG4gICAgICAgICAgYW5zd2VyID0gYW5zd2VyLmxlbmd0aFxuICAgICAgICAgICAgPyBhbnN3ZXIubWFwKChtb2R1bGUpID0+IHByb21wdC5jaG9pY2VzW21vZHVsZV0pXG4gICAgICAgICAgICA6IHByb21wdC5jaG9pY2VzO1xuXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl1bcHJvbXB0Lm5hbWVdID0gYW5zd2VyO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dID0gcmVjdXJzaXZlUHJvcHMoXG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKHt9LCBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSB8fCB7fSksXG4gICAgICAgICAgICBwcm9tcHQubmFtZS5zcGxpdCgnLicpLFxuICAgICAgICAgICAgYW5zd2VyXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgrK3F1ZXN0aW9uc0NvdW50ZXIgPT09IGFsbFF1ZXN0aW9ucy5sZW5ndGgpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgZnNQcm9taXNlcy53cml0ZUZpbGUoXG4gICAgICAgICAgICAgIGNvbmZpZ0ZpbGVOYW1lLFxuICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShjb25maWdGaWxlLCBudWxsLCAyKSxcbiAgICAgICAgICAgICAgJ3V0ZjgnXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICBsb2coMSwgYFtjb25maWddIEVycm9yIHdoaWxlIGNyZWF0aW5nIGNvbmZpZy5qc29uOiAke2Vycm9yfWApO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgLy8gRmluZCB0aGUgY2F0ZWdvcmllc1xuICBjb25zdCBjaG9pY2VzID0gT2JqZWN0LmtleXMocHJvbXB0c0NvbmZpZykubWFwKChjaG9pY2UpID0+ICh7XG4gICAgdGl0bGU6IGAke2Nob2ljZX0gb3B0aW9uc2AsXG4gICAgdmFsdWU6IGNob2ljZVxuICB9KSk7XG5cbiAgLy8gQ2F0ZWdvcnkgcHJvbXB0XG4gIHJldHVybiBwcm9tcHRzKFxuICAgIHtcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXG4gICAgICBuYW1lOiAnY2F0ZWdvcnknLFxuICAgICAgbWVzc2FnZTogJ1doaWNoIGNhdGVnb3J5IGRvIHlvdSB3YW50IHRvIGNvbmZpZ3VyZT8nLFxuICAgICAgaGludDogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXG4gICAgICBpbnN0cnVjdGlvbnM6ICcnLFxuICAgICAgY2hvaWNlc1xuICAgIH0sXG4gICAgeyBvblN1Ym1pdCB9XG4gICk7XG59O1xuXG4vKipcbiAqIE1hcHMgdGhlIG9sZCBvcHRpb25zIHRvIHRoZSBuZXcgY29uZmlnIHN0cnVjdHVyZS5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gb2xkT3B0aW9ucyAtIE9wdGlvbnMgdG8gYmUgbWFwcGVkLlxuICovXG5leHBvcnQgY29uc3QgbWFwVG9OZXdDb25maWcgPSAob2xkT3B0aW9ucykgPT4ge1xuICBjb25zdCBuZXdPcHRpb25zID0ge307XG4gIC8vIEN5Y2xlIHRocm91Z2ggb2xkLXN0cnVjdHVyZWQgb3B0aW9uc1xuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nba2V5XSA/IG5lc3RlZEFyZ3Nba2V5XS5zcGxpdCgnLicpIDogW107XG5cbiAgICAvLyBQb3B1bGF0ZSBvYmplY3QgaW4gY29ycmVjdCBwcm9wZXJ0aWVzIGxldmVsc1xuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXG4gICAgICAob2JqLCBwcm9wLCBpbmRleCkgPT5cbiAgICAgICAgKG9ialtwcm9wXSA9XG4gICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxuICAgICAgbmV3T3B0aW9uc1xuICAgICk7XG4gIH1cbiAgcmV0dXJuIG5ld09wdGlvbnM7XG59O1xuXG4vKipcbiAqIE1lcmdlcyB0aGUgbmV3IG9wdGlvbnMgdG8gdGhlIG9wdGlvbnMgb2JqZWN0LiBJdCBvbWl0cyB1bmRlZmluZWQgdmFsdWVzLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gT2xkIG9wdGlvbnMuXG4gKiBAcGFyYW0ge29iamVjdH0gbmV3T3B0aW9ucyAtIE5ldyBvcHRpb25zLlxuICogQHBhcmFtIHtzdHJpbmdbXX0gYWJzb2x1dGVQcm9wcyAtIEFycmF5IG9mIG9iamVjdCBuYW1lcyB0aGF0IHNob3VsZCBiZSBmb3JjZVxuICogbWVyZ2VkLlxuICovXG5leHBvcnQgY29uc3QgbWVyZ2VDb25maWdPcHRpb25zID0gKG9wdGlvbnMsIG5ld09wdGlvbnMsIGFic29sdXRlUHJvcHMgPSBbXSkgPT4ge1xuICBjb25zdCBtZXJnZWRPcHRpb25zID0gZGVlcENvcHkob3B0aW9ucyk7XG5cbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcbiAgICBtZXJnZWRPcHRpb25zW2tleV0gPVxuICAgICAgaXNPYmplY3QodmFsdWUpICYmXG4gICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXG4gICAgICBtZXJnZWRPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxuICAgICAgICA/IG1lcmdlQ29uZmlnT3B0aW9ucyhtZXJnZWRPcHRpb25zW2tleV0sIHZhbHVlLCBhYnNvbHV0ZVByb3BzKVxuICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcbiAgICAgICAgPyB2YWx1ZVxuICAgICAgICA6IG1lcmdlZE9wdGlvbnNba2V5XTtcbiAgfVxuXG4gIHJldHVybiBtZXJnZWRPcHRpb25zO1xufTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIGZvciB0aGUgYHN0YXJ0RXhwb3J0YCBtZXRob2QgYnkgbWVyZ2luZyB1c2VyIG9wdGlvbnNcbiAqIHdpdGggdGhlIGdlbmVyYWwgb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge2FueX0gZXhwb3J0T3B0aW9ucyAtIFVzZXIgb3B0aW9ucyBmb3IgZXhwb3J0aW5nLlxuICogQHBhcmFtIHthbnl9IGdlbmVyYWxPcHRpb25zIC0gR2VuZXJhbCBvcHRpb25zIGFyZSB1c2VkIGZvciB0aGUgZXhwb3J0IHNlcnZlci5cbiAqIEByZXR1cm4ge29iamVjdH0gLSBVc2VyIG9wdGlvbnMgbWVyZ2VkIHdpdGggZGVmYXVsdCBvcHRpb25zLlxuICovXG5leHBvcnQgY29uc3QgaW5pdEV4cG9ydFNldHRpbmdzID0gKGV4cG9ydE9wdGlvbnMsIGdlbmVyYWxPcHRpb25zID0ge30pID0+IHtcbiAgbGV0IG9wdGlvbnMgPSB7fTtcblxuICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcbiAgICBvcHRpb25zID0gZGVlcENvcHkoZ2VuZXJhbE9wdGlvbnMpO1xuICAgIG9wdGlvbnMuZXhwb3J0LnR5cGUgPSBleHBvcnRPcHRpb25zLnR5cGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQudHlwZTtcbiAgICBvcHRpb25zLmV4cG9ydC5zY2FsZSA9IGV4cG9ydE9wdGlvbnMuc2NhbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQuc2NhbGU7XG4gICAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XG4gICAgICBleHBvcnRPcHRpb25zLm91dGZpbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQub3V0ZmlsZTtcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XG4gICAgICBzdmc6IGV4cG9ydE9wdGlvbnMuc3ZnXG4gICAgfTtcbiAgfSBlbHNlIHtcbiAgICBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXG4gICAgICBleHBvcnRPcHRpb25zLFxuICAgICAgLy8gT21pdCBnb2luZyBkb3duIHJlY3Vyc2l2ZWx5IHdpdGggdGhlIGJlbG93c1xuICAgICAgYWJzb2x1dGVQcm9wc1xuICAgICk7XG4gIH1cblxuICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cbiAgICBvcHRpb25zLmV4cG9ydD8ub3V0ZmlsZSB8fCBgY2hhcnQuJHtvcHRpb25zLmV4cG9ydD8udHlwZSB8fCAncG5nJ31gO1xuICByZXR1cm4gb3B0aW9ucztcbn07XG5cbi8qKlxuICogTG9hZHMgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSBhIGN1c3RvbSBKU09OIGZpbGUuXG4gKlxuICogQHBhcmFtIHtzdHJpbmdbXX0gYXJncyAtIENMSSBhcmd1bWVudHMuXG4gKiBAcmV0dXJuIHtvYmplY3R9IC0gT3B0aW9ucyBvYmplY3QgZnJvbSB0aGUgSlNPTiBmaWxlLlxuICovXG5mdW5jdGlvbiBsb2FkQ29uZmlnRmlsZShhcmdzKSB7XG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uIHdhcyB1c2VkXG4gIGNvbnN0IGNvbmZpZ0luZGV4ID0gYXJncy5maW5kSW5kZXgoXG4gICAgKGFyZykgPT4gYXJnLnJlcGxhY2UoLy0vZywgJycpID09PSAnbG9hZENvbmZpZydcbiAgKTtcblxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIGhhcyBhIHZhbHVlXG4gIGlmIChjb25maWdJbmRleCA+IC0xICYmIGFyZ3NbY29uZmlnSW5kZXggKyAxXSkge1xuICAgIGNvbnN0IGZpbGVOYW1lID0gYXJnc1tjb25maWdJbmRleCArIDFdO1xuICAgIHRyeSB7XG4gICAgICAvLyBDaGVjayBpZiBhbiBhZGRpdGlvbmFsIGNvbmZpZyBmaWxlIGlzIGEgY29ycmVjdCBKU09OIGZpbGVcbiAgICAgIGlmIChmaWxlTmFtZSAmJiBmaWxlTmFtZS5lbmRzV2l0aCgnLmpzb24nKSkge1xuICAgICAgICAvLyBMb2FkIGFuIG9wdGlvbmFsIGN1c3RvbSBKU09OIGNvbmZpZyBmaWxlXG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhmaWxlTmFtZSkpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2coMSwgYFtjb25maWddIFVuYWJsZSB0byBsb2FkIGNvbmZpZyBmcm9tIHRoZSAke2ZpbGVOYW1lfTogJHtlcnJvcn1gKTtcbiAgICB9XG4gIH1cblxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXG4gIHJldHVybiB7fTtcbn1cblxuLyoqXG4gKiBTZXR0aW5nIGNvcnJlY3QgdmFsdWVzIG9mIHRoZSBvcHRpb25zIGZyb20gdGhlIGRlZmF1bHQgY29uZmlnLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25maWdPYmogLSBUaGUgY29uZmlnIG9iamVjdCBiYXNlZCBvbiB3aGljaCB0aGUgaW5pdGlhbFxuICogY29uZmlndXJhdGlvbiBiZSBtYWRlLlxuICogQHBhcmFtIHtvYmplY3R9IGN1c3RvbU9iaiAtIFRoZSBjdXN0b20gb2JqZWN0IHdoaWNoIGNhbiBjb250YWluIGFkZGl0aW9uYWxcbiAqIG9wdGlvbiB2YWx1ZXMgdG8gc2V0LlxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFJlcXVpcmVkIGZvciBjcmVhdGluZyBhIHN0cmluZyBjaGFpbiBvZlxuICogcHJvcGVydGllcyBmb3IgbmVzdGVkIGFyZ3VtZW50cy5cbiAqL1xuZnVuY3Rpb24gdXBkYXRlRGVmYXVsdENvbmZpZyhjb25maWdPYmosIGN1c3RvbU9iaiA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xuICBPYmplY3Qua2V5cyhjb25maWdPYmopLmZvckVhY2goKGtleSkgPT4ge1xuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGtleSkpIHtcbiAgICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnT2JqW2tleV07XG4gICAgICBjb25zdCBjdXN0b21WYWx1ZSA9IGN1c3RvbU9iaiAmJiBjdXN0b21PYmpba2V5XTtcbiAgICAgIGxldCBudW1FbnZWYWw7XG5cbiAgICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcbiAgICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGFuIGVudiB2YXJpYWJsZSBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxuICAgICAgICBpZiAoZW50cnkuZW52TGluaykge1xuICAgICAgICAgIC8vIExvYWQgdGhlIGVudiB2YXJcbiAgICAgICAgICBpZiAoZW50cnkudHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XG4gICAgICAgICAgICBlbnRyeS52YWx1ZSA9IHRvQm9vbGVhbihcbiAgICAgICAgICAgICAgW3Byb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdLCBlbnRyeS52YWx1ZV0uZmluZChcbiAgICAgICAgICAgICAgICAoZWwpID0+IGVsIHx8IGVsID09PSAnZmFsc2UnXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBlbHNlIGlmIChlbnRyeS50eXBlID09PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgbnVtRW52VmFsID0gK3Byb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdO1xuICAgICAgICAgICAgZW50cnkudmFsdWUgPSBudW1FbnZWYWwgPj0gMCA/IG51bUVudlZhbCA6IGVudHJ5LnZhbHVlO1xuICAgICAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgICAgICBlbnRyeS50eXBlLmluZGV4T2YoJ10nKSA+PSAwICYmXG4gICAgICAgICAgICBwcm9jZXNzLmVudltlbnRyeS5lbnZMaW5rXVxuICAgICAgICAgICkge1xuICAgICAgICAgICAgZW50cnkudmFsdWUgPSBwcm9jZXNzLmVudltlbnRyeS5lbnZMaW5rXS5zcGxpdCgnLCcpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBlbnRyeS52YWx1ZSA9IHByb2Nlc3MuZW52W2VudHJ5LmVudkxpbmtdIHx8IGVudHJ5LnZhbHVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogSW5pdHMgb3B0aW9ucyByZWN1cnNpdmVseS5cbiAqXG4gKiBAcGFyYW0ge2FueX0gaXRlbXMgLSBJdGVtcyB0byB1cGRhdGUgb3B0aW9ucyBmcm9tLlxuICogQHJldHVybiB7b2JqZWN0fSAtIFVwZGF0ZWQgb3B0aW9ucyBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIGluaXRPcHRpb25zKGl0ZW1zKSB7XG4gIGxldCBvcHRpb25zID0ge307XG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGl0ZW1zKSkge1xuICAgIG9wdGlvbnNbbmFtZV0gPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoaXRlbSwgJ3ZhbHVlJylcbiAgICAgID8gaXRlbS52YWx1ZVxuICAgICAgOiBpbml0T3B0aW9ucyhpdGVtKTtcbiAgfVxuICByZXR1cm4gb3B0aW9ucztcbn1cblxuLyoqXG4gKiBQYWlycyBhcmd1bWVudCB3aXRoIGEgY29ycmVzcG9uZGluZyB2YWx1ZS5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIEFsbCBzZXJ2ZXIgb3B0aW9ucy5cbiAqIEBwYXJhbSB7c3RyaW5nW119IGFyZ3MgLSBBcnJheSBvZiBhcmd1bWVudHMgZnJvbSBhIHVzZXIuXG4gKiBAcGFyYW0ge29iamVjdH0gZGVmYXVsdENvbmZpZyAtIFRoZSBkZWZhdWx0IGNvbmZpZyBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIHBhaXJBcmd1bWVudFZhbHVlKG9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpIHtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XG4gICAgbGV0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XG5cbiAgICAvLyBGaW5kIHRoZSByaWdodCBwbGFjZSBmb3IgcHJvcGVydHkncyB2YWx1ZVxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxuICAgICAgPyBuZXN0ZWRBcmdzW29wdGlvbl0uc3BsaXQoJy4nKVxuICAgICAgOiBbXTtcblxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcbiAgICAgICAgLy8gRmluZHMgYW4gb3B0aW9uIGFuZCBzZXQgYSBjb3JyZXNwb25kaW5nIHZhbHVlXG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcbiAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV0gfHwgb2JqW3Byb3BdO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhgTWlzc2luZyBhcmd1bWVudCB2YWx1ZSBmb3IgJHtvcHRpb259IWAucmVkLCAnXFxuJyk7XG4gICAgICAgICAgICBvcHRpb25zID0gcHJpbnRVc2FnZShkZWZhdWx0Q29uZmlnKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBvYmpbcHJvcF07XG4gICAgfSwgb3B0aW9ucyk7XG4gIH1cblxuICByZXR1cm4gb3B0aW9ucztcbn1cblxuLyoqXG4gKiBSZWN1cnNpdmVseSBzZXRzIGEgcHJvcGVydHkgaW4gYSBjb3JyZWN0IGluZGVudGF0aW9uIGxldmVsIGJhc2VkIG9uIHRoZVxuICogYXJyYXkgb2YgbmVzdGVkIHByb3BlcnRpZXMgbmFtZXMuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IG9iamVjdFRvVXBkYXRlIC0gT2JqZWN0IHdoZXJlIGEgcHJvcGVydHkgbXVzdCBiZSBzZXQgb24gYVxuICogY29ycmVjdCBsZXZlbC5cbiAqIEBwYXJhbSAge3N0cmluZ1tdfW5lc3RlZE5hbWVzIC0gQXJyYXkgb2YgbmFzdGVkIG5hbWVzIHRoYXQgaW5kaWNhdGVzXG4gKiBpbmRlbnRhdGlvbiBsZXZlbC5cbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIEEgdmFsdWUgdG8gYXNzaWduIHRvIHRoZSBwcm9wZXJ0eS5cbiAqIEByZXR1cm4ge29iamVjdH0gLSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxuICovXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XG4gIHdoaWxlIChuZXN0ZWROYW1lcy5sZW5ndGggPiAxKSB7XG4gICAgY29uc3QgcHJvcE5hbWUgPSBuZXN0ZWROYW1lcy5zaGlmdCgpO1xuXG4gICAgLy8gQ3JlYXRlIGEgcHJvcGVydHkgaW4gb2JqZWN0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcbiAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3RUb1VwZGF0ZSwgcHJvcE5hbWUpKSB7XG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcbiAgICB9XG5cbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXG4gICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0gcmVjdXJzaXZlUHJvcHMoXG4gICAgICBPYmplY3QuYXNzaWduKHt9LCBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0pLFxuICAgICAgbmVzdGVkTmFtZXMsXG4gICAgICB2YWx1ZVxuICAgICk7XG5cbiAgICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XG4gIH1cblxuICAvLyBBc3NpZ24gdGhlIGZpbmFsIHZhbHVlXG4gIG9iamVjdFRvVXBkYXRlW25lc3RlZE5hbWVzWzBdXSA9IHZhbHVlO1xuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XG59XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZ2V0T3B0aW9ucyxcbiAgc2V0T3B0aW9ucyxcbiAgbWFudWFsQ29uZmlnLFxuICBtYXBUb05ld0NvbmZpZyxcbiAgbWVyZ2VDb25maWdPcHRpb25zLFxuICBpbml0RXhwb3J0U2V0dGluZ3Ncbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgcmVhZEZpbGUsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcblxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsga2lsbFBvb2wsIHBvc3RXb3JrIH0gZnJvbSAnLi9wb29sLmpzJztcbmltcG9ydCB7XG4gIGNsZWFyVGV4dCxcbiAgZml4VHlwZSxcbiAgaGFuZGxlUmVzb3VyY2VzLFxuICBpc0NvcnJlY3RKU09OLFxuICBvcHRpb25zU3RyaW5naWZ5LFxuICByb3VuZE51bWJlcixcbiAgdG9Cb29sZWFuLFxuICB3cmFwQXJvdW5kXG59IGZyb20gJy4vdXRpbHMuanMnO1xuaW1wb3J0IHsgaW5pdEV4cG9ydFNldHRpbmdzLCBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xuXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XG5cbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcbiAgLy8gU3RhcnRpbmcgZXhwb3J0aW5nIHByb2Nlc3MgbWVzc2FnZVxuICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XG5cbiAgLy8gSW5pdGlhbGl6ZSBvcHRpb25zXG4gIGNvbnN0IG9wdGlvbnMgPSBpbml0RXhwb3J0U2V0dGluZ3Moc2V0dGluZ3MsIGdldE9wdGlvbnMoKSk7XG5cbiAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xuICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XG5cbiAgLy8gSWYgU1ZHIGlzIGFuIGlucHV0IChhcmd1bWVudCBjYW4gYmUgc2VudCBvbmx5IGJ5IHRoZSByZXF1ZXN0KVxuICBpZiAob3B0aW9ucy5wYXlsb2FkPy5zdmcgJiYgb3B0aW9ucy5wYXlsb2FkLnN2ZyAhPT0gJycpIHtcbiAgICByZXR1cm4gZXhwb3J0QXNTdHJpbmcob3B0aW9ucy5wYXlsb2FkLnN2Zy50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcbiAgfVxuXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcbiAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICYmIGV4cG9ydE9wdGlvbnMuaW5maWxlLmxlbmd0aCkge1xuICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIGlucHV0IGZpbGUuJyk7XG5cbiAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZVxuICAgIHJldHVybiByZWFkRmlsZShleHBvcnRPcHRpb25zLmluZmlsZSwgJ3V0ZjgnLCAoZXJyb3IsIGluZmlsZSkgPT4ge1xuICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgIHJldHVybiBsb2coMSwgYFtjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlOiAke2Vycm9yfS5gKTtcbiAgICAgIH1cblxuICAgICAgLy8gR2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cbiAgICAgIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gaW5maWxlO1xuICAgICAgcmV0dXJuIGV4cG9ydEFzU3RyaW5nKG9wdGlvbnMuZXhwb3J0Lmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gRXhwb3J0IHdpdGggb3B0aW9ucyBmcm9tIHRoZSByYXcgcmVwcmVzZW50YXRpb25cbiAgaWYgKFxuICAgIChleHBvcnRPcHRpb25zLmluc3RyICYmIGV4cG9ydE9wdGlvbnMuaW5zdHIgIT09ICcnKSB8fFxuICAgIChleHBvcnRPcHRpb25zLm9wdGlvbnMgJiYgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSAnJylcbiAgKSB7XG4gICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSByYXcgaW5wdXQuJyk7XG5cbiAgICAvLyBQZXJmb3JtIGEgZGlyZWN0IGluamVjdCB3aGVuIGZvcmNlZFxuICAgIGlmICh0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Db2RlPy5hbGxvd0NvZGVFeGVjdXRpb24pKSB7XG4gICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XG4gICAgfVxuXG4gICAgLy8gRWl0aGVyIHRyeSB0byBwYXJzZSB0byBKU09OIGZpcnN0IG9yIGRvIHRoZSBkaXJlY3QgZXhwb3J0XG4gICAgcmV0dXJuIHR5cGVvZiBleHBvcnRPcHRpb25zLmluc3RyID09PSAnc3RyaW5nJ1xuICAgICAgPyBleHBvcnRBc1N0cmluZyhleHBvcnRPcHRpb25zLmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spXG4gICAgICA6IGRvRXhwb3J0KFxuICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMsXG4gICAgICAgICAgZW5kQ2FsbGJhY2tcbiAgICAgICAgKTtcbiAgfVxuXG4gIC8vIE5vIGlucHV0IHNwZWNpZmllZCwgcGFzcyBhbiBlcnJvciBtZXNzYWdlIHRvIHRoZSBjYWxsYmFja1xuICBsb2coXG4gICAgMSxcbiAgICBjbGVhclRleHQoXG4gICAgICBgW2NoYXJ0XSBObyBpbnB1dCBzcGVjaWZpZWQuXG4gICAgICAke0pTT04uc3RyaW5naWZ5KGV4cG9ydE9wdGlvbnMsIHVuZGVmaW5lZCwgJyAgJyl9LmBcbiAgICApXG4gICk7XG5cbiAgcmV0dXJuIChcbiAgICBlbmRDYWxsYmFjayAmJlxuICAgIGVuZENhbGxiYWNrKGZhbHNlLCB7XG4gICAgICBlcnJvcjogdHJ1ZSxcbiAgICAgIG1lc3NhZ2U6ICdObyBpbnB1dCBzcGVjaWZpZWQuJ1xuICAgIH0pXG4gICk7XG59O1xuXG5leHBvcnQgY29uc3QgYmF0Y2hFeHBvcnQgPSAob3B0aW9ucykgPT4ge1xuICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xuXG4gIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSAtLWJhdGNoIGFyZ3VtZW50c1xuICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykpIHtcbiAgICBwYWlyID0gcGFpci5zcGxpdCgnPScpO1xuICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xuICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcbiAgICAgICAgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgIHN0YXJ0RXhwb3J0KFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICAgICAgICBleHBvcnQ6IHtcbiAgICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcbiAgICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXG4gICAgICAgICAgICAgICAgb3V0ZmlsZTogcGFpclsxXVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgKGluZm8sIGVycm9yKSA9PiB7XG4gICAgICAgICAgICAgIC8vIFRocm93IGFuIGVycm9yXG4gICAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICAgIHJldHVybiByZWplY3QoZXJyb3IpO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcbiAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcbiAgICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0Lm91dGZpbGUsXG4gICAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5kYXRhLCAnYmFzZTY0JylcbiAgICAgICAgICAgICAgKTtcblxuICAgICAgICAgICAgICByZXNvbHZlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgKTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gS2lsbCB0aGUgcG9vbCBhZnRlciBhbGwgZXhwb3J0cyBhcmUgZG9uZVxuICBQcm9taXNlLmFsbChiYXRjaEZ1bmN0aW9ucylcbiAgICAudGhlbigoKSA9PiB7XG4gICAgICBraWxsUG9vbCgpO1xuICAgIH0pXG4gICAgLmNhdGNoKChlcnJvcikgPT4ge1xuICAgICAgbG9nKDEsIGBbY2hhcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBiYXRjaCBleHBvcnQ6ICR7ZXJyb3J9YCk7XG4gICAgICBraWxsUG9vbCgpO1xuICAgIH0pO1xufTtcblxuZXhwb3J0IGNvbnN0IHNpbmdsZUV4cG9ydCA9IChvcHRpb25zKSA9PiB7XG4gIC8vIFVzZSBpbnN0ciBvciBpdHMgYWxpYXMsIG9wdGlvbnNcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xuXG4gIC8vIFBlcmZvcm0gYW4gZXhwb3J0XG4gIHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChpbmZvLCBlcnJvcikgPT4ge1xuICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yXG4gICAgaWYgKGVycm9yKSB7XG4gICAgICBsb2coMSwgYFtjbGldICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgICAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgICB9XG5cbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XG5cbiAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxuICAgIHdyaXRlRmlsZVN5bmMoXG4gICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcbiAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oaW5mby5kYXRhLCAnYmFzZTY0JykgOiBpbmZvLmRhdGFcbiAgICApO1xuXG4gICAgLy8gS2lsbCB0aGUgcG9vbFxuICAgIGtpbGxQb29sKCk7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBGdW5jdGlvbiBmb3IgY2hvb3NpbmcgY2hhcnQgc2l6ZSBhbmQgc2NhbGUgYmFzZWQgb24gb3B0aW9ucyBwcmlvcml0aXphdGlvbi5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIEFsbCBvcHRpb25zIG9iamVjdC5cbiAqIEByZXR1cm4ge29iamVjdH0gLSBBbiBvYmplY3Qgd2l0aCB1cGRhdGVkIHNpemUgYW5kIHNjYWxlIGZvciBhIGNoYXJ0LlxuICovXG5leHBvcnQgY29uc3QgZmluZENoYXJ0U2l6ZSA9IChvcHRpb25zKSA9PiB7XG4gIGNvbnN0IHsgY2hhcnQsIGV4cG9ydGluZyB9ID1cbiAgICBvcHRpb25zLmV4cG9ydD8ub3B0aW9ucyB8fCBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5pbnN0cik7XG5cbiAgLy8gU2VlIGlmIGdsb2JhbE9wdGlvbnMgaG9sZHMgY2hhcnQgb3IgZXhwb3J0aW5nIHNpemVcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmdsb2JhbE9wdGlvbnMpO1xuXG4gIC8vIFNlY3VyZSBzY2FsZSB2YWx1ZVxuICBsZXQgc2NhbGUgPVxuICAgIG9wdGlvbnMuZXhwb3J0Py5zY2FsZSB8fFxuICAgIGV4cG9ydGluZz8uc2NhbGUgfHxcbiAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNjYWxlIHx8XG4gICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRTY2FsZSB8fFxuICAgIDE7XG5cbiAgLy8gdGhlIHNjYWxlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMSBhbmQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxuICBzY2FsZSA9IE1hdGgubWF4KDAuMSwgTWF0aC5taW4oc2NhbGUsIDUuMCkpO1xuXG4gIC8vIHdlIHdhbnQgdG8gcm91bmQgdGhlIG51bWJlcnMgbGlrZSAwLjIzMjM0IC0+IDAuMjNcbiAgc2NhbGUgPSByb3VuZE51bWJlcihzY2FsZSwgMik7XG5cbiAgLy8gRmluZCBjaGFydCBzaXplIGFuZCBzY2FsZVxuICByZXR1cm4ge1xuICAgIGhlaWdodDpcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5oZWlnaHQgfHxcbiAgICAgIGV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XG4gICAgICBjaGFydD8uaGVpZ2h0IHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxuICAgICAgZ2xvYmFsT3B0aW9ucz8uY2hhcnQ/LmhlaWdodCB8fFxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRIZWlnaHQgfHxcbiAgICAgIDQwMCxcbiAgICB3aWR0aDpcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py53aWR0aCB8fFxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxuICAgICAgY2hhcnQ/LndpZHRoIHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8ud2lkdGggfHxcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0V2lkdGggfHxcbiAgICAgIDYwMCxcbiAgICBzY2FsZVxuICB9O1xufTtcblxuLyoqXG4gKiBGdW5jdGlvbiBmb3IgZmluYWwgb3B0aW9ucyBwcmVwYXJhdGlvbiBiZWZvcmUgZXhwb3J0LlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgb2JqZWN0LlxuICogQHBhcmFtIHtvYmplY3R9IGNoYXJ0SnNvbiAtIENoYXJ0IEpTT04uXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBlbmQgY2FsbGJhY2suXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyByZXByZXNlbnRhdGlvbi5cbiAqL1xuY29uc3QgZG9FeHBvcnQgPSAob3B0aW9ucywgY2hhcnRKc29uLCBlbmRDYWxsYmFjaywgc3ZnKSA9PiB7XG4gIGxldCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tQ29kZTogY3VzdG9tQ29kZU9wdGlvbnMgfSA9IG9wdGlvbnM7XG5cbiAgY29uc3QgYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkID1cbiAgICB0eXBlb2YgY3VzdG9tQ29kZU9wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uID09PSAnYm9vbGVhbidcbiAgICAgID8gY3VzdG9tQ29kZU9wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcblxuICBpZiAoIWN1c3RvbUNvZGVPcHRpb25zKSB7XG4gICAgY3VzdG9tQ29kZU9wdGlvbnMgPSBvcHRpb25zLmN1c3RvbUNvZGUgPSB7fTtcbiAgfSBlbHNlIGlmICh0eXBlb2Ygb3B0aW9ucy5jdXN0b21Db2RlLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcbiAgICAvLyBQcm9jZXNzIHJlc291cmNlc1xuICAgIG9wdGlvbnMuY3VzdG9tQ29kZS5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXG4gICAgICBvcHRpb25zLmN1c3RvbUNvZGUucmVzb3VyY2VzLFxuICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tQ29kZS5hbGxvd0ZpbGVSZXNvdXJjZXMpXG4gICAgKTtcbiAgfSBlbHNlIGlmICghb3B0aW9ucy5jdXN0b21Db2RlLnJlc291cmNlcykge1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNvdXJjZXMgPSByZWFkRmlsZVN5bmMoJ3Jlc291cmNlcy5qc29uJywgJ3V0ZjgnKTtcbiAgICAgIG9wdGlvbnMuY3VzdG9tQ29kZS5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXG4gICAgICAgIHJlc291cmNlcyxcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tQ29kZS5hbGxvd0ZpbGVSZXNvdXJjZXMpXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgbG9nKDMsIGBbY2hhcnRdIFRoZSBkZWZhdWx0IHJlc291cmNlcy5qc29uIGZpbGUgbm90IGZvdW5kLmApO1xuICAgIH1cbiAgfVxuXG4gIC8vIElmIHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZyBpc24ndCBzZXQsIHdlIHNob3VsZCByZWZ1c2UgdGhlIHVzYWdlXG4gIC8vIG9mIGNhbGxiYWNrLCByZXNvdXJjZXMsIGFuZCBjdXN0b20gY29kZS4gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGxcbiAgLy8gcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC4gUHJpb3JpdGl6ZWQgc2hvdWxkIGJlIHRoZSBzY29wZWRcbiAgLy8gb3B0aW9uLCB0aGVuIHdlIHNob3VsZCB0YWtlIGEgbG9vayBhdCB0aGUgb3ZlcmFsbCBwb29sIG9wdGlvbi5cbiAgaWYgKCFhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgJiYgY3VzdG9tQ29kZU9wdGlvbnMpIHtcbiAgICBpZiAoXG4gICAgICBjdXN0b21Db2RlT3B0aW9ucy5jYWxsYmFjayB8fFxuICAgICAgY3VzdG9tQ29kZU9wdGlvbnMucmVzb3VyY2VzIHx8XG4gICAgICBjdXN0b21Db2RlT3B0aW9ucy5jdXN0b21Db2RlXG4gICAgKSB7XG4gICAgICAvLyBTZW5kIGJhY2sgYSBmcmllbmRseSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0XG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cbiAgICAgIHJldHVybiAoXG4gICAgICAgIGVuZENhbGxiYWNrICYmXG4gICAgICAgIGVuZENhbGxiYWNrKGZhbHNlLCB7XG4gICAgICAgICAgZXJyb3I6IHRydWUsXG4gICAgICAgICAgbWVzc2FnZTogY2xlYXJUZXh0KFxuICAgICAgICAgICAgYFRoZSBjYWxsYmFjaywgcmVzb3VyY2VzIGFuZCBjdXN0b21Db2RlIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpc1xuICAgICAgICAgICAgc2VydmVyLmBcbiAgICAgICAgICApXG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFJlc2V0IGFsbCBhZGRpdGlvbmFsIGN1c3RvbSBjb2RlXG4gICAgY3VzdG9tQ29kZU9wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcbiAgICBjdXN0b21Db2RlT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcbiAgICBjdXN0b21Db2RlT3B0aW9ucy5jdXN0b21Db2RlID0gZmFsc2U7XG4gIH1cblxuICAvLyBDbGVhbiBwcm9wZXJ0aWVzIHRvIGtlZXAgaXQgbGVhbiBhbmQgbWVhblxuICBpZiAoY2hhcnRKc29uKSB7XG4gICAgY2hhcnRKc29uLmNoYXJ0ID0gY2hhcnRKc29uLmNoYXJ0IHx8IHt9O1xuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcgPSBjaGFydEpzb24uZXhwb3J0aW5nIHx8IHt9O1xuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcuZW5hYmxlZCA9IGZhbHNlO1xuICB9XG5cbiAgZXhwb3J0T3B0aW9ucy5jb25zdHIgPSBleHBvcnRPcHRpb25zLmNvbnN0ciB8fCAnY2hhcnQnO1xuICBleHBvcnRPcHRpb25zLnR5cGUgPSBmaXhUeXBlKGV4cG9ydE9wdGlvbnMudHlwZSwgZXhwb3J0T3B0aW9ucy5vdXRmaWxlKTtcbiAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcbiAgICBleHBvcnRPcHRpb25zLndpZHRoID0gZmFsc2U7XG4gIH1cblxuICAvLyBQcmVwYXJlIGdsb2JhbCBhbmQgdGhlbWUgb3B0aW9uc1xuICBbJ2dsb2JhbE9wdGlvbnMnLCAndGhlbWVPcHRpb25zJ10uZm9yRWFjaCgob3B0aW9uc05hbWUpID0+IHtcbiAgICB0cnkge1xuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMgJiYgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXS5lbmRzV2l0aCgnLmpzb24nKVxuICAgICAgICApIHtcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sICd1dGY4JyksXG4gICAgICAgICAgICB0cnVlXG4gICAgICAgICAgKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcbiAgICAgICAgICAgIHRydWVcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0ge307XG4gICAgICBsb2coMSwgYFtjaGFydF0gVGhlICR7b3B0aW9uc05hbWV9IG5vdCBmb3VuZC5gKTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFByZXBhcmUgY3VzdG9tQ29kZVxuICBpZiAoY3VzdG9tQ29kZU9wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKSB7XG4gICAgY3VzdG9tQ29kZU9wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXG4gICAgICBjdXN0b21Db2RlT3B0aW9ucy5jdXN0b21Db2RlLFxuICAgICAgY3VzdG9tQ29kZU9wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXG4gICAgKTtcbiAgfVxuXG4gIC8vIEdldCB0aGUgY2FsbGJhY2tcbiAgaWYgKFxuICAgIGN1c3RvbUNvZGVPcHRpb25zICYmXG4gICAgY3VzdG9tQ29kZU9wdGlvbnMuY2FsbGJhY2sgJiZcbiAgICBjdXN0b21Db2RlT3B0aW9ucy5jYWxsYmFjaz8uaW5kZXhPZigneycpIDwgMFxuICApIHtcbiAgICAvLyBUaGUgYWxsb3dGaWxlUmVzb3VyY2VzIGlzIGFsd2F5cyBzZXQgdG8gZmFsc2UgZm9yIEhUVFAgcmVxdWVzdHMgdG8gYXZvaWRcbiAgICAvLyBpbmplY3RpbmcgYXJiaXRyYXJ5IGZpbGVzIGZyb20gdGhlIGZzXG4gICAgaWYgKGN1c3RvbUNvZGVPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY3VzdG9tQ29kZU9wdGlvbnMuY2FsbGJhY2sgPSByZWFkRmlsZVN5bmMoXG4gICAgICAgICAgY3VzdG9tQ29kZU9wdGlvbnMuY2FsbGJhY2ssXG4gICAgICAgICAgJ3V0ZjgnXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2coMiwgYFtjaGFydF0gRXJyb3IgbG9hZGluZyBjYWxsYmFjazogJHtlcnJvcn0uYCk7XG4gICAgICAgIGN1c3RvbUNvZGVPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGN1c3RvbUNvZGVPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLy8gU2l6ZSBzZWFyY2hcbiAgb3B0aW9ucy5leHBvcnQgPSB7XG4gICAgLi4ub3B0aW9ucy5leHBvcnQsXG4gICAgLi4uZmluZENoYXJ0U2l6ZShvcHRpb25zKVxuICB9O1xuXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcbiAgcG9zdFdvcmsoZXhwb3J0T3B0aW9ucy5zdHJJbmogfHwgY2hhcnRKc29uIHx8IHN2Zywgb3B0aW9ucylcbiAgICAudGhlbigocmVzdWx0KSA9PiBlbmRDYWxsYmFjayhyZXN1bHQpKVxuICAgIC5jYXRjaCgoZXJyb3IpID0+IHtcbiAgICAgIGxvZygwLCAnW2NoYXJ0XSBXaGVuIHBvc3Rpbmcgd29yazonLCBlcnJvcik7XG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soZmFsc2UsIGVycm9yKTtcbiAgICB9KTtcbn07XG5cbi8qKlxuICogRnVuY3Rpb24gZm9yIHN0cmFpZ2h0IGluamVjdGluZyB0aGUgY29kZS5cbiAqIERhbmdlcm91cyBhbmQgbXVzdCBiZSB1c2VkIGRlbGliZXJhdGVseSBieSBzb21lb25lIHdobyBzZXRzIHVwIGEgc2VydmVyXG4gKiAoc2VlICAtLWFsbG93Q29kZUV4ZWN1dGlvbikuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBBbGwgb3B0aW9ucyBvYmplY3QuXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBmdW5jdGlvbiB0byBjYWxsIHdoZW4gZXhwb3J0aW5nIGlzIGRvbmUuXG4gKi9cbmNvbnN0IGRvU3RyYWlnaHRJbmplY3QgPSAob3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcbiAgdHJ5IHtcbiAgICBsZXQgc3RySW5qO1xuICAgIGxldCBpbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XG5cbiAgICBpZiAodHlwZW9mIGluc3RyICE9PSAnc3RyaW5nJykge1xuICAgICAgLy8gVHJ5IHRvIHN0cmluZ2lmeSBvcHRpb25zXG4gICAgICBzdHJJbmogPSBpbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXG4gICAgICAgIGluc3RyLFxuICAgICAgICBvcHRpb25zLmN1c3RvbUNvZGU/LmFsbG93Q29kZUV4ZWN1dGlvblxuICAgICAgKTtcbiAgICB9XG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcblxuICAgIC8vIEdldCByaWQgb2YgdGhlIDtcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XG4gICAgICBzdHJJbmogPSBzdHJJbmouc3Vic3RyaW5nKDAsIHN0ckluai5sZW5ndGggLSAxKTtcbiAgICB9XG5cbiAgICAvLyBTYXZlIGFzIHN0cmlnaHQgaW5qZWN0IHN0cmluZ1xuICAgIG9wdGlvbnMuZXhwb3J0LnN0ckluaiA9IHN0ckluajtcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBjb25zdCBtZXNzYWdlID0gY2xlYXJUZXh0KFxuICAgICAgYE1hbGZvcm1lZCBpbnB1dCBkZXRlY3RlZCBmb3IgJHtvcHRpb25zLmV4cG9ydD8ucmVxdWVzdElkIHx8ICc/J306XG4gICAgICBQbGVhc2UgbWFrZSBzdXJlIHRoYXQgeW91ciBKU09OL0phdmFTY3JpcHQgb3B0aW9uc1xuICAgICAgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nXG4gICAgICBTVkcsIGl0IGlzIHVuZXNjYXBlZC5gXG4gICAgKTtcblxuICAgIGxvZygxLCBtZXNzYWdlKTtcbiAgICByZXR1cm4gKFxuICAgICAgZW5kQ2FsbGJhY2sgJiZcbiAgICAgIGVuZENhbGxiYWNrKFxuICAgICAgICBmYWxzZSxcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgIGVycm9yOiB0cnVlLFxuICAgICAgICAgIG1lc3NhZ2VcbiAgICAgICAgfSlcbiAgICAgIClcbiAgICApO1xuICB9XG59O1xuXG4vKipcbiAqIFByZXBhcmVzIGFuIGlucHV0IGJlZm9yZSBleHBvcnRpbmcuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZ1RvRXhwb3J0IC0gU3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIFNWRy9leHBvcnQgb3B0aW9ucy5cbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgb2JqZWN0LlxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgZnVuY3Rpb24gdG8gY2FsbCB3aGVuIGV4cG9ydGluZyBpcyBkb25lLlxuICovXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcbiAgY29uc3QgeyBhbGxvd0NvZGVFeGVjdXRpb24gfSA9IG9wdGlvbnMuY3VzdG9tQ29kZTtcblxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcbiAgaWYgKFxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwXG4gICkge1xuICAgIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGFzIFNWRy4nKTtcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrLCBzdHJpbmdUb0V4cG9ydCk7XG4gIH1cblxuICB0cnkge1xuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxuICAgIGNvbnN0IGNoYXJ0SlNPTiA9IEpTT04ucGFyc2Uoc3RyaW5nVG9FeHBvcnQucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJyAnKSk7XG5cbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBjaGFydEpTT04sIGVuZENhbGxiYWNrKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXG4gICAgaWYgKHRvQm9vbGVhbihhbGxvd0NvZGVFeGVjdXRpb24pKSB7XG4gICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIERvIG5vdCBhbGxvdyBzdHJhaWdodCBpbmplY3Rpb24gd2l0aG91dCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWdcbiAgICAgIHJldHVybiAoXG4gICAgICAgIGVuZENhbGxiYWNrICYmXG4gICAgICAgIGVuZENhbGxiYWNrKGZhbHNlLCB7XG4gICAgICAgICAgZXJyb3I6IHRydWUsXG4gICAgICAgICAgbWVzc2FnZTogY2xlYXJUZXh0KFxuICAgICAgICAgICAgYE9ubHkgSlNPTiBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGlzIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZlxuICAgICAgICAgICAgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBleHBvcnRpbmcgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmdcbiAgICAgICAgICAgIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgLS1hbGxvd0NvZGVFeGVjdXRpb24gZmxhZy5gXG4gICAgICAgICAgKVxuICAgICAgICB9KVxuICAgICAgKTtcbiAgICB9XG4gIH1cbn07XG5cbmV4cG9ydCBjb25zdCBnZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAoKSA9PiBhbGxvd0NvZGVFeGVjdXRpb247XG5cbmV4cG9ydCBjb25zdCBzZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAodmFsdWUpID0+IHtcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdG9Cb29sZWFuKHZhbHVlKTtcbn07XG5cbi8qKlxuICogU3RhcnRzIGFuIGV4cG9ydGluZyBwcm9jZXNzXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IHNldHRpbmdzIC0gU2V0dGluZ3MgZm9yIGV4cG9ydC5cbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGZ1bmN0aW9uIHRvIGNhbGwgd2hlbiBleHBvcnRpbmcgaXMgZG9uZS5cbiAqL1xuZXhwb3J0IGRlZmF1bHQge1xuICBiYXRjaEV4cG9ydCxcbiAgc2luZ2xlRXhwb3J0LFxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcbiAgc3RhcnRFeHBvcnQsXG4gIGZpbmRDaGFydFNpemVcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xuXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24sIHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xuaW1wb3J0IHsgZ2V0T3B0aW9ucywgbWVyZ2VDb25maWdPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQge1xuICBjbGVhclRleHQsXG4gIGZpeFR5cGUsXG4gIGlzQ29ycmVjdEpTT04sXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXG4gIG9wdGlvbnNTdHJpbmdpZnksXG4gIG1lYXN1cmVUaW1lXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcblxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xuY29uc3QgcmV2ZXJzZWRNaW1lID0ge1xuICBwbmc6ICdpbWFnZS9wbmcnLFxuICBqcGVnOiAnaW1hZ2UvanBlZycsXG4gIGdpZjogJ2ltYWdlL2dpZicsXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXG59O1xuXG4vLyBUaGUgcmVxdWVzdHMgY291bnRlclxubGV0IHJlcXVlc3RzQ291bnRlciA9IDA7XG5cbmNvbnN0IGJlbmNobWFyayA9IGZhbHNlO1xuXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYmVmb3JlIGEgcmVxdWVzdFxuY29uc3QgYmVmb3JlUmVxdWVzdCA9IFtdO1xuXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYWZ0ZXIgYSByZXF1ZXN0XG5jb25zdCBhZnRlclJlcXVlc3QgPSBbXTtcblxuLyoqXG4gKiBDYWxscyBjYWxsYmFja3MuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gY2FsbGJhY2tzIC0gQW4gYXJyYXkgb2YgY2FsbGJhY2tzLlxuICogQHBhcmFtIHtvYmplY3R9IHJlcXVlc3QgLSBUaGUgcmVxdWVzdC5cbiAqIEBwYXJhbSB7b2JqZWN0fSByZXNwb25zZSAtIFRoZSByZXNwb25zZS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBkYXRhIC0gVGhlIGRhdGEgdG8gc2VuZCB0byBjYWxsYmFja3MuXG4gKiBAcmV0dXJuIHtvYmplY3R9IC0gVGhlIHJlc3VsdCBmcm9tIGEgY2FsbGJhY2suXG4gKi9cbmNvbnN0IGRvQ2FsbGJhY2tzID0gKGNhbGxiYWNrcywgcmVxdWVzdCwgcmVzcG9uc2UsIGRhdGEpID0+IHtcbiAgbGV0IHJlc3VsdCA9IHRydWU7XG4gIGNvbnN0IHsgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5IH0gPSBkYXRhO1xuXG4gIGNhbGxiYWNrcy5zb21lKChjYWxsYmFjaykgPT4ge1xuICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgbGV0IGNhbGxSZXNwb25zZSA9IGNhbGxiYWNrKHJlcXVlc3QsIHJlc3BvbnNlLCBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkpO1xuXG4gICAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB1bmRlZmluZWQgJiYgY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XG4gICAgICAgIHJlc3VsdCA9IGNhbGxSZXNwb25zZTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9KTtcblxuICByZXR1cm4gcmVzdWx0O1xufTtcblxuLyoqXG4gKiBIYW5kbGVzIGFuIGV4cG9ydC5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gcmVxdWVzdCAtIFRoZSByZXF1ZXN0LlxuICogQHBhcmFtIHtvYmplY3R9IHJlc3BvbnNlIC0gVGhlIHJlc3BvbnNlLlxuICovXG5jb25zdCBleHBvcnRIYW5kbGVyID0gKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWVcbiAgY29uc3Qgc3RvcENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xuXG4gIC8vIEdldCB0aGUgY3VycmVudCBzZXJ2ZXIncyBnZW5lcmFsIG9wdGlvbnNcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XG5cbiAgLy8gSW5pdCBkZWZhdWx0IG9wdGlvbnNcbiAgaWYgKGJlbmNobWFyaykge1xuICAgIGNvbnNvbGUubG9nKCdJbml0IGRlZmF1bHQgb3B0aW9uczonLCBzdG9wQ291bnRlcigpLCAnbXMuJyk7XG4gIH1cblxuICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xuICBjb25zdCBpZCA9ICsrcmVxdWVzdHNDb3VudGVyO1xuICBjb25zdCB1bmlxdWVJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcbiAgbGV0IHR5cGUgPSBmaXhUeXBlKGJvZHkudHlwZSk7XG5cbiAgLy8gRml4IHR5cGVcbiAgaWYgKGJlbmNobWFyaykge1xuICAgIGNvbnNvbGUubG9nKCdGaXggdHlwZTonLCBzdG9wQ291bnRlcigpLCAnbXMuJyk7XG4gIH1cblxuICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gYm9keVxuICBpZiAoIWJvZHkpIHtcbiAgICByZXR1cm4gcmVzcG9uc2Uuc3RhdHVzKDQwMCkuc2VuZChcbiAgICAgIGNsZWFyVGV4dChcbiAgICAgICAgYEJvZHkgaXMgcmVxdWlyZWQuIFNlbmRpbmcgYSBib2R5PyBNYWtlIHN1cmUgeW91ciBDb250ZW50LXR5cGUgaGVhZGVyXG4gICAgICAgIGlzIGNvcnJlY3QuIEFjY2VwdGVkIGlzIGFwcGxpY2F0aW9uL2pzb24gYW5kIG11bHRpcGFydC9mb3JtLWRhdGEuYFxuICAgICAgKVxuICAgICk7XG4gIH1cblxuICAvLyBBbGwgb2YgdGhlIGJlbG93IGNhbiBiZSB1c2VkXG4gIGxldCBpbnN0ciA9IGlzQ29ycmVjdEpTT04oYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSk7XG5cbiAgLy8gSXMgY29ycmVjdCBKU09OXG4gIGlmIChiZW5jaG1hcmspIHtcbiAgICBjb25zb2xlLmxvZygnSXMgY29ycmVjdCBKU09OOicsIHN0b3BDb3VudGVyKCksICdtcy4nKTtcbiAgfVxuXG4gIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBKU09OIG9yIFNWRyB0byBleHBvcnRcbiAgaWYgKCFpbnN0ciAmJiAhYm9keS5zdmcpIHtcbiAgICBsb2coXG4gICAgICAyLFxuICAgICAgY2xlYXJUZXh0KFxuICAgICAgICBgUmVxdWVzdCAke3VuaXF1ZUlkfSBmcm9tICR7XG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIENoZWNrIHlvdXIgcGF5bG9hZC5gXG4gICAgICApXG4gICAgKTtcblxuICAgIHJldHVybiByZXNwb25zZS5zdGF0dXMoNDAwKS5zZW5kKFxuICAgICAgY2xlYXJUZXh0KFxuICAgICAgICBgTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBQbGVhc2UgbWFrZSBzdXJlIHlvdSBhcmUgdXNpbmdcbiAgICAgICAgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMsIGFuZCB0aGF0IHRoZSBjaGFydFxuICAgICAgICBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnIG9yICdkYXRhJyBhdHRyaWJ1dGUgaWYgc2VuZGluZ1xuICAgICAgICBKU09OIG9yIGluIHRoZSAnc3ZnJyBpZiBzZW5kaW5nIFNWRy5gXG4gICAgICApXG4gICAgKTtcbiAgfVxuXG4gIGxldCBjYWxsUmVzcG9uc2UgPSBmYWxzZTtcblxuICAvLyBDYWxsIHRoZSBiZWZvcmUgcmVxdWVzdCBmdW5jdGlvbnNcbiAgY2FsbFJlc3BvbnNlID0gZG9DYWxsYmFja3MoYmVmb3JlUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHtcbiAgICBpZCxcbiAgICB1bmlxdWVJZCxcbiAgICB0eXBlLFxuICAgIGJvZHlcbiAgfSk7XG5cbiAgLy8gRG8gY2FsbGJhY2tzXG4gIGlmIChiZW5jaG1hcmspIHtcbiAgICBjb25zb2xlLmxvZygnRG8gY2FsbGJhY2tzOicsIHN0b3BDb3VudGVyKCksICdtcy4nKTtcbiAgfVxuXG4gIC8vIEJsb2NrIHRoZSByZXF1ZXN0IGlmIG9uZSBvZiBhIGNhbGxiYWNrcyBmYWlsZWRcbiAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xuICAgIHJldHVybiByZXNwb25zZS5zZW5kKGNhbGxSZXNwb25zZSk7XG4gIH1cblxuICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcblxuICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXG4gIHJlcXVlc3Quc29ja2V0Lm9uKCdjbG9zZScsICgpID0+IHtcbiAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XG4gIH0pO1xuXG4gIGxvZyg0LCBgW2V4cG9ydF0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdCAke3VuaXF1ZUlkfS5gKTtcblxuICBib2R5LmNvbnN0ciA9ICh0eXBlb2YgYm9keS5jb25zdHIgPT09ICdzdHJpbmcnICYmIGJvZHkuY29uc3RyKSB8fCAnY2hhcnQnO1xuXG4gIC8vIEdhdGhlciBhbmQgb3JnYW5pemUgb3B0aW9ucyBmcm9tIHRoZSBwYXlsb2FkXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0ge1xuICAgIGV4cG9ydDoge1xuICAgICAgaW5zdHIsXG4gICAgICB0eXBlLFxuICAgICAgY29uc3RyOiBib2R5LmNvbnN0clswXS50b0xvd2VyQ2FzZSgpICsgYm9keS5jb25zdHIuc3Vic3RyKDEpLFxuICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcbiAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxuICAgICAgc2NhbGU6IGJvZHkuc2NhbGUgfHwgZGVmYXVsdE9wdGlvbnMuZXhwb3J0LnNjYWxlLFxuICAgICAgZ2xvYmFsT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5Lmdsb2JhbE9wdGlvbnMsIHRydWUpLFxuICAgICAgdGhlbWVPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkudGhlbWVPcHRpb25zLCB0cnVlKVxuICAgIH0sXG4gICAgY3VzdG9tQ29kZToge1xuICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uOiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSxcbiAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXG4gICAgICByZXNvdXJjZXM6IGlzQ29ycmVjdEpTT04oYm9keS5yZXNvdXJjZXMsIHRydWUpLFxuICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXG4gICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGVcbiAgICB9XG4gIH07XG5cbiAgLy8gT3JnYW5pemUgb3B0aW9uc1xuICBpZiAoYmVuY2htYXJrKSB7XG4gICAgY29uc29sZS5sb2coJ09yZ2FuaXplIG9wdGlvbnM6Jywgc3RvcENvdW50ZXIoKSwgJ21zLicpO1xuICB9XG5cbiAgaWYgKGluc3RyKSB7XG4gICAgLy8gU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zXG4gICAgcmVxdWVzdE9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcbiAgICAgIGluc3RyLFxuICAgICAgcmVxdWVzdE9wdGlvbnMuY3VzdG9tQ29kZS5hbGxvd0NvZGVFeGVjdXRpb25cbiAgICApO1xuXG4gICAgLy8gU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zXG4gICAgaWYgKGJlbmNobWFyaykge1xuICAgICAgY29uc29sZS5sb2coJ1N0cmluZ2lmeSBKU09OIHdpdGggb3B0aW9uczonLCBzdG9wQ291bnRlcigpLCAnbXMuJyk7XG4gICAgfVxuICB9XG5cbiAgLy8gTWVyZ2UgdGhlIHJlcXVlc3Qgb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xuICBjb25zdCBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKGRlZmF1bHRPcHRpb25zLCByZXF1ZXN0T3B0aW9ucyk7XG5cbiAgLy8gTWVyZ2UgY29uZmlnIG9wdGlvbnNcbiAgaWYgKGJlbmNobWFyaykge1xuICAgIGNvbnNvbGUubG9nKCdNZXJnZSBjb25maWcgb3B0aW9uczonLCBzdG9wQ291bnRlcigpLCAnbXMuJyk7XG4gIH1cblxuICAvLyBTYXZlIHRoZSBKU09OIGlmIGV4aXN0c1xuICBvcHRpb25zLmV4cG9ydC5vcHRpb25zID0gaW5zdHI7XG5cbiAgLy8gTGFzdGx5LCBhZGQgdGhlIHNlcnZlciBzcGVjaWZpYyBhcmd1bWVudHMgaW50byBvcHRpb25zIGFzIHBheWxvYWRcbiAgb3B0aW9ucy5wYXlsb2FkID0ge1xuICAgIHN2ZzogYm9keS5zdmcgfHwgZmFsc2UsXG4gICAgYjY0OiBib2R5LmI2NCB8fCBmYWxzZSxcbiAgICBkYXRhT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5LmRhdGFPcHRpb25zLCB0cnVlKSxcbiAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQgfHwgZmFsc2UsXG4gICAgcmVxdWVzdElkOiB1bmlxdWVJZFxuICB9O1xuXG4gIC8vIFNldHRpbmcgcGF5bG9hZFxuICBpZiAoYmVuY2htYXJrKSB7XG4gICAgY29uc29sZS5sb2coJ1NldHRpbmcgcGF5bG9hZDonLCBzdG9wQ291bnRlcigpLCAnbXMuJyk7XG4gIH1cblxuICAvLyBUZXN0IHhsaW5rOmhyZWYgZWxlbWVudHMgZnJvbSBwYXlsb2FkJ3MgU1ZHXG4gIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKG9wdGlvbnMucGF5bG9hZC5zdmcpKSB7XG4gICAgcmV0dXJuIHJlc3BvbnNlXG4gICAgICAuc3RhdHVzKDQwMClcbiAgICAgIC5zZW5kKFxuICAgICAgICAnU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4geGxpbms6aHJlZiBlbGVtZW50LidcbiAgICAgICk7XG4gIH1cblxuICAvLyBDaGVjayBVUkwgcmFuZ2VcbiAgaWYgKGJlbmNobWFyaykge1xuICAgIGNvbnNvbGUubG9nKCdDaGVjayBVUkwgcmFuZ2U6Jywgc3RvcENvdW50ZXIoKSwgJ21zLicpO1xuICB9XG5cbiAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXG4gIHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChpbmZvLCBlcnJvcikgPT4ge1xuICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XG4gICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xuXG4gICAgLy8gQWZ0ZXIgUHVwcGV0ZWVyIGV4cG9ydGluZ1xuICAgIGlmIChiZW5jaG1hcmspIHtcbiAgICAgIGNvbnNvbGUubG9nKCdBZnRlciBQdXBwZXRlZXIgZXhwb3J0aW5nOicsIHN0b3BDb3VudGVyKCksICdtcy4nLCAnXFxuJyk7XG4gICAgfVxuXG4gICAgLy8gSWYgdGhlIGNvbm5lY3Rpb24gd2FzIGNsb3NlZCwgZG8gbm90aGluZ1xuICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xuICAgICAgcmV0dXJuIGxvZyhcbiAgICAgICAgMyxcbiAgICAgICAgY2xlYXJUZXh0KFxuICAgICAgICAgIGBbZXhwb3J0XSBUaGUgY2xpZW50IGNsb3NlZCB0aGUgY29ubmVjdGlvbiBiZWZvcmUgdGhlIGNoYXJ0IHdhcyBkb25lXG4gICAgICAgICAgcHJvY2Vzc2luZy5gXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gSWYgZXJyb3IsIHJldHVybiBpdFxuICAgIGlmIChlcnJvcikge1xuICAgICAgbG9nKFxuICAgICAgICAxLFxuICAgICAgICBjbGVhclRleHQoXG4gICAgICAgICAgYFtleHBvcnRdIFdvcms6ICR7dW5pcXVlSWR9IGNvdWxkIG5vdCBiZSBjb21wbGV0ZWQsIHNlbmRpbmc6XG4gICAgICAgICAgJHtlcnJvcn1gXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgICByZXR1cm4gcmVzcG9uc2Uuc3RhdHVzKDQwMCkuc2VuZChlcnJvci5tZXNzYWdlKTtcbiAgICB9XG5cbiAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIHJldHVybiB0aGUgZXJyb3JcbiAgICBpZiAoIWluZm8gfHwgIWluZm8uZGF0YSkge1xuICAgICAgbG9nKFxuICAgICAgICAxLFxuICAgICAgICBjbGVhclRleHQoXG4gICAgICAgICAgYFtleHBvcnRdIFVuZXhwZWN0ZWQgcmV0dXJuIGZyb20gY2hhcnQgZ2VuZXJhdGlvbiwgcGxlYXNlIGNoZWNrIHlvdXJcbiAgICAgICAgICBkYXRhIFJlcXVlc3Q6ICR7dW5pcXVlSWR9IGlzICR7aW5mby5kYXRhfS5gXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgICByZXR1cm4gcmVzcG9uc2VcbiAgICAgICAgLnN0YXR1cyg0MDApXG4gICAgICAgIC5zZW5kKFxuICAgICAgICAgICdVbmV4cGVjdGVkIHJldHVybiBmcm9tIGNoYXJ0IGdlbmVyYXRpb24sIHBsZWFzZSBjaGVjayB5b3VyIGRhdGEuJ1xuICAgICAgICApO1xuICAgIH1cblxuICAgIC8vIEdldCB0aGUgdHlwZSBmcm9tIG9wdGlvbnNcbiAgICB0eXBlID0gaW5mby5vcHRpb25zLmV4cG9ydC50eXBlO1xuXG4gICAgLy8gVGhlIGFmdGVyIHJlcXVlc3QgY2FsbGJhY2tzXG4gICAgZG9DYWxsYmFja3MoYWZ0ZXJSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwgeyBpZCwgYm9keTogaW5mby5kYXRhIH0pO1xuXG4gICAgaWYgKGluZm8uZGF0YSkge1xuICAgICAgLy8gSWYgb25seSBiYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxuICAgICAgaWYgKGJvZHkuYjY0KSB7XG4gICAgICAgIC8vIENoZWNrIGlmIGl0IGlzIGFscmVhZHkgYmFzZTY0IG9yIGEgcmF3IFNWR1xuICAgICAgICBpZiAodHlwZSA9PT0gJ3BkZicpIHtcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChcbiAgICAgICAgICAgIEJ1ZmZlci5mcm9tKGluZm8uZGF0YSwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0JylcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGluZm8uZGF0YSk7XG4gICAgICB9XG5cbiAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxuICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xuXG4gICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxuICAgICAgaWYgKCFib2R5Lm5vRG93bmxvYWQpIHtcbiAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChcbiAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCAnY2hhcnQnfS4ke3R5cGUgfHwgJ3BuZyd9YFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiBTVkcsIHJldHVybiBwbGFpbiBjb250ZW50XG4gICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcbiAgICAgICAgPyByZXNwb25zZS5zZW5kKGluZm8uZGF0YSlcbiAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGluZm8uZGF0YSwgJ2Jhc2U2NCcpKTtcbiAgICB9XG4gIH0pO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xuICBhcHAucG9zdCgnLycsIGV4cG9ydEhhbmRsZXIpO1xuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIGV4cG9ydEhhbmRsZXIpO1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyMywgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xuaW1wb3J0IHsgcG9zaXggfSBmcm9tICdwYXRoJztcblxuaW1wb3J0IGJvZHlQYXJzZXIgZnJvbSAnYm9keS1wYXJzZXInO1xuaW1wb3J0IGNvcnMgZnJvbSAnY29ycyc7XG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcblxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnLi9yYXRlX2xpbWl0LmpzJztcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uL3V0aWxzLmpzJztcblxuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XG5pbXBvcnQgZXhwb3J0Um91dGVzIGZyb20gJy4vcm91dGVzL2V4cG9ydC5qcyc7XG5pbXBvcnQgdnN3aXRjaFJvdXRlIGZyb20gJy4vcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzJztcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcblxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XG5cbi8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcbmFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcblxuLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxuYXBwLnVzZShjb3JzKCkpO1xuXG4vLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIE11bHRlciBwYWNrYWdlXG5jb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcbmNvbnN0IHVwbG9hZCA9IG11bHRlcih7XG4gIHN0b3JhZ2UsXG4gIGxpbWl0czoge1xuICAgIGZpZWxkc1NpemU6ICc1ME1CJ1xuICB9XG59KTtcblxuYXBwLnVzZSh1cGxvYWQuYW55KCkpO1xuXG4vLyBFbmFibGUgYm9keSBwYXJzZXJcbmFwcC51c2UoYm9keVBhcnNlci5qc29uKHsgbGltaXQ6ICc1MG1iJyB9KSk7XG5hcHAudXNlKGJvZHlQYXJzZXIudXJsZW5jb2RlZCh7IGV4dGVuZGVkOiB0cnVlLCBsaW1pdDogJzUwbWInIH0pKTtcbmFwcC51c2UoYm9keVBhcnNlci51cmxlbmNvZGVkKHsgZXh0ZW5kZWQ6IGZhbHNlLCBsaW1pdDogJzUwbWInIH0pKTtcblxuLyoqXG4gKiBFcnJvciBoYW5kbGVyIGZ1bmN0aW9uLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBlcnJvciAtIEFuIGVycm9yIG9iamVjdC5cbiAqIEByZXR1cm4ge3N0cmluZ30gLSBBbiBlcnJvciBtZXNzYWdlLlxuICovXG5jb25zdCBlcnJvckhhbmRsZXIgPSAoZXJyb3IpID0+IGxvZygxLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yfWApO1xuXG4vKipcbiAqIEF0dGFjaGVzIGVycm9yIGhhbmRsZXJzIGZvciBhIHNlcnZlci5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gc2VydmVyIC0gVGhlIGh0dHAvaHR0cHMgc2VydmVyLlxuICovXG5jb25zdCBhdHRhY2hFcnJvckhhbmRsZXJzID0gKHNlcnZlcikgPT4ge1xuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgZXJyb3JIYW5kbGVyKTtcbiAgc2VydmVyLm9uKCdlcnJvcicsIGVycm9ySGFuZGxlcik7XG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+XG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4gZXJyb3JIYW5kbGVyKGVycm9yLCBzb2NrZXQpKVxuICApO1xufTtcblxuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xuICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXG4gIGlmICghc2VydmVyQ29uZmlnLmVuYWJsZSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIC8vIEdldCB0aGUgcG9vbFxuICAvLyBjb25zdCBwb29sID0gZ2V0UG9vbCgpO1xuXG4gIC8vIC8vIFRyeSB0byBjcmVhdGUgYnJvd3NlciBpbnN0YW5jZSBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZlclxuICAvLyBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpO1xuXG4gIC8vIC8vIElmIG5vdCBmb3VuZCwgdGhyb3cgYW4gZXJyb3JcbiAgLy8gaWYgKCFyZXNvdXJjZS5icm93c2VyKSB7XG4gIC8vICAgbG9nKDEsIGBbc2VydmVyXSBDb3VsZCBub3QgYWNxdWlyZSBicm93c2VyIGluc3RhbmNlLmApO1xuICAvLyAgIHByb2Nlc3MuZXhpdCgxKTtcbiAgLy8gfVxuXG4gIC8vIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlXG4gIC8vIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XG5cbiAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXG4gIGlmICghc2VydmVyQ29uZmlnLnNzbC5lbmFibGUgJiYgIXNlcnZlckNvbmZpZy5zc2wuZm9yY2UpIHtcbiAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUClcbiAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcbiAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXG4gICAgYXR0YWNoRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcbiAgICAvLyBMaXN0ZW5cbiAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xuXG4gICAgbG9nKFxuICAgICAgMyxcbiAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnBvcnR9LmBcbiAgICApO1xuICB9XG5cbiAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxuICBpZiAoc2VydmVyQ29uZmlnLnNzbC5lbmFibGUpIHtcbiAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXG4gICAgbGV0IGtleSwgY2VydDtcblxuICAgIHRyeSB7XG4gICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcbiAgICAgIGtleSA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXG4gICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5rZXknKSxcbiAgICAgICAgJ3V0ZjgnXG4gICAgICApO1xuXG4gICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxuICAgICAgY2VydCA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXG4gICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5jcnQnKSxcbiAgICAgICAgJ3V0ZjgnXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2coXG4gICAgICAgIDEsXG4gICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSAke3NlcnZlckNvbmZpZy5zc2wuY2VydFBhdGh9LmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKGtleSAmJiBjZXJ0KSB7XG4gICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXG4gICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcihhcHApO1xuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxuICAgICAgYXR0YWNoRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XG4gICAgICAvLyBMaXN0ZW5cbiAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcblxuICAgICAgbG9nKFxuICAgICAgICAzLFxuICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcuc3NsLnBvcnR9LmBcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gRW5hYmxlIHRoZSByYXRlIGxpbWl0ZXIgaWYgY29uZmlnIHNheXMgc29cbiAgaWYgKFxuICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcbiAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLmVuYWJsZSAmJlxuICAgICFbMCwgTmFOXS5pbmNsdWRlcyhzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzKVxuICApIHtcbiAgICByYXRlTGltaXQoYXBwLCBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nKTtcbiAgfVxuXG4gIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcbiAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XG5cbiAgLy8gU2V0IHVwIHJvdXRlc1xuICBoZWFsdGhSb3V0ZShhcHApO1xuICBleHBvcnRSb3V0ZXMoYXBwKTtcbiAgdWlSb3V0ZShhcHApO1xuICB2c3dpdGNoUm91dGUoYXBwKTtcbn07XG5cbi8qKlxuICogUmV0dXJucyB0aGUgZXhwcmVzcyBpbnN0YW5jZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldEV4cHJlc3MgPSAoKSA9PiB7XG4gIHJldHVybiBleHByZXNzO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBhcHAgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRBcHAgPSAoKSA9PiB7XG4gIHJldHVybiBhcHA7XG59O1xuXG4vKipcbiAqIEFkZHMgYSBtaWRkbGV3YXJlIHRvIHRoZSBzZXJ2ZXIuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IHBhdGggLSBBbiBlbmRwb2ludCBwYXRoIHRvIGFkZCBtaWRkbGV3YXJlcyB0by5cbiAqIEBwYXJhbSB7QXJyYXl9IG1pZGRsZXdhcmVzIC0gQW4gdW5saW1pdGVkIG51bWJlciBvZiBtaWRkbGV3YXJlcyB0byB1c2VcbiAqIGFnYWluc3QgdGhlIHNwZWNpZmljIGVuZHBvaW50LlxuICovXG5leHBvcnQgY29uc3QgdXNlID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xufTtcblxuLyoqXG4gKiBBZGRzIGEgZ2V0IHJvdXRlIHRvIHRoZSBzZXJ2ZXIuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IHBhdGggLSBBbiBlbmRwb2ludCBwYXRoIHRvIGFkZCBtaWRkbGV3YXJlcyB0by5cbiAqIEBwYXJhbSB7QXJyYXl9IG1pZGRsZXdhcmVzIC0gQW4gdW5saW1pdGVkIG51bWJlciBvZiBtaWRkbGV3YXJlcyB0byB1c2VcbiAqIGFnYWluc3QgdGhlIHNwZWNpZmljIGVuZHBvaW50IGZvciBHRVQgbWV0aG9kLlxuICovXG5leHBvcnQgY29uc3QgZ2V0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xufTtcblxuLyoqXG4gKiBBZGRzIGEgcG9zdCByb3V0ZSB0byB0aGUgc2VydmVyLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBwYXRoIC0gQW4gZW5kcG9pbnQgcGF0aCB0byBhZGQgbWlkZGxld2FyZXMgdG8uXG4gKiBAcGFyYW0ge0FycmF5fSBtaWRkbGV3YXJlcyAtIEFuIHVubGltaXRlZCBudW1iZXIgb2YgbWlkZGxld2FyZXMgdG8gdXNlXG4gKiBhZ2FpbnN0IHRoZSBzcGVjaWZpYyBlbmRwb2ludCBmb3IgUE9TVCBtZXRob2QuXG4gKi9cbmV4cG9ydCBjb25zdCBwb3N0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XG4gIGFwcC5wb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcbn07XG5cbi8qKlxuICogRm9yY2VmdWxseSBlbmFibGVzIHJhdGUgbGltaXRpbmcuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGxpbWl0Q29uZmlnIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGZvciB0aGUgcmF0ZSBsaW1pdGVyXG4gKiBjb25maWd1cmF0aW9uLlxuICovXG5leHBvcnQgY29uc3QgZW5hYmxlUmF0ZUxpbWl0aW5nID0gKGxpbWl0Q29uZmlnKSA9PiB7XG4gIHJldHVybiByYXRlTGltaXQoYXBwLCBsaW1pdENvbmZpZyk7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIHN0YXJ0U2VydmVyLFxuICBnZXRFeHByZXNzLFxuICBnZXRBcHAsXG4gIHVzZSxcbiAgZ2V0LFxuICBwb3N0LFxuICBlbmFibGVSYXRlTGltaXRpbmdcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XG4vKipcbiAqIEFkZHMgdGhlIC8gcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIGZvciB0aGUgZXhwb3J0IHNlcnZlclxuICovXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxuICAhYXBwXG4gICAgPyBmYWxzZVxuICAgIDogYXBwLmdldCgnLycsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJykpO1xuICAgICAgfSk7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IGNhY2hlIGZyb20gJy4uLy4uL2NhY2hlLmpzJztcblxuLyoqXG4gKiBBZGRzIGEgcm91dGUgdGhhdCBjYW4gYmUgdXNlZCB0byBjaGFuZ2UgdGhlIEhDIHZlcnNpb24gb24gdGhlIHNlcnZlclxuICogVE9ETzogQWRkIGF1dGggdG9rZW4gYW5kIGNvbm5lY3QgdG8gQVBJXG4gKi9cbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XG4gICFhcHBcbiAgICA/IGZhbHNlXG4gICAgOiBhcHAucG9zdCgnL2NoYW5nZV9oY192ZXJzaW9uLzpuZXdWZXJzaW9uJywgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gICAgICAgIGNvbnN0IGN0b2tlbiA9IHByb2Nlc3MuZW52LkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XG5cbiAgICAgICAgaWYgKCFjdG9rZW4gfHwgIWN0b2tlbi5sZW5ndGgpIHtcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZCh7XG4gICAgICAgICAgICBlcnJvcjogdHJ1ZSxcbiAgICAgICAgICAgIG1lc3NhZ2U6XG4gICAgICAgICAgICAgICdTZXJ2ZXIgbm90IGNvbmZpZ3VyZWQgdG8gZG8gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIG5vdCBzZXQnXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XG5cbiAgICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gY3Rva2VuKSB7XG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoe1xuICAgICAgICAgICAgZXJyb3I6IHRydWUsXG4gICAgICAgICAgICBtZXNzYWdlOiAnSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBzZXQgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyJ1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XG5cbiAgICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxuICAgICAgICAgICAgYXdhaXQgY2FjaGUudXBkYXRlVmVyc2lvbihuZXdWZXJzaW9uKTtcbiAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICByZXNwb25zZS5zZW5kKHtcbiAgICAgICAgICAgICAgZXJyb3I6IHRydWUsXG4gICAgICAgICAgICAgIG1lc3NhZ2U6IGVcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJlc3BvbnNlLnNlbmQoe1xuICAgICAgICAgICAgdmVyc2lvbjogY2FjaGUudmVyc2lvbigpXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmVzcG9uc2Uuc2VuZCh7XG4gICAgICAgICAgICBlcnJvcjogdHJ1ZSxcbiAgICAgICAgICAgIG1lc3NhZ2U6ICdObyBuZXcgdmVyc2lvbiBzdXBwbGllZCdcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjMsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuLy8gQWRkIHRoZSBtYWluIGRpcmVjdG9yeSBpbiB0aGUgZ2xvYmFsIG9iamVjdFxuaW1wb3J0ICdjb2xvcnMnO1xuXG5pbXBvcnQgc2VydmVyLCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcbmltcG9ydCB7XG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcbiAgYmF0Y2hFeHBvcnQsXG4gIHNpbmdsZUV4cG9ydCxcbiAgc3RhcnRFeHBvcnRcbn0gZnJvbSAnLi9jaGFydC5qcyc7XG5pbXBvcnQgeyBtYXBUb05ld0NvbmZpZywgc2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcbmltcG9ydCB7IGxvZywgc2V0TG9nTGV2ZWwsIGVuYWJsZUZpbGVMb2dnaW5nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsga2lsbFBvb2wsIGluaXQgfSBmcm9tICcuL3Bvb2wuanMnO1xuaW1wb3J0IHsgY2hlY2tDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGxvZyxcbiAgbWFwVG9OZXdDb25maWcsXG4gIHNldE9wdGlvbnMsXG4gIHNpbmdsZUV4cG9ydCxcbiAgc3RhcnRFeHBvcnQsXG4gIGJhdGNoRXhwb3J0LFxuICBzZXJ2ZXIsXG4gIHN0YXJ0U2VydmVyLFxuICBraWxsUG9vbCxcbiAgaW5pdFBvb2w6IGFzeW5jIChvcHRpb25zID0ge30pID0+IHtcbiAgICAvLyBTZXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBwZXIgZXhwb3J0IG1vZHVsZSBzY29wZVxuICAgIHNldEFsbG93Q29kZUV4ZWN1dGlvbihcbiAgICAgIG9wdGlvbnMuY3VzdG9tQ29kZSAmJiBvcHRpb25zLmN1c3RvbUNvZGUuYWxsb3dDb2RlRXhlY3V0aW9uXG4gICAgKTtcblxuICAgIC8vIFNldCB0aGUgbG9nIGxldmVsXG4gICAgc2V0TG9nTGV2ZWwob3B0aW9ucy5sb2dnaW5nICYmIHBhcnNlSW50KG9wdGlvbnMubG9nZ2luZy5sZXZlbCkpO1xuXG4gICAgLy8gU2V0IHRoZSBsb2cgZmlsZSBwYXRoIGFuZCBuYW1lXG4gICAgaWYgKG9wdGlvbnMubG9nZ2luZyAmJiBvcHRpb25zLmxvZ2dpbmcuZGVzdCkge1xuICAgICAgZW5hYmxlRmlsZUxvZ2dpbmcoXG4gICAgICAgIG9wdGlvbnMubG9nZ2luZy5kZXN0LFxuICAgICAgICBvcHRpb25zLmxvZ2dpbmcuZmlsZSB8fCAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZydcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxuICAgIGF3YWl0IGNoZWNrQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzIHx8IHsgdmVyc2lvbjogJ2xhdGVzdCcgfSk7XG5cbiAgICAvLyBJbml0IHRoZSBwb29sXG4gICAgYXdhaXQgaW5pdCh7XG4gICAgICBwb29sOiBvcHRpb25zLnBvb2wgfHwge1xuICAgICAgICBpbml0aWFsV29ya2VyczogMSxcbiAgICAgICAgbWF4V29ya2VyczogMVxuICAgICAgfSxcbiAgICAgIHB1cHBldGVlckFyZ3M6IG9wdGlvbnMucHVwcGV0ZWVyPy5hcmdzIHx8IFtdXG4gICAgfSk7XG5cbiAgICAvLyBSZXR1cm4gdXBkYXRlZCBvcHRpb25zXG4gICAgcmV0dXJuIG9wdGlvbnM7XG4gIH1cbn07XG4iXSwibmFtZXMiOlsiZG90ZW52IiwiY29uZmlnIiwiZGVmYXVsdENvbmZpZyIsInB1cHBldGVlciIsImFyZ3MiLCJ2YWx1ZSIsInR5cGUiLCJkZXNjcmlwdGlvbiIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiZW52TGluayIsImNkblVSTCIsImNvcmVTY3JpcHRzIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJzY3JpcHRzIiwiZm9yY2VGZXRjaCIsImV4cG9ydCIsImluZmlsZSIsImluc3RyIiwib3B0aW9ucyIsIm91dGZpbGUiLCJjb25zdHIiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImdsb2JhbE9wdGlvbnMiLCJ0aGVtZU9wdGlvbnMiLCJiYXRjaCIsImN1c3RvbUNvZGUiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJhbGxvd0ZpbGVSZXNvdXJjZXMiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJjcmVhdGVDb25maWciLCJzZXJ2ZXIiLCJlbmFibGUiLCJjbGlOYW1lIiwiaG9zdCIsInBvcnQiLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwicG9vbCIsImluaXRpYWxXb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsInF1ZXVlU2l6ZSIsInRpbWVvdXRUaHJlc2hvbGQiLCJhY3F1aXJlVGltZW91dCIsInJlYXBlciIsImJlbmNobWFya2luZyIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibG9nZ2luZyIsImxldmVsIiwiZmlsZSIsImRlc3QiLCJ1aSIsInJvdXRlIiwib3RoZXIiLCJub0xvZ28iLCJwYXlsb2FkIiwiam9pbiIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibGlzdGVuZXJzIiwia2V5Iiwib3B0aW9uIiwiZW50cmllcyIsImxvZyIsIm5ld0xldmVsIiwidGV4dHMiLCJsZW5ndGgiLCJwcmVmaXgiLCJEYXRlIiwidG9TdHJpbmciLCJzcGxpdCIsInRyaW0iLCJmbiIsImV4aXN0c1N5bmMiLCJta2RpclN5bmMiLCJhcHBlbmRGaWxlIiwiY29uY2F0IiwiZXJyb3IiLCJjb25zb2xlIiwiYXBwbHkiLCJ1bmRlZmluZWQiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInNyYyIsImJhc2VVUkkiLCJjbGVhclRleHQiLCJ0ZXh0IiwicnVsZSIsInJlcGxhY2VyIiwicmVwbGFjZUFsbCIsImZpeFR5cGUiLCJmb3JtYXRzIiwib3V0VHlwZSIsInBvcCIsImZpbmQiLCJ0IiwiaGFuZGxlUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiaGFuZGxlZFJlc291cmNlcyIsImNvcnJlY3RSZXNvdXJjZXMiLCJlbmRzV2l0aCIsImlzQ29ycmVjdEpTT04iLCJyZWFkRmlsZVN5bmMiLCJub3RpY2UiLCJmaWxlcyIsInByb3BOYW1lIiwibWFwIiwiaXRlbSIsImRhdGEiLCJwYXJzZWREYXRhIiwiSlNPTiIsInBhcnNlIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwibmFtZSIsInN0YXJ0c1dpdGgiLCJwcmludFVzYWdlIiwiYm9sZCIsInllbGxvdyIsImN5Y2xlQ2F0ZWdvcmllcyIsImNhdGVnb3JpZXMiLCJkZXNjTmFtZSIsImdyZWVuIiwiaSIsImJsdWUiLCJjYXRlZ29yeSIsInRvVXBwZXJDYXNlIiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJyYXRlTGltaXQiLCJhcHAiLCJsaW1pdENvbmZpZyIsIm1zZyIsInJhdGVPcHRpb25zIiwibWF4IiwibGltaXRlciIsIndpbmRvd01zIiwiZGVsYXlNcyIsImhhbmRsZXIiLCJyZXF1ZXN0IiwicmVzcG9uc2UiLCJmb3JtYXQiLCJqc29uIiwic3RhdHVzIiwic2VuZCIsIm1lc3NhZ2UiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiYXN5bmMiLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJwcm90b2NvbCIsImh0dHBzIiwiaHR0cCIsImdldFByb3RvY29sIiwiZ2V0IiwicmVzIiwib24iLCJjaHVuayIsImNhY2hlUGF0aCIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiYXBwbGllZENvbmZpZyIsImV4dHJhY3RWZXJzaW9uIiwic3Vic3RyIiwiaW5kZXhPZiIsImZldGNoU2NyaXB0Iiwic2NyaXB0IiwicHJveHlBZ2VudCIsImFnZW50IiwidGltZW91dCIsInByb2Nlc3MiLCJlbnYiLCJzdGF0dXNDb2RlIiwidXBkYXRlQ2FjaGUiLCJzb3VyY2VQYXRoIiwiY3VzdG9tU2NyaXB0cyIsImFsbFNjcmlwdHMiLCJjIiwibSIsInByb3h5SG9zdCIsInByb3h5UG9ydCIsIkh0dHBzUHJveHlBZ2VudCIsImZldGNoZWRNb2R1bGVzIiwiYWxsIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJjYWNoZSQxIiwibmV3VmVyc2lvbiIsImFzc2lnbiIsIlJBTkRPTV9QSUQiLCJyYW5kb21CeXRlcyIsIlBVUFBFVEVFUl9ESVIiLCJwYXRoIiwibWluaW1hbEFyZ3MiLCJ0ZW1wbGF0ZSIsImZzIiwiYnJvd3NlciIsIm5ld1BhZ2UiLCJwIiwic2V0Q29udGVudCIsImFkZFNjcmlwdFRhZyIsImV2YWx1YXRlIiwic2V0dXBIaWdoY2hhcnRzIiwiZXJyIiwiJGV2YWwiLCJlbGVtZW50IiwiZXJyb3JNZXNzYWdlIiwiX2Rpc3BsYXlFcnJvcnMiLCJpbm5lckhUTUwiLCJjbG9zZSIsImNvbm5lY3RlZCIsIl9fYmFzZWRpciIsInNldEFzQ29uZmlnIiwicGFnZSIsImNoYXJ0IiwidHJpZ2dlckV4cG9ydCIsInB1cHBldGVlckV4cG9ydCIsImluamVjdGVkUmVzb3VyY2VzIiwiY2xlYXJJbmplY3RlZCIsImRpc3Bvc2UiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsInJlbW92ZSIsImV4cG9ydEJlbmNoIiwiZXhwb3J0T3B0aW9ucyIsInJlcXVlc3RBbmltYXRpb25GcmFtZSIsImRpc3BsYXlFcnJvcnMiLCJkZWJ1Z2dlciIsImQiLCJzdmdCZW5jaCIsImlzU1ZHIiwic2V0UGFnZUJlbmNoIiwic3ZnVGVtcGxhdGUiLCJzdHJJbmoiLCJzZXRDb250ZW50QmVuY2giLCJyZXNCZW5jaCIsImpzIiwicHVzaCIsImNvbnRlbnQiLCJpc0xvY2FsIiwiY3NzQmVuY2giLCJjc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiYWRkU3R5bGVUYWciLCJzaXplIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsInBhcnNlRmxvYXQiLCJIaWdoY2hhcnRzIiwiY2hhcnRzIiwidnBCZW5jaCIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsInpvb21DYWxsYmFjayIsImJvZHkiLCJzdHlsZSIsInpvb20iLCJtYXJnaW4iLCJ4IiwieSIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInRydW5jIiwiZ2V0Q2xpcFJlZ2lvbiIsInJvdW5kIiwiZXhwQmVuY2htYXJrIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJvbWl0QmFja2dyb3VuZCIsInNldFRpbWVvdXQiLCJFcnJvciIsImNyZWF0ZUltYWdlIiwicGRmIiwiY3JlYXRlUERGIiwib2xkQ2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2hpZnQiLCJwdXBwZXRlZXJBcmdzIiwicGVyZm9ybWVkRXhwb3J0cyIsImV4cG9ydEF0dGVtcHRzIiwidGltZVNwZW50IiwiZHJvcHBlZEV4cG9ydHMiLCJzcGVudEF2ZXJhZ2UiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInMiLCJnZXRUaW1lIiwiYnJvd3Nlck5ld1BhZ2UiLCJpc0Nsb3NlZCIsIndvcmtDb3VudCIsInJhbmRvbSIsInZhbGlkYXRlIiwid29ya2VySGFuZGxlIiwibG9nTGV2ZWwiLCJpbml0IiwiYWxsQXJncyIsInRyeUNvdW50Iiwib3BlbiIsImxhdW5jaCIsImhlYWRsZXNzIiwidXNlckRhdGFEaXIiLCJlIiwiY3JlYXRlQnJvd3NlciIsImtpbGxQb29sIiwiY29kZSIsImV4aXQiLCJQb29sIiwibWluIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImRlc3Ryb3lUaW1lb3V0TWlsbGlzIiwiaWRsZVRpbWVvdXRNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsImV2ZW50SWQiLCJyZXNvdXJjZSIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsImZhaWwiLCJnZXRQb29sSW5mbyIsIndvcmtTdGFydCIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJhdmFpbGFibGUiLCJib3Jyb3dlZCIsInBlbmRpbmciLCJzcGFyZVJlc291cmNlQ2FwYWNpdHkiLCJwb29sJDEiLCJwYWNrYWdlVmVyc2lvbiIsIm5wbV9wYWNrYWdlX3ZlcnNpb24iLCJzZXJ2ZXJTdGFydFRpbWUiLCJnZW5lcmFsT3B0aW9ucyIsImdldE9wdGlvbnMiLCJtZXJnZUNvbmZpZ09wdGlvbnMiLCJuZXdPcHRpb25zIiwibWVyZ2VkT3B0aW9ucyIsInVwZGF0ZURlZmF1bHRDb25maWciLCJjb25maWdPYmoiLCJjdXN0b21PYmoiLCJjdXN0b21WYWx1ZSIsIm51bUVudlZhbCIsImVsIiwiaW5pdE9wdGlvbnMiLCJpdGVtcyIsInN0YXJ0RXhwb3J0Iiwic2V0dGluZ3MiLCJlbmRDYWxsYmFjayIsInN2ZyIsImluaXRFeHBvcnRTZXR0aW5ncyIsImV4cG9ydEFzU3RyaW5nIiwicmVhZEZpbGUiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwiZXhwb3J0aW5nIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJjaGFydEpzb24iLCJjdXN0b21Db2RlT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsImVuYWJsZWQiLCJvcHRpb25zTmFtZSIsInRoZW4iLCJjYXRjaCIsInJlcXVlc3RJZCIsInN0cmluZ1RvRXhwb3J0IiwiY2hhcnRKU09OIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0YXJ0IiwiaHJ0aW1lIiwiYmlnaW50IiwibWVhc3VyZVRpbWUiLCJkZWZhdWx0T3B0aW9ucyIsImhlYWRlcnMiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwidG9Mb3dlckNhc2UiLCJiNjQiLCJkYXRhT3B0aW9ucyIsIm5vRG93bmxvYWQiLCJpcFJlZ0V4IiwiaW5mbyIsInJlbW92ZUFsbExpc3RlbmVycyIsIkJ1ZmZlciIsImZyb20iLCJoZWFkZXIiLCJhdHRhY2htZW50IiwicGFyYW1zIiwiZmlsZW5hbWUiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkc1NpemUiLCJhbnkiLCJib2R5UGFyc2VyIiwibGltaXQiLCJ1cmxlbmNvZGVkIiwiZXh0ZW5kZWQiLCJlcnJvckhhbmRsZXIiLCJhdHRhY2hFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwiY2VydCIsImZzUHJvbWlzZXMiLCJwb3NpeCIsImh0dHBzU2VydmVyIiwiTmFOIiwic3RhdGljIiwiYm9vdFRpbWUiLCJ1cHRpbWUiLCJmbG9vciIsImhpZ2hjaGFydHNWZXJzaW9uIiwiYXZlcmFnZVByb2Nlc3NpbmdUaW1lIiwiZmFpbGVkRXhwb3J0cyIsInN1Y2Vzc1JhdGlvIiwiaGVhbHRoUm91dGUiLCJwb3N0IiwiZXhwb3J0Um91dGVzIiwic2VuZEZpbGUiLCJ1aVJvdXRlIiwiY3Rva2VuIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsInRva2VuIiwidnN3aXRjaFJvdXRlIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiaW5kZXgiLCJtYXBUb05ld0NvbmZpZyIsIm9sZE9wdGlvbnMiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJyZWR1Y2UiLCJwcm9wIiwic2V0T3B0aW9ucyIsInVzZXJPcHRpb25zIiwiY29uZmlnSW5kZXgiLCJmaW5kSW5kZXgiLCJhcmciLCJmaWxlTmFtZSIsImxvYWRDb25maWdGaWxlIiwicGFpckFyZ3VtZW50VmFsdWUiLCJzaW5nbGVFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsImluaXRQb29sIiwicGFyc2VJbnQiLCJsb2dEZXN0IiwibG9nRmlsZSIsImVuYWJsZUZpbGVMb2dnaW5nIl0sIm1hcHBpbmdzIjoiNnVCQWlCQUEsRUFBT0MsU0FJQSxNQUFNQyxFQUFnQixDQUMzQkMsVUFBVyxDQUNUQyxLQUFNLENBQ0pDLE1BQU8sR0FDUEMsS0FBTSxXQUNOQyxZQUFhLDZDQUdqQkMsV0FBWSxDQUNWQyxRQUFTLENBQ1BKLE1BQU8sU0FDUEssUUFBUyxxQkFDVEosS0FBTSxTQUNOQyxZQUFhLDhCQUVmSSxPQUFRLENBQ05O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 diff --git a/dist/index.esm.js b/dist/index.esm.js index 5687f6d0..d17d1a14 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import e,{existsSync as t,mkdirSync as o,appendFile as r,readFileSync as i,writeFileSync as n,readFile as s,promises as a}from"fs";import l,{join as c,posix as p}from"path";import u from"body-parser";import d from"cors";import h from"express";import g from"multer";import m from"http";import f from"https";import v from"dotenv";import y from"express-rate-limit";import*as b from"url";import{fileURLToPath as w}from"url";import T from"https-proxy-agent";import{v4 as x}from"uuid";import{Pool as k}from"tarn";import S from"puppeteer";import H from"node:path";import{randomBytes as E}from"node:crypto";import"prompts";v.config();const R={puppeteer:{args:{value:[],type:"string[]",description:"Array of arguments to send to puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"Highcharts version to use."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN",type:"string",description:"The CDN URL of Highcharts scripts to use."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"Highcharts core scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","draggable-points","static-scale","broken-axis","heatmap","tilemap","timeline","treemap","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","pyramid3d","networkgraph","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","stock-tools","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi"],type:"string[]",description:"Highcharts modules to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"Highcharts indicators to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional direct scripts/optional dependencies (e.g. moment.js)."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"Should all the scripts be refetched after rerunning the server."}},export:{infile:{value:!1,type:"string",description:"The input file name along with a type (json or svg). It can be a correct JSON or SVG file."},instr:{value:!1,type:"string",description:"An input in a form of a stringified JSON or SVG file. Overrides the --infile."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf or svg). Ignores the --type flag."},type:{envLink:"EXPORT_DEFAULT_TYPE",value:"png",type:"string",description:"The format of the file to export to. Can be jpeg, png, pdf or svg."},constr:{envLink:"EXPORT_DEFAULT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"The default height of the exported chart. Used when not found any value set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when not found any value set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Ranges between 1 and 5."},height:{type:"number",value:!1,description:"The default height of the exported chart. Overrides the option in the chart settings."},width:{type:"number",value:!1,description:"The width of the exported chart. Overrides the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart. Ranges between 1 and 5."},globalOptions:{value:!1,type:"string",description:"A stringified JSON or a filename with options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"A stringified JSON or a filename with theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Starts a batch job. A string that contains input/output pairs: "in=out;in=out;..".'}},customCode:{allowCodeExecution:{envLink:"HIGHCHARTS_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"If set to true, allow for the execution of arbitrary code when exporting."},allowFileResources:{envLink:"HIGHCHARTS_ALLOW_FILE_RESOURCES",value:!0,type:"boolean",description:"Allow injecting resources from the filesystem. Has no effect when running as a server."},customCode:{value:!1,type:"string",description:"A function to be called before chart initialization. Can be a filename with the js extension."},callback:{value:!1,type:"string",description:"A JavaScript file with a function to run on construction."},resources:{value:!1,type:"string",description:"An additional resource in a form of stringified JSON. It can contain files, js and css sections."},loadConfig:{value:!1,type:"string",description:"A file that contains a pre-defined config to use."},createConfig:{value:!1,type:"string",description:"Allows to set options through a prompt and save in a provided config file."}},server:{enable:{envLink:"HIGHCHARTS_SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"If set to true, starts a server on 0.0.0.0."},host:{envLink:"HIGHCHARTS_SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Also starts a server listening on the supplied hostname."},port:{envLink:"HIGHCHARTS_SERVER_PORT",value:7801,type:"number",description:"The port to use for the server. Defaults to 7801."},ssl:{enable:{envLink:"HIGHCHARTS_SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables the SSL protocol."},force:{envLink:"HIGHCHARTS_SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",description:"If set to true, forces the server to only serve over HTTPS."},port:{envLink:"HIGHCHARTS_SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"HIGHCHARTS_SSL_CERT_PATH",value:"",type:"string",description:"The path to the SSL certificate/key."}},rateLimiting:{enable:{envLink:"HIGHCHARTS_RATE_LIMIT_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting."},maxRequests:{envLink:"HIGHCHARTS_RATE_LIMIT_MAX",value:10,type:"number",description:"Max requests allowed in a one minute."},window:{envLink:"HIGHCHARTS_RATE_LIMIT_WINDOW",value:1,type:"number",description:"The time window in minutes for rate limiting."},delay:{envLink:"HIGHCHARTS_RATE_LIMIT_DELAY",value:0,type:"number",description:"The amount to delay each successive request before hitting the max."},trustProxy:{envLink:"HIGHCHARTS_RATE_LIMIT_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if behind a load balancer."},skipKey:{envLink:"HIGHCHARTS_RATE_LIMIT_SKIP_KEY",value:"",type:"number|string",description:"Allows bypassing the rate limiter and should be provided with skipToken argument."},skipToken:{envLink:"HIGHCHARTS_RATE_LIMIT_SKIP_TOKEN",value:"",type:"number|string",description:"Allows bypassing the rate limiter and should be provided with skipKey argument."}}},pool:{initialWorkers:{envLink:"HIGHCHARTS_POOL_MIN_WORKERS",value:4,type:"number",description:"The number of initial workers to spawn."},maxWorkers:{envLink:"HIGHCHARTS_POOL_MAX_WORKERS",value:8,type:"number",description:"The number of max workers to spawn."},workLimit:{envLink:"HIGHCHARTS_POOL_WORK_LIMIT",value:40,type:"number",description:"The pieces of work that can be performed before restarting process."},queueSize:{envLink:"HIGHCHARTS_POOL_QUEUE_SIZE",value:5,type:"number",description:"The size of the request overflow queue."},timeoutThreshold:{envLink:"HIGHCHARTS_POOL_TIMEOUT",value:5e3,type:"number",description:"The number of milliseconds before timing out."},acquireTimeout:{envLink:"HIGHCHARTS_POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The number of milliseconds to wait for acquiring a resource."},reaper:{envLink:"HIGHCHARTS_POOL_ENABLE_REAPER",value:!0,type:"boolean",description:"Whether or not to evict workers after a certain time period."},benchmarking:{envLink:"HIGHCHARTS_POOL_BENCHMARKING",value:!1,type:"boolean",description:"Enable benchmarking."},listenToProcessExits:{envLink:"HIGHCHARTS_POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Set to false in order to skip attaching process.exit handlers."}},logging:{level:{envLink:"HIGHCHARTS_LOG_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose)."},file:{envLink:"HIGHCHARTS_LOG_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"A name of a log file. The --logDest also needs to be set to enable file logging."},dest:{envLink:"HIGHCHARTS_LOG_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. Also enables file logging."}},ui:{enable:{envLink:"HIGHCHARTS_UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables the UI for the export server."},route:{envLink:"HIGHCHARTS_UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The route to attach the UI to."}},other:{noLogo:{envLink:"HIGHCHARTS_NO_LOGO",value:!1,type:"boolean",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}},payload:{}};R.puppeteer.args.value.join(","),R.highcharts.version.value,R.highcharts.cdnURL.value,R.highcharts.modules.value,R.highcharts.scripts.value.join(","),R.highcharts.forceFetch.value,R.export.type.value,R.export.constr.value,R.export.defaultHeight.value,R.export.defaultWidth.value,R.export.defaultScale.value,R.customCode.allowCodeExecution.value,R.customCode.allowFileResources.value,R.server.enable.value,R.server.host.value,R.server.port.value,R.server.ssl.enable.value,R.server.ssl.force.value,R.server.ssl.port.value,R.server.ssl.certPath.value,R.server.rateLimiting.enable.value,R.server.rateLimiting.maxRequests.value,R.server.rateLimiting.window.value,R.server.rateLimiting.delay.value,R.server.rateLimiting.trustProxy.value,R.server.rateLimiting.skipKey.value,R.server.rateLimiting.skipToken.value,R.pool.initialWorkers.value,R.pool.maxWorkers.value,R.pool.workLimit.value,R.pool.queueSize.value,R.pool.timeoutThreshold.value,R.pool.acquireTimeout.value,R.pool.reaper.value,R.pool.benchmarking.value,R.pool.listenToProcessExits.value,R.logging.level.value,R.logging.file.value,R.logging.dest.value,R.ui.enable.value,R.ui.route.value,R.other.noLogo.value;const L=["options","globalOptions","themeOptions","resources","payload"],C={},O=(e,t="")=>{Object.keys(e).forEach((o=>{if(!["puppeteer","highcharts"].includes(o)){const r=e[o];void 0===r.value?O(r,`${t}.${o}`):C[r.cliName||o]=`${t}.${o}`.substring(1)}}))};O(R);let _={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:"red"},{title:"warning",color:"yellow"},{title:"notice",color:"blue"},{title:"verbose",color:"gray"}],listeners:[]};for(const[e,t]of Object.entries(R.logging))_[e]=t.value;const A=(...e)=>{const[i,...n]=e,{level:s,levelsDesc:a}=_;if(0===i||i>s||s>a.length)return;const l=`${(new Date).toString().split("(")[0].trim()} [${a[i-1].title}] -`;_.listeners.forEach((e=>{e(l,n.join(" "))})),_.toFile&&(_.pathCreated||(!t(_.dest)&&o(_.dest),_.pathCreated=!0),r(`${_.dest}${_.file}`,[l].concat(n).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),_.toFile=!1)}))),_.toConsole&&console.log.apply(void 0,[l.toString()[_.levelsDesc[i-1].color]].concat(n))},$=w(new URL("../.",import.meta.url)),I=(e,t=/\s\s+/g,o=" ")=>e.replaceAll(t,o).trim(),P=(e,t)=>{const o=["png","jpeg","pdf","svg"];if(t){const r=t.split(".").pop();o.includes(r)&&e!==r&&(e=r)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||o.find((t=>t===e))||"png"},j=(e=!1,t)=>{const o=["js","css","files"];let r=e,n=!1;if(t&&e.endsWith(".json"))try{e?e&&e.endsWith(".json")?r=N(i(e,"utf8")):(r=N(e),!0===r&&(r=N(i("resources.json","utf8")))):r=N(i("resources.json","utf8"))}catch(e){return A(3,"[cli] No resources found.")}else r=N(e),t||delete r.files;for(const e in r)o.includes(e)?n||(n=!0):delete r[e];return n?(r.files&&(r.files=r.files.map((e=>e.trim())),(!r.files||r.files.length<=0)&&delete r.files),r):A(3,"[cli] No resources found.")};function N(e,t){try{const o=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof o&&t?JSON.stringify(o):o}catch(e){return!1}}const G=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=G(e[o]));return t},U=(e,t)=>JSON.stringify(e,((e,o)=>("string"==typeof o&&((o=o.trim()).startsWith("function(")||o.startsWith("function ("))&&o.endsWith("}")&&(o=t?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof o?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:o))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function W(){console.log("Usage of CLI arguments:".bold,"\n------",`\nFor more detailed information visit readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[o,r]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(r,"value")){let e=` --${r.cliName||o} ${("<"+r.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,r.description,`[Default: ${r.value.toString().bold}]`.blue)}else e(r)};Object.keys(R).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(R[t]))})),console.log("\n")}const F=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,M=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&M(i(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")};var q=(e,t)=>{const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const i=y({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(A(4,"[rate-limiting] Skipping rate limiter."),!0)});e.use(i),A(3,I(`[rate-limiting] Enabled rate limiting: ${r.max} requests\n per ${r.window} minute per IP, trusting proxy:\n ${r.trustProxy}.`))};async function D(e,t={}){return new Promise(((o,r)=>{const i=(e=>e.startsWith("https")?f:m)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}v.config();const V=c($,".cache"),J={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let z=!1;const K=()=>J.hcVersion=J.sources.substr(0,J.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),X=async(e,t)=>{try{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),A(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},r=await D(`${e}.js`,o);if(200===r.statusCode)return r.text;throw`${r.statusCode}`}catch(t){throw A(1,`[cache] Error fetching script ${e}.js: ${t}.`),t}},B=async(e,t)=>{const{coreScripts:o,modules:r,indicators:i,scripts:s}=e,a="latest"!==e.version&&e.version?`${e.version}/`:"";A(3,"[cache] Updating cache to Highcharts ",a);const l=[...o.map((e=>`${a}${e}`)),...r.map((e=>"map"===e?`maps/${a}modules/${e}`:`${a}modules/${e}`)),...i.map((e=>`stock/${a}indicators/${e}`))];let c;const p=process.env.PROXY_SERVER_HOST,u=process.env.PROXY_SERVER_PORT;p&&u&&(c=new T({host:p,port:+u}));const d={};try{return J.sources=(await Promise.all([...l.map((async t=>{const o=await X(`${e.cdnURL||J.cdnURL}${t}`,c);return"string"==typeof o&&(d[t.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1),o})),...s.map((e=>X(e,c)))])).join(";\n"),K(),n(t,J.sources),d}catch(e){A(1,"[cache] Unable to update local Highcharts cache.")}},Y=async e=>{let r;const s=c(V,"manifest.json"),a=c(V,"sources.js");if(z=e,!t(V)&&o(V),!t(s)||e.forceFetch)A(3,"[cache] Fetching and caching Highcharts dependencies."),r=await B(e,a);else{let t=!1;const o=JSON.parse(i(s));if(o.modules&&Array.isArray(o.modules)){const e={};o.modules.forEach((t=>e[t]=1)),o.modules=e}const{modules:n,coreScripts:l,indicators:c}=e,p=n.length+l.length+c.length;o.version!==e.version?(A(3,"[cache] Highcharts version mismatch in cache, need to re-fetch."),t=!0):Object.keys(o.modules||{}).length!==p?(A(3,"[cache] Cache and requested modules does not match, need to re-fetch."),t=!0):t=(e.modules||[]).some((e=>{if(!o.modules[e])return A(3,`[cache] The ${e} missing in cache, need to re-fetch.`),!0})),t?r=await B(e,a):(A(3,"[cache] Dependency cache is up to date, proceeding."),J.sources=i(a,"utf8"),r=o.modules,K())}await(async(e,t)=>{const o={version:e.version,modules:t||{}};J.activeManifest=o,A(4,"[cache] writing new manifest");try{n(c(V,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){A(1,`[cache] Error writing cache manifest: ${e}.`)}})(e,r)};var Q=async e=>!!z&&await Y(Object.assign(z,{version:e})),Z=()=>J,ee=()=>J.hcVersion;const te=E(64).toString("base64url"),oe=H.join("tmp",`puppeteer-${te}`),re=[`--user-data-dir=${H.join(oe,"profile")}`,"--autoplay-policy=user-gesture-required","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-client-side-phishing-detection","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=AudioServiceOutOfProcess","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-speech-api","--disable-sync","--hide-crash-restore-bubble","--hide-scrollbars","--ignore-gpu-blacklist","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-zygote","--password-store=basic","--use-mock-keychain"],ie=b.fileURLToPath(new URL(".",import.meta.url)),ne=e.readFileSync(ie+"/../templates/template.html","utf8");let se;const ae=async()=>{if(!se)return!1;const e=await se.newPage();return await e.setContent(ne),await e.addScriptTag({path:ie+"/../.cache/sources.js"}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{A(1,"[page error]",t),await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)})),e},le=async()=>{se.connected&&await se.close()};const ce=b.fileURLToPath(new URL(".",import.meta.url)),pe=async(e,t,o)=>await e.evaluate(((e,t)=>window.triggerExport(e,t)),t,o);var ue=async(e,t,o)=>{const r=[],n=async e=>{for(const e of r)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))};try{const s=()=>{};A(4,"[export] Determining export path.");const a=o.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const c=a?.options?.chart?.displayErrors&&Z().activeManifest.modules.debugger;await e.evaluate((e=>window._displayErrors=e),c);const p=()=>{};let u;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(A(4,"[export] Treating as SVG."),"svg"===a.type)return t;u=!0;const o=()=>{};await e.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t)),o()}else if(A(4,"[export] Treating as config."),a.strInj){const t=()=>{};await pe(e,{chart:{height:a.height,width:a.width}},o),t()}else{t.chart.height=a.height,t.chart.width=a.width;const r=()=>{};await pe(e,t,o),r()}p();const d=()=>{},h=o.customCode.resources;if(h){if(h.js&&r.push(await e.addScriptTag({content:h.js})),h.files)for(const t of h.files)try{const o=!t.startsWith("http");r.push(await e.addScriptTag(o?{content:i(t,"utf8")}:{url:t}))}catch(e){A(4,"[export] JS file not found.")}const t=()=>{};if(h.css){let t=h.css.match(/@import\s*([^;]*);/g);if(t)for(let i of t)i&&(i=i.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),i.startsWith("http")?r.push(await e.addStyleTag({url:i})):o.customCode.allowFileResources&&r.push(await e.addStyleTag({path:l.join(ce,i)})));r.push(await e.addStyleTag({content:h.css.replace(/@import\s*([^;]*);/g,"")||" "}))}t()}d();const g=u?await e.$eval("#chart-container svg:first-of-type",(async(e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(a.scale)):await e.evaluate((async()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),m=()=>{},f=Math.ceil(g?.chartHeight||a.height),v=Math.ceil(g?.chartWidth||a.width);await e.setViewport({height:f,width:v,deviceScaleFactor:u?1:parseFloat(a.scale)});const y=u?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await e.evaluate(y,parseFloat(a.scale));const{height:b,width:w,x:T,y:x}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}})))(e);let k;u||await e.setViewport({width:Math.round(w),height:Math.round(b),deviceScaleFactor:parseFloat(a.scale)}),m();const S=()=>{};if("svg"===a.type)k=await(async e=>await e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if("png"===a.type||"jpeg"===a.type)k=await(async(e,t,o,r)=>await Promise.race([e.screenshot({type:t,encoding:o,clip:r,omitBackground:!0}),new Promise(((e,t)=>setTimeout((()=>t(new Error("Rasterization timeout"))),1500)))]))(e,a.type,"base64",{width:v,height:f,x:T,y:x});else{if("pdf"!==a.type)throw`Unsupported output format ${a.type}`;k=await(async(e,t,o,r)=>await e.pdf({height:t+1,width:o,encoding:r}))(e,f,v,"base64")}return await e.evaluate((()=>{const e=Highcharts.charts;if(e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()})),S(),s(),await n(e),k}catch(t){return await n(e),A(1,`[export] Error encountered during export: ${t}`),t}};let de,he=0,ge=0,me=0,fe=0,ve=0,ye={},be=!1;const we={create:async()=>{const e=x();let t=!1;const o=(new Date).getTime();try{if(t=await ae(),!t||t.isClosed())throw"invalid page";A(3,`[pool] Successfully created a worker ${e} - took ${(new Date).getTime()-o} ms.`)}catch(e){throw A(1,`[pool] Error creating a new page in pool entry creation! ${e}`),"Error creating page"}return{id:e,page:t,workCount:Math.round(Math.random()*(ye.workLimit/2))}},validate:e=>!(ye.workLimit&&++e.workCount>ye.workLimit)||(A(3,"[pool] Worker failed validation:",`exceeded work limit (limit is ${ye.workLimit})`),!1),destroy:e=>{A(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()},log:(e,t)=>console.log(`${t}: ${e}`)},Te=async e=>{de=e.puppeteerArgs;try{await(async e=>{const t=[...re,...e||[]];if(!se){let e=0;const o=async()=>{try{A(3,"[browser] attempting to get a browser instance (try",e+")"),se=await S.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){A(0,"[browser]",t),++e<25?(A(3,"[browser] failed:",t),await new Promise((e=>setTimeout(e,4e3))),await o()):A(0,"Max retries reached")}};try{await o()}catch(e){return A(0,"[browser] Unable to open browser"),!1}if(!se)return A(0,"[browser] Unable to open browser"),!1}return se})(de)}catch(e){A(0,"[pool|browser]",e)}if(ye=e&&e.pool?{...e.pool}:{},A(3,"[pool] Initializing pool:",`min ${ye.initialWorkers}, max ${ye.maxWorkers}.`),be)return A(4,"[pool] Already initialized, please kill it before creating a new one.");ye.listenToProcessExits&&(A(4,"[pool] Attaching exit listeners to the process."),process.on("exit",(async()=>{await xe()})),process.on("SIGINT",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{A(4,`The ${t} error, message: ${e.message}.`)})));try{be=new k({...we,min:ye.initialWorkers,max:ye.maxWorkers,createRetryIntervalMillis:200,createTimeoutMillis:ye.acquireTimeout,acquireTimeoutMillis:ye.acquireTimeout,destroyTimeoutMillis:ye.acquireTimeout,idleTimeoutMillis:ye.timeoutThreshold,reapIntervalMillis:1e3,propagateCreateError:!1}),be.on("createFail",((e,t)=>{A(1,`[pool] Error when creating worker of an event id ${e}:`,t)})),be.on("acquireFail",((e,t)=>{A(1,`[pool] Error when acquiring worker of an event id ${e}:`,t)})),be.on("destroyFail",((e,t,o)=>{A(1,`[pool] Error when destroying worker of an id ${t.id}, event id ${e}:`,o)})),be.on("release",(e=>{A(4,`[pool] Releasing a worker of an id ${e.id}`)})),be.on("destroySuccess",((e,t)=>{A(4,`[pool] Destroyed a worker of an id ${t.id}`)}));const e=[];for(let t=0;t{be.release(e)})),A(3,`[pool] The pool is ready with ${ye.initialWorkers} initial resources waiting.`)}catch(e){throw A(1,`[pool] Couldn't create the worker pool ${e}`),e}};async function xe(){return A(3,"[pool] Killing all workers."),be.destroyed?(await le(),!0):(await be.destroy(),await le(),!0)}const ke=async(e,t)=>{let o;const r=e=>{throw++fe,o&&be.release(o),"In pool.postWork: "+e};if(A(4,"[pool] Work received, starting to process."),ye.benchmarking&&Se(),++ge,!be)return A(1,"[pool] Work received, but pool has not been started."),r("Pool is not inited but work was posted to it!");try{A(4,"[pool] Acquiring worker"),o=await be.acquire().promise}catch(e){return r(`[pool] Error when acquiring available entry: ${e}`)}if(A(4,"[pool] Acquired worker handle"),!o.page)return r("Resolved worker page is invalid: pool setup is wonky");try{let i=(new Date).getTime();A(4,`[pool] Starting work on pool entry ${o.id}.`);const n=await ue(o.page,e,t);if(n instanceof Error)return"Rasterization timeout"===n.message&&(o.page.close(),o.page=await ae()),r(n);be.release(o);const s=(new Date).getTime()-i;return me+=s,ve=me/++he,A(4,`[pool] Work completed in ${s} ms.`),{data:n,options:t}}catch(e){r(`Error trying to perform puppeteer export: ${e}.`)}};function Se(){const{min:e,max:t,size:o,available:r,borrowed:i,pending:n,spareResourceCapacity:s}=be;A(4,`[pool] The minimum number of resources allowed by pool: ${e}.`),A(4,`[pool] The maximum number of resources allowed by pool: ${t}.`),A(4,`[pool] The number of all resources in pool (free or in use): ${o}.`),A(4,`[pool] The number of resources that are currently available: ${r}.`),A(4,`[pool] The number of resources that are currently acquired: ${i}.`),A(4,`[pool] The number of callers waiting to acquire a resource: ${n}.`),A(4,`[pool] The number of how many more resources can the pool manage/create: ${s}.`)}var He=()=>({min:be.min,max:be.max,size:be.size,available:be.available,borrowed:be.borrowed,pending:be.pending,spareResourceCapacity:be.spareResourceCapacity}),Ee=()=>ge,Re=()=>fe,Le=()=>ve,Ce=()=>he;const Oe=process.env.npm_package_version,_e=new Date;let Ae={};const $e=()=>Ae,Ie=(e,t,o=[])=>{const r=G(e);for(const[e,n]of Object.entries(t))r[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||o.includes(e)||void 0===r[e]?void 0!==n?n:r[e]:Ie(r[e],n,o);var i;return r};function Pe(e,t={},o=""){Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r],n=t&&t[r];let s;void 0===i.value?Pe(i,n,`${o}.${r}`):(void 0!==n&&(i.value=n),i.envLink&&("boolean"===i.type?i.value=F([process.env[i.envLink],i.value].find((e=>e||"false"===e))):"number"===i.type?(s=+process.env[i.envLink],i.value=s>=0?s:i.value):i.type.indexOf("]")>=0&&process.env[i.envLink]?i.value=process.env[i.envLink].split(","):i.value=process.env[i.envLink]||i.value))}}))}function je(e){let t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:je(r);return t}let Ne=!1;const Ge=async(e,t)=>{A(4,"[chart] Starting exporting process.");const o=((e,t={})=>{let o={};return e.svg?(o=G(t),o.export.type=e.type||e.export.type,o.export.scale=e.scale||e.export.scale,o.export.outfile=e.outfile||e.export.outfile,o.payload={svg:e.svg}):o=Ie(t,e,L),o.export.outfile=o.export?.outfile||`chart.${o.export?.type||"png"}`,o})(e,$e()),r=o.export;return o.payload?.svg&&""!==o.payload.svg?Me(o.payload.svg.trim(),o,t):r.infile&&r.infile.length?(A(4,"[chart] Attempting to export from an input file."),s(r.infile,"utf8",((e,r)=>e?A(1,`[chart] Error loading input file: ${e}.`):(o.export.instr=r,Me(o.export.instr.trim(),o,t))))):r.instr&&""!==r.instr||r.options&&""!==r.options?(A(4,"[chart] Attempting to export from a raw input."),F(o.customCode?.allowCodeExecution)?Fe(o,t):"string"==typeof r.instr?Me(r.instr.trim(),o,t):We(o,r.instr||r.options,t)):(A(1,I(`[chart] No input specified.\n ${JSON.stringify(r,void 0," ")}.`)),t&&t(!1,{error:!0,message:"No input specified."}))},Ue=e=>{const{chart:t,exporting:o}=e.export?.options||N(e.export?.instr),r=N(e.export?.globalOptions);let i=e.export?.scale||o?.scale||r?.exporting?.scale||e.export?.defaultScale||1;return i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const o=Math.pow(10,t||0);return Math.round(+e*o)/o})(i,2),{height:e.export?.height||o?.sourceHeight||t?.height||r?.exporting?.sourceHeight||r?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||o?.sourceWidth||t?.width||r?.exporting?.sourceWidth||r?.chart?.width||e.export?.defaultWidth||600,scale:i}},We=(e,t,o,r)=>{let{export:n,customCode:s}=e;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:Ne;if(s){if("string"==typeof e.customCode.resources)e.customCode.resources=j(e.customCode.resources,F(e.customCode.allowFileResources));else if(!e.customCode.resources)try{const t=i("resources.json","utf8");e.customCode.resources=j(t,F(e.customCode.allowFileResources))}catch(e){A(3,"[chart] The default resources.json file not found.")}}else s=e.customCode={};if(!a&&s){if(s.callback||s.resources||s.customCode)return o&&o(!1,{error:!0,message:I("The callback, resources and customCode have been disabled for this\n server.")});s.callback=!1,s.resources=!1,s.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=P(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{n&&n[e]&&("string"==typeof n[e]&&n[e].endsWith(".json")?n[e]=N(i(n[e],"utf8"),!0):n[e]=N(n[e],!0))}catch(t){n[e]={},A(1,`[chart] The ${e} not found.`)}})),s.allowCodeExecution&&(s.customCode=M(s.customCode,s.allowFileResources)),s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=i(s.callback,"utf8")}catch(e){A(2,`[chart] Error loading callback: ${e}.`),s.callback=!1}else s.callback=!1;e.export={...e.export,...Ue(e)},ke(n.strInj||t||r,e).then((e=>o(e))).catch((e=>(A(0,"[chart] When posting work:",e),o(!1,e))))},Fe=(e,t)=>{try{let o,r=e.export.instr||e.export.options;return"string"!=typeof r&&(o=r=U(r,e.customCode?.allowCodeExecution)),o=r.replaceAll(/\t|\n|\r/g,"").trim(),";"===o[o.length-1]&&(o=o.substring(0,o.length-1)),e.export.strInj=o,We(e,!1,t)}catch(o){const r=I(`Malformed input detected for ${e.export?.requestId||"?"}:\n Please make sure that your JSON/JavaScript options\n are sent using the "options" attribute, and that if you're using\n SVG, it is unescaped.`);return A(1,r),t&&t(!1,JSON.stringify({error:!0,message:r}))}},Me=(e,t,o)=>{const{allowCodeExecution:r}=t.customCode;if(e.indexOf("=0||e.indexOf("=0)return A(4,"[chart] Parsing input as SVG."),We(t,!1,o,e);try{const r=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return We(t,r,o)}catch(e){return F(r)?Fe(t,o):o&&o(!1,{error:!0,message:I("Only JSON configurations and SVG is allowed for this server. If\n this is your server, JavaScript exporting can be enabled by starting\n the server with the --allowCodeExecution flag.")})}},qe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let De=0;const Ve=[],Je=[],ze=(e,t,o,r)=>{let i=!0;const{id:n,uniqueId:s,type:a,body:l}=r;return e.some((e=>{if(e){let r=e(t,o,n,s,a,l);return void 0!==r&&!0!==r&&(i=r),!0}})),i},Ke=(e,t)=>{(()=>{const e=process.hrtime.bigint()})();const o=$e(),r=e.body,i=++De,n=x().replace(/-/g,"");let s=P(r.type);if(!r)return t.status(400).send(I("Body is required. Sending a body? Make sure your Content-type header\n is correct. Accepted is application/json and multipart/form-data."));let a=N(r.infile||r.options||r.data);if(!a&&!r.svg)return A(2,I(`Request ${n} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Check your payload.`)),t.status(400).send(I("No correct chart data found. Please make sure you are using\n application/json or multipart/form-data headers, and that the chart\n data is in the 'infile', 'options' or 'data' attribute if sending\n JSON or in the 'svg' if sending SVG."));let l=!1;if(l=ze(Ve,e,t,{id:i,uniqueId:n,type:s,body:r}),!0!==l)return t.send(l);let c=!1;e.socket.on("close",(()=>{c=!0})),A(4,`[export] Got an incoming HTTP request ${n}.`),r.constr="string"==typeof r.constr&&r.constr||"chart";const p={export:{instr:a,type:s,constr:r.constr[0].toLowerCase()+r.constr.substr(1),height:r.height,width:r.width,scale:r.scale||o.export.scale,globalOptions:N(r.globalOptions,!0),themeOptions:N(r.themeOptions,!0)},customCode:{allowCodeExecution:Ne,allowFileResources:!1,resources:N(r.resources,!0),callback:r.callback,customCode:r.customCode}};a&&(p.export.instr=U(a,p.customCode.allowCodeExecution));const u=Ie(o,p);if(u.export.options=a,u.payload={svg:r.svg||!1,b64:r.b64||!1,dataOptions:N(r.dataOptions,!0),noDownload:r.noDownload||!1,requestId:n},r.svg&&(d=u.payload.svg,["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((e=>d.match(`xlink:href="(?:(http://|https://))?${e}`)))))return t.status(400).send("SVG potentially contain at least one forbidden URL in xlink:href element.");var d;Ge(u,((o,a)=>(e.socket.removeAllListeners("close"),c?A(3,I("[export] The client closed the connection before the chart was done\n processing.")):a?(A(1,I(`[export] Work: ${n} could not be completed, sending:\n ${a}`)),t.status(400).send(a.message)):o&&o.data?(s=o.options.export.type,ze(Je,e,t,{id:i,body:o.data}),o.data?r.b64?"pdf"===s?t.send(Buffer.from(o.data,"utf8").toString("base64")):t.send(o.data):(t.header("Content-Type",qe[s]||"image/png"),r.noDownload||t.attachment(`${e.params.filename||"chart"}.${s||"png"}`),"svg"===s?t.send(o.data):t.send(Buffer.from(o.data,"base64"))):void 0):(A(1,I(`[export] Unexpected return from chart generation, please check your\n data Request: ${n} is ${o.data}.`)),t.status(400).send("Unexpected return from chart generation, please check your data.")))))};const Xe=h();Xe.disable("x-powered-by"),Xe.use(d());const Be=g.memoryStorage(),Ye=g({storage:Be,limits:{fieldsSize:"50MB"}});Xe.use(Ye.any()),Xe.use(u.json({limit:"50mb"})),Xe.use(u.urlencoded({extended:!0,limit:"50mb"})),Xe.use(u.urlencoded({extended:!1,limit:"50mb"}));const Qe=e=>A(1,`[server] Socket error: ${e}`),Ze=e=>{e.on("clientError",Qe),e.on("error",Qe),e.on("connection",(e=>e.on("error",(e=>Qe(e)))))},et=async e=>{if(!e.enable)return!1;if(!e.ssl.enable&&!e.ssl.force){const t=m.createServer(Xe);Ze(t),t.listen(e.port,e.host),A(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,o;try{t=await a.readFile(p.join(e.ssl.certPath,"server.key"),"utf8"),o=await a.readFile(p.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){A(1,`[server] Unable to load key/certificate from ${e.ssl.certPath}.`)}if(t&&o){const t=f.createServer(Xe);Ze(t),t.listen(e.ssl.port,e.host),A(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&q(Xe,e.rateLimiting),Xe.use(h.static(p.join($,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:_e,uptime:Math.floor(((new Date).getTime()-_e.getTime())/1e3/60)+" minutes",version:Oe,highchartsVersion:ee(),averageProcessingTime:Le(),performedExports:Ce(),failedExports:Re(),exportAttempts:Ee(),sucessRatio:Ce()/Ee()*100,pool:He()})}))})(Xe),(e=>{e.post("/",Ke),e.post("/:filename",Ke)})(Xe),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(c($,"public","index.html"))}))})(Xe),(e=>{!!e&&e.post("/change_hc_version/:newVersion",(async(e,t)=>{const o=process.env.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)return t.send({error:!0,message:"Server not configured to do run-time version changes: HIGHCHARTS_ADMIN_TOKEN not set"});const r=e.get("hc-auth");if(!r||r!==o)return t.send({error:!0,message:"Invalid or missing token: set token in the hc-auth header"});const i=e.params.newVersion;if(i){try{await Q(i)}catch(e){t.send({error:!0,message:e})}t.send({version:ee()})}else t.send({error:!0,message:"No new version supplied"})}))})(Xe)};var tt={startServer:et,getExpress:()=>h,getApp:()=>Xe,use:(e,...t)=>{Xe.use(e,...t)},get:(e,...t)=>{Xe.get(e,...t)},post:(e,...t)=>{Xe.post(e,...t)},enableRateLimiting:e=>q(Xe,e)},ot={log:A,mapToNewConfig:e=>{const t={};for(const[o,r]of Object.entries(e)){const e=C[o]?C[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}return t},setOptions:(e,t)=>(t?.length&&(Ae=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const o=e[t+1];try{if(o&&o.endsWith(".json"))return JSON.parse(i(o))}catch(e){A(1,`[config] Unable to load config from the ${o}: ${e}`)}}return{}}(t)),Pe(R,Ae),Ae=je(R),e&&(Ae=Ie(Ae,e,L)),t?.length&&(Ae=function(e,t,o){for(let o=0;o(i.length-1===a&&void 0!==n[s]&&(t[++o]?n[s]=t[o]||n[s]:(console.log(`Missing argument value for ${r}!`.red,"\n"),e=W())),n[s])),e)}return e}(Ae,t)),Ae),singleExport:e=>{e.export.instr=e.export.instr||e.export.options,Ge(e,((e,t)=>{t&&(A(1,`[cli] ${t.message}`),process.exit(1));const{outfile:o,type:r}=e.options.export;n(o||`chart.${r}`,"svg"!==r?Buffer.from(e.data,"base64"):e.data),xe()}))},startExport:Ge,batchExport:e=>{const t=[];for(let o of e.export.batch.split(";"))o=o.split("="),2===o.length&&t.push(new Promise(((t,r)=>{Ge({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,o)=>{if(o)return r(o);n(e.options.export.outfile,Buffer.from(e.data,"base64")),t()}))})));Promise.all(t).then((()=>{xe()})).catch((e=>{A(1,`[chart] Error encountered during batch export: ${e}`),xe()}))},server:tt,startServer:et,killPool:xe,initPool:async(e={})=>{var t,o;return t=e.customCode&&e.customCode.allowCodeExecution,Ne=F(t),(o=e.logging&&parseInt(e.logging.level))>=0&&o<=_.levelsDesc.length&&(_.level=o),e.logging&&e.logging.dest&&((e,t)=>{if(_={..._,dest:e||_.dest,file:t||_.file,toFile:!0},0===_.dest.length)return A(1,"[logger] File logging init: no path supplied.");_.dest.endsWith("/")||(_.dest+="/")})(e.logging.dest,e.logging.file||"highcharts-export-server.log"),await Y(e.highcharts||{version:"latest"}),await Te({pool:e.pool||{initialWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer?.args||[]}),e}};export{ot as default}; +import"colors";import e,{existsSync as t,mkdirSync as o,appendFile as r,readFileSync as i,writeFileSync as n,readFile as s,promises as a}from"fs";import l,{join as c,posix as p}from"path";import u from"body-parser";import d from"cors";import h from"express";import g from"multer";import m from"http";import f from"https";import v from"dotenv";import y from"express-rate-limit";import*as b from"url";import{fileURLToPath as w}from"url";import T from"https-proxy-agent";import{v4 as x}from"uuid";import{Pool as k}from"tarn";import S from"puppeteer";import H from"node:path";import{randomBytes as E}from"node:crypto";import"prompts";v.config();const R={puppeteer:{args:{value:[],type:"string[]",description:"Array of arguments to send to puppeteer."}},highcharts:{version:{value:"latest",envLink:"HIGHCHARTS_VERSION",type:"string",description:"Highcharts version to use."},cdnURL:{value:"https://code.highcharts.com/",envLink:"HIGHCHARTS_CDN",type:"string",description:"The CDN URL of Highcharts scripts to use."},coreScripts:{envLink:"HIGHCHARTS_CORE_SCRIPTS",value:["highcharts","highcharts-more","highcharts-3d"],type:"string[]",description:"Highcharts core scripts to fetch."},modules:{envLink:"HIGHCHARTS_MODULES",value:["stock","map","gantt","exporting","export-data","parallel-coordinates","accessibility","annotations-advanced","boost-canvas","boost","data","draggable-points","static-scale","broken-axis","heatmap","tilemap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","pyramid3d","networkgraph","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","solid-gauge","sonification","stock-tools","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi"],type:"string[]",description:"Highcharts modules to fetch."},indicators:{envLink:"HIGHCHARTS_INDICATORS",value:["indicators-all"],type:"string[]",description:"Highcharts indicators to fetch."},scripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],type:"string[]",description:"Additional direct scripts/optional dependencies (e.g. moment.js)."},forceFetch:{envLink:"HIGHCHARTS_FORCE_FETCH",value:!1,type:"boolean",description:"Should all the scripts be refetched after rerunning the server."}},export:{infile:{value:!1,type:"string",description:"The input file name along with a type (json or svg). It can be a correct JSON or SVG file."},instr:{value:!1,type:"string",description:"An input in a form of a stringified JSON or SVG file. Overrides the --infile."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf or svg). Ignores the --type flag."},type:{envLink:"EXPORT_DEFAULT_TYPE",value:"png",type:"string",description:"The format of the file to export to. Can be jpeg, png, pdf or svg."},constr:{envLink:"EXPORT_DEFAULT_CONSTR",value:"chart",type:"string",description:"The constructor to use. Can be chart, stockChart, mapChart or ganttChart."},defaultHeight:{envLink:"EXPORT_DEFAULT_HEIGHT",value:400,type:"number",description:"The default height of the exported chart. Used when not found any value set."},defaultWidth:{envLink:"EXPORT_DEFAULT_WIDTH",value:600,type:"number",description:"The default width of the exported chart. Used when not found any value set."},defaultScale:{envLink:"EXPORT_DEFAULT_SCALE",value:1,type:"number",description:"The default scale of the exported chart. Ranges between 1 and 5."},height:{type:"number",value:!1,description:"The default height of the exported chart. Overrides the option in the chart settings."},width:{type:"number",value:!1,description:"The width of the exported chart. Overrides the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart. Ranges between 1 and 5."},globalOptions:{value:!1,type:"string",description:"A stringified JSON or a filename with options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"A stringified JSON or a filename with theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Starts a batch job. A string that contains input/output pairs: "in=out;in=out;..".'}},customCode:{allowCodeExecution:{envLink:"HIGHCHARTS_ALLOW_CODE_EXECUTION",value:!1,type:"boolean",description:"If set to true, allow for the execution of arbitrary code when exporting."},allowFileResources:{envLink:"HIGHCHARTS_ALLOW_FILE_RESOURCES",value:!0,type:"boolean",description:"Allow injecting resources from the filesystem. Has no effect when running as a server."},customCode:{value:!1,type:"string",description:"A function to be called before chart initialization. Can be a filename with the js extension."},callback:{value:!1,type:"string",description:"A JavaScript file with a function to run on construction."},resources:{value:!1,type:"string",description:"An additional resource in a form of stringified JSON. It can contain files, js and css sections."},loadConfig:{value:!1,type:"string",description:"A file that contains a pre-defined config to use."},createConfig:{value:!1,type:"string",description:"Allows to set options through a prompt and save in a provided config file."}},server:{enable:{envLink:"HIGHCHARTS_SERVER_ENABLE",value:!1,type:"boolean",cliName:"enableServer",description:"If set to true, starts a server on 0.0.0.0."},host:{envLink:"HIGHCHARTS_SERVER_HOST",value:"0.0.0.0",type:"string",description:"The hostname of the server. Also starts a server listening on the supplied hostname."},port:{envLink:"HIGHCHARTS_SERVER_PORT",value:7801,type:"number",description:"The port to use for the server. Defaults to 7801."},ssl:{enable:{envLink:"HIGHCHARTS_SERVER_SSL_ENABLE",value:!1,type:"boolean",cliName:"enableSsl",description:"Enables the SSL protocol."},force:{envLink:"HIGHCHARTS_SERVER_SSL_FORCE",value:!1,type:"boolean",cliName:"sslForced",description:"If set to true, forces the server to only serve over HTTPS."},port:{envLink:"HIGHCHARTS_SERVER_SSL_PORT",value:443,type:"number",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{envLink:"HIGHCHARTS_SSL_CERT_PATH",value:"",type:"string",description:"The path to the SSL certificate/key."}},rateLimiting:{enable:{envLink:"HIGHCHARTS_RATE_LIMIT_ENABLE",value:!1,type:"boolean",cliName:"enableRateLimiting",description:"Enables rate limiting."},maxRequests:{envLink:"HIGHCHARTS_RATE_LIMIT_MAX",value:10,type:"number",description:"Max requests allowed in a one minute."},window:{envLink:"HIGHCHARTS_RATE_LIMIT_WINDOW",value:1,type:"number",description:"The time window in minutes for rate limiting."},delay:{envLink:"HIGHCHARTS_RATE_LIMIT_DELAY",value:0,type:"number",description:"The amount to delay each successive request before hitting the max."},trustProxy:{envLink:"HIGHCHARTS_RATE_LIMIT_TRUST_PROXY",value:!1,type:"boolean",description:"Set this to true if behind a load balancer."},skipKey:{envLink:"HIGHCHARTS_RATE_LIMIT_SKIP_KEY",value:"",type:"number|string",description:"Allows bypassing the rate limiter and should be provided with skipToken argument."},skipToken:{envLink:"HIGHCHARTS_RATE_LIMIT_SKIP_TOKEN",value:"",type:"number|string",description:"Allows bypassing the rate limiter and should be provided with skipKey argument."}}},pool:{initialWorkers:{envLink:"HIGHCHARTS_POOL_MIN_WORKERS",value:4,type:"number",description:"The number of initial workers to spawn."},maxWorkers:{envLink:"HIGHCHARTS_POOL_MAX_WORKERS",value:8,type:"number",description:"The number of max workers to spawn."},workLimit:{envLink:"HIGHCHARTS_POOL_WORK_LIMIT",value:40,type:"number",description:"The pieces of work that can be performed before restarting process."},queueSize:{envLink:"HIGHCHARTS_POOL_QUEUE_SIZE",value:5,type:"number",description:"The size of the request overflow queue."},timeoutThreshold:{envLink:"HIGHCHARTS_POOL_TIMEOUT",value:5e3,type:"number",description:"The number of milliseconds before timing out."},acquireTimeout:{envLink:"HIGHCHARTS_POOL_ACQUIRE_TIMEOUT",value:5e3,type:"number",description:"The number of milliseconds to wait for acquiring a resource."},reaper:{envLink:"HIGHCHARTS_POOL_ENABLE_REAPER",value:!0,type:"boolean",description:"Whether or not to evict workers after a certain time period."},benchmarking:{envLink:"HIGHCHARTS_POOL_BENCHMARKING",value:!1,type:"boolean",description:"Enable benchmarking."},listenToProcessExits:{envLink:"HIGHCHARTS_POOL_LISTEN_TO_PROCESS_EXITS",value:!0,type:"boolean",description:"Set to false in order to skip attaching process.exit handlers."}},logging:{level:{envLink:"HIGHCHARTS_LOG_LEVEL",value:4,type:"number",cliName:"logLevel",description:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose)."},file:{envLink:"HIGHCHARTS_LOG_FILE",value:"highcharts-export-server.log",type:"string",cliName:"logFile",description:"A name of a log file. The --logDest also needs to be set to enable file logging."},dest:{envLink:"HIGHCHARTS_LOG_DEST",value:"log/",type:"string",cliName:"logDest",description:"The path to store log files. Also enables file logging."}},ui:{enable:{envLink:"HIGHCHARTS_UI_ENABLE",value:!1,type:"boolean",cliName:"enableUi",description:"Enables the UI for the export server."},route:{envLink:"HIGHCHARTS_UI_ROUTE",value:"/",type:"string",cliName:"uiRoute",description:"The route to attach the UI to."}},other:{noLogo:{envLink:"HIGHCHARTS_NO_LOGO",value:!1,type:"boolean",description:"Skip printing the logo on a startup. Will be replaced by a simple text."}},payload:{}};R.puppeteer.args.value.join(","),R.highcharts.version.value,R.highcharts.cdnURL.value,R.highcharts.modules.value,R.highcharts.scripts.value.join(","),R.highcharts.forceFetch.value,R.export.type.value,R.export.constr.value,R.export.defaultHeight.value,R.export.defaultWidth.value,R.export.defaultScale.value,R.customCode.allowCodeExecution.value,R.customCode.allowFileResources.value,R.server.enable.value,R.server.host.value,R.server.port.value,R.server.ssl.enable.value,R.server.ssl.force.value,R.server.ssl.port.value,R.server.ssl.certPath.value,R.server.rateLimiting.enable.value,R.server.rateLimiting.maxRequests.value,R.server.rateLimiting.window.value,R.server.rateLimiting.delay.value,R.server.rateLimiting.trustProxy.value,R.server.rateLimiting.skipKey.value,R.server.rateLimiting.skipToken.value,R.pool.initialWorkers.value,R.pool.maxWorkers.value,R.pool.workLimit.value,R.pool.queueSize.value,R.pool.timeoutThreshold.value,R.pool.acquireTimeout.value,R.pool.reaper.value,R.pool.benchmarking.value,R.pool.listenToProcessExits.value,R.logging.level.value,R.logging.file.value,R.logging.dest.value,R.ui.enable.value,R.ui.route.value,R.other.noLogo.value;const L=["options","globalOptions","themeOptions","resources","payload"],C={},O=(e,t="")=>{Object.keys(e).forEach((o=>{if(!["puppeteer","highcharts"].includes(o)){const r=e[o];void 0===r.value?O(r,`${t}.${o}`):C[r.cliName||o]=`${t}.${o}`.substring(1)}}))};O(R);let _={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:"red"},{title:"warning",color:"yellow"},{title:"notice",color:"blue"},{title:"verbose",color:"gray"}],listeners:[]};for(const[e,t]of Object.entries(R.logging))_[e]=t.value;const A=(...e)=>{const[i,...n]=e,{level:s,levelsDesc:a}=_;if(0===i||i>s||s>a.length)return;const l=`${(new Date).toString().split("(")[0].trim()} [${a[i-1].title}] -`;_.listeners.forEach((e=>{e(l,n.join(" "))})),_.toFile&&(_.pathCreated||(!t(_.dest)&&o(_.dest),_.pathCreated=!0),r(`${_.dest}${_.file}`,[l].concat(n).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),_.toFile=!1)}))),_.toConsole&&console.log.apply(void 0,[l.toString()[_.levelsDesc[i-1].color]].concat(n))},$=w(new URL("../.",import.meta.url)),I=(e,t=/\s\s+/g,o=" ")=>e.replaceAll(t,o).trim(),P=(e,t)=>{const o=["png","jpeg","pdf","svg"];if(t){const r=t.split(".").pop();o.includes(r)&&e!==r&&(e=r)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||o.find((t=>t===e))||"png"},j=(e=!1,t)=>{const o=["js","css","files"];let r=e,n=!1;if(t&&e.endsWith(".json"))try{e?e&&e.endsWith(".json")?r=N(i(e,"utf8")):(r=N(e),!0===r&&(r=N(i("resources.json","utf8")))):r=N(i("resources.json","utf8"))}catch(e){return A(3,"[cli] No resources found.")}else r=N(e),t||delete r.files;for(const e in r)o.includes(e)?n||(n=!0):delete r[e];return n?(r.files&&(r.files=r.files.map((e=>e.trim())),(!r.files||r.files.length<=0)&&delete r.files),r):A(3,"[cli] No resources found.")};function N(e,t){try{const o=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof o&&t?JSON.stringify(o):o}catch(e){return!1}}const G=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=G(e[o]));return t},U=(e,t)=>JSON.stringify(e,((e,o)=>("string"==typeof o&&((o=o.trim()).startsWith("function(")||o.startsWith("function ("))&&o.endsWith("}")&&(o=t?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof o?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:o))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function W(){console.log("Usage of CLI arguments:".bold,"\n------",`\nFor more detailed information visit readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[o,r]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(r,"value")){let e=` --${r.cliName||o} ${("<"+r.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,r.description,`[Default: ${r.value.toString().bold}]`.blue)}else e(r)};Object.keys(R).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(R[t]))})),console.log("\n")}const F=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,M=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&M(i(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")};var q=(e,t)=>{const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const i=y({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(A(4,"[rate-limiting] Skipping rate limiter."),!0)});e.use(i),A(3,I(`[rate-limiting] Enabled rate limiting: ${r.max} requests\n per ${r.window} minute per IP, trusting proxy:\n ${r.trustProxy}.`))};async function D(e,t={}){return new Promise(((o,r)=>{const i=(e=>e.startsWith("https")?f:m)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}v.config();const V=c($,".cache"),J={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""};let z=!1;const K=()=>J.hcVersion=J.sources.substr(0,J.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),X=async(e,t)=>{try{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),A(4,`[cache] Fetching script - ${e}.js`);const o=t?{agent:t,timeout:+process.env.PROXY_SERVER_TIMEOUT||5e3}:{},r=await D(`${e}.js`,o);if(200===r.statusCode)return r.text;throw`${r.statusCode}`}catch(t){throw A(1,`[cache] Error fetching script ${e}.js: ${t}.`),t}},B=async(e,t)=>{const{coreScripts:o,modules:r,indicators:i,scripts:s}=e,a="latest"!==e.version&&e.version?`${e.version}/`:"";A(3,"[cache] Updating cache to Highcharts ",a);const l=[...o.map((e=>`${a}${e}`)),...r.map((e=>"map"===e?`maps/${a}modules/${e}`:`${a}modules/${e}`)),...i.map((e=>`stock/${a}indicators/${e}`))];let c;const p=process.env.PROXY_SERVER_HOST,u=process.env.PROXY_SERVER_PORT;p&&u&&(c=new T({host:p,port:+u}));const d={};try{return J.sources=(await Promise.all([...l.map((async t=>{const o=await X(`${e.cdnURL||J.cdnURL}${t}`,c);return"string"==typeof o&&(d[t.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1),o})),...s.map((e=>X(e,c)))])).join(";\n"),K(),n(t,J.sources),d}catch(e){A(1,"[cache] Unable to update local Highcharts cache.")}},Y=async e=>{let r;const s=c(V,"manifest.json"),a=c(V,"sources.js");if(z=e,!t(V)&&o(V),!t(s)||e.forceFetch)A(3,"[cache] Fetching and caching Highcharts dependencies."),r=await B(e,a);else{let t=!1;const o=JSON.parse(i(s));if(o.modules&&Array.isArray(o.modules)){const e={};o.modules.forEach((t=>e[t]=1)),o.modules=e}const{modules:n,coreScripts:l,indicators:c}=e,p=n.length+l.length+c.length;o.version!==e.version?(A(3,"[cache] Highcharts version mismatch in cache, need to re-fetch."),t=!0):Object.keys(o.modules||{}).length!==p?(A(3,"[cache] Cache and requested modules does not match, need to re-fetch."),t=!0):t=(e.modules||[]).some((e=>{if(!o.modules[e])return A(3,`[cache] The ${e} missing in cache, need to re-fetch.`),!0})),t?r=await B(e,a):(A(3,"[cache] Dependency cache is up to date, proceeding."),J.sources=i(a,"utf8"),r=o.modules,K())}await(async(e,t)=>{const o={version:e.version,modules:t||{}};J.activeManifest=o,A(4,"[cache] writing new manifest");try{n(c(V,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){A(1,`[cache] Error writing cache manifest: ${e}.`)}})(e,r)};var Q=async e=>!!z&&await Y(Object.assign(z,{version:e})),Z=()=>J,ee=()=>J.hcVersion;const te=E(64).toString("base64url"),oe=H.join("tmp",`puppeteer-${te}`),re=[`--user-data-dir=${H.join(oe,"profile")}`,"--autoplay-policy=user-gesture-required","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-client-side-phishing-detection","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=AudioServiceOutOfProcess","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-speech-api","--disable-sync","--hide-crash-restore-bubble","--hide-scrollbars","--ignore-gpu-blacklist","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-zygote","--password-store=basic","--use-mock-keychain"],ie=b.fileURLToPath(new URL(".",import.meta.url)),ne=e.readFileSync(ie+"/../templates/template.html","utf8");let se;const ae=async()=>{if(!se)return!1;const e=await se.newPage();return await e.setContent(ne),await e.addScriptTag({path:ie+"/../.cache/sources.js"}),await e.evaluate((()=>window.setupHighcharts())),e.on("pageerror",(async t=>{A(1,"[page error]",t),await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error

${t.toString()}`)})),e},le=async()=>{se.connected&&await se.close()};const ce=b.fileURLToPath(new URL(".",import.meta.url)),pe=async(e,t,o)=>await e.evaluate(((e,t)=>window.triggerExport(e,t)),t,o);var ue=async(e,t,o)=>{const r=[],n=async e=>{for(const e of r)await e.dispose();await e.evaluate((()=>{const[,...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))};try{const s=()=>{};A(4,"[export] Determining export path.");const a=o.export;await e.evaluate((()=>requestAnimationFrame((()=>{}))));const c=a?.options?.chart?.displayErrors&&Z().activeManifest.modules.debugger;await e.evaluate((e=>window._displayErrors=e),c);const p=()=>{};let u;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(A(4,"[export] Treating as SVG."),"svg"===a.type)return t;u=!0;const o=()=>{};await e.setContent((e=>`\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t)),o()}else if(A(4,"[export] Treating as config."),a.strInj){const t=()=>{};await pe(e,{chart:{height:a.height,width:a.width}},o),t()}else{t.chart.height=a.height,t.chart.width=a.width;const r=()=>{};await pe(e,t,o),r()}p();const d=()=>{},h=o.customCode.resources;if(h){if(h.js&&r.push(await e.addScriptTag({content:h.js})),h.files)for(const t of h.files)try{const o=!t.startsWith("http");r.push(await e.addScriptTag(o?{content:i(t,"utf8")}:{url:t}))}catch(e){A(4,"[export] JS file not found.")}const t=()=>{};if(h.css){let t=h.css.match(/@import\s*([^;]*);/g);if(t)for(let i of t)i&&(i=i.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),i.startsWith("http")?r.push(await e.addStyleTag({url:i})):o.customCode.allowFileResources&&r.push(await e.addStyleTag({path:l.join(ce,i)})));r.push(await e.addStyleTag({content:h.css.replace(/@import\s*([^;]*);/g,"")||" "}))}t()}d();const g=u?await e.$eval("#chart-container svg:first-of-type",(async(e,t)=>({chartHeight:e.height.baseVal.value*t,chartWidth:e.width.baseVal.value*t})),parseFloat(a.scale)):await e.evaluate((async()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return{chartHeight:e,chartWidth:t}})),m=()=>{},f=Math.ceil(g?.chartHeight||a.height),v=Math.ceil(g?.chartWidth||a.width);await e.setViewport({height:f,width:v,deviceScaleFactor:u?1:parseFloat(a.scale)});const y=u?e=>{document.body.style.zoom=e,document.body.style.margin="0px"}:()=>{document.body.style.zoom=1};await e.evaluate(y,parseFloat(a.scale));const{height:b,width:w,x:T,y:x}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}})))(e);let k;u||await e.setViewport({width:Math.round(w),height:Math.round(b),deviceScaleFactor:parseFloat(a.scale)}),m();const S=()=>{};if("svg"===a.type)k=await(async e=>await e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if("png"===a.type||"jpeg"===a.type)k=await(async(e,t,o,r)=>await Promise.race([e.screenshot({type:t,encoding:o,clip:r,omitBackground:!0}),new Promise(((e,t)=>setTimeout((()=>t(new Error("Rasterization timeout"))),1500)))]))(e,a.type,"base64",{width:v,height:f,x:T,y:x});else{if("pdf"!==a.type)throw`Unsupported output format ${a.type}`;k=await(async(e,t,o,r)=>await e.pdf({height:t+1,width:o,encoding:r}))(e,f,v,"base64")}return await e.evaluate((()=>{const e=Highcharts.charts;if(e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()})),S(),s(),await n(e),k}catch(t){return await n(e),A(1,`[export] Error encountered during export: ${t}`),t}};let de,he=0,ge=0,me=0,fe=0,ve=0,ye={},be=!1;const we={create:async()=>{const e=x();let t=!1;const o=(new Date).getTime();try{if(t=await ae(),!t||t.isClosed())throw"invalid page";A(3,`[pool] Successfully created a worker ${e} - took ${(new Date).getTime()-o} ms.`)}catch(e){throw A(1,`[pool] Error creating a new page in pool entry creation! ${e}`),"Error creating page"}return{id:e,page:t,workCount:Math.round(Math.random()*(ye.workLimit/2))}},validate:e=>!(ye.workLimit&&++e.workCount>ye.workLimit)||(A(3,"[pool] Worker failed validation:",`exceeded work limit (limit is ${ye.workLimit})`),!1),destroy:e=>{A(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&e.page.close()},log:(e,t)=>console.log(`${t}: ${e}`)},Te=async e=>{de=e.puppeteerArgs;try{await(async e=>{const t=[...re,...e||[]];if(!se){let e=0;const o=async()=>{try{A(3,"[browser] attempting to get a browser instance (try",e+")"),se=await S.launch({headless:"new",args:t,userDataDir:"./tmp/"})}catch(t){A(0,"[browser]",t),++e<25?(A(3,"[browser] failed:",t),await new Promise((e=>setTimeout(e,4e3))),await o()):A(0,"Max retries reached")}};try{await o()}catch(e){return A(0,"[browser] Unable to open browser"),!1}if(!se)return A(0,"[browser] Unable to open browser"),!1}return se})(de)}catch(e){A(0,"[pool|browser]",e)}if(ye=e&&e.pool?{...e.pool}:{},A(3,"[pool] Initializing pool:",`min ${ye.initialWorkers}, max ${ye.maxWorkers}.`),be)return A(4,"[pool] Already initialized, please kill it before creating a new one.");ye.listenToProcessExits&&(A(4,"[pool] Attaching exit listeners to the process."),process.on("exit",(async()=>{await xe()})),process.on("SIGINT",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("SIGTERM",((e,t)=>{A(4,`The ${e} event with code: ${t}.`),process.exit(1)})),process.on("uncaughtException",(async(e,t)=>{A(4,`The ${t} error, message: ${e.message}.`)})));try{be=new k({...we,min:ye.initialWorkers,max:ye.maxWorkers,createRetryIntervalMillis:200,createTimeoutMillis:ye.acquireTimeout,acquireTimeoutMillis:ye.acquireTimeout,destroyTimeoutMillis:ye.acquireTimeout,idleTimeoutMillis:ye.timeoutThreshold,reapIntervalMillis:1e3,propagateCreateError:!1}),be.on("createFail",((e,t)=>{A(1,`[pool] Error when creating worker of an event id ${e}:`,t)})),be.on("acquireFail",((e,t)=>{A(1,`[pool] Error when acquiring worker of an event id ${e}:`,t)})),be.on("destroyFail",((e,t,o)=>{A(1,`[pool] Error when destroying worker of an id ${t.id}, event id ${e}:`,o)})),be.on("release",(e=>{A(4,`[pool] Releasing a worker of an id ${e.id}`)})),be.on("destroySuccess",((e,t)=>{A(4,`[pool] Destroyed a worker of an id ${t.id}`)}));const e=[];for(let t=0;t{be.release(e)})),A(3,`[pool] The pool is ready with ${ye.initialWorkers} initial resources waiting.`)}catch(e){throw A(1,`[pool] Couldn't create the worker pool ${e}`),e}};async function xe(){return A(3,"[pool] Killing all workers."),be.destroyed?(await le(),!0):(await be.destroy(),await le(),!0)}const ke=async(e,t)=>{let o;const r=e=>{throw++fe,o&&be.release(o),"In pool.postWork: "+e};if(A(4,"[pool] Work received, starting to process."),ye.benchmarking&&Se(),++ge,!be)return A(1,"[pool] Work received, but pool has not been started."),r("Pool is not inited but work was posted to it!");try{A(4,"[pool] Acquiring worker"),o=await be.acquire().promise}catch(e){return r(`[pool] Error when acquiring available entry: ${e}`)}if(A(4,"[pool] Acquired worker handle"),!o.page)return r("Resolved worker page is invalid: pool setup is wonky");try{let i=(new Date).getTime();A(4,`[pool] Starting work on pool entry ${o.id}.`);const n=await ue(o.page,e,t);if(n instanceof Error)return"Rasterization timeout"===n.message&&(o.page.close(),o.page=await ae()),r(n);be.release(o);const s=(new Date).getTime()-i;return me+=s,ve=me/++he,A(4,`[pool] Work completed in ${s} ms.`),{data:n,options:t}}catch(e){r(`Error trying to perform puppeteer export: ${e}.`)}};function Se(){const{min:e,max:t,size:o,available:r,borrowed:i,pending:n,spareResourceCapacity:s}=be;A(4,`[pool] The minimum number of resources allowed by pool: ${e}.`),A(4,`[pool] The maximum number of resources allowed by pool: ${t}.`),A(4,`[pool] The number of all resources in pool (free or in use): ${o}.`),A(4,`[pool] The number of resources that are currently available: ${r}.`),A(4,`[pool] The number of resources that are currently acquired: ${i}.`),A(4,`[pool] The number of callers waiting to acquire a resource: ${n}.`),A(4,`[pool] The number of how many more resources can the pool manage/create: ${s}.`)}var He=()=>({min:be.min,max:be.max,size:be.size,available:be.available,borrowed:be.borrowed,pending:be.pending,spareResourceCapacity:be.spareResourceCapacity}),Ee=()=>ge,Re=()=>fe,Le=()=>ve,Ce=()=>he;const Oe=process.env.npm_package_version,_e=new Date;let Ae={};const $e=()=>Ae,Ie=(e,t,o=[])=>{const r=G(e);for(const[e,n]of Object.entries(t))r[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||o.includes(e)||void 0===r[e]?void 0!==n?n:r[e]:Ie(r[e],n,o);var i;return r};function Pe(e,t={},o=""){Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const i=e[r],n=t&&t[r];let s;void 0===i.value?Pe(i,n,`${o}.${r}`):(void 0!==n&&(i.value=n),i.envLink&&("boolean"===i.type?i.value=F([process.env[i.envLink],i.value].find((e=>e||"false"===e))):"number"===i.type?(s=+process.env[i.envLink],i.value=s>=0?s:i.value):i.type.indexOf("]")>=0&&process.env[i.envLink]?i.value=process.env[i.envLink].split(","):i.value=process.env[i.envLink]||i.value))}}))}function je(e){let t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:je(r);return t}let Ne=!1;const Ge=async(e,t)=>{A(4,"[chart] Starting exporting process.");const o=((e,t={})=>{let o={};return e.svg?(o=G(t),o.export.type=e.type||e.export.type,o.export.scale=e.scale||e.export.scale,o.export.outfile=e.outfile||e.export.outfile,o.payload={svg:e.svg}):o=Ie(t,e,L),o.export.outfile=o.export?.outfile||`chart.${o.export?.type||"png"}`,o})(e,$e()),r=o.export;return o.payload?.svg&&""!==o.payload.svg?Me(o.payload.svg.trim(),o,t):r.infile&&r.infile.length?(A(4,"[chart] Attempting to export from an input file."),s(r.infile,"utf8",((e,r)=>e?A(1,`[chart] Error loading input file: ${e}.`):(o.export.instr=r,Me(o.export.instr.trim(),o,t))))):r.instr&&""!==r.instr||r.options&&""!==r.options?(A(4,"[chart] Attempting to export from a raw input."),F(o.customCode?.allowCodeExecution)?Fe(o,t):"string"==typeof r.instr?Me(r.instr.trim(),o,t):We(o,r.instr||r.options,t)):(A(1,I(`[chart] No input specified.\n ${JSON.stringify(r,void 0," ")}.`)),t&&t(!1,{error:!0,message:"No input specified."}))},Ue=e=>{const{chart:t,exporting:o}=e.export?.options||N(e.export?.instr),r=N(e.export?.globalOptions);let i=e.export?.scale||o?.scale||r?.exporting?.scale||e.export?.defaultScale||1;return i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const o=Math.pow(10,t||0);return Math.round(+e*o)/o})(i,2),{height:e.export?.height||o?.sourceHeight||t?.height||r?.exporting?.sourceHeight||r?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||o?.sourceWidth||t?.width||r?.exporting?.sourceWidth||r?.chart?.width||e.export?.defaultWidth||600,scale:i}},We=(e,t,o,r)=>{let{export:n,customCode:s}=e;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:Ne;if(s){if("string"==typeof e.customCode.resources)e.customCode.resources=j(e.customCode.resources,F(e.customCode.allowFileResources));else if(!e.customCode.resources)try{const t=i("resources.json","utf8");e.customCode.resources=j(t,F(e.customCode.allowFileResources))}catch(e){A(3,"[chart] The default resources.json file not found.")}}else s=e.customCode={};if(!a&&s){if(s.callback||s.resources||s.customCode)return o&&o(!1,{error:!0,message:I("The callback, resources and customCode have been disabled for this\n server.")});s.callback=!1,s.resources=!1,s.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=P(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{n&&n[e]&&("string"==typeof n[e]&&n[e].endsWith(".json")?n[e]=N(i(n[e],"utf8"),!0):n[e]=N(n[e],!0))}catch(t){n[e]={},A(1,`[chart] The ${e} not found.`)}})),s.allowCodeExecution&&(s.customCode=M(s.customCode,s.allowFileResources)),s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=i(s.callback,"utf8")}catch(e){A(2,`[chart] Error loading callback: ${e}.`),s.callback=!1}else s.callback=!1;e.export={...e.export,...Ue(e)},ke(n.strInj||t||r,e).then((e=>o(e))).catch((e=>(A(0,"[chart] When posting work:",e),o(!1,e))))},Fe=(e,t)=>{try{let o,r=e.export.instr||e.export.options;return"string"!=typeof r&&(o=r=U(r,e.customCode?.allowCodeExecution)),o=r.replaceAll(/\t|\n|\r/g,"").trim(),";"===o[o.length-1]&&(o=o.substring(0,o.length-1)),e.export.strInj=o,We(e,!1,t)}catch(o){const r=I(`Malformed input detected for ${e.export?.requestId||"?"}:\n Please make sure that your JSON/JavaScript options\n are sent using the "options" attribute, and that if you're using\n SVG, it is unescaped.`);return A(1,r),t&&t(!1,JSON.stringify({error:!0,message:r}))}},Me=(e,t,o)=>{const{allowCodeExecution:r}=t.customCode;if(e.indexOf("=0||e.indexOf("=0)return A(4,"[chart] Parsing input as SVG."),We(t,!1,o,e);try{const r=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return We(t,r,o)}catch(e){return F(r)?Fe(t,o):o&&o(!1,{error:!0,message:I("Only JSON configurations and SVG is allowed for this server. If\n this is your server, JavaScript exporting can be enabled by starting\n the server with the --allowCodeExecution flag.")})}},qe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let De=0;const Ve=[],Je=[],ze=(e,t,o,r)=>{let i=!0;const{id:n,uniqueId:s,type:a,body:l}=r;return e.some((e=>{if(e){let r=e(t,o,n,s,a,l);return void 0!==r&&!0!==r&&(i=r),!0}})),i},Ke=(e,t)=>{(()=>{const e=process.hrtime.bigint()})();const o=$e(),r=e.body,i=++De,n=x().replace(/-/g,"");let s=P(r.type);if(!r)return t.status(400).send(I("Body is required. Sending a body? Make sure your Content-type header\n is correct. Accepted is application/json and multipart/form-data."));let a=N(r.infile||r.options||r.data);if(!a&&!r.svg)return A(2,I(`Request ${n} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Check your payload.`)),t.status(400).send(I("No correct chart data found. Please make sure you are using\n application/json or multipart/form-data headers, and that the chart\n data is in the 'infile', 'options' or 'data' attribute if sending\n JSON or in the 'svg' if sending SVG."));let l=!1;if(l=ze(Ve,e,t,{id:i,uniqueId:n,type:s,body:r}),!0!==l)return t.send(l);let c=!1;e.socket.on("close",(()=>{c=!0})),A(4,`[export] Got an incoming HTTP request ${n}.`),r.constr="string"==typeof r.constr&&r.constr||"chart";const p={export:{instr:a,type:s,constr:r.constr[0].toLowerCase()+r.constr.substr(1),height:r.height,width:r.width,scale:r.scale||o.export.scale,globalOptions:N(r.globalOptions,!0),themeOptions:N(r.themeOptions,!0)},customCode:{allowCodeExecution:Ne,allowFileResources:!1,resources:N(r.resources,!0),callback:r.callback,customCode:r.customCode}};a&&(p.export.instr=U(a,p.customCode.allowCodeExecution));const u=Ie(o,p);if(u.export.options=a,u.payload={svg:r.svg||!1,b64:r.b64||!1,dataOptions:N(r.dataOptions,!0),noDownload:r.noDownload||!1,requestId:n},r.svg&&(d=u.payload.svg,["localhost","(10).(.*).(.*).(.*)","(127).(.*).(.*).(.*)","(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)","(192).(168).(.*).(.*)"].some((e=>d.match(`xlink:href="(?:(http://|https://))?${e}`)))))return t.status(400).send("SVG potentially contain at least one forbidden URL in xlink:href element.");var d;Ge(u,((o,a)=>(e.socket.removeAllListeners("close"),c?A(3,I("[export] The client closed the connection before the chart was done\n processing.")):a?(A(1,I(`[export] Work: ${n} could not be completed, sending:\n ${a}`)),t.status(400).send(a.message)):o&&o.data?(s=o.options.export.type,ze(Je,e,t,{id:i,body:o.data}),o.data?r.b64?"pdf"===s?t.send(Buffer.from(o.data,"utf8").toString("base64")):t.send(o.data):(t.header("Content-Type",qe[s]||"image/png"),r.noDownload||t.attachment(`${e.params.filename||"chart"}.${s||"png"}`),"svg"===s?t.send(o.data):t.send(Buffer.from(o.data,"base64"))):void 0):(A(1,I(`[export] Unexpected return from chart generation, please check your\n data Request: ${n} is ${o.data}.`)),t.status(400).send("Unexpected return from chart generation, please check your data.")))))};const Xe=h();Xe.disable("x-powered-by"),Xe.use(d());const Be=g.memoryStorage(),Ye=g({storage:Be,limits:{fieldsSize:"50MB"}});Xe.use(Ye.any()),Xe.use(u.json({limit:"50mb"})),Xe.use(u.urlencoded({extended:!0,limit:"50mb"})),Xe.use(u.urlencoded({extended:!1,limit:"50mb"}));const Qe=e=>A(1,`[server] Socket error: ${e}`),Ze=e=>{e.on("clientError",Qe),e.on("error",Qe),e.on("connection",(e=>e.on("error",(e=>Qe(e)))))},et=async e=>{if(!e.enable)return!1;if(!e.ssl.enable&&!e.ssl.force){const t=m.createServer(Xe);Ze(t),t.listen(e.port,e.host),A(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,o;try{t=await a.readFile(p.join(e.ssl.certPath,"server.key"),"utf8"),o=await a.readFile(p.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){A(1,`[server] Unable to load key/certificate from ${e.ssl.certPath}.`)}if(t&&o){const t=f.createServer(Xe);Ze(t),t.listen(e.ssl.port,e.host),A(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&q(Xe,e.rateLimiting),Xe.use(h.static(p.join($,"public"))),(e=>{!!e&&e.get("/health",((e,t)=>{t.send({status:"OK",bootTime:_e,uptime:Math.floor(((new Date).getTime()-_e.getTime())/1e3/60)+" minutes",version:Oe,highchartsVersion:ee(),averageProcessingTime:Le(),performedExports:Ce(),failedExports:Re(),exportAttempts:Ee(),sucessRatio:Ce()/Ee()*100,pool:He()})}))})(Xe),(e=>{e.post("/",Ke),e.post("/:filename",Ke)})(Xe),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(c($,"public","index.html"))}))})(Xe),(e=>{!!e&&e.post("/change_hc_version/:newVersion",(async(e,t)=>{const o=process.env.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)return t.send({error:!0,message:"Server not configured to do run-time version changes: HIGHCHARTS_ADMIN_TOKEN not set"});const r=e.get("hc-auth");if(!r||r!==o)return t.send({error:!0,message:"Invalid or missing token: set token in the hc-auth header"});const i=e.params.newVersion;if(i){try{await Q(i)}catch(e){t.send({error:!0,message:e})}t.send({version:ee()})}else t.send({error:!0,message:"No new version supplied"})}))})(Xe)};var tt={startServer:et,getExpress:()=>h,getApp:()=>Xe,use:(e,...t)=>{Xe.use(e,...t)},get:(e,...t)=>{Xe.get(e,...t)},post:(e,...t)=>{Xe.post(e,...t)},enableRateLimiting:e=>q(Xe,e)},ot={log:A,mapToNewConfig:e=>{const t={};for(const[o,r]of Object.entries(e)){const e=C[o]?C[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}return t},setOptions:(e,t)=>(t?.length&&(Ae=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const o=e[t+1];try{if(o&&o.endsWith(".json"))return JSON.parse(i(o))}catch(e){A(1,`[config] Unable to load config from the ${o}: ${e}`)}}return{}}(t)),Pe(R,Ae),Ae=je(R),e&&(Ae=Ie(Ae,e,L)),t?.length&&(Ae=function(e,t,o){for(let o=0;o(i.length-1===a&&void 0!==n[s]&&(t[++o]?n[s]=t[o]||n[s]:(console.log(`Missing argument value for ${r}!`.red,"\n"),e=W())),n[s])),e)}return e}(Ae,t)),Ae),singleExport:e=>{e.export.instr=e.export.instr||e.export.options,Ge(e,((e,t)=>{t&&(A(1,`[cli] ${t.message}`),process.exit(1));const{outfile:o,type:r}=e.options.export;n(o||`chart.${r}`,"svg"!==r?Buffer.from(e.data,"base64"):e.data),xe()}))},startExport:Ge,batchExport:e=>{const t=[];for(let o of e.export.batch.split(";"))o=o.split("="),2===o.length&&t.push(new Promise(((t,r)=>{Ge({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,o)=>{if(o)return r(o);n(e.options.export.outfile,Buffer.from(e.data,"base64")),t()}))})));Promise.all(t).then((()=>{xe()})).catch((e=>{A(1,`[chart] Error encountered during batch export: ${e}`),xe()}))},server:tt,startServer:et,killPool:xe,initPool:async(e={})=>{var t,o;return t=e.customCode&&e.customCode.allowCodeExecution,Ne=F(t),(o=e.logging&&parseInt(e.logging.level))>=0&&o<=_.levelsDesc.length&&(_.level=o),e.logging&&e.logging.dest&&((e,t)=>{if(_={..._,dest:e||_.dest,file:t||_.file,toFile:!0},0===_.dest.length)return A(1,"[logger] File logging init: no path supplied.");_.dest.endsWith("/")||(_.dest+="/")})(e.logging.dest,e.logging.file||"highcharts-export-server.log"),await Y(e.highcharts||{version:"latest"}),await Te({pool:e.pool||{initialWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer?.args||[]}),e}};export{ot as default}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index 6aadfc70..54adbb3a 100644 --- a/dist/index.esm.js.map +++ b/dist/index.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/schemas/config.js","../lib/logger.js","../lib/utils.js","../lib/server/rate_limit.js","../lib/fetch.js","../lib/cache.js","../lib/browser.js","../lib/export.js","../lib/benchmark.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/server/routes/health.js","../lib/config.js","../lib/chart.js","../lib/server/routes/export.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/server/routes/change_hc_version.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// Load .env into environment variables\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\n// This is the configuration object with all options and their default values,\n// also from the .env file if one exists\nexport const defaultConfig = {\n puppeteer: {\n args: {\n value: [],\n type: 'string[]',\n description: 'Array of arguments to send to puppeteer.'\n }\n },\n highcharts: {\n version: {\n value: 'latest',\n envLink: 'HIGHCHARTS_VERSION',\n type: 'string',\n description: 'Highcharts version to use.'\n },\n cdnURL: {\n value: 'https://code.highcharts.com/',\n envLink: 'HIGHCHARTS_CDN',\n type: 'string',\n description: 'The CDN URL of Highcharts scripts to use.'\n },\n coreScripts: {\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\n type: 'string[]',\n description: 'Highcharts core scripts to fetch.'\n },\n modules: {\n envLink: 'HIGHCHARTS_MODULES',\n value: [\n 'stock',\n 'map',\n 'gantt',\n 'exporting',\n 'export-data',\n 'parallel-coordinates',\n 'accessibility',\n 'annotations-advanced',\n 'boost-canvas',\n 'boost',\n 'data',\n 'draggable-points',\n 'static-scale',\n 'broken-axis',\n 'heatmap',\n 'tilemap',\n 'timeline',\n 'treemap',\n 'item-series',\n 'drilldown',\n 'histogram-bellcurve',\n 'bullet',\n 'funnel',\n 'funnel3d',\n 'pyramid3d',\n 'networkgraph',\n 'pareto',\n 'pattern-fill',\n 'pictorial',\n 'price-indicator',\n 'sankey',\n 'arc-diagram',\n 'dependency-wheel',\n 'series-label',\n 'solid-gauge',\n 'sonification',\n 'stock-tools',\n 'streamgraph',\n 'sunburst',\n 'variable-pie',\n 'variwide',\n 'vector',\n 'venn',\n 'windbarb',\n 'wordcloud',\n 'xrange',\n 'no-data-to-display',\n 'drag-panes',\n 'debugger',\n 'dumbbell',\n 'lollipop',\n 'cylinder',\n 'organization',\n 'dotplot',\n 'marker-clusters',\n 'hollowcandlestick',\n 'heikinashi'\n ],\n type: 'string[]',\n description: 'Highcharts modules to fetch.'\n },\n indicators: {\n envLink: 'HIGHCHARTS_INDICATORS',\n value: ['indicators-all'],\n type: 'string[]',\n description: 'Highcharts indicators to fetch.'\n },\n scripts: {\n value: [\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\n ],\n type: 'string[]',\n description:\n 'Additional direct scripts/optional dependencies (e.g. moment.js).'\n },\n forceFetch: {\n envLink: 'HIGHCHARTS_FORCE_FETCH',\n value: false,\n type: 'boolean',\n description:\n 'Should all the scripts be refetched after rerunning the server.'\n }\n },\n export: {\n infile: {\n value: false,\n type: 'string',\n description:\n 'The input file name along with a type (json or svg). It can be a correct JSON or SVG file.'\n },\n instr: {\n value: false,\n type: 'string',\n description:\n 'An input in a form of a stringified JSON or SVG file. Overrides the --infile.'\n },\n options: {\n value: false,\n type: 'string',\n description: 'An alias for the --instr option.'\n },\n outfile: {\n value: false,\n type: 'string',\n description:\n 'The output filename along with a type (jpeg, png, pdf or svg). Ignores the --type flag.'\n },\n type: {\n envLink: 'EXPORT_DEFAULT_TYPE',\n value: 'png',\n type: 'string',\n description:\n 'The format of the file to export to. Can be jpeg, png, pdf or svg.'\n },\n constr: {\n envLink: 'EXPORT_DEFAULT_CONSTR',\n value: 'chart',\n type: 'string',\n description:\n 'The constructor to use. Can be chart, stockChart, mapChart or ganttChart.'\n },\n defaultHeight: {\n envLink: 'EXPORT_DEFAULT_HEIGHT',\n value: 400,\n type: 'number',\n description:\n 'The default height of the exported chart. Used when not found any value set.'\n },\n defaultWidth: {\n envLink: 'EXPORT_DEFAULT_WIDTH',\n value: 600,\n type: 'number',\n description:\n 'The default width of the exported chart. Used when not found any value set.'\n },\n defaultScale: {\n envLink: 'EXPORT_DEFAULT_SCALE',\n value: 1,\n type: 'number',\n description:\n 'The default scale of the exported chart. Ranges between 1 and 5.'\n },\n height: {\n type: 'number',\n value: false,\n description:\n 'The default height of the exported chart. Overrides the option in the chart settings.'\n },\n width: {\n type: 'number',\n value: false,\n description:\n 'The width of the exported chart. Overrides the option in the chart settings.'\n },\n scale: {\n value: false,\n type: 'number',\n description: 'The scale of the exported chart. Ranges between 1 and 5.'\n },\n globalOptions: {\n value: false,\n type: 'string',\n description:\n 'A stringified JSON or a filename with options to be passed into the Highcharts.setOptions.'\n },\n themeOptions: {\n value: false,\n type: 'string',\n description:\n 'A stringified JSON or a filename with theme options to be passed into the Highcharts.setOptions.'\n },\n batch: {\n value: false,\n type: 'string',\n description:\n 'Starts a batch job. A string that contains input/output pairs: \"in=out;in=out;..\".'\n }\n },\n customCode: {\n allowCodeExecution: {\n envLink: 'HIGHCHARTS_ALLOW_CODE_EXECUTION',\n value: false,\n type: 'boolean',\n description:\n 'If set to true, allow for the execution of arbitrary code when exporting.'\n },\n allowFileResources: {\n envLink: 'HIGHCHARTS_ALLOW_FILE_RESOURCES',\n value: true,\n type: 'boolean',\n description:\n 'Allow injecting resources from the filesystem. Has no effect when running as a server.'\n },\n customCode: {\n value: false,\n type: 'string',\n description:\n 'A function to be called before chart initialization. Can be a filename with the js extension.'\n },\n callback: {\n value: false,\n type: 'string',\n description: 'A JavaScript file with a function to run on construction.'\n },\n resources: {\n value: false,\n type: 'string',\n description:\n 'An additional resource in a form of stringified JSON. It can contain files, js and css sections.'\n },\n loadConfig: {\n value: false,\n type: 'string',\n description: 'A file that contains a pre-defined config to use.'\n },\n createConfig: {\n value: false,\n type: 'string',\n description:\n 'Allows to set options through a prompt and save in a provided config file.'\n }\n },\n server: {\n enable: {\n envLink: 'HIGHCHARTS_SERVER_ENABLE',\n value: false,\n type: 'boolean',\n cliName: 'enableServer',\n description: 'If set to true, starts a server on 0.0.0.0.'\n },\n host: {\n envLink: 'HIGHCHARTS_SERVER_HOST',\n value: '0.0.0.0',\n type: 'string',\n description:\n 'The hostname of the server. Also starts a server listening on the supplied hostname.'\n },\n port: {\n envLink: 'HIGHCHARTS_SERVER_PORT',\n value: 7801,\n type: 'number',\n description: 'The port to use for the server. Defaults to 7801.'\n },\n ssl: {\n enable: {\n envLink: 'HIGHCHARTS_SERVER_SSL_ENABLE',\n value: false,\n type: 'boolean',\n cliName: 'enableSsl',\n description: 'Enables the SSL protocol.'\n },\n force: {\n envLink: 'HIGHCHARTS_SERVER_SSL_FORCE',\n value: false,\n type: 'boolean',\n cliName: 'sslForced',\n description:\n 'If set to true, forces the server to only serve over HTTPS.'\n },\n port: {\n envLink: 'HIGHCHARTS_SERVER_SSL_PORT',\n value: 443,\n type: 'number',\n cliName: 'sslPort',\n description: 'The port on which to run the SSL server.'\n },\n certPath: {\n envLink: 'HIGHCHARTS_SSL_CERT_PATH',\n value: '',\n type: 'string',\n description: 'The path to the SSL certificate/key.'\n }\n },\n rateLimiting: {\n enable: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_ENABLE',\n value: false,\n type: 'boolean',\n cliName: 'enableRateLimiting',\n description: 'Enables rate limiting.'\n },\n maxRequests: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_MAX',\n value: 10,\n type: 'number',\n description: 'Max requests allowed in a one minute.'\n },\n window: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_WINDOW',\n value: 1,\n type: 'number',\n description: 'The time window in minutes for rate limiting.'\n },\n delay: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_DELAY',\n value: 0,\n type: 'number',\n description:\n 'The amount to delay each successive request before hitting the max.'\n },\n trustProxy: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_TRUST_PROXY',\n value: false,\n type: 'boolean',\n description: 'Set this to true if behind a load balancer.'\n },\n skipKey: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_SKIP_KEY',\n value: '',\n type: 'number|string',\n description:\n 'Allows bypassing the rate limiter and should be provided with skipToken argument.'\n },\n skipToken: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_SKIP_TOKEN',\n value: '',\n type: 'number|string',\n description:\n 'Allows bypassing the rate limiter and should be provided with skipKey argument.'\n }\n }\n },\n pool: {\n initialWorkers: {\n envLink: 'HIGHCHARTS_POOL_MIN_WORKERS',\n value: 4,\n type: 'number',\n description: 'The number of initial workers to spawn.'\n },\n maxWorkers: {\n envLink: 'HIGHCHARTS_POOL_MAX_WORKERS',\n value: 8,\n type: 'number',\n description: 'The number of max workers to spawn.'\n },\n workLimit: {\n envLink: 'HIGHCHARTS_POOL_WORK_LIMIT',\n value: 40,\n type: 'number',\n description:\n 'The pieces of work that can be performed before restarting process.'\n },\n queueSize: {\n envLink: 'HIGHCHARTS_POOL_QUEUE_SIZE',\n value: 5,\n type: 'number',\n description: 'The size of the request overflow queue.'\n },\n timeoutThreshold: {\n envLink: 'HIGHCHARTS_POOL_TIMEOUT',\n value: 5000,\n type: 'number',\n description: 'The number of milliseconds before timing out.'\n },\n acquireTimeout: {\n envLink: 'HIGHCHARTS_POOL_ACQUIRE_TIMEOUT',\n value: 5000,\n type: 'number',\n description:\n 'The number of milliseconds to wait for acquiring a resource.'\n },\n reaper: {\n envLink: 'HIGHCHARTS_POOL_ENABLE_REAPER',\n value: true,\n type: 'boolean',\n description:\n 'Whether or not to evict workers after a certain time period.'\n },\n benchmarking: {\n envLink: 'HIGHCHARTS_POOL_BENCHMARKING',\n value: false,\n type: 'boolean',\n description: 'Enable benchmarking.'\n },\n listenToProcessExits: {\n envLink: 'HIGHCHARTS_POOL_LISTEN_TO_PROCESS_EXITS',\n value: true,\n type: 'boolean',\n description:\n 'Set to false in order to skip attaching process.exit handlers.'\n }\n },\n logging: {\n level: {\n envLink: 'HIGHCHARTS_LOG_LEVEL',\n value: 4,\n type: 'number',\n cliName: 'logLevel',\n description:\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose).'\n },\n file: {\n envLink: 'HIGHCHARTS_LOG_FILE',\n value: 'highcharts-export-server.log',\n type: 'string',\n cliName: 'logFile',\n description:\n 'A name of a log file. The --logDest also needs to be set to enable file logging.'\n },\n dest: {\n envLink: 'HIGHCHARTS_LOG_DEST',\n value: 'log/',\n type: 'string',\n cliName: 'logDest',\n description: 'The path to store log files. Also enables file logging.'\n }\n },\n ui: {\n enable: {\n envLink: 'HIGHCHARTS_UI_ENABLE',\n value: false,\n type: 'boolean',\n cliName: 'enableUi',\n description: 'Enables the UI for the export server.'\n },\n route: {\n envLink: 'HIGHCHARTS_UI_ROUTE',\n value: '/',\n type: 'string',\n cliName: 'uiRoute',\n description: 'The route to attach the UI to.'\n }\n },\n other: {\n noLogo: {\n envLink: 'HIGHCHARTS_NO_LOGO',\n value: false,\n type: 'boolean',\n description:\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\n }\n },\n payload: {}\n};\n\n// The config descriptions object for the prompts functionality. It contains\n// information like:\n// * Type of a prompt\n// * Name of an option\n// * Short description of a chosen option\n// * Initial value\nexport const promptsConfig = {\n puppeteer: [\n {\n type: 'list',\n name: 'args',\n message: 'Puppeteer arguments',\n initial: defaultConfig.puppeteer.args.value.join(','),\n separator: ','\n }\n ],\n highcharts: [\n {\n type: 'text',\n name: 'version',\n message: 'Highcharts version',\n initial: defaultConfig.highcharts.version.value\n },\n {\n type: 'text',\n name: 'cdnURL',\n message: 'The url of CDN',\n initial: defaultConfig.highcharts.cdnURL.value\n },\n {\n type: 'multiselect',\n name: 'modules',\n message: 'Available modules',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.modules.value\n },\n {\n type: 'list',\n name: 'scripts',\n message: 'Custom scripts',\n initial: defaultConfig.highcharts.scripts.value.join(','),\n separator: ','\n },\n {\n type: 'toggle',\n name: 'forceFetch',\n message: 'Should refetch all the scripts after each server rerun',\n initial: defaultConfig.highcharts.forceFetch.value\n }\n ],\n export: [\n {\n type: 'select',\n name: 'type',\n message: 'The default type of a file to export to',\n hint: `Default: ${defaultConfig.export.type.value}`,\n initial: 0,\n choices: ['png', 'jpeg', 'pdf', 'svg']\n },\n {\n type: 'select',\n name: 'constr',\n message: 'The default constructor for Highcharts to use',\n hint: `Default: ${defaultConfig.export.constr.value}`,\n initial: 0,\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\n },\n {\n type: 'number',\n name: 'defaultHeight',\n message: 'The default fallback height of the exported chart',\n initial: defaultConfig.export.defaultHeight.value\n },\n {\n type: 'number',\n name: 'defaultWidth',\n message: 'The default fallback width of the exported chart',\n initial: defaultConfig.export.defaultWidth.value\n },\n {\n type: 'number',\n name: 'defaultScale',\n message: 'The default fallback scale of the exported chart',\n initial: defaultConfig.export.defaultScale.value,\n min: 0.1,\n max: 5\n }\n ],\n customCode: [\n {\n type: 'toggle',\n name: 'allowCodeExecution',\n message: 'Allow to execute custom code',\n initial: defaultConfig.customCode.allowCodeExecution.value\n },\n {\n type: 'toggle',\n name: 'allowFileResources',\n message: 'Allow file resources',\n initial: defaultConfig.customCode.allowFileResources.value\n }\n ],\n server: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Starts a server on 0.0.0.0',\n initial: defaultConfig.server.enable.value\n },\n {\n type: 'text',\n name: 'host',\n message: 'A hostname of a server',\n initial: defaultConfig.server.host.value\n },\n {\n type: 'number',\n name: 'port',\n message: 'A port of a server',\n initial: defaultConfig.server.port.value\n },\n {\n type: 'toggle',\n name: 'ssl.enable',\n message: 'Enable SSL protocol',\n initial: defaultConfig.server.ssl.enable.value\n },\n {\n type: 'toggle',\n name: 'ssl.force',\n message: 'Force to only serve over HTTPS',\n initial: defaultConfig.server.ssl.force.value\n },\n {\n type: 'number',\n name: 'ssl.port',\n message: 'Port on which to run the SSL server',\n initial: defaultConfig.server.ssl.port.value\n },\n {\n type: 'text',\n name: 'ssl.certPath',\n message: 'A path where to find the SSL certificate/key',\n initial: defaultConfig.server.ssl.certPath.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.enable',\n message: 'Enable rate limiting',\n initial: defaultConfig.server.rateLimiting.enable.value\n },\n {\n type: 'number',\n name: 'rateLimiting.maxRequests',\n message: 'Max requests allowed in a one minute',\n initial: defaultConfig.server.rateLimiting.maxRequests.value\n },\n {\n type: 'number',\n name: 'rateLimiting.window',\n message: 'The time window in minutes for rate limiting',\n initial: defaultConfig.server.rateLimiting.window.value\n },\n {\n type: 'number',\n name: 'rateLimiting.delay',\n message:\n 'The amount to delay each successive request before hitting the max',\n initial: defaultConfig.server.rateLimiting.delay.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.trustProxy',\n message: 'Set this to true if behind a load balancer',\n initial: defaultConfig.server.rateLimiting.trustProxy.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipKey',\n message:\n 'Allows bypassing the rate limiter and should be provided with skipToken argument',\n initial: defaultConfig.server.rateLimiting.skipKey.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipToken',\n message:\n 'Allows bypassing the rate limiter and should be provided with skipKey argument',\n initial: defaultConfig.server.rateLimiting.skipToken.value\n }\n ],\n pool: [\n {\n type: 'number',\n name: 'initialWorkers',\n message: 'The number of initial workers to spawn',\n initial: defaultConfig.pool.initialWorkers.value\n },\n {\n type: 'number',\n name: 'maxWorkers',\n message: 'The number of max workers to spawn',\n initial: defaultConfig.pool.maxWorkers.value\n },\n {\n type: 'number',\n name: 'workLimit',\n message:\n 'The pieces of work that can be performed before restarting a puppeteer process',\n initial: defaultConfig.pool.workLimit.value\n },\n {\n type: 'number',\n name: 'queueSize',\n message: 'The size of the request overflow queue',\n initial: defaultConfig.pool.queueSize.value\n },\n {\n type: 'number',\n name: 'timeoutThreshold',\n message: 'The number of seconds before timing out',\n initial: defaultConfig.pool.timeoutThreshold.value\n },\n {\n type: 'number',\n name: 'acquireTimeout',\n message: 'The number of milliseconds to wait for acquiring a resource',\n initial: defaultConfig.pool.acquireTimeout.value\n },\n {\n type: 'toggle',\n name: 'reaper',\n message: 'The reaper to remove hanging processes',\n initial: defaultConfig.pool.reaper.value\n },\n {\n type: 'toggle',\n name: 'benchmarking',\n message: 'Set benchmarking',\n initial: defaultConfig.pool.benchmarking.value\n },\n {\n type: 'toggle',\n name: 'listenToProcessExits',\n message: 'Set to false in order to skip attaching process.exit handlers',\n initial: defaultConfig.pool.listenToProcessExits.value\n }\n ],\n logging: [\n {\n type: 'number',\n name: 'level',\n message:\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose)',\n initial: defaultConfig.logging.level.value,\n round: 0,\n min: 0,\n max: 4\n },\n {\n type: 'text',\n name: 'file',\n message:\n 'A name of a log file. The --logDest also needs to be set to enable file logging',\n initial: defaultConfig.logging.file.value\n },\n {\n type: 'text',\n name: 'dest',\n message: 'A path to log files. It enables file logging',\n initial: defaultConfig.logging.dest.value\n }\n ],\n ui: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Enable UI for the export server',\n initial: defaultConfig.ui.enable.value\n },\n {\n type: 'text',\n name: 'route',\n message: 'A route to attach the UI to',\n initial: defaultConfig.ui.route.value\n }\n ],\n other: [\n {\n type: 'toggle',\n name: 'noLogo',\n message:\n 'Skip printing the logo on a startup. Will be replaced by a simple text',\n initial: defaultConfig.other.noLogo.value\n }\n ]\n};\n\n// Absolute props that, in case of merging recursively, need to be force merged\nexport const absoluteProps = [\n 'options',\n 'globalOptions',\n 'themeOptions',\n 'resources',\n 'payload'\n];\n\n// Argument nesting level of all export server options\nexport const nestedArgs = {};\n\n/**\n * Creates nested arguments chain for all options\n *\n * @param {object} obj - The object based on which the initial configuration be\n * made.\n * @param {string } propChain - Required for creating a string chain of\n * properties for nested arguments.\n */\nconst createNestedArgs = (obj, propChain = '') => {\n Object.keys(obj).forEach((k) => {\n if (!['puppeteer', 'highcharts'].includes(k)) {\n const entry = obj[k];\n if (typeof entry.value === 'undefined') {\n // Go deeper in the nested arguments\n createNestedArgs(entry, `${propChain}.${k}`);\n } else {\n // Create the chain of nested arguments\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\n }\n }\n });\n};\n\ncreateNestedArgs(defaultConfig);\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { appendFile, existsSync, mkdirSync } from 'fs';\n\nimport { defaultConfig } from './schemas/config.js';\n\n// The default logging config\nlet logging = {\n // Flags for logging status\n toConsole: true,\n toFile: false,\n pathCreated: false,\n // Log levels\n levelsDesc: [\n {\n title: 'error',\n color: 'red'\n },\n {\n title: 'warning',\n color: 'yellow'\n },\n {\n title: 'notice',\n color: 'blue'\n },\n {\n title: 'verbose',\n color: 'gray'\n }\n ],\n // Log listeners\n listeners: []\n};\n\n// Gather init logging options\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\n logging[key] = option.value;\n}\n\n/**\n * Logs a message. Accepts a variable amount of arguments. Arguments after\n * `level` will be passed directly to console.log, and/or will be joined\n * and appended to the log file.\n *\n * @param {any} args - An array of arguments where the first is the log level\n * and the rest are strings to build a message with.\n */\nexport const log = (...args) => {\n const [newLevel, ...texts] = args;\n\n // Current logging options\n const { level, levelsDesc } = logging;\n\n // Check if log level is within a correct range\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\n return;\n }\n\n // Get rid of the GMT text information\n const newDate = new Date().toString().split('(')[0].trim();\n\n // Create a message's prefix\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\n\n // Call available log listeners\n logging.listeners.forEach((fn) => {\n fn(prefix, texts.join(' '));\n });\n\n // Log to file\n if (logging.toFile) {\n if (!logging.pathCreated) {\n // Create if does not exist\n !existsSync(logging.dest) && mkdirSync(logging.dest);\n\n // We now assume the path is available, e.g. it's the responsibility\n // of the user to create the path with the correct access rights.\n logging.pathCreated = true;\n }\n\n // Add the content to a file\n appendFile(\n `${logging.dest}${logging.file}`,\n [prefix].concat(texts).join(' ') + '\\n',\n (error) => {\n if (error) {\n console.log(`[logger] Unable to write to log file: ${error}`);\n logging.toFile = false;\n }\n }\n );\n }\n\n // Log to console\n if (logging.toConsole) {\n console.log.apply(\n undefined,\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\n );\n }\n};\n\n/**\n * Sets the file logging configuration.\n *\n * @param {string} logDest - A path to log to.\n * @param {string} logFile - The name of the log file.\n */\nexport const enableFileLogging = (logDest, logFile) => {\n // Update logging options\n logging = {\n ...logging,\n dest: logDest || logging.dest,\n file: logFile || logging.file,\n toFile: true\n };\n\n if (logging.dest.length === 0) {\n return log(1, '[logger] File logging init: no path supplied.');\n }\n\n if (!logging.dest.endsWith('/')) {\n logging.dest += '/';\n }\n};\n\n/**\n * Adds a log listener.\n *\n * @param {function} fn - The function to call when getting a log event.\n */\nexport const listen = (fn) => {\n logging.listeners.push(fn);\n};\n\n/**\n * Sets the current log level. Log levels are:\n * - 0 = no logging\n * - 1 = error\n * - 2 = warning\n * - 3 = notice\n * - 4 = verbose\n *\n * @param {number} newLevel - The new log level (0 - 4).\n */\nexport const setLogLevel = (newLevel) => {\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\n logging.level = newLevel;\n }\n};\n\n/**\n * Enables or disables logging to the stdout.\n *\n * @param {boolean} enabled - Whether log to console or not.\n */\nexport const toggleSTDOut = (enabled) => {\n logging.toConsole = enabled;\n};\n\nexport default {\n log,\n enableFileLogging,\n listen,\n setLogLevel,\n toggleSTDOut\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\n\nimport { defaultConfig } from '../lib/schemas/config.js';\nimport { log } from './logger.js';\n\nconst MAX_BACKOFF_ATTEMPTS = 6;\n\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\n\n/**\n * Clears text from whitespaces with a regex rule.\n *\n * @param {string} rule - The rule for clearing a string, default to /\\s\\s+/g.\n * @return {string} - Cleared text.\n */\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\n text.replaceAll(rule, replacer).trim();\n\n/**\n * Delays calling the function by time calculated based on the backoff\n * algorithm.\n *\n * @param {function} fn - A function to try to call with the backoff algorithm\n * on.\n * @param {number} attempt - The number of an attempt, where the first one is 0.\n */\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\n try {\n // Try to call the function\n return await fn(...args);\n } catch (error) {\n // Calculate delay in ms\n const delayInMs = 2 ** attempt * 1000;\n\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\n throw error;\n }\n\n // Wait given amount of time\n await new Promise((response) => setTimeout(response, delayInMs));\n log(\n 3,\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\n );\n\n // Try again\n return expBackoff(fn, attempt, ...args);\n }\n};\n\n/**\n * Fixes to supported type format if MIME.\n *\n * @param {string} type - Type to be corrected.\n * @param {string} outfile - Name of the outfile.\n */\nexport const fixType = (type, outfile) => {\n // MIME types\n const mimeTypes = {\n 'image/png': 'png',\n 'image/jpeg': 'jpeg',\n 'application/pdf': 'pdf',\n 'image/svg+xml': 'svg'\n };\n\n // Formats\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\n\n // Check if type and outfile's extensions are the same\n if (outfile) {\n const outType = outfile.split('.').pop();\n\n // Check if extension has a correct type\n if (formats.includes(outType) && type !== outType) {\n type = outType;\n }\n }\n\n // Return a correct type\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\n};\n\n/**\n * Handles the provided resources.\n *\n * @param {string} resources - The stringified resources.\n * @param {string} allowFileResources - Decide if resources from file are\n * allowed.\n */\nexport const handleResources = (resources = false, allowFileResources) => {\n const allowedProps = ['js', 'css', 'files'];\n\n let handledResources = resources;\n let correctResources = false;\n\n // Try to load resources from a file\n if (allowFileResources && resources.endsWith('.json')) {\n try {\n if (!resources) {\n handledResources = isCorrectJSON(\n readFileSync('resources.json', 'utf8')\n );\n } else if (resources && resources.endsWith('.json')) {\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\n } else {\n handledResources = isCorrectJSON(resources);\n if (handledResources === true) {\n handledResources = isCorrectJSON(\n readFileSync('resources.json', 'utf8')\n );\n }\n }\n } catch (notice) {\n return log(3, `[cli] No resources found.`);\n }\n } else {\n // Try to get JSON\n handledResources = isCorrectJSON(resources);\n\n // Get rid of the files section\n if (!allowFileResources) {\n delete handledResources.files;\n }\n }\n\n // Filter from unnecessary properties\n for (const propName in handledResources) {\n if (!allowedProps.includes(propName)) {\n delete handledResources[propName];\n } else if (!correctResources) {\n correctResources = true;\n }\n }\n\n // Check if at least one of allowed properties is present\n if (!correctResources) {\n return log(3, `[cli] No resources found.`);\n }\n\n // Handle files section\n if (handledResources.files) {\n handledResources.files = handledResources.files.map((item) => item.trim());\n if (!handledResources.files || handledResources.files.length <= 0) {\n delete handledResources.files;\n }\n }\n\n // Return resources\n return handledResources;\n};\n\n/**\n * Checks if provided data is or can be a correct JSON.\n *\n * @param {any} data - Data to be checked.\n * @param {boolean} toString - If true, return stringified representation.\n */\nexport function isCorrectJSON(data, toString) {\n try {\n // Get the string representation if not already before parsing\n const parsedData = JSON.parse(\n typeof data !== 'string' ? JSON.stringify(data) : data\n );\n\n // Return a stringified representation of a JSON if required\n if (typeof parsedData !== 'string' && toString) {\n return JSON.stringify(parsedData);\n }\n\n // Return a JSON\n return parsedData;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Checks if item is an object.\n *\n * @param {any} item - Item to be checked.\n */\nexport const isObject = (item) =>\n typeof item === 'object' && !Array.isArray(item) && item !== null;\n\n/**\n * Checks if string contains private range urls.\n *\n * @export utils\n * @param item {string} item to be checked\n */\nexport const isPrivateRangeUrlFound = (item) => {\n return [\n 'localhost',\n '(10).(.*).(.*).(.*)',\n '(127).(.*).(.*).(.*)',\n '(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)',\n '(192).(168).(.*).(.*)'\n ].some((ipRegEx) =>\n item.match(`xlink:href=\"(?:(http://|https://))?${ipRegEx}`)\n );\n};\n\n/**\n * Creates and returns a deep copy of the given object.\n *\n * @param {object} object - Object to copy.\n * @return {object} - Deep copy of the object.\n */\nexport const deepCopy = (obj) => {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n const copy = Array.isArray(obj) ? [] : {};\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n copy[key] = deepCopy(obj[key]);\n }\n }\n\n return copy;\n};\n\n/**\n * Stringifies object with options. Possible to preserve functions with\n * allowFunctions flag.\n *\n * @param {object} options - Options to stringify.\n * @param {boolean} allowFunctions - Flag for keeping functions.\n */\nexport const optionsStringify = (options, allowFunctions) => {\n const replacerCallback = (name, value) => {\n if (typeof value === 'string') {\n value = value.trim();\n\n // If allowFunctions is set to true, preserve functions\n if (\n (value.startsWith('function(') || value.startsWith('function (')) &&\n value.endsWith('}')\n ) {\n value = allowFunctions\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\n : undefined;\n }\n }\n\n return typeof value === 'function'\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\n : value;\n };\n\n // Stringify options and if required, replace special functions marks\n return JSON.stringify(options, replacerCallback).replaceAll(\n /\"EXP_FUN|EXP_FUN\"/g,\n ''\n );\n};\n\n/**\n * Prints the export server logo.\n *\n * @param {boolean} noLogo - Whether to display logo or text.\n */\nexport const printLogo = (noLogo) => {\n // Get package version either from env or from package.json\n const packageVersion =\n process.env.npm_package_version ||\n JSON.parse(readFileSync(new URL('../package.json', import.meta.url)))\n .version;\n\n // Print text only\n if (noLogo) {\n console.log(`Starting highcharts export server v${packageVersion}...`);\n return;\n }\n\n // Print the logo\n console.log(\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\n `v${packageVersion}`\n );\n};\n\n/**\n * Prints the CLI usage. If required, it can list properties recursively\n */\nexport function printUsage() {\n const pad = 48;\n const readme = 'https://github.com/highcharts/node-export-server#readme';\n\n // Display readme information\n console.log(\n 'Usage of CLI arguments:'.bold,\n '\\n------',\n `\\nFor more detailed information visit readme at: ${readme.bold.yellow}.`\n );\n\n const cycleCategories = (categories) => {\n for (const [name, option] of Object.entries(categories)) {\n // If category has more levels, go further\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\n cycleCategories(option);\n } else {\n let descName = ` --${option.cliName || name} ${\n ('<' + option.type + '>').green\n } `;\n if (descName.length < pad) {\n for (let i = descName.length; i < pad; i++) {\n descName += '.';\n }\n }\n\n // Display correctly aligned messages\n console.log(\n descName,\n option.description,\n `[Default: ${option.value.toString().bold}]`.blue\n );\n }\n }\n };\n\n // Cycle through options of each categories and display the usage info\n Object.keys(defaultConfig).forEach((category) => {\n // Only puppeteer and highcharts categories cannot be configured through CLI\n if (!['puppeteer', 'highcharts'].includes(category)) {\n console.log(`\\n${category.toUpperCase()}`.red);\n cycleCategories(defaultConfig[category]);\n }\n });\n console.log('\\n');\n}\n\n/**\n * Rounds number to passed precision.\n *\n * @param {number} value - Number to round.\n * @param {number} precision - A precision of rounding.\n */\nexport const roundNumber = (value, precision = 1) => {\n const multiplier = Math.pow(10, precision || 0);\n return Math.round(+value * multiplier) / multiplier;\n};\n\n/**\n * Casts the item to boolean.\n *\n * @param {any} item - Item to be cast.\n */\nexport const toBoolean = (item) =>\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\n ? false\n : !!item;\n\n/**\n * If necessary, places a custom code inside a function.\n *\n * @param {any} customCode - The customCode.\n */\nexport const wrapAround = (customCode, allowFileResources) => {\n if (customCode && typeof customCode === 'string') {\n customCode = customCode.trim();\n\n if (customCode.endsWith('.js')) {\n return allowFileResources\n ? wrapAround(readFileSync(customCode, 'utf8'))\n : false;\n } else if (\n customCode.startsWith('function()') ||\n customCode.startsWith('function ()') ||\n customCode.startsWith('()=>') ||\n customCode.startsWith('() =>')\n ) {\n return `(${customCode})()`;\n }\n return customCode.replace(/;$/, '');\n }\n};\n\n/**\n * Utility to measure time.\n */\nexport const measureTime = () => {\n const start = process.hrtime.bigint();\n return () => Number(process.hrtime.bigint() - start) / 1000000;\n};\n\nexport default {\n __dirname,\n clearText,\n expBackoff,\n fixType,\n handleResources,\n isCorrectJSON,\n isObject,\n isPrivateRangeUrlFound,\n optionsStringify,\n printLogo,\n printUsage,\n roundNumber,\n toBoolean,\n wrapAround,\n measureTime\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport rateLimit from 'express-rate-limit';\n\nimport { clearText } from '../utils.js';\nimport { log } from '../logger.js';\n\n/**\n * Enables rate limiting for a given app.\n *\n * @param {object} app - The express app.\n * @param {object} limitConfig - The options for the rate limiting.\n */\nexport default (app, limitConfig) => {\n const msg =\n 'Too many requests, you have been rate limited. Please try again later.';\n\n // Options for the rate limiter\n const rateOptions = {\n max: limitConfig.maxRequests || 30,\n window: limitConfig.window || 1,\n delay: limitConfig.delay || 0,\n trustProxy: limitConfig.trustProxy || false,\n skipKey: limitConfig.skipKey || false,\n skipToken: limitConfig.skipToken || false\n };\n\n // Set if behind a proxy\n if (rateOptions.trustProxy) {\n app.enable('trust proxy');\n }\n\n // Create a limiter\n const limiter = rateLimit({\n windowMs: rateOptions.window * 60 * 1000,\n // Limit each IP to 100 requests per windowMs\n max: rateOptions.max,\n // Disable delaying, full speed until the max limit is reached\n delayMs: rateOptions.delay,\n handler: (request, response) => {\n response.format({\n json: () => {\n response.status(429).send({ message: msg });\n },\n default: () => {\n response.status(429).send(msg);\n }\n });\n },\n skip: (request) => {\n // Allow bypassing the limiter if a valid key/token has been sent\n if (\n rateOptions.skipKey !== false &&\n rateOptions.skipToken !== false &&\n request.query.key === rateOptions.skipKey &&\n request.query.access_token === rateOptions.skipToken\n ) {\n log(4, '[rate-limiting] Skipping rate limiter.');\n return true;\n }\n return false;\n }\n });\n\n // Use a limiter as a middleware\n app.use(limiter);\n\n log(\n 3,\n clearText(\n `[rate-limiting] Enabled rate limiting: ${rateOptions.max} requests\n per ${rateOptions.window} minute per IP, trusting proxy:\n ${rateOptions.trustProxy}.`\n )\n );\n};\n","/**\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\n */\n\nimport http from 'http';\nimport https from 'https';\n\n/**\n * Determines the protocol of the given URL (either `http` or `https`).\n *\n * @function\n * @param {string} url - The URL whose protocol needs to be determined.\n * @returns {Object} Returns the `https` module if the URL starts with 'https',\n * otherwise returns the `http` module.\n * @private\n *\n * @example\n *\n * const protocol = getProtocol('https://example.com');\n * console.log(protocol); // Outputs the 'https' module\n */\nconst getProtocol = (url) => {\n return url.startsWith('https') ? https : http;\n};\n\n/**\n * Sends a GET request to the specified URL with optional request options.\n *\n * @function\n * @async\n * @param {string} url - The URL to fetch.\n * @param {Object} [requestOptions={}] - Optional request options and headers.\n * @returns {Promise} Returns a promise that resolves with the response object.\n * The response object contains a `.text` property with the raw response data.\n * @throws {Error} Throws an error if the request fails or if no data is fetched from the URL.\n *\n * @example\n *\n * async function getData() {\n * try {\n * const response = await fetch('https://api.example.com/data');\n * console.log(response.text);\n * } catch (error) {\n * console.error('Error fetching data:', error);\n * }\n * }\n *\n * getData();\n */\nasync function fetch(url, requestOptions = {}) {\n return new Promise((resolve, reject) => {\n const protocol = getProtocol(url);\n\n protocol\n .get(url, requestOptions, (res) => {\n let data = '';\n\n // A chunk of data has been received.\n res.on('data', (chunk) => {\n data += chunk;\n });\n\n // The whole response has been received.\n res.on('end', () => {\n if (!data) {\n reject('Nothing was fetched from the URL.');\n }\n\n res.text = data;\n resolve(res);\n });\n })\n .on('error', (error) => {\n reject(error);\n });\n });\n}\n\n/**\n * Sends a POST request to the specified URL with the given body and request options.\n *\n * @function\n * @async\n * @param {string} url - The URL to which the request should be sent.\n * @param {Object} [body={}] - The data to be sent as the request body, in JSON format.\n * @param {Object} [requestOptions={}] - Optional request options and headers.\n * @returns {Promise} - Returns a promise that resolves with the parsed JSON response.\n * @throws {Error} Throws an error if the request fails or if the response cannot be parsed.\n *\n * @example\n *\n * async function sendData() {\n * const dataToSend = {\n * key1: 'value1',\n * key2: 'value2',\n * };\n * try {\n * const response = await post('https://api.example.com/data', dataToSend);\n * console.log(response);\n * } catch (error) {\n * console.error('Error sending data:', error);\n * }\n * }\n *\n * sendData();\n */\nasync function post(url, body = {}, requestOptions = {}) {\n return new Promise((resolve, reject) => {\n const protocol = getProtocol(url);\n const data = JSON.stringify(body);\n\n // Set default headers and merge with requestOptions\n const options = Object.assign(\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Length': data.length\n }\n },\n requestOptions\n );\n\n const req = protocol\n .request(url, options, (res) => {\n let responseData = '';\n\n // A chunk of data has been received.\n res.on('data', (chunk) => {\n responseData += chunk;\n });\n\n // The whole response has been received.\n res.on('end', () => {\n try {\n res.text = responseData;\n resolve(res);\n } catch (error) {\n reject(error);\n }\n });\n })\n .on('error', (error) => {\n reject(error);\n });\n\n // Write the request body and end the request.\n req.write(data);\n req.end();\n });\n}\n\nexport default fetch;\nexport { fetch, post };\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// The cache manager manages the Highcharts library and its dependencies.\n// The cache itself is stored in .cache, and is checked by the config system\n// before starting the service\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\n\nimport dotenv from 'dotenv';\nimport HttpsProxyAgent from 'https-proxy-agent';\nimport { fetch } from './fetch.js';\n\nimport { log } from './logger.js';\nimport { __dirname } from '../lib/utils.js';\n\ndotenv.config();\n\nconst cachePath = join(__dirname, '.cache');\n\nconst cache = {\n cdnURL: 'https://code.highcharts.com/',\n activeManifest: {},\n sources: '',\n hcVersion: ''\n};\n\n// TODO: The config should be accesssible globally so we don't have to do this sort of thing..\nlet appliedConfig = false;\n\n/**\n * Extracts the Highcharts version from the cache\n */\nconst extractVersion = () =>\n (cache.hcVersion = cache.sources\n .substr(0, cache.sources.indexOf('*/'))\n .replace('/*', '')\n .replace('*/', '')\n .replace(/\\n/g, '')\n .trim());\n\n/**\n * Saves the Highcharts part of a config to a manifest file in the cache\n *\n * @param {object} config - Highcharts related configuration object.\n * @param {object} fetchedModules - An object that contains mapped names of\n * fetched Highcharts modules to use.\n */\nconst saveConfigToManifest = async (config, fetchedModules) => {\n const newManifest = {\n version: config.version,\n modules: fetchedModules || {}\n };\n\n // Update cache object with the current modules\n cache.activeManifest = newManifest;\n\n log(4, '[cache] writing new manifest');\n\n try {\n writeFileSync(\n join(cachePath, 'manifest.json'),\n JSON.stringify(newManifest),\n 'utf8'\n );\n } catch (error) {\n log(1, `[cache] Error writing cache manifest: ${error}.`);\n }\n};\n\n/**\n * Fetches a single script.\n *\n * @param {string} script - A path to script to get.\n * @param {object} proxyAgent - The proxy agent to use for a request.\n */\nconst fetchScript = async (script, proxyAgent) => {\n try {\n // Get rid of the .js from the custom strings\n if (script.endsWith('.js')) {\n script = script.substring(0, script.length - 3);\n }\n\n log(4, `[cache] Fetching script - ${script}.js`);\n\n // If exists, add proxy agent to request options\n const requestOptions = proxyAgent\n ? {\n agent: proxyAgent,\n timeout: +process.env['PROXY_SERVER_TIMEOUT'] || 5000\n }\n : {};\n\n // Fetch the script\n const response = await fetch(`${script}.js`, requestOptions);\n\n // If OK, return its text representation\n if (response.statusCode === 200) {\n return response.text;\n }\n\n throw `${response.statusCode}`;\n } catch (error) {\n log(1, `[cache] Error fetching script ${script}.js: ${error}.`);\n throw error;\n }\n};\n\n/**\n * Updates the Highcharts cache.\n *\n * @param {object} config - Highcharts related configuration object.\n * @param {string} sourcePath - A path to the file where save updated sources.\n * @return {object} An object that contains mapped names of fetched Highcharts\n * modules to use.\n */\nconst updateCache = async (config, sourcePath) => {\n const { coreScripts, modules, indicators, scripts: customScripts } = config;\n const hcVersion =\n config.version === 'latest' || !config.version ? '' : `${config.version}/`;\n\n log(3, '[cache] Updating cache to Highcharts ', hcVersion);\n\n // Gather all scripts to fetch\n const allScripts = [\n ...coreScripts.map((c) => `${hcVersion}${c}`),\n ...modules.map((m) =>\n m === 'map' ? `maps/${hcVersion}modules/${m}` : `${hcVersion}modules/${m}`\n ),\n ...indicators.map((i) => `stock/${hcVersion}indicators/${i}`)\n ];\n\n // Configure proxy if exists\n let proxyAgent;\n const proxyHost = process.env['PROXY_SERVER_HOST'];\n const proxyPort = process.env['PROXY_SERVER_PORT'];\n\n if (proxyHost && proxyPort) {\n proxyAgent = new HttpsProxyAgent({\n host: proxyHost,\n port: +proxyPort\n });\n }\n\n const fetchedModules = {};\n try {\n cache.sources = // TODO: convert to for loop\n (\n await Promise.all([\n ...allScripts.map(async (script) => {\n const text = await fetchScript(\n `${config.cdnURL || cache.cdnURL}${script}`,\n proxyAgent\n );\n\n // If fetched correctly, set it\n if (typeof text === 'string') {\n fetchedModules[\n script.replace(\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\n ''\n )\n ] = 1;\n }\n\n return text;\n }),\n ...customScripts.map((script) => fetchScript(script, proxyAgent))\n ])\n ).join(';\\n');\n extractVersion();\n\n // Save the fetched modules into caches' source JSON\n writeFileSync(sourcePath, cache.sources);\n return fetchedModules;\n } catch (error) {\n log(1, '[cache] Unable to update local Highcharts cache.');\n }\n};\n\nexport const updateVersion = async (newVersion) =>\n appliedConfig\n ? await checkCache(\n Object.assign(appliedConfig, {\n version: newVersion\n })\n )\n : false;\n\n/**\n * Fetches any missing Highcharts and dependencies\n *\n * @param {object} config - Highcharts related configuration object.\n */\nexport const checkCache = async (config) => {\n let fetchedModules;\n // Prepare paths to manifest and sources from the .cache folder\n const manifestPath = join(cachePath, 'manifest.json');\n const sourcePath = join(cachePath, 'sources.js');\n\n // TODO: deal with trying to switch to the running version\n // const activeVersion = appliedConfig ? appliedConfig.version : false;\n\n appliedConfig = config;\n\n // Create the .cache destination if it doesn't exist already\n !existsSync(cachePath) && mkdirSync(cachePath);\n\n // Fetch all the scripts either if manifest.json does not exist\n // or if the forceFetch option is enabled\n if (!existsSync(manifestPath) || config.forceFetch) {\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\n fetchedModules = await updateCache(config, sourcePath);\n } else {\n let requestUpdate = false;\n\n // Read the manifest JSON\n const manifest = JSON.parse(readFileSync(manifestPath));\n\n // Check if the modules is an array, if so, we rewrite it to a map to make\n // it easier to resolve modules.\n if (manifest.modules && Array.isArray(manifest.modules)) {\n const moduleMap = {};\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\n manifest.modules = moduleMap;\n }\n\n const { modules, coreScripts, indicators } = config;\n const numberOfModules =\n modules.length + coreScripts.length + indicators.length;\n\n // Compare the loaded config with the contents in .cache.\n // If there are changes, fetch requested modules and products,\n // and bake them into a giant blob. Save the blob.\n if (manifest.version !== config.version) {\n log(3, '[cache] Highcharts version mismatch in cache, need to re-fetch.');\n requestUpdate = true;\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\n log(\n 3,\n '[cache] Cache and requested modules does not match, need to re-fetch.'\n );\n requestUpdate = true;\n } else {\n // Check each module, if anything is missing refetch everything\n requestUpdate = (config.modules || []).some((moduleName) => {\n if (!manifest.modules[moduleName]) {\n log(\n 3,\n `[cache] The ${moduleName} missing in cache, need to re-fetch.`\n );\n return true;\n }\n });\n }\n\n if (requestUpdate) {\n fetchedModules = await updateCache(config, sourcePath);\n } else {\n log(3, '[cache] Dependency cache is up to date, proceeding.');\n\n // Load the sources\n cache.sources = readFileSync(sourcePath, 'utf8');\n\n // Get current modules map\n fetchedModules = manifest.modules;\n extractVersion();\n }\n }\n\n // Finally, save the new manifest, which is basically our current config\n // in a slightly different format\n await saveConfigToManifest(config, fetchedModules);\n};\n\nexport default {\n checkCache,\n updateVersion,\n getCache: () => cache,\n highcharts: () => cache.sources,\n version: () => cache.hcVersion\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport puppeteer from 'puppeteer';\nimport fs from 'fs';\nimport * as url from 'url';\nimport { log } from './logger.js';\nimport path from 'node:path';\n\n// Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1463328\n// Not ideal - leaves trash in the FS\nimport { randomBytes } from 'node:crypto';\nconst RANDOM_PID = randomBytes(64).toString('base64url');\nconst PUPPETEER_DIR = path.join('tmp', `puppeteer-${RANDOM_PID}`);\nconst DATA_DIR = path.join(PUPPETEER_DIR, 'profile');\n\n// The minimal args to speed up the browser\nconst minimalArgs = [\n `--user-data-dir=${DATA_DIR}`,\n '--autoplay-policy=user-gesture-required',\n '--disable-background-networking',\n '--disable-background-timer-throttling',\n '--disable-backgrounding-occluded-windows',\n '--disable-breakpad',\n '--disable-client-side-phishing-detection',\n '--disable-component-update',\n '--disable-default-apps',\n '--disable-dev-shm-usage',\n '--disable-domain-reliability',\n '--disable-extensions',\n '--disable-features=AudioServiceOutOfProcess',\n '--disable-hang-monitor',\n '--disable-ipc-flooding-protection',\n '--disable-notifications',\n '--disable-offer-store-unmasked-wallet-cards',\n '--disable-popup-blocking',\n '--disable-print-preview',\n '--disable-prompt-on-repost',\n '--disable-renderer-backgrounding',\n '--disable-session-crashed-bubble',\n '--disable-setuid-sandbox',\n '--disable-speech-api',\n '--disable-sync',\n '--hide-crash-restore-bubble',\n '--hide-scrollbars',\n '--ignore-gpu-blacklist',\n '--metrics-recording-only',\n '--mute-audio',\n '--no-default-browser-check',\n '--no-first-run',\n '--no-pings',\n '--no-sandbox',\n '--no-zygote',\n '--password-store=basic',\n '--use-mock-keychain'\n];\n\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\n\nconst template = fs.readFileSync(\n __dirname + '/../templates/template.html',\n 'utf8'\n);\n\nlet browser;\n\nexport const newPage = async () => {\n if (!browser) return false;\n\n const p = await browser.newPage();\n\n await p.setContent(template);\n await p.addScriptTag({ path: __dirname + '/../.cache/sources.js' });\n // eslint-disable-next-line no-undef\n await p.evaluate(() => window.setupHighcharts());\n\n p.on('pageerror', async (err) => {\n // TODO: Consider adding a switch here that turns on log(0) logging\n // on page errors.\n log(1, '[page error]', err);\n await p.$eval(\n '#container',\n (element, errorMessage) => {\n // eslint-disable-next-line no-undef\n if (window._displayErrors) {\n element.innerHTML = errorMessage;\n }\n },\n `

Chart input data error

${err.toString()}`\n );\n });\n\n return p;\n};\n\nexport const create = async (puppeteerArgs) => {\n const allArgs = [...minimalArgs, ...(puppeteerArgs || [])];\n\n // Create a browser\n if (!browser) {\n let tryCount = 0;\n\n const open = async () => {\n try {\n log(\n 3,\n '[browser] attempting to get a browser instance (try',\n tryCount + ')'\n );\n\n browser = await puppeteer.launch({\n headless: 'new',\n args: allArgs,\n userDataDir: './tmp/'\n });\n } catch (e) {\n log(0, '[browser]', e);\n if (++tryCount < 25) {\n log(3, '[browser] failed:', e);\n await new Promise((response) => setTimeout(response, 4000));\n await open();\n } else {\n log(0, 'Max retries reached');\n }\n }\n };\n\n try {\n await open();\n } catch (e) {\n log(0, '[browser] Unable to open browser');\n return false;\n }\n\n if (!browser) {\n log(0, '[browser] Unable to open browser');\n return false;\n }\n }\n\n // Return a browser promise\n return browser;\n};\n\nexport const get = async () => {\n if (!browser) {\n throw 'No valid browser has been created';\n }\n\n return browser;\n};\n\nexport const close = async () => {\n // Close the browser when connnected\n if (browser.connected) {\n await browser.close();\n }\n};\n\nexport default {\n get,\n close,\n newPage\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// TODO: remove this temp benchmark stuff. I had this idea of doing a general benchmarking\n// system, but it adds so much bloat in the code that it shouldn't be there.\n\nimport benchmark from './benchmark.js';\nimport cache from './cache.js';\nimport { log } from './logger.js';\nimport svgTemplate from './../templates/svg_export/svg_export.js';\n\nimport { readFileSync } from 'fs';\nimport path from 'path';\nimport * as url from 'url';\n\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\n\n// const jsonTemplate = require('./../templates/json_export/json_export.js');\n\n/**\n * Gets the clip region for the chart DOM node.\n *\n * @param {object} page - A page of a browser instance.\n * @return {object} - A clipped region.\n */\nconst getClipRegion = (page) =>\n page.$eval('#chart-container', (element) => {\n const { x, y, width, height } = element.getBoundingClientRect();\n return {\n x,\n y,\n width,\n height: Math.trunc(height > 1 ? height : 500)\n };\n });\n\n/**\n * Rasterizes the page to an image (PNG or JPEG)\n *\n * @param {object} page - A page of a browser instance.\n * @param {string} type - The type of a result image.\n * @param {string} encoding - The type of encoding used.\n * @param {string} clip - The clip region.\n * @returns {string} - A string representation of a screenshot.\n */\nconst createImage = async (page, type, encoding, clip) =>\n await Promise.race([\n page.screenshot({\n type,\n encoding,\n clip,\n\n // #447 - always render on a transparent page\n // this will not affect users who do not explicitly set\n // chart.backgroundColor to a color with opacity lower than 1\n omitBackground: true\n }),\n new Promise((resolve, reject) =>\n setTimeout(() => reject(new Error('Rasterization timeout')), 1500)\n )\n ]);\n\n/**\n * Turns page into a PDF.\n *\n * @param {object} page - A page of a browser instance.\n * @param {number} height - The height of a chart.\n * @param {number} width - The width of a chart.\n * @param {string} encoding - The type of encoding used.\n * @return {object} - A buffer with PDF representation.\n */\nconst createPDF = async (page, height, width, encoding) =>\n await page.pdf({\n // This will remove an extra empty page in PDF exports\n height: height + 1,\n width,\n encoding\n });\n\n/**\n * Exports as a SVG.\n *\n * @param {object} page - A page of a browser instance.\n * @return {object} - The outerHTML element with the SVG representation.\n */\nconst createSVG = async (page) =>\n await page.$eval(\n '#container svg:first-of-type',\n (element) => element.outerHTML\n );\n\n/** Load config into a page and render a chart */\nconst setAsConfig = async (page, chart, options) =>\n await page.evaluate(\n // eslint-disable-next-line no-undef\n (chart, options) => window.triggerExport(chart, options),\n chart,\n options\n );\n\n/** Load SVG into a page */\n// const setAsSVG = async (page, svgStr) => true;\n\n/**\n * Does an export for a given browser.\n *\n * @param {object} browser - A browser instance.\n * @param {object} chart - Chart's options.\n * @param {object} options - All options object.\n * @return {object} - The data returned from one of the methods for exporting\n * a specific type of an image.\n */\nexport default async (page, chart, options) => {\n /**\n * Keeps track of all resources added on the page with addXXXTag. etc\n * It's VITAL that all added resources ends up here so we can clear things\n * out when doing a new export in the same page!\n */\n const injectedResources = [];\n\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\n const clearInjected = async (page) => {\n for (const res of injectedResources) {\n await res.dispose();\n }\n\n // Reset all CSS and script tags\n await page.evaluate(() => {\n // eslint-disable-next-line no-undef\n const [, ...scriptsToRemove] = document.getElementsByTagName('script');\n // eslint-disable-next-line no-undef\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\n // eslint-disable-next-line no-undef\n const [...linksToRemove] = document.getElementsByTagName('link');\n\n // Remove tags\n for (const element of [\n ...scriptsToRemove,\n ...stylesToRemove,\n ...linksToRemove\n ]) {\n element.remove();\n }\n });\n };\n\n try {\n const exportBench = benchmark('Puppeteer');\n\n log(4, '[export] Determining export path.');\n\n const exportOptions = options.export;\n\n // Force a rAF\n // See https://github.com/puppeteer/puppeteer/issues/7507\n // eslint-disable-next-line no-undef\n await page.evaluate(() => requestAnimationFrame(() => {}));\n\n // Decide whether display error or debbuger wrapper around it\n const displayErrors =\n exportOptions?.options?.chart?.displayErrors &&\n cache.getCache().activeManifest.modules.debugger;\n\n // eslint-disable-next-line no-undef\n await page.evaluate((d) => (window._displayErrors = d), displayErrors);\n\n const svgBench = benchmark('SVG handling');\n\n let isSVG;\n\n if (\n chart.indexOf &&\n (chart.indexOf('= 0 || chart.indexOf('= 0)\n ) {\n // SVG INPUT HANDLING\n\n log(4, '[export] Treating as SVG.');\n\n // If input is also svg, just return it\n if (exportOptions.type === 'svg') {\n return chart;\n }\n\n isSVG = true;\n const setPageBench = benchmark('Setting content');\n await page.setContent(svgTemplate(chart));\n setPageBench();\n } else {\n // JSON Config handling\n\n log(4, '[export] Treating as config.');\n\n // Need to perform straight inject\n if (exportOptions.strInj) {\n // Injection based configuration export\n const setPageBench = benchmark('Setting page content (inject)');\n\n await setAsConfig(\n page,\n {\n chart: {\n height: exportOptions.height,\n width: exportOptions.width\n }\n },\n options\n );\n\n setPageBench();\n } else {\n // Basic configuration export\n\n chart.chart.height = exportOptions.height;\n chart.chart.width = exportOptions.width;\n\n const setContentBench = benchmark('Setting page content (config)');\n await setAsConfig(page, chart, options);\n setContentBench();\n }\n }\n\n svgBench();\n const resBench = benchmark('Applying resources');\n\n // Use resources\n const resources = options.customCode.resources;\n if (resources) {\n // Load custom JS code\n if (resources.js) {\n injectedResources.push(\n await page.addScriptTag({\n content: resources.js\n })\n );\n }\n\n // Load scripts from all custom files\n if (resources.files) {\n for (const file of resources.files) {\n try {\n const isLocal = !file.startsWith('http') ? true : false;\n\n // Add each custom script from resources' files\n injectedResources.push(\n await page.addScriptTag(\n isLocal\n ? {\n content: readFileSync(file, 'utf8')\n }\n : {\n url: file\n }\n )\n );\n } catch (notice) {\n log(4, '[export] JS file not found.');\n }\n }\n }\n\n const cssBench = benchmark('Loading css');\n\n // Load CSS\n if (resources.css) {\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\n if (cssImports) {\n // Handle css section\n for (let cssImportPath of cssImports) {\n if (cssImportPath) {\n cssImportPath = cssImportPath\n .replace('url(', '')\n .replace('@import', '')\n .replace(/\"/g, '')\n .replace(/'/g, '')\n .replace(/;/, '')\n .replace(/\\)/g, '')\n .trim();\n\n // Add each custom css from resources\n if (cssImportPath.startsWith('http')) {\n injectedResources.push(\n await page.addStyleTag({\n url: cssImportPath\n })\n );\n } else if (options.customCode.allowFileResources) {\n injectedResources.push(\n await page.addStyleTag({\n path: path.join(__basedir, cssImportPath)\n })\n );\n }\n }\n }\n }\n\n // The rest of the CSS section will be content by now\n injectedResources.push(\n await page.addStyleTag({\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\n })\n );\n }\n\n cssBench();\n }\n\n resBench();\n\n // Get the real chart size\n const size = isSVG\n ? await page.$eval(\n '#chart-container svg:first-of-type',\n async (element, scale) => {\n return {\n chartHeight: element.height.baseVal.value * scale,\n chartWidth: element.width.baseVal.value * scale\n };\n },\n parseFloat(exportOptions.scale)\n )\n : await page.evaluate(async () => {\n // eslint-disable-next-line no-undef\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\n return {\n chartHeight,\n chartWidth\n };\n });\n\n const vpBench = benchmark('Setting viewport');\n\n // Set final height and width for viewport\n const viewportHeight = Math.ceil(size?.chartHeight || exportOptions.height);\n const viewportWidth = Math.ceil(size?.chartWidth || exportOptions.width);\n\n // Set the viewport for the first time\n // NOTE: the call to setViewport is expensive - can we get away with only\n // calling it once, e.g. moving this one into the isSVG condition below?\n await page.setViewport({\n height: viewportHeight,\n width: viewportWidth,\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\n });\n\n // Prepare a zoom callback for the next evaluate call\n const zoomCallback = isSVG\n ? // In case of SVG the zoom must be set directly for body\n (scale) => {\n // Set the zoom as scale\n // eslint-disable-next-line no-undef\n document.body.style.zoom = scale;\n\n // Set the margin to 0px\n // eslint-disable-next-line no-undef\n document.body.style.margin = '0px';\n }\n : // No need for such scale manipulation in case of other types of exports\n () => {\n // Reset the zoom for other exports than to SVGs\n // eslint-disable-next-line no-undef\n document.body.style.zoom = 1;\n };\n\n // Set the zoom accordingly\n await page.evaluate(zoomCallback, parseFloat(exportOptions.scale));\n\n // Get the clip region for the page\n const { height, width, x, y } = await getClipRegion(page);\n\n if (!isSVG) {\n // Set the final viewport now that we have the real height\n await page.setViewport({\n width: Math.round(width),\n height: Math.round(height),\n deviceScaleFactor: parseFloat(exportOptions.scale)\n });\n }\n\n vpBench();\n\n let data;\n\n const expBenchmark = benchmark('Rasterizing chart');\n\n // RASTERIZATION\n if (exportOptions.type === 'svg') {\n // SVG\n data = await createSVG(page);\n } else if (exportOptions.type === 'png' || exportOptions.type === 'jpeg') {\n // PNG or JPEG\n data = await createImage(page, exportOptions.type, 'base64', {\n width: viewportWidth,\n height: viewportHeight,\n x,\n y\n });\n } else if (exportOptions.type === 'pdf') {\n // PDF\n data = await createPDF(page, viewportHeight, viewportWidth, 'base64');\n } else {\n throw `Unsupported output format ${exportOptions.type}`;\n }\n\n // Destroy old charts after the export is done\n await page.evaluate(() => {\n // eslint-disable-next-line no-undef\n const oldCharts = Highcharts.charts;\n\n // Check in any already existing charts\n if (oldCharts.length) {\n // Destroy old charts\n for (const oldChart of oldCharts) {\n oldChart && oldChart.destroy();\n // eslint-disable-next-line no-undef\n Highcharts.charts.shift();\n }\n }\n });\n\n expBenchmark();\n exportBench();\n\n await clearInjected(page);\n\n return data;\n } catch (error) {\n await clearInjected(page);\n log(1, `[export] Error encountered during export: ${error}`);\n\n return error;\n }\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2022, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { log } from './logger.js';\nconst timers = {};\n\n// TODO: Read from config\nlet enabled = false;\n\nexport default (id) => {\n if (!enabled) {\n return () => {};\n }\n\n timers[id] = new Date();\n return () => {\n log(\n 3,\n `[benchmark] - ${id}: ${new Date().getTime() - timers[id].getTime()}ms`\n );\n };\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport cssTemplate from './css.js';\n\nexport default (chart) => `\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${chart}\n
\n \n\n\n`;\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { v4 as uuid } from 'uuid';\nimport { Pool } from 'tarn';\nimport {\n close,\n newPage as browserNewPage,\n create as createBrowser\n} from './browser.js';\nimport { log } from './logger.js';\n\nimport puppeteerExport from './export.js';\n\nlet performedExports = 0;\nlet exportAttempts = 0;\nlet timeSpent = 0;\nlet droppedExports = 0;\nlet spentAverage = 0;\nlet poolConfig = {};\n\n// The pool instance\nlet pool = false;\n\n// Custom puppeteer arguments\nlet puppeteerArgs;\n\nconst factory = {\n /**\n * Creates a new worker.\n *\n * @return {object} - An object with the id of a resource, the work count and\n * a reference to the browser page.\n */\n create: async () => {\n const id = uuid();\n let page = false;\n\n const s = new Date().getTime();\n\n try {\n page = await browserNewPage();\n\n if (!page || page.isClosed()) {\n throw 'invalid page';\n }\n\n log(\n 3,\n `[pool] Successfully created a worker ${id} - took ${\n new Date().getTime() - s\n } ms.`\n );\n } catch (error) {\n log(\n 1,\n `[pool] Error creating a new page in pool entry creation! ${error}`\n );\n\n throw 'Error creating page';\n }\n\n return {\n id,\n page,\n // Try to distribute the initial work count\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\n };\n },\n\n /**\n * Validates a worker.\n *\n * @param {object} workerHandle - A browser's instance.\n *\n * @return {boolean} - Bool that indicates if a resource is valid or not.\n */\n validate: (workerHandle) => {\n if (\n poolConfig.workLimit &&\n ++workerHandle.workCount > poolConfig.workLimit\n ) {\n log(\n 3,\n `[pool] Worker failed validation:`,\n `exceeded work limit (limit is ${poolConfig.workLimit})`\n );\n return false;\n }\n return true;\n },\n\n /**\n * Destroys a worker.\n *\n * @param {object} workerHandle - A browser's instance.\n */\n destroy: (workerHandle) => {\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\n\n if (workerHandle.page) {\n // We don't really need to wait around for this.\n workerHandle.page.close();\n }\n },\n\n // Logger function\n log: (message, logLevel) => console.log(`${logLevel}: ${message}`)\n};\n\n/**\n * Inits the pool of resources.\n *\n * @param {object} config - Pool configuration along with custom puppeteer\n * arguments for the puppeteer.launch function.\n */\nexport const init = async (config) => {\n // The newest puppeteer arguments for the browser creation\n puppeteerArgs = config.puppeteerArgs;\n\n // Wait until we've sucessfully created a browser instance.\n try {\n await createBrowser(puppeteerArgs);\n } catch (e) {\n log(0, '[pool|browser]', e);\n }\n\n // For the module scope usage\n poolConfig = config && config.pool ? { ...config.pool } : {};\n\n log(\n 3,\n '[pool] Initializing pool:',\n `min ${poolConfig.initialWorkers}, max ${poolConfig.maxWorkers}.`\n );\n\n if (pool) {\n return log(\n 4,\n '[pool] Already initialized, please kill it before creating a new one.'\n );\n }\n\n // Attach process' exit listeners\n if (poolConfig.listenToProcessExits) {\n attachProcessExitListeners();\n }\n\n try {\n // Create a pool along with a minimal number of resources\n pool = new Pool({\n // Get the create/validate/destroy/log functions\n ...factory,\n min: poolConfig.initialWorkers,\n max: poolConfig.maxWorkers,\n createRetryIntervalMillis: 200,\n createTimeoutMillis: poolConfig.acquireTimeout,\n acquireTimeoutMillis: poolConfig.acquireTimeout,\n destroyTimeoutMillis: poolConfig.acquireTimeout,\n idleTimeoutMillis: poolConfig.timeoutThreshold,\n reapIntervalMillis: 1000, // poolConfig.reaper ? 120000 : 0, for now\n propagateCreateError: false\n });\n\n // Set events\n pool.on('createFail', (eventId, err) => {\n log(\n 1,\n `[pool] Error when creating worker of an event id ${eventId}:`,\n err\n );\n });\n\n pool.on('acquireFail', (eventId, err) => {\n log(\n 1,\n `[pool] Error when acquiring worker of an event id ${eventId}:`,\n err\n );\n });\n\n pool.on('destroyFail', (eventId, resource, err) => {\n log(\n 1,\n `[pool] Error when destroying worker of an id ${resource.id}, event id ${eventId}:`,\n err\n );\n });\n\n pool.on('release', (resource) => {\n log(4, `[pool] Releasing a worker of an id ${resource.id}`);\n });\n\n pool.on('destroySuccess', (eventId, resource) => {\n log(4, `[pool] Destroyed a worker of an id ${resource.id}`);\n });\n\n const initialResources = [];\n // Create an initial number of resources\n for (let i = 0; i < poolConfig.initialWorkers; i++) {\n initialResources.push(await pool.acquire().promise);\n }\n\n // Release the initial number of resources back to the pool\n initialResources.forEach((resource) => {\n pool.release(resource);\n });\n\n log(\n 3,\n `[pool] The pool is ready with ${poolConfig.initialWorkers} initial resources waiting.`\n );\n } catch (error) {\n log(1, `[pool] Couldn't create the worker pool ${error}`);\n throw error;\n }\n};\n\n/**\n * Attaches process' exit listeners.\n */\nexport function attachProcessExitListeners() {\n log(4, '[pool] Attaching exit listeners to the process.');\n\n // Kill all pool resources on exit\n process.on('exit', async () => {\n await killPool();\n });\n\n // Handler for the SIGINT\n process.on('SIGINT', (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n process.exit(1);\n });\n\n // Handler for the SIGTERM\n process.on('SIGTERM', (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n process.exit(1);\n });\n\n // Handler for the uncaughtException\n process.on('uncaughtException', async (error, name) => {\n log(4, `The ${name} error, message: ${error.message}.`);\n });\n}\n\n/**\n * Kills the pool and flush the browser instance.\n */\nexport async function killPool() {\n log(3, '[pool] Killing all workers.');\n\n // Return true when the pool is already destroyed\n if (pool.destroyed) {\n // Close the browser instance if still connected\n await close();\n return true;\n }\n\n // If still alive, destroy the pool of pages before closing a browser\n await pool.destroy();\n\n // Close the browser instance\n await close();\n return true;\n}\n\n/**\n * Posts work to the pool.\n *\n * @param {object} chart - Chart's options.\n * @param {object} options - All options object.\n */\nexport const postWork = async (chart, options) => {\n let workerHandle;\n\n // Handle fail conditions\n const fail = (msg) => {\n ++droppedExports;\n\n if (workerHandle) {\n pool.release(workerHandle);\n }\n\n throw 'In pool.postWork: ' + msg;\n };\n\n log(4, '[pool] Work received, starting to process.');\n\n if (poolConfig.benchmarking) {\n getPoolInfo();\n }\n\n ++exportAttempts;\n\n if (!pool) {\n log(1, '[pool] Work received, but pool has not been started.');\n return fail('Pool is not inited but work was posted to it!');\n }\n\n // Acquire the worker along with the id of resource and work count\n try {\n log(4, '[pool] Acquiring worker');\n workerHandle = await pool.acquire().promise;\n } catch (error) {\n return fail(`[pool] Error when acquiring available entry: ${error}`);\n }\n\n log(4, '[pool] Acquired worker handle');\n\n if (!workerHandle.page) {\n return fail('Resolved worker page is invalid: pool setup is wonky');\n }\n\n try {\n // Save the start time\n let workStart = new Date().getTime();\n\n log(4, `[pool] Starting work on pool entry ${workerHandle.id}.`);\n\n // Perform an export on a puppeteer level\n const result = await puppeteerExport(workerHandle.page, chart, options);\n\n // Check if it's an error\n if (result instanceof Error) {\n // TODO: If the export failed because puppeteer timed out, we need to force kill the worker so we get a new page. That needs to be handled better than this hack.\n if (result.message === 'Rasterization timeout') {\n workerHandle.page.close();\n workerHandle.page = await browserNewPage();\n }\n\n return fail(result);\n }\n\n // Release the resource back to the pool\n pool.release(workerHandle);\n\n // Used for statistics in averageTime and processedWorkCount, which\n // in turn is used by the /health route.\n const workEnd = new Date().getTime();\n const exportTime = workEnd - workStart;\n timeSpent += exportTime;\n spentAverage = timeSpent / ++performedExports;\n\n log(4, `[pool] Work completed in ${exportTime} ms.`);\n\n // Otherwise return the result\n return {\n data: result,\n options\n };\n } catch (error) {\n fail(`Error trying to perform puppeteer export: ${error}.`);\n }\n};\n\n/**\n * Gets the pool.\n */\nexport function getPool() {\n return pool;\n}\n\nexport const getPoolInfoJSON = () => ({\n min: pool.min,\n max: pool.max,\n size: pool.size,\n available: pool.available,\n borrowed: pool.borrowed,\n pending: pool.pending,\n spareResourceCapacity: pool.spareResourceCapacity\n});\n\n/**\n * Gets the pool's information.\n */\nexport function getPoolInfo() {\n const {\n min,\n max,\n size,\n available,\n borrowed,\n pending,\n spareResourceCapacity\n } = pool;\n\n log(4, `[pool] The minimum number of resources allowed by pool: ${min}.`);\n log(4, `[pool] The maximum number of resources allowed by pool: ${max}.`);\n log(\n 4,\n `[pool] The number of all resources in pool (free or in use): ${size}.`\n );\n log(\n 4,\n `[pool] The number of resources that are currently available: ${available}.`\n );\n log(\n 4,\n `[pool] The number of resources that are currently acquired: ${borrowed}.`\n );\n log(\n 4,\n `[pool] The number of callers waiting to acquire a resource: ${pending}.`\n );\n log(\n 4,\n `[pool] The number of how many more resources can the pool manage/create: ${spareResourceCapacity}.`\n );\n}\n\nexport default {\n init,\n killPool,\n postWork,\n getPool,\n getPoolInfo,\n getPoolInfoJSON,\n workAttempts: () => exportAttempts,\n droppedWork: () => droppedExports,\n averageTime: () => spentAverage,\n processedWorkCount: () => performedExports\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport cache from '../../cache.js';\nimport pool from '../../pool.js';\n\nconst packageVersion = process.env.npm_package_version;\nconst serverStartTime = new Date();\n\n/**\n * Adds the /health route which outputs basic stats for the server\n */\nexport default (app) =>\n !app\n ? false\n : app.get('/health', (request, response) => {\n response.send({\n status: 'OK',\n bootTime: serverStartTime,\n uptime:\n Math.floor(\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\n ) + ' minutes',\n version: packageVersion,\n highchartsVersion: cache.version(),\n averageProcessingTime: pool.averageTime(),\n performedExports: pool.processedWorkCount(),\n failedExports: pool.droppedWork(),\n exportAttempts: pool.workAttempts(),\n sucessRatio: (pool.processedWorkCount() / pool.workAttempts()) * 100,\n // eslint-disable-next-line import/no-named-as-default-member\n pool: pool.getPoolInfoJSON()\n });\n });\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\n\nimport prompts from 'prompts';\n\nimport { log } from './logger.js';\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\nimport {\n absoluteProps,\n defaultConfig,\n nestedArgs,\n promptsConfig\n} from './schemas/config.js';\n\nlet generalOptions = {};\n\n/**\n * Getter for the general options.\n *\n * @return {object} - General options object.\n */\nexport const getOptions = () => generalOptions;\n\n/**\n * Initializes and sets the general options for the server instace.\n *\n * @param {object} userOptions - Additional user options (e.g. from the node\n * module usage).\n * @param {string[]} args - CLI arguments.\n * @return {object} - General options object.\n */\nexport const setOptions = (userOptions, args) => {\n // Only for the CLI usage\n if (args?.length) {\n // Get the additional options from the custom JSON file\n generalOptions = loadConfigFile(args);\n }\n\n // Update the default config with a correct option values\n updateDefaultConfig(defaultConfig, generalOptions);\n\n // Set values for server's options and returns them\n generalOptions = initOptions(defaultConfig);\n\n // Apply user options if there are any\n if (userOptions) {\n // Merge user options\n generalOptions = mergeConfigOptions(\n generalOptions,\n userOptions,\n absoluteProps\n );\n }\n\n // Only for the CLI usage\n if (args?.length) {\n // Pair provided arguments\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\n }\n\n // Return final general options\n return generalOptions;\n};\n\n/**\n * Displays a prompt for the manual configuration.\n *\n * @param {string} configFileName - The name of a configuration file.\n */\nexport const manualConfig = async (configFileName) => {\n // Prepare a config object\n let configFile = {};\n\n // Check if provided config file exists\n if (existsSync(configFileName)) {\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\n }\n\n // Question about a configuration category\n const onSubmit = async (p, categories) => {\n let questionsCounter = 0;\n let allQuestions = [];\n\n // Create a corresponding property in the manualConfig object\n for (const section of categories) {\n // Mark each option with a section\n promptsConfig[section] = promptsConfig[section].map((option) => ({\n ...option,\n section\n }));\n\n // Collect the questions\n allQuestions = [...allQuestions, ...promptsConfig[section]];\n }\n\n await prompts(allQuestions, {\n onSubmit: async (prompt, answer) => {\n // Get the default modules\n if (prompt.name === 'modules') {\n answer = answer.length\n ? answer.map((module) => prompt.choices[module])\n : prompt.choices;\n\n configFile[prompt.section][prompt.name] = answer;\n } else {\n configFile[prompt.section] = recursiveProps(\n Object.assign({}, configFile[prompt.section] || {}),\n prompt.name.split('.'),\n answer\n );\n }\n\n if (++questionsCounter === allQuestions.length) {\n try {\n await fsPromises.writeFile(\n configFileName,\n JSON.stringify(configFile, null, 2),\n 'utf8'\n );\n } catch (error) {\n log(1, `[config] Error while creating config.json: ${error}`);\n }\n return true;\n }\n }\n });\n\n return true;\n };\n\n // Find the categories\n const choices = Object.keys(promptsConfig).map((choice) => ({\n title: `${choice} options`,\n value: choice\n }));\n\n // Category prompt\n return prompts(\n {\n type: 'multiselect',\n name: 'category',\n message: 'Which category do you want to configure?',\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\n instructions: '',\n choices\n },\n { onSubmit }\n );\n};\n\n/**\n * Maps the old options to the new config structure.\n *\n * @param {object} oldOptions - Options to be mapped.\n */\nexport const mapToNewConfig = (oldOptions) => {\n const newOptions = {};\n // Cycle through old-structured options\n for (const [key, value] of Object.entries(oldOptions)) {\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\n\n // Populate object in correct properties levels\n propertiesChain.reduce(\n (obj, prop, index) =>\n (obj[prop] =\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\n newOptions\n );\n }\n return newOptions;\n};\n\n/**\n * Merges the new options to the options object. It omits undefined values.\n *\n * @param {object} options - Old options.\n * @param {object} newOptions - New options.\n * @param {string[]} absoluteProps - Array of object names that should be force\n * merged.\n */\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\n const mergedOptions = deepCopy(options);\n\n for (const [key, value] of Object.entries(newOptions)) {\n mergedOptions[key] =\n isObject(value) &&\n !absoluteProps.includes(key) &&\n mergedOptions[key] !== undefined\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\n : value !== undefined\n ? value\n : mergedOptions[key];\n }\n\n return mergedOptions;\n};\n\n/**\n * Initializes options for the `startExport` method by merging user options\n * with the general options.\n *\n * @param {any} exportOptions - User options for exporting.\n * @param {any} generalOptions - General options are used for the export server.\n * @return {object} - User options merged with default options.\n */\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\n let options = {};\n\n if (exportOptions.svg) {\n options = deepCopy(generalOptions);\n options.export.type = exportOptions.type || exportOptions.export.type;\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\n options.export.outfile =\n exportOptions.outfile || exportOptions.export.outfile;\n options.payload = {\n svg: exportOptions.svg\n };\n } else {\n options = mergeConfigOptions(\n generalOptions,\n exportOptions,\n // Omit going down recursively with the belows\n absoluteProps\n );\n }\n\n options.export.outfile =\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\n return options;\n};\n\n/**\n * Loads the configuration from a custom JSON file.\n *\n * @param {string[]} args - CLI arguments.\n * @return {object} - Options object from the JSON file.\n */\nfunction loadConfigFile(args) {\n // Check if the --loadConfig option was used\n const configIndex = args.findIndex(\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\n );\n\n // Check if the --loadConfig has a value\n if (configIndex > -1 && args[configIndex + 1]) {\n const fileName = args[configIndex + 1];\n try {\n // Check if an additional config file is a correct JSON file\n if (fileName && fileName.endsWith('.json')) {\n // Load an optional custom JSON config file\n return JSON.parse(readFileSync(fileName));\n }\n } catch (error) {\n log(1, `[config] Unable to load config from the ${fileName}: ${error}`);\n }\n }\n\n // No additional options to return\n return {};\n}\n\n/**\n * Setting correct values of the options from the default config.\n *\n * @param {object} configObj - The config object based on which the initial\n * configuration be made.\n * @param {object} customObj - The custom object which can contain additional\n * option values to set.\n * @param {string} propChain - Required for creating a string chain of\n * properties for nested arguments.\n */\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\n Object.keys(configObj).forEach((key) => {\n if (!['puppeteer', 'highcharts'].includes(key)) {\n const entry = configObj[key];\n const customValue = customObj && customObj[key];\n let numEnvVal;\n\n if (typeof entry.value === 'undefined') {\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\n } else {\n // If a value from a custom JSON exists, it take precedence\n if (customValue !== undefined) {\n entry.value = customValue;\n }\n\n // If a value from an env variable exists, it take precedence\n if (entry.envLink) {\n // Load the env var\n if (entry.type === 'boolean') {\n entry.value = toBoolean(\n [process.env[entry.envLink], entry.value].find(\n (el) => el || el === 'false'\n )\n );\n } else if (entry.type === 'number') {\n numEnvVal = +process.env[entry.envLink];\n entry.value = numEnvVal >= 0 ? numEnvVal : entry.value;\n } else if (\n entry.type.indexOf(']') >= 0 &&\n process.env[entry.envLink]\n ) {\n entry.value = process.env[entry.envLink].split(',');\n } else {\n entry.value = process.env[entry.envLink] || entry.value;\n }\n }\n }\n }\n });\n}\n\n/**\n * Inits options recursively.\n *\n * @param {any} items - Items to update options from.\n * @return {object} - Updated options object.\n */\nfunction initOptions(items) {\n let options = {};\n for (const [name, item] of Object.entries(items)) {\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\n ? item.value\n : initOptions(item);\n }\n return options;\n}\n\n/**\n * Pairs argument with a corresponding value.\n *\n * @param {object} options - All server options.\n * @param {string[]} args - Array of arguments from a user.\n * @param {object} defaultConfig - The default config object.\n */\nfunction pairArgumentValue(options, args, defaultConfig) {\n for (let i = 0; i < args.length; i++) {\n let option = args[i].replace(/-/g, '');\n\n // Find the right place for property's value\n const propertiesChain = nestedArgs[option]\n ? nestedArgs[option].split('.')\n : [];\n\n propertiesChain.reduce((obj, prop, index) => {\n if (propertiesChain.length - 1 === index) {\n // Finds an option and set a corresponding value\n if (typeof obj[prop] !== 'undefined') {\n if (args[++i]) {\n obj[prop] = args[i] || obj[prop];\n } else {\n console.log(`Missing argument value for ${option}!`.red, '\\n');\n options = printUsage(defaultConfig);\n }\n }\n }\n return obj[prop];\n }, options);\n }\n\n return options;\n}\n\n/**\n * Recursively sets a property in a correct indentation level based on the\n * array of nested properties names.\n *\n * @param {object} objectToUpdate - Object where a property must be set on a\n * correct level.\n * @param {string[]}nestedNames - Array of nasted names that indicates\n * indentation level.\n * @param {any} value - A value to assign to the property.\n * @return {object} - Updated options object.\n */\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\n while (nestedNames.length > 1) {\n const propName = nestedNames.shift();\n\n // Create a property in object if it doesn't exist\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\n objectToUpdate[propName] = {};\n }\n\n // Call function again if there still names to go\n objectToUpdate[propName] = recursiveProps(\n Object.assign({}, objectToUpdate[propName]),\n nestedNames,\n value\n );\n\n return objectToUpdate;\n }\n\n // Assign the final value\n objectToUpdate[nestedNames[0]] = value;\n return objectToUpdate;\n}\n\nexport default {\n getOptions,\n setOptions,\n manualConfig,\n mapToNewConfig,\n mergeConfigOptions,\n initExportSettings\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFile, readFileSync, writeFileSync } from 'fs';\n\nimport { log } from './logger.js';\nimport { killPool, postWork } from './pool.js';\nimport {\n clearText,\n fixType,\n handleResources,\n isCorrectJSON,\n optionsStringify,\n roundNumber,\n toBoolean,\n wrapAround\n} from './utils.js';\nimport { initExportSettings, getOptions } from './config.js';\n\nlet allowCodeExecution = false;\n\nexport const startExport = async (settings, endCallback) => {\n // Starting exporting process message\n log(4, '[chart] Starting exporting process.');\n\n // Initialize options\n const options = initExportSettings(settings, getOptions());\n\n // Get the export options\n const exportOptions = options.export;\n\n // If SVG is an input (argument can be sent only by the request)\n if (options.payload?.svg && options.payload.svg !== '') {\n return exportAsString(options.payload.svg.trim(), options, endCallback);\n }\n\n // Export using options from the file\n if (exportOptions.infile && exportOptions.infile.length) {\n log(4, '[chart] Attempting to export from an input file.');\n\n // Try to read the file\n return readFile(exportOptions.infile, 'utf8', (error, infile) => {\n if (error) {\n return log(1, `[chart] Error loading input file: ${error}.`);\n }\n\n // Get the string representation\n options.export.instr = infile;\n return exportAsString(options.export.instr.trim(), options, endCallback);\n });\n }\n\n // Export with options from the raw representation\n if (\n (exportOptions.instr && exportOptions.instr !== '') ||\n (exportOptions.options && exportOptions.options !== '')\n ) {\n log(4, '[chart] Attempting to export from a raw input.');\n\n // Perform a direct inject when forced\n if (toBoolean(options.customCode?.allowCodeExecution)) {\n return doStraightInject(options, endCallback);\n }\n\n // Either try to parse to JSON first or do the direct export\n return typeof exportOptions.instr === 'string'\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\n : doExport(\n options,\n exportOptions.instr || exportOptions.options,\n endCallback\n );\n }\n\n // No input specified, pass an error message to the callback\n log(\n 1,\n clearText(\n `[chart] No input specified.\n ${JSON.stringify(exportOptions, undefined, ' ')}.`\n )\n );\n\n return (\n endCallback &&\n endCallback(false, {\n error: true,\n message: 'No input specified.'\n })\n );\n};\n\nexport const batchExport = (options) => {\n const batchFunctions = [];\n\n // Split and pair the --batch arguments\n for (let pair of options.export.batch.split(';')) {\n pair = pair.split('=');\n if (pair.length === 2) {\n batchFunctions.push(\n new Promise((resolve, reject) => {\n startExport(\n {\n ...options,\n export: {\n ...options.export,\n infile: pair[0],\n outfile: pair[1]\n }\n },\n (info, error) => {\n // Throw an error\n if (error) {\n return reject(error);\n }\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n info.options.export.outfile,\n Buffer.from(info.data, 'base64')\n );\n\n resolve();\n }\n );\n })\n );\n }\n }\n\n // Kill the pool after all exports are done\n Promise.all(batchFunctions)\n .then(() => {\n killPool();\n })\n .catch((error) => {\n log(1, `[chart] Error encountered during batch export: ${error}`);\n killPool();\n });\n};\n\nexport const singleExport = (options) => {\n // Use instr or its alias, options\n options.export.instr = options.export.instr || options.export.options;\n\n // Perform an export\n startExport(options, (info, error) => {\n // Exit process when error\n if (error) {\n log(1, `[cli] ${error.message}`);\n process.exit(1);\n }\n\n const { outfile, type } = info.options.export;\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n outfile || `chart.${type}`,\n type !== 'svg' ? Buffer.from(info.data, 'base64') : info.data\n );\n\n // Kill the pool\n killPool();\n });\n};\n\n/**\n * Function for choosing chart size and scale based on options prioritization.\n *\n * @param {object} options - All options object.\n * @return {object} - An object with updated size and scale for a chart.\n */\nexport const findChartSize = (options) => {\n const { chart, exporting } =\n options.export?.options || isCorrectJSON(options.export?.instr);\n\n // See if globalOptions holds chart or exporting size\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\n\n // Secure scale value\n let scale =\n options.export?.scale ||\n exporting?.scale ||\n globalOptions?.exporting?.scale ||\n options.export?.defaultScale ||\n 1;\n\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\n scale = Math.max(0.1, Math.min(scale, 5.0));\n\n // we want to round the numbers like 0.23234 -> 0.23\n scale = roundNumber(scale, 2);\n\n // Find chart size and scale\n return {\n height:\n options.export?.height ||\n exporting?.sourceHeight ||\n chart?.height ||\n globalOptions?.exporting?.sourceHeight ||\n globalOptions?.chart?.height ||\n options.export?.defaultHeight ||\n 400,\n width:\n options.export?.width ||\n exporting?.sourceWidth ||\n chart?.width ||\n globalOptions?.exporting?.sourceWidth ||\n globalOptions?.chart?.width ||\n options.export?.defaultWidth ||\n 600,\n scale\n };\n};\n\n/**\n * Function for final options preparation before export.\n *\n * @param {object} options - All options object.\n * @param {object} chartJson - Chart JSON.\n * @param {function} endCallback - The end callback.\n * @param {string} svg - The SVG representation.\n */\nconst doExport = (options, chartJson, endCallback, svg) => {\n let { export: exportOptions, customCode: customCodeOptions } = options;\n\n const allowCodeExecutionScoped =\n typeof customCodeOptions.allowCodeExecution === 'boolean'\n ? customCodeOptions.allowCodeExecution\n : allowCodeExecution;\n\n if (!customCodeOptions) {\n customCodeOptions = options.customCode = {};\n } else if (typeof options.customCode.resources === 'string') {\n // Process resources\n options.customCode.resources = handleResources(\n options.customCode.resources,\n toBoolean(options.customCode.allowFileResources)\n );\n } else if (!options.customCode.resources) {\n try {\n const resources = readFileSync('resources.json', 'utf8');\n options.customCode.resources = handleResources(\n resources,\n toBoolean(options.customCode.allowFileResources)\n );\n } catch (err) {\n log(3, `[chart] The default resources.json file not found.`);\n }\n }\n\n // If the allowCodeExecution flag isn't set, we should refuse the usage\n // of callback, resources, and custom code. Additionally, the worker will\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\n // option, then we should take a look at the overall pool option.\n if (!allowCodeExecutionScoped && customCodeOptions) {\n if (\n customCodeOptions.callback ||\n customCodeOptions.resources ||\n customCodeOptions.customCode\n ) {\n // Send back a friendly message saying that the exporter does not support\n // these settings.\n return (\n endCallback &&\n endCallback(false, {\n error: true,\n message: clearText(\n `The callback, resources and customCode have been disabled for this\n server.`\n )\n })\n );\n }\n\n // Reset all additional custom code\n customCodeOptions.callback = false;\n customCodeOptions.resources = false;\n customCodeOptions.customCode = false;\n }\n\n // Clean properties to keep it lean and mean\n if (chartJson) {\n chartJson.chart = chartJson.chart || {};\n chartJson.exporting = chartJson.exporting || {};\n chartJson.exporting.enabled = false;\n }\n\n exportOptions.constr = exportOptions.constr || 'chart';\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\n if (exportOptions.type === 'svg') {\n exportOptions.width = false;\n }\n\n // Prepare global and theme options\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\n try {\n if (exportOptions && exportOptions[optionsName]) {\n if (\n typeof exportOptions[optionsName] === 'string' &&\n exportOptions[optionsName].endsWith('.json')\n ) {\n exportOptions[optionsName] = isCorrectJSON(\n readFileSync(exportOptions[optionsName], 'utf8'),\n true\n );\n } else {\n exportOptions[optionsName] = isCorrectJSON(\n exportOptions[optionsName],\n true\n );\n }\n }\n } catch (error) {\n exportOptions[optionsName] = {};\n log(1, `[chart] The ${optionsName} not found.`);\n }\n });\n\n // Prepare customCode\n if (customCodeOptions.allowCodeExecution) {\n customCodeOptions.customCode = wrapAround(\n customCodeOptions.customCode,\n customCodeOptions.allowFileResources\n );\n }\n\n // Get the callback\n if (\n customCodeOptions &&\n customCodeOptions.callback &&\n customCodeOptions.callback?.indexOf('{') < 0\n ) {\n // The allowFileResources is always set to false for HTTP requests to avoid\n // injecting arbitrary files from the fs\n if (customCodeOptions.allowFileResources) {\n try {\n customCodeOptions.callback = readFileSync(\n customCodeOptions.callback,\n 'utf8'\n );\n } catch (error) {\n log(2, `[chart] Error loading callback: ${error}.`);\n customCodeOptions.callback = false;\n }\n } else {\n customCodeOptions.callback = false;\n }\n }\n\n // Size search\n options.export = {\n ...options.export,\n ...findChartSize(options)\n };\n\n // Post the work to the pool\n postWork(exportOptions.strInj || chartJson || svg, options)\n .then((result) => endCallback(result))\n .catch((error) => {\n log(0, '[chart] When posting work:', error);\n return endCallback(false, error);\n });\n};\n\n/**\n * Function for straight injecting the code.\n * Dangerous and must be used deliberately by someone who sets up a server\n * (see --allowCodeExecution).\n *\n * @param {object} options - All options object.\n * @param {function} endCallback - The function to call when exporting is done.\n */\nconst doStraightInject = (options, endCallback) => {\n try {\n let strInj;\n let instr = options.export.instr || options.export.options;\n\n if (typeof instr !== 'string') {\n // Try to stringify options\n strInj = instr = optionsStringify(\n instr,\n options.customCode?.allowCodeExecution\n );\n }\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\n\n // Get rid of the ;\n if (strInj[strInj.length - 1] === ';') {\n strInj = strInj.substring(0, strInj.length - 1);\n }\n\n // Save as stright inject string\n options.export.strInj = strInj;\n return doExport(options, false, endCallback);\n } catch (error) {\n const message = clearText(\n `Malformed input detected for ${options.export?.requestId || '?'}:\n Please make sure that your JSON/JavaScript options\n are sent using the \"options\" attribute, and that if you're using\n SVG, it is unescaped.`\n );\n\n log(1, message);\n return (\n endCallback &&\n endCallback(\n false,\n JSON.stringify({\n error: true,\n message\n })\n )\n );\n }\n};\n\n/**\n * Prepares an input before exporting.\n *\n * @param {string} stringToExport - String representation of SVG/export options.\n * @param {object} options - All options object.\n * @param {function} endCallback - The function to call when exporting is done.\n */\nconst exportAsString = (stringToExport, options, endCallback) => {\n const { allowCodeExecution } = options.customCode;\n\n // Check if it is SVG\n if (\n stringToExport.indexOf('= 0 ||\n stringToExport.indexOf('= 0\n ) {\n log(4, '[chart] Parsing input as SVG.');\n return doExport(options, false, endCallback, stringToExport);\n }\n\n try {\n // Try to parse to JSON and call the doExport function\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\n\n // If a correct JSON, do the export\n return doExport(options, chartJSON, endCallback);\n } catch (error) {\n // Not a valid JSON\n if (toBoolean(allowCodeExecution)) {\n return doStraightInject(options, endCallback);\n } else {\n // Do not allow straight injection without the allowCodeExecution flag\n return (\n endCallback &&\n endCallback(false, {\n error: true,\n message: clearText(\n `Only JSON configurations and SVG is allowed for this server. If\n this is your server, JavaScript exporting can be enabled by starting\n the server with the --allowCodeExecution flag.`\n )\n })\n );\n }\n }\n};\n\nexport const getAllowCodeExecution = () => allowCodeExecution;\n\nexport const setAllowCodeExecution = (value) => {\n allowCodeExecution = toBoolean(value);\n};\n\n/**\n * Starts an exporting process\n *\n * @param {object} settings - Settings for export.\n * @param {function} endCallback - The function to call when exporting is done.\n */\nexport default {\n batchExport,\n singleExport,\n getAllowCodeExecution,\n setAllowCodeExecution,\n startExport,\n findChartSize\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { v4 as uuid } from 'uuid';\n\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\nimport { getOptions, mergeConfigOptions } from '../../config.js';\nimport { log } from '../../logger.js';\nimport {\n clearText,\n fixType,\n isCorrectJSON,\n isPrivateRangeUrlFound,\n optionsStringify,\n measureTime\n} from '../../utils.js';\n\n// Reversed MIME types\nconst reversedMime = {\n png: 'image/png',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n pdf: 'application/pdf',\n svg: 'image/svg+xml'\n};\n\n// The requests counter\nlet requestsCounter = 0;\n\nconst benchmark = false;\n\n// The array of callbacks to call before a request\nconst beforeRequest = [];\n\n// The array of callbacks to call after a request\nconst afterRequest = [];\n\n/**\n * Calls callbacks.\n *\n * @param {Array} callbacks - An array of callbacks.\n * @param {object} request - The request.\n * @param {object} response - The response.\n * @param {object} data - The data to send to callbacks.\n * @return {object} - The result from a callback.\n */\nconst doCallbacks = (callbacks, request, response, data) => {\n let result = true;\n const { id, uniqueId, type, body } = data;\n\n callbacks.some((callback) => {\n if (callback) {\n let callResponse = callback(request, response, id, uniqueId, type, body);\n\n if (callResponse !== undefined && callResponse !== true) {\n result = callResponse;\n }\n\n return true;\n }\n });\n\n return result;\n};\n\n/**\n * Handles an export.\n *\n * @param {object} request - The request.\n * @param {object} response - The response.\n */\nconst exportHandler = (request, response) => {\n // Start counting time\n const stopCounter = measureTime();\n\n // Get the current server's general options\n const defaultOptions = getOptions();\n\n // Init default options\n if (benchmark) {\n console.log('Init default options:', stopCounter(), 'ms.');\n }\n\n const body = request.body;\n const id = ++requestsCounter;\n const uniqueId = uuid().replace(/-/g, '');\n let type = fixType(body.type);\n\n // Fix type\n if (benchmark) {\n console.log('Fix type:', stopCounter(), 'ms.');\n }\n\n // Throw 'Bad Request' if there's no body\n if (!body) {\n return response.status(400).send(\n clearText(\n `Body is required. Sending a body? Make sure your Content-type header\n is correct. Accepted is application/json and multipart/form-data.`\n )\n );\n }\n\n // All of the below can be used\n let instr = isCorrectJSON(body.infile || body.options || body.data);\n\n // Is correct JSON\n if (benchmark) {\n console.log('Is correct JSON:', stopCounter(), 'ms.');\n }\n\n // Throw 'Bad Request' if there's no JSON or SVG to export\n if (!instr && !body.svg) {\n log(\n 2,\n clearText(\n `Request ${uniqueId} from ${\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\n } was incorrect. Check your payload.`\n )\n );\n\n return response.status(400).send(\n clearText(\n `No correct chart data found. Please make sure you are using\n application/json or multipart/form-data headers, and that the chart\n data is in the 'infile', 'options' or 'data' attribute if sending\n JSON or in the 'svg' if sending SVG.`\n )\n );\n }\n\n let callResponse = false;\n\n // Call the before request functions\n callResponse = doCallbacks(beforeRequest, request, response, {\n id,\n uniqueId,\n type,\n body\n });\n\n // Do callbacks\n if (benchmark) {\n console.log('Do callbacks:', stopCounter(), 'ms.');\n }\n\n // Block the request if one of a callbacks failed\n if (callResponse !== true) {\n return response.send(callResponse);\n }\n\n let connectionAborted = false;\n\n // In case the connection is closed, force to abort further actions\n request.socket.on('close', () => {\n connectionAborted = true;\n });\n\n log(4, `[export] Got an incoming HTTP request ${uniqueId}.`);\n\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\n\n // Gather and organize options from the payload\n const requestOptions = {\n export: {\n instr,\n type,\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\n height: body.height,\n width: body.width,\n scale: body.scale || defaultOptions.export.scale,\n globalOptions: isCorrectJSON(body.globalOptions, true),\n themeOptions: isCorrectJSON(body.themeOptions, true)\n },\n customCode: {\n allowCodeExecution: getAllowCodeExecution(),\n allowFileResources: false,\n resources: isCorrectJSON(body.resources, true),\n callback: body.callback,\n customCode: body.customCode\n }\n };\n\n // Organize options\n if (benchmark) {\n console.log('Organize options:', stopCounter(), 'ms.');\n }\n\n if (instr) {\n // Stringify JSON with options\n requestOptions.export.instr = optionsStringify(\n instr,\n requestOptions.customCode.allowCodeExecution\n );\n\n // Stringify JSON with options\n if (benchmark) {\n console.log('Stringify JSON with options:', stopCounter(), 'ms.');\n }\n }\n\n // Merge the request options into default ones\n const options = mergeConfigOptions(defaultOptions, requestOptions);\n\n // Merge config options\n if (benchmark) {\n console.log('Merge config options:', stopCounter(), 'ms.');\n }\n\n // Save the JSON if exists\n options.export.options = instr;\n\n // Lastly, add the server specific arguments into options as payload\n options.payload = {\n svg: body.svg || false,\n b64: body.b64 || false,\n dataOptions: isCorrectJSON(body.dataOptions, true),\n noDownload: body.noDownload || false,\n requestId: uniqueId\n };\n\n // Setting payload\n if (benchmark) {\n console.log('Setting payload:', stopCounter(), 'ms.');\n }\n\n // Test xlink:href elements from payload's SVG\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\n return response\n .status(400)\n .send(\n 'SVG potentially contain at least one forbidden URL in xlink:href element.'\n );\n }\n\n // Check URL range\n if (benchmark) {\n console.log('Check URL range:', stopCounter(), 'ms.');\n }\n\n // Start the export process\n startExport(options, (info, error) => {\n // Remove the close event from the socket\n request.socket.removeAllListeners('close');\n\n // After Puppeteer exporting\n if (benchmark) {\n console.log('After Puppeteer exporting:', stopCounter(), 'ms.', '\\n');\n }\n\n // If the connection was closed, do nothing\n if (connectionAborted) {\n return log(\n 3,\n clearText(\n `[export] The client closed the connection before the chart was done\n processing.`\n )\n );\n }\n\n // If error, return it\n if (error) {\n log(\n 1,\n clearText(\n `[export] Work: ${uniqueId} could not be completed, sending:\n ${error}`\n )\n );\n return response.status(400).send(error.message);\n }\n\n // If data is missing, return the error\n if (!info || !info.data) {\n log(\n 1,\n clearText(\n `[export] Unexpected return from chart generation, please check your\n data Request: ${uniqueId} is ${info.data}.`\n )\n );\n return response\n .status(400)\n .send(\n 'Unexpected return from chart generation, please check your data.'\n );\n }\n\n // Get the type from options\n type = info.options.export.type;\n\n // The after request callbacks\n doCallbacks(afterRequest, request, response, { id, body: info.data });\n\n if (info.data) {\n // If only base64 is required, return it\n if (body.b64) {\n // Check if it is already base64 or a raw SVG\n if (type === 'pdf') {\n return response.send(\n Buffer.from(info.data, 'utf8').toString('base64')\n );\n }\n return response.send(info.data);\n }\n\n // Set correct content type\n response.header('Content-Type', reversedMime[type] || 'image/png');\n\n // Decide whether to download or not chart file\n if (!body.noDownload) {\n response.attachment(\n `${request.params.filename || 'chart'}.${type || 'png'}`\n );\n }\n\n // If SVG, return plain content\n return type === 'svg'\n ? response.send(info.data)\n : response.send(Buffer.from(info.data, 'base64'));\n }\n });\n};\n\nexport default (app) => {\n app.post('/', exportHandler);\n app.post('/:filename', exportHandler);\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { promises as fsPromises } from 'fs';\nimport { posix } from 'path';\n\nimport bodyParser from 'body-parser';\nimport cors from 'cors';\nimport express from 'express';\nimport multer from 'multer';\nimport http from 'http';\nimport https from 'https';\n\nimport { log } from '../logger.js';\nimport rateLimit from './rate_limit.js';\nimport { __dirname } from '../utils.js';\n\nimport healthRoute from './routes/health.js';\nimport exportRoutes from './routes/export.js';\nimport vswitchRoute from './routes/change_hc_version.js';\nimport uiRoute from './routes/ui.js';\n\n// Create express app\nconst app = express();\n\n// Disable the X-Powered-By header\napp.disable('x-powered-by');\n\n// Enable CORS support\napp.use(cors());\n\n// Enable parsing of form data (files) with Multer package\nconst storage = multer.memoryStorage();\nconst upload = multer({\n storage,\n limits: {\n fieldsSize: '50MB'\n }\n});\n\napp.use(upload.any());\n\n// Enable body parser\napp.use(bodyParser.json({ limit: '50mb' }));\napp.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));\napp.use(bodyParser.urlencoded({ extended: false, limit: '50mb' }));\n\n/**\n * Error handler function.\n *\n * @param {object} error - An error object.\n * @return {string} - An error message.\n */\nconst errorHandler = (error) => log(1, `[server] Socket error: ${error}`);\n\n/**\n * Attaches error handlers for a server.\n *\n * @param {object} server - The http/https server.\n */\nconst attachErrorHandlers = (server) => {\n server.on('clientError', errorHandler);\n server.on('error', errorHandler);\n server.on('connection', (socket) =>\n socket.on('error', (error) => errorHandler(error, socket))\n );\n};\n\nexport const startServer = async (serverConfig) => {\n // Stop if not enabled\n if (!serverConfig.enable) {\n return false;\n }\n\n // // Get the pool\n // const pool = getPool();\n\n // // Try to create browser instance before starting the server\n // const resource = await pool.acquire();\n\n // // If not found, throw an error\n // if (!resource.browser) {\n // log(1, `[server] Could not acquire browser instance.`);\n // process.exit(1);\n // }\n\n // // Release the resource\n // pool.release(resource);\n\n // Listen HTTP server\n if (!serverConfig.ssl.enable && !serverConfig.ssl.force) {\n // Main server instance (HTTP)\n const httpServer = http.createServer(app);\n // Attach error handlers and listen to the server\n attachErrorHandlers(httpServer);\n // Listen\n httpServer.listen(serverConfig.port, serverConfig.host);\n\n log(\n 3,\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\n );\n }\n\n // Listen HTTPS server\n if (serverConfig.ssl.enable) {\n // Set up an SSL server also\n let key, cert;\n\n try {\n // Get the SSL key\n key = await fsPromises.readFile(\n posix.join(serverConfig.ssl.certPath, 'server.key'),\n 'utf8'\n );\n\n // Get the SSL certificate\n cert = await fsPromises.readFile(\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\n 'utf8'\n );\n } catch (error) {\n log(\n 1,\n `[server] Unable to load key/certificate from ${serverConfig.ssl.certPath}.`\n );\n }\n\n if (key && cert) {\n // Main server instance (HTTPS)\n const httpsServer = https.createServer(app);\n // Attach error handlers and listen to the server\n attachErrorHandlers(httpsServer);\n // Listen\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\n\n log(\n 3,\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\n );\n }\n }\n\n // Enable the rate limiter if config says so\n if (\n serverConfig.rateLimiting &&\n serverConfig.rateLimiting.enable &&\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\n ) {\n rateLimit(app, serverConfig.rateLimiting);\n }\n\n // Set up static folder's route\n app.use(express.static(posix.join(__dirname, 'public')));\n\n // Set up routes\n healthRoute(app);\n exportRoutes(app);\n uiRoute(app);\n vswitchRoute(app);\n};\n\n/**\n * Returns the express instance.\n */\nexport const getExpress = () => {\n return express;\n};\n\n/**\n * Returns the app instance.\n */\nexport const getApp = () => {\n return app;\n};\n\n/**\n * Adds a middleware to the server.\n *\n * @param {object} path - An endpoint path to add middlewares to.\n * @param {Array} middlewares - An unlimited number of middlewares to use\n * against the specific endpoint.\n */\nexport const use = (path, ...middlewares) => {\n app.use(path, ...middlewares);\n};\n\n/**\n * Adds a get route to the server.\n *\n * @param {object} path - An endpoint path to add middlewares to.\n * @param {Array} middlewares - An unlimited number of middlewares to use\n * against the specific endpoint for GET method.\n */\nexport const get = (path, ...middlewares) => {\n app.get(path, ...middlewares);\n};\n\n/**\n * Adds a post route to the server.\n *\n * @param {object} path - An endpoint path to add middlewares to.\n * @param {Array} middlewares - An unlimited number of middlewares to use\n * against the specific endpoint for POST method.\n */\nexport const post = (path, ...middlewares) => {\n app.post(path, ...middlewares);\n};\n\n/**\n * Forcefully enables rate limiting.\n *\n * @param {object} limitConfig - The options object for the rate limiter\n * configuration.\n */\nexport const enableRateLimiting = (limitConfig) => {\n return rateLimit(app, limitConfig);\n};\n\nexport default {\n startServer,\n getExpress,\n getApp,\n use,\n get,\n post,\n enableRateLimiting\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { join } from 'path';\n\nimport { __dirname } from '../../utils.js';\n/**\n * Adds the / route for a UI when enabled for the export server\n */\nexport default (app) =>\n !app\n ? false\n : app.get('/', (request, response) => {\n response.sendFile(join(__dirname, 'public', 'index.html'));\n });\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport cache from '../../cache.js';\n\n/**\n * Adds a route that can be used to change the HC version on the server\n * TODO: Add auth token and connect to API\n */\nexport default (app) =>\n !app\n ? false\n : app.post('/change_hc_version/:newVersion', async (request, response) => {\n const ctoken = process.env.HIGHCHARTS_ADMIN_TOKEN;\n\n if (!ctoken || !ctoken.length) {\n return response.send({\n error: true,\n message:\n 'Server not configured to do run-time version changes: HIGHCHARTS_ADMIN_TOKEN not set'\n });\n }\n\n const token = request.get('hc-auth');\n\n if (!token || token !== ctoken) {\n return response.send({\n error: true,\n message: 'Invalid or missing token: set token in the hc-auth header'\n });\n }\n\n const newVersion = request.params.newVersion;\n\n if (newVersion) {\n try {\n // eslint-disable-next-line import/no-named-as-default-member\n await cache.updateVersion(newVersion);\n } catch (e) {\n response.send({\n error: true,\n message: e\n });\n }\n\n response.send({\n version: cache.version()\n });\n } else {\n response.send({\n error: true,\n message: 'No new version supplied'\n });\n }\n });\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// Add the main directory in the global object\nimport 'colors';\n\nimport server, { startServer } from './server/server.js';\nimport {\n setAllowCodeExecution,\n batchExport,\n singleExport,\n startExport\n} from './chart.js';\nimport { mapToNewConfig, setOptions } from './config.js';\nimport { log, setLogLevel, enableFileLogging } from './logger.js';\nimport { killPool, init } from './pool.js';\nimport { checkCache } from './cache.js';\n\nexport default {\n log,\n mapToNewConfig,\n setOptions,\n singleExport,\n startExport,\n batchExport,\n server,\n startServer,\n killPool,\n initPool: async (options = {}) => {\n // Set the allowCodeExecution per export module scope\n setAllowCodeExecution(\n options.customCode && options.customCode.allowCodeExecution\n );\n\n // Set the log level\n setLogLevel(options.logging && parseInt(options.logging.level));\n\n // Set the log file path and name\n if (options.logging && options.logging.dest) {\n enableFileLogging(\n options.logging.dest,\n options.logging.file || 'highcharts-export-server.log'\n );\n }\n\n // Check if cache needs to be updated\n await checkCache(options.highcharts || { version: 'latest' });\n\n // Init the pool\n await init({\n pool: options.pool || {\n initialWorkers: 1,\n maxWorkers: 1\n },\n puppeteerArgs: options.puppeteer?.args || []\n });\n\n // Return updated options\n return options;\n }\n};\n"],"names":["dotenv","config","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","modules","indicators","scripts","forceFetch","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","customCode","allowCodeExecution","allowFileResources","callback","resources","loadConfig","createConfig","server","enable","cliName","host","port","ssl","force","certPath","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","pool","initialWorkers","maxWorkers","workLimit","queueSize","timeoutThreshold","acquireTimeout","reaper","benchmarking","listenToProcessExits","logging","level","file","dest","ui","route","other","noLogo","payload","join","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","log","newLevel","texts","length","prefix","Date","toString","split","trim","fn","existsSync","mkdirSync","appendFile","concat","error","console","apply","undefined","__dirname","fileURLToPath","URL","url","clearText","text","rule","replacer","replaceAll","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","endsWith","isCorrectJSON","readFileSync","notice","files","propName","map","item","data","parsedData","JSON","parse","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","name","startsWith","printUsage","bold","yellow","cycleCategories","categories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","rateLimit","app","limitConfig","msg","rateOptions","max","limiter","windowMs","delayMs","handler","request","response","format","json","status","send","message","default","skip","query","access_token","use","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","cachePath","cache","activeManifest","sources","hcVersion","appliedConfig","extractVersion","substr","indexOf","fetchScript","script","proxyAgent","agent","timeout","process","env","statusCode","updateCache","sourcePath","customScripts","allScripts","c","m","proxyHost","proxyPort","HttpsProxyAgent","fetchedModules","all","writeFileSync","checkCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","cache$1","newVersion","assign","RANDOM_PID","randomBytes","PUPPETEER_DIR","path","minimalArgs","template","fs","browser","newPage","p","setContent","addScriptTag","evaluate","setupHighcharts","err","$eval","element","errorMessage","_displayErrors","innerHTML","close","connected","__basedir","setAsConfig","page","chart","triggerExport","puppeteerExport","injectedResources","clearInjected","dispose","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","remove","exportBench","exportOptions","requestAnimationFrame","displayErrors","debugger","d","svgBench","isSVG","setPageBench","svgTemplate","strInj","setContentBench","resBench","js","push","content","isLocal","cssBench","css","cssImports","match","cssImportPath","addStyleTag","size","chartHeight","baseVal","chartWidth","parseFloat","Highcharts","charts","vpBench","viewportHeight","Math","ceil","viewportWidth","setViewport","deviceScaleFactor","zoomCallback","body","style","zoom","margin","x","y","getBoundingClientRect","trunc","getClipRegion","round","expBenchmark","outerHTML","createSVG","encoding","clip","race","screenshot","omitBackground","setTimeout","Error","createImage","pdf","createPDF","oldCharts","oldChart","destroy","shift","puppeteerArgs","performedExports","exportAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","s","getTime","browserNewPage","isClosed","workCount","random","validate","workerHandle","logLevel","init","allArgs","tryCount","open","launch","headless","userDataDir","e","createBrowser","killPool","code","exit","Pool","min","createRetryIntervalMillis","createTimeoutMillis","acquireTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","reapIntervalMillis","propagateCreateError","eventId","resource","initialResources","acquire","promise","release","destroyed","postWork","fail","getPoolInfo","workStart","result","exportTime","available","borrowed","pending","spareResourceCapacity","pool$1","packageVersion","npm_package_version","serverStartTime","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","numEnvVal","el","initOptions","items","startExport","settings","endCallback","svg","initExportSettings","exportAsString","readFile","doStraightInject","doExport","findChartSize","exporting","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","chartJson","customCodeOptions","allowCodeExecutionScoped","enabled","optionsName","then","catch","requestId","stringToExport","chartJSON","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","start","hrtime","bigint","measureTime","defaultOptions","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","b64","dataOptions","noDownload","ipRegEx","info","removeAllListeners","Buffer","from","header","attachment","params","filename","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldsSize","any","bodyParser","limit","urlencoded","extended","errorHandler","attachErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","cert","fsPromises","posix","httpsServer","NaN","static","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","healthRoute","post","exportRoutes","sendFile","uiRoute","ctoken","HIGHCHARTS_ADMIN_TOKEN","token","vswitchRoute","getExpress","getApp","middlewares","enableRateLimiting","index","mapToNewConfig","oldOptions","propertiesChain","reduce","prop","setOptions","userOptions","configIndex","findIndex","arg","fileName","loadConfigFile","pairArgumentValue","singleExport","batchExport","batchFunctions","pair","initPool","parseInt","logDest","logFile","enableFileLogging"],"mappings":"snBAiBAA,EAAOC,SAIA,MAAMC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,GACPC,KAAM,WACNC,YAAa,6CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPK,QAAS,qBACTJ,KAAM,SACNC,YAAa,8BAEfI,OAAQ,CACNN,MAAO,+BACPK,QAAS,iBACTJ,KAAM,SACNC,YAAa,6CAEfK,YAAa,CACXF,QAAS,0BACTL,MAAO,CAAC,aAAc,kBAAmB,iBACzCC,KAAM,WACNC,YAAa,qCAEfM,QAAS,CACPH,QAAS,qBACTL,MAAO,CACL,QACA,MACA,QACA,YACA,cACA,uBACA,gBACA,uBACA,eACA,QACA,OACA,mBACA,eACA,cACA,UACA,UACA,WACA,UACA,cACA,YACA,sBACA,SACA,SACA,WACA,YACA,eACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,cACA,eACA,cACA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,cAEFC,KAAM,WACNC,YAAa,gCAEfO,WAAY,CACVJ,QAAS,wBACTL,MAAO,CAAC,kBACRC,KAAM,WACNC,YAAa,mCAEfQ,QAAS,CACPV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YACE,qEAEJS,WAAY,CACVN,QAAS,yBACTL,OAAO,EACPC,KAAM,UACNC,YACE,oEAGNU,OAAQ,CACNC,OAAQ,CACNb,OAAO,EACPC,KAAM,SACNC,YACE,8FAEJY,MAAO,CACLd,OAAO,EACPC,KAAM,SACNC,YACE,iFAEJa,QAAS,CACPf,OAAO,EACPC,KAAM,SACNC,YAAa,oCAEfc,QAAS,CACPhB,OAAO,EACPC,KAAM,SACNC,YACE,2FAEJD,KAAM,CACJI,QAAS,sBACTL,MAAO,MACPC,KAAM,SACNC,YACE,sEAEJe,OAAQ,CACNZ,QAAS,wBACTL,MAAO,QACPC,KAAM,SACNC,YACE,6EAEJgB,cAAe,CACbb,QAAS,wBACTL,MAAO,IACPC,KAAM,SACNC,YACE,gFAEJiB,aAAc,CAC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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/schemas/config.js","../lib/logger.js","../lib/utils.js","../lib/server/rate_limit.js","../lib/fetch.js","../lib/cache.js","../lib/browser.js","../lib/export.js","../lib/benchmark.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/server/routes/health.js","../lib/config.js","../lib/chart.js","../lib/server/routes/export.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/server/routes/change_hc_version.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// Load .env into environment variables\nimport dotenv from 'dotenv';\n\ndotenv.config();\n\n// This is the configuration object with all options and their default values,\n// also from the .env file if one exists\nexport const defaultConfig = {\n puppeteer: {\n args: {\n value: [],\n type: 'string[]',\n description: 'Array of arguments to send to puppeteer.'\n }\n },\n highcharts: {\n version: {\n value: 'latest',\n envLink: 'HIGHCHARTS_VERSION',\n type: 'string',\n description: 'Highcharts version to use.'\n },\n cdnURL: {\n value: 'https://code.highcharts.com/',\n envLink: 'HIGHCHARTS_CDN',\n type: 'string',\n description: 'The CDN URL of Highcharts scripts to use.'\n },\n coreScripts: {\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\n type: 'string[]',\n description: 'Highcharts core scripts to fetch.'\n },\n modules: {\n envLink: 'HIGHCHARTS_MODULES',\n value: [\n 'stock',\n 'map',\n 'gantt',\n 'exporting',\n 'export-data',\n 'parallel-coordinates',\n 'accessibility',\n 'annotations-advanced',\n 'boost-canvas',\n 'boost',\n 'data',\n 'draggable-points',\n 'static-scale',\n 'broken-axis',\n 'heatmap',\n 'tilemap',\n 'timeline',\n 'treemap',\n 'treegraph',\n 'item-series',\n 'drilldown',\n 'histogram-bellcurve',\n 'bullet',\n 'funnel',\n 'funnel3d',\n 'pyramid3d',\n 'networkgraph',\n 'pareto',\n 'pattern-fill',\n 'pictorial',\n 'price-indicator',\n 'sankey',\n 'arc-diagram',\n 'dependency-wheel',\n 'series-label',\n 'solid-gauge',\n 'sonification',\n 'stock-tools',\n 'streamgraph',\n 'sunburst',\n 'variable-pie',\n 'variwide',\n 'vector',\n 'venn',\n 'windbarb',\n 'wordcloud',\n 'xrange',\n 'no-data-to-display',\n 'drag-panes',\n 'debugger',\n 'dumbbell',\n 'lollipop',\n 'cylinder',\n 'organization',\n 'dotplot',\n 'marker-clusters',\n 'hollowcandlestick',\n 'heikinashi'\n ],\n type: 'string[]',\n description: 'Highcharts modules to fetch.'\n },\n indicators: {\n envLink: 'HIGHCHARTS_INDICATORS',\n value: ['indicators-all'],\n type: 'string[]',\n description: 'Highcharts indicators to fetch.'\n },\n scripts: {\n value: [\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\n ],\n type: 'string[]',\n description:\n 'Additional direct scripts/optional dependencies (e.g. moment.js).'\n },\n forceFetch: {\n envLink: 'HIGHCHARTS_FORCE_FETCH',\n value: false,\n type: 'boolean',\n description:\n 'Should all the scripts be refetched after rerunning the server.'\n }\n },\n export: {\n infile: {\n value: false,\n type: 'string',\n description:\n 'The input file name along with a type (json or svg). It can be a correct JSON or SVG file.'\n },\n instr: {\n value: false,\n type: 'string',\n description:\n 'An input in a form of a stringified JSON or SVG file. Overrides the --infile.'\n },\n options: {\n value: false,\n type: 'string',\n description: 'An alias for the --instr option.'\n },\n outfile: {\n value: false,\n type: 'string',\n description:\n 'The output filename along with a type (jpeg, png, pdf or svg). Ignores the --type flag.'\n },\n type: {\n envLink: 'EXPORT_DEFAULT_TYPE',\n value: 'png',\n type: 'string',\n description:\n 'The format of the file to export to. Can be jpeg, png, pdf or svg.'\n },\n constr: {\n envLink: 'EXPORT_DEFAULT_CONSTR',\n value: 'chart',\n type: 'string',\n description:\n 'The constructor to use. Can be chart, stockChart, mapChart or ganttChart.'\n },\n defaultHeight: {\n envLink: 'EXPORT_DEFAULT_HEIGHT',\n value: 400,\n type: 'number',\n description:\n 'The default height of the exported chart. Used when not found any value set.'\n },\n defaultWidth: {\n envLink: 'EXPORT_DEFAULT_WIDTH',\n value: 600,\n type: 'number',\n description:\n 'The default width of the exported chart. Used when not found any value set.'\n },\n defaultScale: {\n envLink: 'EXPORT_DEFAULT_SCALE',\n value: 1,\n type: 'number',\n description:\n 'The default scale of the exported chart. Ranges between 1 and 5.'\n },\n height: {\n type: 'number',\n value: false,\n description:\n 'The default height of the exported chart. Overrides the option in the chart settings.'\n },\n width: {\n type: 'number',\n value: false,\n description:\n 'The width of the exported chart. Overrides the option in the chart settings.'\n },\n scale: {\n value: false,\n type: 'number',\n description: 'The scale of the exported chart. Ranges between 1 and 5.'\n },\n globalOptions: {\n value: false,\n type: 'string',\n description:\n 'A stringified JSON or a filename with options to be passed into the Highcharts.setOptions.'\n },\n themeOptions: {\n value: false,\n type: 'string',\n description:\n 'A stringified JSON or a filename with theme options to be passed into the Highcharts.setOptions.'\n },\n batch: {\n value: false,\n type: 'string',\n description:\n 'Starts a batch job. A string that contains input/output pairs: \"in=out;in=out;..\".'\n }\n },\n customCode: {\n allowCodeExecution: {\n envLink: 'HIGHCHARTS_ALLOW_CODE_EXECUTION',\n value: false,\n type: 'boolean',\n description:\n 'If set to true, allow for the execution of arbitrary code when exporting.'\n },\n allowFileResources: {\n envLink: 'HIGHCHARTS_ALLOW_FILE_RESOURCES',\n value: true,\n type: 'boolean',\n description:\n 'Allow injecting resources from the filesystem. Has no effect when running as a server.'\n },\n customCode: {\n value: false,\n type: 'string',\n description:\n 'A function to be called before chart initialization. Can be a filename with the js extension.'\n },\n callback: {\n value: false,\n type: 'string',\n description: 'A JavaScript file with a function to run on construction.'\n },\n resources: {\n value: false,\n type: 'string',\n description:\n 'An additional resource in a form of stringified JSON. It can contain files, js and css sections.'\n },\n loadConfig: {\n value: false,\n type: 'string',\n description: 'A file that contains a pre-defined config to use.'\n },\n createConfig: {\n value: false,\n type: 'string',\n description:\n 'Allows to set options through a prompt and save in a provided config file.'\n }\n },\n server: {\n enable: {\n envLink: 'HIGHCHARTS_SERVER_ENABLE',\n value: false,\n type: 'boolean',\n cliName: 'enableServer',\n description: 'If set to true, starts a server on 0.0.0.0.'\n },\n host: {\n envLink: 'HIGHCHARTS_SERVER_HOST',\n value: '0.0.0.0',\n type: 'string',\n description:\n 'The hostname of the server. Also starts a server listening on the supplied hostname.'\n },\n port: {\n envLink: 'HIGHCHARTS_SERVER_PORT',\n value: 7801,\n type: 'number',\n description: 'The port to use for the server. Defaults to 7801.'\n },\n ssl: {\n enable: {\n envLink: 'HIGHCHARTS_SERVER_SSL_ENABLE',\n value: false,\n type: 'boolean',\n cliName: 'enableSsl',\n description: 'Enables the SSL protocol.'\n },\n force: {\n envLink: 'HIGHCHARTS_SERVER_SSL_FORCE',\n value: false,\n type: 'boolean',\n cliName: 'sslForced',\n description:\n 'If set to true, forces the server to only serve over HTTPS.'\n },\n port: {\n envLink: 'HIGHCHARTS_SERVER_SSL_PORT',\n value: 443,\n type: 'number',\n cliName: 'sslPort',\n description: 'The port on which to run the SSL server.'\n },\n certPath: {\n envLink: 'HIGHCHARTS_SSL_CERT_PATH',\n value: '',\n type: 'string',\n description: 'The path to the SSL certificate/key.'\n }\n },\n rateLimiting: {\n enable: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_ENABLE',\n value: false,\n type: 'boolean',\n cliName: 'enableRateLimiting',\n description: 'Enables rate limiting.'\n },\n maxRequests: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_MAX',\n value: 10,\n type: 'number',\n description: 'Max requests allowed in a one minute.'\n },\n window: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_WINDOW',\n value: 1,\n type: 'number',\n description: 'The time window in minutes for rate limiting.'\n },\n delay: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_DELAY',\n value: 0,\n type: 'number',\n description:\n 'The amount to delay each successive request before hitting the max.'\n },\n trustProxy: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_TRUST_PROXY',\n value: false,\n type: 'boolean',\n description: 'Set this to true if behind a load balancer.'\n },\n skipKey: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_SKIP_KEY',\n value: '',\n type: 'number|string',\n description:\n 'Allows bypassing the rate limiter and should be provided with skipToken argument.'\n },\n skipToken: {\n envLink: 'HIGHCHARTS_RATE_LIMIT_SKIP_TOKEN',\n value: '',\n type: 'number|string',\n description:\n 'Allows bypassing the rate limiter and should be provided with skipKey argument.'\n }\n }\n },\n pool: {\n initialWorkers: {\n envLink: 'HIGHCHARTS_POOL_MIN_WORKERS',\n value: 4,\n type: 'number',\n description: 'The number of initial workers to spawn.'\n },\n maxWorkers: {\n envLink: 'HIGHCHARTS_POOL_MAX_WORKERS',\n value: 8,\n type: 'number',\n description: 'The number of max workers to spawn.'\n },\n workLimit: {\n envLink: 'HIGHCHARTS_POOL_WORK_LIMIT',\n value: 40,\n type: 'number',\n description:\n 'The pieces of work that can be performed before restarting process.'\n },\n queueSize: {\n envLink: 'HIGHCHARTS_POOL_QUEUE_SIZE',\n value: 5,\n type: 'number',\n description: 'The size of the request overflow queue.'\n },\n timeoutThreshold: {\n envLink: 'HIGHCHARTS_POOL_TIMEOUT',\n value: 5000,\n type: 'number',\n description: 'The number of milliseconds before timing out.'\n },\n acquireTimeout: {\n envLink: 'HIGHCHARTS_POOL_ACQUIRE_TIMEOUT',\n value: 5000,\n type: 'number',\n description:\n 'The number of milliseconds to wait for acquiring a resource.'\n },\n reaper: {\n envLink: 'HIGHCHARTS_POOL_ENABLE_REAPER',\n value: true,\n type: 'boolean',\n description:\n 'Whether or not to evict workers after a certain time period.'\n },\n benchmarking: {\n envLink: 'HIGHCHARTS_POOL_BENCHMARKING',\n value: false,\n type: 'boolean',\n description: 'Enable benchmarking.'\n },\n listenToProcessExits: {\n envLink: 'HIGHCHARTS_POOL_LISTEN_TO_PROCESS_EXITS',\n value: true,\n type: 'boolean',\n description:\n 'Set to false in order to skip attaching process.exit handlers.'\n }\n },\n logging: {\n level: {\n envLink: 'HIGHCHARTS_LOG_LEVEL',\n value: 4,\n type: 'number',\n cliName: 'logLevel',\n description:\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose).'\n },\n file: {\n envLink: 'HIGHCHARTS_LOG_FILE',\n value: 'highcharts-export-server.log',\n type: 'string',\n cliName: 'logFile',\n description:\n 'A name of a log file. The --logDest also needs to be set to enable file logging.'\n },\n dest: {\n envLink: 'HIGHCHARTS_LOG_DEST',\n value: 'log/',\n type: 'string',\n cliName: 'logDest',\n description: 'The path to store log files. Also enables file logging.'\n }\n },\n ui: {\n enable: {\n envLink: 'HIGHCHARTS_UI_ENABLE',\n value: false,\n type: 'boolean',\n cliName: 'enableUi',\n description: 'Enables the UI for the export server.'\n },\n route: {\n envLink: 'HIGHCHARTS_UI_ROUTE',\n value: '/',\n type: 'string',\n cliName: 'uiRoute',\n description: 'The route to attach the UI to.'\n }\n },\n other: {\n noLogo: {\n envLink: 'HIGHCHARTS_NO_LOGO',\n value: false,\n type: 'boolean',\n description:\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\n }\n },\n payload: {}\n};\n\n// The config descriptions object for the prompts functionality. It contains\n// information like:\n// * Type of a prompt\n// * Name of an option\n// * Short description of a chosen option\n// * Initial value\nexport const promptsConfig = {\n puppeteer: [\n {\n type: 'list',\n name: 'args',\n message: 'Puppeteer arguments',\n initial: defaultConfig.puppeteer.args.value.join(','),\n separator: ','\n }\n ],\n highcharts: [\n {\n type: 'text',\n name: 'version',\n message: 'Highcharts version',\n initial: defaultConfig.highcharts.version.value\n },\n {\n type: 'text',\n name: 'cdnURL',\n message: 'The url of CDN',\n initial: defaultConfig.highcharts.cdnURL.value\n },\n {\n type: 'multiselect',\n name: 'modules',\n message: 'Available modules',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.modules.value\n },\n {\n type: 'list',\n name: 'scripts',\n message: 'Custom scripts',\n initial: defaultConfig.highcharts.scripts.value.join(','),\n separator: ','\n },\n {\n type: 'toggle',\n name: 'forceFetch',\n message: 'Should refetch all the scripts after each server rerun',\n initial: defaultConfig.highcharts.forceFetch.value\n }\n ],\n export: [\n {\n type: 'select',\n name: 'type',\n message: 'The default type of a file to export to',\n hint: `Default: ${defaultConfig.export.type.value}`,\n initial: 0,\n choices: ['png', 'jpeg', 'pdf', 'svg']\n },\n {\n type: 'select',\n name: 'constr',\n message: 'The default constructor for Highcharts to use',\n hint: `Default: ${defaultConfig.export.constr.value}`,\n initial: 0,\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\n },\n {\n type: 'number',\n name: 'defaultHeight',\n message: 'The default fallback height of the exported chart',\n initial: defaultConfig.export.defaultHeight.value\n },\n {\n type: 'number',\n name: 'defaultWidth',\n message: 'The default fallback width of the exported chart',\n initial: defaultConfig.export.defaultWidth.value\n },\n {\n type: 'number',\n name: 'defaultScale',\n message: 'The default fallback scale of the exported chart',\n initial: defaultConfig.export.defaultScale.value,\n min: 0.1,\n max: 5\n }\n ],\n customCode: [\n {\n type: 'toggle',\n name: 'allowCodeExecution',\n message: 'Allow to execute custom code',\n initial: defaultConfig.customCode.allowCodeExecution.value\n },\n {\n type: 'toggle',\n name: 'allowFileResources',\n message: 'Allow file resources',\n initial: defaultConfig.customCode.allowFileResources.value\n }\n ],\n server: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Starts a server on 0.0.0.0',\n initial: defaultConfig.server.enable.value\n },\n {\n type: 'text',\n name: 'host',\n message: 'A hostname of a server',\n initial: defaultConfig.server.host.value\n },\n {\n type: 'number',\n name: 'port',\n message: 'A port of a server',\n initial: defaultConfig.server.port.value\n },\n {\n type: 'toggle',\n name: 'ssl.enable',\n message: 'Enable SSL protocol',\n initial: defaultConfig.server.ssl.enable.value\n },\n {\n type: 'toggle',\n name: 'ssl.force',\n message: 'Force to only serve over HTTPS',\n initial: defaultConfig.server.ssl.force.value\n },\n {\n type: 'number',\n name: 'ssl.port',\n message: 'Port on which to run the SSL server',\n initial: defaultConfig.server.ssl.port.value\n },\n {\n type: 'text',\n name: 'ssl.certPath',\n message: 'A path where to find the SSL certificate/key',\n initial: defaultConfig.server.ssl.certPath.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.enable',\n message: 'Enable rate limiting',\n initial: defaultConfig.server.rateLimiting.enable.value\n },\n {\n type: 'number',\n name: 'rateLimiting.maxRequests',\n message: 'Max requests allowed in a one minute',\n initial: defaultConfig.server.rateLimiting.maxRequests.value\n },\n {\n type: 'number',\n name: 'rateLimiting.window',\n message: 'The time window in minutes for rate limiting',\n initial: defaultConfig.server.rateLimiting.window.value\n },\n {\n type: 'number',\n name: 'rateLimiting.delay',\n message:\n 'The amount to delay each successive request before hitting the max',\n initial: defaultConfig.server.rateLimiting.delay.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.trustProxy',\n message: 'Set this to true if behind a load balancer',\n initial: defaultConfig.server.rateLimiting.trustProxy.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipKey',\n message:\n 'Allows bypassing the rate limiter and should be provided with skipToken argument',\n initial: defaultConfig.server.rateLimiting.skipKey.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipToken',\n message:\n 'Allows bypassing the rate limiter and should be provided with skipKey argument',\n initial: defaultConfig.server.rateLimiting.skipToken.value\n }\n ],\n pool: [\n {\n type: 'number',\n name: 'initialWorkers',\n message: 'The number of initial workers to spawn',\n initial: defaultConfig.pool.initialWorkers.value\n },\n {\n type: 'number',\n name: 'maxWorkers',\n message: 'The number of max workers to spawn',\n initial: defaultConfig.pool.maxWorkers.value\n },\n {\n type: 'number',\n name: 'workLimit',\n message:\n 'The pieces of work that can be performed before restarting a puppeteer process',\n initial: defaultConfig.pool.workLimit.value\n },\n {\n type: 'number',\n name: 'queueSize',\n message: 'The size of the request overflow queue',\n initial: defaultConfig.pool.queueSize.value\n },\n {\n type: 'number',\n name: 'timeoutThreshold',\n message: 'The number of seconds before timing out',\n initial: defaultConfig.pool.timeoutThreshold.value\n },\n {\n type: 'number',\n name: 'acquireTimeout',\n message: 'The number of milliseconds to wait for acquiring a resource',\n initial: defaultConfig.pool.acquireTimeout.value\n },\n {\n type: 'toggle',\n name: 'reaper',\n message: 'The reaper to remove hanging processes',\n initial: defaultConfig.pool.reaper.value\n },\n {\n type: 'toggle',\n name: 'benchmarking',\n message: 'Set benchmarking',\n initial: defaultConfig.pool.benchmarking.value\n },\n {\n type: 'toggle',\n name: 'listenToProcessExits',\n message: 'Set to false in order to skip attaching process.exit handlers',\n initial: defaultConfig.pool.listenToProcessExits.value\n }\n ],\n logging: [\n {\n type: 'number',\n name: 'level',\n message:\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose)',\n initial: defaultConfig.logging.level.value,\n round: 0,\n min: 0,\n max: 4\n },\n {\n type: 'text',\n name: 'file',\n message:\n 'A name of a log file. The --logDest also needs to be set to enable file logging',\n initial: defaultConfig.logging.file.value\n },\n {\n type: 'text',\n name: 'dest',\n message: 'A path to log files. It enables file logging',\n initial: defaultConfig.logging.dest.value\n }\n ],\n ui: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Enable UI for the export server',\n initial: defaultConfig.ui.enable.value\n },\n {\n type: 'text',\n name: 'route',\n message: 'A route to attach the UI to',\n initial: defaultConfig.ui.route.value\n }\n ],\n other: [\n {\n type: 'toggle',\n name: 'noLogo',\n message:\n 'Skip printing the logo on a startup. Will be replaced by a simple text',\n initial: defaultConfig.other.noLogo.value\n }\n ]\n};\n\n// Absolute props that, in case of merging recursively, need to be force merged\nexport const absoluteProps = [\n 'options',\n 'globalOptions',\n 'themeOptions',\n 'resources',\n 'payload'\n];\n\n// Argument nesting level of all export server options\nexport const nestedArgs = {};\n\n/**\n * Creates nested arguments chain for all options\n *\n * @param {object} obj - The object based on which the initial configuration be\n * made.\n * @param {string } propChain - Required for creating a string chain of\n * properties for nested arguments.\n */\nconst createNestedArgs = (obj, propChain = '') => {\n Object.keys(obj).forEach((k) => {\n if (!['puppeteer', 'highcharts'].includes(k)) {\n const entry = obj[k];\n if (typeof entry.value === 'undefined') {\n // Go deeper in the nested arguments\n createNestedArgs(entry, `${propChain}.${k}`);\n } else {\n // Create the chain of nested arguments\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\n }\n }\n });\n};\n\ncreateNestedArgs(defaultConfig);\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { appendFile, existsSync, mkdirSync } from 'fs';\n\nimport { defaultConfig } from './schemas/config.js';\n\n// The default logging config\nlet logging = {\n // Flags for logging status\n toConsole: true,\n toFile: false,\n pathCreated: false,\n // Log levels\n levelsDesc: [\n {\n title: 'error',\n color: 'red'\n },\n {\n title: 'warning',\n color: 'yellow'\n },\n {\n title: 'notice',\n color: 'blue'\n },\n {\n title: 'verbose',\n color: 'gray'\n }\n ],\n // Log listeners\n listeners: []\n};\n\n// Gather init logging options\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\n logging[key] = option.value;\n}\n\n/**\n * Logs a message. Accepts a variable amount of arguments. Arguments after\n * `level` will be passed directly to console.log, and/or will be joined\n * and appended to the log file.\n *\n * @param {any} args - An array of arguments where the first is the log level\n * and the rest are strings to build a message with.\n */\nexport const log = (...args) => {\n const [newLevel, ...texts] = args;\n\n // Current logging options\n const { level, levelsDesc } = logging;\n\n // Check if log level is within a correct range\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\n return;\n }\n\n // Get rid of the GMT text information\n const newDate = new Date().toString().split('(')[0].trim();\n\n // Create a message's prefix\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\n\n // Call available log listeners\n logging.listeners.forEach((fn) => {\n fn(prefix, texts.join(' '));\n });\n\n // Log to file\n if (logging.toFile) {\n if (!logging.pathCreated) {\n // Create if does not exist\n !existsSync(logging.dest) && mkdirSync(logging.dest);\n\n // We now assume the path is available, e.g. it's the responsibility\n // of the user to create the path with the correct access rights.\n logging.pathCreated = true;\n }\n\n // Add the content to a file\n appendFile(\n `${logging.dest}${logging.file}`,\n [prefix].concat(texts).join(' ') + '\\n',\n (error) => {\n if (error) {\n console.log(`[logger] Unable to write to log file: ${error}`);\n logging.toFile = false;\n }\n }\n );\n }\n\n // Log to console\n if (logging.toConsole) {\n console.log.apply(\n undefined,\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\n );\n }\n};\n\n/**\n * Sets the file logging configuration.\n *\n * @param {string} logDest - A path to log to.\n * @param {string} logFile - The name of the log file.\n */\nexport const enableFileLogging = (logDest, logFile) => {\n // Update logging options\n logging = {\n ...logging,\n dest: logDest || logging.dest,\n file: logFile || logging.file,\n toFile: true\n };\n\n if (logging.dest.length === 0) {\n return log(1, '[logger] File logging init: no path supplied.');\n }\n\n if (!logging.dest.endsWith('/')) {\n logging.dest += '/';\n }\n};\n\n/**\n * Adds a log listener.\n *\n * @param {function} fn - The function to call when getting a log event.\n */\nexport const listen = (fn) => {\n logging.listeners.push(fn);\n};\n\n/**\n * Sets the current log level. Log levels are:\n * - 0 = no logging\n * - 1 = error\n * - 2 = warning\n * - 3 = notice\n * - 4 = verbose\n *\n * @param {number} newLevel - The new log level (0 - 4).\n */\nexport const setLogLevel = (newLevel) => {\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\n logging.level = newLevel;\n }\n};\n\n/**\n * Enables or disables logging to the stdout.\n *\n * @param {boolean} enabled - Whether log to console or not.\n */\nexport const toggleSTDOut = (enabled) => {\n logging.toConsole = enabled;\n};\n\nexport default {\n log,\n enableFileLogging,\n listen,\n setLogLevel,\n toggleSTDOut\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\n\nimport { defaultConfig } from '../lib/schemas/config.js';\nimport { log } from './logger.js';\n\nconst MAX_BACKOFF_ATTEMPTS = 6;\n\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\n\n/**\n * Clears text from whitespaces with a regex rule.\n *\n * @param {string} rule - The rule for clearing a string, default to /\\s\\s+/g.\n * @return {string} - Cleared text.\n */\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\n text.replaceAll(rule, replacer).trim();\n\n/**\n * Delays calling the function by time calculated based on the backoff\n * algorithm.\n *\n * @param {function} fn - A function to try to call with the backoff algorithm\n * on.\n * @param {number} attempt - The number of an attempt, where the first one is 0.\n */\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\n try {\n // Try to call the function\n return await fn(...args);\n } catch (error) {\n // Calculate delay in ms\n const delayInMs = 2 ** attempt * 1000;\n\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\n throw error;\n }\n\n // Wait given amount of time\n await new Promise((response) => setTimeout(response, delayInMs));\n log(\n 3,\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\n );\n\n // Try again\n return expBackoff(fn, attempt, ...args);\n }\n};\n\n/**\n * Fixes to supported type format if MIME.\n *\n * @param {string} type - Type to be corrected.\n * @param {string} outfile - Name of the outfile.\n */\nexport const fixType = (type, outfile) => {\n // MIME types\n const mimeTypes = {\n 'image/png': 'png',\n 'image/jpeg': 'jpeg',\n 'application/pdf': 'pdf',\n 'image/svg+xml': 'svg'\n };\n\n // Formats\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\n\n // Check if type and outfile's extensions are the same\n if (outfile) {\n const outType = outfile.split('.').pop();\n\n // Check if extension has a correct type\n if (formats.includes(outType) && type !== outType) {\n type = outType;\n }\n }\n\n // Return a correct type\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\n};\n\n/**\n * Handles the provided resources.\n *\n * @param {string} resources - The stringified resources.\n * @param {string} allowFileResources - Decide if resources from file are\n * allowed.\n */\nexport const handleResources = (resources = false, allowFileResources) => {\n const allowedProps = ['js', 'css', 'files'];\n\n let handledResources = resources;\n let correctResources = false;\n\n // Try to load resources from a file\n if (allowFileResources && resources.endsWith('.json')) {\n try {\n if (!resources) {\n handledResources = isCorrectJSON(\n readFileSync('resources.json', 'utf8')\n );\n } else if (resources && resources.endsWith('.json')) {\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\n } else {\n handledResources = isCorrectJSON(resources);\n if (handledResources === true) {\n handledResources = isCorrectJSON(\n readFileSync('resources.json', 'utf8')\n );\n }\n }\n } catch (notice) {\n return log(3, `[cli] No resources found.`);\n }\n } else {\n // Try to get JSON\n handledResources = isCorrectJSON(resources);\n\n // Get rid of the files section\n if (!allowFileResources) {\n delete handledResources.files;\n }\n }\n\n // Filter from unnecessary properties\n for (const propName in handledResources) {\n if (!allowedProps.includes(propName)) {\n delete handledResources[propName];\n } else if (!correctResources) {\n correctResources = true;\n }\n }\n\n // Check if at least one of allowed properties is present\n if (!correctResources) {\n return log(3, `[cli] No resources found.`);\n }\n\n // Handle files section\n if (handledResources.files) {\n handledResources.files = handledResources.files.map((item) => item.trim());\n if (!handledResources.files || handledResources.files.length <= 0) {\n delete handledResources.files;\n }\n }\n\n // Return resources\n return handledResources;\n};\n\n/**\n * Checks if provided data is or can be a correct JSON.\n *\n * @param {any} data - Data to be checked.\n * @param {boolean} toString - If true, return stringified representation.\n */\nexport function isCorrectJSON(data, toString) {\n try {\n // Get the string representation if not already before parsing\n const parsedData = JSON.parse(\n typeof data !== 'string' ? JSON.stringify(data) : data\n );\n\n // Return a stringified representation of a JSON if required\n if (typeof parsedData !== 'string' && toString) {\n return JSON.stringify(parsedData);\n }\n\n // Return a JSON\n return parsedData;\n } catch (error) {\n return false;\n }\n}\n\n/**\n * Checks if item is an object.\n *\n * @param {any} item - Item to be checked.\n */\nexport const isObject = (item) =>\n typeof item === 'object' && !Array.isArray(item) && item !== null;\n\n/**\n * Checks if string contains private range urls.\n *\n * @export utils\n * @param item {string} item to be checked\n */\nexport const isPrivateRangeUrlFound = (item) => {\n return [\n 'localhost',\n '(10).(.*).(.*).(.*)',\n '(127).(.*).(.*).(.*)',\n '(172).(1[6-9]|2[0-9]|3[0-1]).(.*).(.*)',\n '(192).(168).(.*).(.*)'\n ].some((ipRegEx) =>\n item.match(`xlink:href=\"(?:(http://|https://))?${ipRegEx}`)\n );\n};\n\n/**\n * Creates and returns a deep copy of the given object.\n *\n * @param {object} object - Object to copy.\n * @return {object} - Deep copy of the object.\n */\nexport const deepCopy = (obj) => {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n const copy = Array.isArray(obj) ? [] : {};\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n copy[key] = deepCopy(obj[key]);\n }\n }\n\n return copy;\n};\n\n/**\n * Stringifies object with options. Possible to preserve functions with\n * allowFunctions flag.\n *\n * @param {object} options - Options to stringify.\n * @param {boolean} allowFunctions - Flag for keeping functions.\n */\nexport const optionsStringify = (options, allowFunctions) => {\n const replacerCallback = (name, value) => {\n if (typeof value === 'string') {\n value = value.trim();\n\n // If allowFunctions is set to true, preserve functions\n if (\n (value.startsWith('function(') || value.startsWith('function (')) &&\n value.endsWith('}')\n ) {\n value = allowFunctions\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\n : undefined;\n }\n }\n\n return typeof value === 'function'\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\n : value;\n };\n\n // Stringify options and if required, replace special functions marks\n return JSON.stringify(options, replacerCallback).replaceAll(\n /\"EXP_FUN|EXP_FUN\"/g,\n ''\n );\n};\n\n/**\n * Prints the export server logo.\n *\n * @param {boolean} noLogo - Whether to display logo or text.\n */\nexport const printLogo = (noLogo) => {\n // Get package version either from env or from package.json\n const packageVersion =\n process.env.npm_package_version ||\n JSON.parse(readFileSync(new URL('../package.json', import.meta.url)))\n .version;\n\n // Print text only\n if (noLogo) {\n console.log(`Starting highcharts export server v${packageVersion}...`);\n return;\n }\n\n // Print the logo\n console.log(\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\n `v${packageVersion}`\n );\n};\n\n/**\n * Prints the CLI usage. If required, it can list properties recursively\n */\nexport function printUsage() {\n const pad = 48;\n const readme = 'https://github.com/highcharts/node-export-server#readme';\n\n // Display readme information\n console.log(\n 'Usage of CLI arguments:'.bold,\n '\\n------',\n `\\nFor more detailed information visit readme at: ${readme.bold.yellow}.`\n );\n\n const cycleCategories = (categories) => {\n for (const [name, option] of Object.entries(categories)) {\n // If category has more levels, go further\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\n cycleCategories(option);\n } else {\n let descName = ` --${option.cliName || name} ${\n ('<' + option.type + '>').green\n } `;\n if (descName.length < pad) {\n for (let i = descName.length; i < pad; i++) {\n descName += '.';\n }\n }\n\n // Display correctly aligned messages\n console.log(\n descName,\n option.description,\n `[Default: ${option.value.toString().bold}]`.blue\n );\n }\n }\n };\n\n // Cycle through options of each categories and display the usage info\n Object.keys(defaultConfig).forEach((category) => {\n // Only puppeteer and highcharts categories cannot be configured through CLI\n if (!['puppeteer', 'highcharts'].includes(category)) {\n console.log(`\\n${category.toUpperCase()}`.red);\n cycleCategories(defaultConfig[category]);\n }\n });\n console.log('\\n');\n}\n\n/**\n * Rounds number to passed precision.\n *\n * @param {number} value - Number to round.\n * @param {number} precision - A precision of rounding.\n */\nexport const roundNumber = (value, precision = 1) => {\n const multiplier = Math.pow(10, precision || 0);\n return Math.round(+value * multiplier) / multiplier;\n};\n\n/**\n * Casts the item to boolean.\n *\n * @param {any} item - Item to be cast.\n */\nexport const toBoolean = (item) =>\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\n ? false\n : !!item;\n\n/**\n * If necessary, places a custom code inside a function.\n *\n * @param {any} customCode - The customCode.\n */\nexport const wrapAround = (customCode, allowFileResources) => {\n if (customCode && typeof customCode === 'string') {\n customCode = customCode.trim();\n\n if (customCode.endsWith('.js')) {\n return allowFileResources\n ? wrapAround(readFileSync(customCode, 'utf8'))\n : false;\n } else if (\n customCode.startsWith('function()') ||\n customCode.startsWith('function ()') ||\n customCode.startsWith('()=>') ||\n customCode.startsWith('() =>')\n ) {\n return `(${customCode})()`;\n }\n return customCode.replace(/;$/, '');\n }\n};\n\n/**\n * Utility to measure time.\n */\nexport const measureTime = () => {\n const start = process.hrtime.bigint();\n return () => Number(process.hrtime.bigint() - start) / 1000000;\n};\n\nexport default {\n __dirname,\n clearText,\n expBackoff,\n fixType,\n handleResources,\n isCorrectJSON,\n isObject,\n isPrivateRangeUrlFound,\n optionsStringify,\n printLogo,\n printUsage,\n roundNumber,\n toBoolean,\n wrapAround,\n measureTime\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport rateLimit from 'express-rate-limit';\n\nimport { clearText } from '../utils.js';\nimport { log } from '../logger.js';\n\n/**\n * Enables rate limiting for a given app.\n *\n * @param {object} app - The express app.\n * @param {object} limitConfig - The options for the rate limiting.\n */\nexport default (app, limitConfig) => {\n const msg =\n 'Too many requests, you have been rate limited. Please try again later.';\n\n // Options for the rate limiter\n const rateOptions = {\n max: limitConfig.maxRequests || 30,\n window: limitConfig.window || 1,\n delay: limitConfig.delay || 0,\n trustProxy: limitConfig.trustProxy || false,\n skipKey: limitConfig.skipKey || false,\n skipToken: limitConfig.skipToken || false\n };\n\n // Set if behind a proxy\n if (rateOptions.trustProxy) {\n app.enable('trust proxy');\n }\n\n // Create a limiter\n const limiter = rateLimit({\n windowMs: rateOptions.window * 60 * 1000,\n // Limit each IP to 100 requests per windowMs\n max: rateOptions.max,\n // Disable delaying, full speed until the max limit is reached\n delayMs: rateOptions.delay,\n handler: (request, response) => {\n response.format({\n json: () => {\n response.status(429).send({ message: msg });\n },\n default: () => {\n response.status(429).send(msg);\n }\n });\n },\n skip: (request) => {\n // Allow bypassing the limiter if a valid key/token has been sent\n if (\n rateOptions.skipKey !== false &&\n rateOptions.skipToken !== false &&\n request.query.key === rateOptions.skipKey &&\n request.query.access_token === rateOptions.skipToken\n ) {\n log(4, '[rate-limiting] Skipping rate limiter.');\n return true;\n }\n return false;\n }\n });\n\n // Use a limiter as a middleware\n app.use(limiter);\n\n log(\n 3,\n clearText(\n `[rate-limiting] Enabled rate limiting: ${rateOptions.max} requests\n per ${rateOptions.window} minute per IP, trusting proxy:\n ${rateOptions.trustProxy}.`\n )\n );\n};\n","/**\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\n */\n\nimport http from 'http';\nimport https from 'https';\n\n/**\n * Determines the protocol of the given URL (either `http` or `https`).\n *\n * @function\n * @param {string} url - The URL whose protocol needs to be determined.\n * @returns {Object} Returns the `https` module if the URL starts with 'https',\n * otherwise returns the `http` module.\n * @private\n *\n * @example\n *\n * const protocol = getProtocol('https://example.com');\n * console.log(protocol); // Outputs the 'https' module\n */\nconst getProtocol = (url) => {\n return url.startsWith('https') ? https : http;\n};\n\n/**\n * Sends a GET request to the specified URL with optional request options.\n *\n * @function\n * @async\n * @param {string} url - The URL to fetch.\n * @param {Object} [requestOptions={}] - Optional request options and headers.\n * @returns {Promise} Returns a promise that resolves with the response object.\n * The response object contains a `.text` property with the raw response data.\n * @throws {Error} Throws an error if the request fails or if no data is fetched from the URL.\n *\n * @example\n *\n * async function getData() {\n * try {\n * const response = await fetch('https://api.example.com/data');\n * console.log(response.text);\n * } catch (error) {\n * console.error('Error fetching data:', error);\n * }\n * }\n *\n * getData();\n */\nasync function fetch(url, requestOptions = {}) {\n return new Promise((resolve, reject) => {\n const protocol = getProtocol(url);\n\n protocol\n .get(url, requestOptions, (res) => {\n let data = '';\n\n // A chunk of data has been received.\n res.on('data', (chunk) => {\n data += chunk;\n });\n\n // The whole response has been received.\n res.on('end', () => {\n if (!data) {\n reject('Nothing was fetched from the URL.');\n }\n\n res.text = data;\n resolve(res);\n });\n })\n .on('error', (error) => {\n reject(error);\n });\n });\n}\n\n/**\n * Sends a POST request to the specified URL with the given body and request options.\n *\n * @function\n * @async\n * @param {string} url - The URL to which the request should be sent.\n * @param {Object} [body={}] - The data to be sent as the request body, in JSON format.\n * @param {Object} [requestOptions={}] - Optional request options and headers.\n * @returns {Promise} - Returns a promise that resolves with the parsed JSON response.\n * @throws {Error} Throws an error if the request fails or if the response cannot be parsed.\n *\n * @example\n *\n * async function sendData() {\n * const dataToSend = {\n * key1: 'value1',\n * key2: 'value2',\n * };\n * try {\n * const response = await post('https://api.example.com/data', dataToSend);\n * console.log(response);\n * } catch (error) {\n * console.error('Error sending data:', error);\n * }\n * }\n *\n * sendData();\n */\nasync function post(url, body = {}, requestOptions = {}) {\n return new Promise((resolve, reject) => {\n const protocol = getProtocol(url);\n const data = JSON.stringify(body);\n\n // Set default headers and merge with requestOptions\n const options = Object.assign(\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Length': data.length\n }\n },\n requestOptions\n );\n\n const req = protocol\n .request(url, options, (res) => {\n let responseData = '';\n\n // A chunk of data has been received.\n res.on('data', (chunk) => {\n responseData += chunk;\n });\n\n // The whole response has been received.\n res.on('end', () => {\n try {\n res.text = responseData;\n resolve(res);\n } catch (error) {\n reject(error);\n }\n });\n })\n .on('error', (error) => {\n reject(error);\n });\n\n // Write the request body and end the request.\n req.write(data);\n req.end();\n });\n}\n\nexport default fetch;\nexport { fetch, post };\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// The cache manager manages the Highcharts library and its dependencies.\n// The cache itself is stored in .cache, and is checked by the config system\n// before starting the service\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\n\nimport dotenv from 'dotenv';\nimport HttpsProxyAgent from 'https-proxy-agent';\nimport { fetch } from './fetch.js';\n\nimport { log } from './logger.js';\nimport { __dirname } from '../lib/utils.js';\n\ndotenv.config();\n\nconst cachePath = join(__dirname, '.cache');\n\nconst cache = {\n cdnURL: 'https://code.highcharts.com/',\n activeManifest: {},\n sources: '',\n hcVersion: ''\n};\n\n// TODO: The config should be accesssible globally so we don't have to do this sort of thing..\nlet appliedConfig = false;\n\n/**\n * Extracts the Highcharts version from the cache\n */\nconst extractVersion = () =>\n (cache.hcVersion = cache.sources\n .substr(0, cache.sources.indexOf('*/'))\n .replace('/*', '')\n .replace('*/', '')\n .replace(/\\n/g, '')\n .trim());\n\n/**\n * Saves the Highcharts part of a config to a manifest file in the cache\n *\n * @param {object} config - Highcharts related configuration object.\n * @param {object} fetchedModules - An object that contains mapped names of\n * fetched Highcharts modules to use.\n */\nconst saveConfigToManifest = async (config, fetchedModules) => {\n const newManifest = {\n version: config.version,\n modules: fetchedModules || {}\n };\n\n // Update cache object with the current modules\n cache.activeManifest = newManifest;\n\n log(4, '[cache] writing new manifest');\n\n try {\n writeFileSync(\n join(cachePath, 'manifest.json'),\n JSON.stringify(newManifest),\n 'utf8'\n );\n } catch (error) {\n log(1, `[cache] Error writing cache manifest: ${error}.`);\n }\n};\n\n/**\n * Fetches a single script.\n *\n * @param {string} script - A path to script to get.\n * @param {object} proxyAgent - The proxy agent to use for a request.\n */\nconst fetchScript = async (script, proxyAgent) => {\n try {\n // Get rid of the .js from the custom strings\n if (script.endsWith('.js')) {\n script = script.substring(0, script.length - 3);\n }\n\n log(4, `[cache] Fetching script - ${script}.js`);\n\n // If exists, add proxy agent to request options\n const requestOptions = proxyAgent\n ? {\n agent: proxyAgent,\n timeout: +process.env['PROXY_SERVER_TIMEOUT'] || 5000\n }\n : {};\n\n // Fetch the script\n const response = await fetch(`${script}.js`, requestOptions);\n\n // If OK, return its text representation\n if (response.statusCode === 200) {\n return response.text;\n }\n\n throw `${response.statusCode}`;\n } catch (error) {\n log(1, `[cache] Error fetching script ${script}.js: ${error}.`);\n throw error;\n }\n};\n\n/**\n * Updates the Highcharts cache.\n *\n * @param {object} config - Highcharts related configuration object.\n * @param {string} sourcePath - A path to the file where save updated sources.\n * @return {object} An object that contains mapped names of fetched Highcharts\n * modules to use.\n */\nconst updateCache = async (config, sourcePath) => {\n const { coreScripts, modules, indicators, scripts: customScripts } = config;\n const hcVersion =\n config.version === 'latest' || !config.version ? '' : `${config.version}/`;\n\n log(3, '[cache] Updating cache to Highcharts ', hcVersion);\n\n // Gather all scripts to fetch\n const allScripts = [\n ...coreScripts.map((c) => `${hcVersion}${c}`),\n ...modules.map((m) =>\n m === 'map' ? `maps/${hcVersion}modules/${m}` : `${hcVersion}modules/${m}`\n ),\n ...indicators.map((i) => `stock/${hcVersion}indicators/${i}`)\n ];\n\n // Configure proxy if exists\n let proxyAgent;\n const proxyHost = process.env['PROXY_SERVER_HOST'];\n const proxyPort = process.env['PROXY_SERVER_PORT'];\n\n if (proxyHost && proxyPort) {\n proxyAgent = new HttpsProxyAgent({\n host: proxyHost,\n port: +proxyPort\n });\n }\n\n const fetchedModules = {};\n try {\n cache.sources = // TODO: convert to for loop\n (\n await Promise.all([\n ...allScripts.map(async (script) => {\n const text = await fetchScript(\n `${config.cdnURL || cache.cdnURL}${script}`,\n proxyAgent\n );\n\n // If fetched correctly, set it\n if (typeof text === 'string') {\n fetchedModules[\n script.replace(\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\n ''\n )\n ] = 1;\n }\n\n return text;\n }),\n ...customScripts.map((script) => fetchScript(script, proxyAgent))\n ])\n ).join(';\\n');\n extractVersion();\n\n // Save the fetched modules into caches' source JSON\n writeFileSync(sourcePath, cache.sources);\n return fetchedModules;\n } catch (error) {\n log(1, '[cache] Unable to update local Highcharts cache.');\n }\n};\n\nexport const updateVersion = async (newVersion) =>\n appliedConfig\n ? await checkCache(\n Object.assign(appliedConfig, {\n version: newVersion\n })\n )\n : false;\n\n/**\n * Fetches any missing Highcharts and dependencies\n *\n * @param {object} config - Highcharts related configuration object.\n */\nexport const checkCache = async (config) => {\n let fetchedModules;\n // Prepare paths to manifest and sources from the .cache folder\n const manifestPath = join(cachePath, 'manifest.json');\n const sourcePath = join(cachePath, 'sources.js');\n\n // TODO: deal with trying to switch to the running version\n // const activeVersion = appliedConfig ? appliedConfig.version : false;\n\n appliedConfig = config;\n\n // Create the .cache destination if it doesn't exist already\n !existsSync(cachePath) && mkdirSync(cachePath);\n\n // Fetch all the scripts either if manifest.json does not exist\n // or if the forceFetch option is enabled\n if (!existsSync(manifestPath) || config.forceFetch) {\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\n fetchedModules = await updateCache(config, sourcePath);\n } else {\n let requestUpdate = false;\n\n // Read the manifest JSON\n const manifest = JSON.parse(readFileSync(manifestPath));\n\n // Check if the modules is an array, if so, we rewrite it to a map to make\n // it easier to resolve modules.\n if (manifest.modules && Array.isArray(manifest.modules)) {\n const moduleMap = {};\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\n manifest.modules = moduleMap;\n }\n\n const { modules, coreScripts, indicators } = config;\n const numberOfModules =\n modules.length + coreScripts.length + indicators.length;\n\n // Compare the loaded config with the contents in .cache.\n // If there are changes, fetch requested modules and products,\n // and bake them into a giant blob. Save the blob.\n if (manifest.version !== config.version) {\n log(3, '[cache] Highcharts version mismatch in cache, need to re-fetch.');\n requestUpdate = true;\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\n log(\n 3,\n '[cache] Cache and requested modules does not match, need to re-fetch.'\n );\n requestUpdate = true;\n } else {\n // Check each module, if anything is missing refetch everything\n requestUpdate = (config.modules || []).some((moduleName) => {\n if (!manifest.modules[moduleName]) {\n log(\n 3,\n `[cache] The ${moduleName} missing in cache, need to re-fetch.`\n );\n return true;\n }\n });\n }\n\n if (requestUpdate) {\n fetchedModules = await updateCache(config, sourcePath);\n } else {\n log(3, '[cache] Dependency cache is up to date, proceeding.');\n\n // Load the sources\n cache.sources = readFileSync(sourcePath, 'utf8');\n\n // Get current modules map\n fetchedModules = manifest.modules;\n extractVersion();\n }\n }\n\n // Finally, save the new manifest, which is basically our current config\n // in a slightly different format\n await saveConfigToManifest(config, fetchedModules);\n};\n\nexport default {\n checkCache,\n updateVersion,\n getCache: () => cache,\n highcharts: () => cache.sources,\n version: () => cache.hcVersion\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport puppeteer from 'puppeteer';\nimport fs from 'fs';\nimport * as url from 'url';\nimport { log } from './logger.js';\nimport path from 'node:path';\n\n// Workaround for https://bugs.chromium.org/p/chromium/issues/detail?id=1463328\n// Not ideal - leaves trash in the FS\nimport { randomBytes } from 'node:crypto';\nconst RANDOM_PID = randomBytes(64).toString('base64url');\nconst PUPPETEER_DIR = path.join('tmp', `puppeteer-${RANDOM_PID}`);\nconst DATA_DIR = path.join(PUPPETEER_DIR, 'profile');\n\n// The minimal args to speed up the browser\nconst minimalArgs = [\n `--user-data-dir=${DATA_DIR}`,\n '--autoplay-policy=user-gesture-required',\n '--disable-background-networking',\n '--disable-background-timer-throttling',\n '--disable-backgrounding-occluded-windows',\n '--disable-breakpad',\n '--disable-client-side-phishing-detection',\n '--disable-component-update',\n '--disable-default-apps',\n '--disable-dev-shm-usage',\n '--disable-domain-reliability',\n '--disable-extensions',\n '--disable-features=AudioServiceOutOfProcess',\n '--disable-hang-monitor',\n '--disable-ipc-flooding-protection',\n '--disable-notifications',\n '--disable-offer-store-unmasked-wallet-cards',\n '--disable-popup-blocking',\n '--disable-print-preview',\n '--disable-prompt-on-repost',\n '--disable-renderer-backgrounding',\n '--disable-session-crashed-bubble',\n '--disable-setuid-sandbox',\n '--disable-speech-api',\n '--disable-sync',\n '--hide-crash-restore-bubble',\n '--hide-scrollbars',\n '--ignore-gpu-blacklist',\n '--metrics-recording-only',\n '--mute-audio',\n '--no-default-browser-check',\n '--no-first-run',\n '--no-pings',\n '--no-sandbox',\n '--no-zygote',\n '--password-store=basic',\n '--use-mock-keychain'\n];\n\nconst __dirname = url.fileURLToPath(new URL('.', import.meta.url));\n\nconst template = fs.readFileSync(\n __dirname + '/../templates/template.html',\n 'utf8'\n);\n\nlet browser;\n\nexport const newPage = async () => {\n if (!browser) return false;\n\n const p = await browser.newPage();\n\n await p.setContent(template);\n await p.addScriptTag({ path: __dirname + '/../.cache/sources.js' });\n // eslint-disable-next-line no-undef\n await p.evaluate(() => window.setupHighcharts());\n\n p.on('pageerror', async (err) => {\n // TODO: Consider adding a switch here that turns on log(0) logging\n // on page errors.\n log(1, '[page error]', err);\n await p.$eval(\n '#container',\n (element, errorMessage) => {\n // eslint-disable-next-line no-undef\n if (window._displayErrors) {\n element.innerHTML = errorMessage;\n }\n },\n `

Chart input data error

${err.toString()}`\n );\n });\n\n return p;\n};\n\nexport const create = async (puppeteerArgs) => {\n const allArgs = [...minimalArgs, ...(puppeteerArgs || [])];\n\n // Create a browser\n if (!browser) {\n let tryCount = 0;\n\n const open = async () => {\n try {\n log(\n 3,\n '[browser] attempting to get a browser instance (try',\n tryCount + ')'\n );\n\n browser = await puppeteer.launch({\n headless: 'new',\n args: allArgs,\n userDataDir: './tmp/'\n });\n } catch (e) {\n log(0, '[browser]', e);\n if (++tryCount < 25) {\n log(3, '[browser] failed:', e);\n await new Promise((response) => setTimeout(response, 4000));\n await open();\n } else {\n log(0, 'Max retries reached');\n }\n }\n };\n\n try {\n await open();\n } catch (e) {\n log(0, '[browser] Unable to open browser');\n return false;\n }\n\n if (!browser) {\n log(0, '[browser] Unable to open browser');\n return false;\n }\n }\n\n // Return a browser promise\n return browser;\n};\n\nexport const get = async () => {\n if (!browser) {\n throw 'No valid browser has been created';\n }\n\n return browser;\n};\n\nexport const close = async () => {\n // Close the browser when connnected\n if (browser.connected) {\n await browser.close();\n }\n};\n\nexport default {\n get,\n close,\n newPage\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// TODO: remove this temp benchmark stuff. I had this idea of doing a general benchmarking\n// system, but it adds so much bloat in the code that it shouldn't be there.\n\nimport benchmark from './benchmark.js';\nimport cache from './cache.js';\nimport { log } from './logger.js';\nimport svgTemplate from './../templates/svg_export/svg_export.js';\n\nimport { readFileSync } from 'fs';\nimport path from 'path';\nimport * as url from 'url';\n\nconst __basedir = url.fileURLToPath(new URL('.', import.meta.url));\n\n// const jsonTemplate = require('./../templates/json_export/json_export.js');\n\n/**\n * Gets the clip region for the chart DOM node.\n *\n * @param {object} page - A page of a browser instance.\n * @return {object} - A clipped region.\n */\nconst getClipRegion = (page) =>\n page.$eval('#chart-container', (element) => {\n const { x, y, width, height } = element.getBoundingClientRect();\n return {\n x,\n y,\n width,\n height: Math.trunc(height > 1 ? height : 500)\n };\n });\n\n/**\n * Rasterizes the page to an image (PNG or JPEG)\n *\n * @param {object} page - A page of a browser instance.\n * @param {string} type - The type of a result image.\n * @param {string} encoding - The type of encoding used.\n * @param {string} clip - The clip region.\n * @returns {string} - A string representation of a screenshot.\n */\nconst createImage = async (page, type, encoding, clip) =>\n await Promise.race([\n page.screenshot({\n type,\n encoding,\n clip,\n\n // #447 - always render on a transparent page\n // this will not affect users who do not explicitly set\n // chart.backgroundColor to a color with opacity lower than 1\n omitBackground: true\n }),\n new Promise((resolve, reject) =>\n setTimeout(() => reject(new Error('Rasterization timeout')), 1500)\n )\n ]);\n\n/**\n * Turns page into a PDF.\n *\n * @param {object} page - A page of a browser instance.\n * @param {number} height - The height of a chart.\n * @param {number} width - The width of a chart.\n * @param {string} encoding - The type of encoding used.\n * @return {object} - A buffer with PDF representation.\n */\nconst createPDF = async (page, height, width, encoding) =>\n await page.pdf({\n // This will remove an extra empty page in PDF exports\n height: height + 1,\n width,\n encoding\n });\n\n/**\n * Exports as a SVG.\n *\n * @param {object} page - A page of a browser instance.\n * @return {object} - The outerHTML element with the SVG representation.\n */\nconst createSVG = async (page) =>\n await page.$eval(\n '#container svg:first-of-type',\n (element) => element.outerHTML\n );\n\n/** Load config into a page and render a chart */\nconst setAsConfig = async (page, chart, options) =>\n await page.evaluate(\n // eslint-disable-next-line no-undef\n (chart, options) => window.triggerExport(chart, options),\n chart,\n options\n );\n\n/** Load SVG into a page */\n// const setAsSVG = async (page, svgStr) => true;\n\n/**\n * Does an export for a given browser.\n *\n * @param {object} browser - A browser instance.\n * @param {object} chart - Chart's options.\n * @param {object} options - All options object.\n * @return {object} - The data returned from one of the methods for exporting\n * a specific type of an image.\n */\nexport default async (page, chart, options) => {\n /**\n * Keeps track of all resources added on the page with addXXXTag. etc\n * It's VITAL that all added resources ends up here so we can clear things\n * out when doing a new export in the same page!\n */\n const injectedResources = [];\n\n /** Clear out all state set on the page with addScriptTag/addStyleTag. */\n const clearInjected = async (page) => {\n for (const res of injectedResources) {\n await res.dispose();\n }\n\n // Reset all CSS and script tags\n await page.evaluate(() => {\n // eslint-disable-next-line no-undef\n const [, ...scriptsToRemove] = document.getElementsByTagName('script');\n // eslint-disable-next-line no-undef\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\n // eslint-disable-next-line no-undef\n const [...linksToRemove] = document.getElementsByTagName('link');\n\n // Remove tags\n for (const element of [\n ...scriptsToRemove,\n ...stylesToRemove,\n ...linksToRemove\n ]) {\n element.remove();\n }\n });\n };\n\n try {\n const exportBench = benchmark('Puppeteer');\n\n log(4, '[export] Determining export path.');\n\n const exportOptions = options.export;\n\n // Force a rAF\n // See https://github.com/puppeteer/puppeteer/issues/7507\n // eslint-disable-next-line no-undef\n await page.evaluate(() => requestAnimationFrame(() => {}));\n\n // Decide whether display error or debbuger wrapper around it\n const displayErrors =\n exportOptions?.options?.chart?.displayErrors &&\n cache.getCache().activeManifest.modules.debugger;\n\n // eslint-disable-next-line no-undef\n await page.evaluate((d) => (window._displayErrors = d), displayErrors);\n\n const svgBench = benchmark('SVG handling');\n\n let isSVG;\n\n if (\n chart.indexOf &&\n (chart.indexOf('= 0 || chart.indexOf('= 0)\n ) {\n // SVG INPUT HANDLING\n\n log(4, '[export] Treating as SVG.');\n\n // If input is also svg, just return it\n if (exportOptions.type === 'svg') {\n return chart;\n }\n\n isSVG = true;\n const setPageBench = benchmark('Setting content');\n await page.setContent(svgTemplate(chart));\n setPageBench();\n } else {\n // JSON Config handling\n\n log(4, '[export] Treating as config.');\n\n // Need to perform straight inject\n if (exportOptions.strInj) {\n // Injection based configuration export\n const setPageBench = benchmark('Setting page content (inject)');\n\n await setAsConfig(\n page,\n {\n chart: {\n height: exportOptions.height,\n width: exportOptions.width\n }\n },\n options\n );\n\n setPageBench();\n } else {\n // Basic configuration export\n\n chart.chart.height = exportOptions.height;\n chart.chart.width = exportOptions.width;\n\n const setContentBench = benchmark('Setting page content (config)');\n await setAsConfig(page, chart, options);\n setContentBench();\n }\n }\n\n svgBench();\n const resBench = benchmark('Applying resources');\n\n // Use resources\n const resources = options.customCode.resources;\n if (resources) {\n // Load custom JS code\n if (resources.js) {\n injectedResources.push(\n await page.addScriptTag({\n content: resources.js\n })\n );\n }\n\n // Load scripts from all custom files\n if (resources.files) {\n for (const file of resources.files) {\n try {\n const isLocal = !file.startsWith('http') ? true : false;\n\n // Add each custom script from resources' files\n injectedResources.push(\n await page.addScriptTag(\n isLocal\n ? {\n content: readFileSync(file, 'utf8')\n }\n : {\n url: file\n }\n )\n );\n } catch (notice) {\n log(4, '[export] JS file not found.');\n }\n }\n }\n\n const cssBench = benchmark('Loading css');\n\n // Load CSS\n if (resources.css) {\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\n if (cssImports) {\n // Handle css section\n for (let cssImportPath of cssImports) {\n if (cssImportPath) {\n cssImportPath = cssImportPath\n .replace('url(', '')\n .replace('@import', '')\n .replace(/\"/g, '')\n .replace(/'/g, '')\n .replace(/;/, '')\n .replace(/\\)/g, '')\n .trim();\n\n // Add each custom css from resources\n if (cssImportPath.startsWith('http')) {\n injectedResources.push(\n await page.addStyleTag({\n url: cssImportPath\n })\n );\n } else if (options.customCode.allowFileResources) {\n injectedResources.push(\n await page.addStyleTag({\n path: path.join(__basedir, cssImportPath)\n })\n );\n }\n }\n }\n }\n\n // The rest of the CSS section will be content by now\n injectedResources.push(\n await page.addStyleTag({\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\n })\n );\n }\n\n cssBench();\n }\n\n resBench();\n\n // Get the real chart size\n const size = isSVG\n ? await page.$eval(\n '#chart-container svg:first-of-type',\n async (element, scale) => {\n return {\n chartHeight: element.height.baseVal.value * scale,\n chartWidth: element.width.baseVal.value * scale\n };\n },\n parseFloat(exportOptions.scale)\n )\n : await page.evaluate(async () => {\n // eslint-disable-next-line no-undef\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\n return {\n chartHeight,\n chartWidth\n };\n });\n\n const vpBench = benchmark('Setting viewport');\n\n // Set final height and width for viewport\n const viewportHeight = Math.ceil(size?.chartHeight || exportOptions.height);\n const viewportWidth = Math.ceil(size?.chartWidth || exportOptions.width);\n\n // Set the viewport for the first time\n // NOTE: the call to setViewport is expensive - can we get away with only\n // calling it once, e.g. moving this one into the isSVG condition below?\n await page.setViewport({\n height: viewportHeight,\n width: viewportWidth,\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\n });\n\n // Prepare a zoom callback for the next evaluate call\n const zoomCallback = isSVG\n ? // In case of SVG the zoom must be set directly for body\n (scale) => {\n // Set the zoom as scale\n // eslint-disable-next-line no-undef\n document.body.style.zoom = scale;\n\n // Set the margin to 0px\n // eslint-disable-next-line no-undef\n document.body.style.margin = '0px';\n }\n : // No need for such scale manipulation in case of other types of exports\n () => {\n // Reset the zoom for other exports than to SVGs\n // eslint-disable-next-line no-undef\n document.body.style.zoom = 1;\n };\n\n // Set the zoom accordingly\n await page.evaluate(zoomCallback, parseFloat(exportOptions.scale));\n\n // Get the clip region for the page\n const { height, width, x, y } = await getClipRegion(page);\n\n if (!isSVG) {\n // Set the final viewport now that we have the real height\n await page.setViewport({\n width: Math.round(width),\n height: Math.round(height),\n deviceScaleFactor: parseFloat(exportOptions.scale)\n });\n }\n\n vpBench();\n\n let data;\n\n const expBenchmark = benchmark('Rasterizing chart');\n\n // RASTERIZATION\n if (exportOptions.type === 'svg') {\n // SVG\n data = await createSVG(page);\n } else if (exportOptions.type === 'png' || exportOptions.type === 'jpeg') {\n // PNG or JPEG\n data = await createImage(page, exportOptions.type, 'base64', {\n width: viewportWidth,\n height: viewportHeight,\n x,\n y\n });\n } else if (exportOptions.type === 'pdf') {\n // PDF\n data = await createPDF(page, viewportHeight, viewportWidth, 'base64');\n } else {\n throw `Unsupported output format ${exportOptions.type}`;\n }\n\n // Destroy old charts after the export is done\n await page.evaluate(() => {\n // eslint-disable-next-line no-undef\n const oldCharts = Highcharts.charts;\n\n // Check in any already existing charts\n if (oldCharts.length) {\n // Destroy old charts\n for (const oldChart of oldCharts) {\n oldChart && oldChart.destroy();\n // eslint-disable-next-line no-undef\n Highcharts.charts.shift();\n }\n }\n });\n\n expBenchmark();\n exportBench();\n\n await clearInjected(page);\n\n return data;\n } catch (error) {\n await clearInjected(page);\n log(1, `[export] Error encountered during export: ${error}`);\n\n return error;\n }\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2022, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { log } from './logger.js';\nconst timers = {};\n\n// TODO: Read from config\nlet enabled = false;\n\nexport default (id) => {\n if (!enabled) {\n return () => {};\n }\n\n timers[id] = new Date();\n return () => {\n log(\n 3,\n `[benchmark] - ${id}: ${new Date().getTime() - timers[id].getTime()}ms`\n );\n };\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport cssTemplate from './css.js';\n\nexport default (chart) => `\n\n\n \n \n Highcarts Export\n \n \n \n
\n ${chart}\n
\n \n\n\n`;\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { v4 as uuid } from 'uuid';\nimport { Pool } from 'tarn';\nimport {\n close,\n newPage as browserNewPage,\n create as createBrowser\n} from './browser.js';\nimport { log } from './logger.js';\n\nimport puppeteerExport from './export.js';\n\nlet performedExports = 0;\nlet exportAttempts = 0;\nlet timeSpent = 0;\nlet droppedExports = 0;\nlet spentAverage = 0;\nlet poolConfig = {};\n\n// The pool instance\nlet pool = false;\n\n// Custom puppeteer arguments\nlet puppeteerArgs;\n\nconst factory = {\n /**\n * Creates a new worker.\n *\n * @return {object} - An object with the id of a resource, the work count and\n * a reference to the browser page.\n */\n create: async () => {\n const id = uuid();\n let page = false;\n\n const s = new Date().getTime();\n\n try {\n page = await browserNewPage();\n\n if (!page || page.isClosed()) {\n throw 'invalid page';\n }\n\n log(\n 3,\n `[pool] Successfully created a worker ${id} - took ${\n new Date().getTime() - s\n } ms.`\n );\n } catch (error) {\n log(\n 1,\n `[pool] Error creating a new page in pool entry creation! ${error}`\n );\n\n throw 'Error creating page';\n }\n\n return {\n id,\n page,\n // Try to distribute the initial work count\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\n };\n },\n\n /**\n * Validates a worker.\n *\n * @param {object} workerHandle - A browser's instance.\n *\n * @return {boolean} - Bool that indicates if a resource is valid or not.\n */\n validate: (workerHandle) => {\n if (\n poolConfig.workLimit &&\n ++workerHandle.workCount > poolConfig.workLimit\n ) {\n log(\n 3,\n `[pool] Worker failed validation:`,\n `exceeded work limit (limit is ${poolConfig.workLimit})`\n );\n return false;\n }\n return true;\n },\n\n /**\n * Destroys a worker.\n *\n * @param {object} workerHandle - A browser's instance.\n */\n destroy: (workerHandle) => {\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\n\n if (workerHandle.page) {\n // We don't really need to wait around for this.\n workerHandle.page.close();\n }\n },\n\n // Logger function\n log: (message, logLevel) => console.log(`${logLevel}: ${message}`)\n};\n\n/**\n * Inits the pool of resources.\n *\n * @param {object} config - Pool configuration along with custom puppeteer\n * arguments for the puppeteer.launch function.\n */\nexport const init = async (config) => {\n // The newest puppeteer arguments for the browser creation\n puppeteerArgs = config.puppeteerArgs;\n\n // Wait until we've sucessfully created a browser instance.\n try {\n await createBrowser(puppeteerArgs);\n } catch (e) {\n log(0, '[pool|browser]', e);\n }\n\n // For the module scope usage\n poolConfig = config && config.pool ? { ...config.pool } : {};\n\n log(\n 3,\n '[pool] Initializing pool:',\n `min ${poolConfig.initialWorkers}, max ${poolConfig.maxWorkers}.`\n );\n\n if (pool) {\n return log(\n 4,\n '[pool] Already initialized, please kill it before creating a new one.'\n );\n }\n\n // Attach process' exit listeners\n if (poolConfig.listenToProcessExits) {\n attachProcessExitListeners();\n }\n\n try {\n // Create a pool along with a minimal number of resources\n pool = new Pool({\n // Get the create/validate/destroy/log functions\n ...factory,\n min: poolConfig.initialWorkers,\n max: poolConfig.maxWorkers,\n createRetryIntervalMillis: 200,\n createTimeoutMillis: poolConfig.acquireTimeout,\n acquireTimeoutMillis: poolConfig.acquireTimeout,\n destroyTimeoutMillis: poolConfig.acquireTimeout,\n idleTimeoutMillis: poolConfig.timeoutThreshold,\n reapIntervalMillis: 1000, // poolConfig.reaper ? 120000 : 0, for now\n propagateCreateError: false\n });\n\n // Set events\n pool.on('createFail', (eventId, err) => {\n log(\n 1,\n `[pool] Error when creating worker of an event id ${eventId}:`,\n err\n );\n });\n\n pool.on('acquireFail', (eventId, err) => {\n log(\n 1,\n `[pool] Error when acquiring worker of an event id ${eventId}:`,\n err\n );\n });\n\n pool.on('destroyFail', (eventId, resource, err) => {\n log(\n 1,\n `[pool] Error when destroying worker of an id ${resource.id}, event id ${eventId}:`,\n err\n );\n });\n\n pool.on('release', (resource) => {\n log(4, `[pool] Releasing a worker of an id ${resource.id}`);\n });\n\n pool.on('destroySuccess', (eventId, resource) => {\n log(4, `[pool] Destroyed a worker of an id ${resource.id}`);\n });\n\n const initialResources = [];\n // Create an initial number of resources\n for (let i = 0; i < poolConfig.initialWorkers; i++) {\n initialResources.push(await pool.acquire().promise);\n }\n\n // Release the initial number of resources back to the pool\n initialResources.forEach((resource) => {\n pool.release(resource);\n });\n\n log(\n 3,\n `[pool] The pool is ready with ${poolConfig.initialWorkers} initial resources waiting.`\n );\n } catch (error) {\n log(1, `[pool] Couldn't create the worker pool ${error}`);\n throw error;\n }\n};\n\n/**\n * Attaches process' exit listeners.\n */\nexport function attachProcessExitListeners() {\n log(4, '[pool] Attaching exit listeners to the process.');\n\n // Kill all pool resources on exit\n process.on('exit', async () => {\n await killPool();\n });\n\n // Handler for the SIGINT\n process.on('SIGINT', (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n process.exit(1);\n });\n\n // Handler for the SIGTERM\n process.on('SIGTERM', (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n process.exit(1);\n });\n\n // Handler for the uncaughtException\n process.on('uncaughtException', async (error, name) => {\n log(4, `The ${name} error, message: ${error.message}.`);\n });\n}\n\n/**\n * Kills the pool and flush the browser instance.\n */\nexport async function killPool() {\n log(3, '[pool] Killing all workers.');\n\n // Return true when the pool is already destroyed\n if (pool.destroyed) {\n // Close the browser instance if still connected\n await close();\n return true;\n }\n\n // If still alive, destroy the pool of pages before closing a browser\n await pool.destroy();\n\n // Close the browser instance\n await close();\n return true;\n}\n\n/**\n * Posts work to the pool.\n *\n * @param {object} chart - Chart's options.\n * @param {object} options - All options object.\n */\nexport const postWork = async (chart, options) => {\n let workerHandle;\n\n // Handle fail conditions\n const fail = (msg) => {\n ++droppedExports;\n\n if (workerHandle) {\n pool.release(workerHandle);\n }\n\n throw 'In pool.postWork: ' + msg;\n };\n\n log(4, '[pool] Work received, starting to process.');\n\n if (poolConfig.benchmarking) {\n getPoolInfo();\n }\n\n ++exportAttempts;\n\n if (!pool) {\n log(1, '[pool] Work received, but pool has not been started.');\n return fail('Pool is not inited but work was posted to it!');\n }\n\n // Acquire the worker along with the id of resource and work count\n try {\n log(4, '[pool] Acquiring worker');\n workerHandle = await pool.acquire().promise;\n } catch (error) {\n return fail(`[pool] Error when acquiring available entry: ${error}`);\n }\n\n log(4, '[pool] Acquired worker handle');\n\n if (!workerHandle.page) {\n return fail('Resolved worker page is invalid: pool setup is wonky');\n }\n\n try {\n // Save the start time\n let workStart = new Date().getTime();\n\n log(4, `[pool] Starting work on pool entry ${workerHandle.id}.`);\n\n // Perform an export on a puppeteer level\n const result = await puppeteerExport(workerHandle.page, chart, options);\n\n // Check if it's an error\n if (result instanceof Error) {\n // TODO: If the export failed because puppeteer timed out, we need to force kill the worker so we get a new page. That needs to be handled better than this hack.\n if (result.message === 'Rasterization timeout') {\n workerHandle.page.close();\n workerHandle.page = await browserNewPage();\n }\n\n return fail(result);\n }\n\n // Release the resource back to the pool\n pool.release(workerHandle);\n\n // Used for statistics in averageTime and processedWorkCount, which\n // in turn is used by the /health route.\n const workEnd = new Date().getTime();\n const exportTime = workEnd - workStart;\n timeSpent += exportTime;\n spentAverage = timeSpent / ++performedExports;\n\n log(4, `[pool] Work completed in ${exportTime} ms.`);\n\n // Otherwise return the result\n return {\n data: result,\n options\n };\n } catch (error) {\n fail(`Error trying to perform puppeteer export: ${error}.`);\n }\n};\n\n/**\n * Gets the pool.\n */\nexport function getPool() {\n return pool;\n}\n\nexport const getPoolInfoJSON = () => ({\n min: pool.min,\n max: pool.max,\n size: pool.size,\n available: pool.available,\n borrowed: pool.borrowed,\n pending: pool.pending,\n spareResourceCapacity: pool.spareResourceCapacity\n});\n\n/**\n * Gets the pool's information.\n */\nexport function getPoolInfo() {\n const {\n min,\n max,\n size,\n available,\n borrowed,\n pending,\n spareResourceCapacity\n } = pool;\n\n log(4, `[pool] The minimum number of resources allowed by pool: ${min}.`);\n log(4, `[pool] The maximum number of resources allowed by pool: ${max}.`);\n log(\n 4,\n `[pool] The number of all resources in pool (free or in use): ${size}.`\n );\n log(\n 4,\n `[pool] The number of resources that are currently available: ${available}.`\n );\n log(\n 4,\n `[pool] The number of resources that are currently acquired: ${borrowed}.`\n );\n log(\n 4,\n `[pool] The number of callers waiting to acquire a resource: ${pending}.`\n );\n log(\n 4,\n `[pool] The number of how many more resources can the pool manage/create: ${spareResourceCapacity}.`\n );\n}\n\nexport default {\n init,\n killPool,\n postWork,\n getPool,\n getPoolInfo,\n getPoolInfoJSON,\n workAttempts: () => exportAttempts,\n droppedWork: () => droppedExports,\n averageTime: () => spentAverage,\n processedWorkCount: () => performedExports\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport cache from '../../cache.js';\nimport pool from '../../pool.js';\n\nconst packageVersion = process.env.npm_package_version;\nconst serverStartTime = new Date();\n\n/**\n * Adds the /health route which outputs basic stats for the server\n */\nexport default (app) =>\n !app\n ? false\n : app.get('/health', (request, response) => {\n response.send({\n status: 'OK',\n bootTime: serverStartTime,\n uptime:\n Math.floor(\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\n ) + ' minutes',\n version: packageVersion,\n highchartsVersion: cache.version(),\n averageProcessingTime: pool.averageTime(),\n performedExports: pool.processedWorkCount(),\n failedExports: pool.droppedWork(),\n exportAttempts: pool.workAttempts(),\n sucessRatio: (pool.processedWorkCount() / pool.workAttempts()) * 100,\n // eslint-disable-next-line import/no-named-as-default-member\n pool: pool.getPoolInfoJSON()\n });\n });\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\n\nimport prompts from 'prompts';\n\nimport { log } from './logger.js';\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\nimport {\n absoluteProps,\n defaultConfig,\n nestedArgs,\n promptsConfig\n} from './schemas/config.js';\n\nlet generalOptions = {};\n\n/**\n * Getter for the general options.\n *\n * @return {object} - General options object.\n */\nexport const getOptions = () => generalOptions;\n\n/**\n * Initializes and sets the general options for the server instace.\n *\n * @param {object} userOptions - Additional user options (e.g. from the node\n * module usage).\n * @param {string[]} args - CLI arguments.\n * @return {object} - General options object.\n */\nexport const setOptions = (userOptions, args) => {\n // Only for the CLI usage\n if (args?.length) {\n // Get the additional options from the custom JSON file\n generalOptions = loadConfigFile(args);\n }\n\n // Update the default config with a correct option values\n updateDefaultConfig(defaultConfig, generalOptions);\n\n // Set values for server's options and returns them\n generalOptions = initOptions(defaultConfig);\n\n // Apply user options if there are any\n if (userOptions) {\n // Merge user options\n generalOptions = mergeConfigOptions(\n generalOptions,\n userOptions,\n absoluteProps\n );\n }\n\n // Only for the CLI usage\n if (args?.length) {\n // Pair provided arguments\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\n }\n\n // Return final general options\n return generalOptions;\n};\n\n/**\n * Displays a prompt for the manual configuration.\n *\n * @param {string} configFileName - The name of a configuration file.\n */\nexport const manualConfig = async (configFileName) => {\n // Prepare a config object\n let configFile = {};\n\n // Check if provided config file exists\n if (existsSync(configFileName)) {\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\n }\n\n // Question about a configuration category\n const onSubmit = async (p, categories) => {\n let questionsCounter = 0;\n let allQuestions = [];\n\n // Create a corresponding property in the manualConfig object\n for (const section of categories) {\n // Mark each option with a section\n promptsConfig[section] = promptsConfig[section].map((option) => ({\n ...option,\n section\n }));\n\n // Collect the questions\n allQuestions = [...allQuestions, ...promptsConfig[section]];\n }\n\n await prompts(allQuestions, {\n onSubmit: async (prompt, answer) => {\n // Get the default modules\n if (prompt.name === 'modules') {\n answer = answer.length\n ? answer.map((module) => prompt.choices[module])\n : prompt.choices;\n\n configFile[prompt.section][prompt.name] = answer;\n } else {\n configFile[prompt.section] = recursiveProps(\n Object.assign({}, configFile[prompt.section] || {}),\n prompt.name.split('.'),\n answer\n );\n }\n\n if (++questionsCounter === allQuestions.length) {\n try {\n await fsPromises.writeFile(\n configFileName,\n JSON.stringify(configFile, null, 2),\n 'utf8'\n );\n } catch (error) {\n log(1, `[config] Error while creating config.json: ${error}`);\n }\n return true;\n }\n }\n });\n\n return true;\n };\n\n // Find the categories\n const choices = Object.keys(promptsConfig).map((choice) => ({\n title: `${choice} options`,\n value: choice\n }));\n\n // Category prompt\n return prompts(\n {\n type: 'multiselect',\n name: 'category',\n message: 'Which category do you want to configure?',\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\n instructions: '',\n choices\n },\n { onSubmit }\n );\n};\n\n/**\n * Maps the old options to the new config structure.\n *\n * @param {object} oldOptions - Options to be mapped.\n */\nexport const mapToNewConfig = (oldOptions) => {\n const newOptions = {};\n // Cycle through old-structured options\n for (const [key, value] of Object.entries(oldOptions)) {\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\n\n // Populate object in correct properties levels\n propertiesChain.reduce(\n (obj, prop, index) =>\n (obj[prop] =\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\n newOptions\n );\n }\n return newOptions;\n};\n\n/**\n * Merges the new options to the options object. It omits undefined values.\n *\n * @param {object} options - Old options.\n * @param {object} newOptions - New options.\n * @param {string[]} absoluteProps - Array of object names that should be force\n * merged.\n */\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\n const mergedOptions = deepCopy(options);\n\n for (const [key, value] of Object.entries(newOptions)) {\n mergedOptions[key] =\n isObject(value) &&\n !absoluteProps.includes(key) &&\n mergedOptions[key] !== undefined\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\n : value !== undefined\n ? value\n : mergedOptions[key];\n }\n\n return mergedOptions;\n};\n\n/**\n * Initializes options for the `startExport` method by merging user options\n * with the general options.\n *\n * @param {any} exportOptions - User options for exporting.\n * @param {any} generalOptions - General options are used for the export server.\n * @return {object} - User options merged with default options.\n */\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\n let options = {};\n\n if (exportOptions.svg) {\n options = deepCopy(generalOptions);\n options.export.type = exportOptions.type || exportOptions.export.type;\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\n options.export.outfile =\n exportOptions.outfile || exportOptions.export.outfile;\n options.payload = {\n svg: exportOptions.svg\n };\n } else {\n options = mergeConfigOptions(\n generalOptions,\n exportOptions,\n // Omit going down recursively with the belows\n absoluteProps\n );\n }\n\n options.export.outfile =\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\n return options;\n};\n\n/**\n * Loads the configuration from a custom JSON file.\n *\n * @param {string[]} args - CLI arguments.\n * @return {object} - Options object from the JSON file.\n */\nfunction loadConfigFile(args) {\n // Check if the --loadConfig option was used\n const configIndex = args.findIndex(\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\n );\n\n // Check if the --loadConfig has a value\n if (configIndex > -1 && args[configIndex + 1]) {\n const fileName = args[configIndex + 1];\n try {\n // Check if an additional config file is a correct JSON file\n if (fileName && fileName.endsWith('.json')) {\n // Load an optional custom JSON config file\n return JSON.parse(readFileSync(fileName));\n }\n } catch (error) {\n log(1, `[config] Unable to load config from the ${fileName}: ${error}`);\n }\n }\n\n // No additional options to return\n return {};\n}\n\n/**\n * Setting correct values of the options from the default config.\n *\n * @param {object} configObj - The config object based on which the initial\n * configuration be made.\n * @param {object} customObj - The custom object which can contain additional\n * option values to set.\n * @param {string} propChain - Required for creating a string chain of\n * properties for nested arguments.\n */\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\n Object.keys(configObj).forEach((key) => {\n if (!['puppeteer', 'highcharts'].includes(key)) {\n const entry = configObj[key];\n const customValue = customObj && customObj[key];\n let numEnvVal;\n\n if (typeof entry.value === 'undefined') {\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\n } else {\n // If a value from a custom JSON exists, it take precedence\n if (customValue !== undefined) {\n entry.value = customValue;\n }\n\n // If a value from an env variable exists, it take precedence\n if (entry.envLink) {\n // Load the env var\n if (entry.type === 'boolean') {\n entry.value = toBoolean(\n [process.env[entry.envLink], entry.value].find(\n (el) => el || el === 'false'\n )\n );\n } else if (entry.type === 'number') {\n numEnvVal = +process.env[entry.envLink];\n entry.value = numEnvVal >= 0 ? numEnvVal : entry.value;\n } else if (\n entry.type.indexOf(']') >= 0 &&\n process.env[entry.envLink]\n ) {\n entry.value = process.env[entry.envLink].split(',');\n } else {\n entry.value = process.env[entry.envLink] || entry.value;\n }\n }\n }\n }\n });\n}\n\n/**\n * Inits options recursively.\n *\n * @param {any} items - Items to update options from.\n * @return {object} - Updated options object.\n */\nfunction initOptions(items) {\n let options = {};\n for (const [name, item] of Object.entries(items)) {\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\n ? item.value\n : initOptions(item);\n }\n return options;\n}\n\n/**\n * Pairs argument with a corresponding value.\n *\n * @param {object} options - All server options.\n * @param {string[]} args - Array of arguments from a user.\n * @param {object} defaultConfig - The default config object.\n */\nfunction pairArgumentValue(options, args, defaultConfig) {\n for (let i = 0; i < args.length; i++) {\n let option = args[i].replace(/-/g, '');\n\n // Find the right place for property's value\n const propertiesChain = nestedArgs[option]\n ? nestedArgs[option].split('.')\n : [];\n\n propertiesChain.reduce((obj, prop, index) => {\n if (propertiesChain.length - 1 === index) {\n // Finds an option and set a corresponding value\n if (typeof obj[prop] !== 'undefined') {\n if (args[++i]) {\n obj[prop] = args[i] || obj[prop];\n } else {\n console.log(`Missing argument value for ${option}!`.red, '\\n');\n options = printUsage(defaultConfig);\n }\n }\n }\n return obj[prop];\n }, options);\n }\n\n return options;\n}\n\n/**\n * Recursively sets a property in a correct indentation level based on the\n * array of nested properties names.\n *\n * @param {object} objectToUpdate - Object where a property must be set on a\n * correct level.\n * @param {string[]}nestedNames - Array of nasted names that indicates\n * indentation level.\n * @param {any} value - A value to assign to the property.\n * @return {object} - Updated options object.\n */\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\n while (nestedNames.length > 1) {\n const propName = nestedNames.shift();\n\n // Create a property in object if it doesn't exist\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\n objectToUpdate[propName] = {};\n }\n\n // Call function again if there still names to go\n objectToUpdate[propName] = recursiveProps(\n Object.assign({}, objectToUpdate[propName]),\n nestedNames,\n value\n );\n\n return objectToUpdate;\n }\n\n // Assign the final value\n objectToUpdate[nestedNames[0]] = value;\n return objectToUpdate;\n}\n\nexport default {\n getOptions,\n setOptions,\n manualConfig,\n mapToNewConfig,\n mergeConfigOptions,\n initExportSettings\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFile, readFileSync, writeFileSync } from 'fs';\n\nimport { log } from './logger.js';\nimport { killPool, postWork } from './pool.js';\nimport {\n clearText,\n fixType,\n handleResources,\n isCorrectJSON,\n optionsStringify,\n roundNumber,\n toBoolean,\n wrapAround\n} from './utils.js';\nimport { initExportSettings, getOptions } from './config.js';\n\nlet allowCodeExecution = false;\n\nexport const startExport = async (settings, endCallback) => {\n // Starting exporting process message\n log(4, '[chart] Starting exporting process.');\n\n // Initialize options\n const options = initExportSettings(settings, getOptions());\n\n // Get the export options\n const exportOptions = options.export;\n\n // If SVG is an input (argument can be sent only by the request)\n if (options.payload?.svg && options.payload.svg !== '') {\n return exportAsString(options.payload.svg.trim(), options, endCallback);\n }\n\n // Export using options from the file\n if (exportOptions.infile && exportOptions.infile.length) {\n log(4, '[chart] Attempting to export from an input file.');\n\n // Try to read the file\n return readFile(exportOptions.infile, 'utf8', (error, infile) => {\n if (error) {\n return log(1, `[chart] Error loading input file: ${error}.`);\n }\n\n // Get the string representation\n options.export.instr = infile;\n return exportAsString(options.export.instr.trim(), options, endCallback);\n });\n }\n\n // Export with options from the raw representation\n if (\n (exportOptions.instr && exportOptions.instr !== '') ||\n (exportOptions.options && exportOptions.options !== '')\n ) {\n log(4, '[chart] Attempting to export from a raw input.');\n\n // Perform a direct inject when forced\n if (toBoolean(options.customCode?.allowCodeExecution)) {\n return doStraightInject(options, endCallback);\n }\n\n // Either try to parse to JSON first or do the direct export\n return typeof exportOptions.instr === 'string'\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\n : doExport(\n options,\n exportOptions.instr || exportOptions.options,\n endCallback\n );\n }\n\n // No input specified, pass an error message to the callback\n log(\n 1,\n clearText(\n `[chart] No input specified.\n ${JSON.stringify(exportOptions, undefined, ' ')}.`\n )\n );\n\n return (\n endCallback &&\n endCallback(false, {\n error: true,\n message: 'No input specified.'\n })\n );\n};\n\nexport const batchExport = (options) => {\n const batchFunctions = [];\n\n // Split and pair the --batch arguments\n for (let pair of options.export.batch.split(';')) {\n pair = pair.split('=');\n if (pair.length === 2) {\n batchFunctions.push(\n new Promise((resolve, reject) => {\n startExport(\n {\n ...options,\n export: {\n ...options.export,\n infile: pair[0],\n outfile: pair[1]\n }\n },\n (info, error) => {\n // Throw an error\n if (error) {\n return reject(error);\n }\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n info.options.export.outfile,\n Buffer.from(info.data, 'base64')\n );\n\n resolve();\n }\n );\n })\n );\n }\n }\n\n // Kill the pool after all exports are done\n Promise.all(batchFunctions)\n .then(() => {\n killPool();\n })\n .catch((error) => {\n log(1, `[chart] Error encountered during batch export: ${error}`);\n killPool();\n });\n};\n\nexport const singleExport = (options) => {\n // Use instr or its alias, options\n options.export.instr = options.export.instr || options.export.options;\n\n // Perform an export\n startExport(options, (info, error) => {\n // Exit process when error\n if (error) {\n log(1, `[cli] ${error.message}`);\n process.exit(1);\n }\n\n const { outfile, type } = info.options.export;\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n outfile || `chart.${type}`,\n type !== 'svg' ? Buffer.from(info.data, 'base64') : info.data\n );\n\n // Kill the pool\n killPool();\n });\n};\n\n/**\n * Function for choosing chart size and scale based on options prioritization.\n *\n * @param {object} options - All options object.\n * @return {object} - An object with updated size and scale for a chart.\n */\nexport const findChartSize = (options) => {\n const { chart, exporting } =\n options.export?.options || isCorrectJSON(options.export?.instr);\n\n // See if globalOptions holds chart or exporting size\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\n\n // Secure scale value\n let scale =\n options.export?.scale ||\n exporting?.scale ||\n globalOptions?.exporting?.scale ||\n options.export?.defaultScale ||\n 1;\n\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\n scale = Math.max(0.1, Math.min(scale, 5.0));\n\n // we want to round the numbers like 0.23234 -> 0.23\n scale = roundNumber(scale, 2);\n\n // Find chart size and scale\n return {\n height:\n options.export?.height ||\n exporting?.sourceHeight ||\n chart?.height ||\n globalOptions?.exporting?.sourceHeight ||\n globalOptions?.chart?.height ||\n options.export?.defaultHeight ||\n 400,\n width:\n options.export?.width ||\n exporting?.sourceWidth ||\n chart?.width ||\n globalOptions?.exporting?.sourceWidth ||\n globalOptions?.chart?.width ||\n options.export?.defaultWidth ||\n 600,\n scale\n };\n};\n\n/**\n * Function for final options preparation before export.\n *\n * @param {object} options - All options object.\n * @param {object} chartJson - Chart JSON.\n * @param {function} endCallback - The end callback.\n * @param {string} svg - The SVG representation.\n */\nconst doExport = (options, chartJson, endCallback, svg) => {\n let { export: exportOptions, customCode: customCodeOptions } = options;\n\n const allowCodeExecutionScoped =\n typeof customCodeOptions.allowCodeExecution === 'boolean'\n ? customCodeOptions.allowCodeExecution\n : allowCodeExecution;\n\n if (!customCodeOptions) {\n customCodeOptions = options.customCode = {};\n } else if (typeof options.customCode.resources === 'string') {\n // Process resources\n options.customCode.resources = handleResources(\n options.customCode.resources,\n toBoolean(options.customCode.allowFileResources)\n );\n } else if (!options.customCode.resources) {\n try {\n const resources = readFileSync('resources.json', 'utf8');\n options.customCode.resources = handleResources(\n resources,\n toBoolean(options.customCode.allowFileResources)\n );\n } catch (err) {\n log(3, `[chart] The default resources.json file not found.`);\n }\n }\n\n // If the allowCodeExecution flag isn't set, we should refuse the usage\n // of callback, resources, and custom code. Additionally, the worker will\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\n // option, then we should take a look at the overall pool option.\n if (!allowCodeExecutionScoped && customCodeOptions) {\n if (\n customCodeOptions.callback ||\n customCodeOptions.resources ||\n customCodeOptions.customCode\n ) {\n // Send back a friendly message saying that the exporter does not support\n // these settings.\n return (\n endCallback &&\n endCallback(false, {\n error: true,\n message: clearText(\n `The callback, resources and customCode have been disabled for this\n server.`\n )\n })\n );\n }\n\n // Reset all additional custom code\n customCodeOptions.callback = false;\n customCodeOptions.resources = false;\n customCodeOptions.customCode = false;\n }\n\n // Clean properties to keep it lean and mean\n if (chartJson) {\n chartJson.chart = chartJson.chart || {};\n chartJson.exporting = chartJson.exporting || {};\n chartJson.exporting.enabled = false;\n }\n\n exportOptions.constr = exportOptions.constr || 'chart';\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\n if (exportOptions.type === 'svg') {\n exportOptions.width = false;\n }\n\n // Prepare global and theme options\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\n try {\n if (exportOptions && exportOptions[optionsName]) {\n if (\n typeof exportOptions[optionsName] === 'string' &&\n exportOptions[optionsName].endsWith('.json')\n ) {\n exportOptions[optionsName] = isCorrectJSON(\n readFileSync(exportOptions[optionsName], 'utf8'),\n true\n );\n } else {\n exportOptions[optionsName] = isCorrectJSON(\n exportOptions[optionsName],\n true\n );\n }\n }\n } catch (error) {\n exportOptions[optionsName] = {};\n log(1, `[chart] The ${optionsName} not found.`);\n }\n });\n\n // Prepare customCode\n if (customCodeOptions.allowCodeExecution) {\n customCodeOptions.customCode = wrapAround(\n customCodeOptions.customCode,\n customCodeOptions.allowFileResources\n );\n }\n\n // Get the callback\n if (\n customCodeOptions &&\n customCodeOptions.callback &&\n customCodeOptions.callback?.indexOf('{') < 0\n ) {\n // The allowFileResources is always set to false for HTTP requests to avoid\n // injecting arbitrary files from the fs\n if (customCodeOptions.allowFileResources) {\n try {\n customCodeOptions.callback = readFileSync(\n customCodeOptions.callback,\n 'utf8'\n );\n } catch (error) {\n log(2, `[chart] Error loading callback: ${error}.`);\n customCodeOptions.callback = false;\n }\n } else {\n customCodeOptions.callback = false;\n }\n }\n\n // Size search\n options.export = {\n ...options.export,\n ...findChartSize(options)\n };\n\n // Post the work to the pool\n postWork(exportOptions.strInj || chartJson || svg, options)\n .then((result) => endCallback(result))\n .catch((error) => {\n log(0, '[chart] When posting work:', error);\n return endCallback(false, error);\n });\n};\n\n/**\n * Function for straight injecting the code.\n * Dangerous and must be used deliberately by someone who sets up a server\n * (see --allowCodeExecution).\n *\n * @param {object} options - All options object.\n * @param {function} endCallback - The function to call when exporting is done.\n */\nconst doStraightInject = (options, endCallback) => {\n try {\n let strInj;\n let instr = options.export.instr || options.export.options;\n\n if (typeof instr !== 'string') {\n // Try to stringify options\n strInj = instr = optionsStringify(\n instr,\n options.customCode?.allowCodeExecution\n );\n }\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\n\n // Get rid of the ;\n if (strInj[strInj.length - 1] === ';') {\n strInj = strInj.substring(0, strInj.length - 1);\n }\n\n // Save as stright inject string\n options.export.strInj = strInj;\n return doExport(options, false, endCallback);\n } catch (error) {\n const message = clearText(\n `Malformed input detected for ${options.export?.requestId || '?'}:\n Please make sure that your JSON/JavaScript options\n are sent using the \"options\" attribute, and that if you're using\n SVG, it is unescaped.`\n );\n\n log(1, message);\n return (\n endCallback &&\n endCallback(\n false,\n JSON.stringify({\n error: true,\n message\n })\n )\n );\n }\n};\n\n/**\n * Prepares an input before exporting.\n *\n * @param {string} stringToExport - String representation of SVG/export options.\n * @param {object} options - All options object.\n * @param {function} endCallback - The function to call when exporting is done.\n */\nconst exportAsString = (stringToExport, options, endCallback) => {\n const { allowCodeExecution } = options.customCode;\n\n // Check if it is SVG\n if (\n stringToExport.indexOf('= 0 ||\n stringToExport.indexOf('= 0\n ) {\n log(4, '[chart] Parsing input as SVG.');\n return doExport(options, false, endCallback, stringToExport);\n }\n\n try {\n // Try to parse to JSON and call the doExport function\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\n\n // If a correct JSON, do the export\n return doExport(options, chartJSON, endCallback);\n } catch (error) {\n // Not a valid JSON\n if (toBoolean(allowCodeExecution)) {\n return doStraightInject(options, endCallback);\n } else {\n // Do not allow straight injection without the allowCodeExecution flag\n return (\n endCallback &&\n endCallback(false, {\n error: true,\n message: clearText(\n `Only JSON configurations and SVG is allowed for this server. If\n this is your server, JavaScript exporting can be enabled by starting\n the server with the --allowCodeExecution flag.`\n )\n })\n );\n }\n }\n};\n\nexport const getAllowCodeExecution = () => allowCodeExecution;\n\nexport const setAllowCodeExecution = (value) => {\n allowCodeExecution = toBoolean(value);\n};\n\n/**\n * Starts an exporting process\n *\n * @param {object} settings - Settings for export.\n * @param {function} endCallback - The function to call when exporting is done.\n */\nexport default {\n batchExport,\n singleExport,\n getAllowCodeExecution,\n setAllowCodeExecution,\n startExport,\n findChartSize\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { v4 as uuid } from 'uuid';\n\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\nimport { getOptions, mergeConfigOptions } from '../../config.js';\nimport { log } from '../../logger.js';\nimport {\n clearText,\n fixType,\n isCorrectJSON,\n isPrivateRangeUrlFound,\n optionsStringify,\n measureTime\n} from '../../utils.js';\n\n// Reversed MIME types\nconst reversedMime = {\n png: 'image/png',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n pdf: 'application/pdf',\n svg: 'image/svg+xml'\n};\n\n// The requests counter\nlet requestsCounter = 0;\n\nconst benchmark = false;\n\n// The array of callbacks to call before a request\nconst beforeRequest = [];\n\n// The array of callbacks to call after a request\nconst afterRequest = [];\n\n/**\n * Calls callbacks.\n *\n * @param {Array} callbacks - An array of callbacks.\n * @param {object} request - The request.\n * @param {object} response - The response.\n * @param {object} data - The data to send to callbacks.\n * @return {object} - The result from a callback.\n */\nconst doCallbacks = (callbacks, request, response, data) => {\n let result = true;\n const { id, uniqueId, type, body } = data;\n\n callbacks.some((callback) => {\n if (callback) {\n let callResponse = callback(request, response, id, uniqueId, type, body);\n\n if (callResponse !== undefined && callResponse !== true) {\n result = callResponse;\n }\n\n return true;\n }\n });\n\n return result;\n};\n\n/**\n * Handles an export.\n *\n * @param {object} request - The request.\n * @param {object} response - The response.\n */\nconst exportHandler = (request, response) => {\n // Start counting time\n const stopCounter = measureTime();\n\n // Get the current server's general options\n const defaultOptions = getOptions();\n\n // Init default options\n if (benchmark) {\n console.log('Init default options:', stopCounter(), 'ms.');\n }\n\n const body = request.body;\n const id = ++requestsCounter;\n const uniqueId = uuid().replace(/-/g, '');\n let type = fixType(body.type);\n\n // Fix type\n if (benchmark) {\n console.log('Fix type:', stopCounter(), 'ms.');\n }\n\n // Throw 'Bad Request' if there's no body\n if (!body) {\n return response.status(400).send(\n clearText(\n `Body is required. Sending a body? Make sure your Content-type header\n is correct. Accepted is application/json and multipart/form-data.`\n )\n );\n }\n\n // All of the below can be used\n let instr = isCorrectJSON(body.infile || body.options || body.data);\n\n // Is correct JSON\n if (benchmark) {\n console.log('Is correct JSON:', stopCounter(), 'ms.');\n }\n\n // Throw 'Bad Request' if there's no JSON or SVG to export\n if (!instr && !body.svg) {\n log(\n 2,\n clearText(\n `Request ${uniqueId} from ${\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\n } was incorrect. Check your payload.`\n )\n );\n\n return response.status(400).send(\n clearText(\n `No correct chart data found. Please make sure you are using\n application/json or multipart/form-data headers, and that the chart\n data is in the 'infile', 'options' or 'data' attribute if sending\n JSON or in the 'svg' if sending SVG.`\n )\n );\n }\n\n let callResponse = false;\n\n // Call the before request functions\n callResponse = doCallbacks(beforeRequest, request, response, {\n id,\n uniqueId,\n type,\n body\n });\n\n // Do callbacks\n if (benchmark) {\n console.log('Do callbacks:', stopCounter(), 'ms.');\n }\n\n // Block the request if one of a callbacks failed\n if (callResponse !== true) {\n return response.send(callResponse);\n }\n\n let connectionAborted = false;\n\n // In case the connection is closed, force to abort further actions\n request.socket.on('close', () => {\n connectionAborted = true;\n });\n\n log(4, `[export] Got an incoming HTTP request ${uniqueId}.`);\n\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\n\n // Gather and organize options from the payload\n const requestOptions = {\n export: {\n instr,\n type,\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\n height: body.height,\n width: body.width,\n scale: body.scale || defaultOptions.export.scale,\n globalOptions: isCorrectJSON(body.globalOptions, true),\n themeOptions: isCorrectJSON(body.themeOptions, true)\n },\n customCode: {\n allowCodeExecution: getAllowCodeExecution(),\n allowFileResources: false,\n resources: isCorrectJSON(body.resources, true),\n callback: body.callback,\n customCode: body.customCode\n }\n };\n\n // Organize options\n if (benchmark) {\n console.log('Organize options:', stopCounter(), 'ms.');\n }\n\n if (instr) {\n // Stringify JSON with options\n requestOptions.export.instr = optionsStringify(\n instr,\n requestOptions.customCode.allowCodeExecution\n );\n\n // Stringify JSON with options\n if (benchmark) {\n console.log('Stringify JSON with options:', stopCounter(), 'ms.');\n }\n }\n\n // Merge the request options into default ones\n const options = mergeConfigOptions(defaultOptions, requestOptions);\n\n // Merge config options\n if (benchmark) {\n console.log('Merge config options:', stopCounter(), 'ms.');\n }\n\n // Save the JSON if exists\n options.export.options = instr;\n\n // Lastly, add the server specific arguments into options as payload\n options.payload = {\n svg: body.svg || false,\n b64: body.b64 || false,\n dataOptions: isCorrectJSON(body.dataOptions, true),\n noDownload: body.noDownload || false,\n requestId: uniqueId\n };\n\n // Setting payload\n if (benchmark) {\n console.log('Setting payload:', stopCounter(), 'ms.');\n }\n\n // Test xlink:href elements from payload's SVG\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\n return response\n .status(400)\n .send(\n 'SVG potentially contain at least one forbidden URL in xlink:href element.'\n );\n }\n\n // Check URL range\n if (benchmark) {\n console.log('Check URL range:', stopCounter(), 'ms.');\n }\n\n // Start the export process\n startExport(options, (info, error) => {\n // Remove the close event from the socket\n request.socket.removeAllListeners('close');\n\n // After Puppeteer exporting\n if (benchmark) {\n console.log('After Puppeteer exporting:', stopCounter(), 'ms.', '\\n');\n }\n\n // If the connection was closed, do nothing\n if (connectionAborted) {\n return log(\n 3,\n clearText(\n `[export] The client closed the connection before the chart was done\n processing.`\n )\n );\n }\n\n // If error, return it\n if (error) {\n log(\n 1,\n clearText(\n `[export] Work: ${uniqueId} could not be completed, sending:\n ${error}`\n )\n );\n return response.status(400).send(error.message);\n }\n\n // If data is missing, return the error\n if (!info || !info.data) {\n log(\n 1,\n clearText(\n `[export] Unexpected return from chart generation, please check your\n data Request: ${uniqueId} is ${info.data}.`\n )\n );\n return response\n .status(400)\n .send(\n 'Unexpected return from chart generation, please check your data.'\n );\n }\n\n // Get the type from options\n type = info.options.export.type;\n\n // The after request callbacks\n doCallbacks(afterRequest, request, response, { id, body: info.data });\n\n if (info.data) {\n // If only base64 is required, return it\n if (body.b64) {\n // Check if it is already base64 or a raw SVG\n if (type === 'pdf') {\n return response.send(\n Buffer.from(info.data, 'utf8').toString('base64')\n );\n }\n return response.send(info.data);\n }\n\n // Set correct content type\n response.header('Content-Type', reversedMime[type] || 'image/png');\n\n // Decide whether to download or not chart file\n if (!body.noDownload) {\n response.attachment(\n `${request.params.filename || 'chart'}.${type || 'png'}`\n );\n }\n\n // If SVG, return plain content\n return type === 'svg'\n ? response.send(info.data)\n : response.send(Buffer.from(info.data, 'base64'));\n }\n });\n};\n\nexport default (app) => {\n app.post('/', exportHandler);\n app.post('/:filename', exportHandler);\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { promises as fsPromises } from 'fs';\nimport { posix } from 'path';\n\nimport bodyParser from 'body-parser';\nimport cors from 'cors';\nimport express from 'express';\nimport multer from 'multer';\nimport http from 'http';\nimport https from 'https';\n\nimport { log } from '../logger.js';\nimport rateLimit from './rate_limit.js';\nimport { __dirname } from '../utils.js';\n\nimport healthRoute from './routes/health.js';\nimport exportRoutes from './routes/export.js';\nimport vswitchRoute from './routes/change_hc_version.js';\nimport uiRoute from './routes/ui.js';\n\n// Create express app\nconst app = express();\n\n// Disable the X-Powered-By header\napp.disable('x-powered-by');\n\n// Enable CORS support\napp.use(cors());\n\n// Enable parsing of form data (files) with Multer package\nconst storage = multer.memoryStorage();\nconst upload = multer({\n storage,\n limits: {\n fieldsSize: '50MB'\n }\n});\n\napp.use(upload.any());\n\n// Enable body parser\napp.use(bodyParser.json({ limit: '50mb' }));\napp.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));\napp.use(bodyParser.urlencoded({ extended: false, limit: '50mb' }));\n\n/**\n * Error handler function.\n *\n * @param {object} error - An error object.\n * @return {string} - An error message.\n */\nconst errorHandler = (error) => log(1, `[server] Socket error: ${error}`);\n\n/**\n * Attaches error handlers for a server.\n *\n * @param {object} server - The http/https server.\n */\nconst attachErrorHandlers = (server) => {\n server.on('clientError', errorHandler);\n server.on('error', errorHandler);\n server.on('connection', (socket) =>\n socket.on('error', (error) => errorHandler(error, socket))\n );\n};\n\nexport const startServer = async (serverConfig) => {\n // Stop if not enabled\n if (!serverConfig.enable) {\n return false;\n }\n\n // // Get the pool\n // const pool = getPool();\n\n // // Try to create browser instance before starting the server\n // const resource = await pool.acquire();\n\n // // If not found, throw an error\n // if (!resource.browser) {\n // log(1, `[server] Could not acquire browser instance.`);\n // process.exit(1);\n // }\n\n // // Release the resource\n // pool.release(resource);\n\n // Listen HTTP server\n if (!serverConfig.ssl.enable && !serverConfig.ssl.force) {\n // Main server instance (HTTP)\n const httpServer = http.createServer(app);\n // Attach error handlers and listen to the server\n attachErrorHandlers(httpServer);\n // Listen\n httpServer.listen(serverConfig.port, serverConfig.host);\n\n log(\n 3,\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\n );\n }\n\n // Listen HTTPS server\n if (serverConfig.ssl.enable) {\n // Set up an SSL server also\n let key, cert;\n\n try {\n // Get the SSL key\n key = await fsPromises.readFile(\n posix.join(serverConfig.ssl.certPath, 'server.key'),\n 'utf8'\n );\n\n // Get the SSL certificate\n cert = await fsPromises.readFile(\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\n 'utf8'\n );\n } catch (error) {\n log(\n 1,\n `[server] Unable to load key/certificate from ${serverConfig.ssl.certPath}.`\n );\n }\n\n if (key && cert) {\n // Main server instance (HTTPS)\n const httpsServer = https.createServer(app);\n // Attach error handlers and listen to the server\n attachErrorHandlers(httpsServer);\n // Listen\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\n\n log(\n 3,\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\n );\n }\n }\n\n // Enable the rate limiter if config says so\n if (\n serverConfig.rateLimiting &&\n serverConfig.rateLimiting.enable &&\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\n ) {\n rateLimit(app, serverConfig.rateLimiting);\n }\n\n // Set up static folder's route\n app.use(express.static(posix.join(__dirname, 'public')));\n\n // Set up routes\n healthRoute(app);\n exportRoutes(app);\n uiRoute(app);\n vswitchRoute(app);\n};\n\n/**\n * Returns the express instance.\n */\nexport const getExpress = () => {\n return express;\n};\n\n/**\n * Returns the app instance.\n */\nexport const getApp = () => {\n return app;\n};\n\n/**\n * Adds a middleware to the server.\n *\n * @param {object} path - An endpoint path to add middlewares to.\n * @param {Array} middlewares - An unlimited number of middlewares to use\n * against the specific endpoint.\n */\nexport const use = (path, ...middlewares) => {\n app.use(path, ...middlewares);\n};\n\n/**\n * Adds a get route to the server.\n *\n * @param {object} path - An endpoint path to add middlewares to.\n * @param {Array} middlewares - An unlimited number of middlewares to use\n * against the specific endpoint for GET method.\n */\nexport const get = (path, ...middlewares) => {\n app.get(path, ...middlewares);\n};\n\n/**\n * Adds a post route to the server.\n *\n * @param {object} path - An endpoint path to add middlewares to.\n * @param {Array} middlewares - An unlimited number of middlewares to use\n * against the specific endpoint for POST method.\n */\nexport const post = (path, ...middlewares) => {\n app.post(path, ...middlewares);\n};\n\n/**\n * Forcefully enables rate limiting.\n *\n * @param {object} limitConfig - The options object for the rate limiter\n * configuration.\n */\nexport const enableRateLimiting = (limitConfig) => {\n return rateLimit(app, limitConfig);\n};\n\nexport default {\n startServer,\n getExpress,\n getApp,\n use,\n get,\n post,\n enableRateLimiting\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { join } from 'path';\n\nimport { __dirname } from '../../utils.js';\n/**\n * Adds the / route for a UI when enabled for the export server\n */\nexport default (app) =>\n !app\n ? false\n : app.get('/', (request, response) => {\n response.sendFile(join(__dirname, 'public', 'index.html'));\n });\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport cache from '../../cache.js';\n\n/**\n * Adds a route that can be used to change the HC version on the server\n * TODO: Add auth token and connect to API\n */\nexport default (app) =>\n !app\n ? false\n : app.post('/change_hc_version/:newVersion', async (request, response) => {\n const ctoken = process.env.HIGHCHARTS_ADMIN_TOKEN;\n\n if (!ctoken || !ctoken.length) {\n return response.send({\n error: true,\n message:\n 'Server not configured to do run-time version changes: HIGHCHARTS_ADMIN_TOKEN not set'\n });\n }\n\n const token = request.get('hc-auth');\n\n if (!token || token !== ctoken) {\n return response.send({\n error: true,\n message: 'Invalid or missing token: set token in the hc-auth header'\n });\n }\n\n const newVersion = request.params.newVersion;\n\n if (newVersion) {\n try {\n // eslint-disable-next-line import/no-named-as-default-member\n await cache.updateVersion(newVersion);\n } catch (e) {\n response.send({\n error: true,\n message: e\n });\n }\n\n response.send({\n version: cache.version()\n });\n } else {\n response.send({\n error: true,\n message: 'No new version supplied'\n });\n }\n });\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2023, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// Add the main directory in the global object\nimport 'colors';\n\nimport server, { startServer } from './server/server.js';\nimport {\n setAllowCodeExecution,\n batchExport,\n singleExport,\n startExport\n} from './chart.js';\nimport { mapToNewConfig, setOptions } from './config.js';\nimport { log, setLogLevel, enableFileLogging } from './logger.js';\nimport { killPool, init } from './pool.js';\nimport { checkCache } from './cache.js';\n\nexport default {\n log,\n mapToNewConfig,\n setOptions,\n singleExport,\n startExport,\n batchExport,\n server,\n startServer,\n killPool,\n initPool: async (options = {}) => {\n // Set the allowCodeExecution per export module scope\n setAllowCodeExecution(\n options.customCode && options.customCode.allowCodeExecution\n );\n\n // Set the log level\n setLogLevel(options.logging && parseInt(options.logging.level));\n\n // Set the log file path and name\n if (options.logging && options.logging.dest) {\n enableFileLogging(\n options.logging.dest,\n options.logging.file || 'highcharts-export-server.log'\n );\n }\n\n // Check if cache needs to be updated\n await checkCache(options.highcharts || { version: 'latest' });\n\n // Init the pool\n await init({\n pool: options.pool || {\n initialWorkers: 1,\n maxWorkers: 1\n },\n puppeteerArgs: options.puppeteer?.args || []\n });\n\n // Return updated options\n return options;\n }\n};\n"],"names":["dotenv","config","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","modules","indicators","scripts","forceFetch","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","customCode","allowCodeExecution","allowFileResources","callback","resources","loadConfig","createConfig","server","enable","cliName","host","port","ssl","force","certPath","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","pool","initialWorkers","maxWorkers","workLimit","queueSize","timeoutThreshold","acquireTimeout","reaper","benchmarking","listenToProcessExits","logging","level","file","dest","ui","route","other","noLogo","payload","join","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","log","newLevel","texts","length","prefix","Date","toString","split","trim","fn","existsSync","mkdirSync","appendFile","concat","error","console","apply","undefined","__dirname","fileURLToPath","URL","url","clearText","text","rule","replacer","replaceAll","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","endsWith","isCorrectJSON","readFileSync","notice","files","propName","map","item","data","parsedData","JSON","parse","stringify","deepCopy","copy","Array","isArray","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","name","startsWith","printUsage","bold","yellow","cycleCategories","categories","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","rateLimit","app","limitConfig","msg","rateOptions","max","limiter","windowMs","delayMs","handler","request","response","format","json","status","send","message","default","skip","query","access_token","use","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","cachePath","cache","activeManifest","sources","hcVersion","appliedConfig","extractVersion","substr","indexOf","fetchScript","script","proxyAgent","agent","timeout","process","env","statusCode","updateCache","sourcePath","customScripts","allScripts","c","m","proxyHost","proxyPort","HttpsProxyAgent","fetchedModules","all","writeFileSync","checkCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","cache$1","newVersion","assign","RANDOM_PID","randomBytes","PUPPETEER_DIR","path","minimalArgs","template","fs","browser","newPage","p","setContent","addScriptTag","evaluate","setupHighcharts","err","$eval","element","errorMessage","_displayErrors","innerHTML","close","connected","__basedir","setAsConfig","page","chart","triggerExport","puppeteerExport","injectedResources","clearInjected","dispose","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","remove","exportBench","exportOptions","requestAnimationFrame","displayErrors","debugger","d","svgBench","isSVG","setPageBench","svgTemplate","strInj","setContentBench","resBench","js","push","content","isLocal","cssBench","css","cssImports","match","cssImportPath","addStyleTag","size","chartHeight","baseVal","chartWidth","parseFloat","Highcharts","charts","vpBench","viewportHeight","Math","ceil","viewportWidth","setViewport","deviceScaleFactor","zoomCallback","body","style","zoom","margin","x","y","getBoundingClientRect","trunc","getClipRegion","round","expBenchmark","outerHTML","createSVG","encoding","clip","race","screenshot","omitBackground","setTimeout","Error","createImage","pdf","createPDF","oldCharts","oldChart","destroy","shift","puppeteerArgs","performedExports","exportAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","s","getTime","browserNewPage","isClosed","workCount","random","validate","workerHandle","logLevel","init","allArgs","tryCount","open","launch","headless","userDataDir","e","createBrowser","killPool","code","exit","Pool","min","createRetryIntervalMillis","createTimeoutMillis","acquireTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","reapIntervalMillis","propagateCreateError","eventId","resource","initialResources","acquire","promise","release","destroyed","postWork","fail","getPoolInfo","workStart","result","exportTime","available","borrowed","pending","spareResourceCapacity","pool$1","packageVersion","npm_package_version","serverStartTime","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","numEnvVal","el","initOptions","items","startExport","settings","endCallback","svg","initExportSettings","exportAsString","readFile","doStraightInject","doExport","findChartSize","exporting","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","chartJson","customCodeOptions","allowCodeExecutionScoped","enabled","optionsName","then","catch","requestId","stringToExport","chartJSON","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","start","hrtime","bigint","measureTime","defaultOptions","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","b64","dataOptions","noDownload","ipRegEx","info","removeAllListeners","Buffer","from","header","attachment","params","filename","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldsSize","any","bodyParser","limit","urlencoded","extended","errorHandler","attachErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","cert","fsPromises","posix","httpsServer","NaN","static","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","healthRoute","post","exportRoutes","sendFile","uiRoute","ctoken","HIGHCHARTS_ADMIN_TOKEN","token","vswitchRoute","getExpress","getApp","middlewares","enableRateLimiting","index","mapToNewConfig","oldOptions","propertiesChain","reduce","prop","setOptions","userOptions","configIndex","findIndex","arg","fileName","loadConfigFile","pairArgumentValue","singleExport","batchExport","batchFunctions","pair","initPool","parseInt","logDest","logFile","enableFileLogging"],"mappings":"snBAiBAA,EAAOC,SAIA,MAAMC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,GACPC,KAAM,WACNC,YAAa,6CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPK,QAAS,qBACTJ,KAAM,SACNC,YAAa,8BAEfI,OAAQ,CACNN,MAAO,+BACPK,QAAS,iBACTJ,KAAM,SACNC,YAAa,6CAEfK,YAAa,CACXF,QAAS,0BACTL,MAAO,CAAC,aAAc,kBAAmB,iBACzCC,KAAM,WACNC,YAAa,qCAEfM,QAAS,CACPH,QAAS,qBACTL,MAAO,CACL,QACA,MACA,QACA,YACA,cACA,uBACA,gBACA,uBACA,eACA,QACA,OACA,mBACA,eACA,cACA,UACA,UACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,YACA,eACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,cACA,eACA,cACA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,cAEFC,KAAM,WACNC,YAAa,gCAEfO,WAAY,CACVJ,QAAS,wBACTL,MAAO,CAAC,kBACRC,KAAM,WACNC,YAAa,mCAEfQ,QAAS,CACPV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YACE,qEAEJS,WAAY,CACVN,QAAS,yBACTL,OAAO,EACPC,KAAM,UACNC,YACE,oEAGNU,OAAQ,CACNC,OAAQ,CACNb,OAAO,EACPC,KAAM,SACNC,YACE,8FAEJY,MAAO,CACLd,OAAO,EACPC,KAAM,SACNC,YACE,iFAEJa,QAAS,CACPf,OAAO,EACPC,KAAM,SACNC,YAAa,oCAEfc,QAAS,CACPhB,OAAO,EACPC,KAAM,SACNC,YACE,2FAEJD,KAAM,CACJI,QAAS,sBACTL,MAAO,MACPC,KAAM,SACNC,YACE,sEAEJe,OAAQ,CACNZ,QAAS,wBACTL,MAAO,QACPC,KAAM,SACNC,YACE,6EAEJgB,cAAe,CACbb,QAAS,wBACTL,MAAO,IACPC,KAAM,SACNC,YACE,gFAEJiB,aAA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"} \ No newline at end of file diff --git a/lib/schemas/config.js b/lib/schemas/config.js index d648323e..4380b8f5 100644 --- a/lib/schemas/config.js +++ b/lib/schemas/config.js @@ -67,6 +67,7 @@ export const defaultConfig = { 'tilemap', 'timeline', 'treemap', + 'treegraph', 'item-series', 'drilldown', 'histogram-bellcurve',